diff --git a/g10/keygen.c b/g10/keygen.c index a4117cdd0..5d85c05d4 100644 --- a/g10/keygen.c +++ b/g10/keygen.c @@ -1,6178 +1,6179 @@ /* keygen.c - Generate a key pair * Copyright (C) 1998-2007, 2009-2011 Free Software Foundation, Inc. * Copyright (C) 2014, 2015, 2016, 2017, 2018 Werner Koch * Copyright (C) 2020 g10 Code GmbH * * 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 "gpg.h" #include "../common/util.h" #include "main.h" #include "packet.h" #include "../common/ttyio.h" #include "options.h" #include "keydb.h" #include "trustdb.h" #include "../common/status.h" #include "../common/i18n.h" #include "keyserver-internal.h" #include "call-agent.h" #include "pkglue.h" #include "../common/shareddefs.h" #include "../common/host2net.h" #include "../common/mbox-util.h" /* The default algorithms. If you change them, you should ensure the value is inside the bounds enforced by ask_keysize and gen_xxx. See also get_keysize_range which encodes the allowed ranges. The default answer in ask_algo also needs to be adjusted. */ #define DEFAULT_STD_KEY_PARAM "ed25519/cert,sign+cv25519/encr" #define FUTURE_STD_KEY_PARAM "ed25519/cert,sign+cv25519/encr" /* When generating keys using the streamlined key generation dialog, use this as a default expiration interval. */ const char *default_expiration_interval = "2y"; /* Flag bits used during key generation. */ #define KEYGEN_FLAG_NO_PROTECTION 1 #define KEYGEN_FLAG_TRANSIENT_KEY 2 #define KEYGEN_FLAG_CREATE_V5_KEY 4 /* 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 */ pSUBKEYCREATIONDATE, pSUBKEYEXPIRE, /* in n seconds */ pAUTHKEYCREATIONDATE, /* Not yet used. */ pPASSPHRASE, pSERIALNO, pCARDBACKUPKEY, pHANDLE, pKEYSERVER, pKEYGRIP, pSUBKEYGRIP, pVERSION, /* Desired version of the key packet. */ pSUBVERSION, /* Ditto for the subpacket. */ pCARDKEY /* The keygrips have been taken from active card (bool). */ }; struct para_data_s { struct para_data_s *next; int lnr; enum para_name key; union { u32 expire; u32 creation; int abool; 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; }; /* FIXME: These globals vars are ugly. And using MAX_PREFS even for * aeads is useless, given that we don't expects more than a very few * algorithms. */ 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 byte aead_prefs[MAX_PREFS]; static int naead_prefs; static int mdc_available; static int ks_modify; static int aead_available; static gpg_error_t parse_algo_usage_expire (ctrl_t ctrl, int for_subkey, const char *algostr, const char *usagestr, const char *expirestr, int *r_algo, unsigned int *r_usage, u32 *r_expire, unsigned int *r_nbits, const char **r_curve, int *r_version, char **r_keygrip, u32 *r_keytime); 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 keyno, int algo, int is_primary, kbnode_t pub_root, u32 *timestamp, u32 expireval, int keygen_flags); static unsigned int get_keysize_range (int algo, unsigned int *min, unsigned int *max); /* Return the algo string for a default new key. */ const char * get_default_pubkey_algo (void) { if (opt.def_new_key_algo) { if (*opt.def_new_key_algo && !strchr (opt.def_new_key_algo, ':')) return opt.def_new_key_algo; /* To avoid checking that option every time we delay that until * here. The only thing we really need to make sure is that * there is no colon in the string so that the --gpgconf-list * command won't mess up its output. */ log_info (_("invalid value for option '%s'\n"), "--default-new-key-algo"); } return DEFAULT_STD_KEY_PARAM; } 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; if (pk) { *p++ = ' '; fingerprint_from_pk (pk, array, &n); s = array; /* Fixme: Use bin2hex */ for (i=0; i < n ; i++, s++, p += 2) snprintf (p, 3, "%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 gpg_error_t write_uid (kbnode_t root, const char *s) { PACKET *pkt = xmalloc_clear (sizeof *pkt); size_t n = strlen (s); if (n > MAX_UID_PACKET_LENGTH - 10) return gpg_error (GPG_ERR_INV_USER_ID); pkt->pkttype = PKT_USER_ID; pkt->pkt.user_id = xmalloc_clear (sizeof *pkt->pkt.user_id + n); 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)); return 0; } 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; } /* Add the key usage (i.e. key flags) in SIG from the public keys * pubkey_usage field. OPAQUE has the public key. */ int keygen_add_key_flags (PKT_signature *sig, void *opaque) { PKT_public_key *pk = opaque; do_add_key_flags (sig, pk->pubkey_usage); 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 if(type==4) log_info(_("too many AEAD 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], aead[MAX_PREFS]; int nsym=0, nhash=0, nzip=0, naead=0, val, rc=0; int mdc=1, modify=0; /* mdc defaults on, modify defaults off. */ char dummy_string[25*4+1]; /* Enough for 25 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 */ if (opt.flags.rfc4880bis && !openpgp_aead_test_algo (AEAD_ALGO_OCB)) strcat(dummy_string,"A2 "); if (opt.flags.rfc4880bis && !openpgp_aead_test_algo (AEAD_ALGO_EAX)) strcat(dummy_string,"A1 "); if (personal) { /* The default internal 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 "); } else { /* The default advertised hash algo order is: * SHA-512, SHA-384, SHA-256, SHA-224, SHA-1. */ if (!openpgp_md_test_algo (DIGEST_ALGO_SHA512)) strcat (dummy_string, "H10 "); if (!openpgp_md_test_algo (DIGEST_ALGO_SHA384)) strcat (dummy_string, "H9 "); if (!openpgp_md_test_algo (DIGEST_ALGO_SHA256)) strcat (dummy_string, "H8 "); } 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 compression. */ 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 *prefstringbuf; char *tok, *prefstring; /* We need a writable string. */ prefstring = prefstringbuf = xstrdup (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 ((val=string_to_aead_algo (tok))) { if (set_one_pref (val, 4, tok, aead, &naead)) 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 (prefstringbuf); } 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+naead_prefs+nhash_prefs+nzip_prefs+1))); for(i=0;iprefs[j].type=PREFTYPE_SYM; uid->prefs[j].value=sym_prefs[i]; } for (i=0; i < naead_prefs; i++, j++) { uid->prefs[j].type = PREFTYPE_AEAD; uid->prefs[j].value = aead_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.aead = aead_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, 1, 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_feature_aead (PKT_signature *sig, int enabled) { const byte *s; size_t n; int i; char *buf; s = parse_sig_subpkt (sig, 1, SIGSUBPKT_FEATURES, &n ); if (s && n && ((enabled && (s[0] & 0x02)) || (!enabled && !(s[0] & 0x02)))) return; /* Already set or cleared */ 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] |= 0x02; /* AEAD supported */ else buf[0] &= ~0x02; /* Are there any bits set? */ for (i=0; i < n; i++) if (buf[i]) break; if (i == n) delete_sig_subpkt (sig->hashed, SIGSUBPKT_FEATURES); else build_sig_subpkt (sig, SIGSUBPKT_FEATURES, buf, n); xfree (buf); } static void add_feature_v5 (PKT_signature *sig, int enabled) { const byte *s; size_t n; int i; char *buf; s = parse_sig_subpkt (sig, 1, SIGSUBPKT_FEATURES, &n ); if (s && n && ((enabled && (s[0] & 0x04)) || (!enabled && !(s[0] & 0x04)))) return; /* Already set or cleared */ 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] |= 0x04; /* v5 key supported */ else buf[0] &= ~0x04; /* Are there any bits set? */ for (i=0; i < n; i++) if (buf[i]) break; if (i == n) delete_sig_subpkt (sig->hashed, 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, 1, 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 (naead_prefs) build_sig_subpkt (sig, SIGSUBPKT_PREF_AEAD, aead_prefs, naead_prefs); else { delete_sig_subpkt (sig->hashed, SIGSUBPKT_PREF_AEAD); delete_sig_subpkt (sig->unhashed, SIGSUBPKT_PREF_AEAD); } 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_feature_aead (sig, aead_available); add_feature_v5 (sig, opt.flags.rfc4880bis); 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]; log_assert (revkey->fprlen <= MAX_FINGERPRINT_LEN); buf[0] = revkey->class; buf[1] = revkey->algid; memcpy (buf + 2, revkey->fpr, revkey->fprlen); memset (buf + 2 + revkey->fprlen, 0, sizeof (revkey->fpr) - revkey->fprlen); build_sig_subpkt (sig, SIGSUBPKT_REV_KEY, buf, 2+revkey->fprlen); /* 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 (ctrl_t ctrl, 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 (ctrl, &backsig, pk, NULL, sub_pk, sub_psk, 0x19, 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, NULL); 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; /* fall through */ case 1: pktlen |= buf[mark++] << 8; /* fall through */ 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 (ctrl_t ctrl, kbnode_t 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 (ctrl, &sig, pk, NULL,NULL, psk, 0x1F, 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 (ctrl_t ctrl, kbnode_t 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 (ctrl, &sig, pk, uid, NULL, psk, 0x13, 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 (ctrl_t ctrl, kbnode_t 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 (ctrl, &sig, pri_pk, NULL, sub_pk, pri_psk, 0x18, 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 (ctrl, 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 = NULL; 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, NULL); 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; err = sexp_extract_param_sos (list, "q", &array[1]); if (err) 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: xfree (curve); 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 = (keygen_flags & KEYGEN_FLAG_CREATE_V5_KEY)? 5 : 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, char **passwd_nonce_addr) { int err; PACKET *pkt; PKT_public_key *pk; gcry_sexp_t s_key; err = agent_genkey (NULL, cache_nonce_addr, passwd_nonce_addr, keyparms, !!(keygen_flags & KEYGEN_FLAG_NO_PROTECTION), passphrase, timestamp, &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 = (keygen_flags & KEYGEN_FLAG_CREATE_V5_KEY)? 5 : 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, char **passwd_nonce_addr) { int err; char *keyparms; char nbitsstr[35]; log_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, passwd_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, char **passwd_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, passwd_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, char **passwd_nonce_addr) { gpg_error_t err; char *keyparms; log_assert (algo == PUBKEY_ALGO_ECDSA || algo == PUBKEY_ALGO_EDDSA || algo == PUBKEY_ALGO_ECDH); if (!curve || !*curve) return gpg_error (GPG_ERR_UNKNOWN_CURVE); /* Map the displayed short forms of some curves to their canonical * names. */ if (!ascii_strcasecmp (curve, "cv25519")) curve = "Curve25519"; else if (!ascii_strcasecmp (curve, "ed25519")) curve = "Ed25519"; else if (!ascii_strcasecmp (curve, "cv448")) curve = "X448"; else if (!ascii_strcasecmp (curve, "ed448")) curve = "Ed448"; /* Note that we use the "comp" flag with EdDSA to request the use of a 0x40 compression prefix octet. */ if (algo == PUBKEY_ALGO_EDDSA && !strcmp (curve, "Ed25519")) 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_EDDSA && !strcmp (curve, "Ed448")) keyparms = xtryasprintf ("(genkey(ecc(curve %zu:%s)(flags 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 if (algo == PUBKEY_ALGO_ECDH && !strcmp (curve, "X448")) keyparms = xtryasprintf ("(genkey(ecc(curve %zu:%s)(flags 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, passwd_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, char **passwd_nonce_addr) { int err; char *keyparms; char nbitsstr[35]; const unsigned maxsize = (opt.flags.large_rsa ? 8192 : 4096); log_assert (is_RSA(algo)); if (!nbits) nbits = get_keysize_range (algo, NULL, NULL); if (nbits < 1024) { nbits = 3072; 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, passwd_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")); } /* Ask for the key flags and return them. CURRENT gives the current * usage which should normally be given as 0. MASK gives the allowed * flags. */ unsigned int ask_key_flags_with_mask (int algo, int subkey, unsigned int current, unsigned int mask) { /* 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 possible; if ( strlen(togglers) != 8 ) { tty_printf ("NOTE: Bad translation at %s:%d. " "Please report.\n", __FILE__, __LINE__); togglers = "11223300"; } /* Mask the possible usage flags. This is for example used for a * card based key. For ECDH we need to allows additional usages if * they are provided. */ possible = (openpgp_pk_algo_usage (algo) & mask); if (algo == PUBKEY_ALGO_ECDH) possible |= (current & (PUBKEY_USAGE_ENC |PUBKEY_USAGE_CERT |PUBKEY_USAGE_SIG |PUBKEY_USAGE_AUTH)); /* However, only primary keys may certify. */ if (subkey) possible &= ~PUBKEY_USAGE_CERT; /* Preload the current set with the possible set, without * authentication if CURRENT is 0. If CURRENT is non-zero we mask * with all possible usages. */ if (current) current &= possible; else current = (possible&~PUBKEY_USAGE_AUTH); for (;;) { tty_printf("\n"); tty_printf(_("Possible actions for this %s key: "), (algo == PUBKEY_ALGO_ECDH || algo == PUBKEY_ALGO_ECDSA || algo == PUBKEY_ALGO_EDDSA) ? "ECC" : 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 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; } unsigned int ask_key_flags (int algo, int subkey, unsigned int current) { return ask_key_flags_with_mask (algo, subkey, current, ~0); } /* 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; int algo; if (hexgrip[0] == '&') hexgrip++; err = agent_readkey (ctrl, 0, hexgrip, &public); if (err) return 0; publiclen = gcry_sexp_canon_len (public, 0, NULL, NULL); algo = get_pk_algo_from_canon_sexp (public, publiclen); xfree (public); return map_gcry_pk_to_openpgp (algo); } /* 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. If R_CARDKEY is not NULL and the keygrip has been taken from * an active card, true is stored there; if R_KEYTIME is not NULL the * creation time of that key is then stored there. */ static int ask_algo (ctrl_t ctrl, int addmode, int *r_subkey_algo, unsigned int *r_usage, char **r_keygrip, int *r_cardkey, u32 *r_keytime) { gpg_error_t err; char *keygrip = NULL; u32 keytime = 0; char *answer = NULL; int cardkey = 0; 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%s\n"), 1, ""); #endif if (!addmode && opt.compliance != CO_DE_VS) tty_printf (_(" (%d) DSA and Elgamal%s\n"), 2, ""); if (opt.compliance != CO_DE_VS) tty_printf (_(" (%d) DSA (sign only)%s\n"), 3, ""); #if GPG_USE_RSA tty_printf (_(" (%d) RSA (sign only)%s\n"), 4, ""); #endif if (addmode) { if (opt.compliance != CO_DE_VS) tty_printf (_(" (%d) Elgamal (encrypt only)%s\n"), 5, ""); #if GPG_USE_RSA tty_printf (_(" (%d) RSA (encrypt only)%s\n"), 6, ""); #endif } if (opt.expert) { if (opt.compliance != CO_DE_VS) tty_printf (_(" (%d) DSA (set your own capabilities)%s\n"), 7, ""); #if GPG_USE_RSA tty_printf (_(" (%d) RSA (set your own capabilities)%s\n"), 8, ""); #endif } #if GPG_USE_ECDSA || GPG_USE_ECDH || GPG_USE_EDDSA if (!addmode) tty_printf (_(" (%d) ECC (sign and encrypt)%s\n"), 9, _(" *default*") ); tty_printf (_(" (%d) ECC (sign only)\n"), 10 ); if (opt.expert) tty_printf (_(" (%d) ECC (set your own capabilities)%s\n"), 11, ""); if (addmode) tty_printf (_(" (%d) ECC (encrypt only)%s\n"), 12, ""); #endif if (opt.expert && r_keygrip) tty_printf (_(" (%d) Existing key%s\n"), 13, ""); if (r_keygrip) tty_printf (_(" (%d) Existing key from card%s\n"), 14, ""); for (;;) { *r_usage = 0; *r_subkey_algo = 0; xfree (answer); answer = cpr_get ("keygen.algo", _("Your selection? ")); cpr_kill_prompt (); algo = *answer? atoi (answer) : 9; /* Default algo is 9 */ if (opt.compliance == CO_DE_VS && (algo == 2 || algo == 3 || algo == 5 || algo == 7)) { tty_printf (_("Invalid selection.\n")); } else 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, 0); break; } else if ((algo == 8 || !strcmp (answer, "rsa/*")) && opt.expert) { algo = PUBKEY_ALGO_RSA; *r_usage = ask_key_flags (algo, addmode, 0); break; } else if ((algo == 9 || !strcmp (answer, "ecc+ecc")) && !addmode) { algo = PUBKEY_ALGO_ECDSA; *r_subkey_algo = PUBKEY_ALGO_ECDH; break; } else if ((algo == 10 || !strcmp (answer, "ecc/s"))) { 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, 0); break; } else if ((algo == 12 || !strcmp (answer, "ecc/e")) && 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, 0); break; } else if ((algo == 14 || !strcmp (answer, "cardkey")) && r_keygrip) { char *serialno; keypair_info_t keypairlist, kpi; int count, selection; err = agent_scd_serialno (&serialno, NULL); if (err) { tty_printf (_("error reading the card: %s\n"), gpg_strerror (err)); goto ask_again; } tty_printf (_("Serial number of the card: %s\n"), serialno); xfree (serialno); err = agent_scd_keypairinfo (ctrl, NULL, &keypairlist); if (err) { tty_printf (_("error reading the card: %s\n"), gpg_strerror (err)); goto ask_again; } do { char *authkeyref, *encrkeyref, *signkeyref; agent_scd_getattr_one ("$AUTHKEYID", &authkeyref); agent_scd_getattr_one ("$ENCRKEYID", &encrkeyref); agent_scd_getattr_one ("$SIGNKEYID", &signkeyref); tty_printf (_("Available keys:\n")); for (count=1, kpi=keypairlist; kpi; kpi = kpi->next, count++) { gcry_sexp_t s_pkey; char *algostr = NULL; enum gcry_pk_algos algoid = 0; const char *keyref = kpi->idstr; int any = 0; if (keyref && !agent_scd_readkey (ctrl, keyref, &s_pkey, NULL)) { algostr = pubkey_algo_string (s_pkey, &algoid); gcry_sexp_release (s_pkey); } /* We need to tweak the algo in case GCRY_PK_ECC is * returned because pubkey_algo_string is not aware * of the OpenPGP algo mapping. We need to * distinguish between ECDH and ECDSA but we can do * that only if we got usage flags. * Note: Keep this in sync with parse_key_parameter_part. */ if (algoid == GCRY_PK_ECC && algostr) { if (!strcmp (algostr, "ed25519")) kpi->algo = PUBKEY_ALGO_EDDSA; else if (!strcmp (algostr, "ed448")) kpi->algo = PUBKEY_ALGO_EDDSA; else if (!strcmp (algostr, "cv25519")) kpi->algo = PUBKEY_ALGO_ECDH; else if (!strcmp (algostr, "cv448")) kpi->algo = PUBKEY_ALGO_ECDH; else if ((kpi->usage & GCRY_PK_USAGE_ENCR)) kpi->algo = PUBKEY_ALGO_ECDH; else kpi->algo = PUBKEY_ALGO_ECDSA; } else kpi->algo = map_gcry_pk_to_openpgp (algoid); tty_printf (" (%d) %s %s %s", count, kpi->keygrip, keyref, algostr); if ((kpi->usage & GCRY_PK_USAGE_CERT)) { tty_printf ("%scert", any?",":" ("); any = 1; } if ((kpi->usage & GCRY_PK_USAGE_SIGN)) { tty_printf ("%ssign%s", any?",":" (", (signkeyref && keyref && !strcmp (signkeyref, keyref))? "*":""); any = 1; } if ((kpi->usage & GCRY_PK_USAGE_AUTH)) { tty_printf ("%sauth%s", any?",":" (", (authkeyref && keyref && !strcmp (authkeyref, keyref))? "*":""); any = 1; } if ((kpi->usage & GCRY_PK_USAGE_ENCR)) { tty_printf ("%sencr%s", any?",":" (", (encrkeyref && keyref && !strcmp (encrkeyref, keyref))? "*":""); any = 1; } tty_printf ("%s\n", any?")":""); xfree (algostr); } xfree (answer); answer = cpr_get ("keygen.cardkey", _("Your selection? ")); cpr_kill_prompt (); trim_spaces (answer); selection = atoi (answer); xfree (authkeyref); xfree (encrkeyref); xfree (signkeyref); } while (!(selection > 0 && selection < count)); for (count=1,kpi=keypairlist; kpi; kpi = kpi->next, count++) if (count == selection) break; if (!kpi) { /* Just in case COUNT is zero (no keys). */ free_keypair_info (keypairlist); goto ask_again; } xfree (keygrip); keygrip = xstrdup (kpi->keygrip); cardkey = 1; algo = kpi->algo; keytime = kpi->keytime; /* In expert mode allow to change the usage flags. */ if (opt.expert) *r_usage = ask_key_flags_with_mask (algo, addmode, kpi->usage, kpi->usage); else { *r_usage = kpi->usage; if (addmode) *r_usage &= ~GCRY_PK_USAGE_CERT; } free_keypair_info (keypairlist); break; } else tty_printf (_("Invalid selection.\n")); ask_again: ; } xfree(answer); if (r_keygrip) *r_keygrip = keygrip; if (r_cardkey) *r_cardkey = cardkey; if (r_keytime) *r_keytime = keytime; return algo; } static unsigned int get_keysize_range (int algo, unsigned int *min, unsigned int *max) { unsigned int def; unsigned int dummy1, dummy2; if (!min) min = &dummy1; if (!max) max = &dummy2; switch(algo) { case PUBKEY_ALGO_DSA: *min = opt.expert? 768 : 1024; *max=3072; def=2048; break; case PUBKEY_ALGO_ECDSA: case PUBKEY_ALGO_ECDH: *min=256; *max=521; def=256; break; case PUBKEY_ALGO_EDDSA: *min=255; *max=441; def=255; break; default: *min = opt.compliance == CO_DE_VS ? 2048: 1024; *max = 4096; def = 3072; break; } return def; } /* Return a fixed up keysize depending on ALGO. */ static unsigned int fixup_keysize (unsigned int nbits, int algo, int silent) { if (algo == PUBKEY_ALGO_DSA && (nbits % 64)) { nbits = ((nbits + 63) / 64) * 64; if (!silent) 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 (!silent) 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 (!silent) tty_printf (_("rounded to %u bits\n"), nbits); } } else if ((nbits % 32)) { nbits = ((nbits + 31) / 32) * 32; if (!silent) tty_printf (_("rounded up to %u bits\n"), nbits ); } return nbits; } /* 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; unsigned int min, def, max; int for_subkey = !!primary_keysize; int autocomp = 0; def = get_keysize_range (algo, &min, &max); 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; } 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: nbits = fixup_keysize (nbits, algo, autocomp); return nbits; } /* Ask for the curve. ALGO is the selected algorithm which this function may adjust. Returns a const string of the name of the curve. */ const char * ask_curve (int *algo, int *subkey_algo, const char *current) { /* NB: We always use a complete algo list so that we have stable numbers in the menu regardless on how Gpg was configured. */ struct { const char *name; const char* eddsa_curve; /* Corresponding EdDSA curve. */ const char *pretty_name; unsigned int supported : 1; /* Supported by gpg. */ unsigned int de_vs : 1; /* Allowed in CO_DE_VS. */ unsigned int expert_only : 1; /* Only with --expert */ unsigned int available : 1; /* Available in Libycrypt (runtime checked) */ } curves[] = { #if GPG_USE_ECDSA || GPG_USE_ECDH # define MY_USE_ECDSADH 1 #else # define MY_USE_ECDSADH 0 #endif { "Curve25519", "Ed25519", "Curve 25519", !!GPG_USE_EDDSA, 0, 0, 0 }, { "X448", "Ed448", "Curve 448", !!GPG_USE_EDDSA, 0, 1, 0 }, { "NIST P-256", NULL, NULL, MY_USE_ECDSADH, 0, 1, 0 }, { "NIST P-384", NULL, NULL, MY_USE_ECDSADH, 0, 0, 0 }, { "NIST P-521", NULL, NULL, MY_USE_ECDSADH, 0, 1, 0 }, { "brainpoolP256r1", NULL, "Brainpool P-256", MY_USE_ECDSADH, 1, 0, 0 }, { "brainpoolP384r1", NULL, "Brainpool P-384", MY_USE_ECDSADH, 1, 1, 0 }, { "brainpoolP512r1", NULL, "Brainpool P-512", MY_USE_ECDSADH, 1, 1, 0 }, { "secp256k1", NULL, NULL, MY_USE_ECDSADH, 0, 1, 0 }, }; #undef MY_USE_ECDSADH int idx; char *answer; const char *result = NULL; gcry_sexp_t keyparms; tty_printf (_("Please select which elliptic curve you want:\n")); keyparms = NULL; for (idx=0; idx < DIM(curves); idx++) { int rc; curves[idx].available = 0; if (!curves[idx].supported) continue; if (opt.compliance==CO_DE_VS) { if (!curves[idx].de_vs) continue; /* Not allowed. */ } else if (!opt.expert && curves[idx].expert_only) continue; /* We need to switch from the ECDH name of the curve to the EDDSA name of the curve if we want a signing key. */ gcry_sexp_release (keyparms); rc = gcry_sexp_build (&keyparms, NULL, "(public-key(ecc(curve %s)))", curves[idx].eddsa_curve? curves[idx].eddsa_curve /**/ : curves[idx].name); if (rc) continue; if (!gcry_pk_get_curve (keyparms, 0, NULL)) continue; if (subkey_algo && curves[idx].eddsa_curve) { /* Both Curve 25519 (or 448) keys are to be created. Check that Libgcrypt also supports the real Curve25519 (or 448). */ 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%s\n", idx + 1, curves[idx].pretty_name? curves[idx].pretty_name:curves[idx].name, idx == 0? _(" *default*"):""); } gcry_sexp_release (keyparms); for (;;) { answer = cpr_get ("keygen.curve", _("Your selection? ")); cpr_kill_prompt (); idx = *answer? atoi (answer) : 1; if (!*answer && current) { xfree(answer); return NULL; } else 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 the user selected a signing algorithm and Curve25519 we need to set the algo to EdDSA and update the curve name. If switching away from EdDSA, we need to set the algo back to ECDSA. */ if (*algo == PUBKEY_ALGO_ECDSA || *algo == PUBKEY_ALGO_EDDSA) { if (curves[idx].eddsa_curve) { if (subkey_algo && *subkey_algo == PUBKEY_ALGO_ECDSA) *subkey_algo = PUBKEY_ALGO_EDDSA; *algo = PUBKEY_ALGO_EDDSA; result = curves[idx].eddsa_curve; } else { if (subkey_algo && *subkey_algo == PUBKEY_ALGO_EDDSA) *subkey_algo = PUBKEY_ALGO_ECDSA; *algo = PUBKEY_ALGO_ECDSA; result = curves[idx].name; } } else result = curves[idx].name; break; } } if (!result) result = 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 || !*string || !strcmp (string, "none") || !strcmp (string, "never") || !strcmp (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; } /* Parse a 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; prompt = xasprintf (_("Signature is valid for? (%s) "), def_expire); 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 (*aname && strlen (aname) < 5) { tty_printf(_("Name must be at least 5 characters long\n")); /* However, we allow an empty name. */ } 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); if (!*aname && *amail && !*acomment && !random_is_faked ()) { /* Empty name and comment but with mail address. Use simplified form with only the non-angle-bracketed mail address. */ p = stpcpy (p, amail); } else { 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; } /* 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_t pub_root, u32 timestamp, u32 expiredate, int is_subkey, int keygen_flags, const char *passphrase, char **cache_nonce_addr, char **passwd_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, passwd_nonce_addr); else if (algo == PUBKEY_ALGO_DSA) err = gen_dsa (nbits, pub_root, timestamp, expiredate, is_subkey, keygen_flags, passphrase, cache_nonce_addr, passwd_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, passwd_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, passwd_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; } /* Helper for parse_key_parameter_part_parameter_string for one part of the * specification string; i.e. ALGO/FLAGS. If STRING is NULL or empty * success is returned. On error an error code is returned. Note * that STRING may be modified by this function. NULL may be passed * for any parameter. FOR_SUBKEY shall be true if this is used as a * subkey. If CLEAR_CERT is set a default CERT usage will be cleared; * this is useful if for example the default algorithm is used for a * subkey. If R_KEYVERSION is not NULL it will receive the version of * the key; this is currently 4 but can be changed with the flag "v5" * to create a v5 key. If R_KEYTIME is not NULL and the key has been * taken from active OpenPGP card, its creation time is stored * there. */ static gpg_error_t parse_key_parameter_part (ctrl_t ctrl, char *string, int for_subkey, int clear_cert, int *r_algo, unsigned int *r_size, unsigned int *r_keyuse, char const **r_curve, int *r_keyversion, char **r_keygrip, u32 *r_keytime) { gpg_error_t err; char *flags; int algo; char *endp; const char *curve = NULL; int ecdh_or_ecdsa = 0; unsigned int size; int keyuse; int keyversion = 0; /* Not specified. */ int i; const char *s; int from_card = 0; char *keygrip = NULL; u32 keytime = 0; int is_448 = 0; if (!string || !*string) return 0; /* Success. */ flags = strchr (string, '/'); if (flags) *flags++ = 0; algo = 0; if (!ascii_strcasecmp (string, "card")) from_card = 1; else if (strlen (string) >= 3 && (digitp (string+3) || !string[3])) { if (!ascii_memcasecmp (string, "rsa", 3)) algo = PUBKEY_ALGO_RSA; else if (!ascii_memcasecmp (string, "dsa", 3)) algo = PUBKEY_ALGO_DSA; else if (!ascii_memcasecmp (string, "elg", 3)) algo = PUBKEY_ALGO_ELGAMAL_E; } if (from_card) ; /* We need the flags before we can figure out the key to use. */ else if (algo) { if (!string[3]) size = get_keysize_range (algo, NULL, NULL); else { size = strtoul (string+3, &endp, 10); if (size < 512 || size > 16384 || *endp) return gpg_error (GPG_ERR_INV_VALUE); } } else if ((curve = openpgp_is_curve_supported (string, &algo, &size))) { if (!algo) { algo = PUBKEY_ALGO_ECDH; /* Default ECC algorithm. */ ecdh_or_ecdsa = 1; /* We may need to switch the algo. */ } if (curve && (!strcmp (curve, "X448") || !strcmp (curve, "Ed448"))) is_448 = 1; } else return gpg_error (GPG_ERR_UNKNOWN_CURVE); /* Parse the flags. */ keyuse = 0; if (flags) { char **tokens = NULL; tokens = strtokenize (flags, ","); if (!tokens) return gpg_error_from_syserror (); for (i=0; (s = tokens[i]); i++) { if (!*s) ; else if (!ascii_strcasecmp (s, "sign")) keyuse |= PUBKEY_USAGE_SIG; else if (!ascii_strcasecmp (s, "encrypt") || !ascii_strcasecmp (s, "encr")) keyuse |= PUBKEY_USAGE_ENC; else if (!ascii_strcasecmp (s, "auth")) keyuse |= PUBKEY_USAGE_AUTH; else if (!ascii_strcasecmp (s, "cert")) keyuse |= PUBKEY_USAGE_CERT; else if (!ascii_strcasecmp (s, "ecdsa") && !from_card) { if (algo == PUBKEY_ALGO_ECDH || algo == PUBKEY_ALGO_ECDSA) algo = PUBKEY_ALGO_ECDSA; else { xfree (tokens); return gpg_error (GPG_ERR_INV_FLAG); } ecdh_or_ecdsa = 0; } else if (!ascii_strcasecmp (s, "ecdh") && !from_card) { if (algo == PUBKEY_ALGO_ECDH || algo == PUBKEY_ALGO_ECDSA) algo = PUBKEY_ALGO_ECDH; else { xfree (tokens); return gpg_error (GPG_ERR_INV_FLAG); } ecdh_or_ecdsa = 0; } else if (!ascii_strcasecmp (s, "eddsa") && !from_card) { /* Not required but we allow it for consistency. */ if (algo == PUBKEY_ALGO_EDDSA) ; else { xfree (tokens); return gpg_error (GPG_ERR_INV_FLAG); } } else if (!ascii_strcasecmp (s, "v5")) { if (opt.flags.rfc4880bis) keyversion = 5; } else if (!ascii_strcasecmp (s, "v4")) keyversion = 4; else { xfree (tokens); return gpg_error (GPG_ERR_UNKNOWN_FLAG); } } xfree (tokens); } /* If not yet decided switch between ecdh and ecdsa unless we want * to read the algo from the current card. */ if (from_card) { keypair_info_t keypairlist, kpi; char *reqkeyref; if (!keyuse) keyuse = (for_subkey? PUBKEY_USAGE_ENC /* */ : (PUBKEY_USAGE_CERT|PUBKEY_USAGE_SIG)); /* Access the card to make sure we have one and to show the S/N. */ { char *serialno; err = agent_scd_serialno (&serialno, NULL); if (err) { log_error (_("error reading the card: %s\n"), gpg_strerror (err)); return err; } if (!opt.quiet) log_info (_("Serial number of the card: %s\n"), serialno); xfree (serialno); } err = agent_scd_keypairinfo (ctrl, NULL, &keypairlist); if (err) { log_error (_("error reading the card: %s\n"), gpg_strerror (err)); return err; } agent_scd_getattr_one ((keyuse & (PUBKEY_USAGE_SIG|PUBKEY_USAGE_CERT)) ? "$SIGNKEYID":"$ENCRKEYID", &reqkeyref); algo = 0; /* Should already be the case. */ for (kpi=keypairlist; kpi && !algo; kpi = kpi->next) { gcry_sexp_t s_pkey; char *algostr = NULL; enum gcry_pk_algos algoid = 0; const char *keyref = kpi->idstr; if (!reqkeyref) continue; /* Card does not provide the info (skip all). */ if (!keyref) continue; /* Ooops. */ if (strcmp (reqkeyref, keyref)) continue; /* This is not the requested keyref. */ if ((keyuse & (PUBKEY_USAGE_SIG|PUBKEY_USAGE_CERT)) && (kpi->usage & (GCRY_PK_USAGE_SIGN|GCRY_PK_USAGE_CERT))) ; /* Okay */ else if ((keyuse & PUBKEY_USAGE_ENC) && (kpi->usage & GCRY_PK_USAGE_ENCR)) ; /* Okay */ else continue; /* Not usable for us. */ if (agent_scd_readkey (ctrl, keyref, &s_pkey, NULL)) continue; /* Could not read the key. */ algostr = pubkey_algo_string (s_pkey, &algoid); gcry_sexp_release (s_pkey); /* Map to OpenPGP algo number. * We need to tweak the algo in case GCRY_PK_ECC is * returned because pubkey_algo_string is not aware * of the OpenPGP algo mapping. We need to * distinguish between ECDH and ECDSA but we can do * that only if we got usage flags. * Note: Keep this in sync with ask_algo. */ if (algoid == GCRY_PK_ECC && algostr) { if (!strcmp (algostr, "ed25519")) algo = PUBKEY_ALGO_EDDSA; else if (!strcmp (algostr, "ed448")) { algo = PUBKEY_ALGO_EDDSA; is_448 = 1; } else if (!strcmp (algostr, "cv25519")) algo = PUBKEY_ALGO_ECDH; else if (!strcmp (algostr, "cv448")) { algo = PUBKEY_ALGO_ECDH; is_448 = 1; } else if ((kpi->usage & GCRY_PK_USAGE_ENCR)) algo = PUBKEY_ALGO_ECDH; else algo = PUBKEY_ALGO_ECDSA; } else algo = map_gcry_pk_to_openpgp (algoid); xfree (algostr); xfree (keygrip); keygrip = xtrystrdup (kpi->keygrip); if (!keygrip) { err = gpg_error_from_syserror (); xfree (reqkeyref); free_keypair_info (keypairlist); return err; } keytime = kpi->keytime; } xfree (reqkeyref); free_keypair_info (keypairlist); if (!algo || !keygrip) { err = gpg_error (GPG_ERR_PUBKEY_ALGO); log_error ("no usable key on the card: %s\n", gpg_strerror (err)); xfree (keygrip); return err; } } else if (ecdh_or_ecdsa && keyuse) algo = (keyuse & PUBKEY_USAGE_ENC)? PUBKEY_ALGO_ECDH : PUBKEY_ALGO_ECDSA; else if (ecdh_or_ecdsa) algo = for_subkey? PUBKEY_ALGO_ECDH : PUBKEY_ALGO_ECDSA; /* Set or fix key usage. */ if (!keyuse) { if (algo == PUBKEY_ALGO_ECDSA || algo == PUBKEY_ALGO_EDDSA || algo == PUBKEY_ALGO_DSA) keyuse = PUBKEY_USAGE_SIG; else if (algo == PUBKEY_ALGO_RSA) keyuse = for_subkey? PUBKEY_USAGE_ENC : PUBKEY_USAGE_SIG; else keyuse = PUBKEY_USAGE_ENC; } else if (algo == PUBKEY_ALGO_ECDSA || algo == PUBKEY_ALGO_EDDSA || algo == PUBKEY_ALGO_DSA) { keyuse &= ~PUBKEY_USAGE_ENC; /* Forbid encryption. */ } else if (algo == PUBKEY_ALGO_ECDH || algo == PUBKEY_ALGO_ELGAMAL_E) { keyuse = PUBKEY_USAGE_ENC; /* Allow only encryption. */ } /* Make sure a primary key can certify. */ if (!for_subkey) keyuse |= PUBKEY_USAGE_CERT; /* But if requested remove th cert usage. */ if (clear_cert) keyuse &= ~PUBKEY_USAGE_CERT; /* Check that usage is actually possible. */ if (/**/((keyuse & (PUBKEY_USAGE_SIG|PUBKEY_USAGE_AUTH|PUBKEY_USAGE_CERT)) && !pubkey_get_nsig (algo)) || ((keyuse & PUBKEY_USAGE_ENC) && !pubkey_get_nenc (algo)) || (for_subkey && (keyuse & PUBKEY_USAGE_CERT))) { xfree (keygrip); return gpg_error (GPG_ERR_WRONG_KEY_USAGE); } /* Ed448 and X448 must only be used as v5 keys. */ if (is_448) { if (keyversion == 4) log_info (_("WARNING: v4 is specified, but overridden by v5.\n")); keyversion = 5; } else if (keyversion == 0) keyversion = 4; /* Return values. */ if (r_algo) *r_algo = algo; if (r_size) { unsigned int min, def, max; /* Make sure the keysize is in the allowed range. */ def = get_keysize_range (algo, &min, &max); if (!size) size = def; else if (size < min) size = min; else if (size > max) size = max; *r_size = fixup_keysize (size, algo, 1); } if (r_keyuse) *r_keyuse = keyuse; if (r_curve) *r_curve = curve; if (r_keyversion) *r_keyversion = keyversion; if (r_keygrip) *r_keygrip = keygrip; else xfree (keygrip); if (r_keytime) *r_keytime = keytime; return 0; } /* Parse and return the standard key generation parameter. * The string is expected to be in this format: * * ALGO[/FLAGS][+SUBALGO[/FLAGS]] * * Here ALGO is a string in the same format as printed by the * keylisting. For example: * * rsa3072 := RSA with 3072 bit. * dsa2048 := DSA with 2048 bit. * elg2048 := Elgamal with 2048 bit. * ed25519 := EDDSA using curve Ed25519. * ed448 := EDDSA using curve Ed448. * cv25519 := ECDH using curve Curve25519. * cv448 := ECDH using curve X448. * nistp256:= ECDSA or ECDH using curve NIST P-256 * * All strings with an unknown prefix are considered an elliptic * curve. Curves which have no implicit algorithm require that FLAGS * is given to select whether ECDSA or ECDH is used; this can either * be done using an algorithm keyword or usage keywords. * * FLAGS is a comma delimited string of keywords: * * cert := Allow usage Certify * sign := Allow usage Sign * encr := Allow usage Encrypt * auth := Allow usage Authentication * encrypt := Alias for "encr" * ecdsa := Use algorithm ECDSA. * eddsa := Use algorithm EdDSA. * ecdh := Use algorithm ECDH. * v5 := Create version 5 key (requires option --rfc4880bis) * * There are several defaults and fallbacks depending on the * algorithm. PART can be used to select which part of STRING is * used: * -1 := Both parts * 0 := Only the part of the primary key * 1 := If there is one part parse that one, if there are * two parts parse the part which best matches the * SUGGESTED_USE or in case that can't be evaluated the second part. * Always return using the args for the primary key (R_ALGO,....). * */ gpg_error_t parse_key_parameter_string (ctrl_t ctrl, const char *string, int part, unsigned int suggested_use, int *r_algo, unsigned int *r_size, unsigned int *r_keyuse, char const **r_curve, int *r_version, char **r_keygrip, u32 *r_keytime, int *r_subalgo, unsigned int *r_subsize, unsigned int *r_subkeyuse, char const **r_subcurve, int *r_subversion, char **r_subkeygrip, u32 *r_subkeytime) { gpg_error_t err = 0; char *primary, *secondary; if (r_algo) *r_algo = 0; if (r_size) *r_size = 0; if (r_keyuse) *r_keyuse = 0; if (r_curve) *r_curve = NULL; if (r_version) *r_version = 4; if (r_keygrip) *r_keygrip = NULL; if (r_keytime) *r_keytime = 0; if (r_subalgo) *r_subalgo = 0; if (r_subsize) *r_subsize = 0; if (r_subkeyuse) *r_subkeyuse = 0; if (r_subcurve) *r_subcurve = NULL; if (r_subversion) *r_subversion = 4; if (r_subkeygrip) *r_subkeygrip = NULL; if (r_subkeytime) *r_subkeytime = 0; if (!string || !*string || !ascii_strcasecmp (string, "default") || !strcmp (string, "-")) string = get_default_pubkey_algo (); else if (!ascii_strcasecmp (string, "future-default") || !ascii_strcasecmp (string, "futuredefault")) string = FUTURE_STD_KEY_PARAM; else if (!ascii_strcasecmp (string, "card")) string = "card/cert,sign+card/encr"; primary = xstrdup (string); secondary = strchr (primary, '+'); if (secondary) *secondary++ = 0; if (part == -1 || part == 0) { err = parse_key_parameter_part (ctrl, primary, 0, 0, r_algo, r_size, r_keyuse, r_curve, r_version, r_keygrip, r_keytime); if (!err && part == -1) err = parse_key_parameter_part (ctrl, secondary, 1, 0, r_subalgo, r_subsize, r_subkeyuse, r_subcurve, r_subversion, r_subkeygrip, r_subkeytime); } else if (part == 1) { /* If we have SECONDARY, use that part. If there is only one * part consider this to be the subkey algo. In case a * SUGGESTED_USE has been given and the usage of the secondary * part does not match SUGGESTED_USE try again using the primary * part. Note that when falling back to the primary key we need * to force clearing the cert usage. */ if (secondary) { err = parse_key_parameter_part (ctrl, secondary, 1, 0, r_algo, r_size, r_keyuse, r_curve, r_version, r_keygrip, r_keytime); if (!err && suggested_use && r_keyuse && !(suggested_use & *r_keyuse)) err = parse_key_parameter_part (ctrl, primary, 1, 1 /*(clear cert)*/, r_algo, r_size, r_keyuse, r_curve, r_version, r_keygrip, r_keytime); } else err = parse_key_parameter_part (ctrl, primary, 1, 0, r_algo, r_size, r_keyuse, r_curve, r_version, r_keygrip, r_keytime); } xfree (primary); return err; } /* Append R to the linked list PARA. */ static void append_to_parameter (struct para_data_s *para, struct para_data_s *r) { log_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 (ctrl_t ctrl, 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. */ /* FIXME: We only allow the algo here and have a separate thing * for the curve etc. That is a ugly but demanded for backward * compatibility with the batch key generation. It would be * better to make full use of parse_key_parameter_string. */ parse_key_parameter_string (ctrl, NULL, 0, 0, &i, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL); 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_gcry_pk_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 a usage string. The usage keywords "auth", "sign", "encr" * may be delimited by space, tab, or comma. On error -1 is returned * instead of the usage flags. */ static int parse_usagestr (const char *usagestr) { gpg_error_t err; char **tokens = NULL; const char *s; int i; unsigned int use = 0; tokens = strtokenize (usagestr, " \t,"); if (!tokens) { err = gpg_error_from_syserror (); log_error ("strtokenize failed: %s\n", gpg_strerror (err)); return -1; } for (i=0; (s = tokens[i]); i++) { if (!*s) ; else if (!ascii_strcasecmp (s, "sign")) use |= PUBKEY_USAGE_SIG; else if (!ascii_strcasecmp (s, "encrypt") || !ascii_strcasecmp (s, "encr")) use |= PUBKEY_USAGE_ENC; else if (!ascii_strcasecmp (s, "auth")) use |= PUBKEY_USAGE_AUTH; else if (!ascii_strcasecmp (s, "cert")) use |= PUBKEY_USAGE_CERT; else { xfree (tokens); return -1; /* error */ } } xfree (tokens); return use; } /* * 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 ); int i; if (!r) return 0; /* none (this is an optional parameter)*/ i = parse_usagestr (r->u.value); if (i == -1) { log_error ("%s:%d: invalid usage list\n", fname, r->lnr ); return -1; /* error */ } r->u.usage = i; 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 || r->key == pSUBKEYCREATIONDATE || r->key == pAUTHKEYCREATIONDATE) 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 get_parameter_bool (struct para_data_s *para, enum para_name key) { struct para_data_s *r = get_parameter (para, key); return (r && r->u.abool); } 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 (ctrl, 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 (ctrl, 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 ) { /* If we have only the email part, do not add the space * and the angle brackets. */ if (*r->u.value) p = stpcpy(stpcpy(stpcpy(p," <"), s3 ),">"); else p = 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 { r = get_parameter (para, pKEYSERVER); 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. We ignore this if the * key has been taken from a card and a keycreationtime has already * been set. This is so that we don't generate a key with a * fingerprint different from the one stored on the OpenPGP card. */ r = get_parameter (para, pCREATIONDATE); if (r && *r->u.value && !(get_parameter_bool (para, pCARDKEY) && get_parameter_u32 (para, pKEYCREATIONDATE))) { 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 }, { "Keygrip", pKEYGRIP }, { "Key-Grip", pKEYGRIP }, { "Subkey-grip", pSUBKEYGRIP }, { "Key-Version", pVERSION }, { "Subkey-Version", pSUBVERSION }, { 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; nline = 0; 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; } } if (!opt.flags.rfc4880bis && (keywords[i].key == pVERSION || keywords[i].key == pSUBVERSION)) ; /* Ignore version unless --rfc4880bis is active. */ else { 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 ); } xfree (line); 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, unsigned int use, int version, const char *keygrip, u32 keytime) { struct para_data_s *r; r = xmalloc_clear (sizeof *r + 30); r->key = for_subkey? pSUBKEYUSAGE : pKEYUSAGE; if (use) snprintf (r->u.value, 30, "%s%s%s%s", (use & PUBKEY_USAGE_ENC)? "encr " : "", (use & PUBKEY_USAGE_SIG)? "sign " : "", (use & PUBKEY_USAGE_AUTH)? "auth " : "", (use & PUBKEY_USAGE_CERT)? "cert " : ""); else strcpy (r->u.value, for_subkey ? "encr" : "sign"); r->next = para; para = r; r = xmalloc_clear (sizeof *r + 20); r->key = for_subkey? pSUBKEYTYPE : pKEYTYPE; snprintf (r->u.value, 20, "%d", algo); r->next = para; para = r; if (keygrip) { r = xmalloc_clear (sizeof *r + strlen (keygrip)); r->key = for_subkey? pSUBKEYGRIP : pKEYGRIP; strcpy (r->u.value, keygrip); r->next = para; para = r; } else 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; } if (opt.flags.rfc4880bis) { r = xmalloc_clear (sizeof *r + 20); r->key = for_subkey? pSUBVERSION : pVERSION; snprintf (r->u.value, 20, "%d", version); r->next = para; para = r; } if (keytime) { r = xmalloc_clear (sizeof *r); r->key = for_subkey? pSUBKEYCREATIONDATE : pKEYCREATIONDATE; r->u.creation = keytime; r->next = para; para = r; } return para; } /* * Unattended generation of a standard key. */ void quick_generate_keypair (ctrl_t ctrl, const char *uid, const char *algostr, const char *usagestr, const char *expirestr) { 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 && !*algostr && !*usagestr && !*expirestr && !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 (ctrl); 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)) { write_status_error ("genkey", gpg_error (304)); log_inc_errorcount (); /* we used log_info */ goto leave; } log_info (_("creating anyway\n")); } } if (!*expirestr || strcmp (expirestr, "-") == 0) expirestr = default_expiration_interval; if ((!*algostr || !ascii_strcasecmp (algostr, "default") || !ascii_strcasecmp (algostr, "future-default") || !ascii_strcasecmp (algostr, "futuredefault") || !ascii_strcasecmp (algostr, "card")) && (!*usagestr || !ascii_strcasecmp (usagestr, "default") || !strcmp (usagestr, "-"))) { /* Use default key parameters. */ int algo, subalgo, version, subversion; unsigned int size, subsize; unsigned int keyuse, subkeyuse; const char *curve, *subcurve; char *keygrip, *subkeygrip; u32 keytime, subkeytime; err = parse_key_parameter_string (ctrl, algostr, -1, 0, &algo, &size, &keyuse, &curve, &version, &keygrip, &keytime, &subalgo, &subsize, &subkeyuse, &subcurve, &subversion, &subkeygrip, &subkeytime); if (err) { log_error (_("Key generation failed: %s\n"), gpg_strerror (err)); goto leave; } para = quickgen_set_para (para, 0, algo, size, curve, keyuse, version, keygrip, keytime); if (subalgo) para = quickgen_set_para (para, 1, subalgo, subsize, subcurve, subkeyuse, subversion, subkeygrip, subkeytime); if (*expirestr) { u32 expire; expire = parse_expire_string (expirestr); if (expire == (u32)-1 ) { err = gpg_error (GPG_ERR_INV_VALUE); log_error (_("Key generation failed: %s\n"), gpg_strerror (err)); goto leave; } r = xmalloc_clear (sizeof *r + 20); r->key = pKEYEXPIRE; r->u.expire = expire; r->next = para; para = r; } xfree (keygrip); xfree (subkeygrip); } else { /* Extended unattended mode. Creates only the primary key. */ int algo, version; unsigned int use; u32 expire; unsigned int nbits; const char *curve; char *keygrip; u32 keytime; err = parse_algo_usage_expire (ctrl, 0, algostr, usagestr, expirestr, &algo, &use, &expire, &nbits, &curve, &version, &keygrip, &keytime); if (err) { log_error (_("Key generation failed: %s\n"), gpg_strerror (err) ); goto leave; } para = quickgen_set_para (para, 0, algo, nbits, curve, use, version, keygrip, keytime); r = xmalloc_clear (sizeof *r + 20); r->key = pKEYEXPIRE; r->u.expire = expire; r->next = para; para = r; xfree (keygrip); } /* 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; } if (!ascii_strcasecmp (algostr, "card") || !ascii_strncasecmp (algostr, "card/", 5)) { r = xmalloc_clear (sizeof *r); r->key = pCARDKEY; r->u.abool = 1; 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) { gpg_error_t err; 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 with a card * serial number. */ log_error (_("can't do this in batch mode\n")); print_further_info ("key generation with card serial number"); return; } if (opt.batch) { read_parameter_file (ctrl, fname); return; } if (card_serialno) { #ifdef ENABLE_CARD_SUPPORT struct agent_card_info_s info; memset (&info, 0, sizeof (info)); err = agent_scd_getattr ("KEY-ATTR", &info); if (err) { log_error (_("error getting current key info: %s\n"), gpg_strerror (err)); return; } r = xcalloc (1, sizeof *r + strlen (card_serialno) ); r->key = pSERIALNO; strcpy( r->u.value, card_serialno); r->next = para; para = r; r = xcalloc (1, sizeof *r + 20 ); r->key = pKEYTYPE; sprintf( r->u.value, "%d", info.key_attr[0].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", info.key_attr[1].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; if (info.key_attr[1].algo == PUBKEY_ALGO_RSA) { r = xcalloc (1, sizeof *r + 20 ); r->key = pSUBKEYLENGTH; sprintf( r->u.value, "%u", info.key_attr[1].nbits); r->next = para; para = r; } else if (info.key_attr[1].algo == PUBKEY_ALGO_ECDSA || info.key_attr[1].algo == PUBKEY_ALGO_EDDSA || info.key_attr[1].algo == PUBKEY_ALGO_ECDH) { r = xcalloc (1, sizeof *r + strlen (info.key_attr[1].curve)); r->key = pSUBKEYCURVE; strcpy (r->u.value, info.key_attr[1].curve); r->next = para; para = r; } r = xcalloc (1, sizeof *r + 20 ); r->key = pAUTHKEYTYPE; sprintf( r->u.value, "%d", info.key_attr[2].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 *key_from_hexgrip = NULL; int cardkey; u32 keytime; algo = ask_algo (ctrl, 0, &subkey_algo, &use, &key_from_hexgrip, &cardkey, &keytime); if (key_from_hexgrip) { 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; } r = xmalloc_clear( sizeof *r + 40 ); r->key = pKEYGRIP; strcpy (r->u.value, key_from_hexgrip); r->next = para; para = r; r = xmalloc_clear (sizeof *r); r->key = pCARDKEY; r->u.abool = cardkey; r->next = para; para = r; if (cardkey) { r = xmalloc_clear (sizeof *r); r->key = pKEYCREATIONDATE; r->u.creation = keytime; r->next = para; para = r; } xfree (key_from_hexgrip); } else { const char *curve = 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, NULL); 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. */ if (!strcmp (curve, "Ed25519")) curve = "Curve25519"; else curve = "X448"; } 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, NULL); 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; } } } else /* Default key generation. */ { int subalgo, version, subversion; unsigned int size, subsize; unsigned int keyuse, subkeyuse; const char *curve, *subcurve; char *keygrip, *subkeygrip; u32 keytime, subkeytime; tty_printf ( _("Note: Use \"%s %s\"" " for a full featured key generation dialog.\n"), #if USE_GPG2_HACK GPG_NAME "2" #else GPG_NAME #endif , "--full-generate-key" ); err = parse_key_parameter_string (ctrl, NULL, -1, 0, &algo, &size, &keyuse, &curve, &version, &keygrip, &keytime, &subalgo, &subsize, &subkeyuse, &subcurve, &subversion, &subkeygrip, &subkeytime); if (err) { log_error (_("Key generation failed: %s\n"), gpg_strerror (err)); return; } para = quickgen_set_para (para, 0, algo, size, curve, keyuse, version, keygrip, keytime); if (subalgo) para = quickgen_set_para (para, 1, subalgo, subsize, subcurve, subkeyuse, subversion, subkeygrip, subkeytime); xfree (keygrip); xfree (subkeygrip); } expire = full? ask_expire_interval (0, NULL) : parse_expire_string (default_expiration_interval); 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); } /* 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); } /* Write the *protected* secret key to the file. */ static gpg_error_t card_write_key_to_backup_file (PKT_public_key *sk, const char *backup_dir) { gpg_error_t err = 0; int rc; char keyid_buffer[2 * 8 + 1]; char name_buffer[50]; char *fname; IOBUF fp; mode_t oldmask; PACKET *pkt = NULL; format_keyid (pk_keyid (sk), KF_LONG, keyid_buffer, sizeof (keyid_buffer)); snprintf (name_buffer, sizeof name_buffer, "sk_%s.gpg", keyid_buffer); 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) { err = gpg_error_from_syserror (); log_error (_("can't create backup file '%s': %s\n"), fname, strerror (errno) ); goto leave; } pkt = xcalloc (1, sizeof *pkt); pkt->pkttype = PKT_SECRET_KEY; pkt->pkt.secret_key = sk; rc = build_packet (fp, pkt); if (rc) { log_error ("build packet failed: %s\n", gpg_strerror (rc)); iobuf_cancel (fp); } else { char *fprbuf; 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); fprbuf = hexfingerprint (sk, NULL, 0); if (!fprbuf) { err = gpg_error_from_syserror (); goto leave; } write_status_text_and_buffer (STATUS_BACKUP_KEY_CREATED, fprbuf, fname, strlen (fname), 0); xfree (fprbuf); } leave: xfree (pkt); xfree (fname); return err; } /* Store key to card and make a backup file in OpenPGP format. */ static gpg_error_t card_store_key_with_backup (ctrl_t ctrl, PKT_public_key *sub_psk, const char *backup_dir) { PKT_public_key *sk; gnupg_isotime_t timestamp; gpg_error_t err; char *hexgrip; int rc; struct agent_card_info_s info; gcry_cipher_hd_t cipherhd = NULL; char *cache_nonce = NULL; void *kek = NULL; size_t keklen; sk = copy_public_key (NULL, sub_psk); if (!sk) return gpg_error_from_syserror (); epoch2isotime (timestamp, (time_t)sk->timestamp); err = hexkeygrip_from_pk (sk, &hexgrip); if (err) return err; memset(&info, 0, sizeof (info)); rc = agent_scd_getattr ("SERIALNO", &info); if (rc) return (gpg_error_t)rc; rc = agent_keytocard (hexgrip, 2, 1, info.serialno, timestamp); xfree (info.serialno); if (rc) { err = (gpg_error_t)rc; goto leave; } err = agent_keywrap_key (ctrl, 1, &kek, &keklen); if (err) { log_error ("error getting the KEK: %s\n", gpg_strerror (err)); goto leave; } err = gcry_cipher_open (&cipherhd, GCRY_CIPHER_AES128, GCRY_CIPHER_MODE_AESWRAP, 0); if (!err) err = gcry_cipher_setkey (cipherhd, kek, keklen); if (err) { log_error ("error setting up an encryption context: %s\n", gpg_strerror (err)); goto leave; } err = receive_seckey_from_agent (ctrl, cipherhd, 0, &cache_nonce, hexgrip, sk); if (err) { log_error ("error getting secret key from agent: %s\n", gpg_strerror (err)); goto leave; } err = card_write_key_to_backup_file (sk, backup_dir); if (err) log_error ("writing card key to backup file: %s\n", gpg_strerror (err)); else /* Remove secret key data in agent side. */ agent_scd_learn (NULL, 1); leave: xfree (cache_nonce); gcry_cipher_close (cipherhd); xfree (kek); xfree (hexgrip); free_public_key (sk); return err; } 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 keytimestamp, subkeytimestamp, authkeytimestamp, signtimestamp; char *cache_nonce = NULL; int algo; u32 expire; const char *key_from_hexgrip = NULL; int cardkey; unsigned int keygen_flags; 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); } } log_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); cardkey = get_parameter_bool (para, pCARDKEY); /* In the case that the keys are created from the card we need to * take the timestamps from the card. Only in this case a * pSUBKEYCREATIONDATE or pAUTHKEYCREATIONDATE might be defined and * then we need to use that so that the fingerprint of the subkey * also matches the pre-computed and stored one on the card. In * this case we also use the current time to create the * self-signatures. */ keytimestamp = get_parameter_u32 (para, pKEYCREATIONDATE); if (!keytimestamp) keytimestamp = make_timestamp (); subkeytimestamp = cardkey? get_parameter_u32 (para, pSUBKEYCREATIONDATE) : 0; if (!subkeytimestamp) subkeytimestamp = keytimestamp; authkeytimestamp = cardkey? get_parameter_u32 (para, pAUTHKEYCREATIONDATE): 0; if (!authkeytimestamp) authkeytimestamp = keytimestamp; signtimestamp = cardkey? make_timestamp () : keytimestamp; /* log_debug ("XXX: cardkey ..: %d\n", cardkey); */ /* log_debug ("XXX: keytime ..: %s\n", isotimestamp (keytimestamp)); */ /* log_debug ("XXX: subkeytime: %s\n", isotimestamp (subkeytimestamp)); */ /* log_debug ("XXX: authkeytim: %s\n", isotimestamp (authkeytimestamp)); */ /* log_debug ("XXX: signtime .: %s\n", isotimestamp (signtimestamp)); */ /* Fixme: Check that this comment is still valid: 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. */ algo = get_parameter_algo (ctrl, para, pKEYTYPE, NULL ); expire = get_parameter_u32( para, pKEYEXPIRE ); key_from_hexgrip = get_parameter_value (para, pKEYGRIP); if (cardkey && !key_from_hexgrip) BUG (); keygen_flags = outctrl->keygen_flags; if (get_parameter_uint (para, pVERSION) == 5) keygen_flags |= KEYGEN_FLAG_CREATE_V5_KEY; if (key_from_hexgrip) err = do_create_from_keygrip (ctrl, algo, key_from_hexgrip, cardkey, pub_root, keytimestamp, expire, 0, keygen_flags); else if (!card) err = do_create (algo, get_parameter_uint( para, pKEYLENGTH ), get_parameter_value (para, pKEYCURVE), pub_root, keytimestamp, expire, 0, keygen_flags, get_parameter_passphrase (para), &cache_nonce, NULL); else err = gen_card_key (1, algo, 1, pub_root, &keytimestamp, expire, keygen_flags); /* Get the pointer to the generated public key packet. */ if (!err) { pri_psk = pub_root->next->pkt->pkt.public_key; log_assert (pri_psk); /* Make sure a few fields are correctly set up before going further. */ pri_psk->flags.primary = 1; keyid_from_pk (pri_psk, NULL); /* We don't use pk_keyid to get keyid, because it also asserts that main_keyid is set! */ keyid_copy (pri_psk->main_keyid, pri_psk->keyid); } if (!err && (revkey = get_parameter_revkey (para, pREVOKER))) err = write_direct_sig (ctrl, pub_root, pri_psk, revkey, signtimestamp, cache_nonce); if (!err && (s = get_parameter_value (para, pUSERID))) { err = write_uid (pub_root, s ); if (!err) err = write_selfsigs (ctrl, pub_root, pri_psk, get_parameter_uint (para, pKEYUSAGE), signtimestamp, 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 (3, get_parameter_algo (ctrl, para, pAUTHKEYTYPE, NULL ), 0, pub_root, &authkeytimestamp, expire, keygen_flags); if (!err) err = write_keybinding (ctrl, pub_root, pri_psk, NULL, PUBKEY_USAGE_AUTH, signtimestamp, cache_nonce); } if (!err && get_parameter (para, pSUBKEYTYPE)) { int subkey_algo = get_parameter_algo (ctrl, para, pSUBKEYTYPE, NULL); s = NULL; key_from_hexgrip = get_parameter_value (para, pSUBKEYGRIP); keygen_flags = outctrl->keygen_flags; if (get_parameter_uint (para, pSUBVERSION) == 5) keygen_flags |= KEYGEN_FLAG_CREATE_V5_KEY; if (key_from_hexgrip) err = do_create_from_keygrip (ctrl, subkey_algo, key_from_hexgrip, cardkey, pub_root, subkeytimestamp, get_parameter_u32 (para, pSUBKEYEXPIRE), 1, keygen_flags); else if (!card || (s = get_parameter_value (para, pCARDBACKUPKEY))) { err = do_create (subkey_algo, get_parameter_uint (para, pSUBKEYLENGTH), get_parameter_value (para, pSUBKEYCURVE), pub_root, subkeytimestamp, get_parameter_u32 (para, pSUBKEYEXPIRE), 1, s? KEYGEN_FLAG_NO_PROTECTION : keygen_flags, get_parameter_passphrase (para), &cache_nonce, NULL); /* 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; log_assert (sub_psk); if (s) err = card_store_key_with_backup (ctrl, sub_psk, gnupg_homedir ()); } } else { err = gen_card_key (2, subkey_algo, 0, pub_root, &subkeytimestamp, expire, keygen_flags); } if (!err) err = write_keybinding (ctrl, pub_root, pri_psk, sub_psk, get_parameter_uint (para, pSUBKEYUSAGE), signtimestamp, 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 (ctrl); 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; + char hexfpr[2*MAX_FINGERPRINT_LEN + 1]; no_enc_rsa = ((get_parameter_algo (ctrl, 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); + hexfingerprint (pk, hexfpr, sizeof hexfpr); + register_trusted_key (hexfpr); if (!opt.flags.no_auto_trust_new_key) update_ownertrust (ctrl, pk, ((get_ownertrust (ctrl, pk) & ~TRUST_MASK) | TRUST_ULTIMATE )); gen_standard_revoke (ctrl, pk, cache_nonce); /* Get rid of the first empty packet. */ commit_kbnode (&pub_root); if (!opt.batch) { tty_printf (_("public and secret key created and signed.\n") ); tty_printf ("\n"); merge_keys_and_selfsig (ctrl, pub_root); list_keyblock_direct (ctrl, pub_root, 0, 1, opt.fingerprint || opt.with_fingerprint, 1); } if (!opt.batch && (get_parameter_algo (ctrl, 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); } static gpg_error_t parse_algo_usage_expire (ctrl_t ctrl, int for_subkey, const char *algostr, const char *usagestr, const char *expirestr, int *r_algo, unsigned int *r_usage, u32 *r_expire, unsigned int *r_nbits, const char **r_curve, int *r_version, char **r_keygrip, u32 *r_keytime) { gpg_error_t err; int algo; unsigned int use, nbits; u32 expire; int wantuse; int version = 4; const char *curve = NULL; *r_curve = NULL; if (r_keygrip) *r_keygrip = NULL; if (r_keytime) *r_keytime = 0; nbits = 0; /* Parse the algo string. */ if (algostr && *algostr == '&' && strlen (algostr) == 41) { /* Take algo from existing key. */ algo = check_keygrip (ctrl, algostr+1); /* FIXME: We need the curve name as well. */ return gpg_error (GPG_ERR_NOT_IMPLEMENTED); } err = parse_key_parameter_string (ctrl, algostr, for_subkey? 1 : 0, usagestr? parse_usagestr (usagestr):0, &algo, &nbits, &use, &curve, &version, r_keygrip, r_keytime, NULL, NULL, NULL, NULL, NULL, NULL, NULL); if (err) { if (r_keygrip) { xfree (*r_keygrip); *r_keygrip = NULL; } return err; } /* Parse the usage string. */ if (!usagestr || !*usagestr || !ascii_strcasecmp (usagestr, "default") || !strcmp (usagestr, "-")) ; /* Keep usage from parse_key_parameter_string. */ else if ((wantuse = parse_usagestr (usagestr)) != -1) use = wantuse; else { if (r_keygrip) { xfree (*r_keygrip); *r_keygrip = NULL; } return gpg_error (GPG_ERR_INV_VALUE); } /* Make sure a primary key has the CERT usage. */ if (!for_subkey) use |= PUBKEY_USAGE_CERT; /* Check that usage is possible. NB: We have the same check in * parse_key_parameter_string but need it here again in case the * separate usage value has been given. */ if (/**/((use & (PUBKEY_USAGE_SIG|PUBKEY_USAGE_AUTH|PUBKEY_USAGE_CERT)) && !pubkey_get_nsig (algo)) || ((use & PUBKEY_USAGE_ENC) && !pubkey_get_nenc (algo)) || (for_subkey && (use & PUBKEY_USAGE_CERT))) { if (r_keygrip) { xfree (*r_keygrip); *r_keygrip = NULL; } return gpg_error (GPG_ERR_WRONG_KEY_USAGE); } /* Parse the expire string. */ expire = parse_expire_string (expirestr); if (expire == (u32)-1 ) { if (r_keygrip) { xfree (*r_keygrip); *r_keygrip = NULL; } return gpg_error (GPG_ERR_INV_VALUE); } if (curve) *r_curve = curve; *r_algo = algo; *r_usage = use; *r_expire = expire; *r_nbits = nbits; *r_version = version; return 0; } /* Add a new subkey to an existing key. Returns 0 if a new key has been generated and put into the keyblocks. If any of ALGOSTR, USAGESTR, or EXPIRESTR is NULL interactive mode is used. */ gpg_error_t generate_subkeypair (ctrl_t ctrl, kbnode_t keyblock, const char *algostr, const char *usagestr, const char *expirestr) { gpg_error_t err = 0; int interactive; 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; const char *curve = NULL; u32 cur_time; char *key_from_hexgrip = NULL; u32 keytime = 0; int cardkey = 0; char *hexgrip = NULL; char *serialno = NULL; char *cache_nonce = NULL; char *passwd_nonce = NULL; int keygen_flags = 0; interactive = (!algostr || !usagestr || !expirestr); /* 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, NULL)) { if (interactive) tty_printf (_("Secret parts of primary key are not available.\n")); else log_info ( _("Secret parts of primary key are not available.\n")); err = gpg_error (GPG_ERR_NO_SECKEY); goto leave; } if (serialno) { if (interactive) tty_printf (_("Secret parts of primary key are stored on-card.\n")); else log_info ( _("Secret parts of primary key are stored on-card.\n")); } if (interactive) { algo = ask_algo (ctrl, 1, NULL, &use, &key_from_hexgrip, &cardkey, &keytime); log_assert (algo); if (key_from_hexgrip) nbits = 0; else if (algo == PUBKEY_ALGO_ECDSA || algo == PUBKEY_ALGO_EDDSA || algo == PUBKEY_ALGO_ECDH) curve = ask_curve (&algo, NULL, 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; } } else /* Unattended mode. */ { int version; err = parse_algo_usage_expire (ctrl, 1, algostr, usagestr, expirestr, &algo, &use, &expire, &nbits, &curve, &version, &key_from_hexgrip, &keytime); if (err) goto leave; if (version == 5) keygen_flags |= KEYGEN_FLAG_CREATE_V5_KEY; } /* Verify the passphrase now so that we get a cache item for the * primary key passphrase. The agent also returns a passphrase * nonce, which we can use to set the passphrase for the subkey to * that of the primary key. */ { char *desc = gpg_format_keydesc (ctrl, pri_psk, FORMAT_KEYDESC_NORMAL, 1); err = agent_passwd (ctrl, hexgrip, desc, 1 /*=verify*/, &cache_nonce, &passwd_nonce); xfree (desc); if (gpg_err_code (err) == GPG_ERR_NOT_IMPLEMENTED && gpg_err_source (err) == GPG_ERR_SOURCE_GPGAGENT) err = 0; /* Very likely that the key is on a card. */ if (err) goto leave; } /* Start creation. */ if (key_from_hexgrip) { err = do_create_from_keygrip (ctrl, algo, key_from_hexgrip, cardkey, keyblock, keytime? keytime : cur_time, expire, 1, keygen_flags); } else { const char *passwd; /* 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 subkey. */ if (opt.pinentry_mode != PINENTRY_MODE_LOOPBACK && have_static_passphrase ()) passwd = get_static_passphrase (); else passwd = NULL; err = do_create (algo, nbits, curve, keyblock, cur_time, expire, 1, keygen_flags, passwd, &cache_nonce, &passwd_nonce); } 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 (ctrl, keyblock, pri_psk, sub_psk, use, cur_time, cache_nonce); if (err) goto leave; print_status_key_created ('S', sub_psk, NULL); leave: xfree (key_from_hexgrip); xfree (hexgrip); xfree (serialno); xfree (cache_nonce); xfree (passwd_nonce); 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 (ctrl_t ctrl, kbnode_t pub_keyblock, int keyno, const char *serialno) { gpg_error_t err = 0; kbnode_t node; PKT_public_key *pri_pk = NULL; unsigned int use; u32 expire; u32 cur_time; struct para_data_s *para = NULL; PKT_public_key *sub_pk = NULL; int algo; struct agent_card_info_s info; int keygen_flags = 0; /* FIXME!!! */ log_assert (keyno >= 1 && keyno <= 3); memset (&info, 0, sizeof (info)); err = agent_scd_getattr ("KEY-ATTR", &info); if (err) { log_error (_("error getting current key info: %s\n"), gpg_strerror (err)); return err; } algo = info.key_attr[keyno-1].algo; 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; public 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; } 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 (keyno, algo, 0, pub_keyblock, &cur_time, expire, keygen_flags); /* Get the pointer to the generated public subkey packet. */ if (!err) { for (node = pub_keyblock; node; node = node->next) if (node->pkt->pkttype == PKT_PUBLIC_SUBKEY) sub_pk = node->pkt->pkt.public_key; log_assert (sub_pk); err = write_keybinding (ctrl, pub_keyblock, pri_pk, sub_pk, use, cur_time, NULL); } leave: if (err) log_error (_("Key generation failed: %s\n"), gpg_strerror (err) ); else print_status_key_created ('S', sub_pk, NULL); 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. * FIXME: Does not yet support v5 keys. */ static gpg_error_t gen_card_key (int keyno, int algo, int is_primary, kbnode_t pub_root, u32 *timestamp, u32 expireval, int keygen_flags) { #ifdef ENABLE_CARD_SUPPORT gpg_error_t err; PACKET *pkt; PKT_public_key *pk; char keyid[10]; unsigned char *public; gcry_sexp_t s_key; snprintf (keyid, DIM(keyid), "OPENPGP.%d", keyno); 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 (keyno, 1, 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 (keyno, 1, timestamp); * } */ if (err) { log_error ("key generation failed: %s\n", gpg_strerror (err)); xfree (pkt); xfree (pk); return err; } /* Send the READKEY 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_readkey (NULL, 1, keyid, &public); if (err) return err; err = gcry_sexp_sscan (&s_key, NULL, public, gcry_sexp_canon_len (public, 0, NULL, NULL)); xfree (public); if (err) return err; if (algo == PUBKEY_ALGO_RSA) err = key_from_sexp (pk->pkey, s_key, "public-key", "ne"); else if (algo == PUBKEY_ALGO_ECDSA || algo == PUBKEY_ALGO_EDDSA || algo == PUBKEY_ALGO_ECDH ) err = ecckey_from_sexp (pk->pkey, s_key, algo); else err = gpg_error (GPG_ERR_PUBKEY_ALGO); gcry_sexp_release (s_key); if (err) { log_error ("key_from_sexp failed: %s\n", gpg_strerror (err) ); free_public_key (pk); return err; } pk->timestamp = *timestamp; pk->version = (keygen_flags & KEYGEN_FLAG_CREATE_V5_KEY)? 5 : 4; if (expireval) pk->expiredate = pk->timestamp + expireval; pk->pubkey_algo = algo; 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)keyno; (void)is_primary; (void)pub_root; (void)timestamp; (void)expireval; return gpg_error (GPG_ERR_NOT_SUPPORTED); #endif /*!ENABLE_CARD_SUPPORT*/ } diff --git a/g10/trust.c b/g10/trust.c index bd1c89458..67cb1029b 100644 --- a/g10/trust.c +++ b/g10/trust.c @@ -1,439 +1,428 @@ /* trust.c - High level trust functions * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, * 2008, 2012 Free Software Foundation, Inc. * Copyright (C) 2014 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 "gpg.h" #include "keydb.h" #include "../common/util.h" #include "options.h" #include "packet.h" #include "main.h" #include "../common/i18n.h" #include "trustdb.h" #include "../common/host2net.h" /* Return true if key is disabled. Note that this is usually used via the pk_is_disabled macro. */ int cache_disabled_value (ctrl_t ctrl, PKT_public_key *pk) { #ifdef NO_TRUST_MODELS (void)pk; return 0; #else return tdb_cache_disabled_value (ctrl, pk); #endif } -void -register_trusted_keyid (u32 *keyid) -{ -#ifdef NO_TRUST_MODELS - (void)keyid; -#else - tdb_register_trusted_keyid (keyid); -#endif -} - - void register_trusted_key (const char *string) { #ifdef NO_TRUST_MODELS (void)string; #else /* Some users have conf files with entries like * trusted-key 0x1234567812345678 # foo * That is obviously wrong. Before fixing bug#1206 trailing garbage * on a key specification if was ignored. We detect the above use case * here and cut off the junk-looking-like-a comment. */ if (strchr (string, '#')) { char *buf; buf = xtrystrdup (string); if (buf) { *strchr (buf, '#') = 0; tdb_register_trusted_key (buf); xfree (buf); return; } } tdb_register_trusted_key (string); #endif } /* * This function returns a letter for a trust value. Trust flags * are ignored. */ static int trust_letter (unsigned int value) { switch( (value & TRUST_MASK) ) { case TRUST_UNKNOWN: return '-'; case TRUST_EXPIRED: return 'e'; case TRUST_UNDEFINED: return 'q'; case TRUST_NEVER: return 'n'; case TRUST_MARGINAL: return 'm'; case TRUST_FULLY: return 'f'; case TRUST_ULTIMATE: return 'u'; default: return '?'; } } /* The strings here are similar to those in pkclist.c:do_edit_ownertrust() */ const char * trust_value_to_string (unsigned int value) { switch ((value & TRUST_MASK)) { case TRUST_UNKNOWN: return _("unknown"); case TRUST_EXPIRED: return _("expired"); case TRUST_UNDEFINED: return _("undefined"); case TRUST_NEVER: return _("never"); case TRUST_MARGINAL: return _("marginal"); case TRUST_FULLY: return _("full"); case TRUST_ULTIMATE: return _("ultimate"); default: return "err"; } } int string_to_trust_value (const char *str) { if (!ascii_strcasecmp (str, "undefined")) return TRUST_UNDEFINED; else if (!ascii_strcasecmp (str, "never")) return TRUST_NEVER; else if (!ascii_strcasecmp (str, "marginal")) return TRUST_MARGINAL; else if (!ascii_strcasecmp (str, "full")) return TRUST_FULLY; else if (!ascii_strcasecmp(str, "ultimate")) return TRUST_ULTIMATE; else return -1; } const char * uid_trust_string_fixed (ctrl_t ctrl, PKT_public_key *key, PKT_user_id *uid) { if (!key && !uid) { /* TRANSLATORS: these strings are similar to those in trust_value_to_string(), but are a fixed length. This is needed to make attractive information listings where columns line up properly. The value "10" should be the length of the strings you choose to translate to. This is the length in printable columns. It gets passed to atoi() so everything after the number is essentially a comment and need not be translated. Either key and uid are both NULL, or neither are NULL. */ return _("10 translator see trust.c:uid_trust_string_fixed"); } else if(uid->flags.revoked || (key && key->flags.revoked)) return _("[ revoked]"); else if(uid->flags.expired) return _("[ expired]"); else if(key) { switch (get_validity (ctrl, NULL, key, uid, NULL, 0) & TRUST_MASK) { case TRUST_UNKNOWN: return _("[ unknown]"); case TRUST_EXPIRED: return _("[ expired]"); case TRUST_UNDEFINED: return _("[ undef ]"); case TRUST_NEVER: return _("[ never ]"); case TRUST_MARGINAL: return _("[marginal]"); case TRUST_FULLY: return _("[ full ]"); case TRUST_ULTIMATE: return _("[ultimate]"); } } return "err"; } /* * Return the assigned ownertrust value for the given public key. * The key should be the primary key. */ unsigned int get_ownertrust (ctrl_t ctrl, PKT_public_key *pk) { #ifdef NO_TRUST_MODELS (void)pk; return TRUST_UNKNOWN; #else return tdb_get_ownertrust (ctrl, pk, 0); #endif } /* * Same as get_ownertrust but this takes the minimum ownertrust value * into account, and will bump up the value as needed. NO_CREATE * inhibits creation of a trustdb it that does not yet exists. */ static int get_ownertrust_with_min (ctrl_t ctrl, PKT_public_key *pk, int no_create) { #ifdef NO_TRUST_MODELS (void)pk; return TRUST_UNKNOWN; #else unsigned int otrust, otrust_min; /* Shortcut instead of doing the same twice in the two tdb_get * functions: If the caller asked not to create a trustdb we call * init_trustdb directly and allow it to fail with an error code for * a non-existing trustdb. */ if (no_create && init_trustdb (ctrl, 1)) return TRUST_UNKNOWN; otrust = (tdb_get_ownertrust (ctrl, pk, no_create) & TRUST_MASK); otrust_min = tdb_get_min_ownertrust (ctrl, pk, no_create); if (otrust < otrust_min) { /* If the trust that the user has set is less than the trust that was calculated from a trust signature chain, use the higher of the two. We do this here and not in get_ownertrust since the underlying ownertrust should not really be set - just the appearance of the ownertrust. */ otrust = otrust_min; } return otrust; #endif } /* * Same as get_ownertrust but return a trust letter instead of an * value. This takes the minimum ownertrust value into account. If * NO_CREATE is set, no efforts for creating a trustdb will be taken. */ int get_ownertrust_info (ctrl_t ctrl, PKT_public_key *pk, int no_create) { return trust_letter (get_ownertrust_with_min (ctrl, pk, no_create)); } /* * Same as get_ownertrust but return a trust string instead of an * value. This takes the minimum ownertrust value into account. If * NO_CREATE is set, no efforts for creating a trustdb will be taken. */ const char * get_ownertrust_string (ctrl_t ctrl, PKT_public_key *pk, int no_create) { return trust_value_to_string (get_ownertrust_with_min (ctrl, pk, no_create)); } /* * Set the trust value of the given public key to the new value. * The key should be a primary one. */ void update_ownertrust (ctrl_t ctrl, PKT_public_key *pk, unsigned int new_trust) { #ifdef NO_TRUST_MODELS (void)pk; (void)new_trust; #else tdb_update_ownertrust (ctrl, pk, new_trust); #endif } int clear_ownertrusts (ctrl_t ctrl, PKT_public_key *pk) { #ifdef NO_TRUST_MODELS (void)pk; return 0; #else return tdb_clear_ownertrusts (ctrl, pk); #endif } void revalidation_mark (ctrl_t ctrl) { #ifndef NO_TRUST_MODELS tdb_revalidation_mark (ctrl); #endif } void check_trustdb_stale (ctrl_t ctrl) { #ifndef NO_TRUST_MODELS tdb_check_trustdb_stale (ctrl); #else (void)ctrl; #endif } void check_or_update_trustdb (ctrl_t ctrl) { #ifndef NO_TRUST_MODELS tdb_check_or_update (ctrl); #else (void)ctrl; #endif } /* * Return the validity information for KB/PK (at least one must be * non-NULL). If the namehash is not NULL, the validity of the * corresponding user ID is returned, otherwise, a reasonable value * for the entire key is returned. */ unsigned int get_validity (ctrl_t ctrl, kbnode_t kb, PKT_public_key *pk, PKT_user_id *uid, PKT_signature *sig, int may_ask) { int rc; unsigned int validity; u32 kid[2]; PKT_public_key *main_pk; if (kb && pk) log_assert (keyid_cmp (pk_main_keyid (pk), pk_main_keyid (kb->pkt->pkt.public_key)) == 0); if (! pk) { log_assert (kb); pk = kb->pkt->pkt.public_key; } if (uid) namehash_from_uid (uid); keyid_from_pk (pk, kid); if (pk->main_keyid[0] != kid[0] || pk->main_keyid[1] != kid[1]) { /* This is a subkey - get the mainkey. */ if (kb) main_pk = kb->pkt->pkt.public_key; else { main_pk = xmalloc_clear (sizeof *main_pk); rc = get_pubkey (ctrl, main_pk, pk->main_keyid); if (rc) { char *tempkeystr = xstrdup (keystr (pk->main_keyid)); log_error ("error getting main key %s of subkey %s: %s\n", tempkeystr, keystr (kid), gpg_strerror (rc)); xfree (tempkeystr); validity = TRUST_UNKNOWN; goto leave; } } } else main_pk = pk; #ifdef NO_TRUST_MODELS validity = TRUST_UNKNOWN; #else validity = tdb_get_validity_core (ctrl, kb, pk, uid, main_pk, sig, may_ask); #endif leave: /* Set some flags direct from the key */ if (main_pk->flags.revoked) validity |= TRUST_FLAG_REVOKED; if (main_pk != pk && pk->flags.revoked) validity |= TRUST_FLAG_SUB_REVOKED; /* Note: expiration is a trust value and not a flag - don't know why * I initially designed it that way. */ if (main_pk->has_expired || pk->has_expired) validity = ((validity & (~TRUST_MASK | TRUST_FLAG_PENDING_CHECK)) | TRUST_EXPIRED); if (main_pk != pk && !kb) free_public_key (main_pk); return validity; } int get_validity_info (ctrl_t ctrl, kbnode_t kb, PKT_public_key *pk, PKT_user_id *uid) { int trustlevel; if (kb && pk) log_assert (keyid_cmp (pk_main_keyid (pk), pk_main_keyid (kb->pkt->pkt.public_key)) == 0); if (! pk && kb) pk = kb->pkt->pkt.public_key; if (!pk) return '?'; /* Just in case a NULL PK is passed. */ trustlevel = get_validity (ctrl, kb, pk, uid, NULL, 0); if ((trustlevel & TRUST_FLAG_REVOKED)) return 'r'; return trust_letter (trustlevel); } const char * get_validity_string (ctrl_t ctrl, PKT_public_key *pk, PKT_user_id *uid) { int trustlevel; if (!pk) return "err"; /* Just in case a NULL PK is passed. */ trustlevel = get_validity (ctrl, NULL, pk, uid, NULL, 0); if ((trustlevel & TRUST_FLAG_REVOKED)) return _("revoked"); return trust_value_to_string (trustlevel); } diff --git a/g10/trustdb.c b/g10/trustdb.c index a313a423c..0b9625ea6 100644 --- a/g10/trustdb.c +++ b/g10/trustdb.c @@ -1,2289 +1,2289 @@ /* trustdb.c * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, * 2008, 2012 Free Software Foundation, Inc. * * 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 "gpg.h" #include "../common/status.h" #include "../common/iobuf.h" #include "../regexp/jimregexp.h" #include "keydb.h" #include "../common/util.h" #include "options.h" #include "packet.h" #include "main.h" #include "../common/mbox-util.h" #include "../common/i18n.h" #include "tdbio.h" #include "trustdb.h" #include "tofu.h" #include "key-clean.h" static u32 keyid_from_fpr20 (ctrl_t ctrl, const byte *fpr, u32 *keyid) { u32 dummy_keyid[2]; int fprlen; if( !keyid ) keyid = dummy_keyid; /* Problem: We do only use fingerprints in the trustdb but * we need the keyID here to indetify the key; we can only * use that ugly hack to distinguish between 16 and 20 * bytes fpr - it does not work always so we better change * the whole validation code to only work with * fingerprints */ fprlen = (!fpr[16] && !fpr[17] && !fpr[18] && !fpr[19])? 16:20; if (fprlen != 20) { /* This is special as we have to lookup the key first. */ PKT_public_key pk; int rc; memset (&pk, 0, sizeof pk); rc = get_pubkey_byfprint (ctrl, &pk, NULL, fpr, fprlen); if (rc) { log_printhex (fpr, fprlen, "Oops: keyid_from_fingerprint: no pubkey; fpr:"); keyid[0] = 0; keyid[1] = 0; } else keyid_from_pk (&pk, keyid); } else { keyid[0] = buf32_to_u32 (fpr+12); keyid[1] = buf32_to_u32 (fpr+16); } return keyid[1]; } typedef struct key_item **KeyHashTable; /* see new_key_hash_table() */ /* * Structure to keep track of keys, this is used as an array wherre * the item right after the last one has a keyblock set to NULL. * Maybe we can drop this thing and replace it by key_item */ struct key_array { KBNODE keyblock; }; /* Control information for the trust DB. */ static struct { int init; int level; char *dbname; int no_trustdb; } trustdb_args; /* Some globals. */ static struct key_item *user_utk_list; /* temp. used to store --trusted-keys */ static struct key_item *utk_list; /* all ultimately trusted keys */ static int pending_check_trustdb; static int validate_keys (ctrl_t ctrl, int interactive); /********************************************** ************* some helpers ******************* **********************************************/ static struct key_item * new_key_item (void) { struct key_item *k; k = xmalloc_clear (sizeof *k); return k; } static void release_key_items (struct key_item *k) { struct key_item *k2; for (; k; k = k2) { k2 = k->next; xfree (k->trust_regexp); xfree (k); } } #define KEY_HASH_TABLE_SIZE 1024 /* * For fast keylook up we need a hash table. Each byte of a KeyID * should be distributed equally over the 256 possible values (except * for v3 keyIDs but we consider them as not important here). So we * can just use 10 bits to index a table of KEY_HASH_TABLE_SIZE key items. * Possible optimization: Do not use key_items but other hash_table when the * duplicates lists get too large. */ static KeyHashTable new_key_hash_table (void) { struct key_item **tbl; tbl = xmalloc_clear (KEY_HASH_TABLE_SIZE * sizeof *tbl); return tbl; } static void release_key_hash_table (KeyHashTable tbl) { int i; if (!tbl) return; for (i=0; i < KEY_HASH_TABLE_SIZE; i++) release_key_items (tbl[i]); xfree (tbl); } /* * Returns: True if the keyID is in the given hash table */ static int test_key_hash_table (KeyHashTable tbl, u32 *kid) { struct key_item *k; for (k = tbl[(kid[1] % KEY_HASH_TABLE_SIZE)]; k; k = k->next) if (k->kid[0] == kid[0] && k->kid[1] == kid[1]) return 1; return 0; } /* * Add a new key to the hash table. The key is identified by its key ID. */ static void add_key_hash_table (KeyHashTable tbl, u32 *kid) { int i = kid[1] % KEY_HASH_TABLE_SIZE; struct key_item *k, *kk; for (k = tbl[i]; k; k = k->next) if (k->kid[0] == kid[0] && k->kid[1] == kid[1]) return; /* already in table */ kk = new_key_item (); kk->kid[0] = kid[0]; kk->kid[1] = kid[1]; kk->next = tbl[i]; tbl[i] = kk; } /* * Release a key_array */ static void release_key_array ( struct key_array *keys ) { struct key_array *k; if (keys) { for (k=keys; k->keyblock; k++) release_kbnode (k->keyblock); xfree (keys); } } /********************************************* ********** Initialization ***************** *********************************************/ /* * Used to register extra ultimately trusted keys - this has to be done * before initializing the validation module. * FIXME: Should be replaced by a function to add those keys to the trustdb. */ -void +static void tdb_register_trusted_keyid (u32 *keyid) { struct key_item *k; k = new_key_item (); k->kid[0] = keyid[0]; k->kid[1] = keyid[1]; k->next = user_utk_list; user_utk_list = k; } void tdb_register_trusted_key (const char *string) { gpg_error_t err; KEYDB_SEARCH_DESC desc; u32 kid[2]; err = classify_user_id (string, &desc, 1); if (!err) { if (desc.mode == KEYDB_SEARCH_MODE_LONG_KID) { - register_trusted_keyid (desc.u.kid); + tdb_register_trusted_keyid (desc.u.kid); return; } if (desc.mode == KEYDB_SEARCH_MODE_FPR && desc.fprlen == 20) { kid[0] = buf32_to_u32 (desc.u.fpr+12); kid[1] = buf32_to_u32 (desc.u.fpr+16); - register_trusted_keyid (kid); + tdb_register_trusted_keyid (kid); return; } if (desc.mode == KEYDB_SEARCH_MODE_FPR && desc.fprlen == 32) { kid[0] = buf32_to_u32 (desc.u.fpr); kid[1] = buf32_to_u32 (desc.u.fpr+4); - register_trusted_keyid (kid); + tdb_register_trusted_keyid (kid); return; } } log_error (_("'%s' is not a valid long keyID\n"), string ); } /* * Helper to add a key to the global list of ultimately trusted keys. * Returns: true = inserted, false = already in list. */ static int add_utk (u32 *kid) { struct key_item *k; if (tdb_keyid_is_utk (kid)) return 0; k = new_key_item (); k->kid[0] = kid[0]; k->kid[1] = kid[1]; k->ownertrust = TRUST_ULTIMATE; k->next = utk_list; utk_list = k; if( opt.verbose > 1 ) log_info(_("key %s: accepted as trusted key\n"), keystr(kid)); return 1; } /**************** * Verify that all our secret keys are usable and put them into the utk_list. */ static void verify_own_keys (ctrl_t ctrl) { TRUSTREC rec; ulong recnum; int rc; struct key_item *k; if (utk_list) return; /* scan the trustdb to find all ultimately trusted keys */ for (recnum=1; !tdbio_read_record (recnum, &rec, 0); recnum++ ) { if (rec.rectype == RECTYPE_TRUST && (rec.r.trust.ownertrust & TRUST_MASK) == TRUST_ULTIMATE) { u32 kid[2]; keyid_from_fpr20 (ctrl, rec.r.trust.fingerprint, kid); if (!add_utk (kid)) log_info (_("key %s occurs more than once in the trustdb\n"), keystr(kid)); } } /* Put any --trusted-key keys into the trustdb */ for (k = user_utk_list; k; k = k->next) { if ( add_utk (k->kid) ) { /* not yet in trustDB as ultimately trusted */ PKT_public_key pk; memset (&pk, 0, sizeof pk); rc = get_pubkey (ctrl, &pk, k->kid); if (rc) log_info(_("key %s: no public key for trusted key - skipped\n"), keystr(k->kid)); else { tdb_update_ownertrust (ctrl, &pk, ((tdb_get_ownertrust (ctrl, &pk, 0) & ~TRUST_MASK) | TRUST_ULTIMATE )); release_public_key_parts (&pk); } if (!opt.quiet) log_info (_("key %s marked as ultimately trusted\n"), keystr(k->kid)); } } /* release the helper table table */ release_key_items (user_utk_list); user_utk_list = NULL; return; } /* Returns whether KID is on the list of ultimately trusted keys. */ int tdb_keyid_is_utk (u32 *kid) { struct key_item *k; for (k = utk_list; k; k = k->next) if (k->kid[0] == kid[0] && k->kid[1] == kid[1]) return 1; return 0; } /* Return the list of ultimately trusted keys. */ struct key_item * tdb_utks (void) { return utk_list; } /********************************************* *********** TrustDB stuff ******************* *********************************************/ /* * Read a record but die if it does not exist */ static void read_record (ulong recno, TRUSTREC *rec, int rectype ) { int rc = tdbio_read_record (recno, rec, rectype); if (rc) { log_error(_("trust record %lu, req type %d: read failed: %s\n"), recno, rec->rectype, gpg_strerror (rc) ); tdbio_invalid(); } if (rectype != rec->rectype) { log_error(_("trust record %lu is not of requested type %d\n"), rec->recnum, rectype); tdbio_invalid(); } } /* * Write a record and die on error */ static void write_record (ctrl_t ctrl, TRUSTREC *rec) { int rc = tdbio_write_record (ctrl, rec); if (rc) { log_error(_("trust record %lu, type %d: write failed: %s\n"), rec->recnum, rec->rectype, gpg_strerror (rc) ); tdbio_invalid(); } } /* * sync the TrustDb and die on error */ static void do_sync(void) { int rc = tdbio_sync (); if(rc) { log_error (_("trustdb: sync failed: %s\n"), gpg_strerror (rc) ); g10_exit(2); } } const char * trust_model_string (int model) { switch (model) { case TM_CLASSIC: return "classic"; case TM_PGP: return "pgp"; case TM_EXTERNAL: return "external"; case TM_TOFU: return "tofu"; case TM_TOFU_PGP: return "tofu+pgp"; case TM_ALWAYS: return "always"; case TM_DIRECT: return "direct"; default: return "unknown"; } } /**************** * Perform some checks over the trustdb * level 0: only open the db * 1: used for initial program startup */ int setup_trustdb( int level, const char *dbname ) { /* just store the args */ if( trustdb_args.init ) return 0; trustdb_args.level = level; trustdb_args.dbname = dbname? xstrdup(dbname): NULL; return 0; } void how_to_fix_the_trustdb () { const char *name = trustdb_args.dbname; if (!name) name = "trustdb.gpg"; log_info (_("You may try to re-create the trustdb using the commands:\n")); log_info (" cd %s\n", default_homedir ()); log_info (" %s --export-ownertrust > otrust.tmp\n", GPG_NAME); #ifdef HAVE_W32_SYSTEM log_info (" del %s\n", name); #else log_info (" rm %s\n", name); #endif log_info (" %s --import-ownertrust < otrust.tmp\n", GPG_NAME); log_info (_("If that does not work, please consult the manual\n")); } /* Initialize the trustdb. With NO_CREATE set a missing trustdb is * not an error and the function won't terminate the process on error; * in that case 0 is returned if there is a trustdb or an error code * if no trustdb is available. */ gpg_error_t init_trustdb (ctrl_t ctrl, int no_create) { int level = trustdb_args.level; const char* dbname = trustdb_args.dbname; if( trustdb_args.init ) return 0; trustdb_args.init = 1; if(level==0 || level==1) { int rc = tdbio_set_dbname (ctrl, dbname, (!no_create && level), &trustdb_args.no_trustdb); if (no_create && trustdb_args.no_trustdb) { /* No trustdb found and the caller asked us not to create * it. Return an error and set the initialization state * back so that we always test for an existing trustdb. */ trustdb_args.init = 0; return gpg_error (GPG_ERR_ENOENT); } if (rc) log_fatal("can't init trustdb: %s\n", gpg_strerror (rc) ); } else BUG(); if(opt.trust_model==TM_AUTO) { /* Try and set the trust model off of whatever the trustdb says it is. */ opt.trust_model=tdbio_read_model(); /* Sanity check this ;) */ if(opt.trust_model != TM_CLASSIC && opt.trust_model != TM_PGP && opt.trust_model != TM_TOFU_PGP && opt.trust_model != TM_TOFU && opt.trust_model != TM_EXTERNAL) { log_info(_("unable to use unknown trust model (%d) - " "assuming %s trust model\n"),opt.trust_model,"pgp"); opt.trust_model = TM_PGP; } if(opt.verbose) log_info(_("using %s trust model\n"), trust_model_string (opt.trust_model)); } if (opt.trust_model==TM_PGP || opt.trust_model==TM_CLASSIC || opt.trust_model == TM_TOFU || opt.trust_model == TM_TOFU_PGP) { /* Verify the list of ultimately trusted keys and move the --trusted-keys list there as well. */ if(level==1) verify_own_keys (ctrl); if(!tdbio_db_matches_options()) pending_check_trustdb=1; } return 0; } /* Check whether we have a trust database, initializing it if necessary if the trust model is not 'always trust'. Returns true if we do have a usable trust database. */ int have_trustdb (ctrl_t ctrl) { return !init_trustdb (ctrl, opt.trust_model == TM_ALWAYS); } /**************** * Recreate the WoT but do not ask for new ownertrusts. Special * feature: In batch mode and without a forced yes, this is only done * when a check is due. This can be used to run the check from a crontab */ void check_trustdb (ctrl_t ctrl) { init_trustdb (ctrl, 0); if (opt.trust_model == TM_PGP || opt.trust_model == TM_CLASSIC || opt.trust_model == TM_TOFU_PGP || opt.trust_model == TM_TOFU) { if (opt.batch && !opt.answer_yes) { ulong scheduled; scheduled = tdbio_read_nextcheck (); if (!scheduled) { log_info (_("no need for a trustdb check\n")); return; } if (scheduled > make_timestamp ()) { log_info (_("next trustdb check due at %s\n"), strtimestamp (scheduled)); return; } } validate_keys (ctrl, 0); } else log_info (_("no need for a trustdb check with '%s' trust model\n"), trust_model_string(opt.trust_model)); } /* * Recreate the WoT. */ void update_trustdb (ctrl_t ctrl) { init_trustdb (ctrl, 0); if (opt.trust_model == TM_PGP || opt.trust_model == TM_CLASSIC || opt.trust_model == TM_TOFU_PGP || opt.trust_model == TM_TOFU) validate_keys (ctrl, 1); else log_info (_("no need for a trustdb update with '%s' trust model\n"), trust_model_string(opt.trust_model)); } void tdb_revalidation_mark (ctrl_t ctrl) { init_trustdb (ctrl, 0); if (trustdb_args.no_trustdb && opt.trust_model == TM_ALWAYS) return; /* We simply set the time for the next check to 1 (far back in 1970) so that a --update-trustdb will be scheduled. */ if (tdbio_write_nextcheck (ctrl, 1)) do_sync (); pending_check_trustdb = 1; } int trustdb_pending_check(void) { return pending_check_trustdb; } /* If the trustdb is dirty, and we're interactive, update it. Otherwise, check it unless no-auto-check-trustdb is set. */ void tdb_check_or_update (ctrl_t ctrl) { if (trustdb_pending_check ()) { if (opt.interactive) update_trustdb (ctrl); else if (!opt.no_auto_check_trustdb) check_trustdb (ctrl); } } void read_trust_options (ctrl_t ctrl, byte *trust_model, ulong *created, ulong *nextcheck, byte *marginals, byte *completes, byte *cert_depth, byte *min_cert_level) { TRUSTREC opts; init_trustdb (ctrl, 0); if (trustdb_args.no_trustdb && opt.trust_model == TM_ALWAYS) memset (&opts, 0, sizeof opts); else read_record (0, &opts, RECTYPE_VER); if(trust_model) *trust_model=opts.r.ver.trust_model; if(created) *created=opts.r.ver.created; if(nextcheck) *nextcheck=opts.r.ver.nextcheck; if(marginals) *marginals=opts.r.ver.marginals; if(completes) *completes=opts.r.ver.completes; if(cert_depth) *cert_depth=opts.r.ver.cert_depth; if(min_cert_level) *min_cert_level=opts.r.ver.min_cert_level; } /*********************************************** *********** Ownertrust et al. **************** ***********************************************/ static int read_trust_record (ctrl_t ctrl, PKT_public_key *pk, TRUSTREC *rec) { int rc; init_trustdb (ctrl, 0); rc = tdbio_search_trust_bypk (ctrl, pk, rec); if (rc) { if (gpg_err_code (rc) != GPG_ERR_NOT_FOUND) log_error ("trustdb: searching trust record failed: %s\n", gpg_strerror (rc)); return rc; } if (rec->rectype != RECTYPE_TRUST) { log_error ("trustdb: record %lu is not a trust record\n", rec->recnum); return GPG_ERR_TRUSTDB; } return 0; } /* * Return the assigned ownertrust value for the given public key. The * key should be the primary key. If NO_CREATE is set a missing * trustdb will not be created. This comes for example handy when we * want to print status lines (DECRYPTION_KEY) which carry ownertrust * values but we usually use --always-trust. */ unsigned int tdb_get_ownertrust (ctrl_t ctrl, PKT_public_key *pk, int no_create) { TRUSTREC rec; gpg_error_t err; if (trustdb_args.no_trustdb && opt.trust_model == TM_ALWAYS) return TRUST_UNKNOWN; /* If the caller asked not to create a trustdb we call init_trustdb * directly and allow it to fail with an error code for a * non-existing trustdb. */ if (no_create && init_trustdb (ctrl, 1)) return TRUST_UNKNOWN; err = read_trust_record (ctrl, pk, &rec); if (gpg_err_code (err) == GPG_ERR_NOT_FOUND) return TRUST_UNKNOWN; /* no record yet */ if (err) { tdbio_invalid (); return TRUST_UNKNOWN; /* actually never reached */ } return rec.r.trust.ownertrust; } unsigned int tdb_get_min_ownertrust (ctrl_t ctrl, PKT_public_key *pk, int no_create) { TRUSTREC rec; gpg_error_t err; if (trustdb_args.no_trustdb && opt.trust_model == TM_ALWAYS) return TRUST_UNKNOWN; /* If the caller asked not to create a trustdb we call init_trustdb * directly and allow it to fail with an error code for a * non-existing trustdb. */ if (no_create && init_trustdb (ctrl, 1)) return TRUST_UNKNOWN; err = read_trust_record (ctrl, pk, &rec); if (gpg_err_code (err) == GPG_ERR_NOT_FOUND) return TRUST_UNKNOWN; /* no record yet */ if (err) { tdbio_invalid (); return TRUST_UNKNOWN; /* actually never reached */ } return rec.r.trust.min_ownertrust; } /* * Set the trust value of the given public key to the new value. * The key should be a primary one. */ void tdb_update_ownertrust (ctrl_t ctrl, PKT_public_key *pk, unsigned int new_trust ) { TRUSTREC rec; gpg_error_t err; if (trustdb_args.no_trustdb && opt.trust_model == TM_ALWAYS) return; err = read_trust_record (ctrl, pk, &rec); if (!err) { if (DBG_TRUST) log_debug ("update ownertrust from %u to %u\n", (unsigned int)rec.r.trust.ownertrust, new_trust ); if (rec.r.trust.ownertrust != new_trust) { rec.r.trust.ownertrust = new_trust; write_record (ctrl, &rec); tdb_revalidation_mark (ctrl); do_sync (); } } else if (gpg_err_code (err) == GPG_ERR_NOT_FOUND) { /* no record yet - create a new one */ if (DBG_TRUST) log_debug ("insert ownertrust %u\n", new_trust ); memset (&rec, 0, sizeof rec); rec.recnum = tdbio_new_recnum (ctrl); rec.rectype = RECTYPE_TRUST; fpr20_from_pk (pk, rec.r.trust.fingerprint); rec.r.trust.ownertrust = new_trust; write_record (ctrl, &rec); tdb_revalidation_mark (ctrl); do_sync (); } else { tdbio_invalid (); } } static void update_min_ownertrust (ctrl_t ctrl, u32 *kid, unsigned int new_trust) { PKT_public_key *pk; TRUSTREC rec; gpg_error_t err; if (trustdb_args.no_trustdb && opt.trust_model == TM_ALWAYS) return; pk = xmalloc_clear (sizeof *pk); err = get_pubkey (ctrl, pk, kid); if (err) { log_error (_("public key %s not found: %s\n"), keystr (kid), gpg_strerror (err)); xfree (pk); return; } err = read_trust_record (ctrl, pk, &rec); if (!err) { if (DBG_TRUST) log_debug ("key %08lX%08lX: update min_ownertrust from %u to %u\n", (ulong)kid[0],(ulong)kid[1], (unsigned int)rec.r.trust.min_ownertrust, new_trust ); if (rec.r.trust.min_ownertrust != new_trust) { rec.r.trust.min_ownertrust = new_trust; write_record (ctrl, &rec); tdb_revalidation_mark (ctrl); do_sync (); } } else if (gpg_err_code (err) == GPG_ERR_NOT_FOUND) { /* no record yet - create a new one */ if (DBG_TRUST) log_debug ("insert min_ownertrust %u\n", new_trust ); memset (&rec, 0, sizeof rec); rec.recnum = tdbio_new_recnum (ctrl); rec.rectype = RECTYPE_TRUST; fpr20_from_pk (pk, rec.r.trust.fingerprint); rec.r.trust.min_ownertrust = new_trust; write_record (ctrl, &rec); tdb_revalidation_mark (ctrl); do_sync (); } else { tdbio_invalid (); } free_public_key (pk); } /* * Clear the ownertrust and min_ownertrust values. * * Return: True if a change actually happened. */ int tdb_clear_ownertrusts (ctrl_t ctrl, PKT_public_key *pk) { TRUSTREC rec; gpg_error_t err; init_trustdb (ctrl, 0); if (trustdb_args.no_trustdb && opt.trust_model == TM_ALWAYS) return 0; err = read_trust_record (ctrl, pk, &rec); if (!err) { if (DBG_TRUST) { log_debug ("clearing ownertrust (old value %u)\n", (unsigned int)rec.r.trust.ownertrust); log_debug ("clearing min_ownertrust (old value %u)\n", (unsigned int)rec.r.trust.min_ownertrust); } if (rec.r.trust.ownertrust || rec.r.trust.min_ownertrust) { rec.r.trust.ownertrust = 0; rec.r.trust.min_ownertrust = 0; write_record (ctrl, &rec); tdb_revalidation_mark (ctrl); do_sync (); return 1; } } else if (gpg_err_code (err) != GPG_ERR_NOT_FOUND) { tdbio_invalid (); } return 0; } /* * Note: Caller has to do a sync */ static void update_validity (ctrl_t ctrl, PKT_public_key *pk, PKT_user_id *uid, int depth, int validity) { TRUSTREC trec, vrec; gpg_error_t err; ulong recno; namehash_from_uid(uid); err = read_trust_record (ctrl, pk, &trec); if (err && gpg_err_code (err) != GPG_ERR_NOT_FOUND) { tdbio_invalid (); return; } if (gpg_err_code (err) == GPG_ERR_NOT_FOUND) { /* No record yet - create a new one. */ memset (&trec, 0, sizeof trec); trec.recnum = tdbio_new_recnum (ctrl); trec.rectype = RECTYPE_TRUST; fpr20_from_pk (pk, trec.r.trust.fingerprint); trec.r.trust.ownertrust = 0; } /* locate an existing one */ recno = trec.r.trust.validlist; while (recno) { read_record (recno, &vrec, RECTYPE_VALID); if ( !memcmp (vrec.r.valid.namehash, uid->namehash, 20) ) break; recno = vrec.r.valid.next; } if (!recno) /* insert a new validity record */ { memset (&vrec, 0, sizeof vrec); vrec.recnum = tdbio_new_recnum (ctrl); vrec.rectype = RECTYPE_VALID; memcpy (vrec.r.valid.namehash, uid->namehash, 20); vrec.r.valid.next = trec.r.trust.validlist; trec.r.trust.validlist = vrec.recnum; } vrec.r.valid.validity = validity; vrec.r.valid.full_count = uid->help_full_count; vrec.r.valid.marginal_count = uid->help_marginal_count; write_record (ctrl, &vrec); trec.r.trust.depth = depth; write_record (ctrl, &trec); } /*********************************************** ********* Query trustdb values ************** ***********************************************/ /* Return true if key is disabled. Note that this is usually used via the pk_is_disabled macro. */ int tdb_cache_disabled_value (ctrl_t ctrl, PKT_public_key *pk) { gpg_error_t err; TRUSTREC trec; int disabled = 0; if (pk->flags.disabled_valid) return pk->flags.disabled; init_trustdb (ctrl, 0); if (trustdb_args.no_trustdb) return 0; /* No trustdb => not disabled. */ err = read_trust_record (ctrl, pk, &trec); if (err && gpg_err_code (err) != GPG_ERR_NOT_FOUND) { tdbio_invalid (); goto leave; } if (gpg_err_code (err) == GPG_ERR_NOT_FOUND) { /* No record found, so assume not disabled. */ goto leave; } if ((trec.r.trust.ownertrust & TRUST_FLAG_DISABLED)) disabled = 1; /* Cache it for later so we don't need to look at the trustdb every time */ pk->flags.disabled = disabled; pk->flags.disabled_valid = 1; leave: return disabled; } void tdb_check_trustdb_stale (ctrl_t ctrl) { static int did_nextcheck=0; init_trustdb (ctrl, 0); if (trustdb_args.no_trustdb) return; /* No trustdb => can't be stale. */ if (!did_nextcheck && (opt.trust_model == TM_PGP || opt.trust_model == TM_CLASSIC || opt.trust_model == TM_TOFU_PGP || opt.trust_model == TM_TOFU)) { ulong scheduled; did_nextcheck = 1; scheduled = tdbio_read_nextcheck (); if ((scheduled && scheduled <= make_timestamp ()) || pending_check_trustdb) { if (opt.no_auto_check_trustdb) { pending_check_trustdb = 1; if (!opt.quiet) log_info (_("please do a --check-trustdb\n")); } else { if (!opt.quiet) log_info (_("checking the trustdb\n")); validate_keys (ctrl, 0); } } } } /* * Return the validity information for KB/PK (at least one of them * must be non-NULL). This is the core of get_validity. If SIG is * not NULL, then the trust is being evaluated in the context of the * provided signature. This is used by the TOFU code to record * statistics. */ unsigned int tdb_get_validity_core (ctrl_t ctrl, kbnode_t kb, PKT_public_key *pk, PKT_user_id *uid, PKT_public_key *main_pk, PKT_signature *sig, int may_ask) { TRUSTREC trec, vrec; gpg_error_t err = 0; ulong recno; #ifdef USE_TOFU unsigned int tofu_validity = TRUST_UNKNOWN; int free_kb = 0; #endif unsigned int validity = TRUST_UNKNOWN; if (kb && pk) log_assert (keyid_cmp (pk_main_keyid (pk), pk_main_keyid (kb->pkt->pkt.public_key)) == 0); if (! pk) { log_assert (kb); pk = kb->pkt->pkt.public_key; } #ifndef USE_TOFU (void)sig; (void)may_ask; #endif init_trustdb (ctrl, 0); /* If we have no trustdb (which also means it has not been created) and the trust-model is always, we don't know the validity - return immediately. If we won't do that the tdbio code would try to open the trustdb and run into a fatal error. */ if (trustdb_args.no_trustdb && opt.trust_model == TM_ALWAYS) return TRUST_UNKNOWN; check_trustdb_stale (ctrl); if(opt.trust_model==TM_DIRECT) { /* Note that this happens BEFORE any user ID stuff is checked. The direct trust model applies to keys as a whole. */ validity = tdb_get_ownertrust (ctrl, main_pk, 0); goto leave; } #ifdef USE_TOFU if (opt.trust_model == TM_TOFU || opt.trust_model == TM_TOFU_PGP) { kbnode_t n = NULL; strlist_t user_id_list = NULL; int done = 0; /* If the caller didn't supply a user id then use all uids. */ if (! uid) { if (! kb) { kb = get_pubkeyblock (ctrl, main_pk->keyid); free_kb = 1; } n = kb; } if (DBG_TRUST && sig && sig->signers_uid) log_debug ("TOFU: only considering user id: '%s'\n", sig->signers_uid); while (!done && (uid || (n = find_next_kbnode (n, PKT_USER_ID)))) { PKT_user_id *user_id; int expired = 0; if (uid) { user_id = uid; /* If the caller specified a user id, then we only process the specified user id and are done after the first iteration. */ done = 1; } else user_id = n->pkt->pkt.user_id; if (user_id->attrib_data) /* Skip user attributes. */ continue; if (sig && sig->signers_uid) /* Make sure the UID matches. */ { char *email = mailbox_from_userid (user_id->name, 0); if (!email || !*email || strcmp (sig->signers_uid, email) != 0) { if (DBG_TRUST) log_debug ("TOFU: skipping user id '%s', which does" " not match the signer's email ('%s')\n", email, sig->signers_uid); xfree (email); continue; } xfree (email); } /* If the user id is revoked or expired, then skip it. */ if (user_id->flags.revoked || user_id->flags.expired) { if (DBG_TRUST) { char *s; if (user_id->flags.revoked && user_id->flags.expired) s = "revoked and expired"; else if (user_id->flags.revoked) s = "revoked"; else s = "expire"; log_debug ("TOFU: Ignoring %s user id (%s)\n", s, user_id->name); } if (user_id->flags.revoked) continue; expired = 1; } add_to_strlist (&user_id_list, user_id->name); user_id_list->flags = expired; } /* Process the user ids in the order they appear in the key block. */ strlist_rev (&user_id_list); /* It only makes sense to observe any signature before getting the validity. This is because if the current signature results in a conflict, then we damn well want to take that into account. */ if (sig) { err = tofu_register_signature (ctrl, main_pk, user_id_list, sig->digest, sig->digest_len, sig->timestamp, "unknown"); if (err) { log_error ("TOFU: error registering signature: %s\n", gpg_strerror (err)); tofu_validity = TRUST_UNKNOWN; } } if (! err) tofu_validity = tofu_get_validity (ctrl, main_pk, user_id_list, may_ask); free_strlist (user_id_list); if (free_kb) release_kbnode (kb); } #endif /*USE_TOFU*/ if (opt.trust_model == TM_TOFU_PGP || opt.trust_model == TM_CLASSIC || opt.trust_model == TM_PGP) { err = read_trust_record (ctrl, main_pk, &trec); if (err && gpg_err_code (err) != GPG_ERR_NOT_FOUND) { tdbio_invalid (); return 0; } if (gpg_err_code (err) == GPG_ERR_NOT_FOUND) { /* No record found. */ validity = TRUST_UNKNOWN; goto leave; } /* Loop over all user IDs */ recno = trec.r.trust.validlist; validity = 0; while (recno) { read_record (recno, &vrec, RECTYPE_VALID); if(uid) { /* If a user ID is given we return the validity for that user ID ONLY. If the namehash is not found, then there is no validity at all (i.e. the user ID wasn't signed). */ if(memcmp(vrec.r.valid.namehash,uid->namehash,20)==0) { validity=(vrec.r.valid.validity & TRUST_MASK); break; } } else { /* If no user ID is given, we take the maximum validity over all user IDs */ if (validity < (vrec.r.valid.validity & TRUST_MASK)) validity = (vrec.r.valid.validity & TRUST_MASK); } recno = vrec.r.valid.next; } if ((trec.r.trust.ownertrust & TRUST_FLAG_DISABLED)) { validity |= TRUST_FLAG_DISABLED; pk->flags.disabled = 1; } else pk->flags.disabled = 0; pk->flags.disabled_valid = 1; } leave: #ifdef USE_TOFU validity = tofu_wot_trust_combine (tofu_validity, validity); #else /*!USE_TOFU*/ validity &= TRUST_MASK; if (validity == TRUST_NEVER) /* TRUST_NEVER trumps everything else. */ validity |= TRUST_NEVER; if (validity == TRUST_EXPIRED) /* TRUST_EXPIRED trumps everything but TRUST_NEVER. */ validity |= TRUST_EXPIRED; #endif /*!USE_TOFU*/ if (opt.trust_model != TM_TOFU && pending_check_trustdb) validity |= TRUST_FLAG_PENDING_CHECK; return validity; } static void get_validity_counts (ctrl_t ctrl, PKT_public_key *pk, PKT_user_id *uid) { TRUSTREC trec, vrec; ulong recno; if(pk==NULL || uid==NULL) BUG(); namehash_from_uid(uid); uid->help_marginal_count=uid->help_full_count=0; init_trustdb (ctrl, 0); if(read_trust_record (ctrl, pk, &trec)) return; /* loop over all user IDs */ recno = trec.r.trust.validlist; while (recno) { read_record (recno, &vrec, RECTYPE_VALID); if(memcmp(vrec.r.valid.namehash,uid->namehash,20)==0) { uid->help_marginal_count=vrec.r.valid.marginal_count; uid->help_full_count=vrec.r.valid.full_count; /* es_printf("Fetched marginal %d, full %d\n",uid->help_marginal_count,uid->help_full_count); */ break; } recno = vrec.r.valid.next; } } void list_trust_path( const char *username ) { (void)username; } /**************** * Enumerate all keys, which are needed to build all trust paths for * the given key. This function does not return the key itself or * the ultimate key (the last point in cerificate chain). Only * certificate chains which ends up at an ultimately trusted key * are listed. If ownertrust or validity is not NULL, the corresponding * value for the returned LID is also returned in these variable(s). * * 1) create a void pointer and initialize it to NULL * 2) pass this void pointer by reference to this function. * Set lid to the key you want to enumerate and pass it by reference. * 3) call this function as long as it does not return -1 * to indicate EOF. LID does contain the next key used to build the web * 4) Always call this function a last time with LID set to NULL, * so that it can free its context. * * Returns: -1 on EOF or the level of the returned LID */ int enum_cert_paths( void **context, ulong *lid, unsigned *ownertrust, unsigned *validity ) { (void)context; (void)lid; (void)ownertrust; (void)validity; return -1; } /**************** * Print the current path */ void enum_cert_paths_print (void **context, FILE *fp, int refresh, ulong selected_lid) { (void)context; (void)fp; (void)refresh; (void)selected_lid; } /**************************************** *********** NEW NEW NEW **************** ****************************************/ static int ask_ownertrust (ctrl_t ctrl, u32 *kid, int minimum) { PKT_public_key *pk; int rc; int ot; pk = xmalloc_clear (sizeof *pk); rc = get_pubkey (ctrl, pk, kid); if (rc) { log_error (_("public key %s not found: %s\n"), keystr(kid), gpg_strerror (rc) ); return TRUST_UNKNOWN; } if(opt.force_ownertrust) { log_info("force trust for key %s to %s\n", keystr(kid),trust_value_to_string(opt.force_ownertrust)); tdb_update_ownertrust (ctrl, pk, opt.force_ownertrust); ot=opt.force_ownertrust; } else { ot=edit_ownertrust (ctrl, pk, 0); if(ot>0) ot = tdb_get_ownertrust (ctrl, pk, 0); else if(ot==0) ot = minimum?minimum:TRUST_UNDEFINED; else ot = -1; /* quit */ } free_public_key( pk ); return ot; } static void mark_keyblock_seen (KeyHashTable tbl, KBNODE node) { for ( ;node; node = node->next ) if (node->pkt->pkttype == PKT_PUBLIC_KEY || node->pkt->pkttype == PKT_PUBLIC_SUBKEY) { u32 aki[2]; keyid_from_pk (node->pkt->pkt.public_key, aki); add_key_hash_table (tbl, aki); } } static void dump_key_array (int depth, struct key_array *keys) { struct key_array *kar; for (kar=keys; kar->keyblock; kar++) { KBNODE node = kar->keyblock; u32 kid[2]; keyid_from_pk(node->pkt->pkt.public_key, kid); es_printf ("%d:%08lX%08lX:K::%c::::\n", depth, (ulong)kid[0], (ulong)kid[1], '?'); for (; node; node = node->next) { if (node->pkt->pkttype == PKT_USER_ID) { int len = node->pkt->pkt.user_id->len; if (len > 30) len = 30; es_printf ("%d:%08lX%08lX:U:::%c:::", depth, (ulong)kid[0], (ulong)kid[1], (node->flag & 4)? 'f': (node->flag & 2)? 'm': (node->flag & 1)? 'q':'-'); es_write_sanitized (es_stdout, node->pkt->pkt.user_id->name, len, ":", NULL); es_putc (':', es_stdout); es_putc ('\n', es_stdout); } } } } static void store_validation_status (ctrl_t ctrl, int depth, kbnode_t keyblock, KeyHashTable stored) { KBNODE node; int status; int any = 0; for (node=keyblock; node; node = node->next) { if (node->pkt->pkttype == PKT_USER_ID) { PKT_user_id *uid = node->pkt->pkt.user_id; if (node->flag & 4) status = TRUST_FULLY; else if (node->flag & 2) status = TRUST_MARGINAL; else if (node->flag & 1) status = TRUST_UNDEFINED; else status = 0; if (status) { update_validity (ctrl, keyblock->pkt->pkt.public_key, uid, depth, status); mark_keyblock_seen(stored,keyblock); any = 1; } } } if (any) do_sync (); } /* Returns a sanitized copy of the regexp (which might be "", but not NULL). */ /* Operator characters except '.' and backslash. See regex(7) on BSD. */ #define REGEXP_OPERATOR_CHARS "^[$()|*+?{" static char * sanitize_regexp(const char *old) { size_t start=0,len=strlen(old),idx=0; int escaped=0,standard_bracket=0; char *new=xmalloc((len*2)+1); /* enough to \-escape everything if we have to */ /* There are basically two commonly-used regexps here. GPG and most versions of PGP use "<[^>]+[@.]example\.com>$" and PGP (9) command line uses "example.com" (i.e. whatever the user specifies, and we can't expect users know to use "\." instead of "."). So here are the rules: we're allowed to start with "<[^>]+[@.]" and end with ">$" or start and end with nothing. In between, the only legal regex character is ".", and everything else gets escaped. Part of the gotcha here is that some regex packages allow more than RFC-4880 requires. For example, 4880 has no "{}" operator, but GNU regex does. Commenting removes these operators from consideration. A possible future enhancement is to use commenting to effectively back off a given regex to the Henry Spencer syntax in 4880. -dshaw */ /* Are we bracketed between "<[^>]+[@.]" and ">$" ? */ if(len>=12 && strncmp(old,"<[^>]+[@.]",10)==0 && old[len-2]=='>' && old[len-1]=='$') { strcpy(new,"<[^>]+[@.]"); idx=strlen(new); standard_bracket=1; start+=10; len-=2; } /* Walk the remaining characters and ensure that everything that is left is not an operational regex character. */ for(;start$", then it was escaping the ">" and is fine. If the regexp actually ended with the bare "\", then it's an illegal regexp and regcomp should kick it out. */ if(standard_bracket) strcat(new,">$"); return new; } /* Used by validate_one_keyblock to confirm a regexp within a trust signature. Returns 1 for match, and 0 for no match or regex error. */ static int check_regexp(const char *expr,const char *string) { int ret; char *regexp; regexp=sanitize_regexp(expr); { regex_t pat; ret=regcomp(&pat,regexp,REG_ICASE|REG_EXTENDED); if(ret==0) { ret=regexec(&pat,string,0,NULL,0); regfree(&pat); } ret=(ret==0); } if(DBG_TRUST) log_debug("regexp '%s' ('%s') on '%s': %s\n", regexp,expr,string,ret?"YES":"NO"); xfree(regexp); return ret; } /* * Return true if the key is signed by one of the keys in the given * key ID list. User IDs with a valid signature are marked by node * flags as follows: * flag bit 0: There is at least one signature * 1: There is marginal confidence that this is a legitimate uid * 2: There is full confidence that this is a legitimate uid. * 8: Used for internal purposes. * 9: Ditto (in mark_usable_uid_certs()) * 10: Ditto (ditto) * This function assumes that all kbnode flags are cleared on entry. */ static int validate_one_keyblock (ctrl_t ctrl, kbnode_t kb, struct key_item *klist, u32 curtime, u32 *next_expire) { struct key_item *kr; KBNODE node, uidnode=NULL; PKT_user_id *uid=NULL; PKT_public_key *pk = kb->pkt->pkt.public_key; u32 main_kid[2]; int issigned=0, any_signed = 0; keyid_from_pk(pk, main_kid); for (node=kb; node; node = node->next) { /* A bit of discussion here: is it better for the web of trust to be built among only self-signed uids? On the one hand, a self-signed uid is a statement that the key owner definitely intended that uid to be there, but on the other hand, a signed (but not self-signed) uid does carry trust, of a sort, even if it is a statement being made by people other than the key owner "through" the uids on the key owner's key. I'm going with the latter. However, if the user ID was explicitly revoked, or passively allowed to expire, that should stop validity through the user ID until it is resigned. -dshaw */ if (node->pkt->pkttype == PKT_USER_ID && !node->pkt->pkt.user_id->flags.revoked && !node->pkt->pkt.user_id->flags.expired) { if (uidnode && issigned) { if (uid->help_full_count >= opt.completes_needed || uid->help_marginal_count >= opt.marginals_needed ) uidnode->flag |= 4; else if (uid->help_full_count || uid->help_marginal_count) uidnode->flag |= 2; uidnode->flag |= 1; any_signed = 1; } uidnode = node; uid=uidnode->pkt->pkt.user_id; /* If the selfsig is going to expire... */ if(uid->expiredate && uid->expiredate<*next_expire) *next_expire = uid->expiredate; issigned = 0; get_validity_counts (ctrl, pk, uid); mark_usable_uid_certs (ctrl, kb, uidnode, main_kid, klist, curtime, next_expire); } else if (node->pkt->pkttype == PKT_SIGNATURE && (node->flag & (1<<8)) && uid) { /* Note that we are only seeing unrevoked sigs here */ PKT_signature *sig = node->pkt->pkt.signature; kr = is_in_klist (klist, sig); /* If the trust_regexp does not match, it's as if the sig did not exist. This is safe for non-trust sigs as well since we don't accept a regexp on the sig unless it's a trust sig. */ if (kr && (!kr->trust_regexp || !(opt.trust_model == TM_PGP || opt.trust_model == TM_TOFU_PGP) || (uidnode && check_regexp(kr->trust_regexp, uidnode->pkt->pkt.user_id->name)))) { /* Are we part of a trust sig chain? We always favor the latest trust sig, rather than the greater or lesser trust sig or value. I could make a decent argument for any of these cases, but this seems to be what PGP does, and I'd like to be compatible. -dms */ if ((opt.trust_model == TM_PGP || opt.trust_model == TM_TOFU_PGP) && sig->trust_depth && pk->trust_timestamp <= sig->timestamp) { unsigned char depth; /* If the depth on the signature is less than the chain currently has, then use the signature depth so we don't increase the depth beyond what the signer wanted. If the depth on the signature is more than the chain currently has, then use the chain depth so we use as much of the signature depth as the chain will permit. An ultimately trusted signature can restart the depth to whatever level it likes. */ if (sig->trust_depth < kr->trust_depth || kr->ownertrust == TRUST_ULTIMATE) depth = sig->trust_depth; else depth = kr->trust_depth; if (depth) { if(DBG_TRUST) log_debug ("trust sig on %s, sig depth is %d," " kr depth is %d\n", uidnode->pkt->pkt.user_id->name, sig->trust_depth, kr->trust_depth); /* If we got here, we know that: this is a trust sig. it's a newer trust sig than any previous trust sig on this key (not uid). it is legal in that it was either generated by an ultimate key, or a key that was part of a trust chain, and the depth does not violate the original trust sig. if there is a regexp attached, it matched successfully. */ if (DBG_TRUST) log_debug ("replacing trust value %d with %d and " "depth %d with %d\n", pk->trust_value,sig->trust_value, pk->trust_depth,depth); pk->trust_value = sig->trust_value; pk->trust_depth = depth-1; /* If the trust sig contains a regexp, record it on the pk for the next round. */ if (sig->trust_regexp) pk->trust_regexp = sig->trust_regexp; } } if (kr->ownertrust == TRUST_ULTIMATE) uid->help_full_count = opt.completes_needed; else if (kr->ownertrust == TRUST_FULLY) uid->help_full_count++; else if (kr->ownertrust == TRUST_MARGINAL) uid->help_marginal_count++; issigned = 1; } } } if (uidnode && issigned) { if (uid->help_full_count >= opt.completes_needed || uid->help_marginal_count >= opt.marginals_needed ) uidnode->flag |= 4; else if (uid->help_full_count || uid->help_marginal_count) uidnode->flag |= 2; uidnode->flag |= 1; any_signed = 1; } return any_signed; } static int search_skipfnc (void *opaque, u32 *kid, int dummy_uid_no) { (void)dummy_uid_no; return test_key_hash_table ((KeyHashTable)opaque, kid); } /* * Scan all keys and return a key_array of all suitable keys from * klist. The caller has to pass keydb handle so that we don't use * to create our own. Returns either a key_array or NULL in case of * an error. No results found are indicated by an empty array. * Caller hast to release the returned array. */ static struct key_array * validate_key_list (ctrl_t ctrl, KEYDB_HANDLE hd, KeyHashTable full_trust, struct key_item *klist, u32 curtime, u32 *next_expire) { KBNODE keyblock = NULL; struct key_array *keys = NULL; size_t nkeys, maxkeys; int rc; KEYDB_SEARCH_DESC desc; maxkeys = 1000; keys = xmalloc ((maxkeys+1) * sizeof *keys); nkeys = 0; rc = keydb_search_reset (hd); if (rc) { log_error ("keydb_search_reset failed: %s\n", gpg_strerror (rc)); xfree (keys); return NULL; } memset (&desc, 0, sizeof desc); desc.mode = KEYDB_SEARCH_MODE_FIRST; desc.skipfnc = search_skipfnc; desc.skipfncvalue = full_trust; rc = keydb_search (hd, &desc, 1, NULL); if (gpg_err_code (rc) == GPG_ERR_NOT_FOUND) { keys[nkeys].keyblock = NULL; return keys; } if (rc) { log_error ("keydb_search(first) failed: %s\n", gpg_strerror (rc)); goto die; } desc.mode = KEYDB_SEARCH_MODE_NEXT; /* change mode */ do { PKT_public_key *pk; rc = keydb_get_keyblock (hd, &keyblock); if (rc) { log_error ("keydb_get_keyblock failed: %s\n", gpg_strerror (rc)); goto die; } if ( keyblock->pkt->pkttype != PKT_PUBLIC_KEY) { log_debug ("ooops: invalid pkttype %d encountered\n", keyblock->pkt->pkttype); dump_kbnode (keyblock); release_kbnode(keyblock); continue; } /* prepare the keyblock for further processing */ merge_keys_and_selfsig (ctrl, keyblock); clear_kbnode_flags (keyblock); pk = keyblock->pkt->pkt.public_key; if (pk->has_expired || pk->flags.revoked) { /* it does not make sense to look further at those keys */ mark_keyblock_seen (full_trust, keyblock); } else if (validate_one_keyblock (ctrl, keyblock, klist, curtime, next_expire)) { KBNODE node; if (pk->expiredate && pk->expiredate >= curtime && pk->expiredate < *next_expire) *next_expire = pk->expiredate; if (nkeys == maxkeys) { maxkeys += 1000; keys = xrealloc (keys, (maxkeys+1) * sizeof *keys); } keys[nkeys++].keyblock = keyblock; /* Optimization - if all uids are fully trusted, then we never need to consider this key as a candidate again. */ for (node=keyblock; node; node = node->next) if (node->pkt->pkttype == PKT_USER_ID && !(node->flag & 4)) break; if(node==NULL) mark_keyblock_seen (full_trust, keyblock); keyblock = NULL; } release_kbnode (keyblock); keyblock = NULL; } while (!(rc = keydb_search (hd, &desc, 1, NULL))); if (rc && gpg_err_code (rc) != GPG_ERR_NOT_FOUND) { log_error ("keydb_search_next failed: %s\n", gpg_strerror (rc)); goto die; } keys[nkeys].keyblock = NULL; return keys; die: keys[nkeys].keyblock = NULL; release_key_array (keys); return NULL; } /* Caller must sync */ static void reset_trust_records (ctrl_t ctrl) { TRUSTREC rec; ulong recnum; int count = 0, nreset = 0; for (recnum=1; !tdbio_read_record (recnum, &rec, 0); recnum++ ) { if(rec.rectype==RECTYPE_TRUST) { count++; if(rec.r.trust.min_ownertrust) { rec.r.trust.min_ownertrust=0; write_record (ctrl, &rec); } } else if(rec.rectype==RECTYPE_VALID && ((rec.r.valid.validity&TRUST_MASK) || rec.r.valid.marginal_count || rec.r.valid.full_count)) { rec.r.valid.validity &= ~TRUST_MASK; rec.r.valid.marginal_count=rec.r.valid.full_count=0; nreset++; write_record (ctrl, &rec); } } if (opt.verbose) { log_info (ngettext("%d key processed", "%d keys processed", count), count); log_printf (ngettext(" (%d validity count cleared)\n", " (%d validity counts cleared)\n", nreset), nreset); } } /* * Run the key validation procedure. * * This works this way: * Step 1: Find all ultimately trusted keys (UTK). * mark them all as seen and put them into klist. * Step 2: loop max_cert_times * Step 3: if OWNERTRUST of any key in klist is undefined * ask user to assign ownertrust * Step 4: Loop over all keys in the keyDB which are not marked seen * Step 5: if key is revoked or expired * mark key as seen * continue loop at Step 4 * Step 6: For each user ID of that key signed by a key in klist * Calculate validity by counting trusted signatures. * Set validity of user ID * Step 7: If any signed user ID was found * mark key as seen * End Loop * Step 8: Build a new klist from all fully trusted keys from step 6 * End Loop * Ready * */ static int validate_keys (ctrl_t ctrl, int interactive) { int rc = 0; int quit=0; struct key_item *klist = NULL; struct key_item *k; struct key_array *keys = NULL; struct key_array *kar; KEYDB_HANDLE kdb = NULL; KBNODE node; int depth; int ot_unknown, ot_undefined, ot_never, ot_marginal, ot_full, ot_ultimate; KeyHashTable stored,used,full_trust; u32 start_time, next_expire; /* Make sure we have all sigs cached. TODO: This is going to require some architectural re-thinking, as it is agonizingly slow. Perhaps combine this with reset_trust_records(), or only check the caches on keys that are actually involved in the web of trust. */ keydb_rebuild_caches (ctrl, 0); kdb = keydb_new (ctrl); if (!kdb) return gpg_error_from_syserror (); start_time = make_timestamp (); next_expire = 0xffffffff; /* set next expire to the year 2106 */ stored = new_key_hash_table (); used = new_key_hash_table (); full_trust = new_key_hash_table (); reset_trust_records (ctrl); /* Fixme: Instead of always building a UTK list, we could just build it * here when needed */ if (!utk_list) { if (!opt.quiet) log_info (_("no ultimately trusted keys found\n")); goto leave; } /* mark all UTKs as used and fully_trusted and set validity to ultimate */ for (k=utk_list; k; k = k->next) { KBNODE keyblock; PKT_public_key *pk; keyblock = get_pubkeyblock (ctrl, k->kid); if (!keyblock) { log_error (_("public key of ultimately" " trusted key %s not found\n"), keystr(k->kid)); continue; } mark_keyblock_seen (used, keyblock); mark_keyblock_seen (stored, keyblock); mark_keyblock_seen (full_trust, keyblock); pk = keyblock->pkt->pkt.public_key; for (node=keyblock; node; node = node->next) { if (node->pkt->pkttype == PKT_USER_ID) update_validity (ctrl, pk, node->pkt->pkt.user_id, 0, TRUST_ULTIMATE); } if ( pk->expiredate && pk->expiredate >= start_time && pk->expiredate < next_expire) next_expire = pk->expiredate; release_kbnode (keyblock); do_sync (); } if (opt.trust_model == TM_TOFU) /* In the TOFU trust model, we only need to save the ultimately trusted keys. */ goto leave; klist = utk_list; if (!opt.quiet) log_info ("marginals needed: %d completes needed: %d trust model: %s\n", opt.marginals_needed, opt.completes_needed, trust_model_string (opt.trust_model)); for (depth=0; depth < opt.max_cert_depth; depth++) { int valids=0,key_count; /* See whether we should assign ownertrust values to the keys in klist. */ ot_unknown = ot_undefined = ot_never = 0; ot_marginal = ot_full = ot_ultimate = 0; for (k=klist; k; k = k->next) { int min=0; /* 120 and 60 are as per RFC2440 */ if(k->trust_value>=120) min=TRUST_FULLY; else if(k->trust_value>=60) min=TRUST_MARGINAL; if(min!=k->min_ownertrust) update_min_ownertrust (ctrl, k->kid,min); if (interactive && k->ownertrust == TRUST_UNKNOWN) { k->ownertrust = ask_ownertrust (ctrl, k->kid,min); if (k->ownertrust == (unsigned int)(-1)) { quit=1; goto leave; } } /* This can happen during transition from an old trustdb before trust sigs. It can also happen if a user uses two different versions of GnuPG or changes the --trust-model setting. */ if(k->ownertrustkid[0],(ulong)k->kid[1], trust_value_to_string(k->ownertrust), trust_value_to_string(min)); k->ownertrust=min; } if (k->ownertrust == TRUST_UNKNOWN) ot_unknown++; else if (k->ownertrust == TRUST_UNDEFINED) ot_undefined++; else if (k->ownertrust == TRUST_NEVER) ot_never++; else if (k->ownertrust == TRUST_MARGINAL) ot_marginal++; else if (k->ownertrust == TRUST_FULLY) ot_full++; else if (k->ownertrust == TRUST_ULTIMATE) ot_ultimate++; valids++; } /* Find all keys which are signed by a key in kdlist */ keys = validate_key_list (ctrl, kdb, full_trust, klist, start_time, &next_expire); if (!keys) { log_error ("validate_key_list failed\n"); rc = GPG_ERR_GENERAL; goto leave; } for (key_count=0, kar=keys; kar->keyblock; kar++, key_count++) ; /* Store the calculated valididation status somewhere */ if (opt.verbose > 1 && DBG_TRUST) dump_key_array (depth, keys); for (kar=keys; kar->keyblock; kar++) store_validation_status (ctrl, depth, kar->keyblock, stored); if (!opt.quiet) log_info (_("depth: %d valid: %3d signed: %3d" " trust: %d-, %dq, %dn, %dm, %df, %du\n"), depth, valids, key_count, ot_unknown, ot_undefined, ot_never, ot_marginal, ot_full, ot_ultimate ); /* Build a new kdlist from all fully valid keys in KEYS */ if (klist != utk_list) release_key_items (klist); klist = NULL; for (kar=keys; kar->keyblock; kar++) { for (node=kar->keyblock; node; node = node->next) { if (node->pkt->pkttype == PKT_USER_ID && (node->flag & 4)) { u32 kid[2]; /* have we used this key already? */ keyid_from_pk (kar->keyblock->pkt->pkt.public_key, kid); if(test_key_hash_table(used,kid)==0) { /* Normally we add both the primary and subkey ids to the hash via mark_keyblock_seen, but since we aren't using this hash as a skipfnc, that doesn't matter here. */ add_key_hash_table (used,kid); k = new_key_item (); k->kid[0]=kid[0]; k->kid[1]=kid[1]; k->ownertrust = (tdb_get_ownertrust (ctrl, kar->keyblock->pkt->pkt.public_key, 0) & TRUST_MASK); k->min_ownertrust = tdb_get_min_ownertrust (ctrl, kar->keyblock->pkt->pkt.public_key, 0); k->trust_depth= kar->keyblock->pkt->pkt.public_key->trust_depth; k->trust_value= kar->keyblock->pkt->pkt.public_key->trust_value; if(kar->keyblock->pkt->pkt.public_key->trust_regexp) k->trust_regexp= xstrdup(kar->keyblock->pkt-> pkt.public_key->trust_regexp); k->next = klist; klist = k; break; } } } } release_key_array (keys); keys = NULL; if (!klist) break; /* no need to dive in deeper */ } leave: keydb_release (kdb); release_key_array (keys); if (klist != utk_list) release_key_items (klist); release_key_hash_table (full_trust); release_key_hash_table (used); release_key_hash_table (stored); if (!rc && !quit) /* mark trustDB as checked */ { int rc2; if (next_expire == 0xffffffff || next_expire < start_time ) tdbio_write_nextcheck (ctrl, 0); else { tdbio_write_nextcheck (ctrl, next_expire); if (!opt.quiet) log_info (_("next trustdb check due at %s\n"), strtimestamp (next_expire)); } rc2 = tdbio_update_version_record (ctrl); if (rc2) { log_error (_("unable to update trustdb version record: " "write failed: %s\n"), gpg_strerror (rc2)); tdbio_invalid (); } do_sync (); pending_check_trustdb = 0; } return rc; } diff --git a/g10/trustdb.h b/g10/trustdb.h index d52fc53f2..6c7fd6c8e 100644 --- a/g10/trustdb.h +++ b/g10/trustdb.h @@ -1,135 +1,133 @@ /* trustdb.h - Trust database * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, * 2005, 2012 Free Software Foundation, Inc. * * 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 . */ #ifndef G10_TRUSTDB_H #define G10_TRUSTDB_H /* Trust values must be sorted in ascending order! */ #define TRUST_MASK 15 #define TRUST_UNKNOWN 0 /* o: not yet calculated/assigned */ #define TRUST_EXPIRED 1 /* e: calculation may be invalid */ #define TRUST_UNDEFINED 2 /* q: not enough information for calculation */ #define TRUST_NEVER 3 /* n: never trust this pubkey */ #define TRUST_MARGINAL 4 /* m: marginally trusted */ #define TRUST_FULLY 5 /* f: fully trusted */ #define TRUST_ULTIMATE 6 /* u: ultimately trusted */ /* Trust values not covered by the mask. */ #define TRUST_FLAG_REVOKED 32 /* r: revoked */ #define TRUST_FLAG_SUB_REVOKED 64 /* r: revoked but for subkeys */ #define TRUST_FLAG_DISABLED 128 /* d: key/uid disabled */ #define TRUST_FLAG_PENDING_CHECK 256 /* a check-trustdb is pending */ #define TRUST_FLAG_TOFU_BASED 512 /* The trust value is based on * the TOFU information. */ /* Private value used in tofu.c - must be different from the trust values. */ #define _tofu_GET_TRUST_ERROR 100 /* Length of the hash used to select UIDs in keyedit.c. */ #define NAMEHASH_LEN 20 /*-- trust.c --*/ int cache_disabled_value (ctrl_t ctrl, PKT_public_key *pk); -void register_trusted_keyid (u32 *keyid); void register_trusted_key (const char *string); const char *trust_value_to_string (unsigned int value); int string_to_trust_value (const char *str); const char *uid_trust_string_fixed (ctrl_t ctrl, PKT_public_key *key, PKT_user_id *uid); unsigned int get_ownertrust (ctrl_t ctrl, PKT_public_key *pk); void update_ownertrust (ctrl_t ctrl, PKT_public_key *pk, unsigned int new_trust); int clear_ownertrusts (ctrl_t ctrl, PKT_public_key *pk); void revalidation_mark (ctrl_t ctrl); void check_trustdb_stale (ctrl_t ctrl); void check_or_update_trustdb (ctrl_t ctrl); unsigned int get_validity (ctrl_t ctrl, kbnode_t kb, PKT_public_key *pk, PKT_user_id *uid, PKT_signature *sig, int may_ask); int get_validity_info (ctrl_t ctrl, kbnode_t kb, PKT_public_key *pk, PKT_user_id *uid); const char *get_validity_string (ctrl_t ctrl, PKT_public_key *pk, PKT_user_id *uid); /*-- trustdb.c --*/ -void tdb_register_trusted_keyid (u32 *keyid); void tdb_register_trusted_key (const char *string); /* Returns whether KID is on the list of ultimately trusted keys. */ int tdb_keyid_is_utk (u32 *kid); /* Return the list of ultimately trusted keys. The caller must not * modify this list nor must it free the list. */ struct key_item *tdb_utks (void); void check_trustdb (ctrl_t ctrl); void update_trustdb (ctrl_t ctrl); int setup_trustdb( int level, const char *dbname ); void how_to_fix_the_trustdb (void); const char *trust_model_string (int model); gpg_error_t init_trustdb (ctrl_t ctrl, int no_create); int have_trustdb (ctrl_t ctrl); void tdb_check_trustdb_stale (ctrl_t ctrl); void tdb_revalidation_mark (ctrl_t ctrl); int trustdb_pending_check(void); void tdb_check_or_update (ctrl_t ctrl); int tdb_cache_disabled_value (ctrl_t ctrl, PKT_public_key *pk); unsigned int tdb_get_validity_core (ctrl_t ctrl, kbnode_t kb, PKT_public_key *pk, PKT_user_id *uid, PKT_public_key *main_pk, PKT_signature *sig, int may_ask); void list_trust_path( const char *username ); int enum_cert_paths( void **context, ulong *lid, unsigned *ownertrust, unsigned *validity ); void enum_cert_paths_print( void **context, FILE *fp, int refresh, ulong selected_lid ); void read_trust_options (ctrl_t ctrl, byte *trust_model, ulong *created, ulong *nextcheck, byte *marginals, byte *completes, byte *cert_depth, byte *min_cert_level); unsigned int tdb_get_ownertrust (ctrl_t ctrl, PKT_public_key *pk, int no_create); unsigned int tdb_get_min_ownertrust (ctrl_t ctrl, PKT_public_key *pk, int no_create); int get_ownertrust_info (ctrl_t ctrl, PKT_public_key *pk, int no_create); const char *get_ownertrust_string (ctrl_t ctrl, PKT_public_key *pk, int no_create); void tdb_update_ownertrust (ctrl_t ctrl, PKT_public_key *pk, unsigned int new_trust); int tdb_clear_ownertrusts (ctrl_t ctrl, PKT_public_key *pk); /*-- tdbdump.c --*/ void list_trustdb (ctrl_t ctrl, estream_t fp, const char *username); void export_ownertrust (ctrl_t ctrl); void import_ownertrust (ctrl_t ctrl, const char *fname); /*-- pkclist.c --*/ int edit_ownertrust (ctrl_t ctrl, PKT_public_key *pk, int mode); #endif /*G10_TRUSTDB_H*/