From eedef97cd9679ae68d7c989f194d957a35a00dd1 Mon Sep 17 00:00:00 2001 From: Francois Kritzinger Date: Wed, 28 Feb 2024 10:52:08 +0200 Subject: Verify webhook request HMACs --- mod/hmac.cxx | 95 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 95 insertions(+) create mode 100644 mod/hmac.cxx (limited to 'mod/hmac.cxx') diff --git a/mod/hmac.cxx b/mod/hmac.cxx new file mode 100644 index 0000000..1a78b4c --- /dev/null +++ b/mod/hmac.cxx @@ -0,0 +1,95 @@ +#include + +#include + +using namespace std; +using namespace butl; + +string brep:: +compute_hmac (const options::openssl_options& o, + const void* m, size_t l, + const char* k) +{ + try + { + fdpipe errp (fdopen_pipe ()); // stderr pipe. + + // To compute an HMAC over stdin with the key : + // + // openssl mac -digest SHA256 -macopt "key:" HMAC + // + // Note that here we assume both output and diagnostics will fit into pipe + // buffers and don't poll both with fdselect(). + // + openssl os (path ("-"), // Read message from openssl::out. + path ("-"), // Write output to openssl::in. + process::pipe (errp.in.get (), move (errp.out)), + process_env (o.openssl (), o.openssl_envvar ()), + "mac", o.openssl_option (), + "-digest", "SHA256", + "-macopt", string ("key:") + k, + "HMAC"); + + ifdstream err (move (errp.in)); + + string h; // The HMAC value. + try + { + // In case of an exception, skip and close input after output. + // + // Note: re-open in/out so that they get automatically closed on + // an exception. + // + ifdstream in (os.in.release (), fdstream_mode::skip); + ofdstream out (os.out.release ()); + + // Write the message to openssl's input. + // + out.write (static_cast (m), l); + out.close (); + + // Read the HMAC value from openssl's output. + // + h = in.read_text (); + in.close (); + } + catch (const io_error& e) + { + // If the process exits with non-zero status, assume the IO error is due + // to that and fall through. + // + if (os.wait ()) + { + throw_generic_error ( + e.code ().value (), + (string ("unable to read/write openssl stdout/stdin: ") + + e.what ()).c_str ()); + } + } + + if (!os.wait ()) + { + string et (err.read_text ()); + throw_generic_error (EINVAL, + ("non-zero openssl exit status: " + et).c_str ()); + } + + err.close (); + + return h; + } + catch (const process_error& e) + { + throw_generic_error ( + e.code ().value (), + (string ("unable to execute openssl: ") + e.what ()).c_str ()); + } + catch (const io_error& e) + { + // Unable to read diagnostics from stderr. + // + throw_generic_error ( + e.code ().value (), + (string ("unable to read openssl stderr : ") + e.what ()).c_str ()); + } +} -- cgit v1.1