Skip to content

Commit a5b66c6

Browse files
Merge pull request ClickHouse#78745 from rschu1ze/openssl-api
Further modernization of OpenSSL calls
2 parents 81a654b + b483d88 commit a5b66c6

File tree

5 files changed

+82
-108
lines changed

5 files changed

+82
-108
lines changed

src/Common/OpenSSLHelpers.cpp

Lines changed: 12 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -46,13 +46,13 @@ void encodeSHA256(const void * text, size_t size, unsigned char * out)
4646
auto ctx = std::unique_ptr<EVP_MD_CTX, decltype(&EVP_MD_CTX_free)>(EVP_MD_CTX_new(), EVP_MD_CTX_free);
4747

4848
if (!EVP_DigestInit(ctx.get(), EVP_sha256()))
49-
throw Exception(ErrorCodes::OPENSSL_ERROR, "SHA256 EVP_DigestInit failed: {}", getOpenSSLErrors());
49+
throw Exception(ErrorCodes::OPENSSL_ERROR, "EVP_DigestInit failed: {}", getOpenSSLErrors());
5050

5151
if (!EVP_DigestUpdate(ctx.get(), text, size))
52-
throw Exception(ErrorCodes::OPENSSL_ERROR, "SHA256 EVP_DigestUpdate failed: {}", getOpenSSLErrors());
52+
throw Exception(ErrorCodes::OPENSSL_ERROR, "EVP_DigestUpdate failed: {}", getOpenSSLErrors());
5353

5454
if (!EVP_DigestFinal(ctx.get(), out, nullptr))
55-
throw Exception(ErrorCodes::OPENSSL_ERROR, "SHA256 EVP_DigestFinal failed: {}", getOpenSSLErrors());
55+
throw Exception(ErrorCodes::OPENSSL_ERROR, "EVP_DigestFinal failed: {}", getOpenSSLErrors());
5656
}
5757

5858
std::vector<uint8_t> hmacSHA256(const std::vector<uint8_t> & key, const std::string & data)
@@ -61,31 +61,28 @@ std::vector<uint8_t> hmacSHA256(const std::vector<uint8_t> & key, const std::str
6161
size_t out_len = 0;
6262

6363
using MacPtr = std::unique_ptr<EVP_MAC, decltype(&EVP_MAC_free)>;
64-
using CtxPtr = std::unique_ptr<EVP_MAC_CTX, decltype(&EVP_MAC_CTX_free)>;
65-
6664
MacPtr mac(EVP_MAC_fetch(nullptr, "HMAC", nullptr), &EVP_MAC_free);
6765
if (!mac)
68-
throw Exception(ErrorCodes::OPENSSL_ERROR, "Failed to fetch HMAC algorithm");
66+
throw Exception(ErrorCodes::OPENSSL_ERROR, "EVP_MAC_fetch failed: {}", getOpenSSLErrors());
6967

68+
using CtxPtr = std::unique_ptr<EVP_MAC_CTX, decltype(&EVP_MAC_CTX_free)>;
7069
CtxPtr ctx(EVP_MAC_CTX_new(mac.get()), &EVP_MAC_CTX_free);
7170
if (!ctx)
72-
throw Exception(ErrorCodes::OPENSSL_ERROR, "Failed to create HMAC context");
71+
throw Exception(ErrorCodes::OPENSSL_ERROR, "EVP_MAC_CTX_new failed: {}", getOpenSSLErrors());
7372

7473
OSSL_PARAM params[] = {
7574
OSSL_PARAM_utf8_string("digest", const_cast<char*>("SHA256"), 0),
7675
OSSL_PARAM_END
7776
};
7877

79-
if (EVP_MAC_init(ctx.get(), key.data(), key.size(), params) != 1)
80-
throw Exception(ErrorCodes::OPENSSL_ERROR, "EVP_MAC_init failed");
78+
if (!EVP_MAC_init(ctx.get(), key.data(), key.size(), params))
79+
throw Exception(ErrorCodes::OPENSSL_ERROR, "EVP_MAC_init failed: {}", getOpenSSLErrors());
8180

82-
if (EVP_MAC_update(ctx.get(),
83-
reinterpret_cast<const unsigned char*>(data.data()),
84-
data.size()) != 1)
85-
throw Exception(ErrorCodes::OPENSSL_ERROR, "EVP_MAC_update failed");
81+
if (!EVP_MAC_update(ctx.get(), reinterpret_cast<const unsigned char*>(data.data()), data.size()))
82+
throw Exception(ErrorCodes::OPENSSL_ERROR, "EVP_MAC_update failed: {}", getOpenSSLErrors());
8683

87-
if (EVP_MAC_final(ctx.get(), result.data(), &out_len, result.size()) != 1)
88-
throw Exception(ErrorCodes::OPENSSL_ERROR, "EVP_MAC_final failed");
84+
if (!EVP_MAC_final(ctx.get(), result.data(), &out_len, result.size()))
85+
throw Exception(ErrorCodes::OPENSSL_ERROR, "EVP_MAC_final failed: {}", getOpenSSLErrors());
8986

9087
result.resize(out_len);
9188
return result;

src/Compression/CompressionCodecEncrypted.cpp

Lines changed: 64 additions & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -125,62 +125,52 @@ size_t encrypt(std::string_view plaintext, char * ciphertext_and_tag, Encryption
125125
{
126126
int out_len;
127127
int ciphertext_len;
128-
EVP_CIPHER_CTX * ctx;
129-
EVP_CIPHER * cipher;
130128

131-
ctx = EVP_CIPHER_CTX_new();
129+
using EVP_CIPHER_CTX_ptr = std::unique_ptr<EVP_CIPHER_CTX, decltype(&EVP_CIPHER_CTX_free)>;
130+
const auto ctx = EVP_CIPHER_CTX_ptr(EVP_CIPHER_CTX_new(), EVP_CIPHER_CTX_free);
132131
if (!ctx)
133132
throw Exception(ErrorCodes::OPENSSL_ERROR, "EVP_CIPHER_CTX_new failed: {}", getOpenSSLErrors());
134133

135-
try
136-
{
137-
cipher = EVP_CIPHER_fetch(nullptr, getMethod(method), nullptr);
138-
if (!cipher)
139-
throw Exception(ErrorCodes::OPENSSL_ERROR, "EVP_CIPHER_fetch failed: {}", getOpenSSLErrors());
134+
using EVP_CIPHER_ptr = std::unique_ptr<EVP_CIPHER, decltype(&EVP_CIPHER_free)>;
135+
const auto cipher = EVP_CIPHER_ptr(EVP_CIPHER_fetch(nullptr, getMethod(method), nullptr), EVP_CIPHER_free);
136+
if (!cipher)
137+
throw Exception(ErrorCodes::OPENSSL_ERROR, "EVP_CIPHER_fetch failed: {}", getOpenSSLErrors());
140138

141-
if (!EVP_EncryptInit_ex(ctx, cipher, nullptr, nullptr, nullptr))
142-
throw Exception(ErrorCodes::OPENSSL_ERROR, "EVP_EncryptInit_ex failed: {}", getOpenSSLErrors());
139+
if (!EVP_EncryptInit_ex(ctx.get(), cipher.get(), nullptr, nullptr, nullptr))
140+
throw Exception(ErrorCodes::OPENSSL_ERROR, "EVP_EncryptInit_ex failed: {}", getOpenSSLErrors());
143141

144-
if (!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_IVLEN, static_cast<int32_t>(nonce.size()), nullptr))
145-
throw Exception(ErrorCodes::OPENSSL_ERROR, "EVP_CIPHER_CTX_ctrl failed: {}", getOpenSSLErrors());
142+
if (!EVP_CIPHER_CTX_ctrl(ctx.get(), EVP_CTRL_GCM_SET_IVLEN, static_cast<int32_t>(nonce.size()), nullptr))
143+
throw Exception(ErrorCodes::OPENSSL_ERROR, "EVP_CIPHER_CTX_ctrl failed: {}", getOpenSSLErrors());
146144

147-
if (!EVP_EncryptInit_ex(ctx, nullptr, nullptr,
148-
reinterpret_cast<const uint8_t*>(key.data()),
149-
reinterpret_cast<const uint8_t *>(nonce.data())))
150-
throw Exception(ErrorCodes::OPENSSL_ERROR, "EVP_EncryptInit_ex failed: {}", getOpenSSLErrors());
145+
if (!EVP_EncryptInit_ex(ctx.get(), nullptr, nullptr,
146+
reinterpret_cast<const uint8_t*>(key.data()),
147+
reinterpret_cast<const uint8_t *>(nonce.data())))
148+
throw Exception(ErrorCodes::OPENSSL_ERROR, "EVP_EncryptInit_ex failed: {}", getOpenSSLErrors());
151149

152-
if (!EVP_EncryptUpdate(ctx,
153-
reinterpret_cast<uint8_t *>(ciphertext_and_tag),
154-
&out_len,
155-
reinterpret_cast<const uint8_t *>(plaintext.data()),
156-
static_cast<int32_t>(plaintext.size())))
157-
throw Exception(ErrorCodes::OPENSSL_ERROR, "EVP_EncryptUpdate failed: {}", getOpenSSLErrors());
150+
if (!EVP_EncryptUpdate(ctx.get(),
151+
reinterpret_cast<uint8_t *>(ciphertext_and_tag),
152+
&out_len,
153+
reinterpret_cast<const uint8_t *>(plaintext.data()),
154+
static_cast<int32_t>(plaintext.size())))
155+
throw Exception(ErrorCodes::OPENSSL_ERROR, "EVP_EncryptUpdate failed: {}", getOpenSSLErrors());
158156

159-
__msan_unpoison(ciphertext_and_tag, out_len); /// OpenSSL uses assembly which evades msan's analysis
157+
__msan_unpoison(ciphertext_and_tag, out_len); /// OpenSSL uses assembly which evades msan's analysis
160158

161-
ciphertext_len = out_len;
159+
ciphertext_len = out_len;
162160

163-
if (!EVP_EncryptFinal_ex(ctx,
164-
reinterpret_cast<uint8_t *>(ciphertext_and_tag) + out_len,
165-
reinterpret_cast<int32_t *>(&out_len)))
166-
throw Exception(ErrorCodes::OPENSSL_ERROR, "EVP_EncryptFinal_ex failed: {}", getOpenSSLErrors());
161+
if (!EVP_EncryptFinal_ex(ctx.get(),
162+
reinterpret_cast<uint8_t *>(ciphertext_and_tag) + out_len,
163+
reinterpret_cast<int32_t *>(&out_len)))
164+
throw Exception(ErrorCodes::OPENSSL_ERROR, "EVP_EncryptFinal_ex failed: {}", getOpenSSLErrors());
167165

168-
__msan_unpoison(ciphertext_and_tag, out_len); /// OpenSSL uses assembly which evades msan's analysis
166+
__msan_unpoison(ciphertext_and_tag, out_len); /// OpenSSL uses assembly which evades msan's analysis
169167

170-
ciphertext_len += out_len;
168+
ciphertext_len += out_len;
169+
170+
/// Get the tag
171+
if (!EVP_CIPHER_CTX_ctrl(ctx.get(), EVP_CTRL_GCM_GET_TAG, tag_size, reinterpret_cast<uint8_t *>(ciphertext_and_tag) + plaintext.size()))
172+
throw Exception(ErrorCodes::OPENSSL_ERROR, "EVP_CIPHER_CTX_ctrl failed: {}", getOpenSSLErrors());
171173

172-
/// Get the tag
173-
if (!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_GET_TAG, tag_size, reinterpret_cast<uint8_t *>(ciphertext_and_tag) + plaintext.size()))
174-
throw Exception(ErrorCodes::OPENSSL_ERROR, "EVP_CIPHER_CTX_ctrl failed: {}", getOpenSSLErrors());
175-
}
176-
catch (...)
177-
{
178-
EVP_CIPHER_free(cipher);
179-
EVP_CIPHER_CTX_free(ctx);
180-
throw;
181-
}
182-
EVP_CIPHER_free(cipher);
183-
EVP_CIPHER_CTX_free(ctx);
184174
return ciphertext_len + tag_size;
185175
}
186176

@@ -192,62 +182,51 @@ size_t decrypt(std::string_view ciphertext, char * plaintext, EncryptionMethod m
192182
{
193183
int out_len;
194184
int plaintext_len;
195-
EVP_CIPHER_CTX * ctx;
196-
EVP_CIPHER * cipher;
197185

198-
ctx = EVP_CIPHER_CTX_new();
186+
using EVP_CIPHER_CTX_ptr = std::unique_ptr<EVP_CIPHER_CTX, decltype(&EVP_CIPHER_CTX_free)>;
187+
const auto ctx = EVP_CIPHER_CTX_ptr(EVP_CIPHER_CTX_new(), EVP_CIPHER_CTX_free);
199188
if (!ctx)
200189
throw Exception(ErrorCodes::OPENSSL_ERROR, "EVP_CIPHER_CTX_new failed: {}", getOpenSSLErrors());
201190

202-
try
203-
{
204-
cipher = EVP_CIPHER_fetch(nullptr, getMethod(method), nullptr);
205-
if (!cipher)
206-
throw Exception(ErrorCodes::OPENSSL_ERROR, "EVP_CIPHER_fetch failed: {}", getOpenSSLErrors());
191+
using EVP_CIPHER_ptr = std::unique_ptr<EVP_CIPHER, decltype(&EVP_CIPHER_free)>;
192+
const auto cipher = EVP_CIPHER_ptr(EVP_CIPHER_fetch(nullptr, getMethod(method), nullptr), EVP_CIPHER_free);
193+
if (!cipher)
194+
throw Exception(ErrorCodes::OPENSSL_ERROR, "EVP_CIPHER_fetch failed: {}", getOpenSSLErrors());
207195

208-
if (!EVP_DecryptInit_ex(ctx, cipher, nullptr, nullptr, nullptr))
209-
throw Exception(ErrorCodes::OPENSSL_ERROR, "EVP_DecryptInit_ex failed: {}", getOpenSSLErrors());
196+
if (!EVP_DecryptInit_ex(ctx.get(), cipher.get(), nullptr, nullptr, nullptr))
197+
throw Exception(ErrorCodes::OPENSSL_ERROR, "EVP_DecryptInit_ex failed: {}", getOpenSSLErrors());
210198

211-
if (!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_IVLEN, static_cast<int32_t>(nonce.size()), nullptr))
212-
throw Exception(ErrorCodes::OPENSSL_ERROR, "EVP_CIPHER_CTX_ctrl failed: {}", getOpenSSLErrors());
199+
if (!EVP_CIPHER_CTX_ctrl(ctx.get(), EVP_CTRL_GCM_SET_IVLEN, static_cast<int32_t>(nonce.size()), nullptr))
200+
throw Exception(ErrorCodes::OPENSSL_ERROR, "EVP_CIPHER_CTX_ctrl failed: {}", getOpenSSLErrors());
213201

214-
if (!EVP_DecryptInit_ex(ctx, nullptr, nullptr,
215-
reinterpret_cast<const uint8_t*>(key.data()),
216-
reinterpret_cast<const uint8_t *>(nonce.data())))
217-
throw Exception(ErrorCodes::OPENSSL_ERROR, "EVP_DecryptInit_ex failed: {}", getOpenSSLErrors());
202+
if (!EVP_DecryptInit_ex(ctx.get(), nullptr, nullptr,
203+
reinterpret_cast<const uint8_t*>(key.data()),
204+
reinterpret_cast<const uint8_t *>(nonce.data())))
205+
throw Exception(ErrorCodes::OPENSSL_ERROR, "EVP_DecryptInit_ex failed: {}", getOpenSSLErrors());
218206

219-
if (!EVP_CIPHER_CTX_ctrl(ctx,
220-
EVP_CTRL_GCM_SET_TAG,
221-
tag_size,
222-
reinterpret_cast<uint8_t *>(const_cast<char *>(ciphertext.data())) + ciphertext.size() - tag_size))
223-
throw Exception(ErrorCodes::OPENSSL_ERROR, "EVP_CIPHER_CTX_ctrl failed: {}", getOpenSSLErrors());
207+
if (!EVP_CIPHER_CTX_ctrl(ctx.get(),
208+
EVP_CTRL_GCM_SET_TAG,
209+
tag_size,
210+
reinterpret_cast<uint8_t *>(const_cast<char *>(ciphertext.data())) + ciphertext.size() - tag_size))
211+
throw Exception(ErrorCodes::OPENSSL_ERROR, "EVP_CIPHER_CTX_ctrl failed: {}", getOpenSSLErrors());
224212

225-
if (!EVP_DecryptUpdate(ctx,
226-
reinterpret_cast<uint8_t *>(plaintext),
227-
reinterpret_cast<int32_t *>(&out_len),
228-
reinterpret_cast<const uint8_t *>(ciphertext.data()),
229-
static_cast<int32_t>(ciphertext.size()) - tag_size))
230-
throw Exception(ErrorCodes::OPENSSL_ERROR, "EVP_DecryptUpdate failed: {}", getOpenSSLErrors());
213+
if (!EVP_DecryptUpdate(ctx.get(),
214+
reinterpret_cast<uint8_t *>(plaintext),
215+
reinterpret_cast<int32_t *>(&out_len),
216+
reinterpret_cast<const uint8_t *>(ciphertext.data()),
217+
static_cast<int32_t>(ciphertext.size()) - tag_size))
218+
throw Exception(ErrorCodes::OPENSSL_ERROR, "EVP_DecryptUpdate failed: {}", getOpenSSLErrors());
231219

232-
__msan_unpoison(plaintext, out_len); /// OpenSSL uses assembly which evades msan's analysis
220+
__msan_unpoison(plaintext, out_len); /// OpenSSL uses assembly which evades msan's analysis
233221

234-
plaintext_len = out_len;
222+
plaintext_len = out_len;
235223

236-
if (!EVP_DecryptFinal_ex(ctx,
237-
reinterpret_cast<uint8_t *>(plaintext) + out_len,
238-
reinterpret_cast<int32_t *>(&out_len)))
239-
throw Exception(ErrorCodes::OPENSSL_ERROR, "EVP_DecryptFinal_ex failed: {}", getOpenSSLErrors());
224+
if (!EVP_DecryptFinal_ex(ctx.get(),
225+
reinterpret_cast<uint8_t *>(plaintext) + out_len,
226+
reinterpret_cast<int32_t *>(&out_len)))
227+
throw Exception(ErrorCodes::OPENSSL_ERROR, "EVP_DecryptFinal_ex failed: {}", getOpenSSLErrors());
240228

241-
__msan_unpoison(plaintext, out_len); /// OpenSSL uses assembly which evades msan's analysis
242-
}
243-
catch (...)
244-
{
245-
EVP_CIPHER_free(cipher);
246-
EVP_CIPHER_CTX_free(ctx);
247-
throw;
248-
}
249-
EVP_CIPHER_free(cipher);
250-
EVP_CIPHER_CTX_free(ctx);
229+
__msan_unpoison(plaintext, out_len); /// OpenSSL uses assembly which evades msan's analysis
251230

252231
return plaintext_len + out_len;
253232
}

src/Functions/FunctionsAES.h

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -376,8 +376,7 @@ class FunctionEncrypt : public IFunction
376376
encrypted += output_len;
377377

378378
// 3: retrieve encrypted data (ciphertext)
379-
if (!EVP_EncryptFinal_ex(evp_ctx,
380-
reinterpret_cast<unsigned char*>(encrypted), &output_len))
379+
if (!EVP_EncryptFinal_ex(evp_ctx, reinterpret_cast<unsigned char*>(encrypted), &output_len))
381380
onError("EVP_EncryptFinal_ex");
382381
__msan_unpoison(encrypted, output_len); /// OpenSSL uses assembly which evades msan's analysis
383382
encrypted += output_len;
@@ -693,8 +692,7 @@ class FunctionDecrypt : public IFunction
693692
}
694693

695694
// 4: retrieve encrypted data (ciphertext)
696-
if (!decrypt_fail && !EVP_DecryptFinal_ex(evp_ctx,
697-
reinterpret_cast<unsigned char*>(decrypted), &output_len))
695+
if (!decrypt_fail && !EVP_DecryptFinal_ex(evp_ctx, reinterpret_cast<unsigned char*>(decrypted), &output_len))
698696
{
699697
if constexpr (!use_null_when_decrypt_fail)
700698
onError("EVP_DecryptFinal_ex");

src/IO/FileEncryptionCommon.cpp

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -143,8 +143,7 @@ namespace
143143
{
144144
uint8_t ciphertext[kBlockSize];
145145
int ciphertext_size = 0;
146-
if (!EVP_EncryptFinal_ex(evp_ctx,
147-
ciphertext, &ciphertext_size))
146+
if (!EVP_EncryptFinal_ex(evp_ctx, ciphertext, &ciphertext_size))
148147
throw Exception(ErrorCodes::OPENSSL_ERROR, "EVP_EncryptFinal_ex: {}", getOpenSSLErrors());
149148
__msan_unpoison(ciphertext, ciphertext_size); /// OpenSSL uses assembly which evades msans analysis
150149
if (ciphertext_size)
@@ -302,7 +301,7 @@ void Encryptor::encrypt(const char * data, size_t size, WriteBuffer & out)
302301

303302
if (!EVP_EncryptInit_ex(evp_ctx, nullptr, nullptr,
304303
reinterpret_cast<const uint8_t*>(key.c_str()), reinterpret_cast<const uint8_t*>(current_iv.c_str())))
305-
throw Exception(DB::ErrorCodes::OPENSSL_ERROR, "!EVP_EncryptInit_ex failed: {}", getOpenSSLErrors());
304+
throw Exception(DB::ErrorCodes::OPENSSL_ERROR, "EVP_EncryptInit_ex failed: {}", getOpenSSLErrors());
306305

307306
size_t in_size = 0;
308307
size_t out_size = 0;

tests/queries/0_stateless/00002_log_and_exception_messages_formatting.sql

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
-- Tags: no-parallel, no-fasttest, no-ubsan, no-batch, no-flaky-check
22
-- no-parallel because we want to run this test when most of the other tests already passed
3-
-- This is not a regular test. It is intended to run once after other tests to validate certain statistics about the whole test runs.
43

4+
-- This is not a regular test. It is intended to run once after other tests to validate certain statistics about the whole test runs.
55
-- TODO: I advise to put in inside clickhouse-test instead.
6+
67
-- If this test fails, see the "Top patterns of log messages" diagnostics in the end of run.log
78

89
system flush logs text_log;

0 commit comments

Comments
 (0)