# # # patch "netcmd.cc" # from [8f23b4db83aa07305b02cc0b4ca8c0ffccd39841] # to [b8a5d8e0ca337c099e75f2e4957400b29077ae01] # # patch "netcmd.hh" # from [8a49f900191f21a2c4fbfbcc0df7e8f49630e98b] # to [e6e9409fb9dae822a261493efd5084e544618db7] # # patch "unit-tests/netcmd.cc" # from [1d71ef9e25baee6f28f9ce34cee3f46886467138] # to [9c4a55299e107ce149928396aa6302edd258da1b] # ============================================================ --- netcmd.cc 8f23b4db83aa07305b02cc0b4ca8c0ffccd39841 +++ netcmd.cc b8a5d8e0ca337c099e75f2e4957400b29077ae01 @@ -20,7 +20,9 @@ #include "hmac.hh" #include "globish.hh" +using std::pair; using std::string; +using std::vector; static netcmd_item_type read_netcmd_item_type(string const & in, @@ -110,6 +112,9 @@ netcmd::read(u8 min_version, u8 max_vers case static_cast(done_cmd): case static_cast(data_cmd): case static_cast(delta_cmd): + case static_cast(automate_cmd): + case static_cast(automate_command_cmd): + case static_cast(automate_packet_cmd): case static_cast(usher_cmd): case static_cast(usher_reply_cmd): cmd_code = static_cast(cmd_byte); @@ -557,6 +562,144 @@ void } void +netcmd::read_automate_cmd(key_id & client, + id & nonce1, + rsa_oaep_sha_data & hmac_key_encrypted, + rsa_sha1_signature & signature) +{ + size_t pos = 0; + client = key_id(extract_substring(payload, pos, + constants::merkle_hash_length_in_bytes, + "automate netcmd, key id"), + origin::network); + nonce1 = id(extract_substring(payload, pos, + constants::merkle_hash_length_in_bytes, + "automate netcmd, nonce1"), + origin::network); + { + string hmac_key; + extract_variable_length_string(payload, hmac_key, pos, + "automate netcmd, hmac_key_encrypted"); + hmac_key_encrypted = rsa_oaep_sha_data(hmac_key, origin::network); + } + { + string sig; + extract_variable_length_string(payload, sig, pos, + "automate netcmd, signature"); + signature = rsa_sha1_signature(sig, origin::network); + } + assert_end_of_buffer(payload, pos, "automate netcmd payload"); +} + +void +netcmd::write_automate_cmd(key_id const & client, + id const & nonce1, + rsa_oaep_sha_data & hmac_key_encrypted, + rsa_sha1_signature & signature) +{ + cmd_code = automate_cmd; + + I(client.inner()().size() == constants::merkle_hash_length_in_bytes); + I(nonce1().size() == constants::merkle_hash_length_in_bytes); + + payload += client.inner()(); + payload += nonce1(); + + insert_variable_length_string(hmac_key_encrypted(), payload); + insert_variable_length_string(signature(), payload); +} + +void +netcmd::read_automate_command_cmd(vector & args, + vector > & opts) +{ + size_t pos = 0; + { + size_t nargs = extract_datum_uleb128(payload, pos, + "automate_command netcmd, arg count"); + args.clear(); + for (size_t i = 0; i < nargs; ++i) + { + string arg; + extract_variable_length_string(payload, arg, pos, + "automate_command netcmd, argument"); + args.push_back(arg); + } + } + { + size_t nopts = extract_datum_uleb128(payload, pos, + "automate_command netcmd, option count"); + opts.clear(); + for (size_t i = 0; i < nopts; ++i) + { + string name; + extract_variable_length_string(payload, name, pos, + "automate_command netcmd, option name"); + string value; + extract_variable_length_string(payload, value, pos, + "automate_command netcmd, option name"); + opts.push_back(make_pair(name, value)); + } + } + assert_end_of_buffer(payload, pos, "automate_command netcmd payload"); +} + +void +netcmd::write_automate_command_cmd(vector const & args, + vector > const & opts) +{ + cmd_code = automate_command_cmd; + + insert_datum_uleb128(args.size(), payload); + for (vector::const_iterator a = args.begin(); + a != args.end(); ++a) + { + insert_variable_length_string(*a, payload); + } + + insert_datum_uleb128(opts.size(), payload); + for (vector >::const_iterator o = opts.begin(); + o != opts.end(); ++o) + { + insert_variable_length_string(o->first, payload); + insert_variable_length_string(o->second, payload); + } +} + +void +netcmd::read_automate_packet_cmd(int & command_num, + int & err_code, + bool & last, + string & packet_data) +{ + size_t pos = 0; + + command_num = int(extract_datum_uleb128(payload, pos, + "automate_packet netcmd, command_num")); + err_code = int(extract_datum_uleb128(payload, pos, + "automate_packet netcmd, err_code")); + last = (extract_datum_uleb128(payload, pos, + "automate_packet netcmd, last") == 1); + extract_variable_length_string(payload, packet_data, pos, + "automate_packet netcmd, packet_data"); + assert_end_of_buffer(payload, pos, "automate_packet netcmd payload"); +} + +void +netcmd::write_automate_packet_cmd(int command_num, + int err_code, + bool last, + string const & packet_data) +{ + cmd_code = automate_packet_cmd; + + insert_datum_uleb128(size_t(command_num), payload); + insert_datum_uleb128(size_t(err_code), payload); + insert_datum_uleb128(last?1:0, payload); + insert_variable_length_string(packet_data, payload); +} + +void netcmd::read_usher_cmd(utf8 & greeting) const { size_t pos = 0; ============================================================ --- netcmd.hh 8a49f900191f21a2c4fbfbcc0df7e8f49630e98b +++ netcmd.hh e6e9409fb9dae822a261493efd5084e544618db7 @@ -73,6 +73,11 @@ typedef enum data_cmd = 8, delta_cmd = 9, + // automation commands + automate_cmd = 10, + automate_command_cmd = 11, + automate_packet_cmd = 12, + // usher commands // usher_cmd is sent either by a proxy that needs to know where // to forward a connection (the reply gives the desired hostname and @@ -178,6 +183,27 @@ public: id const & base, id const & ident, delta const & del); + void read_automate_cmd(key_id & client, + id & nonce1, + rsa_oaep_sha_data & hmac_key_encrypted, + rsa_sha1_signature & signature); + void write_automate_cmd(key_id const & client, + id const & nonce1, + rsa_oaep_sha_data & hmac_key_encrypted, + rsa_sha1_signature & signature); + void read_automate_command_cmd(std::vector & args, + std::vector > & opts); + void write_automate_command_cmd(std::vector const & args, + std::vector > const & opts); + void read_automate_packet_cmd(int & command_num, + int & err_code, + bool & last, + std::string & packet_data); + void write_automate_packet_cmd(int command_num, + int err_code, + bool last, + std::string const & packet_data); + void read_usher_cmd(utf8 & greeting) const; void write_usher_cmd(utf8 const & greeting); void read_usher_reply_cmd(u8 & version, utf8 & server, globish & pattern) const; ============================================================ --- unit-tests/netcmd.cc 1d71ef9e25baee6f28f9ce34cee3f46886467138 +++ unit-tests/netcmd.cc 9c4a55299e107ce149928396aa6302edd258da1b @@ -190,6 +190,32 @@ UNIT_TEST(functions) L(FL("auth_cmd test done, buffer was %d bytes") % buf.size()); } + // automate_cmd + { + L(FL("checking i/o round trip on auth_cmd")); + netcmd out_cmd(constants::netcmd_current_protocol_version); + netcmd in_cmd(constants::netcmd_current_protocol_version); + string buf; + key_id out_client(raw_sha1("happy client day"), origin::internal); + id out_nonce1(raw_sha1("nonce me amadeus"), origin::internal); + key_id in_client; + id in_nonce1; + // total cheat, since we don't actually verify that rsa_oaep_sha_data + // is sensible anywhere here... + rsa_oaep_sha_data out_key("nonce start my heart"), in_key; + rsa_sha1_signature out_signature(raw_sha1("burble") + raw_sha1("gorby"), + origin::internal), in_signature; + + out_cmd.write_automate_cmd(out_client, out_nonce1, out_key, out_signature); + do_netcmd_roundtrip(out_cmd, in_cmd, buf); + in_cmd.read_automate_cmd(in_client, in_nonce1, in_key, in_signature); + UNIT_TEST_CHECK(in_client == out_client); + UNIT_TEST_CHECK(in_nonce1 == out_nonce1); + UNIT_TEST_CHECK(in_key == out_key); + UNIT_TEST_CHECK(in_signature == out_signature); + L(FL("automate_cmd test done, buffer was %d bytes") % buf.size()); + } + // confirm_cmd { L(FL("checking i/o round trip on confirm_cmd")); @@ -283,6 +309,54 @@ UNIT_TEST(functions) L(FL("delta_cmd test done, buffer was %d bytes") % buf.size()); } + // automate_command_cmd + { + L(FL("checking i/o round trip on automate_command_cmd")); + netcmd out_cmd(constants::netcmd_current_protocol_version); + netcmd in_cmd(constants::netcmd_current_protocol_version); + + std::vector in_args, out_args; + std::vector > in_opts, out_opts; + + in_args.push_back("foo"); + in_args.push_back("bar"); + in_opts.push_back(std::make_pair("abc", "def")); + + out_cmd.write_automate_command_cmd(in_args, in_opts); + string buf; + do_netcmd_roundtrip(out_cmd, in_cmd, buf); + in_cmd.read_automate_command_cmd(out_args, out_opts); + + UNIT_TEST_CHECK(in_args == out_args); + UNIT_TEST_CHECK(in_opts == out_opts); + L(FL("automate_command_cmd test done, buffer was %d bytes") % buf.size()); + } + + // automate_packet_cmd + { + L(FL("checking i/o round trip on automate_packet_cmd")); + netcmd out_cmd(constants::netcmd_current_protocol_version); + netcmd in_cmd(constants::netcmd_current_protocol_version); + + int in_cmd_num(3), out_cmd_num; + int in_err_code(9), out_err_code; + bool in_last(true), out_last; + string in_data("this is some packet data"), out_data; + + out_cmd.write_automate_packet_cmd(in_cmd_num, in_err_code, + in_last, in_data); + string buf; + do_netcmd_roundtrip(out_cmd, in_cmd, buf); + in_cmd.read_automate_packet_cmd(out_cmd_num, out_err_code, + out_last, out_data); + + UNIT_TEST_CHECK(in_cmd_num == out_cmd_num); + UNIT_TEST_CHECK(in_err_code == out_err_code); + UNIT_TEST_CHECK(in_last == out_last); + UNIT_TEST_CHECK(in_data == out_data); + L(FL("automate_packet_cmd test done, buffer was %d bytes") % buf.size()); + } + } catch (bad_decode & d) {