# # # add_file "botan_pipe_cache.hh" # content [6a935f221e4a9368cbef90618e4a3847d1053dbc] # # patch "Makefile.am" # from [242b7438c47167c49dc69f129232bd6b91261a22] # to [868eff98716b795d27b9f00b523e2c42d9e1f0ce] # # patch "file_io.cc" # from [358fb964dc42e7f936a136342b93bb3a4744d1b3] # to [db5ed54600200ee2cda6ff1a2a8b0ecb463b653b] # # patch "gzip.cc" # from [93f149779d9f0132940a206e008eeef3ca618b92] # to [72e05981fe6cc8aa932363eef6c187241a4bb31d] # # patch "hmac.cc" # from [115a8c2bd6e81ea28d4628e77e4ad4dfae8e00a9] # to [da58d8141987a07675d0a8aaf8ab70b60d53ac90] # # patch "hmac.hh" # from [6953e20a8a307882b42c317e31714a53f8dae510] # to [38920db37f7ac41a26c51b97a9fb2a394d0f37ff] # # patch "key_store.cc" # from [167e6637e117ee23709dc32bb029cb0288064606] # to [0f3eb9d8e4e664f42a1099f299c325604fae9cc9] # # patch "monotone.cc" # from [c105422e7de754e19a87af2cd8ad4b798159520e] # to [e7cb1f117494c4853f3320a4add02474b6a2ff6c] # # patch "tester.cc" # from [5698be54abe68883c1ce41db0ba95e461a1f3fad] # to [da1589e5c3cc77aa51b5658a71b613e6b1ec64db] # # patch "transforms.cc" # from [144f5ceb3515a7b9a392e6963c5841788a8bdbd0] # to [47dcee3eac105e9bc2d39f8f9802d606dcf5c5bd] # # patch "unit_tests.cc" # from [45a81af10ac5ffd8be8d0bf9c4c8ee03f63bf16d] # to [5baf8acaed8b1a76321a7b8e95de47414bf97de7] # ============================================================ --- botan_pipe_cache.hh 6a935f221e4a9368cbef90618e4a3847d1053dbc +++ botan_pipe_cache.hh 6a935f221e4a9368cbef90618e4a3847d1053dbc @@ -0,0 +1,90 @@ +#ifndef __BOTAN_PIPE_CACHE_HH__ +#define __BOTAN_PIPE_CACHE_HH__ + +// Copyright (C) 2008 Zack Weinberg +// +// This program is made available under the GNU GPL version 2.0 or +// greater. See the accompanying file COPYING for details. +// +// This program is distributed WITHOUT ANY WARRANTY; without even the +// implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +// PURPOSE. + +#include +#include +#include "sanity.hh" + +// This file defines a simple lifetime-of-the-program caching strategy for +// Botan::Pipe objects. Instead of writing +// +// Botan::Pipe p(...); +// +// you do +// +// static cached_botan_pipe p(new Botan::Pipe(...)); +// +// and then use p like a Botan::Pipe object (except with -> instead of .). +// +// The global pipe_cache_cleanup object takes care of destroying all such +// cached pipes before the Botan::LibraryInitializer object is destroyed. + +class pipe_cache_cleanup; + +class cached_botan_pipe +{ + friend class pipe_cache_cleanup; + cached_botan_pipe * next_tbd; + boost::scoped_ptr pipe; + +public: + cached_botan_pipe(Botan::Pipe * p); + ~cached_botan_pipe() { I(!pipe); } + Botan::Pipe & operator*() + { I(pipe); return *pipe; } + Botan::Pipe * operator->() + { I(pipe); return pipe.get(); } + + // ??? operator bool, operator! a la boost::scoped_ptr + // (what's with the bizarro unspecified_bool_type thing?) +}; + +extern Botan::Pipe * unfiltered_pipe; +extern pipe_cache_cleanup * global_pipe_cleanup_object; + +class pipe_cache_cleanup +{ + friend class cached_botan_pipe; + struct cached_botan_pipe * to_be_destroyed; + +public: + pipe_cache_cleanup() : to_be_destroyed(0) + { + I(!global_pipe_cleanup_object); + global_pipe_cleanup_object = this; + } + ~pipe_cache_cleanup() + { + for (cached_botan_pipe * p = to_be_destroyed; p; p = p->next_tbd) + p->pipe.reset(0); + global_pipe_cleanup_object = 0; + } +}; + +// must be defined after class pipe_cache_cleanup +inline cached_botan_pipe::cached_botan_pipe(Botan::Pipe * p) + : pipe(p) +{ + I(global_pipe_cleanup_object); + this->next_tbd = global_pipe_cleanup_object->to_be_destroyed; + global_pipe_cleanup_object->to_be_destroyed = this; +} + +// Local Variables: +// mode: C++ +// fill-column: 76 +// c-file-style: "gnu" +// indent-tabs-mode: nil +// End: +// vim: et:sw=2:sts=2:ts=2:cino=>2s,{s,\:s,+s,t0,g0,^-2,e-2,n-2,p2s,(0,=s: + +#endif // __BOTAN_PIPE_CACHE_HH__ ============================================================ --- Makefile.am 242b7438c47167c49dc69f129232bd6b91261a22 +++ Makefile.am 868eff98716b795d27b9f00b523e2c42d9e1f0ce @@ -25,6 +25,7 @@ MOST_SOURCES = \ $(SANITY_CORE_SOURCES) $(LUAEXT_SOURCES) platform-wrapped.hh \ rev_types.hh mtn-sanity.cc mtn-sanity.hh ui.cc ui.hh \ app_state.cc app_state.hh \ + botan_pipe_cache.hh \ commands.cc commands.hh $(CMD_SOURCES) \ diff_patch.cc diff_patch.hh \ lua_hooks.cc lua_hooks.hh \ ============================================================ --- file_io.cc 358fb964dc42e7f936a136342b93bb3a4744d1b3 +++ file_io.cc db5ed54600200ee2cda6ff1a2a8b0ecb463b653b @@ -12,6 +12,7 @@ #include #include "botan/botan.h" +#include "botan_pipe_cache.hh" #include "file_io.hh" #include "sanity.hh" @@ -334,11 +335,10 @@ read_data(any_path const & p, data & dat ifstream file(p.as_external().c_str(), ios_base::in | ios_base::binary); N(file, F("cannot open file %s for reading") % p); - Botan::Pipe pipe; - pipe.start_msg(); - file >> pipe; - pipe.end_msg(); - dat = data(pipe.read_all_as_string()); + unfiltered_pipe->start_msg(); + file >> *unfiltered_pipe; + unfiltered_pipe->end_msg(); + dat = data(unfiltered_pipe->read_all_as_string(Botan::Pipe::LAST_MESSAGE)); } void read_directory(any_path const & path, @@ -358,11 +358,10 @@ read_data_stdin(data & dat) static bool have_consumed_stdin = false; N(!have_consumed_stdin, F("Cannot read standard input multiple times")); have_consumed_stdin = true; - Botan::Pipe pipe; - pipe.start_msg(); - cin >> pipe; - pipe.end_msg(); - dat = data(pipe.read_all_as_string()); + unfiltered_pipe->start_msg(); + cin >> *unfiltered_pipe; + unfiltered_pipe->end_msg(); + dat = data(unfiltered_pipe->read_all_as_string(Botan::Pipe::LAST_MESSAGE)); } void @@ -562,13 +561,16 @@ calculate_ident(file_path const & file, hexenc & ident) { // no conversions necessary, use streaming form + static cached_botan_pipe + p(new Botan::Pipe(new Botan::Hash_Filter("SHA-160"), + new Botan::Hex_Encoder(Botan::Hex_Encoder::Lowercase))); + // Best to be safe and check it isn't a dir. assert_path_is_file(file); - Botan::Pipe p(new Botan::Hash_Filter("SHA-160"), new Botan::Hex_Encoder()); Botan::DataSource_Stream infile(file.as_external(), true); - p.process_msg(infile); + p->process_msg(infile); - ident = hexenc(lowercase(p.read_all_as_string())); + ident = hexenc(p->read_all_as_string(Botan::Pipe::LAST_MESSAGE)); } // Local Variables: ============================================================ --- gzip.cc 93f149779d9f0132940a206e008eeef3ca618b92 +++ gzip.cc 72e05981fe6cc8aa932363eef6c187241a4bb31d @@ -200,7 +200,7 @@ void Gzip_Compression::put_footer() SecureVector buf(4); SecureVector tmpbuf(4); - pipe.read(tmpbuf.begin(), tmpbuf.size()); + pipe.read(tmpbuf.begin(), tmpbuf.size(), Pipe::LAST_MESSAGE); // CRC32 is the reverse order to what gzip expects. for (int i = 0; i < 4; i++) @@ -365,7 +365,7 @@ void Gzip_Decompression::check_footer() // 4 byte CRC32, and 4 byte length field SecureVector buf(4); SecureVector tmpbuf(4); - pipe.read(tmpbuf.begin(), tmpbuf.size()); + pipe.read(tmpbuf.begin(), tmpbuf.size(), Pipe::LAST_MESSAGE); // CRC32 is the reverse order to what gzip expects. for (int i = 0; i < 4; i++) @@ -406,7 +406,7 @@ void Gzip_Decompression::clear() no_writes = true; inflateReset(&(zlib->stream)); - footer.clear(); + footer.destroy(); pos = 0; datacount = 0; } ============================================================ --- hmac.cc 115a8c2bd6e81ea28d4628e77e4ad4dfae8e00a9 +++ hmac.cc da58d8141987a07675d0a8aaf8ab70b60d53ac90 @@ -12,7 +12,10 @@ chained_hmac::chained_hmac(netsync_sessi chained_hmac::chained_hmac(netsync_session_key const & session_key, bool active) : hmac_length(constants::sha1_digest_length), active(active), - key(reinterpret_cast(session_key().data()), session_key().size()) + key(reinterpret_cast(session_key().data()), + session_key().size()), + engine(new Botan::MAC_Filter("HMAC(SHA-160)", key, + constants::sha1_digest_length)) { chain_val.assign(hmac_length, 0x00); } @@ -24,6 +27,9 @@ chained_hmac::set_key(netsync_session_ke { key = Botan::SymmetricKey(reinterpret_cast(session_key().data()), session_key().size()); + engine.reset(); + engine.append(new Botan::MAC_Filter("HMAC(SHA-160)", key, + constants::sha1_digest_length)); } } @@ -38,14 +44,12 @@ chained_hmac::process(string const & str I(pos + n <= str.size()); - Botan::Pipe p(new Botan::MAC_Filter("HMAC(SHA-160)", key, - constants::sha1_digest_length)); - p.start_msg(); - p.write(chain_val); - p.write(reinterpret_cast(str.data() + pos), n); - p.end_msg(); + engine.start_msg(); + engine.write(chain_val); + engine.write(reinterpret_cast(str.data() + pos), n); + engine.end_msg(); - chain_val = p.read_all_as_string(); + chain_val = engine.read_all_as_string(Botan::Pipe::LAST_MESSAGE); I(chain_val.size() == constants::sha1_digest_length); return chain_val; @@ -62,15 +66,13 @@ chained_hmac::process(string_queue const I(pos + n <= str.size()); - Botan::Pipe p(new Botan::MAC_Filter("HMAC(SHA-160)", key, - constants::sha1_digest_length)); - p.start_msg(); - p.write(chain_val); - p.write(reinterpret_cast(str.front_pointer(n) + pos), n); - - p.end_msg(); + engine.start_msg(); + engine.write(chain_val); + engine.write(reinterpret_cast(str.front_pointer(n) + + pos), n); + engine.end_msg(); - chain_val = p.read_all_as_string(); + chain_val = engine.read_all_as_string(Botan::Pipe::LAST_MESSAGE); I(chain_val.size() == constants::sha1_digest_length); return chain_val; ============================================================ --- hmac.hh 6953e20a8a307882b42c317e31714a53f8dae510 +++ hmac.hh 38920db37f7ac41a26c51b97a9fb2a394d0f37ff @@ -23,6 +23,7 @@ private: private: bool active; Botan::SymmetricKey key; + Botan::Pipe engine; std::string chain_val; }; ============================================================ --- key_store.cc 167e6637e117ee23709dc32bb029cb0288064606 +++ key_store.cc 0f3eb9d8e4e664f42a1099f299c325604fae9cc9 @@ -17,6 +17,7 @@ #include "botan/rsa.h" #include "botan/keypair.h" #include "botan/pem.h" +#include "botan_pipe_cache.hh" using std::make_pair; using std::istringstream; @@ -377,9 +378,8 @@ key_store_state::decrypt_private_key(rsa shared_ptr pkcs8_key; try // with empty passphrase { - Pipe p; - p.process_msg(kp.priv()); - pkcs8_key.reset(Botan::PKCS8::load_key(p, "")); + Botan::DataSource_Memory ds(kp.priv()); + pkcs8_key.reset(Botan::PKCS8::load_key(ds, "")); } catch (Botan::Exception & e) { @@ -397,9 +397,8 @@ key_store_state::decrypt_private_key(rsa for (;;) try { - Pipe p; - p.process_msg(kp.priv()); - pkcs8_key.reset(Botan::PKCS8::load_key(p, phrase())); + Botan::DataSource_Memory ds(kp.priv()); + pkcs8_key.reset(Botan::PKCS8::load_key(ds, phrase())); break; } catch (Botan::Exception & e) @@ -469,22 +468,23 @@ key_store::create_key_pair(database & db // serialize and maybe encrypt the private key keypair kp; SecureVector pubkey, privkey; - Pipe p; - p.start_msg(); + + unfiltered_pipe->start_msg(); if ((*maybe_passphrase)().length()) - Botan::PKCS8::encrypt_key(priv, p, + Botan::PKCS8::encrypt_key(priv, *unfiltered_pipe, (*maybe_passphrase)(), "PBE-PKCS5v20(SHA-1,TripleDES/CBC)", Botan::RAW_BER); else - Botan::PKCS8::encode(priv, p); - kp.priv = rsa_priv_key(p.read_all_as_string()); + Botan::PKCS8::encode(priv, *unfiltered_pipe); + unfiltered_pipe->end_msg(); + kp.priv = rsa_priv_key(unfiltered_pipe->read_all_as_string(Pipe::LAST_MESSAGE)); // serialize the public key - Pipe p2; - p2.start_msg(); - Botan::X509::encode(priv, p2, Botan::RAW_BER); - kp.pub = rsa_pub_key(p2.read_all_as_string()); + unfiltered_pipe->start_msg(); + Botan::X509::encode(priv, *unfiltered_pipe, Botan::RAW_BER); + unfiltered_pipe->end_msg(); + kp.pub = rsa_pub_key(unfiltered_pipe->read_all_as_string(Pipe::LAST_MESSAGE)); // convert to storage format L(FL("generated %d-byte public key\n" @@ -519,12 +519,12 @@ key_store::change_key_passphrase(rsa_key utf8 new_phrase; get_passphrase(new_phrase, id, true, false); - Pipe p; - p.start_msg(); - Botan::PKCS8::encrypt_key(*priv, p, new_phrase(), + unfiltered_pipe->start_msg(); + Botan::PKCS8::encrypt_key(*priv, *unfiltered_pipe, new_phrase(), "PBE-PKCS5v20(SHA-1,TripleDES/CBC)", Botan::RAW_BER); - kp.priv = rsa_priv_key(p.read_all_as_string()); + unfiltered_pipe->end_msg(); + kp.priv = rsa_priv_key(unfiltered_pipe->read_all_as_string(Pipe::LAST_MESSAGE)); delete_key(id); put_key_pair(id, kp); @@ -684,6 +684,7 @@ key_store::export_key_for_agent(rsa_keyp utf8 new_phrase; get_passphrase(new_phrase, id, true, false); + // This pipe cannot sensibly be recycled. Pipe p(new Botan::DataSink_Stream(os)); p.start_msg(); if (new_phrase().length()) @@ -734,10 +735,9 @@ key_store_state::migrate_old_key_pair // recognize an unencrypted, raw-BER blob as such, but gets it // right if it's PEM-coded. SecureVector arc4_decrypt(arc4_decryptor.read_all()); - Pipe p; - p.process_msg(Botan::PEM_Code::encode(arc4_decrypt, "PRIVATE KEY")); - - pkcs8_key.reset(Botan::PKCS8::load_key(p)); + Botan::DataSource_Memory ds(Botan::PEM_Code::encode(arc4_decrypt, + "PRIVATE KEY")); + pkcs8_key.reset(Botan::PKCS8::load_key(ds)); break; } catch (Botan::Exception & e) @@ -758,20 +758,20 @@ key_store_state::migrate_old_key_pair I(priv_key); // now we can write out the new key - Pipe p; - p.start_msg(); - Botan::PKCS8::encrypt_key(*priv_key, p, phrase(), + unfiltered_pipe->start_msg(); + Botan::PKCS8::encrypt_key(*priv_key, *unfiltered_pipe, phrase(), "PBE-PKCS5v20(SHA-1,TripleDES/CBC)", Botan::RAW_BER); - kp.priv = rsa_priv_key(p.read_all_as_string()); + unfiltered_pipe->end_msg(); + kp.priv = rsa_priv_key(unfiltered_pipe->read_all_as_string(Pipe::LAST_MESSAGE)); // also the public key (which is derivable from the private key; asking // Botan for the X.509 encoding of the private key implies that we want // it to derive and produce the public key) - Pipe p2; - p2.start_msg(); - Botan::X509::encode(*priv_key, p2, Botan::RAW_BER); - kp.pub = rsa_pub_key(p2.read_all_as_string()); + unfiltered_pipe->start_msg(); + Botan::X509::encode(*priv_key, *unfiltered_pipe, Botan::RAW_BER); + unfiltered_pipe->end_msg(); + kp.pub = rsa_pub_key(unfiltered_pipe->read_all_as_string(Pipe::LAST_MESSAGE)); // if the database had a public key entry for this key, make sure it // matches what we derived from the private key entry, but don't abort the ============================================================ --- monotone.cc c105422e7de754e19a87af2cd8ad4b798159520e +++ monotone.cc e7cb1f117494c4853f3320a4add02474b6a2ff6c @@ -19,9 +19,9 @@ #include "botan/botan.h" #include "i18n.h" #include "app_state.hh" +#include "botan_pipe_cache.hh" #include "commands.hh" #include "sanity.hh" -#include "cleanup.hh" #include "file_io.hh" #include "charset.hh" #include "ui.hh" @@ -99,6 +99,11 @@ void localize_monotone() } } +// define the global objects needed by botan_pipe_cache.hh +pipe_cache_cleanup * global_pipe_cleanup_object; +Botan::Pipe * unfiltered_pipe; +static unsigned char unfiltered_pipe_cleanup_mem[sizeof(cached_botan_pipe)]; + option::concrete_option_set read_global_options(options & opts, args_vector & args) { @@ -166,9 +171,14 @@ cpp_main(int argc, char ** argv) Botan::LibraryInitializer acquire_botan("thread_safe=0 selftest=0 " "seed_rng=1 use_engines=0 " "secure_memory=1 fips140=0"); + + // and caching for botan pipes + pipe_cache_cleanup acquire_botan_pipe_caching; + unfiltered_pipe = new Botan::Pipe; + new (unfiltered_pipe_cleanup_mem) cached_botan_pipe(unfiltered_pipe); // Record where we are. This has to happen before any use of - // boost::filesystem. + // paths.hh objects. save_initial_path(); // decode all argv values into a UTF-8 array ============================================================ --- tester.cc 5698be54abe68883c1ce41db0ba95e461a1f3fad +++ tester.cc da1589e5c3cc77aa51b5658a71b613e6b1ec64db @@ -6,6 +6,8 @@ #include "tester-plaf.hh" #include "vector.hh" #include "sanity.hh" +#include "botan/botan.h" +#include "botan_pipe_cache.hh" #include #include @@ -38,6 +40,11 @@ sanity & global_sanity = real_sanity; tester_sanity real_sanity; sanity & global_sanity = real_sanity; +// define the global objects needed by botan_pipe_cache.hh +pipe_cache_cleanup * global_pipe_cleanup_object; +Botan::Pipe * unfiltered_pipe; +static unsigned char unfiltered_pipe_cleanup_mem[sizeof(cached_botan_pipe)]; + string basename(string const & s) { string::size_type sep = s.rfind('/'); @@ -904,7 +911,7 @@ parse_makeflags(char const * mflags, } } else if (int_int_option(i->c_str(), "--jobserver-fds=", jread, jwrite)) - ; + 0; } // do not permit -j in MAKEFLAGS to override -j on the command line. @@ -1004,6 +1011,16 @@ int main(int argc, char **argv) try { global_sanity.initialize(argc, argv, "C"); + // Set up secure memory allocation etc + Botan::LibraryInitializer acquire_botan("thread_safe=0 selftest=0 " + "seed_rng=1 use_engines=0 " + "secure_memory=1 fips140=0"); + + // and caching for botan pipes + pipe_cache_cleanup acquire_botan_pipe_caching; + unfiltered_pipe = new Botan::Pipe; + new (unfiltered_pipe_cleanup_mem) cached_botan_pipe(unfiltered_pipe); + parse_command_line(argc, argv, want_help, need_help, debugging, list_only, run_one, jobs, tests_to_run); ============================================================ --- transforms.cc 144f5ceb3515a7b9a392e6963c5841788a8bdbd0 +++ transforms.cc 47dcee3eac105e9bc2d39f8f9802d606dcf5c5bd @@ -8,26 +8,25 @@ // PURPOSE. #include "base.hh" -#include -#include #include -#include -#include "vector.hh" - +#include "botan_pipe_cache.hh" #include "botan/botan.h" #include "botan/sha160.h" #include "gzip.hh" -#include "cleanup.hh" -#include "constants.hh" -#include "sanity.hh" #include "transforms.hh" -#include "simplestring_xform.hh" -#include "vocab.hh" #include "xdelta.hh" #include "char_classifiers.hh" using std::string; +using Botan::Pipe; +using Botan::Base64_Encoder; +using Botan::Base64_Decoder; +using Botan::Hex_Encoder; +using Botan::Hex_Decoder; +using Botan::Gzip_Compression; +using Botan::Gzip_Decompression; +using Botan::Hash_Filter; // this file contans various sorts of string transformations. each // transformation should be self-explanatory from its type signature. see @@ -98,37 +97,33 @@ error_in_transform(Botan::Exception & e) I(false); // can't get here } -// worker function for the visible functions below -namespace { -template string xform(XFM * x, string const & in) -{ - string out; - try - { - Botan::Pipe pipe(x); - pipe.process_msg(in); - out = pipe.read_all_as_string(); - } - catch (Botan::Exception & e) - { - error_in_transform(e); - } - return out; -} -} - // full specializations for the usable cases of xform() // use extra error checking in base64 and hex decoding -#define SPECIALIZE_XFORM(T, carg) \ - template<> string xform(string const &in) \ - { return xform(new T(carg), in); } +#define SPECIALIZE_XFORM(T, carg) \ + template<> string xform(string const & in) \ + { \ + string out; \ + try \ + { \ + static cached_botan_pipe pipe(new Pipe(new T(carg))); \ + /* this might actually be a problem here */ \ + I(pipe->message_count() < Pipe::LAST_MESSAGE); \ + pipe->process_msg(in); \ + out = pipe->read_all_as_string(Pipe::LAST_MESSAGE); \ + } \ + catch (Botan::Exception & e) \ + { \ + error_in_transform(e); \ + } \ + return out; \ + } -SPECIALIZE_XFORM(Botan::Base64_Encoder,); -SPECIALIZE_XFORM(Botan::Base64_Decoder, Botan::IGNORE_WS); -SPECIALIZE_XFORM(Botan::Hex_Encoder, Botan::Hex_Encoder::Lowercase); -SPECIALIZE_XFORM(Botan::Hex_Decoder, Botan::IGNORE_WS); -SPECIALIZE_XFORM(Botan::Gzip_Compression,); -SPECIALIZE_XFORM(Botan::Gzip_Decompression,); +SPECIALIZE_XFORM(Base64_Encoder,); +SPECIALIZE_XFORM(Base64_Decoder, Botan::IGNORE_WS); +SPECIALIZE_XFORM(Hex_Encoder, Hex_Encoder::Lowercase); +SPECIALIZE_XFORM(Hex_Decoder, Botan::IGNORE_WS); +SPECIALIZE_XFORM(Gzip_Compression,); +SPECIALIZE_XFORM(Gzip_Decompression,); template void pack(T const & in, base64< gzip > & out) @@ -138,10 +133,10 @@ void pack(T const & in, base64< gzip try { - Botan::Pipe pipe(new Botan::Gzip_Compression(), - new Botan::Base64_Encoder); - pipe.process_msg(in()); - tmp = pipe.read_all_as_string(); + static cached_botan_pipe pipe(new Pipe(new Gzip_Compression, + new Base64_Encoder)); + pipe->process_msg(in()); + tmp = pipe->read_all_as_string(Pipe::LAST_MESSAGE); out = base64< gzip >(tmp); } catch (Botan::Exception & e) @@ -155,10 +150,10 @@ void unpack(base64< gzip > const & in { try { - Botan::Pipe pipe(new Botan::Base64_Decoder(), - new Botan::Gzip_Decompression()); - pipe.process_msg(in()); - out = T(pipe.read_all_as_string()); + static cached_botan_pipe pipe(new Pipe(new Base64_Decoder, + new Gzip_Decompression)); + pipe->process_msg(in()); + out = T(pipe->read_all_as_string(Pipe::LAST_MESSAGE)); } catch (Botan::Exception & e) { @@ -202,10 +197,10 @@ calculate_ident(data const & dat, { try { - Botan::Pipe p(new Botan::Hash_Filter("SHA-160"), - new Botan::Hex_Encoder(Botan::Hex_Encoder::Lowercase)); - p.process_msg(dat()); - ident = hexenc(p.read_all_as_string()); + static cached_botan_pipe p(new Pipe(new Hash_Filter("SHA-160"), + new Hex_Encoder(Hex_Encoder::Lowercase))); + p->process_msg(dat()); + ident = hexenc(p->read_all_as_string(Pipe::LAST_MESSAGE)); } catch (Botan::Exception & e) { ============================================================ --- unit_tests.cc 45a81af10ac5ffd8be8d0bf9c4c8ee03f63bf16d +++ unit_tests.cc 5baf8acaed8b1a76321a7b8e95de47414bf97de7 @@ -25,6 +25,7 @@ #include "sanity.hh" #include "ui.hh" #include "current_exception.hh" +#include "botan_pipe_cache.hh" using std::map; using std::pair; @@ -149,9 +150,10 @@ void unit_test::do_checkpoint(char const log_state(file, line, "CHECKPOINT", message); } -static int run_test(test_t test) -{ -} +// define the global objects needed by botan_pipe_cache.hh +pipe_cache_cleanup * global_pipe_cleanup_object; +Botan::Pipe * unfiltered_pipe; +static unsigned char unfiltered_pipe_cleanup_mem[sizeof(cached_botan_pipe)]; int main(int argc, char * argv[]) { @@ -198,7 +200,14 @@ int main(int argc, char * argv[]) // set up some global state before running the tests - Botan::LibraryInitializer::initialize(); + // keep this in sync with monotone.cc, except for selftest=1 here, =0 there + Botan::LibraryInitializer acquire_botan("thread_safe=0 selftest=1 " + "seed_rng=1 use_engines=0 " + "secure_memory=1 fips140=0"); + // and caching for botan pipes + pipe_cache_cleanup acquire_botan_pipe_caching; + unfiltered_pipe = new Botan::Pipe; + new (unfiltered_pipe_cleanup_mem) cached_botan_pipe(unfiltered_pipe); // Make clog and cout use the same streambuf as cerr; this ensures // that all messages will appear in the order written, no matter what