# # # patch "cmd_key_cert.cc" # from [eba5cb5fad09136c4a23e56a823f3134de5dea4c] # to [63b100b1dfc6c648204e8ba38b7b54ece19b45a2] # # patch "platform.hh" # from [b5cb961e19daf9302d866c2f066d8338db7c79c3] # to [b39c772b2b9967346509da8f1c814f2b8549889c] # # patch "ssh_agent.cc" # from [ec41ef3892607ba363d5bfd3ffc686bae6ef1ae3] # to [181ea122c65e0e916d87ed91df9a63120e667a42] # # patch "ssh_agent.hh" # from [b5cf999ba112dc33279647aac778a458258f7e06] # to [91380e8cfbaddc9dd86e1deea61a0f8d32b29b28] # # patch "unix/ssh_agent_platform.cc" # from [50796ebd56e4d4c6d01d6a6230d3ca44599bf7a7] # to [0afd1db219c11c44914be34360c79011aee1d12c] # # patch "unix/ssh_agent_platform.hh" # from [8308eb23fa4efb032cc1c13f626b287351742479] # to [4f48ace4c0cb407ccfdfa2a149b080717f135a3b] # # patch "win32/ssh_agent_platform.cc" # from [d07bead2459a552439e4c0f06178c1ee900e7ca2] # to [2d9a982788530e4a7f10c3b29224f44458a4a54c] # # patch "win32/ssh_agent_platform.hh" # from [db4156f82cbcd4a725c70fedc0aebfa056e00eb5] # to [9f7f837a96f42a915dbe5c5370bb18da1357c250] # ============================================================ --- cmd_key_cert.cc eba5cb5fad09136c4a23e56a823f3134de5dea4c +++ cmd_key_cert.cc 63b100b1dfc6c648204e8ba38b7b54ece19b45a2 @@ -21,6 +21,7 @@ #include "transforms.hh" #include "ssh_agent.hh" #include "botan/pipe.h" +#include "botan/rsa.h" using std::cout; using std::ostream_iterator; ============================================================ --- platform.hh b5cb961e19daf9302d866c2f066d8338db7c79c3 +++ platform.hh b39c772b2b9967346509da8f1c814f2b8549889c @@ -148,12 +148,6 @@ std::string get_locale_dir(); // determine directory to load locale data from std::string get_locale_dir(); -#ifdef WIN32 -#include "win32/ssh_agent_platform.hh" -#else -#include "unix/ssh_agent_platform.hh" -#endif - // Local Variables: // mode: C++ // fill-column: 76 ============================================================ --- ssh_agent.cc ec41ef3892607ba363d5bfd3ffc686bae6ef1ae3 +++ ssh_agent.cc 181ea122c65e0e916d87ed91df9a63120e667a42 @@ -15,7 +15,19 @@ #include "netio.hh" #include "keys.hh" #include "botan/numthry.h" +#include "numeric_vocab.hh" +#include "netxx/stream.h" +#include "botan/rsa.h" +#include "botan/bigint.h" +#include +#include "platform.hh" +#ifdef WIN32 +#include "win32/ssh_agent_platform.hh" +#else +#include "unix/ssh_agent_platform.hh" +#endif + using Botan::RSA_PublicKey; using Botan::RSA_PrivateKey; using Botan::BigInt; @@ -25,6 +37,14 @@ using std::vector; using std::string; using std::vector; +struct ssh_agent_state : ssh_agent_platform +{ + vector keys; // cache + + void read_packet(string & packet); + void write_packet(string const & packet); +}; + /* * The ssh-agent network format is essentially based on a u32 which * is the length of the packet followed by that number of bytes. @@ -93,45 +113,39 @@ using std::vector; * data = signed data */ -ssh_agent::ssh_agent() -{ - connect(); -} +// +// Helper functions for packing and unpacking data from the wire protocol. +// -ssh_agent::~ssh_agent() +static u32 +get_long(char const * buf) { - disconnect(); + L((FL("ssh_agent: get_long: %u %u %u %u") + % widen(buf[0]) + % widen(buf[1]) + % widen(buf[2]) + % widen(buf[3]))); + return ((widen(buf[0]) << 24) + | (widen(buf[1]) << 16) + | (widen(buf[2]) << 8) + | widen(buf[3])); } -u32 -ssh_agent::get_long(char const * buf) +static u32 +get_long_from_buf(string const & buf, u32 & loc) { - L((FL("ssh_agent: get_long: %u %u %u %u") - % widen(buf[0]) - % widen(buf[1]) - % widen(buf[2]) - % widen(buf[3]))); - return ((widen(buf[0]) << 24) - | (widen(buf[1]) << 16) - | (widen(buf[2]) << 8) - | widen(buf[3])); -} - -u32 -ssh_agent::get_long_from_buf(string const & buf, u32 & loc) -{ - E(buf.length() >= loc + 4, F("string not long enough to get a long")); + E(buf.length() >= loc + 4, + F("string not long enough to get a long")); u32 ret = get_long(buf.data() + loc); - //E(ret <= 2048, F("long is larger than expected")); loc += 4; return ret; } -void -ssh_agent::get_string_from_buf(string const & buf, - u32 & loc, - u32 & len, - string & out) +static void +get_string_from_buf(string const & buf, + u32 & loc, + u32 & len, + string & out) { L(FL("ssh_agent: get_string_from_buf: buf length: %u, loc: %u" ) % buf.length() @@ -148,8 +162,8 @@ ssh_agent::get_string_from_buf(string co loc += len; } -void -ssh_agent::put_long(u32 l, char * buf) +static void +put_long(u32 l, char * buf) { buf[0] = (char)(unsigned char)(l >> 24); buf[1] = (char)(unsigned char)(l >> 16); @@ -162,8 +176,8 @@ ssh_agent::put_long(u32 l, char * buf) % (u32)(unsigned char)buf[3]); } -void -ssh_agent::put_long_into_buf(u32 l, string & buf) +static void +put_long_into_buf(u32 l, string & buf) { char lb[4]; L(FL("ssh_agent: put_long_into_buf: long: %u, buf len: %i") @@ -174,23 +188,34 @@ ssh_agent::put_long_into_buf(u32 l, stri L(FL("ssh_agent: put_long_into_buf: buf len now %i") % buf.length()); } -void -ssh_agent::put_bigint_into_buf(BigInt const & bi, string & buf) +static void +put_string_into_buf(string const & str, string & buf) { + L(FL("ssh_agent: put_string_into_buf: str len %i, buf len %i") + % str.length() + % buf.length()); + put_long_into_buf(str.length(), buf); + buf.append(str.c_str(), str.length()); + L(FL("ssh_agent: put_string_into_buf: buf len now %i") % buf.length()); +} + +static void +put_bigint_into_buf(BigInt const & bi, string & buf) +{ L(FL("ssh_agent: put_bigint_into_buf: bigint.bytes(): %u, bigint: %s") % bi.bytes() % bi); SecureVector bi_buf = BigInt::encode(bi); string bi_str; if (*bi_buf.begin() & 0x80) - bi_str.append(1, static_cast(0)); + bi_str.append(1, static_cast(0)); bi_str.append((char *) bi_buf.begin(), bi_buf.size()); put_string_into_buf(bi_str, buf); L(FL("ssh_agent: put_bigint_into_buf: buf len now %i") % buf.length()); } -void -ssh_agent::put_public_key_into_buf(RSA_PublicKey const & key, string & buf) +static void +put_public_key_into_buf(RSA_PublicKey const & key, string & buf) { L(FL("ssh_agent: put_public_key_into_buf: key e: %s, n: %s") % key.get_e() @@ -201,8 +226,8 @@ ssh_agent::put_public_key_into_buf(RSA_P L(FL("ssh_agent: put_public_key_into_buf: buf len now %i") % buf.length()); } -void -ssh_agent::put_private_key_into_buf(RSA_PrivateKey const & key, string & buf) +static void +put_private_key_into_buf(RSA_PrivateKey const & key, string & buf) { L(FL("ssh_agent: put_private_key_into_buf: key e: %s, n: %s") % key.get_e() @@ -218,19 +243,13 @@ ssh_agent::put_private_key_into_buf(RSA_ L(FL("ssh_agent: put_private_key_into_buf: buf len now %i") % buf.length()); } -void -ssh_agent::put_string_into_buf(string const & str, string & buf) -{ - L(FL("ssh_agent: put_string_into_buf: str len %i, buf len %i") - % str.length() - % buf.length()); - put_long_into_buf(str.length(), buf); - buf.append(str.c_str(), str.length()); - L(FL("ssh_agent: put_string_into_buf: buf len now %i") % buf.length()); -} +// +// Non-platform-specific ssh_agent_state methods, dealing with the basic +// protocol packet format. +// void -ssh_agent::fetch_packet(string & packet) +ssh_agent_state::read_packet(string & packet) { u32 len; string len_buf; @@ -244,22 +263,48 @@ ssh_agent::fetch_packet(string & packet) read_data(len, packet); } +void +ssh_agent_state::write_packet(string const & packet) +{ + string sized_packet; + put_string_into_buf(packet, sized_packet); + write_data(sized_packet); +} + +// +// ssh_agent public methods. +// + +ssh_agent::ssh_agent() + : s(new ssh_agent_state()) +{ +} + +ssh_agent::~ssh_agent() +{ + delete s; +} + +bool +ssh_agent::connected() +{ + return s->connected(); +} + vector const ssh_agent::get_keys() { - if (!connected()) + if (!s->connected()) { L(FL("ssh_agent: get_keys: stream not initialized, no agent")); - return keys; + return s->keys; } - string out("\0\0\0\1", 4); - char ch[1]; - ch[0] = 11; - out.append(ch, 1); - write_data(out); + const char get_keys_cmd[1] = { 11 }; + s->write_packet(string(get_keys_cmd, sizeof get_keys_cmd)); + string packet; - fetch_packet(packet); + s->read_packet(packet); //first byte is packet type u32 packet_loc = 0; @@ -307,33 +352,11 @@ ssh_agent::get_keys() % key.length()); RSA_PublicKey rsa_key(n, e); - keys.push_back(rsa_key); + s->keys.push_back(rsa_key); + } + else + L(FL("ssh_agent: ignoring key of type '%s'") % type); - } else - L(FL("ssh_agent: ignoring key of type '%s'") % type); - - //if (type == "ssh-dss") - // { - // L(FL("ssh_agent: DSA (ignoring)")); - // string p; - // get_string_from_buf(key, key_loc, slen, p); - // //BigInt pb = BigInt::decode((unsigned char *)(p.c_str()), slen, BigInt::Binary); - // //L(FL("ssh_agent: p: %s, len %u") % pb % slen); - // string q; - // get_string_from_buf(key, key_loc, slen, q); - // //BigInt qb = BigInt::decode((unsigned char *)(q.c_str()), slen, BigInt::Binary); - // //L(FL("ssh_agent: q: %s, len %u") % qb % slen); - // string g; - // get_string_from_buf(key, key_loc, slen, g); - // //BigInt gb = BigInt::decode((unsigned char *)(g.c_str()), slen, BigInt::Binary); - // //L(FL("ssh_agent: g: %s, len %u") % gb % slen); - // string pub_key; - // get_string_from_buf(key, key_loc, slen, pub_key); - // //BigInt pkb = BigInt::decode((unsigned char *)(pub_key.c_str()), slen, BigInt::Binary); - // //L(FL("ssh_agent: pub_key: %s, len %u") % pkb % slen); - // } else - // E(false, F("key type '%s' not recognized by ssh-agent code") % type); - L(FL("ssh_agent: packet length %u, packet loc %u, key length %u," " key loc, %u") % packet.length() @@ -351,7 +374,8 @@ ssh_agent::get_keys() " location (%u), length (%i)") % packet_loc % packet.length()); - return keys; + + return s->keys; } void @@ -366,41 +390,31 @@ ssh_agent::sign_data(RSA_PublicKey const % key.get_e() % key.get_n() % data.length()); - string data_out; + string packet_out; string key_buf; string full_sig; - unsigned char cmd[1]; - cmd[0] = 13; - data_out.append((char *)cmd, 1); + + packet_out.append(1, (char)13); // command byte put_public_key_into_buf(key, key_buf); - put_string_into_buf(key_buf, data_out); + put_string_into_buf(key_buf, packet_out); - put_string_into_buf(data, data_out); + put_string_into_buf(data, packet_out); u32 flags = 0; - put_long_into_buf(flags, data_out); + put_long_into_buf(flags, packet_out); - L(FL("ssh_agent: sign_data: data_out length: %u") % data_out.length()); + L(FL("ssh_agent: sign_data: data_out length: %u") % packet_out.length()); + s->write_packet(packet_out); - string packet_out; - put_string_into_buf(data_out, packet_out); - - //stream->write(packet_out.c_str(), packet_out.length()); - write_data(packet_out); - string packet_in; - fetch_packet(packet_in); + s->read_packet(packet_in); u32 packet_in_loc = 0; - /* - E(packet_in.at(0) == 14, - (F("ssh_agent: sign_data: packet_in type (%u) != 14") - % (u32)packet_in.at(0))); - */ - if (packet_in.at(0) != 14) { - L(FL("ssh_agent: sign_data: packet_in type (%u) != 14") - % (u32)packet_in.at(0)); - return; - } + if (packet_in.at(0) != 14) + { + L(FL("ssh_agent: sign_data: packet_in type (%u) != 14") + % (u32)packet_in.at(0)); + return; + } packet_in_loc += 1; u32 full_sig_len; @@ -428,45 +442,30 @@ ssh_agent::sign_data(RSA_PublicKey const % packet_in.length())); } -bool -ssh_agent::connected() -{ - return ssh_agent_platform::connected(); -} - void ssh_agent::add_identity(RSA_PrivateKey const & key, string const & comment) { - E(connected(), + E(s->connected(), F("ssh_agent: add_identity: attempted to add a key when not connected")); L(FL("ssh_agent: add_identity: key e: %s, n: %s, comment len: %i") % key.get_e() % key.get_n() % comment.length()); - string data_out; - string key_buf; - unsigned char cmd[1]; - cmd[0] = 17; - //data_out.append((char *)cmd, 1); - key_buf.append((char *)cmd, 1); - put_private_key_into_buf(key, key_buf); - put_string_into_buf(comment, key_buf); - //put_string_into_buf(key_buf, data_out); - string packet_out; - put_string_into_buf(key_buf, packet_out); - //stream->write(packet_out.c_str(), packet_out.length()); - write_data(packet_out); + packet_out.append(1, (char)17); // command byte + put_private_key_into_buf(key, packet_out); + put_string_into_buf(comment, packet_out); + s->write_packet(packet_out); string packet_in; - fetch_packet(packet_in); - u32 packet_in_loc = 0; + s->read_packet(packet_in); + E(packet_in.length() == 1, + F("ssh_agent: add_identity: response packet of unexpected size (%u)") + % packet_in.length()); E(packet_in.at(0) == 6, F("ssh_agent: packet type (%u) != 6") % (u32)packet_in.at(0)); - packet_in_loc += 1; - } // Local Variables: ============================================================ --- ssh_agent.hh b5cf999ba112dc33279647aac778a458258f7e06 +++ ssh_agent.hh 91380e8cfbaddc9dd86e1deea61a0f8d32b29b28 @@ -10,47 +10,32 @@ #ifndef __SSH_AGENT_H__ #define __SSH_AGENT_H__ -#include "numeric_vocab.hh" -#include "netxx/stream.h" -#include "botan/rsa.h" -#include "botan/bigint.h" -#include #include "vector.hh" -#include "platform.hh" -class ssh_agent : ssh_agent_platform +namespace Botan { -public: + class RSA_PublicKey; + class RSA_PrivateKey; +}; + +class ssh_agent_state; + +struct ssh_agent +{ ssh_agent(); ~ssh_agent(); std::vector const get_keys(); void sign_data(Botan::RSA_PublicKey const & key, std::string const & data, std::string & out); - void add_identity(Botan::RSA_PrivateKey const & key, std::string const & comment); + void add_identity(Botan::RSA_PrivateKey const & key, + std::string const & comment); bool connected(); private: - std::vector keys; - - //helper functions for reading and unpacking data from ssh-agent - void fetch_packet(std::string & packet); - u32 get_long(char const * buf); - u32 get_long_from_buf(std::string const & buf, u32 & loc); - void get_string_from_buf(std::string const & buf, - u32 & loc, - u32 & len, - std::string & out); - - //helper functions for packing data to send to ssh-agent - void put_long(u32 l, char * buf); - void put_long_into_buf(u32 l, std::string & buf); - void put_string_into_buf(std::string const & str, std::string & buf); - void put_bigint_into_buf(Botan::BigInt const & bi, std::string & buf); - void put_public_key_into_buf(Botan::RSA_PublicKey const & key, std::string & buf); - void put_private_key_into_buf(Botan::RSA_PrivateKey const & key, std::string & buf); + ssh_agent_state * s; }; - + // Local Variables: // mode: C++ // fill-column: 76 ============================================================ --- unix/ssh_agent_platform.cc 50796ebd56e4d4c6d01d6a6230d3ca44599bf7a7 +++ unix/ssh_agent_platform.cc 0afd1db219c11c44914be34360c79011aee1d12c @@ -20,24 +20,25 @@ #include "ssh_agent_platform.hh" -using boost::shared_ptr; using Netxx::Stream; +using Netxx::socket_type; using std::min; using std::string; -bool +// helper function for constructor +socket_type ssh_agent_platform::connect() { const char *authsocket; - int sock; struct sockaddr_un sunaddr; + socket_type sock; authsocket = getenv("SSH_AUTH_SOCK"); if (!authsocket || !strlen(authsocket)) { L(FL("ssh_agent: connect: ssh-agent socket not found")); - return false; + return -1; } sunaddr.sun_family = AF_UNIX; @@ -47,7 +48,7 @@ ssh_agent_platform::connect() if (sock < 0) { W(F("ssh_agent: connect: could not open socket to ssh-agent")); - return false; + return -1; } int ret = fcntl(sock, F_SETFD, FD_CLOEXEC); @@ -55,38 +56,26 @@ ssh_agent_platform::connect() { close(sock); W(F("ssh_agent: connect: could not set up socket for ssh-agent")); - return false; + return -1; } ret = ::connect(sock, (struct sockaddr *)&sunaddr, sizeof sunaddr); if (ret < 0) { close(sock); W(F("ssh_agent: connect: could not connect to socket for ssh-agent")); - return false; + return -1; } - stream = shared_ptr(new Stream(sock)); - return true; -} -bool -ssh_agent_platform::disconnect() -{ - if (connected()) - stream->close(); - return true; + return sock; } -bool -ssh_agent_platform::connected() -{ - return stream != NULL; -} - void ssh_agent_platform::write_data(string const & data) { - L(FL("ssh_agent_platform::write_data: asked to write %u bytes") % data.length()); - stream->write(data.c_str(), data.length()); + L(FL("ssh_agent_platform::write_data: asked to write %u bytes") + % data.length()); + I(connected()); + stream.write(data.c_str(), data.length()); } void @@ -97,14 +86,12 @@ ssh_agent_platform::read_data(u32 const char read_buf[bufsize]; u32 get = len; L(FL("ssh_agent: read_data: asked to read %u bytes") % len); + I(connected()); + while (get > 0) { - ret = stream->read(read_buf, min(get, bufsize)); + ret = stream.read(read_buf, min(get, bufsize)); E(ret >= 0, F("stream read failed (%i)") % ret); - /* - if (ret > 0) - L(FL("ssh_agent: read_data: read %i bytes") % ret); - */ out.append(read_buf, ret); get -= ret; } ============================================================ --- unix/ssh_agent_platform.hh 8308eb23fa4efb032cc1c13f626b287351742479 +++ unix/ssh_agent_platform.hh 4f48ace4c0cb407ccfdfa2a149b080717f135a3b @@ -7,18 +7,21 @@ // implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. -#include #include "../numeric_vocab.hh" #include "../netxx/stream.h" class ssh_agent_platform { private: - boost::shared_ptr stream; + Netxx::Stream stream; + Netxx::socket_type connect(); public: - bool connect(); - bool disconnect(); - bool connected(); + // We rely on Netxx::Stream not blowing up if constructed from an + // invalid file descriptor, as long as no one actually tries to write() + // or read() on it. + ssh_agent_platform() : stream(connect()) {} + bool connected() { return stream.get_socketfd() != -1; } + void write_data(std::string const & data); void read_data(u32 const len, std::string & out); }; ============================================================ --- win32/ssh_agent_platform.cc d07bead2459a552439e4c0f06178c1ee900e7ca2 +++ win32/ssh_agent_platform.cc 2d9a982788530e4a7f10c3b29224f44458a4a54c @@ -18,18 +18,16 @@ using std::string; #define AGENT_COPYDATA_ID 0x804e50ba /* random goop */ #define AGENT_MAX_MSGLEN 8192 -bool -ssh_agent_platform::connect() +void +ssh_agent_platform::ssh_agent_platform() + : hwnd(NULL), filemap(NULL), filemap_view(NULL), read_len(0) { char mapname[32]; L(FL("ssh_agent: connect")); hwnd = FindWindow("Pageant", "Pageant"); if (!hwnd) - { - filemap = NULL; - return false; - } + return; sprintf(mapname, "PageantRequest%08x", (unsigned)GetCurrentThreadId()); filemap = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, @@ -37,41 +35,36 @@ ssh_agent_platform::connect() if (filemap == NULL || filemap == INVALID_HANDLE_VALUE) { hwnd = NULL; - return false; + return; } filemap_view = (char*)MapViewOfFile(filemap, FILE_MAP_WRITE, 0, 0, 0); if (filemap_view == 0) { - hwnd = NULL; CloseHandle(filemap); filemap = NULL; - return false; + hwnd = NULL; } - - return true; } -bool -ssh_agent_platform::disconnect() +ssh_agent_platform::~ssh_agent_platform() { - if (filemap != NULL) - { - CloseHandle(filemap); - filemap = NULL; - hwnd = NULL; - UnmapViewOfFile(filemap_view); - filemap_view = NULL; - } - return true; + if (filemap == NULL) + return; + + UnmapViewOfFile(filemap_view); + filemap_view = NULL; + CloseHandle(filemap); + filemap = NULL; + hwnd = NULL; } bool ssh_agent_platform::connected() { - return hwnd != NULL && (IsWindow(hwnd) != 0); + return hwnd && IsWindow(hwnd); } void @@ -82,14 +75,14 @@ ssh_agent_platform::write_data(string co COPYDATASTRUCT cds; char mapname[32]; - if (!connected()) - return; - + I(connected()); sprintf(mapname, "PageantRequest%08x", (unsigned)GetCurrentThreadId()); - L(FL("ssh_agent_platform::write_data: writing %u bytes to %s") % data.length() % mapname); + L(FL("ssh_agent_platform::write_data: writing %u bytes to %s") + % data.length() % mapname); - E(data.length() < AGENT_MAX_MSGLEN, F("Asked to write more than %u to pageant.") % AGENT_MAX_MSGLEN); + E(data.length() < AGENT_MAX_MSGLEN, + F("Asked to write more than %u to pageant.") % AGENT_MAX_MSGLEN); memcpy(filemap_view, data.c_str(), data.length()); cds.dwData = AGENT_COPYDATA_ID; @@ -107,12 +100,12 @@ ssh_agent_platform::read_data(u32 const void ssh_agent_platform::read_data(u32 const len, string & out) { - if (!connected()) - return; + I(connected()); L(FL("ssh_agent: read_data: asked to read %u bytes") % len); - E((read_len + len) < AGENT_MAX_MSGLEN, F("Asked to read more than %u from pageant.") % AGENT_MAX_MSGLEN); + E((read_len + len) < AGENT_MAX_MSGLEN, + F("Asked to read more than %u from pageant.") % AGENT_MAX_MSGLEN); out.append(filemap_view + read_len, len); ============================================================ --- win32/ssh_agent_platform.hh db4156f82cbcd4a725c70fedc0aebfa056e00eb5 +++ win32/ssh_agent_platform.hh 9f7f837a96f42a915dbe5c5370bb18da1357c250 @@ -8,6 +8,7 @@ // PURPOSE. #include "../numeric_vocab.hh" +#define WIN32_LEAN_AND_MEAN // no gui definitions #include class ssh_agent_platform { @@ -18,9 +19,10 @@ public: u32 read_len; public: - bool connect(); - bool disconnect(); + ssh_agent_platform(); + ~ssh_agent_platform(); bool connected(); + void write_data(std::string const & data); void read_data(u32 const len, std::string & out); };