diff options
Diffstat (limited to 'openssl/client/client.cxx')
-rw-r--r-- | openssl/client/client.cxx | 191 |
1 files changed, 191 insertions, 0 deletions
diff --git a/openssl/client/client.cxx b/openssl/client/client.cxx new file mode 100644 index 0000000..42c4f92 --- /dev/null +++ b/openssl/client/client.cxx @@ -0,0 +1,191 @@ +// file : openssl/client/client.cxx -*- C++ -*- +// copyright : Copyright (c) 2014-2018 Code Synthesis Ltd +// license : MIT; see accompanying LICENSE file + +#include <iostream> // cin, cout + +#include <libbutl/pager.mxx> + +#include <openssl/protocol.hxx> +#include <openssl/diagnostics.hxx> + +#include <openssl/client/options.hxx> + +namespace openssl +{ + namespace client + { + using namespace std; + using namespace butl; + + static int + main (int argc, char* argv[]) + try + { + // Parse the command/options. + // + string cmd; + options ops; + + int i (1); + if (argc > i && *argv[i] != '-') + cmd = argv[i++]; + + cli::argv_scanner scan (i, argc, argv); + + ops.parse (scan); + + // Version. + // + if (ops.version ()) + { + cout << "openssl-client " << OPENSSL_AGENT_VERSION_ID << endl + << "libbutl " << LIBBUTL_VERSION_ID << endl + << "Copyright (c) 2014-2018 Code Synthesis Ltd" << endl + << "This is free software released under the MIT license." + << endl; + + return 0; + } + + // Help. + // + if (ops.help ()) + { + pager p ("openssl-client help", false); + print_openssl_client_usage (p.stream ()); + + // If the pager failed, assume it has issued some diagnostics. + // + return p.wait () ? 0 : 1; + } + + if (cmd != "rsautl") + fail << "openssl-client command expected" << + info << "run '" << argv[0] << " --help' for more information"; + + if (!ops.sign ()) + fail << "-sign option is required"; + + if (!ops.keyform_specified ()) + fail << "-keyform option is required"; + + if (ops.keyform () != "engine") + fail << "invalid value '" << ops.keyform () + << "' for option -keyform"; + + if (!ops.engine_specified ()) + fail << "-engine option is required"; + + if (ops.engine () != "pkcs11") + fail << "invalid value '" << ops.engine () << "' for option -engine"; + + if (!ops.inkey_specified ()) + fail << "-inkey option is required"; + + // Obtain the agent socket path. + // + path sock_path; + + try + { + optional<string> p (getenv ("OPENSSL_AGENT_PKCS11_SOCK")); + + if (!p) + fail << "OPENSSL_AGENT_PKCS11_SOCK environment variable is not set"; + + sock_path = path (move (*p)); + } + catch (const invalid_path& e) + { + fail << "invalid OPENSSL_AGENT_PKCS11_SOCK environment variable " + << "value '" << e.path << "'"; + } + + // Read the data to sign from stdin. + // + vector<char> data; + + try + { + stdin_fdmode (fdstream_mode::binary); + + cin.exceptions (ostream::badbit | ostream::failbit); + + data = vector<char> (istreambuf_iterator<char> (cin), + istreambuf_iterator<char> ()); + } + catch (const io_error&) + { + fail << "unable to read data from stdin"; + } + + // Sign the data. + // + vector<char> signature; + + try + { + auto_fd sock (connect (sock_path)); + + ifdstream is (fddup (sock.get ())); + ofdstream os (move (sock)); + + string s (ops.simulate_specified () + ? to_string (ops.simulate ()) + : ""); + + os << request ("sign", + strings ({ops.inkey (), move (s)}), + move (data)); + os.close (); + + response r; + is >> r; + + if (r.status != 0) + { + text << r.error; + return r.status; + } + + signature = move (r.output); + } + catch (const io_error&) + { + fail << "unable to communicate with openssl-agent-pkcs11"; + } + + // Write it out. + // + try + { + stdout_fdmode (fdstream_mode::binary); + + cout.exceptions (ostream::badbit | ostream::failbit); + cout.write (signature.data (), signature.size ()); + } + catch (const io_error&) + { + fail << "error: unable to write signature to stdout"; + } + + return 0; + } + catch (const failed&) + { + return 1; // Diagnostics has already been issued. + } + catch (const cli::exception& e) + { + error << e; + return 1; + } + } +} + +int +main (int argc, char* argv[]) +{ + return openssl::client::main (argc, argv); +} |