aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKaren Arutyunov <karen@codesynthesis.com>2017-05-29 20:05:54 +0300
committerKaren Arutyunov <karen@codesynthesis.com>2017-05-30 19:04:13 +0300
commit95ff8f359cfc2189bd4d7e02e15373027d2bda32 (patch)
tree2b22d991886c0a5c2678ea0fb5f565f90d57df25
parent1b57e247b8d1a7a41a8ee45d6d524c71edd63a81 (diff)
Implement openssl process
-rw-r--r--libbutl/buildfile1
-rw-r--r--libbutl/curl.cxx2
-rw-r--r--libbutl/curl.ixx3
-rw-r--r--libbutl/curl.txx2
-rw-r--r--libbutl/fdstream.hxx7
-rw-r--r--libbutl/openssl.cxx96
-rw-r--r--libbutl/openssl.hxx165
-rw-r--r--libbutl/openssl.ixx31
-rw-r--r--libbutl/openssl.txx56
-rw-r--r--libbutl/sendmail.ixx1
-rw-r--r--tests/buildfile3
-rw-r--r--tests/openssl/buildfile7
-rw-r--r--tests/openssl/driver.cxx35
-rw-r--r--tests/openssl/testscript5
14 files changed, 409 insertions, 5 deletions
diff --git a/libbutl/buildfile b/libbutl/buildfile
index 473c1d5..d5f492b 100644
--- a/libbutl/buildfile
+++ b/libbutl/buildfile
@@ -15,6 +15,7 @@ lib{butl}: \
{hxx cxx}{ manifest-parser } \
{hxx cxx}{ manifest-serializer } \
{hxx }{ multi-index } \
+ {hxx ixx txx cxx}{ openssl } \
{hxx }{ optional } \
{hxx cxx}{ pager } \
{hxx ixx txx cxx}{ path } \
diff --git a/libbutl/curl.cxx b/libbutl/curl.cxx
index daa1fd3..a04d52e 100644
--- a/libbutl/curl.cxx
+++ b/libbutl/curl.cxx
@@ -4,7 +4,7 @@
#include <libbutl/curl.hxx>
-#include <utility> // move(), forward()
+#include <utility> // move()
#include <exception> // invalid_argument
#include <libbutl/utility.hxx> // casecmp()
diff --git a/libbutl/curl.ixx b/libbutl/curl.ixx
index fcc1bab..204dfa1 100644
--- a/libbutl/curl.ixx
+++ b/libbutl/curl.ixx
@@ -2,7 +2,8 @@
// copyright : Copyright (c) 2014-2017 Code Synthesis Ltd
// license : MIT; see accompanying LICENSE file
-#include <utility> // move(), forward()
+#include <cstddef> // size_t
+#include <utility> // forward()
namespace butl
{
diff --git a/libbutl/curl.txx b/libbutl/curl.txx
index 5fd81dc..f6f0e96 100644
--- a/libbutl/curl.txx
+++ b/libbutl/curl.txx
@@ -2,7 +2,7 @@
// copyright : Copyright (c) 2014-2017 Code Synthesis Ltd
// license : MIT; see accompanying LICENSE file
-#include <utility> // move(), forward()
+#include <utility> // forward()
#include <exception> // invalid_argument
namespace butl
diff --git a/libbutl/fdstream.hxx b/libbutl/fdstream.hxx
index dd33263..a8f203d 100644
--- a/libbutl/fdstream.hxx
+++ b/libbutl/fdstream.hxx
@@ -387,6 +387,13 @@ namespace butl
void
open (auto_fd&& fd) {buf_.open (std::move (fd)); clear ();}
+ void
+ open (auto_fd&& fd, fdstream_mode m)
+ {
+ open (std::move (fd));
+ skip_ = (m & fdstream_mode::skip) == fdstream_mode::skip;
+ }
+
void close ();
auto_fd release (); // Note: no skipping.
bool is_open () const {return buf_.is_open ();}
diff --git a/libbutl/openssl.cxx b/libbutl/openssl.cxx
new file mode 100644
index 0000000..aa4e720
--- /dev/null
+++ b/libbutl/openssl.cxx
@@ -0,0 +1,96 @@
+// file : libbutl/openssl.cxx -*- C++ -*-
+// copyright : Copyright (c) 2014-2017 Code Synthesis Ltd
+// license : MIT; see accompanying LICENSE file
+
+#include <libbutl/openssl.hxx>
+
+#include <utility> // move()
+
+using namespace std;
+
+namespace butl
+{
+ int openssl::
+ map_in (nullfd_t, io_data& d)
+ {
+ d.pipe.in = fdnull (); // /dev/null
+ return d.pipe.in.get ();
+ }
+
+ int openssl::
+ map_in (const path& f, io_data& d)
+ {
+ if (f.string () == "-")
+ {
+ // Note: no need for any options, openssl reads from stdin by default.
+ //
+ d.pipe = fdopen_pipe (fdopen_mode::binary);
+ out.open (move (d.pipe.out));
+ }
+ else
+ {
+ d.options.push_back ("-in");
+ d.options.push_back (f.string ().c_str ());
+ d.pipe.in = fdnull (); // /dev/null
+ }
+
+ return d.pipe.in.get ();
+ }
+
+ int openssl::
+ map_in (fdstream_mode m, io_data& d)
+ {
+ assert (m == fdstream_mode::text || m == fdstream_mode::binary);
+
+ // Note: no need for any options, openssl reads from stdin by default.
+ //
+ d.pipe = fdopen_pipe (m == fdstream_mode::binary
+ ? fdopen_mode::binary
+ : fdopen_mode::none);
+
+ out.open (move (d.pipe.out));
+ return d.pipe.in.get ();
+ }
+
+ int openssl::
+ map_out (nullfd_t, io_data& d)
+ {
+ d.pipe.out = fdnull ();
+ return d.pipe.out.get (); // /dev/null
+ }
+
+ int openssl::
+ map_out (const path& f, io_data& d)
+ {
+ if (f.string () == "-")
+ {
+ // Note: no need for any options, openssl writes to stdout by default.
+ //
+ d.pipe = fdopen_pipe (fdopen_mode::binary);
+ in.open (move (d.pipe.in), fdstream_mode::skip);
+ }
+ else
+ {
+ d.options.push_back ("-out");
+ d.options.push_back (f.string ().c_str ());
+ d.pipe.out = fdnull (); // /dev/null
+ }
+
+ return d.pipe.out.get ();
+ }
+
+ int openssl::
+ map_out (fdstream_mode m, io_data& d)
+ {
+ assert (m == fdstream_mode::text || m == fdstream_mode::binary);
+
+ // Note: no need for any options, openssl writes to stdout by default.
+ //
+ d.pipe = fdopen_pipe (m == fdstream_mode::binary
+ ? fdopen_mode::binary
+ : fdopen_mode::none);
+
+ in.open (move (d.pipe.in), fdstream_mode::skip);
+ return d.pipe.out.get ();
+ }
+}
diff --git a/libbutl/openssl.hxx b/libbutl/openssl.hxx
new file mode 100644
index 0000000..2f54f93
--- /dev/null
+++ b/libbutl/openssl.hxx
@@ -0,0 +1,165 @@
+// file : libbutl/openssl.hxx -*- C++ -*-
+// copyright : Copyright (c) 2014-2017 Code Synthesis Ltd
+// license : MIT; see accompanying LICENSE file
+
+#ifndef LIBBUTL_OPENSSL_HXX
+#define LIBBUTL_OPENSSL_HXX
+
+#include <string>
+#include <type_traits>
+
+#include <libbutl/export.hxx>
+
+#include <libbutl/process.hxx>
+#include <libbutl/fdstream.hxx>
+#include <libbutl/small-vector.hxx>
+
+namespace butl
+{
+ // Perform a crypto operation using the openssl(1) program. Throw
+ // process_error and io_error (both derive from system_error) in case of
+ // errors.
+ //
+ // The I (in) and O (out) can be of the following types/values:
+ //
+ // nullfd Signal that no input/output is expected.
+ //
+ // path Read input/write output from/to a file. If the special "-"
+ // value is used, then instead input is connected to the
+ // openssl::out ofdstream member and output -- to the
+ // openssl::in ifdstream member. Note that the argument type
+ // should be path, not string (i.e., pass path("-")). Also
+ // note that the streams are opened in the binary mode. To
+ // change that, use fdstream_mode::text instead (see below).
+ //
+ // fdstream_mode Only text and binary values are meaningful. Same as
+ // path("-"), but also specifies the translation mode.
+ //
+ // other Forwarded as is to process_start(). Normally either int or
+ // auto_fd.
+ //
+ // For example:
+ //
+ // openssl os (path ("key.pub.pem"), // Read key from file,
+ // path ("-"), // Write result to openssl::in.
+ // 2,
+ // "openssl", "pkey",
+ // "-pubin", "-outform", "DER");
+ //
+ // Typical usage:
+ //
+ // try
+ // {
+ // openssl os (nullfd, // No input expected.
+ // path ("-"), // Output to openssl::in.
+ // 2, // Diagnostics to stderr.
+ // path ("openssl"), // Program path.
+ // "rand", // Command.
+ // 64); // Command options.
+ //
+ // vector<char> r (os.in.read_binary ());
+ // os.in.close ();
+ //
+ // if (!os.wait ())
+ // ... // openssl returned non-zero status.
+ // }
+ // catch (const system_error& e)
+ // {
+ // cerr << "openssl error: " << e << endl;
+ // }
+ //
+ // Notes:
+ //
+ // 1. If opened, in stream is in the skip mode (see fdstream_mode).
+ //
+ // 2. If opened, in/out must be explicitly closed before calling wait().
+ //
+ // 3. Normally the order of options is not important (unless they override
+ // each other). However, openssl 1.0.1 seems to have bugs in that
+ // department (that were apparently fixed in 1.0.2). To work around these
+ // bugs pass user-supplied options first.
+ //
+ class LIBBUTL_EXPORT openssl: public process
+ {
+ public:
+ ifdstream in;
+ ofdstream out;
+
+ template <typename I,
+ typename O,
+ typename E,
+ typename P,
+ typename... A>
+ openssl (I&& in,
+ O&& out,
+ E&& err,
+ const P& program,
+ const std::string& command,
+ A&&... options);
+
+ // Version with the command line callback (see process_run() for details).
+ //
+ template <typename C,
+ typename I,
+ typename O,
+ typename E,
+ typename P,
+ typename... A>
+ openssl (const C&,
+ I&& in,
+ O&& out,
+ E&& err,
+ const P& program,
+ const std::string& command,
+ A&&... options);
+
+ private:
+ template <typename T>
+ struct is_other
+ {
+ using type = typename std::remove_reference<
+ typename std::remove_cv<T>::type>::type;
+
+ static const bool value = !(std::is_same<type, nullfd_t>::value ||
+ std::is_same<type, path>::value ||
+ std::is_same<type, fdstream_mode>::value);
+ };
+
+ struct io_data
+ {
+ fdpipe pipe;
+ small_vector<const char*, 2> options;
+ };
+
+ int
+ map_in (nullfd_t, io_data&);
+
+ int
+ map_in (const path&, io_data&);
+
+ int
+ map_in (fdstream_mode, io_data&);
+
+ template <typename I>
+ typename std::enable_if<is_other<I>::value, I>::type
+ map_in (I&&, io_data&);
+
+ int
+ map_out (nullfd_t, io_data&);
+
+ int
+ map_out (const path&, io_data&);
+
+ int
+ map_out (fdstream_mode, io_data&);
+
+ template <typename O>
+ typename std::enable_if<is_other<O>::value, O>::type
+ map_out (O&&, io_data&);
+ };
+}
+
+#include <libbutl/openssl.ixx>
+#include <libbutl/openssl.txx>
+
+#endif // LIBBUTL_OPENSSL_HXX
diff --git a/libbutl/openssl.ixx b/libbutl/openssl.ixx
new file mode 100644
index 0000000..2af5029
--- /dev/null
+++ b/libbutl/openssl.ixx
@@ -0,0 +1,31 @@
+// file : libbutl/openssl.ixx -*- C++ -*-
+// copyright : Copyright (c) 2014-2017 Code Synthesis Ltd
+// license : MIT; see accompanying LICENSE file
+
+#include <cstddef> // size_t
+#include <utility> // move(), forward()
+
+namespace butl
+{
+ template <typename I,
+ typename O,
+ typename E,
+ typename P,
+ typename... A>
+ inline openssl::
+ openssl (I&& in,
+ O&& out,
+ E&& err,
+ const P& program,
+ const std::string& command,
+ A&&... options)
+ : openssl ([] (const char* [], std::size_t) {},
+ std::forward<I> (in),
+ std::forward<O> (out),
+ std::forward<E> (err),
+ program,
+ command,
+ std::forward<A> (options)...)
+ {
+ }
+}
diff --git a/libbutl/openssl.txx b/libbutl/openssl.txx
new file mode 100644
index 0000000..aaaa239
--- /dev/null
+++ b/libbutl/openssl.txx
@@ -0,0 +1,56 @@
+// file : libbutl/openssl.txx -*- C++ -*-
+// copyright : Copyright (c) 2014-2017 Code Synthesis Ltd
+// license : MIT; see accompanying LICENSE file
+
+#include <utility> // move(), forward()
+
+namespace butl
+{
+ template <typename I>
+ typename std::enable_if<openssl::is_other<I>::value, I>::type openssl::
+ map_in (I&& in, io_data&)
+ {
+ return std::forward<I> (in);
+ }
+
+ template <typename O>
+ typename std::enable_if<openssl::is_other<O>::value, O>::type openssl::
+ map_out (O&& out, io_data&)
+ {
+ return std::forward<O> (out);
+ }
+
+ template <typename C,
+ typename I,
+ typename O,
+ typename E,
+ typename P,
+ typename... A>
+ openssl::
+ openssl (const C& cmdc,
+ I&& in,
+ O&& out,
+ E&& err,
+ const P& program,
+ const std::string& command,
+ A&&... options)
+ {
+ io_data in_data;
+ io_data out_data;
+
+ process& p (*this);
+ p = process_start (
+ cmdc,
+ map_in (std::forward<I> (in), in_data),
+ map_out (std::forward<O> (out), out_data),
+ std::forward<E> (err),
+ dir_path (),
+ program,
+ command,
+ in_data.options,
+ out_data.options,
+ std::forward<A> (options)...);
+
+ // Note: leaving this scope closes any open ends of the pipes in io_data.
+ }
+}
diff --git a/libbutl/sendmail.ixx b/libbutl/sendmail.ixx
index b88ee20..9746a8b 100644
--- a/libbutl/sendmail.ixx
+++ b/libbutl/sendmail.ixx
@@ -2,6 +2,7 @@
// copyright : Copyright (c) 2014-2017 Code Synthesis Ltd
// license : MIT; see accompanying LICENSE file
+#include <cstddef> // size_t
#include <utility> // move(), forward()
namespace butl
diff --git a/tests/buildfile b/tests/buildfile
index 6761a42..a721517 100644
--- a/tests/buildfile
+++ b/tests/buildfile
@@ -2,5 +2,4 @@
# copyright : Copyright (c) 2014-2017 Code Synthesis Ltd
# license : MIT; see accompanying LICENSE file
-./: {*/ -curl/ -sendmail/}
-
+./: {*/ -curl/ -openssl/ -sendmail/}
diff --git a/tests/openssl/buildfile b/tests/openssl/buildfile
new file mode 100644
index 0000000..3a3ab49
--- /dev/null
+++ b/tests/openssl/buildfile
@@ -0,0 +1,7 @@
+# file : tests/openssl/buildfile
+# copyright : Copyright (c) 2014-2017 Code Synthesis Ltd
+# license : MIT; see accompanying LICENSE file
+
+exe{driver}: cxx{driver} ../../libbutl/lib{butl} test{testscript}
+
+include ../../libbutl/
diff --git a/tests/openssl/driver.cxx b/tests/openssl/driver.cxx
new file mode 100644
index 0000000..769c77e
--- /dev/null
+++ b/tests/openssl/driver.cxx
@@ -0,0 +1,35 @@
+// file : tests/openssl/driver.cxx -*- C++ -*-
+// copyright : Copyright (c) 2014-2017 Code Synthesis Ltd
+// license : MIT; see accompanying LICENSE file
+
+#include <vector>
+#include <iostream>
+#include <iterator>
+#include <system_error>
+
+#include <libbutl/path.hxx>
+#include <libbutl/utility.hxx> // operator<<(ostream, exception)
+#include <libbutl/openssl.hxx>
+
+using namespace std;
+using namespace butl;
+
+// Usage: argv[0]
+//
+int
+main (int, const char* argv[])
+try
+{
+ openssl os (nullfd, path ("-"), 2, path ("openssl"), "rand", 128);
+
+ vector<char> r
+ ((istreambuf_iterator<char> (os.in)), istreambuf_iterator<char> ());
+
+ os.in.close ();
+ return os.wait () && r.size () == 128 ? 0 : 1;
+}
+catch (const system_error& e)
+{
+ cerr << argv[0] << ": " << e << endl;
+ return 1;
+}
diff --git a/tests/openssl/testscript b/tests/openssl/testscript
new file mode 100644
index 0000000..f0eef62
--- /dev/null
+++ b/tests/openssl/testscript
@@ -0,0 +1,5 @@
+# file : tests/openssl/testscript
+# copyright : Copyright (c) 2014-2017 Code Synthesis Ltd
+# license : MIT; see accompanying LICENSE file
+
+$*