From 3bedd5e59afbce74b9008b4b23617b93e1fb324c Mon Sep 17 00:00:00 2001 From: Yan Xue Date: Wed, 22 May 2019 16:56:40 -0700 Subject: [PATCH 01/16] Expose functions for verifying digital signature Signed-off-by: Yan Xue --- source/extensions/filters/common/lua/BUILD | 1 + .../extensions/filters/http/lua/lua_filter.cc | 123 ++++++++++++ .../extensions/filters/http/lua/lua_filter.h | 62 +++++- .../filters/http/lua/lua_filter_test.cc | 183 +++++++++++++++++- .../filters/http/lua/lua_integration_test.cc | 78 ++++++++ 5 files changed, 437 insertions(+), 10 deletions(-) diff --git a/source/extensions/filters/common/lua/BUILD b/source/extensions/filters/common/lua/BUILD index 8edd21d87ec58..11de8307b2f46 100644 --- a/source/extensions/filters/common/lua/BUILD +++ b/source/extensions/filters/common/lua/BUILD @@ -14,6 +14,7 @@ envoy_cc_library( hdrs = ["lua.h"], external_deps = [ "luajit", + "ssl", ], deps = [ "//include/envoy/thread_local:thread_local_interface", diff --git a/source/extensions/filters/http/lua/lua_filter.cc b/source/extensions/filters/http/lua/lua_filter.cc index 38b997dd27e7e..d9132ce0a0efd 100644 --- a/source/extensions/filters/http/lua/lua_filter.cc +++ b/source/extensions/filters/http/lua/lua_filter.cc @@ -9,6 +9,13 @@ #include "common/common/enum_to_int.h" #include "common/http/message_impl.h" +#include "absl/strings/ascii.h" +#include "absl/strings/escaping.h" +#include "absl/strings/str_cat.h" +#include "openssl/base64.h" +#include "openssl/bytestring.h" +#include "openssl/evp.h" + namespace Envoy { namespace Extensions { namespace HttpFilters { @@ -428,6 +435,122 @@ int StreamHandleWrapper::luaLogCritical(lua_State* state) { return 0; } +int StreamHandleWrapper::luaVerifySignature(lua_State* state) { + // Step 1: get public key + auto ptr = lua_touserdata(state, 2); + auto key = reinterpret_cast(ptr); + + // Step 2: initialize EVP_MD_CTX + auto ctx = EVP_MD_CTX_new(); + + // Step 3: initialize EVP_MD + absl::string_view hashFunc = luaL_checkstring(state, 3); + const EVP_MD* md = nullptr; + hashFunc = absl::AsciiStrToLower(hashFunc); + + // Ref + // https://github.com/google/boringssl/blob/ff62b38b4b5a0e7926034b5f93d0c276e55b571d/include/openssl/digest.h#L79 + if (hashFunc == "md4") { + md = EVP_md4(); + } else if (hashFunc == "md5") { + md = EVP_md5(); + } else if (hashFunc == "sha1") { + md = EVP_sha1(); + } else if (hashFunc == "sha224") { + md = EVP_sha224(); + } else if (hashFunc == "sha256") { + md = EVP_sha256(); + } else if (hashFunc == "sha384") { + md = EVP_sha384(); + } else if (hashFunc == "sha512") { + md = EVP_sha512(); + } else if (hashFunc == "md5_sha1") { + md = EVP_md5_sha1(); + } else { + lua_pushboolean(state, false); + auto errMsg = absl::StrCat(hashFunc, " is not supported."); + lua_pushlstring(state, errMsg.data(), errMsg.length()); + EVP_MD_CTX_free(ctx); + return 2; + } + + // Step 4: initialize EVP_DigestVerify + int ok = EVP_DigestVerifyInit(ctx, nullptr, md, nullptr, key); + if (!ok) { + lua_pushboolean(state, false); + absl::string_view errMsg = "Failed to initialize digest verify."; + lua_pushlstring(state, errMsg.data(), errMsg.length()); + EVP_MD_CTX_free(ctx); + return 2; + } + + // Step 5: verify signature + const char* signature = luaL_checkstring(state, 4); + int sigLen = luaL_checknumber(state, 5); + absl::string_view sig(signature, sigLen); + + const char* clearText = luaL_checkstring(state, 6); + int textLen = luaL_checknumber(state, 7); + absl::string_view text(clearText, textLen); + + ok = EVP_DigestVerify(ctx, reinterpret_cast(sig.data()), sig.length(), + reinterpret_cast(text.data()), text.length()); + + // Step 6: check result + if (ok == 1) { + lua_pushboolean(state, true); + lua_pushnil(state); + EVP_MD_CTX_free(ctx); + return 2; + } + + lua_pushboolean(state, false); + auto errMsg = absl::StrCat("Failed to verify digest. Error code: ", ok); + lua_pushlstring(state, errMsg.data(), errMsg.length()); + EVP_MD_CTX_free(ctx); + return 2; +} + +int StreamHandleWrapper::luaDecodeBase64(lua_State* state) { + // Get input string + absl::string_view str = luaL_checkstring(state, 2); + std::string output; + + auto ok = absl::Base64Unescape(str, &output); + + if (ok) { + lua_pushlstring(state, output.data(), output.length()); + } else { + // If decode failed, push a nil into stack. + lua_pushnil(state); + } + + return 1; +} + +int StreamHandleWrapper::luaImportPublicKey(lua_State* state) { + // Get byte array the the length. + const char* str = luaL_checkstring(state, 2); + int n = luaL_checknumber(state, 3); + + absl::string_view keyder(str, n); + CBS cbs({reinterpret_cast(keyder.data()), keyder.length()}); + auto key = EVP_parse_public_key(&cbs); + if (key == nullptr) { + lua_pushnil(state); + } else { + lua_pushlightuserdata(state, key); + } + return 1; +} + +int StreamHandleWrapper::luaReleasePublicKey(lua_State* state) { + auto ptr = lua_touserdata(state, 2); + auto key = reinterpret_cast(ptr); + EVP_PKEY_free(key); + return 0; +} + FilterConfig::FilterConfig(const std::string& lua_code, ThreadLocal::SlotAllocator& tls, Upstream::ClusterManager& cluster_manager) : cluster_manager_(cluster_manager), lua_state_(lua_code, tls) { diff --git a/source/extensions/filters/http/lua/lua_filter.h b/source/extensions/filters/http/lua/lua_filter.h index c162cf38ad0b9..d6d93f15dbf10 100644 --- a/source/extensions/filters/http/lua/lua_filter.h +++ b/source/extensions/filters/http/lua/lua_filter.h @@ -127,14 +127,25 @@ class StreamHandleWrapper : public Filters::Common::Lua::BaseLuaObjectdecodeHeaders(request_headers, true)); } +// Check base64 decode. +TEST_F(LuaHttpFilterTest, CheckBase64Decode) { + const std::string SCRIPT{R"EOF( + function envoy_on_request(request_handle) + str = request_handle:decodeBase64("aGVsbG8=") + if str == nil then + request_handle:logTrace("fail") + else + request_handle:logTrace(str) + end + end + )EOF"}; + + InSequence s; + setup(SCRIPT); + + Http::TestHeaderMapImpl request_headers{{":path", "/"}}; + + EXPECT_CALL(*filter_, scriptLog(spdlog::level::trace, StrEq("hello"))); + EXPECT_EQ(Http::FilterHeadersStatus::Continue, filter_->decodeHeaders(request_headers, true)); +} + +// Check base64 decode. +TEST_F(LuaHttpFilterTest, CheckBase64DecodeFailure) { + const std::string SCRIPT{R"EOF( + function envoy_on_request(request_handle) + str = request_handle:decodeBase64(".") + if str == nil then + request_handle:logTrace("fail") + else + request_handle:logTrace(str) + end + end + )EOF"}; + + InSequence s; + setup(SCRIPT); + + Http::TestHeaderMapImpl request_headers{{":path", "/"}}; + + EXPECT_CALL(*filter_, scriptLog(spdlog::level::trace, StrEq("fail"))); + EXPECT_EQ(Http::FilterHeadersStatus::Continue, filter_->decodeHeaders(request_headers, true)); +} + +TEST_F(LuaHttpFilterTest, ImportandReleasePublicKey) { + const std::string SCRIPT{R"EOF( + function string.fromhex(str) + return (str:gsub('..', function (cc) + return string.char(tonumber(cc, 16)) + end)) + end + function envoy_on_request(request_handle) + key = "30820122300d06092a864886f70d01010105000382010f003082010a0282010100a7471266d01d160308d73409c06f2e8d35c531c458d3e480e9f3191847d062ec5ccff7bc51e949d5f2c3540c189a4eca1e8633a62cf2d0923101c27e38013e71de9ae91a704849bff7fbe2ce5bf4bd666fd9731102a53193fe5a9a5a50644ff8b1183fa897646598caad22a37f9544510836372b44c58c98586fb7144629cd8c9479592d996d32ff6d395c0b8442ec5aa1ef8051529ea0e375883cefc72c04e360b4ef8f5760650589ca814918f678eee39b884d5af8136a9630a6cc0cde157dc8e00f39540628d5f335b2c36c54c7c8bc3738a6b21acff815405afa28e5183f550dac19abcf1145a7f9ced987db680e4a229cac75dee347ec9ebce1fc3dbbbb0203010001" + raw = key:fromhex() + key = request_handle:importPublicKey(raw, string.len(raw)) + + if key == nil then + request_handle:logTrace("failed to import public key") + else + request_handle:releasePublicKey(key) + request_handle:logTrace("succeeded to import public key") + end + end + )EOF"}; + + InSequence s; + setup(SCRIPT); + + Http::TestHeaderMapImpl request_headers{{":path", "/"}}; + + EXPECT_CALL(*filter_, scriptLog(spdlog::level::trace, StrEq("succeeded to import public key"))); + EXPECT_EQ(Http::FilterHeadersStatus::Continue, filter_->decodeHeaders(request_headers, true)); +} + +TEST_F(LuaHttpFilterTest, InvalidPublicKey) { + const std::string SCRIPT{R"EOF( + function string.fromhex(str) + return (str:gsub('..', function (cc) + return string.char(tonumber(cc, 16)) + end)) + end + function envoy_on_request(request_handle) + key = "0000" + raw = key:fromhex() + key = request_handle:importPublicKey(raw, string.len(raw)) + + if key == nil then + request_handle:logTrace("failed to import public key") + else + request_handle:releasePublicKey(key) + request_handle:logTrace("succeeded to import public key") + end + end + )EOF"}; + + InSequence s; + setup(SCRIPT); + + Http::TestHeaderMapImpl request_headers{{":path", "/"}}; + + EXPECT_CALL(*filter_, scriptLog(spdlog::level::trace, StrEq("failed to import public key"))); + EXPECT_EQ(Http::FilterHeadersStatus::Continue, filter_->decodeHeaders(request_headers, true)); +} + +TEST_F(LuaHttpFilterTest, SignatureVerify) { + const std::string SCRIPT{R"EOF( + function string.fromhex(str) + return (str:gsub('..', function (cc) + return string.char(tonumber(cc, 16)) + end)) + end + function envoy_on_request(request_handle) + key = "30820122300d06092a864886f70d01010105000382010f003082010a0282010100a7471266d01d160308d73409c06f2e8d35c531c458d3e480e9f3191847d062ec5ccff7bc51e949d5f2c3540c189a4eca1e8633a62cf2d0923101c27e38013e71de9ae91a704849bff7fbe2ce5bf4bd666fd9731102a53193fe5a9a5a50644ff8b1183fa897646598caad22a37f9544510836372b44c58c98586fb7144629cd8c9479592d996d32ff6d395c0b8442ec5aa1ef8051529ea0e375883cefc72c04e360b4ef8f5760650589ca814918f678eee39b884d5af8136a9630a6cc0cde157dc8e00f39540628d5f335b2c36c54c7c8bc3738a6b21acff815405afa28e5183f550dac19abcf1145a7f9ced987db680e4a229cac75dee347ec9ebce1fc3dbbbb0203010001" + hashFunc = "sha256" + signature = "345ac3a167558f4f387a81c2d64234d901a7ceaa544db779d2f797b0ea4ef851b740905a63e2f4d5af42cee093a29c7155db9a63d3d483e0ef948f5ac51ce4e10a3a6606fd93ef68ee47b30c37491103039459122f78e1c7ea71a1a5ea24bb6519bca02c8c9915fe8be24927c91812a13db72dbcb500103a79e8f67ff8cb9e2a631974e0668ab3977bf570a91b67d1b6bcd5dce84055f21427d64f4256a042ab1dc8e925d53a769f6681a873f5859693a7728fcbe95beace1563b5ffbcd7c93b898aeba31421dafbfadeea50229c49fd6c445449314460f3d19150bd29a91333beaced557ed6295234f7c14fa46303b7e977d2c89ba8a39a46a35f33eb07a332" + data = "hello" + + rawkey = key:fromhex() + pkey = request_handle:importPublicKey(rawkey, string.len(rawkey)) + + if pkey == nil then + request_handle:logTrace("failed to import public key") + return + end + + rawsig = signature:fromhex() + + ok, error = request_handle:verifySignature(pkey, hashFunc, rawsig, string.len(rawsig), data, string.len(data)) + if ok then + request_handle:logTrace("signature is valid") + else + request_handle:logTrace(error) + end + + ok, error = request_handle:verifySignature(pkey, "unknown", rawsig, string.len(rawsig), data, string.len(data)) + if ok then + request_handle:logTrace("signature is valid") + else + request_handle:logTrace(error) + end + + ok, error = request_handle:verifySignature(pkey, hashFunc, "0000", 4, data, string.len(data)) + if ok then + request_handle:logTrace("signature is valid") + else + request_handle:logTrace(error) + end + + ok, error = request_handle:verifySignature(pkey, hashFunc, rawsig, string.len(rawsig), "xxxx", 4) + if ok then + request_handle:logTrace("signature is valid") + else + request_handle:logTrace(error) + end + + request_handle:releasePublicKey(pkey) + end + )EOF"}; + + InSequence s; + setup(SCRIPT); + + Http::TestHeaderMapImpl request_headers{{":path", "/"}}; + + EXPECT_CALL(*filter_, scriptLog(spdlog::level::trace, StrEq("signature is valid"))); + EXPECT_CALL(*filter_, scriptLog(spdlog::level::trace, StrEq("unknown is not supported."))); + EXPECT_CALL(*filter_, + scriptLog(spdlog::level::trace, StrEq("Failed to verify digest. Error code: 0"))); + EXPECT_CALL(*filter_, + scriptLog(spdlog::level::trace, StrEq("Failed to verify digest. Error code: 0"))); + EXPECT_EQ(Http::FilterHeadersStatus::Continue, filter_->decodeHeaders(request_headers, true)); +} + } // namespace } // namespace Lua } // namespace HttpFilters diff --git a/test/extensions/filters/http/lua/lua_integration_test.cc b/test/extensions/filters/http/lua/lua_integration_test.cc index bad8a03574727..e5286272c5fdd 100644 --- a/test/extensions/filters/http/lua/lua_integration_test.cc +++ b/test/extensions/filters/http/lua/lua_integration_test.cc @@ -53,6 +53,8 @@ class LuaIntegrationTest : public testing::TestWithParammakeHeaderOnlyRequest(request_headers); + waitForNextUpstreamRequest(); + + EXPECT_EQ("approved", upstream_request_->headers() + .get(Http::LowerCaseString("signature_verification")) + ->value() + .getStringView()); + + upstream_request_->encodeHeaders(default_response_headers_, true); + response->waitForEndStream(); + + EXPECT_TRUE(response->complete()); + EXPECT_EQ("200", response->headers().Status()->value().getStringView()); + + cleanup(); +} + } // namespace } // namespace Envoy From 05854ec5ab881f814d87bd5325e912df02a3a4ef Mon Sep 17 00:00:00 2001 From: Yan Xue Date: Wed, 22 May 2019 17:42:31 -0700 Subject: [PATCH 02/16] Add release note and document Signed-off-by: Yan Xue --- .../configuration/http_filters/lua_filter.rst | 51 +++++++++++++++++++ docs/root/intro/version_history.rst | 1 + 2 files changed, 52 insertions(+) diff --git a/docs/root/configuration/http_filters/lua_filter.rst b/docs/root/configuration/http_filters/lua_filter.rst index 815e5aef96322..64b02794b5a9e 100644 --- a/docs/root/configuration/http_filters/lua_filter.rst +++ b/docs/root/configuration/http_filters/lua_filter.rst @@ -312,6 +312,57 @@ Returns the current request's underlying :repo:`connection `. +importPublicKey() +^^^^^^^^^^^^^^^^^ + +.. code-block:: lua + + pkey = handle:importPublicKey(keyder, keyderLenght) + +Returns public key which is used by :ref:`verifySignature ` to verify digital signature. + +.. attention:: + + Remember to call :ref:`releasePublicKey ` if *pkey* is not needed to avoid memory leak. + +.. _release_public_key: + +releasePublicKey() +^^^^^^^^^^^^^^^^^^ + +.. code-block:: lua + + handle:releasePublicKey(pkey) + +Free the resource of *pkey* + +decodeBase64() +^^^^^^^^^^^^^^ + +.. code-block:: lua + + raw = request_handle:decodeBase64(str) + +Decodes base64 encoded string. Returns *nil* if input string is invalid. + +.. _verify_signature: + +verifySignature() +^^^^^^^^^^^^^^^^^ + +.. code-block:: lua + + ok, error = verifySignature(pkey, hashFunction, signature, signatureLength, data, dataLength) + +Verify signature using provided parameters. *pkey* is the public key, *hashFunction* is the variable +for hash function which be used for verifying signature. *MD4*, *MD5*, *SHA1*, *SHA224*, *SHA256*, +*SHA384*, *SHA512* and *MD5_SHA1* are supported. *signature* is the signature to be verified. +*signatureLength* is the length of the signature. *data* is the content which will be hashed. +*dataLength* is the length of data. + +The function returns a pair. If the first element is *true*, the second element will be empty +which means signature is verified; otherwise, the second element will store the error message. + .. _config_http_filters_lua_header_wrapper: Header object API diff --git a/docs/root/intro/version_history.rst b/docs/root/intro/version_history.rst index 5666890b05463..3f1aa1211f7e5 100644 --- a/docs/root/intro/version_history.rst +++ b/docs/root/intro/version_history.rst @@ -17,6 +17,7 @@ Version history * ext_authz: added a `x-envoy-auth-partial-body` metadata header set to `false|true` indicating if there is a partial body sent in the authorization request message. * ext_authz: added configurable status code that allows customizing HTTP responses on filter check status errors. * ext_authz: added option to `ext_authz` that allows the filter clearing route cache. +* filter: exposed functions to Lua to verify digital signature. * grpc-json: added support for :ref:`auto mapping `. * health check: added :ref:`initial jitter ` to add jitter to the first health check in order to prevent thundering herd on Envoy startup. From dd3aa1713fcf8b316f1ad9d3224092f7ea33f785 Mon Sep 17 00:00:00 2001 From: Yan Xue Date: Wed, 22 May 2019 18:26:08 -0700 Subject: [PATCH 03/16] refactor Signed-off-by: Yan Xue --- .../extensions/filters/http/lua/lua_filter.cc | 51 +++++++++++-------- .../extensions/filters/http/lua/lua_filter.h | 4 ++ 2 files changed, 33 insertions(+), 22 deletions(-) diff --git a/source/extensions/filters/http/lua/lua_filter.cc b/source/extensions/filters/http/lua/lua_filter.cc index d9132ce0a0efd..b765749222bee 100644 --- a/source/extensions/filters/http/lua/lua_filter.cc +++ b/source/extensions/filters/http/lua/lua_filter.cc @@ -435,6 +435,32 @@ int StreamHandleWrapper::luaLogCritical(lua_State* state) { return 0; } +const EVP_MD* StreamHandleWrapper::getDigest(const absl::string_view& name) { + auto hash = absl::AsciiStrToLower(name); + + // Hash Hash algorithms set refers + // https://github.com/google/boringssl/blob/ff62b38b4b5a0e7926034b5f93d0c276e55b571d/include/openssl/digest.h + if (hash == "md4") { + return EVP_md4(); + } else if (hash == "md5") { + return EVP_md5(); + } else if (hash == "sha1") { + return EVP_sha1(); + } else if (hash == "sha224") { + return EVP_sha224(); + } else if (hash == "sha256") { + return EVP_sha256(); + } else if (hash == "sha384") { + return EVP_sha384(); + } else if (hash == "sha512") { + return EVP_sha512(); + } else if (hash == "md5_sha1") { + return EVP_md5_sha1(); + } else { + return nullptr; + } +} + int StreamHandleWrapper::luaVerifySignature(lua_State* state) { // Step 1: get public key auto ptr = lua_touserdata(state, 2); @@ -445,28 +471,9 @@ int StreamHandleWrapper::luaVerifySignature(lua_State* state) { // Step 3: initialize EVP_MD absl::string_view hashFunc = luaL_checkstring(state, 3); - const EVP_MD* md = nullptr; - hashFunc = absl::AsciiStrToLower(hashFunc); - - // Ref - // https://github.com/google/boringssl/blob/ff62b38b4b5a0e7926034b5f93d0c276e55b571d/include/openssl/digest.h#L79 - if (hashFunc == "md4") { - md = EVP_md4(); - } else if (hashFunc == "md5") { - md = EVP_md5(); - } else if (hashFunc == "sha1") { - md = EVP_sha1(); - } else if (hashFunc == "sha224") { - md = EVP_sha224(); - } else if (hashFunc == "sha256") { - md = EVP_sha256(); - } else if (hashFunc == "sha384") { - md = EVP_sha384(); - } else if (hashFunc == "sha512") { - md = EVP_sha512(); - } else if (hashFunc == "md5_sha1") { - md = EVP_md5_sha1(); - } else { + auto md = getDigest(hashFunc); + + if (md == nullptr) { lua_pushboolean(state, false); auto errMsg = absl::StrCat(hashFunc, " is not supported."); lua_pushlstring(state, errMsg.data(), errMsg.length()); diff --git a/source/extensions/filters/http/lua/lua_filter.h b/source/extensions/filters/http/lua/lua_filter.h index d6d93f15dbf10..7b78966d780bd 100644 --- a/source/extensions/filters/http/lua/lua_filter.h +++ b/source/extensions/filters/http/lua/lua_filter.h @@ -7,6 +7,8 @@ #include "extensions/filters/http/lua/wrappers.h" #include "extensions/filters/http/well_known_names.h" +#include "openssl/evp.h" + namespace Envoy { namespace Extensions { namespace HttpFilters { @@ -262,6 +264,8 @@ class StreamHandleWrapper : public Filters::Common::Lua::BaseLuaObject Date: Wed, 22 May 2019 19:31:44 -0700 Subject: [PATCH 04/16] Revert unnecessary change Signed-off-by: Yan Xue --- test/extensions/filters/http/lua/lua_filter_test.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/extensions/filters/http/lua/lua_filter_test.cc b/test/extensions/filters/http/lua/lua_filter_test.cc index 491b83ea513f1..8e5c53b22fb43 100644 --- a/test/extensions/filters/http/lua/lua_filter_test.cc +++ b/test/extensions/filters/http/lua/lua_filter_test.cc @@ -85,8 +85,8 @@ class LuaHttpFilterTest : public testing::Test { } void setupSecureConnection(const bool secure) { - EXPECT_CALL(decoder_callbacks_, connection()).WillRepeatedly(Return(&connection_)); - EXPECT_CALL(Const(connection_), ssl()).WillRepeatedly(Return(secure ? &ssl_ : nullptr)); + EXPECT_CALL(decoder_callbacks_, connection()).WillOnce(Return(&connection_)); + EXPECT_CALL(Const(connection_), ssl()).Times(1).WillOnce(Return(secure ? &ssl_ : nullptr)); } void setupMetadata(const std::string& yaml) { From 85cec32eadbddd0d2389730d926a3d27776c45ba Mon Sep 17 00:00:00 2001 From: Yan Xue Date: Mon, 27 May 2019 11:33:08 -0700 Subject: [PATCH 05/16] CR requested change Signed-off-by: Yan Xue --- source/extensions/filters/http/lua/lua_filter.cc | 16 ++++++++-------- source/extensions/filters/http/lua/lua_filter.h | 2 +- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/source/extensions/filters/http/lua/lua_filter.cc b/source/extensions/filters/http/lua/lua_filter.cc index b765749222bee..368421803eece 100644 --- a/source/extensions/filters/http/lua/lua_filter.cc +++ b/source/extensions/filters/http/lua/lua_filter.cc @@ -470,13 +470,13 @@ int StreamHandleWrapper::luaVerifySignature(lua_State* state) { auto ctx = EVP_MD_CTX_new(); // Step 3: initialize EVP_MD - absl::string_view hashFunc = luaL_checkstring(state, 3); - auto md = getDigest(hashFunc); + absl::string_view hash_func = luaL_checkstring(state, 3); + auto md = getDigest(hash_func); if (md == nullptr) { lua_pushboolean(state, false); - auto errMsg = absl::StrCat(hashFunc, " is not supported."); - lua_pushlstring(state, errMsg.data(), errMsg.length()); + auto err_msg = absl::StrCat(hash_func, " is not supported."); + lua_pushlstring(state, err_msg.data(), err_msg.length()); EVP_MD_CTX_free(ctx); return 2; } @@ -485,8 +485,8 @@ int StreamHandleWrapper::luaVerifySignature(lua_State* state) { int ok = EVP_DigestVerifyInit(ctx, nullptr, md, nullptr, key); if (!ok) { lua_pushboolean(state, false); - absl::string_view errMsg = "Failed to initialize digest verify."; - lua_pushlstring(state, errMsg.data(), errMsg.length()); + absl::string_view err_msg = "Failed to initialize digest verify."; + lua_pushlstring(state, err_msg.data(), err_msg.length()); EVP_MD_CTX_free(ctx); return 2; } @@ -512,8 +512,8 @@ int StreamHandleWrapper::luaVerifySignature(lua_State* state) { } lua_pushboolean(state, false); - auto errMsg = absl::StrCat("Failed to verify digest. Error code: ", ok); - lua_pushlstring(state, errMsg.data(), errMsg.length()); + auto err_msg = absl::StrCat("Failed to verify digest. Error code: ", ok); + lua_pushlstring(state, err_msg.data(), err_msg.length()); EVP_MD_CTX_free(ctx); return 2; } diff --git a/source/extensions/filters/http/lua/lua_filter.h b/source/extensions/filters/http/lua/lua_filter.h index 7b78966d780bd..c702553108bd6 100644 --- a/source/extensions/filters/http/lua/lua_filter.h +++ b/source/extensions/filters/http/lua/lua_filter.h @@ -264,7 +264,7 @@ class StreamHandleWrapper : public Filters::Common::Lua::BaseLuaObject Date: Wed, 29 May 2019 09:27:58 -0700 Subject: [PATCH 06/16] Change comment Signed-off-by: Yan Xue --- test/extensions/filters/http/lua/lua_integration_test.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/extensions/filters/http/lua/lua_integration_test.cc b/test/extensions/filters/http/lua/lua_integration_test.cc index e5286272c5fdd..dad6877c40377 100644 --- a/test/extensions/filters/http/lua/lua_integration_test.cc +++ b/test/extensions/filters/http/lua/lua_integration_test.cc @@ -389,7 +389,7 @@ name: envoy.lua cleanup(); } -// Basic request and response. +// Basic test for verifying signature. TEST_P(LuaIntegrationTest, SignatureVerification) { const std::string FILTER_AND_CODE = R"EOF( From 8d33bd55cf3b3ea0bcbc11b037a09d7cd9d838fa Mon Sep 17 00:00:00 2001 From: Yan Xue Date: Thu, 30 May 2019 14:23:58 -0700 Subject: [PATCH 07/16] Replace auto with type Signed-off-by: Yan Xue --- source/extensions/filters/http/lua/lua_filter.cc | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/source/extensions/filters/http/lua/lua_filter.cc b/source/extensions/filters/http/lua/lua_filter.cc index 368421803eece..a8ea2e9270594 100644 --- a/source/extensions/filters/http/lua/lua_filter.cc +++ b/source/extensions/filters/http/lua/lua_filter.cc @@ -436,7 +436,7 @@ int StreamHandleWrapper::luaLogCritical(lua_State* state) { } const EVP_MD* StreamHandleWrapper::getDigest(const absl::string_view& name) { - auto hash = absl::AsciiStrToLower(name); + std::string hash = absl::AsciiStrToLower(name); // Hash Hash algorithms set refers // https://github.com/google/boringssl/blob/ff62b38b4b5a0e7926034b5f93d0c276e55b571d/include/openssl/digest.h @@ -467,15 +467,15 @@ int StreamHandleWrapper::luaVerifySignature(lua_State* state) { auto key = reinterpret_cast(ptr); // Step 2: initialize EVP_MD_CTX - auto ctx = EVP_MD_CTX_new(); + EVP_MD_CTX* ctx = EVP_MD_CTX_new(); // Step 3: initialize EVP_MD absl::string_view hash_func = luaL_checkstring(state, 3); - auto md = getDigest(hash_func); + const EVP_MD* md = getDigest(hash_func); if (md == nullptr) { lua_pushboolean(state, false); - auto err_msg = absl::StrCat(hash_func, " is not supported."); + std::string err_msg = absl::StrCat(hash_func, " is not supported."); lua_pushlstring(state, err_msg.data(), err_msg.length()); EVP_MD_CTX_free(ctx); return 2; @@ -512,7 +512,7 @@ int StreamHandleWrapper::luaVerifySignature(lua_State* state) { } lua_pushboolean(state, false); - auto err_msg = absl::StrCat("Failed to verify digest. Error code: ", ok); + std::string err_msg = absl::StrCat("Failed to verify digest. Error code: ", ok); lua_pushlstring(state, err_msg.data(), err_msg.length()); EVP_MD_CTX_free(ctx); return 2; @@ -523,7 +523,7 @@ int StreamHandleWrapper::luaDecodeBase64(lua_State* state) { absl::string_view str = luaL_checkstring(state, 2); std::string output; - auto ok = absl::Base64Unescape(str, &output); + bool ok = absl::Base64Unescape(str, &output); if (ok) { lua_pushlstring(state, output.data(), output.length()); @@ -536,13 +536,13 @@ int StreamHandleWrapper::luaDecodeBase64(lua_State* state) { } int StreamHandleWrapper::luaImportPublicKey(lua_State* state) { - // Get byte array the the length. + // Get byte array and the length. const char* str = luaL_checkstring(state, 2); int n = luaL_checknumber(state, 3); absl::string_view keyder(str, n); CBS cbs({reinterpret_cast(keyder.data()), keyder.length()}); - auto key = EVP_parse_public_key(&cbs); + EVP_PKEY* key = EVP_parse_public_key(&cbs); if (key == nullptr) { lua_pushnil(state); } else { From e83fb9bf806ab117b0d3cbecd441eee1e9117d4f Mon Sep 17 00:00:00 2001 From: Yan Xue Date: Mon, 3 Jun 2019 20:15:12 -0700 Subject: [PATCH 08/16] Decouple Lua bind and OpenSSL functions Signed-off-by: Yan Xue --- .../configuration/http_filters/lua_filter.rst | 2 +- source/common/crypto/utility.cc | 77 ++++++++++++- source/common/crypto/utility.h | 43 ++++++++ source/extensions/filters/common/lua/BUILD | 1 - source/extensions/filters/http/lua/BUILD | 1 + .../extensions/filters/http/lua/lua_filter.cc | 102 ++++-------------- .../extensions/filters/http/lua/lua_filter.h | 2 - test/common/crypto/utility_test.cc | 79 ++++++++++++++ 8 files changed, 221 insertions(+), 86 deletions(-) diff --git a/docs/root/configuration/http_filters/lua_filter.rst b/docs/root/configuration/http_filters/lua_filter.rst index 64b02794b5a9e..c439acae31f06 100644 --- a/docs/root/configuration/http_filters/lua_filter.rst +++ b/docs/root/configuration/http_filters/lua_filter.rst @@ -323,7 +323,7 @@ Returns public key which is used by :ref:`verifySignature ` to .. attention:: - Remember to call :ref:`releasePublicKey ` if *pkey* is not needed to avoid memory leak. + Remember to call :ref:`releasePublicKey ` when *pkey* is not needed to avoid memory leak. .. _release_public_key: diff --git a/source/common/crypto/utility.cc b/source/common/crypto/utility.cc index 885b4c0bbcaba..82e273c5fea9b 100644 --- a/source/common/crypto/utility.cc +++ b/source/common/crypto/utility.cc @@ -3,7 +3,9 @@ #include "common/common/assert.h" #include "common/common/stack_array.h" -#include "openssl/evp.h" +#include "absl/strings/ascii.h" +#include "absl/strings/str_cat.h" +#include "openssl/bytestring.h" #include "openssl/hmac.h" #include "openssl/sha.h" @@ -41,6 +43,79 @@ std::vector Utility::getSha256Hmac(const std::vector& key, return hmac; } +VerificationOutput Utility::verifySignature(void* ptr, const absl::string_view& hash, + const std::vector& signature, + const std::vector& clearText) { + // Step 1: get public key + auto key = reinterpret_cast(ptr); + + // Step 2: initialize EVP_MD_CTX + EVP_MD_CTX* ctx = EVP_MD_CTX_new(); + + // Step 3: initialize EVP_MD + const EVP_MD* md = Utility::getHashFunction(hash); + + if (md == nullptr) { + EVP_MD_CTX_free(ctx); + return {false, absl::StrCat(hash, " is not supported.")}; + } + + // Step 4: initialize EVP_DigestVerify + int ok = EVP_DigestVerifyInit(ctx, nullptr, md, nullptr, key); + if (!ok) { + EVP_MD_CTX_free(ctx); + return {false, "Failed to initialize digest verify."}; + } + + // Step 5: verify signature + ok = + EVP_DigestVerify(ctx, signature.data(), signature.size(), clearText.data(), clearText.size()); + + // Step 6: check result + if (ok == 1) { + EVP_MD_CTX_free(ctx); + return {true, ""}; + } + + EVP_MD_CTX_free(ctx); + std::string err_msg; + absl::StrAppend(&err_msg, "Failed to verify digest. Error code: ", ok); + return {false, err_msg}; +} + +void* Utility::importPublicKey(const std::vector& key) { + CBS cbs({key.data(), key.size()}); + return EVP_parse_public_key(&cbs); +} + +void Utility::releasePublicKey(void* ptr) { EVP_PKEY_free(reinterpret_cast(ptr)); } + +const EVP_MD* Utility::getHashFunction(const absl::string_view& name) { + std::string hash = absl::AsciiStrToLower(name); + + // Hash algorithms set refers + // https://github.com/google/boringssl/blob/master/include/openssl/digest.h + if (hash == "md4") { + return EVP_md4(); + } else if (hash == "md5") { + return EVP_md5(); + } else if (hash == "sha1") { + return EVP_sha1(); + } else if (hash == "sha224") { + return EVP_sha224(); + } else if (hash == "sha256") { + return EVP_sha256(); + } else if (hash == "sha384") { + return EVP_sha384(); + } else if (hash == "sha512") { + return EVP_sha512(); + } else if (hash == "md5_sha1") { + return EVP_md5_sha1(); + } else { + return nullptr; + } +} + } // namespace Crypto } // namespace Common } // namespace Envoy diff --git a/source/common/crypto/utility.h b/source/common/crypto/utility.h index f755aaf0a7dc4..5dd5599fd42c3 100644 --- a/source/common/crypto/utility.h +++ b/source/common/crypto/utility.h @@ -6,11 +6,24 @@ #include "envoy/buffer/buffer.h" #include "absl/strings/string_view.h" +#include "openssl/evp.h" namespace Envoy { namespace Common { namespace Crypto { +struct VerificationOutput { + /** + * Verification result. If result_ is true, error_message_ is empty. + */ + bool result_; + + /** + * Error message when verification failed. + */ + std::string error_message_; +}; + class Utility { public: /** @@ -28,6 +41,36 @@ class Utility { */ static std::vector getSha256Hmac(const std::vector& key, absl::string_view message); + + /** + * Verify cryptographic signatures. + * @param key pointer to public key + * @param hash hash function(including MD4, MD5, SHA1, SHA224, SHA256, SHA384, SHA512, + * MD5_SHA1) + * @param signature signature + * @param clearText clear text + * @return If the result_ is true, the error_message_ is empty; otherwise, + * the error_message_ stores the error message + */ + static VerificationOutput verifySignature(void* key, const absl::string_view& hash, + const std::vector& signature, + const std::vector& clearText); + + /** + * Import public key. + * @param key key string + * @return pointer to public key + */ + static void* importPublicKey(const std::vector& key); + + /** + * Release public key. + * @param key pointer to public key + */ + static void releasePublicKey(void* key); + +private: + static const EVP_MD* getHashFunction(const absl::string_view& name); }; } // namespace Crypto diff --git a/source/extensions/filters/common/lua/BUILD b/source/extensions/filters/common/lua/BUILD index 11de8307b2f46..8edd21d87ec58 100644 --- a/source/extensions/filters/common/lua/BUILD +++ b/source/extensions/filters/common/lua/BUILD @@ -14,7 +14,6 @@ envoy_cc_library( hdrs = ["lua.h"], external_deps = [ "luajit", - "ssl", ], deps = [ "//include/envoy/thread_local:thread_local_interface", diff --git a/source/extensions/filters/http/lua/BUILD b/source/extensions/filters/http/lua/BUILD index de27cd3a70471..61711704d1906 100644 --- a/source/extensions/filters/http/lua/BUILD +++ b/source/extensions/filters/http/lua/BUILD @@ -22,6 +22,7 @@ envoy_cc_library( "//include/envoy/upstream:cluster_manager_interface", "//source/common/buffer:buffer_lib", "//source/common/common:enum_to_int", + "//source/common/crypto:utility_lib", "//source/common/http:message_lib", "//source/extensions/filters/common/lua:lua_lib", "//source/extensions/filters/common/lua:wrappers_lib", diff --git a/source/extensions/filters/http/lua/lua_filter.cc b/source/extensions/filters/http/lua/lua_filter.cc index a8ea2e9270594..40dcdcd50766f 100644 --- a/source/extensions/filters/http/lua/lua_filter.cc +++ b/source/extensions/filters/http/lua/lua_filter.cc @@ -7,14 +7,10 @@ #include "common/buffer/buffer_impl.h" #include "common/common/assert.h" #include "common/common/enum_to_int.h" +#include "common/crypto/utility.h" #include "common/http/message_impl.h" -#include "absl/strings/ascii.h" #include "absl/strings/escaping.h" -#include "absl/strings/str_cat.h" -#include "openssl/base64.h" -#include "openssl/bytestring.h" -#include "openssl/evp.h" namespace Envoy { namespace Extensions { @@ -435,86 +431,32 @@ int StreamHandleWrapper::luaLogCritical(lua_State* state) { return 0; } -const EVP_MD* StreamHandleWrapper::getDigest(const absl::string_view& name) { - std::string hash = absl::AsciiStrToLower(name); - - // Hash Hash algorithms set refers - // https://github.com/google/boringssl/blob/ff62b38b4b5a0e7926034b5f93d0c276e55b571d/include/openssl/digest.h - if (hash == "md4") { - return EVP_md4(); - } else if (hash == "md5") { - return EVP_md5(); - } else if (hash == "sha1") { - return EVP_sha1(); - } else if (hash == "sha224") { - return EVP_sha224(); - } else if (hash == "sha256") { - return EVP_sha256(); - } else if (hash == "sha384") { - return EVP_sha384(); - } else if (hash == "sha512") { - return EVP_sha512(); - } else if (hash == "md5_sha1") { - return EVP_md5_sha1(); - } else { - return nullptr; - } -} - int StreamHandleWrapper::luaVerifySignature(lua_State* state) { - // Step 1: get public key + // Step 1: get key pointer auto ptr = lua_touserdata(state, 2); - auto key = reinterpret_cast(ptr); - - // Step 2: initialize EVP_MD_CTX - EVP_MD_CTX* ctx = EVP_MD_CTX_new(); - - // Step 3: initialize EVP_MD - absl::string_view hash_func = luaL_checkstring(state, 3); - const EVP_MD* md = getDigest(hash_func); - if (md == nullptr) { - lua_pushboolean(state, false); - std::string err_msg = absl::StrCat(hash_func, " is not supported."); - lua_pushlstring(state, err_msg.data(), err_msg.length()); - EVP_MD_CTX_free(ctx); - return 2; - } - - // Step 4: initialize EVP_DigestVerify - int ok = EVP_DigestVerifyInit(ctx, nullptr, md, nullptr, key); - if (!ok) { - lua_pushboolean(state, false); - absl::string_view err_msg = "Failed to initialize digest verify."; - lua_pushlstring(state, err_msg.data(), err_msg.length()); - EVP_MD_CTX_free(ctx); - return 2; - } + // Step 2: get hash function + absl::string_view hash = luaL_checkstring(state, 3); - // Step 5: verify signature + // Step 3: get signature const char* signature = luaL_checkstring(state, 4); int sigLen = luaL_checknumber(state, 5); - absl::string_view sig(signature, sigLen); + std::vector sigVec(signature, signature + sigLen); + // Step 4: get clear text const char* clearText = luaL_checkstring(state, 6); int textLen = luaL_checknumber(state, 7); - absl::string_view text(clearText, textLen); + std::vector textVec(clearText, clearText + textLen); - ok = EVP_DigestVerify(ctx, reinterpret_cast(sig.data()), sig.length(), - reinterpret_cast(text.data()), text.length()); + // Step 5: verify signature + auto output = Common::Crypto::Utility::verifySignature(ptr, hash, sigVec, textVec); - // Step 6: check result - if (ok == 1) { - lua_pushboolean(state, true); + lua_pushboolean(state, output.result_); + if (output.result_) { lua_pushnil(state); - EVP_MD_CTX_free(ctx); - return 2; + } else { + lua_pushlstring(state, output.error_message_.data(), output.error_message_.length()); } - - lua_pushboolean(state, false); - std::string err_msg = absl::StrCat("Failed to verify digest. Error code: ", ok); - lua_pushlstring(state, err_msg.data(), err_msg.length()); - EVP_MD_CTX_free(ctx); return 2; } @@ -539,22 +481,20 @@ int StreamHandleWrapper::luaImportPublicKey(lua_State* state) { // Get byte array and the length. const char* str = luaL_checkstring(state, 2); int n = luaL_checknumber(state, 3); + std::vector keyVec(str, str + n); - absl::string_view keyder(str, n); - CBS cbs({reinterpret_cast(keyder.data()), keyder.length()}); - EVP_PKEY* key = EVP_parse_public_key(&cbs); - if (key == nullptr) { - lua_pushnil(state); - } else { + auto key = Common::Crypto::Utility::importPublicKey(keyVec); + if (key != nullptr) { lua_pushlightuserdata(state, key); + } else { + lua_pushnil(state); } + return 1; } int StreamHandleWrapper::luaReleasePublicKey(lua_State* state) { - auto ptr = lua_touserdata(state, 2); - auto key = reinterpret_cast(ptr); - EVP_PKEY_free(key); + Common::Crypto::Utility::releasePublicKey(lua_touserdata(state, 2)); return 0; } diff --git a/source/extensions/filters/http/lua/lua_filter.h b/source/extensions/filters/http/lua/lua_filter.h index c702553108bd6..3132ff16901f7 100644 --- a/source/extensions/filters/http/lua/lua_filter.h +++ b/source/extensions/filters/http/lua/lua_filter.h @@ -264,8 +264,6 @@ class StreamHandleWrapper : public Filters::Common::Lua::BaseLuaObject text(data, data + strlen(data)); + + auto result = Utility::verifySignature(pubKey, hashFunc, sig, text); + + EXPECT_EQ(true, result.result_); + EXPECT_EQ("", result.error_message_); + + hashFunc = "unknown"; + result = Utility::verifySignature(pubKey, hashFunc, sig, text); + EXPECT_EQ(false, result.result_); + EXPECT_EQ("unknown is not supported.", result.error_message_); + + hashFunc = "sha256"; + result = Utility::verifySignature(nullptr, hashFunc, sig, text); + EXPECT_EQ(false, result.result_); + EXPECT_EQ("Failed to initialize digest verify.", result.error_message_); + + data = "baddata"; + text = std::vector(data, data + strlen(data)); + result = Utility::verifySignature(pubKey, hashFunc, sig, text); + EXPECT_EQ(false, result.result_); + EXPECT_EQ("Failed to verify digest. Error code: 0", result.error_message_); + + data = "hello"; + text = std::vector(data, data + strlen(data)); + signature = "000000"; + sig = Hex::decode(signature); + result = Utility::verifySignature(pubKey, hashFunc, sig, text); + EXPECT_EQ(false, result.result_); + EXPECT_EQ("Failed to verify digest. Error code: 0", result.error_message_); + + Utility::releasePublicKey(pubKey); +} + } // namespace } // namespace Crypto } // namespace Common From 3300c17f4914e206bc6e384e4704632e41969ce8 Mon Sep 17 00:00:00 2001 From: Yan Xue Date: Tue, 4 Jun 2019 09:49:43 -0700 Subject: [PATCH 09/16] Remove decodebase64 and change pkey to pubkey Signed-off-by: Yan Xue --- .../configuration/http_filters/lua_filter.rst | 28 +++----- source/common/crypto/utility.cc | 14 ++-- source/common/crypto/utility.h | 5 +- .../extensions/filters/http/lua/lua_filter.cc | 27 ++------ .../extensions/filters/http/lua/lua_filter.h | 15 +---- test/common/crypto/utility_test.cc | 10 +-- .../filters/http/lua/lua_filter_test.cc | 64 ++----------------- .../filters/http/lua/lua_integration_test.cc | 27 ++++++-- 8 files changed, 56 insertions(+), 134 deletions(-) diff --git a/docs/root/configuration/http_filters/lua_filter.rst b/docs/root/configuration/http_filters/lua_filter.rst index c439acae31f06..401b6b30694c7 100644 --- a/docs/root/configuration/http_filters/lua_filter.rst +++ b/docs/root/configuration/http_filters/lua_filter.rst @@ -317,13 +317,13 @@ importPublicKey() .. code-block:: lua - pkey = handle:importPublicKey(keyder, keyderLenght) + pubkey = handle:importPublicKey(keyder, keyderLenght) Returns public key which is used by :ref:`verifySignature ` to verify digital signature. .. attention:: - Remember to call :ref:`releasePublicKey ` when *pkey* is not needed to avoid memory leak. + Remember to call :ref:`releasePublicKey ` when *pubkey* is not needed to avoid memory leak. .. _release_public_key: @@ -332,18 +332,9 @@ releasePublicKey() .. code-block:: lua - handle:releasePublicKey(pkey) + handle:releasePublicKey(pubkey) -Free the resource of *pkey* - -decodeBase64() -^^^^^^^^^^^^^^ - -.. code-block:: lua - - raw = request_handle:decodeBase64(str) - -Decodes base64 encoded string. Returns *nil* if input string is invalid. +Free the resource of *pubkey* .. _verify_signature: @@ -352,13 +343,12 @@ verifySignature() .. code-block:: lua - ok, error = verifySignature(pkey, hashFunction, signature, signatureLength, data, dataLength) + ok, error = verifySignature(hashFunction, pubkey, signature, signatureLength, data, dataLength) -Verify signature using provided parameters. *pkey* is the public key, *hashFunction* is the variable -for hash function which be used for verifying signature. *MD4*, *MD5*, *SHA1*, *SHA224*, *SHA256*, -*SHA384*, *SHA512* and *MD5_SHA1* are supported. *signature* is the signature to be verified. -*signatureLength* is the length of the signature. *data* is the content which will be hashed. -*dataLength* is the length of data. +Verify signature using provided parameters. *hashFunction* is the variable for hash function which be used +for verifying signature. *SHA1*, *SHA224*, *SHA256*, *SHA384* and *SHA512* are supported. +*pubkey* is the public key. *signature* is the signature to be verified. *signatureLength* is +the length of the signature. *data* is the content which will be hashed. *dataLength* is the length of data. The function returns a pair. If the first element is *true*, the second element will be empty which means signature is verified; otherwise, the second element will store the error message. diff --git a/source/common/crypto/utility.cc b/source/common/crypto/utility.cc index 82e273c5fea9b..8cabcc66d0eea 100644 --- a/source/common/crypto/utility.cc +++ b/source/common/crypto/utility.cc @@ -43,11 +43,11 @@ std::vector Utility::getSha256Hmac(const std::vector& key, return hmac; } -VerificationOutput Utility::verifySignature(void* ptr, const absl::string_view& hash, +VerificationOutput Utility::verifySignature(const absl::string_view& hash, void* ptr, const std::vector& signature, const std::vector& clearText) { // Step 1: get public key - auto key = reinterpret_cast(ptr); + auto pubkey = reinterpret_cast(ptr); // Step 2: initialize EVP_MD_CTX EVP_MD_CTX* ctx = EVP_MD_CTX_new(); @@ -61,7 +61,7 @@ VerificationOutput Utility::verifySignature(void* ptr, const absl::string_view& } // Step 4: initialize EVP_DigestVerify - int ok = EVP_DigestVerifyInit(ctx, nullptr, md, nullptr, key); + int ok = EVP_DigestVerifyInit(ctx, nullptr, md, nullptr, pubkey); if (!ok) { EVP_MD_CTX_free(ctx); return {false, "Failed to initialize digest verify."}; @@ -95,11 +95,7 @@ const EVP_MD* Utility::getHashFunction(const absl::string_view& name) { // Hash algorithms set refers // https://github.com/google/boringssl/blob/master/include/openssl/digest.h - if (hash == "md4") { - return EVP_md4(); - } else if (hash == "md5") { - return EVP_md5(); - } else if (hash == "sha1") { + if (hash == "sha1") { return EVP_sha1(); } else if (hash == "sha224") { return EVP_sha224(); @@ -109,8 +105,6 @@ const EVP_MD* Utility::getHashFunction(const absl::string_view& name) { return EVP_sha384(); } else if (hash == "sha512") { return EVP_sha512(); - } else if (hash == "md5_sha1") { - return EVP_md5_sha1(); } else { return nullptr; } diff --git a/source/common/crypto/utility.h b/source/common/crypto/utility.h index 5dd5599fd42c3..4abae53d5bbad 100644 --- a/source/common/crypto/utility.h +++ b/source/common/crypto/utility.h @@ -44,15 +44,14 @@ class Utility { /** * Verify cryptographic signatures. + * @param hash hash function(including SHA1, SHA224, SHA256, SHA384, SHA512) * @param key pointer to public key - * @param hash hash function(including MD4, MD5, SHA1, SHA224, SHA256, SHA384, SHA512, - * MD5_SHA1) * @param signature signature * @param clearText clear text * @return If the result_ is true, the error_message_ is empty; otherwise, * the error_message_ stores the error message */ - static VerificationOutput verifySignature(void* key, const absl::string_view& hash, + static VerificationOutput verifySignature(const absl::string_view& hash, void* key, const std::vector& signature, const std::vector& clearText); diff --git a/source/extensions/filters/http/lua/lua_filter.cc b/source/extensions/filters/http/lua/lua_filter.cc index 40dcdcd50766f..ef2b2b99fbbd5 100644 --- a/source/extensions/filters/http/lua/lua_filter.cc +++ b/source/extensions/filters/http/lua/lua_filter.cc @@ -432,11 +432,11 @@ int StreamHandleWrapper::luaLogCritical(lua_State* state) { } int StreamHandleWrapper::luaVerifySignature(lua_State* state) { - // Step 1: get key pointer - auto ptr = lua_touserdata(state, 2); + // Step 1: get hash function + absl::string_view hash = luaL_checkstring(state, 2); - // Step 2: get hash function - absl::string_view hash = luaL_checkstring(state, 3); + // Step 2: get key pointer + auto ptr = lua_touserdata(state, 3); // Step 3: get signature const char* signature = luaL_checkstring(state, 4); @@ -449,7 +449,7 @@ int StreamHandleWrapper::luaVerifySignature(lua_State* state) { std::vector textVec(clearText, clearText + textLen); // Step 5: verify signature - auto output = Common::Crypto::Utility::verifySignature(ptr, hash, sigVec, textVec); + auto output = Common::Crypto::Utility::verifySignature(hash, ptr, sigVec, textVec); lua_pushboolean(state, output.result_); if (output.result_) { @@ -460,23 +460,6 @@ int StreamHandleWrapper::luaVerifySignature(lua_State* state) { return 2; } -int StreamHandleWrapper::luaDecodeBase64(lua_State* state) { - // Get input string - absl::string_view str = luaL_checkstring(state, 2); - std::string output; - - bool ok = absl::Base64Unescape(str, &output); - - if (ok) { - lua_pushlstring(state, output.data(), output.length()); - } else { - // If decode failed, push a nil into stack. - lua_pushnil(state); - } - - return 1; -} - int StreamHandleWrapper::luaImportPublicKey(lua_State* state) { // Get byte array and the length. const char* str = luaL_checkstring(state, 2); diff --git a/source/extensions/filters/http/lua/lua_filter.h b/source/extensions/filters/http/lua/lua_filter.h index 3132ff16901f7..b2780e0b749dd 100644 --- a/source/extensions/filters/http/lua/lua_filter.h +++ b/source/extensions/filters/http/lua/lua_filter.h @@ -7,8 +7,6 @@ #include "extensions/filters/http/lua/wrappers.h" #include "extensions/filters/http/well_known_names.h" -#include "openssl/evp.h" - namespace Envoy { namespace Extensions { namespace HttpFilters { @@ -144,7 +142,6 @@ class StreamHandleWrapper : public Filters::Common::Lua::BaseLuaObject text(data, data + strlen(data)); - auto result = Utility::verifySignature(pubKey, hashFunc, sig, text); + auto result = Utility::verifySignature(hashFunc, pubKey, sig, text); EXPECT_EQ(true, result.result_); EXPECT_EQ("", result.error_message_); hashFunc = "unknown"; - result = Utility::verifySignature(pubKey, hashFunc, sig, text); + result = Utility::verifySignature(hashFunc, pubKey, sig, text); EXPECT_EQ(false, result.result_); EXPECT_EQ("unknown is not supported.", result.error_message_); hashFunc = "sha256"; - result = Utility::verifySignature(nullptr, hashFunc, sig, text); + result = Utility::verifySignature(hashFunc, nullptr, sig, text); EXPECT_EQ(false, result.result_); EXPECT_EQ("Failed to initialize digest verify.", result.error_message_); data = "baddata"; text = std::vector(data, data + strlen(data)); - result = Utility::verifySignature(pubKey, hashFunc, sig, text); + result = Utility::verifySignature(hashFunc, pubKey, sig, text); EXPECT_EQ(false, result.result_); EXPECT_EQ("Failed to verify digest. Error code: 0", result.error_message_); @@ -122,7 +122,7 @@ TEST(UtilityTest, TestVerifySignature) { text = std::vector(data, data + strlen(data)); signature = "000000"; sig = Hex::decode(signature); - result = Utility::verifySignature(pubKey, hashFunc, sig, text); + result = Utility::verifySignature(hashFunc, pubKey, sig, text); EXPECT_EQ(false, result.result_); EXPECT_EQ("Failed to verify digest. Error code: 0", result.error_message_); diff --git a/test/extensions/filters/http/lua/lua_filter_test.cc b/test/extensions/filters/http/lua/lua_filter_test.cc index 8e5c53b22fb43..18fb6569b6aae 100644 --- a/test/extensions/filters/http/lua/lua_filter_test.cc +++ b/test/extensions/filters/http/lua/lua_filter_test.cc @@ -14,13 +14,7 @@ #include "test/test_common/printers.h" #include "test/test_common/utility.h" -#include "absl/strings/escaping.h" -#include "fmt/printf.h" #include "gmock/gmock.h" -#include "openssl/base64.h" -#include "openssl/bytestring.h" -#include "openssl/evp.h" -#include "openssl/pem.h" using testing::_; using testing::AtLeast; @@ -1583,50 +1577,6 @@ TEST_F(LuaHttpFilterTest, CheckConnection) { EXPECT_EQ(Http::FilterHeadersStatus::Continue, filter_->decodeHeaders(request_headers, true)); } -// Check base64 decode. -TEST_F(LuaHttpFilterTest, CheckBase64Decode) { - const std::string SCRIPT{R"EOF( - function envoy_on_request(request_handle) - str = request_handle:decodeBase64("aGVsbG8=") - if str == nil then - request_handle:logTrace("fail") - else - request_handle:logTrace(str) - end - end - )EOF"}; - - InSequence s; - setup(SCRIPT); - - Http::TestHeaderMapImpl request_headers{{":path", "/"}}; - - EXPECT_CALL(*filter_, scriptLog(spdlog::level::trace, StrEq("hello"))); - EXPECT_EQ(Http::FilterHeadersStatus::Continue, filter_->decodeHeaders(request_headers, true)); -} - -// Check base64 decode. -TEST_F(LuaHttpFilterTest, CheckBase64DecodeFailure) { - const std::string SCRIPT{R"EOF( - function envoy_on_request(request_handle) - str = request_handle:decodeBase64(".") - if str == nil then - request_handle:logTrace("fail") - else - request_handle:logTrace(str) - end - end - )EOF"}; - - InSequence s; - setup(SCRIPT); - - Http::TestHeaderMapImpl request_headers{{":path", "/"}}; - - EXPECT_CALL(*filter_, scriptLog(spdlog::level::trace, StrEq("fail"))); - EXPECT_EQ(Http::FilterHeadersStatus::Continue, filter_->decodeHeaders(request_headers, true)); -} - TEST_F(LuaHttpFilterTest, ImportandReleasePublicKey) { const std::string SCRIPT{R"EOF( function string.fromhex(str) @@ -1701,44 +1651,44 @@ TEST_F(LuaHttpFilterTest, SignatureVerify) { data = "hello" rawkey = key:fromhex() - pkey = request_handle:importPublicKey(rawkey, string.len(rawkey)) + pubkey = request_handle:importPublicKey(rawkey, string.len(rawkey)) - if pkey == nil then + if pubkey == nil then request_handle:logTrace("failed to import public key") return end rawsig = signature:fromhex() - ok, error = request_handle:verifySignature(pkey, hashFunc, rawsig, string.len(rawsig), data, string.len(data)) + ok, error = request_handle:verifySignature(hashFunc, pubkey, rawsig, string.len(rawsig), data, string.len(data)) if ok then request_handle:logTrace("signature is valid") else request_handle:logTrace(error) end - ok, error = request_handle:verifySignature(pkey, "unknown", rawsig, string.len(rawsig), data, string.len(data)) + ok, error = request_handle:verifySignature("unknown", pubkey, rawsig, string.len(rawsig), data, string.len(data)) if ok then request_handle:logTrace("signature is valid") else request_handle:logTrace(error) end - ok, error = request_handle:verifySignature(pkey, hashFunc, "0000", 4, data, string.len(data)) + ok, error = request_handle:verifySignature(hashFunc, pubkey, "0000", 4, data, string.len(data)) if ok then request_handle:logTrace("signature is valid") else request_handle:logTrace(error) end - ok, error = request_handle:verifySignature(pkey, hashFunc, rawsig, string.len(rawsig), "xxxx", 4) + ok, error = request_handle:verifySignature(hashFunc, pubkey, rawsig, string.len(rawsig), "xxxx", 4) if ok then request_handle:logTrace("signature is valid") else request_handle:logTrace(error) end - request_handle:releasePublicKey(pkey) + request_handle:releasePublicKey(pubkey) end )EOF"}; diff --git a/test/extensions/filters/http/lua/lua_integration_test.cc b/test/extensions/filters/http/lua/lua_integration_test.cc index dad6877c40377..0576085180739 100644 --- a/test/extensions/filters/http/lua/lua_integration_test.cc +++ b/test/extensions/filters/http/lua/lua_integration_test.cc @@ -402,14 +402,31 @@ name: envoy.lua end)) end + -- decoding + function dec(data) + local b='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/' + data = string.gsub(data, '[^'..b..'=]', '') + return (data:gsub('.', function(x) + if (x == '=') then return '' end + local r,f='',(b:find(x)-1) + for i=6,1,-1 do r=r..(f%2^i-f%2^(i-1)>0 and '1' or '0') end + return r; + end):gsub('%d%d%d?%d?%d?%d?%d?%d?', function(x) + if (#x ~= 8) then return '' end + local c=0 + for i=1,8 do c=c+(x:sub(i,i)=='1' and 2^(8-i) or 0) end + return string.char(c) + end)) + end + function envoy_on_request(request_handle) local metadata = request_handle:metadata():get("keyset") local keyder = metadata[request_handle:headers():get("keyid")] - local rawkeyder = request_handle:decodeBase64(keyder) - local key = request_handle:importPublicKey(rawkeyder, string.len(rawkeyder)) + local rawkeyder = dec(keyder) + local pubkey = request_handle:importPublicKey(rawkeyder, string.len(rawkeyder)) - if key == nil then + if pubkey == nil then request_handle:logErr("log test") request_handle:headers():add("signature_verification", "rejected") return @@ -419,7 +436,7 @@ name: envoy.lua local sig = request_handle:headers():get("signature") local rawsig = sig:fromhex() local data = request_handle:headers():get("message") - local ok, error = request_handle:verifySignature(key, hash, rawsig, string.len(rawsig), data, string.len(data)) + local ok, error = request_handle:verifySignature(hash, pubkey, rawsig, string.len(rawsig), data, string.len(data)) if ok then request_handle:headers():add("signature_verification", "approved") @@ -428,7 +445,7 @@ name: envoy.lua request_handle:headers():add("signature_verification", "rejected") end - request_handle:releasePublicKey(key) + request_handle:releasePublicKey(pubkey) end )EOF"; From 7c8444b37fb57565c623e03ffb6a4cb410c29f0b Mon Sep 17 00:00:00 2001 From: Yan Xue Date: Tue, 4 Jun 2019 10:34:58 -0700 Subject: [PATCH 10/16] Use bssl::ScopedEVP_MD_CTX Signed-off-by: Yan Xue --- source/common/crypto/utility.cc | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/source/common/crypto/utility.cc b/source/common/crypto/utility.cc index 8cabcc66d0eea..c6656c7a4e88f 100644 --- a/source/common/crypto/utility.cc +++ b/source/common/crypto/utility.cc @@ -50,34 +50,30 @@ VerificationOutput Utility::verifySignature(const absl::string_view& hash, void* auto pubkey = reinterpret_cast(ptr); // Step 2: initialize EVP_MD_CTX - EVP_MD_CTX* ctx = EVP_MD_CTX_new(); + bssl::ScopedEVP_MD_CTX ctx; // Step 3: initialize EVP_MD const EVP_MD* md = Utility::getHashFunction(hash); if (md == nullptr) { - EVP_MD_CTX_free(ctx); return {false, absl::StrCat(hash, " is not supported.")}; } // Step 4: initialize EVP_DigestVerify - int ok = EVP_DigestVerifyInit(ctx, nullptr, md, nullptr, pubkey); + int ok = EVP_DigestVerifyInit(ctx.get(), nullptr, md, nullptr, pubkey); if (!ok) { - EVP_MD_CTX_free(ctx); return {false, "Failed to initialize digest verify."}; } // Step 5: verify signature - ok = - EVP_DigestVerify(ctx, signature.data(), signature.size(), clearText.data(), clearText.size()); + ok = EVP_DigestVerify(ctx.get(), signature.data(), signature.size(), clearText.data(), + clearText.size()); // Step 6: check result if (ok == 1) { - EVP_MD_CTX_free(ctx); return {true, ""}; } - EVP_MD_CTX_free(ctx); std::string err_msg; absl::StrAppend(&err_msg, "Failed to verify digest. Error code: ", ok); return {false, err_msg}; From b8748a4bdfad1f38652b5a8f68e0b3a1068827e9 Mon Sep 17 00:00:00 2001 From: Yan Xue Date: Tue, 4 Jun 2019 13:44:44 -0700 Subject: [PATCH 11/16] Remove unused include Signed-off-by: Yan Xue --- source/extensions/filters/http/lua/lua_filter.cc | 2 -- 1 file changed, 2 deletions(-) diff --git a/source/extensions/filters/http/lua/lua_filter.cc b/source/extensions/filters/http/lua/lua_filter.cc index ef2b2b99fbbd5..ee9208970aa77 100644 --- a/source/extensions/filters/http/lua/lua_filter.cc +++ b/source/extensions/filters/http/lua/lua_filter.cc @@ -10,8 +10,6 @@ #include "common/crypto/utility.h" #include "common/http/message_impl.h" -#include "absl/strings/escaping.h" - namespace Envoy { namespace Extensions { namespace HttpFilters { From 5833663de84f18c2e0cdb008e4f8da6fa38ba823 Mon Sep 17 00:00:00 2001 From: Yan Xue Date: Tue, 4 Jun 2019 15:12:03 -0700 Subject: [PATCH 12/16] Rename local variable Signed-off-by: Yan Xue --- .../configuration/http_filters/lua_filter.rst | 2 +- source/common/crypto/utility.cc | 6 +-- .../extensions/filters/http/lua/lua_filter.cc | 12 +++--- test/common/crypto/utility_test.cc | 38 ++++++++----------- .../filters/http/lua/lua_filter_test.cc | 4 +- 5 files changed, 27 insertions(+), 35 deletions(-) diff --git a/docs/root/configuration/http_filters/lua_filter.rst b/docs/root/configuration/http_filters/lua_filter.rst index 401b6b30694c7..548b7a8b7839e 100644 --- a/docs/root/configuration/http_filters/lua_filter.rst +++ b/docs/root/configuration/http_filters/lua_filter.rst @@ -317,7 +317,7 @@ importPublicKey() .. code-block:: lua - pubkey = handle:importPublicKey(keyder, keyderLenght) + pubkey = handle:importPublicKey(keyder, keyderLength) Returns public key which is used by :ref:`verifySignature ` to verify digital signature. diff --git a/source/common/crypto/utility.cc b/source/common/crypto/utility.cc index c6656c7a4e88f..6189468451af3 100644 --- a/source/common/crypto/utility.cc +++ b/source/common/crypto/utility.cc @@ -47,7 +47,7 @@ VerificationOutput Utility::verifySignature(const absl::string_view& hash, void* const std::vector& signature, const std::vector& clearText) { // Step 1: get public key - auto pubkey = reinterpret_cast(ptr); + auto pub_key = reinterpret_cast(ptr); // Step 2: initialize EVP_MD_CTX bssl::ScopedEVP_MD_CTX ctx; @@ -60,7 +60,7 @@ VerificationOutput Utility::verifySignature(const absl::string_view& hash, void* } // Step 4: initialize EVP_DigestVerify - int ok = EVP_DigestVerifyInit(ctx.get(), nullptr, md, nullptr, pubkey); + int ok = EVP_DigestVerifyInit(ctx.get(), nullptr, md, nullptr, pub_key); if (!ok) { return {false, "Failed to initialize digest verify."}; } @@ -87,7 +87,7 @@ void* Utility::importPublicKey(const std::vector& key) { void Utility::releasePublicKey(void* ptr) { EVP_PKEY_free(reinterpret_cast(ptr)); } const EVP_MD* Utility::getHashFunction(const absl::string_view& name) { - std::string hash = absl::AsciiStrToLower(name); + const std::string hash = absl::AsciiStrToLower(name); // Hash algorithms set refers // https://github.com/google/boringssl/blob/master/include/openssl/digest.h diff --git a/source/extensions/filters/http/lua/lua_filter.cc b/source/extensions/filters/http/lua/lua_filter.cc index ee9208970aa77..c4abd8e06be23 100644 --- a/source/extensions/filters/http/lua/lua_filter.cc +++ b/source/extensions/filters/http/lua/lua_filter.cc @@ -438,16 +438,16 @@ int StreamHandleWrapper::luaVerifySignature(lua_State* state) { // Step 3: get signature const char* signature = luaL_checkstring(state, 4); - int sigLen = luaL_checknumber(state, 5); - std::vector sigVec(signature, signature + sigLen); + int sig_len = luaL_checknumber(state, 5); + const std::vector sig_vec(signature, signature + sig_len); // Step 4: get clear text - const char* clearText = luaL_checkstring(state, 6); - int textLen = luaL_checknumber(state, 7); - std::vector textVec(clearText, clearText + textLen); + const char* clear_text = luaL_checkstring(state, 6); + int text_len = luaL_checknumber(state, 7); + const std::vector text_vec(clear_text, clear_text + text_len); // Step 5: verify signature - auto output = Common::Crypto::Utility::verifySignature(hash, ptr, sigVec, textVec); + auto output = Common::Crypto::Utility::verifySignature(hash, ptr, sig_vec, text_vec); lua_pushboolean(state, output.result_); if (output.result_) { diff --git a/test/common/crypto/utility_test.cc b/test/common/crypto/utility_test.cc index a64e163f3f3cf..a97a65a5eaa41 100644 --- a/test/common/crypto/utility_test.cc +++ b/test/common/crypto/utility_test.cc @@ -59,18 +59,15 @@ TEST(UtilityTest, TestImportPublicKey) { "d5af8136a9630a6cc0cde157dc8e00f39540628d5f335b2c36c54c7c8bc3738a6b21acff815405afa28e5" "183f550dac19abcf1145a7f9ced987db680e4a229cac75dee347ec9ebce1fc3dbbbb0203010001"; - auto keyvec = Hex::decode(key); - - auto pubKey = Utility::importPublicKey(keyvec); - EXPECT_NE(nullptr, pubKey); - Utility::releasePublicKey(pubKey); + auto pub_key = Utility::importPublicKey(Hex::decode(key)); + EXPECT_NE(nullptr, pub_key); + Utility::releasePublicKey(pub_key); key = "badkey"; - keyvec = Hex::decode(key); - pubKey = Utility::importPublicKey(keyvec); - EXPECT_EQ(nullptr, pubKey); - Utility::releasePublicKey(pubKey); + pub_key = Utility::importPublicKey(Hex::decode(key)); + EXPECT_EQ(nullptr, pub_key); + Utility::releasePublicKey(pub_key); } TEST(UtilityTest, TestVerifySignature) { @@ -81,7 +78,7 @@ TEST(UtilityTest, TestVerifySignature) { "395c0b8442ec5aa1ef8051529ea0e375883cefc72c04e360b4ef8f5760650589ca814918f678eee39b884" "d5af8136a9630a6cc0cde157dc8e00f39540628d5f335b2c36c54c7c8bc3738a6b21acff815405afa28e5" "183f550dac19abcf1145a7f9ced987db680e4a229cac75dee347ec9ebce1fc3dbbbb0203010001"; - auto hashFunc = "sha256"; + auto hash_func = "sha256"; auto signature = "345ac3a167558f4f387a81c2d64234d901a7ceaa544db779d2f797b0ea4ef851b740905a63e2f4d5af42cee093a2" "9c7155db9a63d3d483e0ef948f5ac51ce4e10a3a6606fd93ef68ee47b30c37491103039459122f78e1c7ea71a1a5" @@ -91,42 +88,37 @@ TEST(UtilityTest, TestVerifySignature) { "295234f7c14fa46303b7e977d2c89ba8a39a46a35f33eb07a332"; auto data = "hello"; - auto keyvec = Hex::decode(key); - auto pubKey = Utility::importPublicKey(keyvec); + auto pub_key = Utility::importPublicKey(Hex::decode(key)); - auto sig = Hex::decode(signature); std::vector text(data, data + strlen(data)); - auto result = Utility::verifySignature(hashFunc, pubKey, sig, text); + auto sig = Hex::decode(signature); + auto result = Utility::verifySignature(hash_func, pub_key, sig, text); EXPECT_EQ(true, result.result_); EXPECT_EQ("", result.error_message_); - hashFunc = "unknown"; - result = Utility::verifySignature(hashFunc, pubKey, sig, text); + result = Utility::verifySignature("unknown", pub_key, sig, text); EXPECT_EQ(false, result.result_); EXPECT_EQ("unknown is not supported.", result.error_message_); - hashFunc = "sha256"; - result = Utility::verifySignature(hashFunc, nullptr, sig, text); + result = Utility::verifySignature(hash_func, nullptr, sig, text); EXPECT_EQ(false, result.result_); EXPECT_EQ("Failed to initialize digest verify.", result.error_message_); data = "baddata"; text = std::vector(data, data + strlen(data)); - result = Utility::verifySignature(hashFunc, pubKey, sig, text); + result = Utility::verifySignature(hash_func, pub_key, sig, text); EXPECT_EQ(false, result.result_); EXPECT_EQ("Failed to verify digest. Error code: 0", result.error_message_); data = "hello"; text = std::vector(data, data + strlen(data)); - signature = "000000"; - sig = Hex::decode(signature); - result = Utility::verifySignature(hashFunc, pubKey, sig, text); + result = Utility::verifySignature(hash_func, pub_key, Hex::decode("000000"), text); EXPECT_EQ(false, result.result_); EXPECT_EQ("Failed to verify digest. Error code: 0", result.error_message_); - Utility::releasePublicKey(pubKey); + Utility::releasePublicKey(pub_key); } } // namespace diff --git a/test/extensions/filters/http/lua/lua_filter_test.cc b/test/extensions/filters/http/lua/lua_filter_test.cc index 18fb6569b6aae..b89bb850176e7 100644 --- a/test/extensions/filters/http/lua/lua_filter_test.cc +++ b/test/extensions/filters/http/lua/lua_filter_test.cc @@ -1592,9 +1592,9 @@ TEST_F(LuaHttpFilterTest, ImportandReleasePublicKey) { if key == nil then request_handle:logTrace("failed to import public key") else - request_handle:releasePublicKey(key) request_handle:logTrace("succeeded to import public key") end + request_handle:releasePublicKey(key) end )EOF"}; @@ -1622,9 +1622,9 @@ TEST_F(LuaHttpFilterTest, InvalidPublicKey) { if key == nil then request_handle:logTrace("failed to import public key") else - request_handle:releasePublicKey(key) request_handle:logTrace("succeeded to import public key") end + request_handle:releasePublicKey(key) end )EOF"}; From 14fed2294883faff42ecdb9eced7289aedf5892b Mon Sep 17 00:00:00 2001 From: Yan Xue Date: Tue, 4 Jun 2019 22:01:51 -0700 Subject: [PATCH 13/16] Add EVP_PKEY wrapper Signed-off-by: Yan Xue --- .../configuration/http_filters/lua_filter.rst | 15 ------------- source/common/crypto/utility.cc | 15 +++++-------- source/common/crypto/utility.h | 18 ++++++--------- source/extensions/filters/http/lua/BUILD | 1 + .../extensions/filters/http/lua/lua_filter.cc | 16 +++++--------- .../extensions/filters/http/lua/lua_filter.h | 9 ++------ .../extensions/filters/http/lua/wrappers.cc | 9 ++++++++ source/extensions/filters/http/lua/wrappers.h | 22 +++++++++++++++++++ test/common/crypto/utility_test.cc | 18 +++++++-------- .../filters/http/lua/lua_filter_test.cc | 12 ++++------ .../filters/http/lua/lua_integration_test.cc | 2 +- 11 files changed, 67 insertions(+), 70 deletions(-) diff --git a/docs/root/configuration/http_filters/lua_filter.rst b/docs/root/configuration/http_filters/lua_filter.rst index 548b7a8b7839e..23f4d2a65ad6b 100644 --- a/docs/root/configuration/http_filters/lua_filter.rst +++ b/docs/root/configuration/http_filters/lua_filter.rst @@ -321,21 +321,6 @@ importPublicKey() Returns public key which is used by :ref:`verifySignature ` to verify digital signature. -.. attention:: - - Remember to call :ref:`releasePublicKey ` when *pubkey* is not needed to avoid memory leak. - -.. _release_public_key: - -releasePublicKey() -^^^^^^^^^^^^^^^^^^ - -.. code-block:: lua - - handle:releasePublicKey(pubkey) - -Free the resource of *pubkey* - .. _verify_signature: verifySignature() diff --git a/source/common/crypto/utility.cc b/source/common/crypto/utility.cc index 6189468451af3..5f03f288d0271 100644 --- a/source/common/crypto/utility.cc +++ b/source/common/crypto/utility.cc @@ -43,9 +43,9 @@ std::vector Utility::getSha256Hmac(const std::vector& key, return hmac; } -VerificationOutput Utility::verifySignature(const absl::string_view& hash, void* ptr, - const std::vector& signature, - const std::vector& clearText) { +const VerificationOutput Utility::verifySignature(const absl::string_view& hash, void* ptr, + const std::vector& signature, + const std::vector& text) { // Step 1: get public key auto pub_key = reinterpret_cast(ptr); @@ -66,8 +66,7 @@ VerificationOutput Utility::verifySignature(const absl::string_view& hash, void* } // Step 5: verify signature - ok = EVP_DigestVerify(ctx.get(), signature.data(), signature.size(), clearText.data(), - clearText.size()); + ok = EVP_DigestVerify(ctx.get(), signature.data(), signature.size(), text.data(), text.size()); // Step 6: check result if (ok == 1) { @@ -79,13 +78,11 @@ VerificationOutput Utility::verifySignature(const absl::string_view& hash, void* return {false, err_msg}; } -void* Utility::importPublicKey(const std::vector& key) { +const PublicKeyPtr* Utility::importPublicKey(const std::vector& key) { CBS cbs({key.data(), key.size()}); - return EVP_parse_public_key(&cbs); + return new PublicKeyPtr(EVP_parse_public_key(&cbs)); } -void Utility::releasePublicKey(void* ptr) { EVP_PKEY_free(reinterpret_cast(ptr)); } - const EVP_MD* Utility::getHashFunction(const absl::string_view& name) { const std::string hash = absl::AsciiStrToLower(name); diff --git a/source/common/crypto/utility.h b/source/common/crypto/utility.h index 4abae53d5bbad..952cd7518e230 100644 --- a/source/common/crypto/utility.h +++ b/source/common/crypto/utility.h @@ -24,6 +24,8 @@ struct VerificationOutput { std::string error_message_; }; +typedef bssl::UniquePtr PublicKeyPtr; + class Utility { public: /** @@ -47,26 +49,20 @@ class Utility { * @param hash hash function(including SHA1, SHA224, SHA256, SHA384, SHA512) * @param key pointer to public key * @param signature signature - * @param clearText clear text + * @param text clear text * @return If the result_ is true, the error_message_ is empty; otherwise, * the error_message_ stores the error message */ - static VerificationOutput verifySignature(const absl::string_view& hash, void* key, - const std::vector& signature, - const std::vector& clearText); + static const VerificationOutput verifySignature(const absl::string_view& hash, void* key, + const std::vector& signature, + const std::vector& text); /** * Import public key. * @param key key string * @return pointer to public key */ - static void* importPublicKey(const std::vector& key); - - /** - * Release public key. - * @param key pointer to public key - */ - static void releasePublicKey(void* key); + static const PublicKeyPtr* importPublicKey(const std::vector& key); private: static const EVP_MD* getHashFunction(const absl::string_view& name); diff --git a/source/extensions/filters/http/lua/BUILD b/source/extensions/filters/http/lua/BUILD index 61711704d1906..646636b28098e 100644 --- a/source/extensions/filters/http/lua/BUILD +++ b/source/extensions/filters/http/lua/BUILD @@ -37,6 +37,7 @@ envoy_cc_library( deps = [ "//include/envoy/http:header_map_interface", "//include/envoy/stream_info:stream_info_interface", + "//source/common/crypto:utility_lib", "//source/common/http:utility_lib", "//source/extensions/filters/common/lua:lua_lib", "//source/extensions/filters/common/lua:wrappers_lib", diff --git a/source/extensions/filters/http/lua/lua_filter.cc b/source/extensions/filters/http/lua/lua_filter.cc index c4abd8e06be23..196c383048b92 100644 --- a/source/extensions/filters/http/lua/lua_filter.cc +++ b/source/extensions/filters/http/lua/lua_filter.cc @@ -462,23 +462,18 @@ int StreamHandleWrapper::luaImportPublicKey(lua_State* state) { // Get byte array and the length. const char* str = luaL_checkstring(state, 2); int n = luaL_checknumber(state, 3); - std::vector keyVec(str, str + n); + std::vector key(str, str + n); - auto key = Common::Crypto::Utility::importPublicKey(keyVec); - if (key != nullptr) { - lua_pushlightuserdata(state, key); + if (public_key_wrapper_.get() != nullptr) { + public_key_wrapper_.pushStack(); } else { - lua_pushnil(state); + public_key_wrapper_.reset( + PublicKeyWrapper::create(state, Common::Crypto::Utility::importPublicKey(key)), true); } return 1; } -int StreamHandleWrapper::luaReleasePublicKey(lua_State* state) { - Common::Crypto::Utility::releasePublicKey(lua_touserdata(state, 2)); - return 0; -} - FilterConfig::FilterConfig(const std::string& lua_code, ThreadLocal::SlotAllocator& tls, Upstream::ClusterManager& cluster_manager) : cluster_manager_(cluster_manager), lua_state_(lua_code, tls) { @@ -493,6 +488,7 @@ FilterConfig::FilterConfig(const std::string& lua_code, ThreadLocal::SlotAllocat lua_state_.registerType(); lua_state_.registerType(); lua_state_.registerType(); + lua_state_.registerType(); request_function_slot_ = lua_state_.registerGlobal("envoy_on_request"); if (lua_state_.getGlobalRef(request_function_slot_) == LUA_REFNIL) { diff --git a/source/extensions/filters/http/lua/lua_filter.h b/source/extensions/filters/http/lua/lua_filter.h index b2780e0b749dd..84da9e013648a 100644 --- a/source/extensions/filters/http/lua/lua_filter.h +++ b/source/extensions/filters/http/lua/lua_filter.h @@ -143,7 +143,6 @@ class StreamHandleWrapper : public Filters::Common::Lua::BaseLuaObject metadata_wrapper_; Filters::Common::Lua::LuaDeathRef stream_info_wrapper_; Filters::Common::Lua::LuaDeathRef connection_wrapper_; + Filters::Common::Lua::LuaDeathRef public_key_wrapper_; State state_{State::Running}; std::function yield_callback_; Http::AsyncClient::Request* http_request_{}; diff --git a/source/extensions/filters/http/lua/wrappers.cc b/source/extensions/filters/http/lua/wrappers.cc index f675d34cfa598..b2a5ed4c6a3a0 100644 --- a/source/extensions/filters/http/lua/wrappers.cc +++ b/source/extensions/filters/http/lua/wrappers.cc @@ -174,6 +174,15 @@ int DynamicMetadataMapWrapper::luaPairs(lua_State* state) { return 1; } +int PublicKeyWrapper::luaGet(lua_State* state) { + if (public_key_ == nullptr || public_key_->get() == nullptr) { + lua_pushnil(state); + } else { + lua_pushlightuserdata(state, public_key_->get()); + } + return 1; +} + } // namespace Lua } // namespace HttpFilters } // namespace Extensions diff --git a/source/extensions/filters/http/lua/wrappers.h b/source/extensions/filters/http/lua/wrappers.h index 91f1a400f5b81..73ef6cecde14d 100644 --- a/source/extensions/filters/http/lua/wrappers.h +++ b/source/extensions/filters/http/lua/wrappers.h @@ -3,6 +3,8 @@ #include "envoy/http/header_map.h" #include "envoy/stream_info/stream_info.h" +#include "common/crypto/utility.h" + #include "extensions/filters/common/lua/lua.h" namespace Envoy { @@ -201,6 +203,26 @@ class StreamInfoWrapper : public Filters::Common::Lua::BaseLuaObject { +public: + PublicKeyWrapper(const Envoy::Common::Crypto::PublicKeyPtr* key) : public_key_(key) {} + static ExportedFunctions exportedFunctions() { return {{"get", static_luaGet}}; } + + ~PublicKeyWrapper() { delete public_key_; } + +private: + /** + * Get a pointer to public key. + * @return pointer to public key. + */ + DECLARE_LUA_FUNCTION(PublicKeyWrapper, luaGet); + + const Envoy::Common::Crypto::PublicKeyPtr* public_key_; +}; + } // namespace Lua } // namespace HttpFilters } // namespace Extensions diff --git a/test/common/crypto/utility_test.cc b/test/common/crypto/utility_test.cc index a97a65a5eaa41..bedef5064412d 100644 --- a/test/common/crypto/utility_test.cc +++ b/test/common/crypto/utility_test.cc @@ -60,14 +60,14 @@ TEST(UtilityTest, TestImportPublicKey) { "183f550dac19abcf1145a7f9ced987db680e4a229cac75dee347ec9ebce1fc3dbbbb0203010001"; auto pub_key = Utility::importPublicKey(Hex::decode(key)); - EXPECT_NE(nullptr, pub_key); - Utility::releasePublicKey(pub_key); + EXPECT_NE(nullptr, pub_key->get()); + delete pub_key; key = "badkey"; pub_key = Utility::importPublicKey(Hex::decode(key)); - EXPECT_EQ(nullptr, pub_key); - Utility::releasePublicKey(pub_key); + EXPECT_EQ(nullptr, pub_key->get()); + delete pub_key; } TEST(UtilityTest, TestVerifySignature) { @@ -93,12 +93,12 @@ TEST(UtilityTest, TestVerifySignature) { std::vector text(data, data + strlen(data)); auto sig = Hex::decode(signature); - auto result = Utility::verifySignature(hash_func, pub_key, sig, text); + auto result = Utility::verifySignature(hash_func, pub_key->get(), sig, text); EXPECT_EQ(true, result.result_); EXPECT_EQ("", result.error_message_); - result = Utility::verifySignature("unknown", pub_key, sig, text); + result = Utility::verifySignature("unknown", pub_key->get(), sig, text); EXPECT_EQ(false, result.result_); EXPECT_EQ("unknown is not supported.", result.error_message_); @@ -108,17 +108,17 @@ TEST(UtilityTest, TestVerifySignature) { data = "baddata"; text = std::vector(data, data + strlen(data)); - result = Utility::verifySignature(hash_func, pub_key, sig, text); + result = Utility::verifySignature(hash_func, pub_key->get(), sig, text); EXPECT_EQ(false, result.result_); EXPECT_EQ("Failed to verify digest. Error code: 0", result.error_message_); data = "hello"; text = std::vector(data, data + strlen(data)); - result = Utility::verifySignature(hash_func, pub_key, Hex::decode("000000"), text); + result = Utility::verifySignature(hash_func, pub_key->get(), Hex::decode("000000"), text); EXPECT_EQ(false, result.result_); EXPECT_EQ("Failed to verify digest. Error code: 0", result.error_message_); - Utility::releasePublicKey(pub_key); + delete pub_key; } } // namespace diff --git a/test/extensions/filters/http/lua/lua_filter_test.cc b/test/extensions/filters/http/lua/lua_filter_test.cc index b89bb850176e7..f133c1471e4b5 100644 --- a/test/extensions/filters/http/lua/lua_filter_test.cc +++ b/test/extensions/filters/http/lua/lua_filter_test.cc @@ -1577,7 +1577,7 @@ TEST_F(LuaHttpFilterTest, CheckConnection) { EXPECT_EQ(Http::FilterHeadersStatus::Continue, filter_->decodeHeaders(request_headers, true)); } -TEST_F(LuaHttpFilterTest, ImportandReleasePublicKey) { +TEST_F(LuaHttpFilterTest, ImportPublicKey) { const std::string SCRIPT{R"EOF( function string.fromhex(str) return (str:gsub('..', function (cc) @@ -1587,14 +1587,13 @@ TEST_F(LuaHttpFilterTest, ImportandReleasePublicKey) { function envoy_on_request(request_handle) key = "30820122300d06092a864886f70d01010105000382010f003082010a0282010100a7471266d01d160308d73409c06f2e8d35c531c458d3e480e9f3191847d062ec5ccff7bc51e949d5f2c3540c189a4eca1e8633a62cf2d0923101c27e38013e71de9ae91a704849bff7fbe2ce5bf4bd666fd9731102a53193fe5a9a5a50644ff8b1183fa897646598caad22a37f9544510836372b44c58c98586fb7144629cd8c9479592d996d32ff6d395c0b8442ec5aa1ef8051529ea0e375883cefc72c04e360b4ef8f5760650589ca814918f678eee39b884d5af8136a9630a6cc0cde157dc8e00f39540628d5f335b2c36c54c7c8bc3738a6b21acff815405afa28e5183f550dac19abcf1145a7f9ced987db680e4a229cac75dee347ec9ebce1fc3dbbbb0203010001" raw = key:fromhex() - key = request_handle:importPublicKey(raw, string.len(raw)) + key = request_handle:importPublicKey(raw, string.len(raw)):get() if key == nil then request_handle:logTrace("failed to import public key") else request_handle:logTrace("succeeded to import public key") end - request_handle:releasePublicKey(key) end )EOF"}; @@ -1617,14 +1616,13 @@ TEST_F(LuaHttpFilterTest, InvalidPublicKey) { function envoy_on_request(request_handle) key = "0000" raw = key:fromhex() - key = request_handle:importPublicKey(raw, string.len(raw)) + key = request_handle:importPublicKey(raw, string.len(raw)):get() if key == nil then request_handle:logTrace("failed to import public key") else request_handle:logTrace("succeeded to import public key") end - request_handle:releasePublicKey(key) end )EOF"}; @@ -1651,7 +1649,7 @@ TEST_F(LuaHttpFilterTest, SignatureVerify) { data = "hello" rawkey = key:fromhex() - pubkey = request_handle:importPublicKey(rawkey, string.len(rawkey)) + pubkey = request_handle:importPublicKey(rawkey, string.len(rawkey)):get() if pubkey == nil then request_handle:logTrace("failed to import public key") @@ -1687,8 +1685,6 @@ TEST_F(LuaHttpFilterTest, SignatureVerify) { else request_handle:logTrace(error) end - - request_handle:releasePublicKey(pubkey) end )EOF"}; diff --git a/test/extensions/filters/http/lua/lua_integration_test.cc b/test/extensions/filters/http/lua/lua_integration_test.cc index 0576085180739..4149d43338525 100644 --- a/test/extensions/filters/http/lua/lua_integration_test.cc +++ b/test/extensions/filters/http/lua/lua_integration_test.cc @@ -424,7 +424,7 @@ name: envoy.lua local keyder = metadata[request_handle:headers():get("keyid")] local rawkeyder = dec(keyder) - local pubkey = request_handle:importPublicKey(rawkeyder, string.len(rawkeyder)) + local pubkey = request_handle:importPublicKey(rawkeyder, string.len(rawkeyder)):get() if pubkey == nil then request_handle:logErr("log test") From 425f09ebcae9037452a26314a72e888b2bb65954 Mon Sep 17 00:00:00 2001 From: Yan Xue Date: Tue, 4 Jun 2019 23:55:53 -0700 Subject: [PATCH 14/16] Use unique_ptr Signed-off-by: Yan Xue --- source/common/crypto/utility.cc | 8 +++----- source/common/crypto/utility.h | 2 +- source/extensions/filters/http/lua/wrappers.cc | 4 ++-- source/extensions/filters/http/lua/wrappers.h | 6 ++---- test/common/crypto/utility_test.cc | 16 ++++++---------- 5 files changed, 14 insertions(+), 22 deletions(-) diff --git a/source/common/crypto/utility.cc b/source/common/crypto/utility.cc index 5f03f288d0271..061263b21c215 100644 --- a/source/common/crypto/utility.cc +++ b/source/common/crypto/utility.cc @@ -73,14 +73,12 @@ const VerificationOutput Utility::verifySignature(const absl::string_view& hash, return {true, ""}; } - std::string err_msg; - absl::StrAppend(&err_msg, "Failed to verify digest. Error code: ", ok); - return {false, err_msg}; + return {false, absl::StrCat("Failed to verify digest. Error code: ", ok)}; } -const PublicKeyPtr* Utility::importPublicKey(const std::vector& key) { +PublicKeyPtr Utility::importPublicKey(const std::vector& key) { CBS cbs({key.data(), key.size()}); - return new PublicKeyPtr(EVP_parse_public_key(&cbs)); + return PublicKeyPtr(EVP_parse_public_key(&cbs)); } const EVP_MD* Utility::getHashFunction(const absl::string_view& name) { diff --git a/source/common/crypto/utility.h b/source/common/crypto/utility.h index 952cd7518e230..8a9f374e0cefc 100644 --- a/source/common/crypto/utility.h +++ b/source/common/crypto/utility.h @@ -62,7 +62,7 @@ class Utility { * @param key key string * @return pointer to public key */ - static const PublicKeyPtr* importPublicKey(const std::vector& key); + static PublicKeyPtr importPublicKey(const std::vector& key); private: static const EVP_MD* getHashFunction(const absl::string_view& name); diff --git a/source/extensions/filters/http/lua/wrappers.cc b/source/extensions/filters/http/lua/wrappers.cc index b2a5ed4c6a3a0..332211d4c8bb0 100644 --- a/source/extensions/filters/http/lua/wrappers.cc +++ b/source/extensions/filters/http/lua/wrappers.cc @@ -175,10 +175,10 @@ int DynamicMetadataMapWrapper::luaPairs(lua_State* state) { } int PublicKeyWrapper::luaGet(lua_State* state) { - if (public_key_ == nullptr || public_key_->get() == nullptr) { + if (public_key_ == nullptr || public_key_.get() == nullptr) { lua_pushnil(state); } else { - lua_pushlightuserdata(state, public_key_->get()); + lua_pushlightuserdata(state, public_key_.get()); } return 1; } diff --git a/source/extensions/filters/http/lua/wrappers.h b/source/extensions/filters/http/lua/wrappers.h index 73ef6cecde14d..e5bc0041d0d80 100644 --- a/source/extensions/filters/http/lua/wrappers.h +++ b/source/extensions/filters/http/lua/wrappers.h @@ -208,11 +208,9 @@ class StreamInfoWrapper : public Filters::Common::Lua::BaseLuaObject { public: - PublicKeyWrapper(const Envoy::Common::Crypto::PublicKeyPtr* key) : public_key_(key) {} + PublicKeyWrapper(Envoy::Common::Crypto::PublicKeyPtr key) : public_key_(std::move(key)) {} static ExportedFunctions exportedFunctions() { return {{"get", static_luaGet}}; } - ~PublicKeyWrapper() { delete public_key_; } - private: /** * Get a pointer to public key. @@ -220,7 +218,7 @@ class PublicKeyWrapper : public Filters::Common::Lua::BaseLuaObjectget()); - delete pub_key; + EXPECT_NE(nullptr, pub_key.get()); key = "badkey"; pub_key = Utility::importPublicKey(Hex::decode(key)); - EXPECT_EQ(nullptr, pub_key->get()); - delete pub_key; + EXPECT_EQ(nullptr, pub_key.get()); } TEST(UtilityTest, TestVerifySignature) { @@ -93,12 +91,12 @@ TEST(UtilityTest, TestVerifySignature) { std::vector text(data, data + strlen(data)); auto sig = Hex::decode(signature); - auto result = Utility::verifySignature(hash_func, pub_key->get(), sig, text); + auto result = Utility::verifySignature(hash_func, pub_key.get(), sig, text); EXPECT_EQ(true, result.result_); EXPECT_EQ("", result.error_message_); - result = Utility::verifySignature("unknown", pub_key->get(), sig, text); + result = Utility::verifySignature("unknown", pub_key.get(), sig, text); EXPECT_EQ(false, result.result_); EXPECT_EQ("unknown is not supported.", result.error_message_); @@ -108,17 +106,15 @@ TEST(UtilityTest, TestVerifySignature) { data = "baddata"; text = std::vector(data, data + strlen(data)); - result = Utility::verifySignature(hash_func, pub_key->get(), sig, text); + result = Utility::verifySignature(hash_func, pub_key.get(), sig, text); EXPECT_EQ(false, result.result_); EXPECT_EQ("Failed to verify digest. Error code: 0", result.error_message_); data = "hello"; text = std::vector(data, data + strlen(data)); - result = Utility::verifySignature(hash_func, pub_key->get(), Hex::decode("000000"), text); + result = Utility::verifySignature(hash_func, pub_key.get(), Hex::decode("000000"), text); EXPECT_EQ(false, result.result_); EXPECT_EQ("Failed to verify digest. Error code: 0", result.error_message_); - - delete pub_key; } } // namespace From 9d24d6d9e7880da808e0a8ebee453afc2bb6827f Mon Sep 17 00:00:00 2001 From: Yan Xue Date: Wed, 5 Jun 2019 11:57:16 -0700 Subject: [PATCH 15/16] Resolve some comments Signed-off-by: Yan Xue --- docs/root/intro/version_history.rst | 2 +- source/common/crypto/utility.cc | 19 ++++++++----------- source/common/crypto/utility.h | 5 +++-- .../extensions/filters/http/lua/lua_filter.cc | 3 ++- 4 files changed, 14 insertions(+), 15 deletions(-) diff --git a/docs/root/intro/version_history.rst b/docs/root/intro/version_history.rst index 3f1aa1211f7e5..c69983e480189 100644 --- a/docs/root/intro/version_history.rst +++ b/docs/root/intro/version_history.rst @@ -17,7 +17,7 @@ Version history * ext_authz: added a `x-envoy-auth-partial-body` metadata header set to `false|true` indicating if there is a partial body sent in the authorization request message. * ext_authz: added configurable status code that allows customizing HTTP responses on filter check status errors. * ext_authz: added option to `ext_authz` that allows the filter clearing route cache. -* filter: exposed functions to Lua to verify digital signature. +* lua: exposed functions to Lua to verify digital signature. * grpc-json: added support for :ref:`auto mapping `. * health check: added :ref:`initial jitter ` to add jitter to the first health check in order to prevent thundering herd on Envoy startup. diff --git a/source/common/crypto/utility.cc b/source/common/crypto/utility.cc index 061263b21c215..659d29250f967 100644 --- a/source/common/crypto/utility.cc +++ b/source/common/crypto/utility.cc @@ -43,32 +43,29 @@ std::vector Utility::getSha256Hmac(const std::vector& key, return hmac; } -const VerificationOutput Utility::verifySignature(const absl::string_view& hash, void* ptr, +const VerificationOutput Utility::verifySignature(const absl::string_view hash, EVP_PKEY* pubKey, const std::vector& signature, const std::vector& text) { - // Step 1: get public key - auto pub_key = reinterpret_cast(ptr); - - // Step 2: initialize EVP_MD_CTX + // Step 1: initialize EVP_MD_CTX bssl::ScopedEVP_MD_CTX ctx; - // Step 3: initialize EVP_MD + // Step 2: initialize EVP_MD const EVP_MD* md = Utility::getHashFunction(hash); if (md == nullptr) { return {false, absl::StrCat(hash, " is not supported.")}; } - // Step 4: initialize EVP_DigestVerify - int ok = EVP_DigestVerifyInit(ctx.get(), nullptr, md, nullptr, pub_key); + // Step 3: initialize EVP_DigestVerify + int ok = EVP_DigestVerifyInit(ctx.get(), nullptr, md, nullptr, pubKey); if (!ok) { return {false, "Failed to initialize digest verify."}; } - // Step 5: verify signature + // Step 4: verify signature ok = EVP_DigestVerify(ctx.get(), signature.data(), signature.size(), text.data(), text.size()); - // Step 6: check result + // Step 5: check result if (ok == 1) { return {true, ""}; } @@ -81,7 +78,7 @@ PublicKeyPtr Utility::importPublicKey(const std::vector& key) { return PublicKeyPtr(EVP_parse_public_key(&cbs)); } -const EVP_MD* Utility::getHashFunction(const absl::string_view& name) { +const EVP_MD* Utility::getHashFunction(const absl::string_view name) { const std::string hash = absl::AsciiStrToLower(name); // Hash algorithms set refers diff --git a/source/common/crypto/utility.h b/source/common/crypto/utility.h index 8a9f374e0cefc..39bd5803eb715 100644 --- a/source/common/crypto/utility.h +++ b/source/common/crypto/utility.h @@ -20,6 +20,7 @@ struct VerificationOutput { /** * Error message when verification failed. + * TODO(crazyxy): switch to absl::StatusOr when available */ std::string error_message_; }; @@ -53,7 +54,7 @@ class Utility { * @return If the result_ is true, the error_message_ is empty; otherwise, * the error_message_ stores the error message */ - static const VerificationOutput verifySignature(const absl::string_view& hash, void* key, + static const VerificationOutput verifySignature(const absl::string_view hash, EVP_PKEY* key, const std::vector& signature, const std::vector& text); @@ -65,7 +66,7 @@ class Utility { static PublicKeyPtr importPublicKey(const std::vector& key); private: - static const EVP_MD* getHashFunction(const absl::string_view& name); + static const EVP_MD* getHashFunction(const absl::string_view name); }; } // namespace Crypto diff --git a/source/extensions/filters/http/lua/lua_filter.cc b/source/extensions/filters/http/lua/lua_filter.cc index 196c383048b92..1dd5edff1fad7 100644 --- a/source/extensions/filters/http/lua/lua_filter.cc +++ b/source/extensions/filters/http/lua/lua_filter.cc @@ -447,7 +447,8 @@ int StreamHandleWrapper::luaVerifySignature(lua_State* state) { const std::vector text_vec(clear_text, clear_text + text_len); // Step 5: verify signature - auto output = Common::Crypto::Utility::verifySignature(hash, ptr, sig_vec, text_vec); + auto output = Common::Crypto::Utility::verifySignature(hash, reinterpret_cast(ptr), + sig_vec, text_vec); lua_pushboolean(state, output.result_); if (output.result_) { From 26349b9689b6ebda7ff69d9a1ab9ac6542a0b06c Mon Sep 17 00:00:00 2001 From: Yan Xue Date: Wed, 5 Jun 2019 13:22:06 -0700 Subject: [PATCH 16/16] More comments Signed-off-by: Yan Xue --- docs/root/intro/version_history.rst | 2 +- source/common/crypto/utility.cc | 4 ++-- source/common/crypto/utility.h | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/root/intro/version_history.rst b/docs/root/intro/version_history.rst index c69983e480189..90ec364af4d63 100644 --- a/docs/root/intro/version_history.rst +++ b/docs/root/intro/version_history.rst @@ -17,7 +17,6 @@ Version history * ext_authz: added a `x-envoy-auth-partial-body` metadata header set to `false|true` indicating if there is a partial body sent in the authorization request message. * ext_authz: added configurable status code that allows customizing HTTP responses on filter check status errors. * ext_authz: added option to `ext_authz` that allows the filter clearing route cache. -* lua: exposed functions to Lua to verify digital signature. * grpc-json: added support for :ref:`auto mapping `. * health check: added :ref:`initial jitter ` to add jitter to the first health check in order to prevent thundering herd on Envoy startup. @@ -30,6 +29,7 @@ Version history * listener: added :ref:`source IP ` and :ref:`source port ` filter chain matching. +* lua: exposed functions to Lua to verify digital signature. * original_src filter: added the :ref:`filter`. * rbac: migrated from v2alpha to v2. * redis: add support for Redis cluster custom cluster type. diff --git a/source/common/crypto/utility.cc b/source/common/crypto/utility.cc index 659d29250f967..fbaff483eb3e2 100644 --- a/source/common/crypto/utility.cc +++ b/source/common/crypto/utility.cc @@ -43,7 +43,7 @@ std::vector Utility::getSha256Hmac(const std::vector& key, return hmac; } -const VerificationOutput Utility::verifySignature(const absl::string_view hash, EVP_PKEY* pubKey, +const VerificationOutput Utility::verifySignature(absl::string_view hash, EVP_PKEY* pubKey, const std::vector& signature, const std::vector& text) { // Step 1: initialize EVP_MD_CTX @@ -78,7 +78,7 @@ PublicKeyPtr Utility::importPublicKey(const std::vector& key) { return PublicKeyPtr(EVP_parse_public_key(&cbs)); } -const EVP_MD* Utility::getHashFunction(const absl::string_view name) { +const EVP_MD* Utility::getHashFunction(absl::string_view name) { const std::string hash = absl::AsciiStrToLower(name); // Hash algorithms set refers diff --git a/source/common/crypto/utility.h b/source/common/crypto/utility.h index 39bd5803eb715..9649f74b45190 100644 --- a/source/common/crypto/utility.h +++ b/source/common/crypto/utility.h @@ -54,7 +54,7 @@ class Utility { * @return If the result_ is true, the error_message_ is empty; otherwise, * the error_message_ stores the error message */ - static const VerificationOutput verifySignature(const absl::string_view hash, EVP_PKEY* key, + static const VerificationOutput verifySignature(absl::string_view hash, EVP_PKEY* key, const std::vector& signature, const std::vector& text); @@ -66,7 +66,7 @@ class Utility { static PublicKeyPtr importPublicKey(const std::vector& key); private: - static const EVP_MD* getHashFunction(const absl::string_view name); + static const EVP_MD* getHashFunction(absl::string_view name); }; } // namespace Crypto