diff options
author | Francois Kritzinger <francois@codesynthesis.com> | 2024-02-28 10:52:08 +0200 |
---|---|---|
committer | Francois Kritzinger <francois@codesynthesis.com> | 2024-10-15 09:05:27 +0200 |
commit | bf260eb306aa90485c74217ef9c86c728d11c6da (patch) | |
tree | 8655e851fc7d5f17e9d567468efc6f90f73aa165 /mod/hmac.cxx | |
parent | 3f9c0b966b9f2d910101f60a199a957da52234a8 (diff) |
Verify webhook request HMACs
Diffstat (limited to 'mod/hmac.cxx')
-rw-r--r-- | mod/hmac.cxx | 92 |
1 files changed, 92 insertions, 0 deletions
diff --git a/mod/hmac.cxx b/mod/hmac.cxx new file mode 100644 index 0000000..dc9eca0 --- /dev/null +++ b/mod/hmac.cxx @@ -0,0 +1,92 @@ +#include <mod/hmac.hxx> + +#include <libbutl/openssl.hxx> + +using namespace std; +using namespace butl; + +string brep:: +compute_hmac (const options::openssl_options& o, + const vector<char>& m, + const char* k) +{ + try + { + fdpipe errp (fdopen_pipe ()); // stderr pipe. + + // To compute an HMAC over stdin with the key "secret": + // + // openssl mac -digest SHA256 -macopt "key:secret" HMAC + // + 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. + try + { + // In case of exception, skip and close input after output. + // + // Note: re-open in/out so that they get automatically closed on + // exception. + // + ifdstream in (os.in.release (), fdstream_mode::skip); + ofdstream out (os.out.release ()); + + // Write the message to openssl's input. + // + out.write (m.data (), m.size ()); + out.close (); + + // Read the HMAC 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 ()); + } +} |