Index: Makefile
===================================================================
--- Makefile (nonexistent)
+++ Makefile (revision 5)
@@ -0,0 +1,56 @@
+
+COMPONENT_TARGETS = $(HARDWARE_NOARCH)
+
+
+include ../../../../build-system/constants.mk
+
+
+url = $(DOWNLOAD_SERVER)/sources/packages/l/botan
+
+versions = 2.19.3
+pkgname = Botan
+suffix = tar.xz
+
+tarballs = $(addsuffix .$(suffix), $(addprefix $(pkgname)-, $(versions)))
+sha1s = $(addsuffix .sha1sum, $(tarballs))
+
+patches = $(CURDIR)/patches/Botan-2.19.3-boost-bind.patch
+
+.NOTPARALLEL: $(patches)
+
+
+BUILD_TARGETS = $(tarballs) $(sha1s) $(patches)
+
+
+include ../../../../build-system/core.mk
+
+
+.PHONY: download_clean
+
+
+$(tarballs):
+ @echo -e "\n======= Downloading source tarballs =======\n" ; \
+ for tarball in $(tarballs) ; do \
+ echo "$(url)/$$tarball" | xargs -n 1 -P 100 wget $(WGET_OPTIONS) - & \
+ done ; wait
+
+$(sha1s): $(tarballs)
+ @for sha in $@ ; do \
+ echo -e "\n======= Downloading '$$sha' signature =======\n" ; \
+ echo "$(url)/$$sha" | xargs -n 1 -P 100 wget $(WGET_OPTIONS) - & wait %1 ; \
+ touch $$sha ; \
+ echo -e "\n======= Check the '$$sha' sha1sum =======\n" ; \
+ sha1sum --check $$sha ; ret="$$?" ; \
+ if [ "$$ret" == "1" ]; then \
+ echo -e "\n======= ERROR: Bad '$$sha' sha1sum =======\n" ; \
+ exit 1 ; \
+ fi ; \
+ done
+
+$(patches): $(sha1s)
+ @echo -e "\n======= Create Patches =======\n" ; \
+ ( cd create-2.19.3-boost-bind-patch ; ./create.patch.sh ) ; \
+ echo -e "\n"
+
+download_clean:
+ @rm -f $(tarballs) $(sha1s) $(patches)
Index: create-2.19.3-boost-bind-patch/Botan-2.19.3-new/src/cli/tls_http_server.cpp
===================================================================
--- create-2.19.3-boost-bind-patch/Botan-2.19.3-new/src/cli/tls_http_server.cpp (nonexistent)
+++ create-2.19.3-boost-bind-patch/Botan-2.19.3-new/src/cli/tls_http_server.cpp (revision 5)
@@ -0,0 +1,579 @@
+/*
+* (C) 2014,2015,2017,2019 Jack Lloyd
+* (C) 2016 Matthias Gierlings
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#include "cli.h"
+
+#if defined(BOTAN_HAS_TLS) && defined(BOTAN_HAS_BOOST_ASIO) && defined(BOTAN_TARGET_OS_HAS_FILESYSTEM)
+
+#include <iostream>
+#include <fstream>
+#include <iomanip>
+#include <string>
+#include <vector>
+#include <thread>
+#include <atomic>
+
+#define _GLIBCXX_HAVE_GTHR_DEFAULT
+#include <boost/asio.hpp>
+#include <boost/bind/bind.hpp>
+#include <botan/internal/os_utils.h>
+
+#include <botan/tls_server.h>
+#include <botan/tls_messages.h>
+#include <botan/x509cert.h>
+#include <botan/pkcs8.h>
+#include <botan/version.h>
+#include <botan/hex.h>
+#include <botan/rng.h>
+
+#if defined(BOTAN_HAS_TLS_SQLITE3_SESSION_MANAGER)
+ #include <botan/tls_session_manager_sqlite.h>
+#endif
+
+#include "tls_helpers.h"
+
+#if BOOST_VERSION >= 107000
+#define GET_IO_SERVICE(s) (static_cast<boost::asio::io_context&>((s).get_executor().context()))
+#else
+#define GET_IO_SERVICE(s) ((s).get_io_service())
+#endif
+
+namespace Botan_CLI {
+
+namespace {
+
+using boost::asio::ip::tcp;
+
+inline void log_exception(const char* where, const std::exception& e)
+ {
+ std::cout << where << ' ' << e.what() << std::endl;
+ }
+
+class ServerStatus
+ {
+ public:
+ ServerStatus(size_t max_clients) : m_max_clients(max_clients), m_clients_serviced(0) {}
+
+ bool should_exit() const
+ {
+ if(m_max_clients == 0)
+ return false;
+
+ return clients_serviced() >= m_max_clients;
+ }
+
+ void client_serviced() { m_clients_serviced++; }
+
+ size_t clients_serviced() const { return m_clients_serviced.load(); }
+ private:
+ size_t m_max_clients;
+ std::atomic<size_t> m_clients_serviced;
+ };
+
+/*
+* This is an incomplete and highly buggy HTTP request parser. It is just
+* barely sufficient to handle a GET request sent by a browser.
+*/
+class HTTP_Parser final
+ {
+ public:
+ class Request
+ {
+ public:
+ const std::string& verb() const { return m_verb; }
+ const std::string& location() const { return m_location; }
+ const std::map<std::string, std::string>& headers() const { return m_headers; }
+
+ Request(const std::string& verb,
+ const std::string& location,
+ const std::map<std::string, std::string>& headers) :
+ m_verb(verb),
+ m_location(location),
+ m_headers(headers)
+ {}
+
+ private:
+ std::string m_verb;
+ std::string m_location;
+ std::map<std::string, std::string> m_headers;
+ };
+
+ class Callbacks
+ {
+ public:
+ virtual void handle_http_request(const Request& request) = 0;
+ virtual ~Callbacks() = default;
+ };
+
+ HTTP_Parser(Callbacks& cb) : m_cb(cb) {}
+
+ void consume_input(const uint8_t buf[], size_t buf_len)
+ {
+ m_req_buf.append(reinterpret_cast<const char*>(buf), buf_len);
+
+ std::istringstream strm(m_req_buf);
+
+ std::string http_version;
+ std::string verb;
+ std::string location;
+ std::map<std::string, std::string> headers;
+
+ strm >> verb >> location >> http_version;
+
+ if(verb.empty() || location.empty())
+ return;
+
+ while(true)
+ {
+ std::string header_line;
+ std::getline(strm, header_line);
+
+ if(header_line == "\r")
+ {
+ continue;
+ }
+
+ auto delim = header_line.find(": ");
+ if(delim == std::string::npos)
+ {
+ break;
+ }
+
+ const std::string hdr_name = header_line.substr(0, delim);
+ const std::string hdr_val = header_line.substr(delim + 2, std::string::npos);
+
+ headers[hdr_name] = hdr_val;
+
+ if(headers.size() > 1024)
+ throw Botan::Invalid_Argument("Too many HTTP headers sent in request");
+ }
+
+ if(verb != "" && location != "")
+ {
+ Request req(verb, location, headers);
+ m_cb.handle_http_request(req);
+ m_req_buf.clear();
+ }
+ else
+ printf("ignoring\n");
+ }
+ private:
+ Callbacks& m_cb;
+ std::string m_req_buf;
+ };
+
+static const size_t READBUF_SIZE = 4096;
+
+class TLS_Asio_HTTP_Session final : public std::enable_shared_from_this<TLS_Asio_HTTP_Session>,
+ public Botan::TLS::Callbacks,
+ public HTTP_Parser::Callbacks
+ {
+ public:
+ typedef std::shared_ptr<TLS_Asio_HTTP_Session> pointer;
+
+ static pointer create(
+ boost::asio::io_service& io,
+ Botan::TLS::Session_Manager& session_manager,
+ Botan::Credentials_Manager& credentials,
+ Botan::TLS::Policy& policy)
+ {
+ return pointer(new TLS_Asio_HTTP_Session(io, session_manager, credentials, policy));
+ }
+
+ tcp::socket& client_socket()
+ {
+ return m_client_socket;
+ }
+
+ void start()
+ {
+ m_c2s.resize(READBUF_SIZE);
+ client_read(boost::system::error_code(), 0); // start read loop
+ }
+
+ void stop()
+ {
+ m_tls.close();
+ }
+
+ private:
+ TLS_Asio_HTTP_Session(boost::asio::io_service& io,
+ Botan::TLS::Session_Manager& session_manager,
+ Botan::Credentials_Manager& credentials,
+ Botan::TLS::Policy& policy)
+ : m_strand(io)
+ , m_client_socket(io)
+ , m_rng(cli_make_rng())
+ , m_tls(*this, session_manager, credentials, policy, *m_rng) {}
+
+ void client_read(const boost::system::error_code& error,
+ size_t bytes_transferred)
+ {
+ if(error)
+ {
+ return stop();
+ }
+
+ try
+ {
+ m_tls.received_data(&m_c2s[0], bytes_transferred);
+ }
+ catch(Botan::Exception& e)
+ {
+ log_exception("TLS connection failed", e);
+ return stop();
+ }
+
+ m_client_socket.async_read_some(
+ boost::asio::buffer(&m_c2s[0], m_c2s.size()),
+ m_strand.wrap(
+ boost::bind(
+ &TLS_Asio_HTTP_Session::client_read, shared_from_this(),
+ boost::asio::placeholders::error,
+ boost::asio::placeholders::bytes_transferred)));
+ }
+
+ void handle_client_write_completion(const boost::system::error_code& error)
+ {
+ if(error)
+ {
+ return stop();
+ }
+
+ m_s2c.clear();
+
+ if(m_s2c_pending.empty() && m_tls.is_closed())
+ {
+ m_client_socket.close();
+ }
+ tls_emit_data(nullptr, 0); // initiate another write if needed
+ }
+
+ std::string tls_server_choose_app_protocol(const std::vector<std::string>& /*client_protos*/) override
+ {
+ return "http/1.1";
+ }
+
+ void tls_record_received(uint64_t /*rec_no*/, const uint8_t buf[], size_t buf_len) override
+ {
+ if(!m_http_parser)
+ m_http_parser.reset(new HTTP_Parser(*this));
+
+ m_http_parser->consume_input(buf, buf_len);
+ }
+
+ std::string summarize_request(const HTTP_Parser::Request& request)
+ {
+ std::ostringstream strm;
+
+ strm << "Client " << client_socket().remote_endpoint().address().to_string()
+ << " requested " << request.verb() << " " << request.location() << "\n";
+
+ if(request.headers().empty() == false)
+ {
+ strm << "Client HTTP headers:\n";
+ for(auto kv : request.headers())
+ strm << " " << kv.first << ": " << kv.second << "\n";
+ }
+
+ return strm.str();
+ }
+
+ void handle_http_request(const HTTP_Parser::Request& request) override
+ {
+ std::ostringstream response;
+ if(request.verb() == "GET")
+ {
+ if(request.location() == "/" || request.location() == "/status")
+ {
+ const std::string http_summary = summarize_request(request);
+
+ const std::string report = m_session_summary + m_chello_summary + http_summary;
+
+ response << "HTTP/1.0 200 OK\r\n";
+ response << "Server: " << Botan::version_string() << "\r\n";
+ response << "Content-Type: text/plain\r\n";
+ response << "Content-Length: " << report.size() << "\r\n";
+ response << "\r\n";
+
+ response << report;
+ }
+ else
+ {
+ response << "HTTP/1.0 404 Not Found\r\n\r\n";
+ }
+ }
+ else
+ {
+ response << "HTTP/1.0 405 Method Not Allowed\r\n\r\n";
+ }
+
+ const std::string response_str = response.str();
+ m_tls.send(response_str);
+ m_tls.close();
+ }
+
+ void tls_emit_data(const uint8_t buf[], size_t buf_len) override
+ {
+ if(buf_len > 0)
+ {
+ m_s2c_pending.insert(m_s2c_pending.end(), buf, buf + buf_len);
+ }
+
+ // no write now active and we still have output pending
+ if(m_s2c.empty() && !m_s2c_pending.empty())
+ {
+ std::swap(m_s2c_pending, m_s2c);
+
+ boost::asio::async_write(
+ m_client_socket,
+ boost::asio::buffer(&m_s2c[0], m_s2c.size()),
+ m_strand.wrap(
+ boost::bind(
+ &TLS_Asio_HTTP_Session::handle_client_write_completion,
+ shared_from_this(),
+ boost::asio::placeholders::error)));
+ }
+ }
+
+ bool tls_session_established(const Botan::TLS::Session& session) override
+ {
+ std::ostringstream strm;
+
+ strm << "TLS negotiation with " << Botan::version_string() << " test server\n\n";
+
+ strm << "Version: " << session.version().to_string() << "\n";
+ strm << "Ciphersuite: " << session.ciphersuite().to_string() << "\n";
+ if(session.session_id().empty() == false)
+ {
+ strm << "SessionID: " << Botan::hex_encode(session.session_id()) << "\n";
+ }
+ if(session.server_info().hostname() != "")
+ {
+ strm << "SNI: " << session.server_info().hostname() << "\n";
+ }
+
+ m_session_summary = strm.str();
+ return true;
+ }
+
+ void tls_inspect_handshake_msg(const Botan::TLS::Handshake_Message& message) override
+ {
+ if(message.type() == Botan::TLS::CLIENT_HELLO)
+ {
+ const Botan::TLS::Client_Hello& client_hello = dynamic_cast<const Botan::TLS::Client_Hello&>(message);
+
+ std::ostringstream strm;
+
+ strm << "Client random: " << Botan::hex_encode(client_hello.random()) << "\n";
+
+ strm << "Client offered following ciphersuites:\n";
+ for(uint16_t suite_id : client_hello.ciphersuites())
+ {
+ Botan::TLS::Ciphersuite ciphersuite = Botan::TLS::Ciphersuite::by_id(suite_id);
+
+ strm << " - 0x"
+ << std::hex << std::setfill('0') << std::setw(4) << suite_id
+ << std::dec << std::setfill(' ') << std::setw(0) << " ";
+
+ if(ciphersuite.valid())
+ strm << ciphersuite.to_string() << "\n";
+ else if(suite_id == 0x00FF)
+ strm << "Renegotiation SCSV\n";
+ else
+ strm << "Unknown ciphersuite\n";
+ }
+
+ m_chello_summary = strm.str();
+ }
+
+ }
+
+ void tls_alert(Botan::TLS::Alert alert) override
+ {
+ if(alert.type() == Botan::TLS::Alert::CLOSE_NOTIFY)
+ {
+ m_tls.close();
+ return;
+ }
+ else
+ {
+ std::cout << "Alert " << alert.type_string() << std::endl;
+ }
+ }
+
+ boost::asio::io_service::strand m_strand;
+
+ tcp::socket m_client_socket;
+
+ std::unique_ptr<Botan::RandomNumberGenerator> m_rng;
+ Botan::TLS::Server m_tls;
+ std::string m_chello_summary;
+ std::string m_session_summary;
+ std::unique_ptr<HTTP_Parser> m_http_parser;
+
+ std::vector<uint8_t> m_c2s;
+ std::vector<uint8_t> m_s2c;
+ std::vector<uint8_t> m_s2c_pending;
+ };
+
+class TLS_Asio_HTTP_Server final
+ {
+ public:
+ typedef TLS_Asio_HTTP_Session session;
+
+ TLS_Asio_HTTP_Server(
+ boost::asio::io_service& io, unsigned short port,
+ Botan::Credentials_Manager& creds,
+ Botan::TLS::Policy& policy,
+ Botan::TLS::Session_Manager& session_mgr,
+ size_t max_clients)
+ : m_acceptor(io, tcp::endpoint(tcp::v4(), port))
+ , m_creds(creds)
+ , m_policy(policy)
+ , m_session_manager(session_mgr)
+ , m_status(max_clients)
+ {
+ session::pointer new_session = make_session();
+
+ m_acceptor.async_accept(
+ new_session->client_socket(),
+ boost::bind(
+ &TLS_Asio_HTTP_Server::handle_accept,
+ this,
+ new_session,
+ boost::asio::placeholders::error));
+ }
+
+ private:
+ session::pointer make_session()
+ {
+ return session::create(
+ GET_IO_SERVICE(m_acceptor),
+ m_session_manager,
+ m_creds,
+ m_policy);
+ }
+
+ void handle_accept(session::pointer new_session,
+ const boost::system::error_code& error)
+ {
+ if(!error)
+ {
+ new_session->start();
+ new_session = make_session();
+
+ m_status.client_serviced();
+
+ if(m_status.should_exit() == false)
+ {
+ m_acceptor.async_accept(
+ new_session->client_socket(),
+ boost::bind(
+ &TLS_Asio_HTTP_Server::handle_accept,
+ this,
+ new_session,
+ boost::asio::placeholders::error));
+ }
+ }
+ }
+
+ tcp::acceptor m_acceptor;
+
+ Botan::Credentials_Manager& m_creds;
+ Botan::TLS::Policy& m_policy;
+ Botan::TLS::Session_Manager& m_session_manager;
+ ServerStatus m_status;
+ };
+
+}
+
+class TLS_HTTP_Server final : public Command
+ {
+ public:
+ TLS_HTTP_Server() : Command("tls_http_server server_cert server_key "
+ "--port=443 --policy=default --threads=0 --max-clients=0 "
+ "--session-db= --session-db-pass=") {}
+
+ std::string group() const override
+ {
+ return "tls";
+ }
+
+ std::string description() const override
+ {
+ return "Provides a simple HTTP server";
+ }
+
+ size_t thread_count() const
+ {
+ if(size_t t = get_arg_sz("threads"))
+ return t;
+ if(size_t t = Botan::OS::get_cpu_available())
+ return t;
+ return 2;
+ }
+
+ void go() override
+ {
+ const uint16_t listen_port = get_arg_u16("port");
+
+ const std::string server_crt = get_arg("server_cert");
+ const std::string server_key = get_arg("server_key");
+
+ const size_t num_threads = thread_count();
+ const size_t max_clients = get_arg_sz("max-clients");
+
+ Basic_Credentials_Manager creds(rng(), server_crt, server_key);
+
+ auto policy = load_tls_policy(get_arg("policy"));
+
+ std::unique_ptr<Botan::TLS::Session_Manager> session_mgr;
+
+ const std::string sessions_db = get_arg("session-db");
+
+ if(!sessions_db.empty())
+ {
+#if defined(BOTAN_HAS_TLS_SQLITE3_SESSION_MANAGER)
+ const std::string sessions_passphrase = get_passphrase_arg("Session DB passphrase", "session-db-pass");
+ session_mgr.reset(new Botan::TLS::Session_Manager_SQLite(sessions_passphrase, rng(), sessions_db));
+#else
+ throw CLI_Error_Unsupported("Sqlite3 support not available");
+#endif
+ }
+
+ if(!session_mgr)
+ {
+ session_mgr.reset(new Botan::TLS::Session_Manager_In_Memory(rng()));
+ }
+
+ boost::asio::io_service io;
+
+ TLS_Asio_HTTP_Server server(io, listen_port, creds, *policy, *session_mgr, max_clients);
+
+ std::vector<std::shared_ptr<std::thread>> threads;
+
+ // run forever... first thread is main calling io.run below
+ for(size_t i = 2; i <= num_threads; ++i)
+ {
+ threads.push_back(std::make_shared<std::thread>([&io]() { io.run(); }));
+ }
+
+ io.run();
+
+ for(size_t i = 0; i < threads.size(); ++i)
+ {
+ threads[i]->join();
+ }
+ }
+ };
+
+BOTAN_REGISTER_COMMAND("tls_http_server", TLS_HTTP_Server);
+
+}
+
+#endif
Index: create-2.19.3-boost-bind-patch/Botan-2.19.3-new/src/cli/tls_proxy.cpp
===================================================================
--- create-2.19.3-boost-bind-patch/Botan-2.19.3-new/src/cli/tls_proxy.cpp (nonexistent)
+++ create-2.19.3-boost-bind-patch/Botan-2.19.3-new/src/cli/tls_proxy.cpp (revision 5)
@@ -0,0 +1,526 @@
+/*
+* TLS Server Proxy
+* (C) 2014,2015,2019 Jack Lloyd
+* (C) 2016 Matthias Gierlings
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#include "cli.h"
+
+#if defined(BOTAN_HAS_TLS) && defined(BOTAN_HAS_BOOST_ASIO) && defined(BOTAN_TARGET_OS_HAS_FILESYSTEM)
+
+#include <iostream>
+#include <string>
+#include <vector>
+#include <thread>
+#include <atomic>
+
+#define _GLIBCXX_HAVE_GTHR_DEFAULT
+#include <boost/asio.hpp>
+#include <boost/bind/bind.hpp>
+#include <botan/internal/os_utils.h>
+
+#include <botan/tls_server.h>
+#include <botan/x509cert.h>
+#include <botan/pkcs8.h>
+#include <botan/hex.h>
+#include <botan/rng.h>
+
+#if defined(BOTAN_HAS_TLS_SQLITE3_SESSION_MANAGER)
+ #include <botan/tls_session_manager_sqlite.h>
+#endif
+
+#include "tls_helpers.h"
+
+#if BOOST_VERSION >= 107000
+#define GET_IO_SERVICE(s) (static_cast<boost::asio::io_context&>((s).get_executor().context()))
+#else
+#define GET_IO_SERVICE(s) ((s).get_io_service())
+#endif
+
+namespace Botan_CLI {
+
+namespace {
+
+using boost::asio::ip::tcp;
+
+void log_exception(const char* where, const std::exception& e)
+ {
+ std::cout << where << ' ' << e.what() << std::endl;
+ }
+
+void log_error(const char* where, const boost::system::error_code& error)
+ {
+ std::cout << where << ' ' << error.message() << std::endl;
+ }
+
+void log_binary_message(const char* where, const uint8_t buf[], size_t buf_len)
+ {
+ BOTAN_UNUSED(where, buf, buf_len);
+ //std::cout << where << ' ' << Botan::hex_encode(buf, buf_len) << std::endl;
+ }
+
+void log_text_message(const char* where, const uint8_t buf[], size_t buf_len)
+ {
+ BOTAN_UNUSED(where, buf, buf_len);
+ //const char* c = reinterpret_cast<const char*>(buf);
+ //std::cout << where << ' ' << std::string(c, c + buf_len) << std::endl;
+ }
+
+class ServerStatus
+ {
+ public:
+ ServerStatus(size_t max_clients) : m_max_clients(max_clients), m_clients_serviced(0) {}
+
+ bool should_exit() const
+ {
+ if(m_max_clients == 0)
+ return false;
+
+ return clients_serviced() >= m_max_clients;
+ }
+
+ void client_serviced() { m_clients_serviced++; }
+
+ size_t clients_serviced() const { return m_clients_serviced.load(); }
+ private:
+ size_t m_max_clients;
+ std::atomic<size_t> m_clients_serviced;
+ };
+
+class tls_proxy_session final : public std::enable_shared_from_this<tls_proxy_session>,
+ public Botan::TLS::Callbacks
+ {
+ public:
+ enum { readbuf_size = 17 * 1024 };
+
+ typedef std::shared_ptr<tls_proxy_session> pointer;
+
+ static pointer create(
+ boost::asio::io_service& io,
+ Botan::TLS::Session_Manager& session_manager,
+ Botan::Credentials_Manager& credentials,
+ Botan::TLS::Policy& policy,
+ tcp::resolver::iterator endpoints)
+ {
+ return pointer(
+ new tls_proxy_session(
+ io,
+ session_manager,
+ credentials,
+ policy,
+ endpoints)
+ );
+ }
+
+ tcp::socket& client_socket()
+ {
+ return m_client_socket;
+ }
+
+ void start()
+ {
+ m_c2p.resize(readbuf_size);
+ client_read(boost::system::error_code(), 0); // start read loop
+ }
+
+ void stop()
+ {
+ if(m_is_closed == false)
+ {
+ /*
+ Don't need to talk to the server anymore
+ Client socket is closed during write callback
+ */
+ m_server_socket.close();
+ m_tls.close();
+ m_is_closed = true;
+ }
+ }
+
+ private:
+ tls_proxy_session(
+ boost::asio::io_service& io,
+ Botan::TLS::Session_Manager& session_manager,
+ Botan::Credentials_Manager& credentials,
+ Botan::TLS::Policy& policy,
+ tcp::resolver::iterator endpoints)
+ : m_strand(io)
+ , m_server_endpoints(endpoints)
+ , m_client_socket(io)
+ , m_server_socket(io)
+ , m_rng(cli_make_rng())
+ , m_tls(*this,
+ session_manager,
+ credentials,
+ policy,
+ *m_rng) {}
+
+ void client_read(const boost::system::error_code& error,
+ size_t bytes_transferred)
+ {
+ if(error)
+ {
+ log_error("Read failed", error);
+ stop();
+ return;
+ }
+
+ try
+ {
+ if(!m_tls.is_active())
+ {
+ log_binary_message("From client", &m_c2p[0], bytes_transferred);
+ }
+ m_tls.received_data(&m_c2p[0], bytes_transferred);
+ }
+ catch(Botan::Exception& e)
+ {
+ log_exception("TLS connection failed", e);
+ stop();
+ return;
+ }
+
+ m_client_socket.async_read_some(
+ boost::asio::buffer(&m_c2p[0], m_c2p.size()),
+ m_strand.wrap(
+ boost::bind(
+ &tls_proxy_session::client_read, shared_from_this(),
+ boost::asio::placeholders::error,
+ boost::asio::placeholders::bytes_transferred)));
+ }
+
+ void handle_client_write_completion(const boost::system::error_code& error)
+ {
+ if(error)
+ {
+ log_error("Client write", error);
+ stop();
+ return;
+ }
+
+ m_p2c.clear();
+
+ if(m_p2c_pending.empty() && m_tls.is_closed())
+ {
+ m_client_socket.close();
+ }
+ tls_emit_data(nullptr, 0); // initiate another write if needed
+ }
+
+ void handle_server_write_completion(const boost::system::error_code& error)
+ {
+ if(error)
+ {
+ log_error("Server write", error);
+ stop();
+ return;
+ }
+
+ m_p2s.clear();
+ proxy_write_to_server(nullptr, 0); // initiate another write if needed
+ }
+
+ void tls_record_received(uint64_t /*rec_no*/, const uint8_t buf[], size_t buf_len) override
+ {
+ // Immediately bounce message to server
+ proxy_write_to_server(buf, buf_len);
+ }
+
+ void tls_emit_data(const uint8_t buf[], size_t buf_len) override
+ {
+ if(buf_len > 0)
+ {
+ m_p2c_pending.insert(m_p2c_pending.end(), buf, buf + buf_len);
+ }
+
+ // no write now active and we still have output pending
+ if(m_p2c.empty() && !m_p2c_pending.empty())
+ {
+ std::swap(m_p2c_pending, m_p2c);
+
+ log_binary_message("To Client", &m_p2c[0], m_p2c.size());
+
+ boost::asio::async_write(
+ m_client_socket,
+ boost::asio::buffer(&m_p2c[0], m_p2c.size()),
+ m_strand.wrap(
+ boost::bind(
+ &tls_proxy_session::handle_client_write_completion,
+ shared_from_this(),
+ boost::asio::placeholders::error)));
+ }
+ }
+
+ void proxy_write_to_server(const uint8_t buf[], size_t buf_len)
+ {
+ if(buf_len > 0)
+ {
+ m_p2s_pending.insert(m_p2s_pending.end(), buf, buf + buf_len);
+ }
+
+ // no write now active and we still have output pending
+ if(m_p2s.empty() && !m_p2s_pending.empty())
+ {
+ std::swap(m_p2s_pending, m_p2s);
+
+ log_text_message("To Server", &m_p2s[0], m_p2s.size());
+
+ boost::asio::async_write(
+ m_server_socket,
+ boost::asio::buffer(&m_p2s[0], m_p2s.size()),
+ m_strand.wrap(
+ boost::bind(
+ &tls_proxy_session::handle_server_write_completion,
+ shared_from_this(),
+ boost::asio::placeholders::error)));
+ }
+ }
+
+ void server_read(const boost::system::error_code& error,
+ size_t bytes_transferred)
+ {
+ if(error)
+ {
+ log_error("Server read failed", error);
+ stop();
+ return;
+ }
+
+ try
+ {
+ if(bytes_transferred)
+ {
+ log_text_message("Server to client", &m_s2p[0], m_s2p.size());
+ log_binary_message("Server to client", &m_s2p[0], m_s2p.size());
+ m_tls.send(&m_s2p[0], bytes_transferred);
+ }
+ }
+ catch(Botan::Exception& e)
+ {
+ log_exception("TLS connection failed", e);
+ stop();
+ return;
+ }
+
+ m_s2p.resize(readbuf_size);
+
+ m_server_socket.async_read_some(
+ boost::asio::buffer(&m_s2p[0], m_s2p.size()),
+ m_strand.wrap(
+ boost::bind(&tls_proxy_session::server_read, shared_from_this(),
+ boost::asio::placeholders::error,
+ boost::asio::placeholders::bytes_transferred)));
+ }
+
+ bool tls_session_established(const Botan::TLS::Session& session) override
+ {
+ m_hostname = session.server_info().hostname();
+
+ auto onConnect = [this](boost::system::error_code ec, tcp::resolver::iterator /*endpoint*/)
+ {
+ if(ec)
+ {
+ log_error("Server connection", ec);
+ return;
+ }
+ server_read(boost::system::error_code(), 0); // start read loop
+ proxy_write_to_server(nullptr, 0);
+ };
+ async_connect(m_server_socket, m_server_endpoints, onConnect);
+ return true;
+ }
+
+ void tls_alert(Botan::TLS::Alert alert) override
+ {
+ if(alert.type() == Botan::TLS::Alert::CLOSE_NOTIFY)
+ {
+ m_tls.close();
+ return;
+ }
+ }
+
+ boost::asio::io_service::strand m_strand;
+
+ tcp::resolver::iterator m_server_endpoints;
+
+ tcp::socket m_client_socket;
+ tcp::socket m_server_socket;
+
+ std::unique_ptr<Botan::RandomNumberGenerator> m_rng;
+ Botan::TLS::Server m_tls;
+ std::string m_hostname;
+
+ std::vector<uint8_t> m_c2p;
+ std::vector<uint8_t> m_p2c;
+ std::vector<uint8_t> m_p2c_pending;
+
+ std::vector<uint8_t> m_s2p;
+ std::vector<uint8_t> m_p2s;
+ std::vector<uint8_t> m_p2s_pending;
+
+ bool m_is_closed = false;
+ };
+
+class tls_proxy_server final
+ {
+ public:
+ typedef tls_proxy_session session;
+
+ tls_proxy_server(
+ boost::asio::io_service& io, unsigned short port,
+ tcp::resolver::iterator endpoints,
+ Botan::Credentials_Manager& creds,
+ Botan::TLS::Policy& policy,
+ Botan::TLS::Session_Manager& session_mgr,
+ size_t max_clients)
+ : m_acceptor(io, tcp::endpoint(tcp::v4(), port))
+ , m_server_endpoints(endpoints)
+ , m_creds(creds)
+ , m_policy(policy)
+ , m_session_manager(session_mgr)
+ , m_status(max_clients)
+ {
+ session::pointer new_session = make_session();
+
+ m_acceptor.async_accept(
+ new_session->client_socket(),
+ boost::bind(
+ &tls_proxy_server::handle_accept,
+ this,
+ new_session,
+ boost::asio::placeholders::error));
+ }
+
+ private:
+ session::pointer make_session()
+ {
+ return session::create(
+ GET_IO_SERVICE(m_acceptor),
+ m_session_manager,
+ m_creds,
+ m_policy,
+ m_server_endpoints);
+ }
+
+ void handle_accept(session::pointer new_session,
+ const boost::system::error_code& error)
+ {
+ if(!error)
+ {
+ new_session->start();
+ new_session = make_session();
+
+ m_status.client_serviced();
+
+ if(m_status.should_exit() == false)
+ {
+ m_acceptor.async_accept(
+ new_session->client_socket(),
+ boost::bind(
+ &tls_proxy_server::handle_accept,
+ this,
+ new_session,
+ boost::asio::placeholders::error));
+ }
+ }
+ }
+
+ tcp::acceptor m_acceptor;
+ tcp::resolver::iterator m_server_endpoints;
+
+ Botan::Credentials_Manager& m_creds;
+ Botan::TLS::Policy& m_policy;
+ Botan::TLS::Session_Manager& m_session_manager;
+ ServerStatus m_status;
+ };
+
+}
+
+class TLS_Proxy final : public Command
+ {
+ public:
+ TLS_Proxy() : Command("tls_proxy listen_port target_host target_port server_cert server_key "
+ "--policy=default --threads=0 --max-clients=0 --session-db= --session-db-pass=") {}
+
+ std::string group() const override
+ {
+ return "tls";
+ }
+
+ std::string description() const override
+ {
+ return "Proxies requests between a TLS client and a TLS server";
+ }
+
+ size_t thread_count() const
+ {
+ if(size_t t = get_arg_sz("threads"))
+ return t;
+ if(size_t t = Botan::OS::get_cpu_available())
+ return t;
+ return 2;
+ }
+
+ void go() override
+ {
+ const uint16_t listen_port = get_arg_u16("listen_port");
+ const std::string target = get_arg("target_host");
+ const std::string target_port = get_arg("target_port");
+
+ const std::string server_crt = get_arg("server_cert");
+ const std::string server_key = get_arg("server_key");
+
+ const size_t num_threads = thread_count();
+ const size_t max_clients = get_arg_sz("max-clients");
+
+ Basic_Credentials_Manager creds(rng(), server_crt, server_key);
+
+ auto policy = load_tls_policy(get_arg("policy"));
+
+ boost::asio::io_service io;
+
+ tcp::resolver resolver(io);
+ auto server_endpoint_iterator = resolver.resolve({ target, target_port });
+
+ std::unique_ptr<Botan::TLS::Session_Manager> session_mgr;
+
+#if defined(BOTAN_HAS_TLS_SQLITE3_SESSION_MANAGER)
+ const std::string sessions_passphrase = get_passphrase_arg("Session DB passphrase", "session-db-pass");
+ const std::string sessions_db = get_arg("session-db");
+
+ if(!sessions_db.empty())
+ {
+ session_mgr.reset(new Botan::TLS::Session_Manager_SQLite(sessions_passphrase, rng(), sessions_db));
+ }
+#endif
+ if(!session_mgr)
+ {
+ session_mgr.reset(new Botan::TLS::Session_Manager_In_Memory(rng()));
+ }
+
+ tls_proxy_server server(io, listen_port, server_endpoint_iterator, creds, *policy, *session_mgr, max_clients);
+
+ std::vector<std::shared_ptr<std::thread>> threads;
+
+ // run forever... first thread is main calling io.run below
+ for(size_t i = 2; i <= num_threads; ++i)
+ {
+ threads.push_back(std::make_shared<std::thread>([&io]() { io.run(); }));
+ }
+
+ io.run();
+
+ for(size_t i = 0; i < threads.size(); ++i)
+ {
+ threads[i]->join();
+ }
+ }
+ };
+
+BOTAN_REGISTER_COMMAND("tls_proxy", TLS_Proxy);
+
+}
+
+#endif
Index: create-2.19.3-boost-bind-patch/Botan-2.19.3-new/src/cli
===================================================================
--- create-2.19.3-boost-bind-patch/Botan-2.19.3-new/src/cli (nonexistent)
+++ create-2.19.3-boost-bind-patch/Botan-2.19.3-new/src/cli (revision 5)
Property changes on: create-2.19.3-boost-bind-patch/Botan-2.19.3-new/src/cli
___________________________________________________________________
Added: svn:ignore
## -0,0 +1,73 ##
+
+# install dir
+dist
+
+# Target build dirs
+.a1x-newlib
+.a2x-newlib
+.at91sam7s-newlib
+
+.build-machine
+
+.a1x-glibc
+.a2x-glibc
+.h3-glibc
+.h5-glibc
+.i586-glibc
+.i686-glibc
+.imx6-glibc
+.jz47xx-glibc
+.makefile
+.am335x-glibc
+.omap543x-glibc
+.p5600-glibc
+.power8-glibc
+.power8le-glibc
+.power9-glibc
+.power9le-glibc
+.m1000-glibc
+.riscv64-glibc
+.rk328x-glibc
+.rk33xx-glibc
+.rk339x-glibc
+.s8xx-glibc
+.s9xx-glibc
+.x86_64-glibc
+
+# Hidden files (each file)
+.makefile
+.dist
+.rootfs
+
+# src & hw requires
+.src_requires
+.src_requires_depend
+.requires
+.requires_depend
+
+# Tarballs
+*.gz
+*.bz2
+*.lz
+*.xz
+*.tgz
+*.txz
+
+# Signatures
+*.asc
+*.sig
+*.sign
+*.sha1sum
+
+# Patches
+*.patch
+
+# Descriptions
+*.dsc
+*.txt
+
+# Default linux config files
+*.defconfig
+
+# backup copies
+*~
Index: create-2.19.3-boost-bind-patch/Botan-2.19.3-new/src/tests/unit_asio_stream.cpp
===================================================================
--- create-2.19.3-boost-bind-patch/Botan-2.19.3-new/src/tests/unit_asio_stream.cpp (nonexistent)
+++ create-2.19.3-boost-bind-patch/Botan-2.19.3-new/src/tests/unit_asio_stream.cpp (revision 5)
@@ -0,0 +1,817 @@
+/*
+* TLS ASIO Stream Unit Tests
+* (C) 2018-2020 Jack Lloyd
+* 2018-2020 Hannes Rantzsch, Tim Oesterreich, Rene Meusel
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#include "tests.h"
+
+#if defined(BOTAN_HAS_TLS) && defined(BOTAN_HAS_TLS_ASIO_STREAM)
+
+#include <botan/asio_stream.h>
+#include <botan/tls_callbacks.h>
+
+// The boost::beast::test::stream we use is available starting from boost
+// version 1.68, so we cannot run these tests with a smaller version.
+#include <boost/version.hpp>
+#if BOOST_VERSION >= 106800
+
+// boost::beast::test::stream's include path has been changed in boost version
+// 1.70.
+#if BOOST_VERSION < 107000
+#include <boost/beast/experimental/test/stream.hpp>
+#else
+#include <boost/beast/_experimental/test/stream.hpp>
+#endif
+
+#include <boost/bind/bind.hpp>
+
+namespace Botan_Tests {
+
+namespace net = boost::asio;
+using error_code = boost::system::error_code;
+
+constexpr uint8_t TEST_DATA[] = "The story so far: In the beginning the Universe was created. "
+ "This has made a lot of people very angry and been widely regarded as a bad move.";
+constexpr std::size_t TEST_DATA_SIZE = 142;
+static_assert(sizeof(TEST_DATA) == TEST_DATA_SIZE, "size of TEST_DATA must match TEST_DATA_SIZE");
+
+/**
+ * Mocked Botan::TLS::Channel. Pretends to perform TLS operations and triggers appropriate callbacks in StreamCore.
+ */
+class MockChannel
+ {
+ public:
+ MockChannel(Botan::TLS::Callbacks& core)
+ : m_callbacks(core)
+ , m_bytes_till_complete_record(TEST_DATA_SIZE)
+ , m_active(false) {}
+
+ public:
+ std::size_t received_data(const uint8_t[], std::size_t buf_size)
+ {
+ if(m_bytes_till_complete_record <= buf_size)
+ {
+ m_callbacks.tls_record_received(0, TEST_DATA, TEST_DATA_SIZE);
+ m_active = true; // claim to be active once a full record has been received (for handshake test)
+ return 0;
+ }
+ m_bytes_till_complete_record -= buf_size;
+ return m_bytes_till_complete_record;
+ }
+
+ void send(const uint8_t buf[], std::size_t buf_size) { m_callbacks.tls_emit_data(buf, buf_size); }
+
+ bool is_active() { return m_active; }
+
+ protected:
+ Botan::TLS::Callbacks& m_callbacks;
+ std::size_t m_bytes_till_complete_record; // number of bytes still to read before tls record is completed
+ bool m_active;
+ };
+
+class ThrowingMockChannel : public MockChannel
+ {
+ public:
+ static boost::system::error_code expected_ec()
+ {
+ return Botan::TLS::Alert::UNEXPECTED_MESSAGE;
+ }
+
+ ThrowingMockChannel(Botan::TLS::Callbacks& core) : MockChannel(core)
+ {
+ }
+
+ std::size_t received_data(const uint8_t[], std::size_t)
+ {
+ throw Botan::TLS::Unexpected_Message("test_error");
+ }
+
+ void send(const uint8_t[], std::size_t)
+ {
+ throw Botan::TLS::Unexpected_Message("test_error");
+ }
+ };
+
+// Unfortunately, boost::beast::test::stream keeps lowest_layer_type private and
+// only friends boost::asio::ssl::stream. We need to make our own.
+class TestStream : public boost::beast::test::stream
+ {
+ public:
+ using boost::beast::test::stream::stream;
+ using lowest_layer_type = boost::beast::test::stream;
+ };
+
+using FailCount = boost::beast::test::fail_count;
+
+class AsioStream : public Botan::TLS::Stream<TestStream, MockChannel>
+ {
+ public:
+ template <typename... Args>
+ AsioStream(Botan::TLS::Context& context, Args&& ... args)
+ : Stream(context, args...)
+ {
+ m_native_handle = std::unique_ptr<MockChannel>(new MockChannel(m_core));
+ }
+
+ virtual ~AsioStream() = default;
+ };
+
+class ThrowingAsioStream : public Botan::TLS::Stream<TestStream, ThrowingMockChannel>
+ {
+ public:
+ template <typename... Args>
+ ThrowingAsioStream(Botan::TLS::Context& context, Args&& ... args)
+ : Stream(context, args...)
+ {
+ m_native_handle = std::unique_ptr<ThrowingMockChannel>(new ThrowingMockChannel(m_core));
+ }
+
+ virtual ~ThrowingAsioStream() = default;
+ };
+
+/**
+ * Synchronous tests for Botan::Stream.
+ *
+ * This test validates the asynchronous behavior Botan::Stream, including its utility classes StreamCore and Async_*_Op.
+ * The stream's channel, i.e. TLS_Client or TLS_Server, is mocked and pretends to perform TLS operations (noop) and
+ * provides the test data to the stream.
+ * The underlying network socket, claiming it read / wrote a number of bytes.
+ */
+class Asio_Stream_Tests final : public Test
+ {
+ Botan::Credentials_Manager m_credentials_manager;
+ Botan::Null_RNG m_rng;
+ Botan::TLS::Session_Manager_Noop m_session_manager;
+ Botan::TLS::Default_Policy m_policy;
+
+ Botan::TLS::Context get_context()
+ {
+ return Botan::TLS::Context(m_credentials_manager, m_rng, m_session_manager, m_policy);
+ }
+
+ // use memcmp to check if the data in a is a prefix of the data in b
+ bool contains(const void* a, const void* b, const std::size_t size) { return memcmp(a, b, size) == 0; }
+
+ boost::string_view test_data() const
+ {
+ return boost::string_view(reinterpret_cast<const char*>(TEST_DATA), TEST_DATA_SIZE);
+ }
+
+ void test_sync_handshake(std::vector<Test::Result>& results)
+ {
+ net::io_context ioc;
+ auto ctx = get_context();
+ AsioStream ssl(ctx, ioc, test_data());
+
+ ssl.handshake(Botan::TLS::CLIENT);
+
+ Test::Result result("sync TLS handshake");
+ result.test_eq("feeds data into channel until active", ssl.native_handle()->is_active(), true);
+ results.push_back(result);
+ }
+
+ void test_sync_handshake_error(std::vector<Test::Result>& results)
+ {
+ net::io_context ioc;
+ // fail right away
+ FailCount fc{0, net::error::no_recovery};
+ TestStream remote{ioc};
+
+ auto ctx = get_context();
+ AsioStream ssl(ctx, ioc, fc);
+ ssl.next_layer().connect(remote);
+
+ // mimic handshake initialization
+ ssl.native_handle()->send(TEST_DATA, TEST_DATA_SIZE);
+
+ error_code ec;
+ ssl.handshake(Botan::TLS::CLIENT, ec);
+
+ Test::Result result("sync TLS handshake error");
+ result.test_eq("does not activate channel", ssl.native_handle()->is_active(), false);
+ result.confirm("propagates error code", ec == net::error::no_recovery);
+ results.push_back(result);
+ }
+
+ void test_sync_handshake_throw(std::vector<Test::Result>& results)
+ {
+ net::io_context ioc;
+ TestStream remote{ioc};
+
+ auto ctx = get_context();
+ ThrowingAsioStream ssl(ctx, ioc, test_data());
+ ssl.next_layer().connect(remote);
+
+ error_code ec;
+ ssl.handshake(Botan::TLS::CLIENT, ec);
+
+ Test::Result result("sync TLS handshake error");
+ result.test_eq("does not activate channel", ssl.native_handle()->is_active(), false);
+ result.confirm("propagates error code", ec == ThrowingMockChannel::expected_ec());
+ results.push_back(result);
+ }
+
+ void test_async_handshake(std::vector<Test::Result>& results)
+ {
+ net::io_context ioc;
+ TestStream remote{ioc};
+
+ auto ctx = get_context();
+ AsioStream ssl(ctx, ioc, test_data());
+ ssl.next_layer().connect(remote);
+
+ // mimic handshake initialization
+ ssl.native_handle()->send(TEST_DATA, TEST_DATA_SIZE);
+
+ Test::Result result("async TLS handshake");
+
+ auto handler = [&](const error_code&)
+ {
+ result.confirm("reads from socket", ssl.next_layer().nread() > 0);
+ result.confirm("writes from socket", ssl.next_layer().nwrite() > 0);
+ result.test_eq("feeds data into channel until active", ssl.native_handle()->is_active(), true);
+ };
+
+ ssl.async_handshake(Botan::TLS::CLIENT, handler);
+
+ ssl.next_layer().close_remote();
+ ioc.run();
+ results.push_back(result);
+ }
+
+ void test_async_handshake_error(std::vector<Test::Result>& results)
+ {
+ net::io_context ioc;
+ // fail right away
+ FailCount fc{0, net::error::no_recovery};
+ TestStream remote{ioc};
+
+ auto ctx = get_context();
+ AsioStream ssl(ctx, ioc, fc);
+ ssl.next_layer().connect(remote);
+
+ // mimic handshake initialization
+ ssl.native_handle()->send(TEST_DATA, TEST_DATA_SIZE);
+
+ Test::Result result("async TLS handshake error");
+
+ auto handler = [&](const error_code &ec)
+ {
+ result.test_eq("does not activate channel", ssl.native_handle()->is_active(), false);
+ result.confirm("propagates error code", ec == net::error::no_recovery);
+ };
+
+ ssl.async_handshake(Botan::TLS::CLIENT, handler);
+
+ ioc.run();
+ results.push_back(result);
+ }
+
+ void test_async_handshake_throw(std::vector<Test::Result>& results)
+ {
+ net::io_context ioc;
+ TestStream remote{ioc};
+
+ auto ctx = get_context();
+ ThrowingAsioStream ssl(ctx, ioc, test_data());
+ ssl.next_layer().connect(remote);
+
+ Test::Result result("async TLS handshake throw");
+
+ auto handler = [&](const error_code &ec)
+ {
+ result.test_eq("does not activate channel", ssl.native_handle()->is_active(), false);
+ result.confirm("propagates error code", ec == ThrowingMockChannel::expected_ec());
+ };
+
+ ssl.async_handshake(Botan::TLS::CLIENT, handler);
+
+ ioc.run();
+ results.push_back(result);
+ }
+
+ void test_sync_read_some_success(std::vector<Test::Result>& results)
+ {
+ net::io_context ioc;
+
+ auto ctx = get_context();
+ AsioStream ssl(ctx, ioc, test_data());
+
+ const std::size_t buf_size = 128;
+ uint8_t buf[buf_size];
+ error_code ec;
+
+ auto bytes_transferred = net::read(ssl, net::mutable_buffer(buf, sizeof(buf)), ec);
+
+ Test::Result result("sync read_some success");
+ result.confirm("reads the correct data", contains(buf, TEST_DATA, buf_size));
+ result.test_eq("reads the correct amount of data", bytes_transferred, buf_size);
+ result.confirm("does not report an error", !ec);
+
+ results.push_back(result);
+ }
+
+ void test_sync_read_some_buffer_sequence(std::vector<Test::Result>& results)
+ {
+ net::io_context ioc;
+
+ auto ctx = get_context();
+ AsioStream ssl(ctx, ioc, test_data());
+ error_code ec;
+
+ std::vector<net::mutable_buffer> data;
+ uint8_t buf1[TEST_DATA_SIZE/2];
+ uint8_t buf2[TEST_DATA_SIZE/2];
+ data.emplace_back(net::mutable_buffer(buf1, TEST_DATA_SIZE/2));
+ data.emplace_back(net::mutable_buffer(buf2, TEST_DATA_SIZE/2));
+
+ auto bytes_transferred = net::read(ssl, data, ec);
+
+ Test::Result result("sync read_some buffer sequence");
+
+ result.confirm("reads the correct data",
+ contains(buf1, TEST_DATA, TEST_DATA_SIZE/2) &&
+ contains(buf2, TEST_DATA+TEST_DATA_SIZE/2, TEST_DATA_SIZE/2));
+ result.test_eq("reads the correct amount of data", bytes_transferred, TEST_DATA_SIZE);
+ result.confirm("does not report an error", !ec);
+
+ results.push_back(result);
+ }
+
+ void test_sync_read_some_error(std::vector<Test::Result>& results)
+ {
+ net::io_context ioc;
+ // fail right away
+ FailCount fc{0, net::error::no_recovery};
+ TestStream remote{ioc};
+
+ auto ctx = get_context();
+ AsioStream ssl(ctx, ioc, fc);
+ ssl.next_layer().connect(remote);
+
+ uint8_t buf[128];
+ error_code ec;
+
+ auto bytes_transferred = net::read(ssl, net::mutable_buffer(buf, sizeof(buf)), ec);
+
+ Test::Result result("sync read_some error");
+ result.test_eq("didn't transfer anything", bytes_transferred, 0);
+ result.confirm("propagates error code", ec == net::error::no_recovery);
+
+ results.push_back(result);
+ }
+
+ void test_sync_read_some_throw(std::vector<Test::Result>& results)
+ {
+ net::io_context ioc;
+ TestStream remote{ioc};
+
+ auto ctx = get_context();
+ ThrowingAsioStream ssl(ctx, ioc, test_data());
+ ssl.next_layer().connect(remote);
+
+ uint8_t buf[128];
+ error_code ec;
+
+ auto bytes_transferred = net::read(ssl, net::mutable_buffer(buf, sizeof(buf)), ec);
+
+ Test::Result result("sync read_some throw");
+ result.test_eq("didn't transfer anything", bytes_transferred, 0);
+ result.confirm("propagates error code", ec == ThrowingMockChannel::expected_ec());
+
+ results.push_back(result);
+ }
+
+ void test_sync_read_zero_buffer(std::vector<Test::Result>& results)
+ {
+ net::io_context ioc;
+
+ auto ctx = get_context();
+ AsioStream ssl(ctx, ioc);
+
+ const std::size_t buf_size = 128;
+ uint8_t buf[buf_size];
+ error_code ec;
+
+ auto bytes_transferred = net::read(ssl, net::mutable_buffer(buf, std::size_t(0)), ec);
+
+ Test::Result result("sync read_some into zero-size buffer");
+ result.test_eq("reads the correct amount of data", bytes_transferred, 0);
+ // This relies on an implementation detail of TestStream: A "real" asio::tcp::stream
+ // would block here. TestStream sets error_code::eof.
+ result.confirm("does not report an error", !ec);
+
+ results.push_back(result);
+ }
+
+ void test_async_read_some_success(std::vector<Test::Result>& results)
+ {
+ net::io_context ioc;
+ TestStream remote{ioc};
+
+ auto ctx = get_context();
+ AsioStream ssl(ctx, ioc, test_data());
+ uint8_t data[TEST_DATA_SIZE];
+
+ Test::Result result("async read_some success");
+
+ auto read_handler = [&](const error_code &ec, std::size_t bytes_transferred)
+ {
+ result.confirm("reads the correct data", contains(data, TEST_DATA, TEST_DATA_SIZE));
+ result.test_eq("reads the correct amount of data", bytes_transferred, TEST_DATA_SIZE);
+ result.confirm("does not report an error", !ec);
+ };
+
+ net::mutable_buffer buf {data, TEST_DATA_SIZE};
+ net::async_read(ssl, buf, read_handler);
+
+ ssl.next_layer().close_remote();
+ ioc.run();
+ results.push_back(result);
+ }
+
+ void test_async_read_some_buffer_sequence(std::vector<Test::Result>& results)
+ {
+ net::io_context ioc;
+ auto ctx = get_context();
+ AsioStream ssl(ctx, ioc, test_data());
+
+ std::vector<net::mutable_buffer> data;
+ uint8_t buf1[TEST_DATA_SIZE/2];
+ uint8_t buf2[TEST_DATA_SIZE/2];
+ data.emplace_back(net::mutable_buffer(buf1, TEST_DATA_SIZE/2));
+ data.emplace_back(net::mutable_buffer(buf2, TEST_DATA_SIZE/2));
+
+ Test::Result result("async read_some buffer sequence");
+
+ auto read_handler = [&](const error_code &ec, std::size_t bytes_transferred)
+ {
+ result.confirm("reads the correct data",
+ contains(buf1, TEST_DATA, TEST_DATA_SIZE/2) &&
+ contains(buf2, TEST_DATA+TEST_DATA_SIZE/2, TEST_DATA_SIZE/2));
+ result.test_eq("reads the correct amount of data", bytes_transferred, TEST_DATA_SIZE);
+ result.confirm("does not report an error", !ec);
+ };
+
+ net::async_read(ssl, data, read_handler);
+
+ ssl.next_layer().close_remote();
+ ioc.run();
+ results.push_back(result);
+ }
+
+ void test_async_read_some_error(std::vector<Test::Result>& results)
+ {
+ net::io_context ioc;
+ // fail right away
+ FailCount fc{0, net::error::no_recovery};
+ auto ctx = get_context();
+ AsioStream ssl(ctx, ioc, fc);
+ uint8_t data[TEST_DATA_SIZE];
+
+ Test::Result result("async read_some error");
+
+ auto read_handler = [&](const error_code &ec, std::size_t bytes_transferred)
+ {
+ result.test_eq("didn't transfer anything", bytes_transferred, 0);
+ result.confirm("propagates error code", ec == net::error::no_recovery);
+ };
+
+ net::mutable_buffer buf {data, TEST_DATA_SIZE};
+ net::async_read(ssl, buf, read_handler);
+
+ ssl.next_layer().close_remote();
+ ioc.run();
+ results.push_back(result);
+ }
+
+ void test_async_read_some_throw(std::vector<Test::Result>& results)
+ {
+ net::io_context ioc;
+ auto ctx = get_context();
+ ThrowingAsioStream ssl(ctx, ioc, test_data());
+ uint8_t data[TEST_DATA_SIZE];
+
+ Test::Result result("async read_some throw");
+
+ auto read_handler = [&](const error_code &ec, std::size_t bytes_transferred)
+ {
+ result.test_eq("didn't transfer anything", bytes_transferred, 0);
+ result.confirm("propagates error code", ec == ThrowingMockChannel::expected_ec());
+ };
+
+ net::mutable_buffer buf {data, TEST_DATA_SIZE};
+ net::async_read(ssl, buf, read_handler);
+
+ ssl.next_layer().close_remote();
+ ioc.run();
+ results.push_back(result);
+ }
+
+ void test_async_read_zero_buffer(std::vector<Test::Result>& results)
+ {
+ net::io_context ioc;
+ TestStream remote{ioc};
+
+ auto ctx = get_context();
+ AsioStream ssl(ctx, ioc);
+ uint8_t data[TEST_DATA_SIZE];
+
+ Test::Result result("async read_some into zero-size buffer");
+
+ auto read_handler = [&](const error_code &ec, std::size_t bytes_transferred)
+ {
+ result.test_eq("reads the correct amount of data", bytes_transferred, 0);
+ // This relies on an implementation detail of TestStream: A "real" asio::tcp::stream
+ // would block here. TestStream sets error_code::eof.
+ result.confirm("does not report an error", !ec);
+ };
+
+ net::mutable_buffer buf {data, std::size_t(0)};
+ net::async_read(ssl, buf, read_handler);
+
+ ssl.next_layer().close_remote();
+ ioc.run();
+ results.push_back(result);
+ }
+
+ void test_sync_write_some_success(std::vector<Test::Result>& results)
+ {
+ net::io_context ioc;
+ TestStream remote{ioc};
+
+ auto ctx = get_context();
+ AsioStream ssl(ctx, ioc);
+ ssl.next_layer().connect(remote);
+ error_code ec;
+
+ auto bytes_transferred = net::write(ssl, net::const_buffer(TEST_DATA, TEST_DATA_SIZE), ec);
+
+ Test::Result result("sync write_some success");
+ result.confirm("writes the correct data", remote.str() == test_data());
+ result.test_eq("writes the correct amount of data", bytes_transferred, TEST_DATA_SIZE);
+ result.confirm("does not report an error", !ec);
+
+ results.push_back(result);
+ }
+
+ void test_sync_no_handshake(std::vector<Test::Result>& results)
+ {
+ net::io_context ioc;
+ TestStream remote{ioc};
+
+ auto ctx = get_context();
+ Botan::TLS::Stream<TestStream> ssl(ctx, ioc); // Note that we're not using MockChannel here
+ ssl.next_layer().connect(remote);
+ error_code ec;
+
+ net::write(ssl, net::const_buffer(TEST_DATA, TEST_DATA_SIZE), ec);
+
+ Test::Result result("sync write_some without handshake fails gracefully");
+ result.confirm("reports an error", ec.failed());
+
+ results.push_back(result);
+ }
+
+ void test_sync_write_some_buffer_sequence(std::vector<Test::Result>& results)
+ {
+ net::io_context ioc;
+ TestStream remote{ioc};
+
+ auto ctx = get_context();
+ AsioStream ssl(ctx, ioc);
+ ssl.next_layer().connect(remote);
+ error_code ec;
+
+ // this should be Botan::TLS::MAX_PLAINTEXT_SIZE + 1024 + 1
+ std::array<uint8_t, 17 * 1024 + 1> random_data;
+ random_data.fill('4'); // chosen by fair dice roll
+ random_data.back() = '5';
+
+ std::vector<net::const_buffer> data;
+ data.emplace_back(net::const_buffer(random_data.data(), 1));
+ for(std::size_t i = 1; i < random_data.size(); i += 1024)
+ {
+ data.emplace_back(net::const_buffer(random_data.data() + i, 1024));
+ }
+
+ auto bytes_transferred = net::write(ssl, data, ec);
+
+ Test::Result result("sync write_some buffer sequence");
+
+ result.confirm("[precondition] MAX_PLAINTEXT_SIZE is still smaller than random_data.size()",
+ Botan::TLS::MAX_PLAINTEXT_SIZE < random_data.size());
+
+ result.confirm("writes the correct data",
+ contains(remote.buffer().data().data(), random_data.data(), random_data.size()));
+ result.test_eq("writes the correct amount of data", bytes_transferred, random_data.size());
+ result.test_eq("correct number of writes", ssl.next_layer().nwrite(), 2);
+ result.confirm("does not report an error", !ec);
+
+ results.push_back(result);
+ }
+
+ void test_sync_write_some_error(std::vector<Test::Result>& results)
+ {
+ net::io_context ioc;
+ // fail right away
+ FailCount fc{0, net::error::no_recovery};
+ TestStream remote{ioc};
+
+ auto ctx = get_context();
+ AsioStream ssl(ctx, ioc, fc);
+ ssl.next_layer().connect(remote);
+
+ error_code ec;
+
+ auto bytes_transferred = net::write(ssl, net::const_buffer(TEST_DATA, TEST_DATA_SIZE), ec);
+
+ Test::Result result("sync write_some error");
+ result.test_eq("didn't transfer anything", bytes_transferred, 0);
+ result.confirm("propagates error code", ec == net::error::no_recovery);
+
+ results.push_back(result);
+ }
+
+ void test_sync_write_some_throw(std::vector<Test::Result>& results)
+ {
+ net::io_context ioc;
+ TestStream remote{ioc};
+
+ auto ctx = get_context();
+ ThrowingAsioStream ssl(ctx, ioc);
+ ssl.next_layer().connect(remote);
+ error_code ec;
+
+ auto bytes_transferred = net::write(ssl, net::const_buffer(TEST_DATA, TEST_DATA_SIZE), ec);
+
+ Test::Result result("sync write_some throw");
+ result.test_eq("didn't transfer anything", bytes_transferred, 0);
+ result.confirm("propagates error code", ec == ThrowingMockChannel::expected_ec());
+
+ results.push_back(result);
+ }
+
+ void test_async_write_some_success(std::vector<Test::Result>& results)
+ {
+ net::io_context ioc;
+ TestStream remote{ioc};
+
+ auto ctx = get_context();
+ AsioStream ssl(ctx, ioc);
+ ssl.next_layer().connect(remote);
+
+ Test::Result result("async write_some success");
+
+ auto write_handler = [&](const error_code &ec, std::size_t bytes_transferred)
+ {
+ result.confirm("writes the correct data", remote.str() == test_data());
+ result.test_eq("writes the correct amount of data", bytes_transferred, TEST_DATA_SIZE);
+ result.confirm("does not report an error", !ec);
+ };
+
+ net::async_write(ssl, net::const_buffer(TEST_DATA, TEST_DATA_SIZE), write_handler);
+
+ ioc.run();
+ results.push_back(result);
+ }
+
+ void test_async_write_some_buffer_sequence(std::vector<Test::Result>& results)
+ {
+ net::io_context ioc;
+ TestStream remote{ioc};
+
+ auto ctx = get_context();
+ AsioStream ssl(ctx, ioc);
+ ssl.next_layer().connect(remote);
+
+ // this should be Botan::TLS::MAX_PLAINTEXT_SIZE + 1024 + 1
+ std::array<uint8_t, 17 * 1024 + 1> random_data;
+ random_data.fill('4'); // chosen by fair dice roll
+ random_data.back() = '5';
+
+ std::vector<net::const_buffer> src;
+ src.emplace_back(net::const_buffer(random_data.data(), 1));
+ for(std::size_t i = 1; i < random_data.size(); i += 1024)
+ {
+ src.emplace_back(net::const_buffer(random_data.data() + i, 1024));
+ }
+
+ Test::Result result("async write_some buffer sequence");
+
+ result.confirm("[precondition] MAX_PLAINTEXT_SIZE is still smaller than random_data.size()",
+ Botan::TLS::MAX_PLAINTEXT_SIZE < random_data.size());
+
+ auto write_handler = [&](const error_code &ec, std::size_t bytes_transferred)
+ {
+ result.confirm("writes the correct data",
+ contains(remote.buffer().data().data(), random_data.data(), random_data.size()));
+ result.test_eq("writes the correct amount of data", bytes_transferred, random_data.size());
+ result.test_eq("correct number of writes", ssl.next_layer().nwrite(), 2);
+ result.confirm("does not report an error", !ec);
+ };
+
+ net::async_write(ssl, src, write_handler);
+
+ ioc.run();
+ results.push_back(result);
+ }
+
+ void test_async_write_some_error(std::vector<Test::Result>& results)
+ {
+ net::io_context ioc;
+ // fail right away
+ FailCount fc{0, net::error::no_recovery};
+ TestStream remote{ioc};
+
+ auto ctx = get_context();
+ AsioStream ssl(ctx, ioc, fc);
+ ssl.next_layer().connect(remote);
+
+ Test::Result result("async write_some error");
+
+ auto write_handler = [&](const error_code &ec, std::size_t bytes_transferred)
+ {
+ result.test_eq("committed some bytes to the core", bytes_transferred, TEST_DATA_SIZE);
+ result.confirm("propagates error code", ec == net::error::no_recovery);
+ };
+
+ net::async_write(ssl, net::const_buffer(TEST_DATA, TEST_DATA_SIZE), write_handler);
+
+ ioc.run();
+ results.push_back(result);
+ }
+
+ void test_async_write_throw(std::vector<Test::Result>& results)
+ {
+ net::io_context ioc;
+ TestStream remote{ioc};
+
+ auto ctx = get_context();
+ ThrowingAsioStream ssl(ctx, ioc);
+ ssl.next_layer().connect(remote);
+
+ Test::Result result("async write_some throw");
+
+ auto write_handler = [&](const error_code &ec, std::size_t bytes_transferred)
+ {
+ result.test_eq("didn't transfer anything", bytes_transferred, 0);
+ result.confirm("propagates error code", ec == ThrowingMockChannel::expected_ec());
+ };
+
+ net::async_write(ssl, net::const_buffer(TEST_DATA, TEST_DATA_SIZE), write_handler);
+
+ ioc.run();
+ results.push_back(result);
+ }
+
+ public:
+ std::vector<Test::Result> run() override
+ {
+ std::vector<Test::Result> results;
+
+ test_sync_no_handshake(results);
+
+ test_sync_handshake(results);
+ test_sync_handshake_error(results);
+ test_sync_handshake_throw(results);
+
+ test_async_handshake(results);
+ test_async_handshake_error(results);
+ test_async_handshake_throw(results);
+
+ test_sync_read_some_success(results);
+ test_sync_read_some_buffer_sequence(results);
+ test_sync_read_some_error(results);
+ test_sync_read_some_throw(results);
+ test_sync_read_zero_buffer(results);
+
+ test_async_read_some_success(results);
+ test_async_read_some_buffer_sequence(results);
+ test_async_read_some_error(results);
+ test_async_read_some_throw(results);
+ test_async_read_zero_buffer(results);
+
+ test_sync_write_some_success(results);
+ test_sync_write_some_buffer_sequence(results);
+ test_sync_write_some_error(results);
+ test_sync_write_some_throw(results);
+
+ test_async_write_some_success(results);
+ test_async_write_some_buffer_sequence(results);
+ test_async_write_some_error(results);
+ test_async_write_throw(results);
+
+ return results;
+ }
+ };
+
+BOTAN_REGISTER_TEST("tls", "tls_asio_stream", Asio_Stream_Tests);
+
+} // namespace Botan_Tests
+
+#endif // BOOST_VERSION
+#endif // BOTAN_HAS_TLS && BOTAN_HAS_BOOST_ASIO
Index: create-2.19.3-boost-bind-patch/Botan-2.19.3-new/src/tests
===================================================================
--- create-2.19.3-boost-bind-patch/Botan-2.19.3-new/src/tests (nonexistent)
+++ create-2.19.3-boost-bind-patch/Botan-2.19.3-new/src/tests (revision 5)
Property changes on: create-2.19.3-boost-bind-patch/Botan-2.19.3-new/src/tests
___________________________________________________________________
Added: svn:ignore
## -0,0 +1,73 ##
+
+# install dir
+dist
+
+# Target build dirs
+.a1x-newlib
+.a2x-newlib
+.at91sam7s-newlib
+
+.build-machine
+
+.a1x-glibc
+.a2x-glibc
+.h3-glibc
+.h5-glibc
+.i586-glibc
+.i686-glibc
+.imx6-glibc
+.jz47xx-glibc
+.makefile
+.am335x-glibc
+.omap543x-glibc
+.p5600-glibc
+.power8-glibc
+.power8le-glibc
+.power9-glibc
+.power9le-glibc
+.m1000-glibc
+.riscv64-glibc
+.rk328x-glibc
+.rk33xx-glibc
+.rk339x-glibc
+.s8xx-glibc
+.s9xx-glibc
+.x86_64-glibc
+
+# Hidden files (each file)
+.makefile
+.dist
+.rootfs
+
+# src & hw requires
+.src_requires
+.src_requires_depend
+.requires
+.requires_depend
+
+# Tarballs
+*.gz
+*.bz2
+*.lz
+*.xz
+*.tgz
+*.txz
+
+# Signatures
+*.asc
+*.sig
+*.sign
+*.sha1sum
+
+# Patches
+*.patch
+
+# Descriptions
+*.dsc
+*.txt
+
+# Default linux config files
+*.defconfig
+
+# backup copies
+*~
Index: create-2.19.3-boost-bind-patch/Botan-2.19.3-new/src
===================================================================
--- create-2.19.3-boost-bind-patch/Botan-2.19.3-new/src (nonexistent)
+++ create-2.19.3-boost-bind-patch/Botan-2.19.3-new/src (revision 5)
Property changes on: create-2.19.3-boost-bind-patch/Botan-2.19.3-new/src
___________________________________________________________________
Added: svn:ignore
## -0,0 +1,73 ##
+
+# install dir
+dist
+
+# Target build dirs
+.a1x-newlib
+.a2x-newlib
+.at91sam7s-newlib
+
+.build-machine
+
+.a1x-glibc
+.a2x-glibc
+.h3-glibc
+.h5-glibc
+.i586-glibc
+.i686-glibc
+.imx6-glibc
+.jz47xx-glibc
+.makefile
+.am335x-glibc
+.omap543x-glibc
+.p5600-glibc
+.power8-glibc
+.power8le-glibc
+.power9-glibc
+.power9le-glibc
+.m1000-glibc
+.riscv64-glibc
+.rk328x-glibc
+.rk33xx-glibc
+.rk339x-glibc
+.s8xx-glibc
+.s9xx-glibc
+.x86_64-glibc
+
+# Hidden files (each file)
+.makefile
+.dist
+.rootfs
+
+# src & hw requires
+.src_requires
+.src_requires_depend
+.requires
+.requires_depend
+
+# Tarballs
+*.gz
+*.bz2
+*.lz
+*.xz
+*.tgz
+*.txz
+
+# Signatures
+*.asc
+*.sig
+*.sign
+*.sha1sum
+
+# Patches
+*.patch
+
+# Descriptions
+*.dsc
+*.txt
+
+# Default linux config files
+*.defconfig
+
+# backup copies
+*~
Index: create-2.19.3-boost-bind-patch/Botan-2.19.3-new
===================================================================
--- create-2.19.3-boost-bind-patch/Botan-2.19.3-new (nonexistent)
+++ create-2.19.3-boost-bind-patch/Botan-2.19.3-new (revision 5)
Property changes on: create-2.19.3-boost-bind-patch/Botan-2.19.3-new
___________________________________________________________________
Added: svn:ignore
## -0,0 +1,73 ##
+
+# install dir
+dist
+
+# Target build dirs
+.a1x-newlib
+.a2x-newlib
+.at91sam7s-newlib
+
+.build-machine
+
+.a1x-glibc
+.a2x-glibc
+.h3-glibc
+.h5-glibc
+.i586-glibc
+.i686-glibc
+.imx6-glibc
+.jz47xx-glibc
+.makefile
+.am335x-glibc
+.omap543x-glibc
+.p5600-glibc
+.power8-glibc
+.power8le-glibc
+.power9-glibc
+.power9le-glibc
+.m1000-glibc
+.riscv64-glibc
+.rk328x-glibc
+.rk33xx-glibc
+.rk339x-glibc
+.s8xx-glibc
+.s9xx-glibc
+.x86_64-glibc
+
+# Hidden files (each file)
+.makefile
+.dist
+.rootfs
+
+# src & hw requires
+.src_requires
+.src_requires_depend
+.requires
+.requires_depend
+
+# Tarballs
+*.gz
+*.bz2
+*.lz
+*.xz
+*.tgz
+*.txz
+
+# Signatures
+*.asc
+*.sig
+*.sign
+*.sha1sum
+
+# Patches
+*.patch
+
+# Descriptions
+*.dsc
+*.txt
+
+# Default linux config files
+*.defconfig
+
+# backup copies
+*~
Index: create-2.19.3-boost-bind-patch/create.patch.sh
===================================================================
--- create-2.19.3-boost-bind-patch/create.patch.sh (nonexistent)
+++ create-2.19.3-boost-bind-patch/create.patch.sh (revision 5)
@@ -0,0 +1,15 @@
+#!/bin/sh
+
+VERSION=2.19.3
+
+tar --files-from=file.list -xJvf ../Botan-$VERSION.tar.xz
+mv Botan-$VERSION Botan-$VERSION-orig
+
+cp -rf ./Botan-$VERSION-new ./Botan-$VERSION
+
+diff --unified -Nr Botan-$VERSION-orig Botan-$VERSION > Botan-$VERSION-boost-bind.patch
+
+mv Botan-$VERSION-boost-bind.patch ../patches
+
+rm -rf ./Botan-$VERSION
+rm -rf ./Botan-$VERSION-orig
Property changes on: create-2.19.3-boost-bind-patch/create.patch.sh
___________________________________________________________________
Added: svn:executable
## -0,0 +1 ##
+*
\ No newline at end of property
Index: create-2.19.3-boost-bind-patch/file.list
===================================================================
--- create-2.19.3-boost-bind-patch/file.list (nonexistent)
+++ create-2.19.3-boost-bind-patch/file.list (revision 5)
@@ -0,0 +1,3 @@
+Botan-2.19.3/src/cli/tls_http_server.cpp
+Botan-2.19.3/src/cli/tls_proxy.cpp
+Botan-2.19.3/src/tests/unit_asio_stream.cpp
Index: create-2.19.3-boost-bind-patch
===================================================================
--- create-2.19.3-boost-bind-patch (nonexistent)
+++ create-2.19.3-boost-bind-patch (revision 5)
Property changes on: create-2.19.3-boost-bind-patch
___________________________________________________________________
Added: svn:ignore
## -0,0 +1,73 ##
+
+# install dir
+dist
+
+# Target build dirs
+.a1x-newlib
+.a2x-newlib
+.at91sam7s-newlib
+
+.build-machine
+
+.a1x-glibc
+.a2x-glibc
+.h3-glibc
+.h5-glibc
+.i586-glibc
+.i686-glibc
+.imx6-glibc
+.jz47xx-glibc
+.makefile
+.am335x-glibc
+.omap543x-glibc
+.p5600-glibc
+.power8-glibc
+.power8le-glibc
+.power9-glibc
+.power9le-glibc
+.m1000-glibc
+.riscv64-glibc
+.rk328x-glibc
+.rk33xx-glibc
+.rk339x-glibc
+.s8xx-glibc
+.s9xx-glibc
+.x86_64-glibc
+
+# Hidden files (each file)
+.makefile
+.dist
+.rootfs
+
+# src & hw requires
+.src_requires
+.src_requires_depend
+.requires
+.requires_depend
+
+# Tarballs
+*.gz
+*.bz2
+*.lz
+*.xz
+*.tgz
+*.txz
+
+# Signatures
+*.asc
+*.sig
+*.sign
+*.sha1sum
+
+# Patches
+*.patch
+
+# Descriptions
+*.dsc
+*.txt
+
+# Default linux config files
+*.defconfig
+
+# backup copies
+*~
Index: patches/README
===================================================================
--- patches/README (nonexistent)
+++ patches/README (revision 5)
@@ -0,0 +1,6 @@
+
+/* begin *
+
+ TODO: Leave some comment here.
+
+ * end */
Index: patches
===================================================================
--- patches (nonexistent)
+++ patches (revision 5)
Property changes on: patches
___________________________________________________________________
Added: svn:ignore
## -0,0 +1,73 ##
+
+# install dir
+dist
+
+# Target build dirs
+.a1x-newlib
+.a2x-newlib
+.at91sam7s-newlib
+
+.build-machine
+
+.a1x-glibc
+.a2x-glibc
+.h3-glibc
+.h5-glibc
+.i586-glibc
+.i686-glibc
+.imx6-glibc
+.jz47xx-glibc
+.makefile
+.am335x-glibc
+.omap543x-glibc
+.p5600-glibc
+.power8-glibc
+.power8le-glibc
+.power9-glibc
+.power9le-glibc
+.m1000-glibc
+.riscv64-glibc
+.rk328x-glibc
+.rk33xx-glibc
+.rk339x-glibc
+.s8xx-glibc
+.s9xx-glibc
+.x86_64-glibc
+
+# Hidden files (each file)
+.makefile
+.dist
+.rootfs
+
+# src & hw requires
+.src_requires
+.src_requires_depend
+.requires
+.requires_depend
+
+# Tarballs
+*.gz
+*.bz2
+*.lz
+*.xz
+*.tgz
+*.txz
+
+# Signatures
+*.asc
+*.sig
+*.sign
+*.sha1sum
+
+# Patches
+*.patch
+
+# Descriptions
+*.dsc
+*.txt
+
+# Default linux config files
+*.defconfig
+
+# backup copies
+*~
Index: .
===================================================================
--- . (nonexistent)
+++ . (revision 5)
Property changes on: .
___________________________________________________________________
Added: svn:ignore
## -0,0 +1,73 ##
+
+# install dir
+dist
+
+# Target build dirs
+.a1x-newlib
+.a2x-newlib
+.at91sam7s-newlib
+
+.build-machine
+
+.a1x-glibc
+.a2x-glibc
+.h3-glibc
+.h5-glibc
+.i586-glibc
+.i686-glibc
+.imx6-glibc
+.jz47xx-glibc
+.makefile
+.am335x-glibc
+.omap543x-glibc
+.p5600-glibc
+.power8-glibc
+.power8le-glibc
+.power9-glibc
+.power9le-glibc
+.m1000-glibc
+.riscv64-glibc
+.rk328x-glibc
+.rk33xx-glibc
+.rk339x-glibc
+.s8xx-glibc
+.s9xx-glibc
+.x86_64-glibc
+
+# Hidden files (each file)
+.makefile
+.dist
+.rootfs
+
+# src & hw requires
+.src_requires
+.src_requires_depend
+.requires
+.requires_depend
+
+# Tarballs
+*.gz
+*.bz2
+*.lz
+*.xz
+*.tgz
+*.txz
+
+# Signatures
+*.asc
+*.sig
+*.sign
+*.sha1sum
+
+# Patches
+*.patch
+
+# Descriptions
+*.dsc
+*.txt
+
+# Default linux config files
+*.defconfig
+
+# backup copies
+*~