aboutsummaryrefslogtreecommitdiff
path: root/libbutl/openssl.hxx
blob: 58e38f8a3c00132f438f8b96a1676ab883b4615f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
// file      : libbutl/openssl.hxx -*- C++ -*-
// license   : MIT; see accompanying LICENSE file

#pragma once

#include <string>
#include <type_traits>

#include <libbutl/path.hxx>
#include <libbutl/process.hxx>
#include <libbutl/fdstream.hxx>
#include <libbutl/small-vector.hxx>

#include <libbutl/export.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_SYMEXPORT openssl: public process
  {
  public:
    ifdstream in;
    ofdstream out;

    template <typename I,
              typename O,
              typename E,
              typename... A>
    openssl (I&& in,
             O&& out,
             E&& err,
             const process_env&,
             const std::string& command,
             A&&... options);

    // Version with the command line callback (see process_run_callback() for
    // details).
    //
    template <typename C,
              typename I,
              typename O,
              typename E,
              typename... A>
    openssl (const C&,
             I&& in,
             O&& out,
             E&& err,
             const process_env&,
             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;
    };

    pipe
    map_in (nullfd_t, io_data&);

    pipe
    map_in (const path&, io_data&);

    pipe
    map_in (fdstream_mode, io_data&);

    template <typename I>
    typename std::enable_if<is_other<I>::value, I>::type
    map_in (I&&, io_data&);

    pipe
    map_out (nullfd_t, io_data&);

    pipe
    map_out (const path&, io_data&);

    pipe
    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>