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/strings/ascii.h"
7
#include "absl/strings/str_cat.h"
8
#include "absl/types/span.h"
9
#include "openssl/pem.h"
10

            
11
namespace Envoy {
12
namespace Common {
13
namespace Crypto {
14

            
15
11646
std::vector<uint8_t> UtilityImpl::getSha256Digest(const Buffer::Instance& buffer) {
16
11646
  std::vector<uint8_t> digest(SHA256_DIGEST_LENGTH);
17
11646
  bssl::ScopedEVP_MD_CTX ctx;
18
11646
  auto rc = EVP_DigestInit(ctx.get(), EVP_sha256());
19
11646
  RELEASE_ASSERT(rc == 1, "Failed to init digest context");
20
11662
  for (const auto& slice : buffer.getRawSlices()) {
21
674
    rc = EVP_DigestUpdate(ctx.get(), slice.mem_, slice.len_);
22
674
    RELEASE_ASSERT(rc == 1, "Failed to update digest");
23
674
  }
24
11646
  rc = EVP_DigestFinal(ctx.get(), digest.data(), nullptr);
25
11646
  RELEASE_ASSERT(rc == 1, "Failed to finalize digest");
26
11646
  return digest;
27
11646
}
28

            
29
std::vector<uint8_t> UtilityImpl::getSha256Hmac(absl::Span<const uint8_t> key,
30
1124
                                                absl::string_view message) {
31
1124
  std::vector<uint8_t> hmac(SHA256_DIGEST_LENGTH);
32
1124
  const auto ret =
33
1124
      HMAC(EVP_sha256(), key.data(), key.size(), reinterpret_cast<const uint8_t*>(message.data()),
34
1124
           message.size(), hmac.data(), nullptr);
35
1124
  RELEASE_ASSERT(ret != nullptr, "Failed to create HMAC");
36
1124
  return hmac;
37
1124
}
38

            
39
absl::Status UtilityImpl::verifySignature(absl::string_view hash_function, PKeyObject& key,
40
                                          absl::Span<const uint8_t> signature,
41
50
                                          absl::Span<const uint8_t> text) {
42
50
  bssl::ScopedEVP_MD_CTX ctx;
43

            
44
50
  const EVP_MD* md = getHashFunction(hash_function);
45

            
46
50
  if (md == nullptr) {
47
4
    return absl::InvalidArgumentError(absl::StrCat(hash_function, " is not supported."));
48
4
  }
49
46
  EVP_PKEY* pkey = key.getEVP_PKEY();
50

            
51
46
  if (pkey == nullptr) {
52
5
    return absl::InternalError("Failed to initialize digest verify.");
53
5
  }
54

            
55
41
  int ok = EVP_DigestVerifyInit(ctx.get(), nullptr, md, nullptr, pkey);
56
41
  if (!ok) {
57
    return absl::InternalError("Failed to initialize digest verify.");
58
  }
59

            
60
41
  ok = EVP_DigestVerify(ctx.get(), signature.data(), signature.size(), text.data(), text.size());
61

            
62
41
  if (ok == 1) {
63
37
    return absl::OkStatus();
64
37
  }
65

            
66
4
  return absl::InternalError(absl::StrCat("Failed to verify digest. Error code: ", ok));
67
41
}
68

            
69
absl::StatusOr<std::vector<uint8_t>> UtilityImpl::sign(absl::string_view hash_function,
70
                                                       PKeyObject& key,
71
39
                                                       absl::Span<const uint8_t> text) {
72
39
  bssl::ScopedEVP_MD_CTX ctx;
73

            
74
39
  const EVP_MD* md = getHashFunction(hash_function);
75

            
76
39
  if (md == nullptr) {
77
13
    return absl::InvalidArgumentError(absl::StrCat(hash_function, " is not supported."));
78
13
  }
79

            
80
26
  EVP_PKEY* pkey = key.getEVP_PKEY();
81

            
82
26
  if (pkey == nullptr) {
83
3
    return absl::InternalError("Invalid key type: private key required for signing operation.");
84
3
  }
85

            
86
23
  int ok = EVP_DigestSignInit(ctx.get(), nullptr, md, nullptr, pkey);
87
23
  if (!ok) {
88
    return absl::InternalError("Invalid private key: key data is corrupted or malformed.");
89
  }
90

            
91
23
  size_t sig_len = 0;
92
23
  ok = EVP_DigestSign(ctx.get(), nullptr, &sig_len, text.data(), text.size());
93
23
  if (!ok) {
94
    return absl::InternalError("Failed to get signature length.");
95
  }
96

            
97
23
  std::vector<uint8_t> signature(sig_len);
98
23
  ok = EVP_DigestSign(ctx.get(), signature.data(), &sig_len, text.data(), text.size());
99
23
  if (!ok) {
100
    return absl::InternalError("Failed to create signature.");
101
  }
102

            
103
23
  RELEASE_ASSERT(signature.size() >= sig_len, "signature.size() >= sig_len");
104
23
  signature.resize(sig_len);
105
23
  return signature;
106
23
}
107

            
108
namespace {
109
// Template helper for importing keys with different formats and types
110
template <typename KeyObjectType, typename ParseFunction>
111
20
PKeyObjectPtr importKeyPEM(absl::string_view key, ParseFunction parse_func) {
112
  // PEM format: Use PEM parsing which automatically handles both PKCS#1 and PKCS#8 formats
113
20
  bssl::UniquePtr<BIO> bio(BIO_new_mem_buf(key.data(), key.size()));
114
20
  if (!bio) {
115
    return std::make_unique<KeyObjectType>(nullptr);
116
  }
117
20
  return std::make_unique<KeyObjectType>(parse_func(bio.get(), nullptr, nullptr, nullptr));
118
20
}
119

            
120
template <typename KeyObjectType, typename ParseFunction>
121
54
PKeyObjectPtr importKeyDER(absl::Span<const uint8_t> key, ParseFunction parse_func) {
122
  // DER format: Use DER parsing
123
54
  CBS cbs({key.data(), key.size()});
124
54
  return std::make_unique<KeyObjectType>(parse_func(&cbs));
125
54
}
126
} // namespace
127

            
128
15
PKeyObjectPtr UtilityImpl::importPublicKeyPEM(absl::string_view key) {
129
15
  return importKeyPEM<PKeyObject>(key, PEM_read_bio_PUBKEY);
130
15
}
131

            
132
39
PKeyObjectPtr UtilityImpl::importPublicKeyDER(absl::Span<const uint8_t> key) {
133
39
  return importKeyDER<PKeyObject>(key, EVP_parse_public_key);
134
39
}
135

            
136
5
PKeyObjectPtr UtilityImpl::importPrivateKeyPEM(absl::string_view key) {
137
5
  return importKeyPEM<PKeyObject>(key, PEM_read_bio_PrivateKey);
138
5
}
139

            
140
15
PKeyObjectPtr UtilityImpl::importPrivateKeyDER(absl::Span<const uint8_t> key) {
141
15
  return importKeyDER<PKeyObject>(key, EVP_parse_private_key);
142
15
}
143

            
144
89
const EVP_MD* UtilityImpl::getHashFunction(absl::string_view name) {
145
89
  const std::string hash = absl::AsciiStrToLower(name);
146

            
147
  // Hash algorithms set refers
148
  // https://github.com/google/boringssl/blob/main/include/openssl/digest.h
149
89
  if (hash == "sha1") {
150
8
    return EVP_sha1();
151
81
  } else if (hash == "sha224") {
152
7
    return EVP_sha224();
153
74
  } else if (hash == "sha256") {
154
42
    return EVP_sha256();
155
56
  } else if (hash == "sha384") {
156
8
    return EVP_sha384();
157
24
  } else if (hash == "sha512") {
158
7
    return EVP_sha512();
159
17
  } else {
160
17
    return nullptr;
161
17
  }
162
89
}
163

            
164
// Register the crypto utility singleton.
165
static Crypto::ScopedUtilitySingleton* utility_ =
166
    new Crypto::ScopedUtilitySingleton(std::make_unique<Crypto::UtilityImpl>());
167

            
168
} // namespace Crypto
169
} // namespace Common
170
} // namespace Envoy