Repository: randombit/botan
Pull request #1964 (2019-05-22 09:47:51)

Allow specification of platform/build dependent boost library name + AppVeyor uses boost 
This is based on #1963 and uses the pre-installed boost 1.69.0 on AppVeyor. The `appveyor.yml` now specifies which version of boost to use for each matrix configuration. Note that we opted to use the static library versions of boost in all cases. Probably its also possible to use the dynamic ones, but we didn't test that.

~~Once AppVeyor turns green for the first time, I'll squash the comments, if you want.~~

Re: Re: #1930



Patch:
diff --git a/configure.py b/configure.py
index fcaf65f34..bd3f34bd5 100755
--- a/configure.py
+++ b/configure.py
@@ -255,12 +255,12 @@ class BuildPaths(object): # pylint: disable=too-many-instance-attributes
             out += [self.fuzzer_output_dir]
         return out
 
-    def format_include_paths(self, cc, external_includes):
+    def format_include_paths(self, cc, external_include):
         dash_i = cc.add_include_dir_option
         output = dash_i + self.include_dir
         if self.external_headers:
             output += ' ' + dash_i + self.external_include_dir
-        for external_include in external_includes:
+        if external_include:
             output += ' ' + dash_i + external_include
         return output
 
@@ -414,11 +414,11 @@ def process_command_line(args): # pylint: disable=too-many-locals,too-many-state
     build_group.add_option('--with-build-dir', metavar='DIR', default='',
                            help='setup the build in DIR')
 
-    build_group.add_option('--with-external-includedir', metavar='DIR', default=[],
-                           help='use DIR for external includes', action='append')
+    build_group.add_option('--with-external-includedir', metavar='DIR', default='',
+                           help='use DIR for external includes')
 
-    build_group.add_option('--with-external-libdir', metavar='DIR', default=[],
-                           help='use DIR for external libs', action='append')
+    build_group.add_option('--with-external-libdir', metavar='DIR', default='',
+                           help='use DIR for external libs')
 
     build_group.add_option('--with-sysroot-dir', metavar='DIR', default='',
                            help='use DIR for system root while cross-compiling')
@@ -488,6 +488,8 @@ def process_command_line(args): # pylint: disable=too-many-locals,too-many-state
                            help=optparse.SUPPRESS_HELP)
     build_group.add_option('--without-pkg-config', dest='with_pkg_config', action='store_false',
                            help=optparse.SUPPRESS_HELP)
+    build_group.add_option('--boost-library-name', dest='boost_libnames', default=[],
+                           help="file name of some boost library to link", action='append')
 
     docs_group = optparse.OptionGroup(parser, 'Documentation Options')
 
@@ -1783,7 +1785,32 @@ def create_template_vars(source_paths, build_paths, options, modules, cc, arch,
     """
 
     def external_link_cmd():
-        return ' '.join([cc.add_lib_dir_option + libdir for libdir in options.with_external_libdir])
+        return (' ' + cc.add_lib_dir_option + options.with_external_libdir) if options.with_external_libdir else ''
+
+    def adjust_library_name(info_txt_libname):
+        """
+        Apply custom library name mappings where necessary
+        """
+
+        # potentially map boost library names to the associated name provided
+        # via ./configure.py --boost-library-name <build/platform specific name>
+        #
+        # We assume that info.txt contains the library name's "stem", i.e.
+        # 'boost_system'. While the user-provided (actual) library will contain
+        # the same stem plus a set of prefixes and/or suffixes, e.g.
+        # libboost_system-vc140-mt-x64-1_69.lib. We use the stem for selecting
+        # the correct user-provided library name override.
+        if options.boost_libnames and 'boost_' in info_txt_libname:
+            adjusted_libnames = [chosen_libname for chosen_libname in options.boost_libnames \
+                                 if info_txt_libname in chosen_libname]
+
+            if len(adjusted_libnames) > 1:
+                logging.warning('Ambiguous boost library names: %s' % ', '.join(adjusted_libnames))
+            if len(adjusted_libnames) > 0:
+                logging.debug('Replacing boost library name %s -> %s' % (info_txt_libname, adjusted_libnames[0]))
+                return adjusted_libnames[0]
+
+        return info_txt_libname
 
     def link_to(module_member_name):
         """
@@ -1804,7 +1831,7 @@ def create_template_vars(source_paths, build_paths, options, modules, cc, arch,
                         if osinfo.basename not in exceptions:
                             libs |= set(module_link_to)
 
-        return sorted(libs)
+        return sorted([adjust_library_name(lib) for lib in libs])
 
     def choose_mp_bits():
         mp_bits = arch.wordsize # allow command line override?
@@ -2004,8 +2031,8 @@ def create_template_vars(source_paths, build_paths, options, modules, cc, arch,
 
         'visibility_attribute': cc.gen_visibility_attribute(options),
 
-        'lib_link_cmd': cc.so_link_command_for(osinfo.basename, options) + ' ' + external_link_cmd(),
-        'exe_link_cmd': cc.binary_link_command_for(osinfo.basename, options) + ' ' + external_link_cmd(),
+        'lib_link_cmd': cc.so_link_command_for(osinfo.basename, options) + external_link_cmd(),
+        'exe_link_cmd': cc.binary_link_command_for(osinfo.basename, options) + external_link_cmd(),
         'post_link_cmd': '',
 
         'ar_command': ar_command(),
@@ -2512,7 +2539,7 @@ class AmalgamationGenerator(object):
     filename_prefix = 'botan_all'
 
     _header_guard_pattern = re.compile(r'^#define BOTAN_.*_H_\s*$')
-    _header_endif_pattern = re.compile(r'^#endif.*$')
+    _header_endif_pattern = re.compile(r'^#endif\s*$')
 
     @staticmethod
     def read_header(filepath):
diff --git a/doc/manual/building.rst b/doc/manual/building.rst
index 0762ff772..dfbd61d54 100644
--- a/doc/manual/building.rst
+++ b/doc/manual/building.rst
@@ -719,14 +719,12 @@ Setup the build in a specified directory instead of ``./build``
 --with-external-includedir=DIR
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-Search for includes in this directory. Provide this parameter multiple times to
-define multiple additional include directories.
+Search for includes in this directory.
 
 --with-external-libdir=DIR
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-Add DIR to the link path. Provide this parameter multiple times to define
-multiple additional library link directories.
+Add DIR to the link path
 
 --with-sysroot-dir=DIR
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -788,6 +786,15 @@ read one input from stdin and then exit.
 
 Specify an additional library that fuzzer binaries must link with.
 
+--boost-library-name
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Provide an alternative name for a boost library. Depending on the platform and
+boost's build configuration these library names differ significantly (see `here
+<https://www.boost.org/doc/libs/1_70_0/more/getting_started/unix-variants.html#library-naming>`_).
+The provided library name must be suitable as identifier in a linker parameter,
+e.g on unix: ``boost_system`` or windows: ``libboost_regex-vc71-x86-1_70.lib``.
+
 --without-documentation
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
diff --git a/news.rst b/news.rst
index 20b87edec..d7d708ed6 100644
--- a/news.rst
+++ b/news.rst
@@ -5,7 +5,7 @@ Version 2.11.0, Not Yet Released
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 * Add a shim allowing testing Botan against the BoringSSL test suite.
-  (GH #1954 #1955 #1956 #1959)
+  (GH #1954 #1955 #1956)
 
 * Add a ``boost::asio`` TLS stream compatible with ``boost::asio::ssl``.
   (GH #1839 #1927)
diff --git a/src/bogo_shim/bogo_shim.cpp b/src/bogo_shim/bogo_shim.cpp
index 6af76d3f1..daf139de9 100644
--- a/src/bogo_shim/bogo_shim.cpp
+++ b/src/bogo_shim/bogo_shim.cpp
@@ -16,7 +16,6 @@
 #include <botan/tls_algos.h>
 #include <botan/data_src.h>
 #include <botan/pkcs8.h>
-#include <botan/loadstor.h>
 #include <botan/oids.h>
 #include <botan/chacha_rng.h>
 #include <botan/base64.h>
@@ -50,25 +49,22 @@ int shim_output(const std::string& s, int rc = 0)
    return rc;
    }
 
+void shim_exit_with_error(const std::string& s, int rc = 1)
+   {
+   std::cerr << s << "\n";
+   std::exit(rc);
+   }
+
 void shim_log(const std::string& s)
    {
    if(::getenv("BOTAN_BOGO_SHIM_LOG"))
       {
-      static FILE* log = std::fopen("/tmp/bogo_shim.log", "w");
-      struct timeval tv;
-      ::gettimeofday(&tv, nullptr);
-      std::fprintf(log, "%zu.%lu: %s\n", tv.tv_sec, tv.tv_usec, s.c_str());
-      std::fflush(log);
+      static FILE* f = fopen("/tmp/bogo_shim.log", "w");
+      fprintf(f, "%d: %s\n", (int)time(nullptr), s.c_str());
+      fflush(f);
       }
    }
 
-void BOTAN_NORETURN shim_exit_with_error(const std::string& s, int rc = 1)
-   {
-   shim_log("Exiting with " + s);
-   std::cerr << s << "\n";
-   std::exit(rc);
-   }
-
 std::string map_to_bogo_error(const std::string& e)
    {
    static const std::unordered_map<std::string, std::string> err_map
@@ -77,8 +73,6 @@ std::string map_to_bogo_error(const std::string& e)
          { "Bad Hello_Request, has non-zero size", ":BAD_HELLO_REQUEST:" },
          { "Bad code for TLS alert level", ":UNKNOWN_ALERT_TYPE:" },
          { "Bad extension size", ":DECODE_ERROR:" },
-         { "Bad length in hello verify request", ":DECODE_ERROR:" },
-         { "Bad lengths in DTLS header", ":BAD_HANDSHAKE_RECORD:" },
          { "Bad signature on server key exchange", ":BAD_SIGNATURE:" },
          { "Bad size (1) for TLS alert message", ":BAD_ALERT:" },
          { "Bad size (4) for TLS alert message", ":BAD_ALERT:" },
@@ -95,7 +89,6 @@ std::string map_to_bogo_error(const std::string& e)
          { "Client policy prohibits renegotiation", ":NO_RENEGOTIATION:" },
          { "Client resumed extended ms session without sending extension", ":RESUMED_EMS_SESSION_WITHOUT_EMS_EXTENSION:" },
          { "Client signalled fallback SCSV, possible attack", ":INAPPROPRIATE_FALLBACK:" },
-         { "Client version DTLS v1.0 is unacceptable by policy", ":UNSUPPORTED_PROTOCOL:" },
          { "Client version TLS v1.0 is unacceptable by policy", ":UNSUPPORTED_PROTOCOL:" },
          { "Client version TLS v1.1 is unacceptable by policy", ":UNSUPPORTED_PROTOCOL:" },
          { "Client: No certificates sent by server", ":DECODE_ERROR:" },
@@ -104,7 +97,6 @@ std::string map_to_bogo_error(const std::string& e)
          { "Encoding error: Cannot encode PSS string, output length too small", ":NO_COMMON_SIGNATURE_ALGORITHMS:" },
          { "Finished message didn't verify", ":DIGEST_CHECK_FAILED:" },
          { "Inconsistent length in certificate request", ":DECODE_ERROR:" },
-         { "Inconsistent values in fragmented DTLS handshake header", ":FRAGMENT_MISMATCH:" },
          { "Invalid CertificateRequest: Length field outside parameters", ":DECODE_ERROR:" },
          { "Invalid CertificateVerify: Extra bytes at end of message", ":DECODE_ERROR:" },
          { "Invalid Certificate_Status: invalid length field", ":DECODE_ERROR:" },
@@ -129,7 +121,6 @@ std::string map_to_bogo_error(const std::string& e)
          { "Server changed version after renegotiation", ":WRONG_SSL_VERSION:" },
          { "Server downgraded version after renegotiation", ":WRONG_SSL_VERSION:" },
          { "Server replied using a ciphersuite not allowed in version it offered", ":WRONG_CIPHER_RETURNED:" },
-         { "Server replied with DTLS-SRTP alg we did not send", ":BAD_SRTP_PROTECTION_PROFILE_LIST:" },
          { "Server replied with ciphersuite we didn't send", ":WRONG_CIPHER_RETURNED:" },
          { "Server replied with later version than client offered", ":UNSUPPORTED_PROTOCOL:" },
          { "Server replied with non-null compression method", ":UNSUPPORTED_COMPRESSION_ALGORITHM:" },
@@ -147,7 +138,6 @@ std::string map_to_bogo_error(const std::string& e)
          { "Server sent bad values for secure renegotiation", ":RENEGOTIATION_MISMATCH:" },
          { "Server version TLS v1.0 is unacceptable by policy", ":UNSUPPORTED_PROTOCOL:" },
          { "Server version TLS v1.1 is unacceptable by policy", ":UNSUPPORTED_PROTOCOL:" },
-         { "Server version DTLS v1.0 is unacceptable by policy", ":UNSUPPORTED_PROTOCOL:" },
          { "Server_Hello_Done: Must be empty, and is not", ":DECODE_ERROR:" },
          { "Simulated OCSP callback failure", ":OCSP_CB_ERROR:" },
          { "Simulating cert verify callback failure", ":CERT_CB_ERROR:" },
@@ -176,7 +166,6 @@ std::string map_to_bogo_error(const std::string& e)
          { "Unexpected state transition in handshake, expected server_key_exchange|server_hello_done received certificate_request", ":UNEXPECTED_MESSAGE:" },
          { "Unknown TLS handshake message type 43", ":UNEXPECTED_MESSAGE:" },
          { "Unknown TLS handshake message type 44", ":UNEXPECTED_MESSAGE:" },
-         { "Unknown TLS handshake message type 45", ":UNEXPECTED_MESSAGE:" },
          { "Unknown TLS handshake message type 46", ":UNEXPECTED_MESSAGE:" },
          { "Unknown TLS handshake message type 53", ":UNEXPECTED_MESSAGE:" },
          { "Unknown TLS handshake message type 54", ":UNEXPECTED_MESSAGE:" },
@@ -280,14 +269,9 @@ class Shim_Socket final
          while(sent_so_far != len)
             {
             const size_t left = len - sent_so_far;
-            socket_op_ret_type sent = ::send(m_socket, Botan::cast_uint8_ptr_to_char(&buf[sent_so_far]), left, MSG_NOSIGNAL);
+            socket_op_ret_type sent = ::send(m_socket, Botan::cast_uint8_ptr_to_char(&buf[sent_so_far]), left, 0);
             if(sent < 0)
-               {
-               if(errno == EPIPE)
-                  return;
-               else
-                  throw Shim_Exception("Socket write failed", errno);
-               }
+               throw Shim_Exception("Socket write failed", errno);
             else
                sent_so_far += static_cast<size_t>(sent);
             }
@@ -297,7 +281,8 @@ class Shim_Socket final
          {
          if(m_socket < 0)
             throw Shim_Exception("Socket was bad on read");
-         socket_op_ret_type got = ::read(m_socket, Botan::cast_uint8_ptr_to_char(buf), len);
+         socket_op_ret_type got = ::recv(m_socket, Botan::cast_uint8_ptr_to_char(buf), len, 0);
+         //shim_log("Read returned " + std::to_string(got));
 
          if(got < 0)
             {
@@ -660,7 +645,7 @@ std::unique_ptr<Shim_Arguments> parse_options(char* argv[])
       //"max-send-fragment",
       "max-version",
       "min-version",
-      "mtu",
+      //"mtu",
       "port",
       "read-size",
       "resume-count",
@@ -887,15 +872,9 @@ class Shim_Policy final : public Botan::TLS::Policy
          return (!m_args.flag_set("no-tls12"));
          }
 
-      bool allow_dtls10() const override
-         {
-         return true; // ???
-         }
+      //bool allow_dtls10() const override;
 
-      bool allow_dtls12() const override
-         {
-         return true; // ???
-         }
+      //bool allow_dtls12() const override;
 
       //Botan::TLS::Group_Params default_dh_group() const override;
 
@@ -915,22 +894,7 @@ class Shim_Policy final : public Botan::TLS::Policy
 
       //uint32_t session_ticket_lifetime() const override;
 
-      std::vector<uint16_t> srtp_profiles() const override
-         {
-         if(m_args.option_used("srtp-profiles"))
-            {
-            std::string srtp = m_args.get_string_opt("srtp-profiles");
-
-            if(srtp == "SRTP_AES128_CM_SHA1_80:SRTP_AES128_CM_SHA1_32")
-               return {1,2};
-            else if(srtp == "SRTP_AES128_CM_SHA1_80")
-               return {1};
-            else
-               shim_exit_with_error("unknown srtp-profiles");
-            }
-         else
-            return {};
-         }
+      //std::vector<uint16_t> srtp_profiles() const override;
 
       bool only_resume_with_exact_version() const override
          {
@@ -980,10 +944,7 @@ class Shim_Policy final : public Botan::TLS::Policy
       std::vector<uint16_t> ciphersuite_list(Botan::TLS::Protocol_Version version,
                                              bool have_srp) const override;
 
-      size_t dtls_default_mtu() const override
-         {
-         return m_args.get_int_opt_or_else("mtu", 1232);
-         }
+      //size_t dtls_default_mtu() const override;
 
       //size_t dtls_initial_timeout() const override;
 
@@ -1191,6 +1152,8 @@ class Shim_Callbacks final : public Botan::TLS::Callbacks
          m_is_datagram(args.flag_set("dtls")),
          m_warning_alerts(0),
          m_empty_records(0),
+         m_should_exit(false),
+         m_first_write_pending(true),
          m_sent_close(false)
          {}
 
@@ -1201,24 +1164,8 @@ class Shim_Callbacks final : public Botan::TLS::Callbacks
 
       void tls_emit_data(const uint8_t data[], size_t size) override
          {
-         if(m_is_datagram)
-            {
-            shim_log("sending record of len " + std::to_string(size));
-            const uint8_t hdr[5] = {
-               'P',
-               static_cast<uint8_t>((size >> 24) & 0xFF),
-               static_cast<uint8_t>((size >> 16) & 0xFF),
-               static_cast<uint8_t>((size >> 8) & 0xFF),
-               static_cast<uint8_t>(size & 0xFF),
-            };
-
-            m_socket.write(hdr, sizeof(hdr));
-            m_socket.write(data, size);
-            }
-         else
-            {
-            m_socket.write(data, size);
-            }
+         //shim_log("Emit data len" + std::to_string(size));
+         m_socket.write(data, size);
          }
 
       void tls_record_received(uint64_t /*seq_no*/, const uint8_t data[], size_t size) override
@@ -1234,11 +1181,19 @@ class Shim_Callbacks final : public Botan::TLS::Callbacks
             {
             m_empty_records = 0;
             }
+         shim_log("Got a record len " + std::to_string(size));
+         if(m_first_write_pending)
+            {
+
+            //m_channel->send("hello");
+            m_first_write_pending = false;
+            }
 
          std::vector<uint8_t> buf(data, data + size);
          for(size_t i = 0; i != size; ++i)
             buf[i] ^= 0xFF;
 
+         shim_log("Sending " + std::to_string(size) + " bytes of blob");
          m_channel->send(buf);
          }
 
@@ -1341,30 +1296,30 @@ class Shim_Callbacks final : public Botan::TLS::Callbacks
          if(m_args.option_used("expect-no-session-id"))
             {
             if(session.session_id().size() > 0)
-               shim_exit_with_error("Unexpected session ID");
+               shim_exit_with_error("GOT UNEXPECTED SESSION ID");
             }
 
          if(m_args.option_used("expect-version"))
             {
             if(session.version().version_code() != m_args.get_int_opt("expect-version"))
-               shim_exit_with_error("Unexpected version");
+               shim_exit_with_error("UNEXPECTED VERSION");
             }
 
          if(m_args.flag_set("expect-secure-renegotiation"))
             {
             if(m_channel->secure_renegotiation_supported() == false)
-               shim_exit_with_error("Expected secure renegotiation");
+               shim_exit_with_error("EXPECTED SECURE RENEGOTIATION");
             }
          else if(m_args.flag_set("expect-no-secure-renegotiation"))
             {
             if(m_channel->secure_renegotiation_supported() == true)
-               shim_exit_with_error("Expected no secure renegotation");
+               shim_exit_with_error("EXPECTED NO SECURE RENEGOTIATION");
             }
 
          if(m_args.flag_set("expect-extended-master-secret"))
             {
             if(session.supports_extended_master_secret() == false)
-               shim_exit_with_error("Expected extended maseter secret");
+               shim_exit_with_error("NO ETM");
             }
 
          return true;
@@ -1383,8 +1338,8 @@ class Shim_Callbacks final : public Botan::TLS::Callbacks
             const std::string label = m_args.get_string_opt("export-label");
             const std::string context = m_args.get_string_opt("export-context");
             const auto exported = m_channel->key_material_export(label, context, length);
-            shim_log("Sending " + std::to_string(length) + " bytes of key material");
             m_channel->send(exported.bits_of());
+            shim_log("Sending " + std::to_string(length) + " bytes of export");
             }
 
          const std::string alpn = m_channel->application_protocol();
@@ -1418,6 +1373,11 @@ class Shim_Callbacks final : public Botan::TLS::Callbacks
             }
          }
 
+      bool should_exit() const
+         {
+         return m_should_exit;
+         }
+
    private:
       Botan::TLS::Channel* m_channel;
       const Shim_Arguments& m_args;
@@ -1426,6 +1386,8 @@ class Shim_Callbacks final : public Botan::TLS::Callbacks
       const bool m_is_datagram;
       size_t m_warning_alerts;
       size_t m_empty_records;
+      bool m_should_exit;
+      bool m_first_write_pending;
       bool m_sent_close;
    };
 
@@ -1447,12 +1409,8 @@ int main(int /*argc*/, char* argv[])
       const bool is_server = args->flag_set("server");
       const bool is_datagram = args->flag_set("dtls");
 
-      const size_t buf_size = args->get_int_opt_or_else("read-size", 18*1024);
-
-      /*
       if(is_datagram)
          throw Shim_Exception("No support for DTLS yet", 89);
-      */
 
       Botan::ChaCha_RNG rng(Botan::secure_vector<uint8_t>(64));
       Botan::TLS::Session_Manager_In_Memory session_manager(rng, 1024);
@@ -1462,8 +1420,6 @@ int main(int /*argc*/, char* argv[])
          {
          Shim_Socket socket("localhost", port);
 
-         shim_log("Connection " + std::to_string(i+1) + "/" + std::to_string(resume_count+1));
-
          Shim_Policy policy(*args);
          Shim_Callbacks callbacks(*args, socket, policy);
 
@@ -1490,64 +1446,24 @@ int main(int /*argc*/, char* argv[])
 
          callbacks.set_channel(chan.get());
 
-         std::vector<uint8_t> buf(buf_size);
+         shim_log("Starting read loop");
+
+         std::vector<uint8_t> buf(args->get_int_opt_or_else("read-size", 18*1024));
+         size_t need_to_read = 5; // header len
 
-         for(;;)
+         while(!callbacks.should_exit())
             {
-            if(is_datagram)
+            size_t got = socket.read(buf.data(), buf.size());
+            if(got == 0)
                {
-               uint8_t opcode;
-               size_t got = socket.read(&opcode, 1);
-               if(got == 0)
-                  {
-                  shim_log("EOF on socket");
-                  break;
-                  }
-
-               if(opcode == 'P')
-                  {
-                  uint8_t len_bytes[4];
-                  if(socket.read(len_bytes, sizeof(len_bytes)) != 4)
-                     shim_exit_with_error("Short read getting packet len");
-
-                  size_t packet_len = Botan::load_be<uint32_t>(len_bytes, 0);
-
-                  if(buf.size() < packet_len)
-                     buf.resize(packet_len);
-                  if(socket.read(buf.data(), packet_len) != packet_len)
-                     shim_exit_with_error("Short read getting packet data " + std::to_string(packet_len));
-
-                  chan->received_data(buf.data(), packet_len);
-                  }
-               else if(opcode == 'T')
-                  {
-                  uint8_t timeout_ack = 't';
-
-                  uint8_t timeout_bytes[8];
-                  if(socket.read(timeout_bytes, sizeof(timeout_bytes)) != 8)
-                     shim_exit_with_error("Short read getting timeout value");
-
-                  const uint64_t nsec = Botan::load_be<uint64_t>(timeout_bytes, 0);
-
-                  shim_log("Timeout nsec " + std::to_string(nsec));
+               shim_log("EOF on socket");
+               break;
+               }
 
-                  // FIXME handle this!
+            need_to_read = chan->received_data(buf.data(), got);
 
-                  socket.write(&timeout_ack, 1); // ack it anyway
-                  }
-               else
-                  shim_exit_with_error("Unknown opcode " + std::to_string(opcode));
-               }
-            else
-               {
-               size_t got = socket.read(buf.data(), buf.size());
-               if(got == 0)
-                  {
-                  shim_log("EOF on socket");
-                  break;
-                  }
-               chan->received_data(buf.data(), got);
-               }
+            if(need_to_read == 0)
+               need_to_read = 5;
             }
 
          if(args->option_used("expect-total-renegotiations"))
@@ -1559,7 +1475,6 @@ int main(int /*argc*/, char* argv[])
                                     std::to_string(policy.sessions_established() - 1) +
                                     " exp " + std::to_string(exp));
             }
-         shim_log("End of resume loop");
          }
 
       }
diff --git a/src/bogo_shim/config.json b/src/bogo_shim/config.json
index bdac49818..424cd6857 100644
--- a/src/bogo_shim/config.json
+++ b/src/bogo_shim/config.json
@@ -51,15 +51,12 @@
         "*FalseStart*": "Botan doesn't do false start",
         "MaxSendFragment*": "Maximum fragment extension not supported",
         "ExportKeyingMaterial-EmptyContext*": "No support for this",
-
         "Peek-*": "No peek API",
-        "*OldCallback*": "OpenSSL/BoringSSL specific",
 
         "CheckLeafCurve": "Botan ignores this",
 
         "OCSPStapling-Server-*": "Server doesn't support OCSP stapling currently",
-        "UnsolicitedCertificateExtensions-TLS*": "Server doesn't support OCSP stapling currently",
-        "ServerOCSPCallback": "Server doesn't support OCSP stapling currently",
+        "UnsolicitedCertificateExtensions-TLS*":  "Server doesn't support OCSP stapling currently",
 
         "CipherNegotiation-2": "No support for cipher equivalence classes",
         "CipherNegotiation-3": "No support for cipher equivalence classes",
@@ -78,12 +75,9 @@
         "Resume-Client-NoResume-TLS1-TLS11": "BoGo expects resumption attempt sends latest version",
         "Resume-Client-NoResume-TLS1-TLS12": "BoGo expects resumption attempt sends latest version",
         "Resume-Client-NoResume-TLS11-TLS12": "BoGo expects resumption attempt sends latest version",
-        "Resume-Client-NoResume-TLS1-TLS12-DTLS": "BoGo expects resumption attempt sends latest version",
-
         "Resume-Client-Mismatch-TLS1-TLS11": "BoGo expects resumption attempt sends latest version",
         "Resume-Client-Mismatch-TLS1-TLS12": "BoGo expects resumption attempt sends latest version",
         "Resume-Client-Mismatch-TLS11-TLS12": "BoGo expects resumption attempt sends latest version",
-        "Resume-Client-Mismatch-TLS1-TLS12-DTLS": "BoGo expects resumption attempt sends latest version",
 
         "CurveTest-Client-Compressed*": "Point compression is supported, which BoGo doesn't expect",
         "PointFormat-Client-MissingUncompressed": "Point compression is supported, which BoGo doesn't expect",
@@ -99,34 +93,11 @@
         "RSAPSSSupport-ConfigPSS-NoCerts-TLS12-Server": "Not possible to disable PSS",
         "RSAPSSSupport-Default-NoCerts-TLS12-Server": "Not possible to disable PSS",
 
-        "SRTP-Server-IgnoreMKI-*": "Non-empty MKI is rejected",
-        "DTLS-Replay*": "Needs analysis",
-        "DTLS-Retransmit*": "Shim needs timeout support",
-
-        "AppDataAfterChangeCipherSpec-DTLS*": "Needs investigation",
-        "BadChangeCipherSpec-DTLS-*": "Needs investigation",
-        "DTLS-StrayRetransmitFinished-ClientFull": "Needs investigation",
-        "DTLS-StrayRetransmitFinished-ServerResume": "Needs investigation",
-        "DisableEverything-DTLS": "Needs investigation",
-        "LargeCiphertext-DTLS": "Needs investigation",
-        "MajorVersionTolerance-DTLS": "Needs investigation",
-        "MinimumVersion-Client-TLS12-TLS1-DTLS": "Needs investigation",
-        "MinimumVersion-Server-TLS12-TLS1-DTLS": "Needs investigation",
-        "MixCompleteMessageWithFragments-DTLS": "Needs investigation",
-        "NoSupportedVersions-DTLS": "Needs investigation",
-        "ReorderHandshakeFragments-Small-DTLS": "Needs investigation",
-        "SendUnencryptedFinished-DTLS": "Needs investigation",
-        "VersionNegotiation-Client-TLS1-TLS12-DTLS": "Needs investigation",
-        "VersionNegotiation-Server-TLS1-TLS12-DTLS": "Needs investigation",
-        "VersionTooLow-DTLS": "Needs investigation",
-
-        "MTUExceeded": "BoringSSL splits DTLS handshakes differently",
-
-        "ClientOCSPCallback-FailNoStaple-*-DTLS*": "Alert problem",
-        "MinimumVersion-Client2-TLS12-TLS1-DTLS": "Alert problem",
-        "SendBogusAlertType-DTLS": "Alert problem",
-        "TrailingMessageData-*-DTLS*": "Alert problem",
-        "WrongMessageType-*-DTLS*": "Alert problem",
+        "*DTLS*": "Shim is missing DTLS support",
+        "SRTP*":  "Shim is missing DTLS support",
+        "SendSplitAlert*": "Shim is missing DTLS support",
+        "StrayChangeCipherSpec": "Shim is missing DTLS support",
+        "MTU*": "Shim is missing DTLS support",
 
         "Renegotiate-Client-Packed": "Packing HelloRequest with Finished loses the HelloRequest (bug)",
         "SendHalfHelloRequest*PackHandshake": "Packing HelloRequest with Finished loses the HelloRequest (bug)",
diff --git a/src/lib/tls/tls_cbc/tls_cbc.cpp b/src/lib/tls/tls_cbc/tls_cbc.cpp
index e14f2ab86..aa54194a3 100644
--- a/src/lib/tls/tls_cbc/tls_cbc.cpp
+++ b/src/lib/tls/tls_cbc/tls_cbc.cpp
@@ -28,7 +28,7 @@ TLS_CBC_HMAC_AEAD_Mode::TLS_CBC_HMAC_AEAD_Mode(Cipher_Dir dir,
                                                std::unique_ptr<MessageAuthenticationCode> mac,
                                                size_t cipher_keylen,
                                                size_t mac_keylen,
-                                               Protocol_Version version,
+                                               bool use_explicit_iv,
                                                bool use_encrypt_then_mac) :
    m_cipher_name(cipher->name()),
    m_mac_name(mac->name()),
@@ -39,9 +39,7 @@ TLS_CBC_HMAC_AEAD_Mode::TLS_CBC_HMAC_AEAD_Mode(Cipher_Dir dir,
    m_tag_size = mac->output_length();
    m_block_size = cipher->block_size();
 
-   m_iv_size = version.supports_explicit_cbc_ivs() ? m_block_size : 0;
-
-   m_is_datagram = version.is_datagram_protocol();
+   m_iv_size = use_explicit_iv ? m_block_size : 0;
 
    m_mac = std::move(mac);
 
@@ -344,8 +342,8 @@ void TLS_CBC_HMAC_AEAD_Decryption::perform_additional_compressions(size_t plen,
    // If there are no compressions, we just add 55/111 dummy bytes so that no
    // compression is performed.
    const uint16_t data_len = block_size * add_compressions + equal * max_bytes_in_first_block;
-   std::vector<uint8_t> data(data_len);
-   mac().update(data);
+   secure_vector<uint8_t> data(data_len);
+   mac().update(unlock(data));
    // we do not need to clear the MAC since the connection is broken anyway
    }
 
@@ -462,14 +460,6 @@ void TLS_CBC_HMAC_AEAD_Decryption::finish(secure_vector<uint8_t>& buffer, size_t
       else
          {
          perform_additional_compressions(record_len, pad_size);
-
-         /*
-         * In DTLS case we have to finish computing the MAC since we require the
-         * MAC state be reset for future packets. This extra timing channel may
-         * be exploitable in a Lucky13 variant.
-         */
-         if(is_datagram_protocol())
-            mac().final(mac_buf);
          throw TLS_Exception(Alert::BAD_RECORD_MAC, "Message authentication failure");
          }
       }
diff --git a/src/lib/tls/tls_cbc/tls_cbc.h b/src/lib/tls/tls_cbc/tls_cbc.h
index 284a51391..c8a808156 100644
--- a/src/lib/tls/tls_cbc/tls_cbc.h
+++ b/src/lib/tls/tls_cbc/tls_cbc.h
@@ -12,7 +12,6 @@
 #include <botan/aead.h>
 #include <botan/block_cipher.h>
 #include <botan/mac.h>
-#include <botan/tls_version.h>
 
 namespace Botan {
 
@@ -51,7 +50,7 @@ class BOTAN_TEST_API TLS_CBC_HMAC_AEAD_Mode : public AEAD_Mode
                              std::unique_ptr<MessageAuthenticationCode> mac,
                              size_t cipher_keylen,
                              size_t mac_keylen,
-                             Protocol_Version version,
+                             bool use_explicit_iv,
                              bool use_encrypt_then_mac);
 
       size_t cipher_keylen() const { return m_cipher_keylen; }
@@ -61,8 +60,6 @@ class BOTAN_TEST_API TLS_CBC_HMAC_AEAD_Mode : public AEAD_Mode
 
       bool use_encrypt_then_mac() const { return m_use_encrypt_then_mac; }
 
-      bool is_datagram_protocol() const { return m_is_datagram; }
-
       Cipher_Mode& cbc() const { return *m_cbc; }
 
       MessageAuthenticationCode& mac() const
@@ -90,7 +87,6 @@ class BOTAN_TEST_API TLS_CBC_HMAC_AEAD_Mode : public AEAD_Mode
       size_t m_tag_size;
       size_t m_block_size;
       bool m_use_encrypt_then_mac;
-      bool m_is_datagram;
 
       std::unique_ptr<Cipher_Mode> m_cbc;
       std::unique_ptr<MessageAuthenticationCode> m_mac;
@@ -113,14 +109,14 @@ class BOTAN_TEST_API TLS_CBC_HMAC_AEAD_Encryption final : public TLS_CBC_HMAC_AE
                              std::unique_ptr<MessageAuthenticationCode> mac,
                              const size_t cipher_keylen,
                              const size_t mac_keylen,
-                             const Protocol_Version version,
+                             bool use_explicit_iv,
                              bool use_encrypt_then_mac) :
          TLS_CBC_HMAC_AEAD_Mode(ENCRYPTION,
                                 std::move(cipher),
                                 std::move(mac),
                                 cipher_keylen,
                                 mac_keylen,
-                                version,
+                                use_explicit_iv,
                                 use_encrypt_then_mac)
          {}
 
@@ -147,14 +143,14 @@ class BOTAN_TEST_API TLS_CBC_HMAC_AEAD_Decryption final : public TLS_CBC_HMAC_AE
                                    std::unique_ptr<MessageAuthenticationCode> mac,
                                    const size_t cipher_keylen,
                                    const size_t mac_keylen,
-                                   const Protocol_Version version,
+                                   bool use_explicit_iv,
                                    bool use_encrypt_then_mac) :
          TLS_CBC_HMAC_AEAD_Mode(DECRYPTION,
                                 std::move(cipher),
                                 std::move(mac),
                                 cipher_keylen,
                                 mac_keylen,
-                                version,
+                                use_explicit_iv,
                                 use_encrypt_then_mac)
          {}
 
diff --git a/src/lib/tls/tls_handshake_io.cpp b/src/lib/tls/tls_handshake_io.cpp
index afab1dd20..47a9ad6d2 100644
--- a/src/lib/tls/tls_handshake_io.cpp
+++ b/src/lib/tls/tls_handshake_io.cpp
@@ -39,6 +39,18 @@ uint64_t steady_clock_ms()
       std::chrono::steady_clock::now().time_since_epoch()).count();
    }
 
+size_t split_for_mtu(size_t mtu, size_t msg_size)
+   {
+   const size_t DTLS_HEADERS_SIZE = 25; // DTLS record+handshake headers
+
+   const size_t parts = (msg_size + mtu) / mtu;
+
+   if(parts + DTLS_HEADERS_SIZE > mtu)
+      return parts + 1;
+
+   return parts;
+   }
+
 }
 
 Protocol_Version Stream_Handshake_IO::initial_record_version() const
@@ -413,15 +425,17 @@ std::vector<uint8_t> Datagram_Handshake_IO::send_message(uint16_t msg_seq,
       }
    else
       {
-      size_t frag_offset = 0;
+      const size_t parts = split_for_mtu(m_mtu, msg_bits.size());
 
-      const size_t DTLS_HANDSHAKE_HEADERS = 32;
-      const size_t ciphersuite_overhead = (epoch > 0) ? 32 : 0;
-      const size_t max_rec_size = m_mtu - DTLS_HANDSHAKE_HEADERS - ciphersuite_overhead;
+      const size_t parts_size = (msg_bits.size() + parts) / parts;
+
+      size_t frag_offset = 0;
 
       while(frag_offset != msg_bits.size())
          {
-         const size_t frag_len = std::min<size_t>(msg_bits.size() - frag_offset, max_rec_size);
+         const size_t frag_len =
+            std::min<size_t>(msg_bits.size() - frag_offset,
+                             parts_size);
 
          m_send_hs(epoch,
                    HANDSHAKE,
diff --git a/src/lib/tls/tls_record.cpp b/src/lib/tls/tls_record.cpp
index a07efd306..ae807fcdc 100644
--- a/src/lib/tls/tls_record.cpp
+++ b/src/lib/tls/tls_record.cpp
@@ -67,7 +67,7 @@ Connection_Cipher_State::Connection_Cipher_State(Protocol_Version version,
                          std::move(mac),
                          suite.cipher_keylen(),
                          suite.mac_keylen(),
-                         version,
+                         version.supports_explicit_cbc_ivs(),
                          uses_encrypt_then_mac));
          }
       else
@@ -77,7 +77,7 @@ Connection_Cipher_State::Connection_Cipher_State(Protocol_Version version,
                          std::move(mac),
                          suite.cipher_keylen(),
                          suite.mac_keylen(),
-                         version,
+                         version.supports_explicit_cbc_ivs(),
                          uses_encrypt_then_mac));
          }
 
diff --git a/src/lib/utils/boost/info.txt b/src/lib/utils/boost/info.txt
index 69df031be..6330cbafd 100644
--- a/src/lib/utils/boost/info.txt
+++ b/src/lib/utils/boost/info.txt
@@ -5,6 +5,5 @@ BOOST_ASIO -> 20131228
 load_on vendor
 
 <libs>
-all!windows -> boost_system
-windows -> boost_system.lib
+all -> boost_system
 </libs>
diff --git a/src/scripts/ci/appveyor.yml b/src/scripts/ci/appveyor.yml
index 3988522ca..bc9a65d08 100644
--- a/src/scripts/ci/appveyor.yml
+++ b/src/scripts/ci/appveyor.yml
@@ -14,30 +14,45 @@ environment:
       PLATFORM: x86
       TARGET: shared
       APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015
+      BOOST_ROOT: "C:\\Libraries\\boost_1_69_0"
+      BOOST_LIBRARYDIR: "C:\\Libraries\\boost_1_69_0\\lib32-msvc-14.0"
+      BOOST_SYSTEM_LIBRARY: "libboost_system-vc140-mt-x32-1_69.lib"
 
     # MSVC 2015 DLL x86-64
     - MSVS: 2015
       PLATFORM: x86_amd64
       TARGET: shared
       APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015
+      BOOST_ROOT: "C:\\Libraries\\boost_1_69_0"
+      BOOST_LIBRARYDIR: "C:\\Libraries\\boost_1_69_0\\lib64-msvc-14.0"
+      BOOST_SYSTEM_LIBRARY: "libboost_system-vc140-mt-x64-1_69.lib"
 
     # MSVC 2017 DLL x86-32
     - MSVS: 2017
       PLATFORM: x86
       TARGET: shared
       APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
+      BOOST_ROOT: "C:\\Libraries\\boost_1_69_0"
+      BOOST_LIBRARYDIR: "C:\\Libraries\\boost_1_69_0\\lib32-msvc-14.1"
+      BOOST_SYSTEM_LIBRARY: "libboost_system-vc141-mt-x32-1_69.lib"
 
     # MSVC 2017 DLL x86-64
     - MSVS: 2017
       PLATFORM: x86_amd64
       TARGET: shared
       APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
+      BOOST_ROOT: "C:\\Libraries\\boost_1_69_0"
+      BOOST_LIBRARYDIR: "C:\\Libraries\\boost_1_69_0\\lib64-msvc-14.1"
+      BOOST_SYSTEM_LIBRARY: "libboost_system-vc141-mt-x64-1_69.lib"
 
     # MSVC 2017 static x86-64
     - MSVS: 2017
       PLATFORM: x86_amd64
       TARGET: static
       APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
+      BOOST_ROOT: "C:\\Libraries\\boost_1_69_0"
+      BOOST_LIBRARYDIR: "C:\\Libraries\\boost_1_69_0\\lib64-msvc-14.1"
+      BOOST_SYSTEM_LIBRARY: "libboost_system-vc141-mt-x64-1_69.lib"
 
     # MSVC 2019 x86-64 w/debug iterators
     - MSVS: 2019
diff --git a/src/scripts/ci_build.py b/src/scripts/ci_build.py
index 257cc8827..e00b219f6 100755
--- a/src/scripts/ci_build.py
+++ b/src/scripts/ci_build.py
@@ -202,6 +202,16 @@ def determine_flags(target, target_os, target_cpu, target_cc, cc_bin, ccache, ro
         if target_os == 'osx' or target == 'coverage':
             flags += ['--with-boost']
 
+        if target_os == 'windows' and target in ['shared', 'static']:
+            # ./configure.py needs extra hand-holding for boost on windows
+            boost_root = os.environ['BOOST_ROOT']
+            boost_libs = os.environ['BOOST_LIBRARYDIR']
+            boost_system = os.environ['BOOST_SYSTEM_LIBRARY']
+            flags += ['--with-boost',
+                      '--with-external-includedir', boost_root,
+                      '--with-external-libdir', boost_libs,
+                      '--boost-library-name', boost_system]
+
         if target_os == 'linux':
             flags += ['--with-lzma']
 


Test patch:
diff --git a/src/cli/timing_tests.cpp b/src/cli/timing_tests.cpp
index 577196c4d..3f5152ec1 100644
--- a/src/cli/timing_tests.cpp
+++ b/src/cli/timing_tests.cpp
@@ -209,7 +209,7 @@ class Lucky13_Timing_Test final : public Timing_Test
          , m_mac_keylen(mac_keylen)
          , m_dec(Botan::BlockCipher::create_or_throw("AES-128"),
                  Botan::MessageAuthenticationCode::create_or_throw("HMAC(" + m_mac_algo + ")"),
-                 16, m_mac_keylen, Botan::TLS::Protocol_Version::TLS_V11, false) {}
+                 16, m_mac_keylen, true, false) {}
 
       std::vector<uint8_t> prepare_input(std::string input) override;
       ticks measure_critical_function(std::vector<uint8_t> input) override;
diff --git a/src/tests/test_tls.cpp b/src/tests/test_tls.cpp
index 0798fc120..9b734bdea 100644
--- a/src/tests/test_tls.cpp
+++ b/src/tests/test_tls.cpp
@@ -170,12 +170,13 @@ class TLS_CBC_Tests final : public Text_Based_Test
          const bool is_valid = vars.get_req_sz("Valid") == 1;
 
          // todo test permutations
+         bool explicit_iv = true;
          bool encrypt_then_mac = false;
 
          Botan::TLS::TLS_CBC_HMAC_AEAD_Decryption tls_cbc(
             std::unique_ptr<Botan::BlockCipher>(new Noop_Block_Cipher(block_size)),
             std::unique_ptr<Botan::MessageAuthenticationCode>(new ZeroMac(mac_len)),
-            0, 0, Botan::TLS::Protocol_Version::TLS_V11, encrypt_then_mac);
+            0, 0, explicit_iv, encrypt_then_mac);
 
          tls_cbc.set_key(std::vector<uint8_t>(0));
          std::vector<uint8_t> ad(13);