Line data Source code
1 : #include "source/common/crypto/utility_impl.h" 2 : 3 : #include "source/common/common/assert.h" 4 : #include "source/common/crypto/crypto_impl.h" 5 : 6 : #include "absl/container/fixed_array.h" 7 : #include "absl/strings/ascii.h" 8 : #include "absl/strings/str_cat.h" 9 : 10 : namespace Envoy { 11 : namespace Common { 12 : namespace Crypto { 13 : 14 29 : std::vector<uint8_t> UtilityImpl::getSha256Digest(const Buffer::Instance& buffer) { 15 29 : std::vector<uint8_t> digest(SHA256_DIGEST_LENGTH); 16 29 : bssl::ScopedEVP_MD_CTX ctx; 17 29 : auto rc = EVP_DigestInit(ctx.get(), EVP_sha256()); 18 29 : RELEASE_ASSERT(rc == 1, "Failed to init digest context"); 19 29 : for (const auto& slice : buffer.getRawSlices()) { 20 29 : rc = EVP_DigestUpdate(ctx.get(), slice.mem_, slice.len_); 21 29 : RELEASE_ASSERT(rc == 1, "Failed to update digest"); 22 29 : } 23 29 : rc = EVP_DigestFinal(ctx.get(), digest.data(), nullptr); 24 29 : RELEASE_ASSERT(rc == 1, "Failed to finalize digest"); 25 29 : return digest; 26 29 : } 27 : 28 : std::vector<uint8_t> UtilityImpl::getSha256Hmac(const std::vector<uint8_t>& key, 29 0 : absl::string_view message) { 30 0 : std::vector<uint8_t> hmac(SHA256_DIGEST_LENGTH); 31 0 : const auto ret = 32 0 : HMAC(EVP_sha256(), key.data(), key.size(), reinterpret_cast<const uint8_t*>(message.data()), 33 0 : message.size(), hmac.data(), nullptr); 34 0 : RELEASE_ASSERT(ret != nullptr, "Failed to create HMAC"); 35 0 : return hmac; 36 0 : } 37 : 38 : const VerificationOutput UtilityImpl::verifySignature(absl::string_view hash, CryptoObject& key, 39 : const std::vector<uint8_t>& signature, 40 183 : const std::vector<uint8_t>& text) { 41 : // Step 1: initialize EVP_MD_CTX 42 183 : bssl::ScopedEVP_MD_CTX ctx; 43 : 44 : // Step 2: initialize EVP_MD 45 183 : const EVP_MD* md = getHashFunction(hash); 46 : 47 183 : if (md == nullptr) { 48 150 : return {false, absl::StrCat(hash, " is not supported.")}; 49 150 : } 50 : // Step 3: initialize EVP_DigestVerify 51 33 : auto pkey_wrapper = Common::Crypto::Access::getTyped<Common::Crypto::PublicKeyObject>(key); 52 33 : EVP_PKEY* pkey = pkey_wrapper->getEVP_PKEY(); 53 : 54 33 : if (pkey == nullptr) { 55 11 : return {false, "Failed to initialize digest verify."}; 56 11 : } 57 : 58 22 : int ok = EVP_DigestVerifyInit(ctx.get(), nullptr, md, nullptr, pkey); 59 22 : if (!ok) { 60 0 : return {false, "Failed to initialize digest verify."}; 61 0 : } 62 : 63 : // Step 4: verify signature 64 22 : ok = EVP_DigestVerify(ctx.get(), signature.data(), signature.size(), text.data(), text.size()); 65 : 66 : // Step 5: check result 67 22 : if (ok == 1) { 68 1 : return {true, ""}; 69 1 : } 70 : 71 21 : return {false, absl::StrCat("Failed to verify digest. Error code: ", ok)}; 72 22 : } 73 : 74 183 : CryptoObjectPtr UtilityImpl::importPublicKey(const std::vector<uint8_t>& key) { 75 183 : CBS cbs({key.data(), key.size()}); 76 : 77 183 : return std::make_unique<PublicKeyObject>(EVP_parse_public_key(&cbs)); 78 183 : } 79 : 80 183 : const EVP_MD* UtilityImpl::getHashFunction(absl::string_view name) { 81 183 : const std::string hash = absl::AsciiStrToLower(name); 82 : 83 : // Hash algorithms set refers 84 : // https://github.com/google/boringssl/blob/master/include/openssl/digest.h 85 183 : if (hash == "sha1") { 86 10 : return EVP_sha1(); 87 173 : } else if (hash == "sha224") { 88 4 : return EVP_sha224(); 89 169 : } else if (hash == "sha256") { 90 9 : return EVP_sha256(); 91 160 : } else if (hash == "sha384") { 92 7 : return EVP_sha384(); 93 153 : } else if (hash == "sha512") { 94 3 : return EVP_sha512(); 95 150 : } else { 96 150 : return nullptr; 97 150 : } 98 183 : } 99 : 100 : // Register the crypto utility singleton. 101 : static Crypto::ScopedUtilitySingleton* utility_ = 102 : new Crypto::ScopedUtilitySingleton(std::make_unique<Crypto::UtilityImpl>()); 103 : 104 : } // namespace Crypto 105 : } // namespace Common 106 : } // namespace Envoy