# # # add_dir "tests/key_files_deleted_securely" # # add_file "tests/key_files_deleted_securely/__driver__.lua" # content [5ebce927330de357100e56fa2e6843d4adc3081f] # # patch "NEWS" # from [7efaa0e15d63b4dd2e2739ec49f6125a9ba82d2e] # to [1b68689f04849db39a7e9f0abd6e18c397d56230] # # patch "key_store.cc" # from [6baa5ed8d6427745a64effcfd20e1c7f25bd1d7d] # to [e92239be24d42a9ea613384f3efb8a756cb4cacf] # ============================================================ --- tests/key_files_deleted_securely/__driver__.lua 5ebce927330de357100e56fa2e6843d4adc3081f +++ tests/key_files_deleted_securely/__driver__.lua 5ebce927330de357100e56fa2e6843d4adc3081f @@ -0,0 +1,25 @@ +mtn_setup() + +-- create two keys, rename both, the first to a custom name, +-- the second to an old-style name without ident + +check(mtn("genkey", "foobar"), 0, false, true, "\n\n") +check(grep("has hash", "stderr"), 0, true) +line = readfile("stdout") +keyid1 = string.sub(line, -42, -3) +check(rename("keys/foobar."..keyid1, "keys/something-else")) + +check(mtn("genkey", "foobar", "--force-duplicate-key"), 0, false, true, "\n\n") +check(grep("has hash", "stderr"), 0, true) +line = readfile("stdout") +keyid2 = string.sub(line, -42, -3) +check(rename("keys/foobar."..keyid2, "keys/foobar")) + +check(mtn("dropkey", keyid1), 1, false, true) +check(qgrep("expected key with id '" ..keyid1.."' in key file", "stderr")) + +-- if the conflicting key is gone, ensure that dropkey properly deletes +-- the old key file, even if it has no keyid suffixed +remove("keys/something-else") +check(mtn("dropkey", "foobar"), 0, false, false) + ============================================================ --- NEWS 7efaa0e15d63b4dd2e2739ec49f6125a9ba82d2e +++ NEWS 1b68689f04849db39a7e9f0abd6e18c397d56230 @@ -125,6 +125,14 @@ Xxx Xxx 99 99:99:99 UTC 2010 when dealing with restricted file sets (fixes monotone bug #30291) + - The 'passphrase' and 'dropkey' commands now handle private keys + in old-style key files (without the hash part in the file name) + properly. + monotone also makes it very sure now that the key file of a + private key which is about to be deleted really and only + contains the key which should be deleted and nothing else + (fixes monotone bug #30376) + - monotone no longer throws an unrecoverable error if a public or private key is addressed with some non-existing key id (fixes monotone bug #30462) ============================================================ --- key_store.cc 6baa5ed8d6427745a64effcfd20e1c7f25bd1d7d +++ key_store.cc e92239be24d42a9ea613384f3efb8a756cb4cacf @@ -409,6 +409,43 @@ key_store_state::put_key_pair_memory(ful return true; } +struct key_delete_validator : public packet_consumer +{ + key_id expected_ident; + system_path file; + key_delete_validator(key_id const & id, system_path const & f) + : expected_ident(id), file(f) {} + virtual ~key_delete_validator() {} + virtual void consume_file_data(file_id const & ident, + file_data const & dat) + { E(false, origin::system, F("Invalid data in key file.")); } + virtual void consume_file_delta(file_id const & id_old, + file_id const & id_new, + file_delta const & del) + { E(false, origin::system, F("Invalid data in key file.")); } + virtual void consume_revision_data(revision_id const & ident, + revision_data const & dat) + { E(false, origin::system, F("Invalid data in key file.")); } + virtual void consume_revision_cert(cert const & t) + { E(false, origin::system, F("Invalid data in key file.")); } + virtual void consume_public_key(key_name const & ident, + rsa_pub_key const & k) + { E(false, origin::system, F("Invalid data in key file.")); } + virtual void consume_key_pair(key_name const & name, + keypair const & kp) + { + L(FL("reading key pair '%s' from key store for validation") % name); + key_id ident; + key_hash_code(name, kp.pub, ident); + E(ident == expected_ident, origin::user, + F("expected key with id '%s' in key file '%s', got key with id '%s'") + % expected_ident % file % ident); + } + virtual void consume_old_private_key(key_name const & ident, + old_arc4_rsa_priv_key const & k) + { L(FL("skipping id check before deleting old private key in '%s'") % file); } +}; + void key_store::delete_key(key_id const & ident) { @@ -418,6 +455,22 @@ key_store::delete_key(key_id const & ide { system_path file; s->get_key_file(ident, i->second.first, file); + if (!file_exists(file)) + s->get_old_key_file(i->second.first, file); + + // sanity: if we read the key originally from a file which did not + // follow the NAME.IDENT scheme and have another key pair with NAME + // in the key dir, we could accidentially drop the wrong private key + // here, so validate if the file really contains the key with the + // ID we want to delete, before going mad + { + key_delete_validator val(ident, file); + data dat; + read_data(file, dat); + istringstream is(dat()); + I(read_packets(is, val)); + } + delete_file(file); s->keys.erase(i);