// file : openssl/client/client.cxx -*- C++ -*- // copyright : Copyright (c) 2014-2018 Code Synthesis Ltd // license : MIT; see accompanying LICENSE file #include // cin, cout #include #include #include #include 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 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 data; try { stdin_fdmode (fdstream_mode::binary); cin.exceptions (ostream::badbit | ostream::failbit); data = vector (istreambuf_iterator (cin), istreambuf_iterator ()); } catch (const io_error&) { fail << "unable to read data from stdin"; } // Sign the data. // vector 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); }