Skip to content

Commit

Permalink
move common/crypto impl to extensions for openssl (envoyproxy#7344)
Browse files Browse the repository at this point in the history
Description: Move common/crypto impl (i.e. utility.cc) to extensions to make it clear that the impl is ssl-impl specific (e.g. boringgsl vs openssl) and easier to plug in an openssl impl. 
Risk Level: Low
Testing: Passes all standard tests
Docs Changes: None
Release Notes: None

Signed-off-by: William DeCoste <[email protected]>
  • Loading branch information
bdecoste authored and lizan committed Sep 16, 2019
1 parent c5738e1 commit 6ec15ce
Show file tree
Hide file tree
Showing 19 changed files with 223 additions and 78 deletions.
2 changes: 2 additions & 0 deletions CODEOWNERS
Original file line number Diff line number Diff line change
Expand Up @@ -57,3 +57,5 @@ extensions/filters/common/original_src @snowp @klarose
/*/extensions/filters/common/expr @kyessenov @yangminzhu
# webassembly common extension
/*/extensions/common/wasm @jplevyak @PiotrSikora
# common crypto extension
/*/extensions/common/crypto @lizan @PiotrSikora @bdecoste
5 changes: 5 additions & 0 deletions bazel/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -350,3 +350,8 @@ alias(
},
),
)

alias(
name = "crypto_utility_lib",
actual = "//source/extensions/common/crypto:utility_lib",
)
14 changes: 14 additions & 0 deletions include/envoy/common/crypto/BUILD
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
licenses(["notice"]) # Apache 2

load(
"//bazel:envoy_build_system.bzl",
"envoy_cc_library",
"envoy_package",
)

envoy_package()

envoy_cc_library(
name = "crypto_interface",
hdrs = ["crypto.h"],
)
24 changes: 24 additions & 0 deletions include/envoy/common/crypto/crypto.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
#pragma once

#include <memory>

namespace Envoy {
namespace Common {
namespace Crypto {

class CryptoObject {
public:
virtual ~CryptoObject() = default;
};

using CryptoObjectPtr = std::unique_ptr<CryptoObject>;

namespace Access {

template <class T> T* getTyped(CryptoObject& crypto) { return dynamic_cast<T*>(&crypto); }

} // namespace Access

} // namespace Crypto
} // namespace Common
} // namespace Envoy
1 change: 1 addition & 0 deletions source/common/config/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -311,6 +311,7 @@ envoy_cc_library(
srcs = ["remote_data_fetcher.cc"],
hdrs = ["remote_data_fetcher.h"],
deps = [
"//bazel:crypto_utility_lib",
"//include/envoy/upstream:cluster_manager_interface",
"//source/common/common:hex_lib",
"//source/common/crypto:utility_lib",
Expand Down
7 changes: 3 additions & 4 deletions source/common/crypto/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,12 @@ envoy_package()

envoy_cc_library(
name = "utility_lib",
srcs = ["utility.cc"],
hdrs = ["utility.h"],
external_deps = [
"ssl",
hdrs = [
"utility.h",
],
deps = [
"//include/envoy/buffer:buffer_interface",
"//include/envoy/common/crypto:crypto_interface",
"//source/common/common:assert_lib",
"//source/common/common:stack_array",
],
Expand Down
74 changes: 34 additions & 40 deletions source/common/crypto/utility.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@
#include <vector>

#include "envoy/buffer/buffer.h"
#include "envoy/common/crypto/crypto.h"

#include "absl/strings/string_view.h"
#include "openssl/evp.h"

namespace Envoy {
namespace Common {
Expand All @@ -25,50 +25,44 @@ struct VerificationOutput {
std::string error_message_;
};

using PublicKeyPtr = bssl::UniquePtr<EVP_PKEY>;
namespace Utility {

class Utility {
public:
/**
* Computes the SHA-256 digest of a buffer.
* @param buffer the buffer.
* @return a vector of bytes for the computed digest.
*/
static std::vector<uint8_t> getSha256Digest(const Buffer::Instance& buffer);

/**
* Computes the SHA-256 HMAC for a given key and message.
* @param key the HMAC function key.
* @param message message data for the HMAC function.
* @return a vector of bytes for the computed HMAC.
*/
static std::vector<uint8_t> getSha256Hmac(const std::vector<uint8_t>& key,
absl::string_view message);
/**
* Computes the SHA-256 digest of a buffer.
* @param buffer the buffer.
* @return a vector of bytes for the computed digest.
*/
std::vector<uint8_t> getSha256Digest(const Buffer::Instance& buffer);

/**
* Verify cryptographic signatures.
* @param hash hash function(including SHA1, SHA224, SHA256, SHA384, SHA512)
* @param key pointer to public key
* @param signature signature
* @param text clear text
* @return If the result_ is true, the error_message_ is empty; otherwise,
* the error_message_ stores the error message
*/
static const VerificationOutput verifySignature(absl::string_view hash, EVP_PKEY* key,
const std::vector<uint8_t>& signature,
const std::vector<uint8_t>& text);
/**
* Computes the SHA-256 HMAC for a given key and message.
* @param key the HMAC function key.
* @param message message data for the HMAC function.
* @return a vector of bytes for the computed HMAC.
*/
std::vector<uint8_t> getSha256Hmac(const std::vector<uint8_t>& key, absl::string_view message);

/**
* Import public key.
* @param key key string
* @return pointer to public key
*/
static PublicKeyPtr importPublicKey(const std::vector<uint8_t>& key);
/**
* Verify cryptographic signatures.
* @param hash hash function(including SHA1, SHA224, SHA256, SHA384, SHA512)
* @param key pointer to EVP_PKEY public key
* @param signature signature
* @param text clear text
* @return If the result_ is true, the error_message_ is empty; otherwise,
* the error_message_ stores the error message
*/
const VerificationOutput verifySignature(absl::string_view hash, CryptoObject& key,
const std::vector<uint8_t>& signature,
const std::vector<uint8_t>& text);

private:
static const EVP_MD* getHashFunction(absl::string_view name);
};
/**
* Import public key.
* @param key key string
* @return pointer to EVP_PKEY public key
*/
CryptoObjectPtr importPublicKey(const std::vector<uint8_t>& key);

} // namespace Utility
} // namespace Crypto
} // namespace Common
} // namespace Envoy
29 changes: 29 additions & 0 deletions source/extensions/common/crypto/BUILD
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
licenses(["notice"]) # Apache 2

load(
"//bazel:envoy_build_system.bzl",
"envoy_cc_library",
"envoy_package",
)

envoy_package()

envoy_cc_library(
name = "utility_lib",
srcs = [
"crypto_impl.cc",
"utility.cc",
],
hdrs = [
"crypto_impl.h",
],
external_deps = [
"ssl",
],
deps = [
"//include/envoy/buffer:buffer_interface",
"//source/common/common:assert_lib",
"//source/common/common:stack_array",
"//source/common/crypto:utility_lib",
],
)
13 changes: 13 additions & 0 deletions source/extensions/common/crypto/crypto_impl.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#include "extensions/common/crypto/crypto_impl.h"

namespace Envoy {
namespace Common {
namespace Crypto {

EVP_PKEY* PublicKeyObject::getEVP_PKEY() const { return pkey_.get(); }

void PublicKeyObject::setEVP_PKEY(EVP_PKEY* pkey) { pkey_.reset(pkey); }

} // namespace Crypto
} // namespace Common
} // namespace Envoy
26 changes: 26 additions & 0 deletions source/extensions/common/crypto/crypto_impl.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
#pragma once

#include "envoy/common/crypto/crypto.h"

#include "openssl/base.h"
#include "openssl/evp.h"

namespace Envoy {
namespace Common {
namespace Crypto {

class PublicKeyObject : public Envoy::Common::Crypto::CryptoObject {
public:
PublicKeyObject() = default;
PublicKeyObject(EVP_PKEY* pkey) : pkey_(pkey) {}
PublicKeyObject(const PublicKeyObject& pkey_wrapper);
EVP_PKEY* getEVP_PKEY() const;
void setEVP_PKEY(EVP_PKEY* pkey);

private:
bssl::UniquePtr<EVP_PKEY> pkey_;
};

} // namespace Crypto
} // namespace Common
} // namespace Envoy
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
#include "common/common/assert.h"
#include "common/common/stack_array.h"

#include "extensions/common/crypto/crypto_impl.h"

#include "absl/strings/ascii.h"
#include "absl/strings/str_cat.h"
#include "openssl/bytestring.h"
Expand All @@ -13,7 +15,11 @@ namespace Envoy {
namespace Common {
namespace Crypto {

std::vector<uint8_t> Utility::getSha256Digest(const Buffer::Instance& buffer) {
namespace Utility {

const EVP_MD* getHashFunction(absl::string_view name);

std::vector<uint8_t> getSha256Digest(const Buffer::Instance& buffer) {
std::vector<uint8_t> digest(SHA256_DIGEST_LENGTH);
EVP_MD_CTX* ctx(EVP_MD_CTX_new());
auto rc = EVP_DigestInit(ctx, EVP_sha256());
Expand All @@ -31,8 +37,7 @@ std::vector<uint8_t> Utility::getSha256Digest(const Buffer::Instance& buffer) {
return digest;
}

std::vector<uint8_t> Utility::getSha256Hmac(const std::vector<uint8_t>& key,
absl::string_view message) {
std::vector<uint8_t> getSha256Hmac(const std::vector<uint8_t>& key, absl::string_view message) {
std::vector<uint8_t> hmac(SHA256_DIGEST_LENGTH);
const auto ret =
HMAC(EVP_sha256(), key.data(), key.size(), reinterpret_cast<const uint8_t*>(message.data()),
Expand All @@ -41,21 +46,28 @@ std::vector<uint8_t> Utility::getSha256Hmac(const std::vector<uint8_t>& key,
return hmac;
}

const VerificationOutput Utility::verifySignature(absl::string_view hash, EVP_PKEY* pubKey,
const std::vector<uint8_t>& signature,
const std::vector<uint8_t>& text) {
const VerificationOutput verifySignature(absl::string_view hash, CryptoObject& key,
const std::vector<uint8_t>& signature,
const std::vector<uint8_t>& text) {
// Step 1: initialize EVP_MD_CTX
bssl::ScopedEVP_MD_CTX ctx;

// Step 2: initialize EVP_MD
const EVP_MD* md = Utility::getHashFunction(hash);
const EVP_MD* md = getHashFunction(hash);

if (md == nullptr) {
return {false, absl::StrCat(hash, " is not supported.")};
}

// Step 3: initialize EVP_DigestVerify
int ok = EVP_DigestVerifyInit(ctx.get(), nullptr, md, nullptr, pubKey);
auto pkey_wrapper = Common::Crypto::Access::getTyped<Common::Crypto::PublicKeyObject>(key);
EVP_PKEY* pkey = pkey_wrapper->getEVP_PKEY();

if (pkey == nullptr) {
free(pkey_wrapper);
return {false, "Failed to initialize digest verify."};
}

int ok = EVP_DigestVerifyInit(ctx.get(), nullptr, md, nullptr, pkey);
if (!ok) {
return {false, "Failed to initialize digest verify."};
}
Expand All @@ -71,12 +83,13 @@ const VerificationOutput Utility::verifySignature(absl::string_view hash, EVP_PK
return {false, absl::StrCat("Failed to verify digest. Error code: ", ok)};
}

PublicKeyPtr Utility::importPublicKey(const std::vector<uint8_t>& key) {
CryptoObjectPtr importPublicKey(const std::vector<uint8_t>& key) {
CBS cbs({key.data(), key.size()});
return PublicKeyPtr(EVP_parse_public_key(&cbs));

return std::make_unique<PublicKeyObject>(EVP_parse_public_key(&cbs));
}

const EVP_MD* Utility::getHashFunction(absl::string_view name) {
const EVP_MD* getHashFunction(absl::string_view name) {
const std::string hash = absl::AsciiStrToLower(name);

// Hash algorithms set refers
Expand All @@ -96,6 +109,7 @@ const EVP_MD* Utility::getHashFunction(absl::string_view name) {
}
}

} // namespace Utility
} // namespace Crypto
} // namespace Common
} // namespace Envoy
1 change: 1 addition & 0 deletions source/extensions/filters/http/common/aws/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ envoy_cc_library(
"//source/common/crypto:utility_lib",
"//source/common/http:headers_lib",
"//source/common/singleton:const_singleton",
"//source/extensions/common/crypto:utility_lib",
],
)

Expand Down
2 changes: 2 additions & 0 deletions source/extensions/filters/http/lua/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ envoy_cc_library(
"//source/common/common:enum_to_int",
"//source/common/crypto:utility_lib",
"//source/common/http:message_lib",
"//source/extensions/common/crypto:utility_lib",
"//source/extensions/filters/common/lua:lua_lib",
"//source/extensions/filters/common/lua:wrappers_lib",
"//source/extensions/filters/http:well_known_names",
Expand All @@ -39,6 +40,7 @@ envoy_cc_library(
"//include/envoy/stream_info:stream_info_interface",
"//source/common/crypto:utility_lib",
"//source/common/http:utility_lib",
"//source/extensions/common/crypto:utility_lib",
"//source/extensions/filters/common/lua:lua_lib",
"//source/extensions/filters/common/lua:wrappers_lib",
],
Expand Down
11 changes: 4 additions & 7 deletions source/extensions/filters/http/lua/lua_filter.cc
Original file line number Diff line number Diff line change
Expand Up @@ -455,11 +455,9 @@ int StreamHandleWrapper::luaVerifySignature(lua_State* state) {
const char* clear_text = luaL_checkstring(state, 6);
int text_len = luaL_checknumber(state, 7);
const std::vector<uint8_t> text_vec(clear_text, clear_text + text_len);

// Step 5: verify signature
auto output = Common::Crypto::Utility::verifySignature(hash, reinterpret_cast<EVP_PKEY*>(ptr),
sig_vec, text_vec);

auto crypto = reinterpret_cast<Common::Crypto::CryptoObject*>(ptr);
auto output = Common::Crypto::Utility::verifySignature(hash, *crypto, sig_vec, text_vec);
lua_pushboolean(state, output.result_);
if (output.result_) {
lua_pushnil(state);
Expand All @@ -474,12 +472,11 @@ int StreamHandleWrapper::luaImportPublicKey(lua_State* state) {
const char* str = luaL_checkstring(state, 2);
int n = luaL_checknumber(state, 3);
std::vector<uint8_t> key(str, str + n);

if (public_key_wrapper_.get() != nullptr) {
public_key_wrapper_.pushStack();
} else {
public_key_wrapper_.reset(
PublicKeyWrapper::create(state, Common::Crypto::Utility::importPublicKey(key)), true);
Common::Crypto::CryptoObjectPtr crypto_ptr = Common::Crypto::Utility::importPublicKey(key);
public_key_wrapper_.reset(PublicKeyWrapper::create(state, std::move(crypto_ptr)), true);
}

return 1;
Expand Down
Loading

0 comments on commit 6ec15ce

Please sign in to comment.