# # # patch "automate.cc" # from [87049e712992df21fb42ef1be995c32b6ff5bc4d] # to [5fecee3d3a25cb9b4d6acc26f32c3015ec3a427c] # # patch "cmd_key_cert.cc" # from [9767be9ce37d29af3921bf6b0d28d8934c55450c] # to [2c05d042474f603c0d90ff90eb18b54e147969c6] # # patch "key_store.cc" # from [330ba136f19b8be47f607d517d31aaf0a5df1e5f] # to [bd326bd1ecd08a77260bbb3e3b16bc5c6d3a3e23] # # patch "key_store.hh" # from [f6177a89fdc8de0253742753796d9433358697ac] # to [e766f5e892e86fd13789dab619dff23f8d18c61a] # # patch "options_list.hh" # from [99c4d289318e9ee197529222e338c7a4d355f0e7] # to [ebf225b29163498b112186d68498e7811360fd85] # # patch "tests/generating_and_extracting_keys_and_certs/__driver__.lua" # from [05637dc96224fada7b358b4cbbf7f98a380deb6e] # to [2eb174c51d9abc474580cdfb28ee5afcf3464977] # # patch "tests/key_files_created_securely/__driver__.lua" # from [e4e15e30715504a2eac0ef5b4fc5e83a4815931f] # to [63a9bd279770dc1fcefec5eb6cead7fd3e061982] # ============================================================ --- automate.cc 87049e712992df21fb42ef1be995c32b6ff5bc4d +++ automate.cc 5fecee3d3a25cb9b4d6acc26f32c3015ec3a427c @@ -1784,7 +1784,7 @@ CMD_AUTOMATE(genkey, N_("KEYID PASSPHRAS CMD_AUTOMATE(genkey, N_("KEYID PASSPHRASE"), N_("Generates a key"), "", - options::opts::none) + options::opts::force_duplicate_key) { E(args.size() == 2, origin::user, F("wrong argument count")); @@ -1795,18 +1795,21 @@ CMD_AUTOMATE(genkey, N_("KEYID PASSPHRAS key_name name; internalize_key_name(idx(args, 0), name); - E(!keys.key_pair_exists(name), origin::user, - F("you already have a key named '%s'") % name); - if (db.database_specified()) + if (!app.opts.force_duplicate_key) { - E(!db.public_key_exists(name), origin::user, - F("there is another key named '%s'") % name); + E(!keys.key_pair_exists(name), origin::user, + F("you already have a key named '%s'") % name); + if (db.database_specified()) + { + E(!db.public_key_exists(name), origin::user, + F("there is another key named '%s'") % name); + } } utf8 passphrase = idx(args, 1); key_id hash; - keys.create_key_pair(db, name, &passphrase, &hash); + keys.create_key_pair(db, name, key_store::create_quiet, &passphrase, &hash); basic_io::printer prt; basic_io::stanza stz; ============================================================ --- cmd_key_cert.cc 9767be9ce37d29af3921bf6b0d28d8934c55450c +++ cmd_key_cert.cc 2c05d042474f603c0d90ff90eb18b54e147969c6 @@ -32,7 +32,7 @@ CMD(genkey, "genkey", "", CMD_REF(key_an CMD(genkey, "genkey", "", CMD_REF(key_and_cert), N_("KEYID"), N_("Generates an RSA key-pair"), "", - options::opts::none) + options::opts::force_duplicate_key) { database db(app); key_store keys(app); @@ -43,12 +43,15 @@ CMD(genkey, "genkey", "", CMD_REF(key_an key_name name; internalize_key_name(idx(args, 0), name); - E(!keys.key_pair_exists(name), origin::user, - F("you already have a key named '%s'") % name); - if (db.database_specified()) + if (!app.opts.force_duplicate_key) { - E(!db.public_key_exists(name), origin::user, - F("there is another key named '%s'") % name); + E(!keys.key_pair_exists(name), origin::user, + F("you already have a key named '%s'") % name); + if (db.database_specified()) + { + E(!db.public_key_exists(name), origin::user, + F("there is another key named '%s'") % name); + } } keys.create_key_pair(db, name); ============================================================ --- key_store.cc 330ba136f19b8be47f607d517d31aaf0a5df1e5f +++ key_store.cc bd326bd1ecd08a77260bbb3e3b16bc5c6d3a3e23 @@ -16,6 +16,7 @@ #include #include +#include "char_classifiers.hh" #include "key_store.hh" #include "file_io.hh" #include "packet.hh" @@ -96,7 +97,8 @@ struct key_store_state } // internal methods - void get_key_file(key_id const & ident, system_path & file); + void get_key_file(key_id const & ident, key_name const & name, + system_path & file); void get_old_key_file(key_name const & name, system_path & file); void write_key(full_key_info const & info); void maybe_read_key_dir(); @@ -321,12 +323,31 @@ key_store_state::get_key_file(key_id con void key_store_state::get_key_file(key_id const & ident, + key_name const & name, system_path & file) { hexenc encoded; encode_hexenc(ident.inner(), encoded); - file = key_dir / path_component(encoded(), origin::internal); + static const string allowed_special_chars("@%^_-+=.,;~[]"); + string basename; + for (string::const_iterator iter = name().begin(); + iter != name().end(); ++iter) + { + if (is_alnum(*iter) || + is_space(*iter) || + allowed_special_chars.find(*iter) != string::npos) + { + basename += *iter; + } + else + { + basename += '?'; + } + } + + file = key_dir / path_component(basename + "." + encoded(), + origin::internal); } void @@ -353,7 +374,7 @@ key_store_state::write_key(full_key_info data dat(oss.str(), info.second.first.made_from); system_path file; - get_key_file(info.first, file); + get_key_file(info.first, info.second.first, file); // Make sure the private key is not readable by anyone other than the user. L(FL("writing key '%s' to file '%s' in dir '%s'") @@ -406,13 +427,14 @@ key_store::delete_key(key_id const & ide key_map::iterator i = s->keys.find(ident); if (i != s->keys.end()) { + system_path file; + s->get_key_file(ident, i->second.first, file); + delete_file(file); + s->keys.erase(i); s->signer_cache.erase(ident); s->privkey_cache.erase(ident); } - system_path file; - s->get_key_file(ident, file); - delete_file(file); } // @@ -587,6 +609,7 @@ key_store::create_key_pair(database & db void key_store::create_key_pair(database & db, key_name const & ident, + create_key_pair_mode create_mode, utf8 const * maybe_passphrase, key_id * const maybe_hash) { @@ -608,7 +631,14 @@ key_store::create_key_pair(database & db } // okay, now we can create the key - P(F("generating key-pair '%s'") % ident); + if (create_mode == create_verbose) + { + P(F("generating key-pair '%s'") % ident); + } + else + { + L(FL("generating key-pair '%s'") % ident); + } #if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,7,7) RSA_PrivateKey priv(s->rng->get(), static_cast(constants::keylen)); @@ -649,19 +679,39 @@ key_store::create_key_pair(database & db % kp.priv().size()); // and save it. - P(F("storing key-pair '%s' in %s/") % ident % get_key_dir()); + if (create_mode == create_verbose) + { + P(F("storing key-pair '%s' in %s/") % ident % get_key_dir()); + } + else + { + L(FL("storing key-pair '%s' in %s/") % ident % get_key_dir()); + } put_key_pair(ident, kp); if (db.database_specified()) { guard.acquire(); - P(F("storing public key '%s' in %s") % ident % db.get_filename()); + if (create_mode == create_verbose) + { + P(F("storing public key '%s' in %s") % ident % db.get_filename()); + } + else + { + L(FL("storing public key '%s' in %s") % ident % db.get_filename()); + } db.put_key(ident, kp.pub); guard.commit(); } + key_id hash; + key_hash_code(ident, kp.pub, hash); if (maybe_hash) - key_hash_code(ident, kp.pub, *maybe_hash); + *maybe_hash = hash; + if (create_mode == create_verbose) + { + P(F("key '%s' has hash '%s'") % ident % hash); + } } void ============================================================ --- key_store.hh f6177a89fdc8de0253742753796d9433358697ac +++ key_store.hh e766f5e892e86fd13789dab619dff23f8d18c61a @@ -86,7 +86,9 @@ public: void cache_decrypted_key(key_id const & id); + enum create_key_pair_mode { create_quiet, create_verbose }; void create_key_pair(database & db, key_name const & ident, + create_key_pair_mode create_mode = create_verbose, utf8 const * maybe_passphrase = NULL, key_id * const maybe_hash = NULL); ============================================================ --- options_list.hh 99c4d289318e9ee197529222e338c7a4d355f0e7 +++ options_list.hh ebf225b29163498b112186d68498e7811360fd85 @@ -371,6 +371,15 @@ GOPT(ssh_sign, "ssh-sign", std::string, } #endif +OPT(force_duplicate_key, "force-duplicate-key", bool, false, + gettext_noop("force genkey to not error out when the named key " + "already exists")) +#ifdef option_bodies +{ + force_duplicate_key = true; +} +#endif + OPT(full, "full", bool, false, gettext_noop("print detailed information")) #ifdef option_bodies ============================================================ --- tests/generating_and_extracting_keys_and_certs/__driver__.lua 05637dc96224fada7b358b4cbbf7f98a380deb6e +++ tests/generating_and_extracting_keys_and_certs/__driver__.lua 2eb174c51d9abc474580cdfb28ee5afcf3464977 @@ -10,7 +10,9 @@ check(mtn("genkey", tkey), 1, false, fal check(mtn("genkey", tkey), 1, false, false, tkey .. "\n" .. "\n" .. "\n" .. tkey .. "\n" .. tkey .. "\n") -- generate a new key -check(mtn("genkey", tkey), 0, false, false, tkey .. "\n" .. tkey .. "\n") +check(mtn("genkey", tkey), 0, false, true, tkey .. "\n" .. tkey .. "\n") +-- genkey prints key hash +check(qgrep("key '" .. tkey .. "' has hash '[[:xdigit:]]{40}'", "stderr")) -- check key exists check(mtn("ls", "keys"), 0, true) ============================================================ --- tests/key_files_created_securely/__driver__.lua e4e15e30715504a2eac0ef5b4fc5e83a4815931f +++ tests/key_files_created_securely/__driver__.lua 63a9bd279770dc1fcefec5eb6cead7fd3e061982 @@ -24,5 +24,5 @@ keyid = string.sub(line, 0, 40) line = readfile("stdout") keyid = string.sub(line, 0, 40) -check({ "ls", "-l", "keys/" .. keyid }, 0, true, nil) -check(qgrep("^-rw------- .*keys/" .. keyid, "stdout")) +check({ "ls", "-l", "keys/foobar." .. keyid }, 0, true, nil) +check(qgrep("^-rw------- .*keys/foobar." .. keyid, "stdout"))