The unified diff between revisions [869f0c37..] and [e24ccc23..] is displayed below. It can also be downloaded as a raw diff.
This diff has been restricted to the following files: 'netsync.cc'
#
#
# patch "netsync.cc"
# from [218fabbe4a06f50089a50833c72f9c1b4ed78a91]
# to [cba71cd069c2658e79568849fe0328c92695547d]
#
============================================================
--- netsync.cc 218fabbe4a06f50089a50833c72f9c1b4ed78a91
+++ netsync.cc cba71cd069c2658e79568849fe0328c92695547d
@@ -112,18 +112,34 @@
// protocol
// --------
//
+// The protocol is a simple binary command-packet system over TCP;
+// each packet consists of a single byte which identifies the protocol
+// version, a byte which identifies the command name inside that
+// version, a size_t sent as a uleb128 indicating the length of the
+// packet, that many bytes of payload, and finally 20 bytes of SHA-1
+// HMAC calculated over the payload. The key for the SHA-1 HMAC is 20
+// bytes of 0 during authentication, and a 20-byte random key chosen
+// by the client after authentication (discussed below).
+//
+//---- Pre-v5 packet format ----
+//
// the protocol is a simple binary command-packet system over tcp; each
// packet consists of a byte which identifies the protocol version, a byte
// which identifies the command name inside that version, a size_t sent as
// a uleb128 indicating the length of the packet, and then that many bytes
// of payload, and finally 4 bytes of adler32 checksum (in LSB order) over
-// the payload. decoding involves simply buffering until a sufficient
-// number of bytes are received, then advancing the buffer pointer. any
-// time an adler32 check fails, the protocol is assumed to have lost
-// synchronization, and the connection is dropped. the parties are free to
-// drop the tcp stream at any point, if too much data is received or too
-// much idle time passes; no commitments or transactions are made.
+// the payload.
//
+// ---- end pre-v5 packet format ----
+//
+// decoding involves simply buffering until a sufficient number of
+// bytes are received, then advancing the buffer pointer. any time an
+// integrity check (adler32 for pre-v5, HMAC for post-v5) fails, the
+// protocol is assumed to have lost synchronization, and the
+// connection is dropped. the parties are free to drop the tcp stream
+// at any point, if too much data is received or too much idle time
+// passes; no commitments or transactions are made.
+//
// one special command, "bye", is used to shut down a connection
// gracefully. once each side has received all the data they want, they
// can send a "bye" command to the other side. as soon as either side has
@@ -135,6 +151,31 @@
// "hello <id> <nonce>" command, which identifies the server's RSA key and
// issues a nonce which must be used for a subsequent authentication.
//
+// The client then responds with either:
+//
+// An "auth (source|sink|both) <pattern> <id> <nonce1> <hmac key>
+// <sig>" command, which identifies its RSA key, notes the role it
+// wishes to play in the synchronization, identifies the pattern it
+// wishes to sync with, signs the previous nonce with its own key, and
+// informs the server of the HMAC key it wishes to use for this
+// session (encrypted with the server's public key); or
+//
+// An "anonymous (source|sink|both) <pattern> <hmac key>" command,
+// which identifies the role it wishes to play in the synchronization,
+// the pattern it ishes to sync with, and the HMAC key it wishes to
+// use for this session (also encrypted with the server's public key).
+//
+// The server then replies with a "confirm" command, which contains no
+// other data but will only have the correct HMAC integrity code if
+// the server received and properly decrypted the HMAC key offered by
+// the client. This transitions the peers into an authenticated state
+// and begins refinement.
+//
+// ---- Pre-v5 authentication process notes ----
+//
+// the exchange begins in a non-authenticated state. the server sends a
+// "hello <id> <nonce>" command, which identifies the server's RSA key and
+// issues a nonce which must be used for a subsequent authentication.
// the client can then respond with an "auth (source|sink|both)
// <pattern> <id> <nonce1> <nonce2> <sig>" command which identifies its
// RSA key, notes the role it wishes to play in the synchronization,
@@ -146,6 +187,8 @@
// the signature of the second nonce sent by the client. this
// transitions the peers into an authenticated state and begins refinement.
//
+// ---- End pre-v5 authentication process ----
+//
// refinement begins with the client sending its root public key and
// manifest certificate merkle nodes to the server. the server then
// compares the root to each slot in *its* root node, and for each slot
@@ -221,7 +264,6 @@ session
string outbuf;
netcmd cmd;
- u8 protocol_version;
bool armed;
bool arm();
@@ -229,6 +271,9 @@ session
boost::regex pattern_re;
id remote_peer_key_hash;
rsa_keypair_id remote_peer_key_name;
+ netsync_session_key session_key;
+ netsync_hmac_value read_hmac;
+ netsync_hmac_value write_hmac;
bool authenticated;
time_t last_io_time;
@@ -321,14 +366,16 @@ session
id const & nonce);
void queue_anonymous_cmd(protocol_role role,
string const & pattern,
- id const & nonce2);
+ id const & nonce2,
+ base64<rsa_pub_key> server_key_encoded);
void queue_auth_cmd(protocol_role role,
string const & pattern,
id const & client,
id const & nonce1,
id const & nonce2,
- string const & signature);
- void queue_confirm_cmd(string const & signature);
+ string const & signature,
+ base64<rsa_pub_key> server_key_encoded);
+ void queue_confirm_cmd();
void queue_refine_cmd(merkle_node const & node);
void queue_send_data_cmd(netcmd_item_type type,
id const & item);
@@ -352,15 +399,15 @@ session
rsa_pub_key const & server_key,
id const & nonce);
bool process_anonymous_cmd(protocol_role role,
- string const & pattern,
- id const & nonce2);
+ string const & pattern);
bool process_auth_cmd(protocol_role role,
string const & pattern,
id const & client,
id const & nonce1,
- id const & nonce2,
string const & signature);
+ void respond_to_auth_cmd(rsa_oaep_sha_data hmac_key_encrypted);
bool process_confirm_cmd(string const & signature);
+ void respond_to_confirm_cmd();
bool process_refine_cmd(merkle_node const & node);
bool process_send_data_cmd(netcmd_item_type type,
id const & item);
@@ -433,12 +480,14 @@ session::session(protocol_role role,
str(sock, to),
inbuf(""),
outbuf(""),
- protocol_version(constants::netcmd_current_protocol_version),
armed(false),
pattern(""),
pattern_re(".*"),
remote_peer_key_hash(""),
remote_peer_key_name(""),
+ session_key(constants::netsync_key_initializer),
+ read_hmac(constants::netsync_key_initializer),
+ write_hmac(constants::netsync_key_initializer),
authenticated(false),
last_io_time(::time(NULL)),
byte_in_ticker(NULL),
@@ -729,7 +778,7 @@ session::write_netcmd_and_try_flush(netc
session::write_netcmd_and_try_flush(netcmd const & cmd)
{
if (!encountered_error)
- cmd.write(outbuf);
+ cmd.write(outbuf, session_key, write_hmac);
else
L(F("dropping outgoing netcmd (because we're in error unwind mode)\n"));
// FIXME: this helps keep the protocol pipeline full but it seems to
@@ -1320,7 +1369,7 @@ session::queue_bye_cmd()
session::queue_bye_cmd()
{
L(F("queueing 'bye' command\n"));
- netcmd cmd(protocol_version);
+ netcmd cmd;
cmd.write_bye_cmd();
write_netcmd_and_try_flush(cmd);
this->sent_goodbye = true;
@@ -1330,7 +1379,7 @@ session::queue_error_cmd(string const &
session::queue_error_cmd(string const & errmsg)
{
L(F("queueing 'error' command\n"));
- netcmd cmd(protocol_version);
+ netcmd cmd;
cmd.write_error_cmd(errmsg);
write_netcmd_and_try_flush(cmd);
this->sent_goodbye = true;
@@ -1343,7 +1392,7 @@ session::queue_done_cmd(size_t level,
string typestr;
netcmd_item_type_to_string(type, typestr);
L(F("queueing 'done' command for %s level %s\n") % typestr % level);
- netcmd cmd(protocol_version);
+ netcmd cmd;
cmd.write_done_cmd(level, type);
write_netcmd_and_try_flush(cmd);
}
@@ -1352,7 +1401,7 @@ session::queue_hello_cmd(id const & serv
session::queue_hello_cmd(id const & server,
id const & nonce)
{
- netcmd cmd(protocol_version);
+ netcmd cmd;
hexenc<id> server_encoded;
encode_hexenc(server, server_encoded);
@@ -1369,11 +1418,16 @@ session::queue_anonymous_cmd(protocol_ro
void
session::queue_anonymous_cmd(protocol_role role,
string const & pattern,
- id const & nonce2)
+ id const & nonce2,
+ base64<rsa_pub_key> server_key_encoded)
{
- netcmd cmd(protocol_version);
- cmd.write_anonymous_cmd(role, pattern, nonce2);
+ netcmd cmd;
+ rsa_oaep_sha_data hmac_key_encrypted;
+ encrypt_rsa(app.lua, remote_peer_key_name, server_key_encoded,
+ nonce2(), hmac_key_encrypted);
+ cmd.write_anonymous_cmd(role, pattern, hmac_key_encrypted);
write_netcmd_and_try_flush(cmd);
+ session_key = netsync_session_key(nonce2());
}
void
@@ -1382,18 +1436,23 @@ session::queue_auth_cmd(protocol_role ro
id const & client,
id const & nonce1,
id const & nonce2,
- string const & signature)
+ string const & signature,
+ base64<rsa_pub_key> server_key_encoded)
{
- netcmd cmd(protocol_version);
- cmd.write_auth_cmd(role, pattern, client, nonce1, nonce2, signature);
+ netcmd cmd;
+ rsa_oaep_sha_data hmac_key_encrypted;
+ encrypt_rsa(app.lua, remote_peer_key_name, server_key_encoded,
+ nonce2(), hmac_key_encrypted);
+ cmd.write_auth_cmd(role, pattern, client, nonce1, hmac_key_encrypted, signature);
write_netcmd_and_try_flush(cmd);
+ session_key = netsync_session_key(nonce2());
}
-void
-session::queue_confirm_cmd(string const & signature)
+void
+session::queue_confirm_cmd()
{
- netcmd cmd(protocol_version);
- cmd.write_confirm_cmd(signature);
+ netcmd cmd;
+ cmd.write_confirm_cmd();
write_netcmd_and_try_flush(cmd);
}
@@ -1406,7 +1465,7 @@ session::queue_refine_cmd(merkle_node co
netcmd_item_type_to_string(node.type, typestr);
L(F("queueing request for refinement of %s node '%s', level %d\n")
% typestr % hpref % static_cast<int>(node.level));
- netcmd cmd(protocol_version);
+ netcmd cmd;
cmd.write_refine_cmd(node);
write_netcmd_and_try_flush(cmd);
}
@@ -1436,7 +1495,7 @@ session::queue_send_data_cmd(netcmd_item
L(F("queueing request for data of %s item '%s'\n")
% typestr % hid);
- netcmd cmd(protocol_version);
+ netcmd cmd;
cmd.write_send_data_cmd(type, item);
write_netcmd_and_try_flush(cmd);
note_item_requested(type, item);
@@ -1472,7 +1531,7 @@ session::queue_send_delta_cmd(netcmd_ite
L(F("queueing request for contents of %s delta '%s' -> '%s'\n")
% typestr % base_hid % ident_hid);
- netcmd cmd(protocol_version);
+ netcmd cmd;
cmd.write_send_delta_cmd(type, base, ident);
write_netcmd_and_try_flush(cmd);
note_item_requested(type, ident);
@@ -1497,7 +1556,7 @@ session::queue_data_cmd(netcmd_item_type
L(F("queueing %d bytes of data for %s item '%s'\n")
% dat.size() % typestr % hid);
- netcmd cmd(protocol_version);
+ netcmd cmd;
cmd.write_data_cmd(type, item, dat);
write_netcmd_and_try_flush(cmd);
note_item_sent(type, item);
@@ -1527,7 +1586,7 @@ session::queue_delta_cmd(netcmd_item_typ
L(F("queueing %s delta '%s' -> '%s'\n")
% typestr % base_hid % ident_hid);
- netcmd cmd(protocol_version);
+ netcmd cmd;
cmd.write_delta_cmd(type, base, ident, del);
write_netcmd_and_try_flush(cmd);
note_item_sent(type, ident);
@@ -1550,7 +1609,7 @@ session::queue_nonexistant_cmd(netcmd_it
L(F("queueing note of nonexistance of %s item '%s'\n")
% typestr % hid);
- netcmd cmd(protocol_version);
+ netcmd cmd;
cmd.write_nonexistant_cmd(type, item);
write_netcmd_and_try_flush(cmd);
}
@@ -1636,22 +1695,6 @@ get_branches(app_state & app, vector<str
W(F("No branches found."));
}
-void
-convert_pattern(utf8 & pat, utf8 & conv)
-{
- string x = pat();
- string pattern = "";
- string e = ".|*?+()[]{}^$\\";
- for (string::const_iterator i = x.begin(); i != x.end(); i++)
- {
- if (e.find(*i) != e.npos)
- pattern += '\\';
- pattern += *i;
- }
- conv = pattern + ".*";
-}
-
-
static const var_domain known_servers_domain = var_domain("known-servers");
bool
@@ -1716,13 +1759,6 @@ session::process_hello_cmd(rsa_keypair_i
}
utf8 pat(pattern);
- if (protocol_version < 5)
- {
- W(F("Talking to an old server. "
- "Using %s as a collection, not a regex.") % pattern);
- convert_pattern(pattern, pat);
- this->pattern_re = boost::regex(pat());
- }
vector<string> branchnames;
set<utf8> ok_branches;
get_branches(app, branchnames);
@@ -1756,11 +1792,12 @@ session::process_hello_cmd(rsa_keypair_i
// make a new nonce of our own and send off the 'auth'
queue_auth_cmd(this->role, this->pattern(), our_key_hash_raw,
- nonce, mk_nonce(), sig_raw());
+ nonce, mk_nonce(), sig_raw(), their_key_encoded);
}
else
{
- queue_anonymous_cmd(this->role, this->pattern(), mk_nonce());
+ queue_anonymous_cmd(this->role, this->pattern(),
+ mk_nonce(), their_key_encoded);
}
return true;
}
@@ -1778,18 +1815,8 @@ session::process_anonymous_cmd(protocol_
bool
session::process_anonymous_cmd(protocol_role role,
- string const & pattern,
- id const & nonce2)
+ string const & pattern)
{
- hexenc<id> hnonce2;
- encode_hexenc(nonce2, hnonce2);
-
- L(F("received 'anonymous' netcmd from client for pattern '%s' "
- "in %s mode with nonce2 '%s'\n")
- % pattern % (role == source_and_sink_role ? "source and sink" :
- (role == source_role ? "source " : "sink"))
- % hnonce2);
-
//
// internally netsync thinks in terms of sources and sinks. users like
// thinking of repositories as "readonly", "readwrite", or "writeonly".
@@ -1850,15 +1877,6 @@ session::process_anonymous_cmd(protocol_
rebuild_merkle_trees(app, ok_branches);
- // get our private key and sign back
- L(F("anonymous read permitted, signing back nonce\n"));
- base64<rsa_sha1_signature> sig;
- rsa_sha1_signature sig_raw;
- base64< arc4<rsa_priv_key> > our_priv;
- load_priv_key(app, app.signing_key, our_priv);
- make_signature(app.lua, app.signing_key, our_priv, nonce2(), sig);
- decode_base64(sig, sig_raw);
- queue_confirm_cmd(sig_raw());
this->pattern = pattern;
this->remote_peer_key_name = rsa_keypair_id("");
this->authenticated = true;
@@ -1866,20 +1884,16 @@ session::process_anonymous_cmd(protocol_
return true;
}
-bool
-session::process_auth_cmd(protocol_role role,
- string const & pattern,
- id const & client,
- id const & nonce1,
- id const & nonce2,
+bool
+session::process_auth_cmd(protocol_role role,
+ string const & pattern,
+ id const & client,
+ id const & nonce1,
string const & signature)
{
I(this->remote_peer_key_hash().size() == 0);
I(this->saved_nonce().size() == constants::merkle_hash_length_in_bytes);
- hexenc<id> hnonce1, hnonce2;
- encode_hexenc(nonce1, hnonce1);
- encode_hexenc(nonce2, hnonce2);
hexenc<id> their_key_hash;
encode_hexenc(client, their_key_hash);
set<utf8> ok_branches;
@@ -1893,12 +1907,6 @@ session::process_auth_cmd(protocol_role
}
boost::regex reg(pattern);
- L(F("received 'auth' netcmd from client '%s' for pattern '%s' "
- "in %s mode with nonce1 '%s' and nonce2 '%s'\n")
- % their_key_hash % pattern % (role == source_and_sink_role ? "source and sink" :
- (role == source_role ? "source " : "sink"))
- % hnonce1 % hnonce2);
-
// check that they replied with the nonce we asked for
if (!(nonce1 == this->saved_nonce))
{
@@ -2004,13 +2012,6 @@ session::process_auth_cmd(protocol_role
{
// get our private key and sign back
L(F("client signature OK, accepting authentication\n"));
- base64<rsa_sha1_signature> sig;
- rsa_sha1_signature sig_raw;
- base64< arc4<rsa_priv_key> > our_priv;
- load_priv_key(app, app.signing_key, our_priv);
- make_signature(app.lua, app.signing_key, our_priv, nonce2(), sig);
- decode_base64(sig, sig_raw);
- queue_confirm_cmd(sig_raw());
this->pattern = pattern;
this->pattern_re = boost::regex(this->pattern());
this->authenticated = true;
@@ -2039,6 +2040,18 @@ session::process_auth_cmd(protocol_role
return false;
}
+void
+session::respond_to_auth_cmd(rsa_oaep_sha_data hmac_key_encrypted)
+{
+ L(F("Writing HMAC confirm command"));
+ base64< arc4<rsa_priv_key> > our_priv;
+ load_priv_key(app, app.signing_key, our_priv);
+ string hmac_key;
+ decrypt_rsa(app.lua, app.signing_key, our_priv, hmac_key_encrypted, hmac_key);
+ session_key = netsync_session_key(hmac_key);
+ queue_confirm_cmd();
+}
+
bool
session::process_confirm_cmd(string const & signature)
{
@@ -2065,20 +2078,6 @@ session::process_confirm_cmd(string cons
if (check_signature(app.lua, their_id, their_key, this->saved_nonce(), sig))
{
L(F("server signature OK, accepting authentication\n"));
- this->authenticated = true;
-
- merkle_ptr root;
- load_merkle_node(epoch_item, 0, get_root_prefix().val, root);
- queue_refine_cmd(*root);
- queue_done_cmd(0, epoch_item);
-
- load_merkle_node(key_item, 0, get_root_prefix().val, root);
- queue_refine_cmd(*root);
- queue_done_cmd(0, key_item);
-
- load_merkle_node(cert_item, 0, get_root_prefix().val, root);
- queue_refine_cmd(*root);
- queue_done_cmd(0, cert_item);
return true;
}
else
@@ -2093,6 +2092,23 @@ session::process_confirm_cmd(string cons
return false;
}
+void
+session::respond_to_confirm_cmd()
+{
+ merkle_ptr root;
+ load_merkle_node(epoch_item, 0, get_root_prefix().val, root);
+ queue_refine_cmd(*root);
+ queue_done_cmd(0, epoch_item);
+
+ load_merkle_node(key_item, 0, get_root_prefix().val, root);
+ queue_refine_cmd(*root);
+ queue_done_cmd(0, key_item);
+
+ load_merkle_node(cert_item, 0, get_root_prefix().val, root);
+ queue_refine_cmd(*root);
+ queue_done_cmd(0, cert_item);
+}
+
static bool
data_exists(netcmd_item_type type,
id const & item,
@@ -2985,8 +3001,6 @@ session::dispatch_payload(netcmd const &
rsa_pub_key server_key;
id nonce;
cmd.read_hello_cmd(server_keyname, server_key, nonce);
- if (cmd.get_version() < protocol_version)
- protocol_version = cmd.get_version();
return process_hello_cmd(server_keyname, server_key, nonce);
}
break;
@@ -3000,11 +3014,17 @@ session::dispatch_payload(netcmd const &
{
protocol_role role;
string pattern;
- id nonce2;
- cmd.read_anonymous_cmd(role, pattern, nonce2);
- if (cmd.get_version() < protocol_version)
- protocol_version = cmd.get_version();
- return process_anonymous_cmd(role, pattern, nonce2);
+ rsa_oaep_sha_data hmac_key_encrypted;
+ cmd.read_anonymous_cmd(role, pattern, hmac_key_encrypted);
+ L(F("received 'anonymous' netcmd from client for pattern '%s' "
+ "in %s mode\n")
+ % pattern % (role == source_and_sink_role ? "source and sink" :
+ (role == source_role ? "source " : "sink")));
+
+ if (!process_anonymous_cmd(role, pattern))
+ return false;
+ respond_to_auth_cmd(hmac_key_encrypted);
+ return true;
}
break;
@@ -3015,11 +3035,25 @@ session::dispatch_payload(netcmd const &
protocol_role role;
string pattern, signature;
id client, nonce1, nonce2;
- cmd.read_auth_cmd(role, pattern, client, nonce1, nonce2, signature);
- if (cmd.get_version() < protocol_version)
- protocol_version = cmd.get_version();
- return process_auth_cmd(role, pattern, client,
- nonce1, nonce2, signature);
+ rsa_oaep_sha_data hmac_key_encrypted;
+ cmd.read_auth_cmd(role, pattern, client, nonce1,
+ hmac_key_encrypted, signature);
+
+ hexenc<id> their_key_hash;
+ encode_hexenc(client, their_key_hash);
+ hexenc<id> hnonce1;
+ encode_hexenc(nonce1, hnonce1);
+
+ L(F("received 'auth(hmac)' netcmd from client '%s' for pattern '%s' "
+ "in %s mode with nonce1 '%s'\n")
+ % their_key_hash % pattern % (role == source_and_sink_role ? "source and sink" :
+ (role == source_role ? "source " : "sink"))
+ % hnonce1);
+
+ if (!process_auth_cmd(role, pattern, client, nonce1, signature))
+ return false;
+ respond_to_auth_cmd(hmac_key_encrypted);
+ return true;
}
break;
@@ -3028,8 +3062,10 @@ session::dispatch_payload(netcmd const &
require(voice == client_voice, "confirm netcmd received in client voice");
{
string signature;
- cmd.read_confirm_cmd(signature);
- return process_confirm_cmd(signature);
+ cmd.read_confirm_cmd();
+ this->authenticated = true;
+ respond_to_confirm_cmd();
+ return true;
}
break;
@@ -3151,7 +3187,7 @@ session::arm()
{
if (!armed)
{
- if (cmd.read(inbuf))
+ if (cmd.read(inbuf, session_key, read_hmac))
{
// inbuf.erase(0, cmd.encoded_size());
armed = true;
@@ -3179,7 +3215,7 @@ bool session::process()
}
catch (bad_decode & bd)
{
- W(F("caught bad_decode exception processing peer %s: '%s'\n") % peer_id % bd.what);
+ W(F("protocol error while processing peer %s: '%s'\n") % peer_id % bd.what);
return false;
}
}
@@ -3212,7 +3248,7 @@ call_server(protocol_role role,
}
catch (bad_decode & bd)
{
- W(F("caught bad_decode exception decoding input from peer %s: '%s'\n")
+ W(F("protocol error while processing peer %s: '%s'\n")
% sess.peer_id % bd.what);
return;
}
@@ -3239,7 +3275,7 @@ call_server(protocol_role role,
}
catch (bad_decode & bd)
{
- W(F("caught bad_decode exception decoding input from peer %s: '%s'\n")
+ W(F("protocol error while processing peer %s: '%s'\n")
% sess.peer_id % bd.what);
return;
}
@@ -3313,7 +3349,7 @@ arm_sessions_and_calculate_probe(Netxx::
}
catch (bad_decode & bd)
{
- W(F("caught bad_decode exception decoding input from peer %s: '%s', marking as bad\n")
+ W(F("protocol error while processing peer %s: '%s', marking as bad\n")
% i->second->peer_id % bd.what);
arm_failed.insert(i->first);
}
@@ -3370,7 +3406,7 @@ handle_read_available(Netxx::socket_type
}
catch (bad_decode & bd)
{
- W(F("caught bad_decode exception decoding input from peer %s: '%s', disconnecting\n")
+ W(F("protocol error while processing peer %s: '%s', disconnecting\n")
% sess->peer_id % bd.what);
sessions.erase(fd);
live_p = false;
@@ -3616,21 +3652,6 @@ session::rebuild_merkle_trees(app_state
ticker certs_ticker("certs", "c", 256);
ticker keys_ticker("keys", "k", 1);
- // this code is wrong. the way the logic _should_ work is:
- // -- start with all branches we want to include
- // -- for each such branch, find all branch certs for that branch
- // -- for each such cert, note down its revision
- // (or these two steps can be replaced with anything else that gives us
- // list of all revisions in the branch)
- // -- expand this set of revisions to include all of their ancestors
- // -- for each such revision, insert all of its certs into the cert table,
- // and note all of its branches and keys
- // -- for each such branch, insert its epoch into the epoch table, and for
- // each such key, insert its key into the key table.
- // this somewhat convoluted approach is necessary to handle cases where
- // ancestors leave the branch inclusion set, where revisions carry branches
- // that are otherwise outside of the inclusion set, etc.
-
set<revision_id> revision_ids;
set<rsa_keypair_id> inserted_keys;
@@ -3649,6 +3670,9 @@ session::rebuild_merkle_trees(app_state
}
}
+ // FIXME: we should probably include epochs for all branches mentioned in
+ // any included branch cert, rather than just for branches included by the
+ // branch mask
{
map<cert_value, epoch_data> epochs;
app.db.get_epochs(epochs);