This is an automated email from the ASF dual-hosted git repository.
xyz pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/pulsar-client-cpp.git
The following commit(s) were added to refs/heads/main by this push:
new 4366ffe Update OpenSSL API (#509)
4366ffe is described below
commit 4366ffe7c96380da0357d5e7e148e4886d6700e0
Author: Liu Zixian <[email protected]>
AuthorDate: Tue Oct 14 16:13:46 2025 +0800
Update OpenSSL API (#509)
---
lib/MessageCrypto.cc | 110 +++++++++++++++++++++++++++++++++----------
lib/MessageCrypto.h | 10 ++--
lib/auth/athenz/ZTSClient.cc | 34 ++++++++++---
lib/auth/athenz/ZTSClient.h | 3 ++
4 files changed, 123 insertions(+), 34 deletions(-)
diff --git a/lib/MessageCrypto.cc b/lib/MessageCrypto.cc
index dc636c0..b06ff65 100644
--- a/lib/MessageCrypto.cc
+++ b/lib/MessageCrypto.cc
@@ -35,9 +35,6 @@ MessageCrypto::MessageCrypto(const std::string& logCtx, bool
keyGenNeeded)
ivLen_(12),
iv_(new unsigned char[ivLen_]),
logCtx_(logCtx) {
- SSL_library_init();
- SSL_load_error_strings();
-
if (!keyGenNeeded) {
mdCtx_ = EVP_MD_CTX_create();
EVP_MD_CTX_init(mdCtx_);
@@ -50,9 +47,9 @@ MessageCrypto::MessageCrypto(const std::string& logCtx, bool
keyGenNeeded)
MessageCrypto::~MessageCrypto() {}
-RSA* MessageCrypto::loadPublicKey(std::string& pubKeyStr) {
+EVP_PKEY* MessageCrypto::loadPublicKey(std::string& pubKeyStr) {
BIO* pubBio = NULL;
- RSA* rsaPub = NULL;
+ EVP_PKEY* rsaPub = NULL;
pubBio = BIO_new_mem_buf((char*)pubKeyStr.c_str(), -1);
if (pubBio == NULL) {
@@ -60,7 +57,7 @@ RSA* MessageCrypto::loadPublicKey(std::string& pubKeyStr) {
return rsaPub;
}
- rsaPub = PEM_read_bio_RSA_PUBKEY(pubBio, NULL, NULL, NULL);
+ rsaPub = PEM_read_bio_PUBKEY(pubBio, NULL, NULL, NULL);
if (rsaPub == NULL) {
LOG_ERROR(logCtx_ << " Failed to load public key");
}
@@ -69,9 +66,9 @@ RSA* MessageCrypto::loadPublicKey(std::string& pubKeyStr) {
return rsaPub;
}
-RSA* MessageCrypto::loadPrivateKey(std::string& privateKeyStr) {
+EVP_PKEY* MessageCrypto::loadPrivateKey(std::string& privateKeyStr) {
BIO* privBio = NULL;
- RSA* rsaPriv = NULL;
+ EVP_PKEY* rsaPriv = NULL;
privBio = BIO_new_mem_buf((char*)privateKeyStr.c_str(), -1);
if (privBio == NULL) {
@@ -79,7 +76,7 @@ RSA* MessageCrypto::loadPrivateKey(std::string&
privateKeyStr) {
return rsaPriv;
}
- rsaPriv = PEM_read_bio_RSAPrivateKey(privBio, NULL, NULL, NULL);
+ rsaPriv = PEM_read_bio_PrivateKey(privBio, NULL, NULL, NULL);
if (rsaPriv == NULL) {
LOG_ERROR(logCtx_ << " Failed to load private key");
}
@@ -88,6 +85,59 @@ RSA* MessageCrypto::loadPrivateKey(std::string&
privateKeyStr) {
return rsaPriv;
}
+bool MessageCrypto::rsaDecrypt(EVP_PKEY_CTX* ctx, const std::string& in,
+ boost::scoped_array<unsigned char>& out,
size_t& outLen) {
+ if (EVP_PKEY_decrypt_init(ctx) <= 0) {
+ LOG_ERROR(logCtx_ << "Failed to initialize decryption");
+ return false;
+ }
+ if (EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_OAEP_PADDING) <= 0) {
+ LOG_ERROR(logCtx_ << "Failed to set RSA padding");
+ return false;
+ }
+ auto inStr_ = reinterpret_cast<unsigned const char*>(in.c_str());
+ size_t rsaSize;
+ if (EVP_PKEY_decrypt(ctx, NULL, &rsaSize, inStr_, in.size()) <= 0) {
+ LOG_ERROR(logCtx_ << "Failed to determine decrypt buffer size");
+ return false;
+ }
+ if (rsaSize != outLen) {
+ outLen = rsaSize;
+ out.reset(new unsigned char[outLen]);
+ }
+ if (EVP_PKEY_decrypt(ctx, out.get(), &outLen, inStr_, in.size()) <= 0) {
+ LOG_ERROR(logCtx_ << "Failed to decrypt.");
+ return false;
+ }
+ return true;
+}
+
+bool MessageCrypto::rsaEncrypt(EVP_PKEY_CTX* ctx, boost::scoped_array<unsigned
char>& in, size_t inLen,
+ boost::scoped_array<unsigned char>& out,
size_t& outLen) {
+ if (EVP_PKEY_encrypt_init(ctx) <= 0) {
+ LOG_ERROR(logCtx_ << "Failed to initialize encryption");
+ return false;
+ }
+ if (EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_OAEP_PADDING) <= 0) {
+ LOG_ERROR(logCtx_ << "Failed to set RSA padding");
+ return false;
+ }
+ size_t rsaSize;
+ if (EVP_PKEY_encrypt(ctx, NULL, &rsaSize, in.get(), inLen) <= 0) {
+ LOG_ERROR(logCtx_ << "Failed to determine encrypt buffer size");
+ return false;
+ }
+ if (rsaSize != outLen) {
+ outLen = rsaSize;
+ out.reset(new unsigned char[rsaSize]);
+ }
+ if (EVP_PKEY_encrypt(ctx, out.get(), &outLen, in.get(), inLen) <= 0) {
+ LOG_ERROR(logCtx_ << "Failed to encrypt.");
+ return false;
+ }
+ return true;
+}
+
bool MessageCrypto::getDigest(const std::string& keyName, const void* input,
unsigned int inputLen,
unsigned char keyDigest[], unsigned int&
digestLen) {
if (EVP_DigestInit_ex(mdCtx_, EVP_md5(), NULL) != 1) {
@@ -181,24 +231,29 @@ Result MessageCrypto::addPublicKeyCipher(const
std::string& keyName, const Crypt
return result;
}
- RSA* pubKey = loadPublicKey(keyInfo.getKey());
+ auto* pubKey = loadPublicKey(keyInfo.getKey());
if (pubKey == NULL) {
LOG_ERROR(logCtx_ << "Failed to load public key " << keyName);
return ResultCryptoError;
}
LOG_DEBUG(logCtx_ << " Public key " << keyName << " loaded successfully.");
- int inSize = RSA_size(pubKey);
- boost::scoped_array<unsigned char> encryptedKey(new unsigned char[inSize]);
-
- int outSize =
- RSA_public_encrypt(dataKeyLen_, dataKey_.get(), encryptedKey.get(),
pubKey, RSA_PKCS1_OAEP_PADDING);
-
- if (inSize != outSize) {
- LOG_ERROR(logCtx_ << "Ciphertext is length not matching input key
length for key " << keyName);
+ boost::scoped_array<unsigned char> encryptedKey{nullptr};
+ size_t encryptedKeyLen{0};
+ auto* ctx = EVP_PKEY_CTX_new(pubKey, NULL);
+ if (!ctx) {
+ LOG_ERROR(logCtx_ << "Failed to create EVP_PKEY_CTX for " << keyName);
+ EVP_PKEY_free(pubKey);
+ return ResultCryptoError;
+ }
+ bool encrypted = rsaEncrypt(ctx, dataKey_, dataKeyLen_, encryptedKey,
encryptedKeyLen);
+ EVP_PKEY_CTX_free(ctx);
+ EVP_PKEY_free(pubKey);
+ if (!encrypted) {
+ LOG_ERROR(logCtx_ << "Failed to encrypt with " << keyName);
return ResultCryptoError;
}
- std::string encryptedKeyStr(reinterpret_cast<char*>(encryptedKey.get()),
inSize);
+ std::string encryptedKeyStr(reinterpret_cast<char*>(encryptedKey.get()),
encryptedKeyLen);
std::shared_ptr<EncryptionKeyInfo> eki(new EncryptionKeyInfo());
eki->setKey(encryptedKeyStr);
eki->setMetadata(keyInfo.getMetadata());
@@ -353,7 +408,7 @@ bool MessageCrypto::decryptDataKey(const
proto::EncryptionKeys& encKeys, const C
keyReader.getPrivateKey(keyName, keyMeta, keyInfo);
// Convert key from string to RSA key
- RSA* privKey = loadPrivateKey(keyInfo.getKey());
+ auto* privKey = loadPrivateKey(keyInfo.getKey());
if (privKey == NULL) {
LOG_ERROR(logCtx_ << " Failed to load private key " << keyName);
return false;
@@ -361,11 +416,16 @@ bool MessageCrypto::decryptDataKey(const
proto::EncryptionKeys& encKeys, const C
LOG_DEBUG(logCtx_ << " Private key " << keyName << " loaded
successfully.");
// Decrypt data key
- int outSize = RSA_private_decrypt(encryptedDataKey.size(),
- reinterpret_cast<unsigned const
char*>(encryptedDataKey.c_str()),
- dataKey_.get(), privKey,
RSA_PKCS1_OAEP_PADDING);
-
- if (outSize == -1) {
+ auto* ctx = EVP_PKEY_CTX_new(privKey, NULL);
+ if (!ctx) {
+ LOG_ERROR(logCtx_ << "Failed to create EVP_PKEY_CTX for " << keyName);
+ EVP_PKEY_free(privKey);
+ return false;
+ }
+ bool decrypted = rsaDecrypt(ctx, encryptedDataKey, dataKey_, dataKeyLen_);
+ EVP_PKEY_CTX_free(ctx);
+ EVP_PKEY_free(privKey);
+ if (!decrypted) {
LOG_ERROR(logCtx_ << "Failed to decrypt AES key for " << keyName);
return false;
}
diff --git a/lib/MessageCrypto.h b/lib/MessageCrypto.h
index 3e955d9..cd07bf5 100644
--- a/lib/MessageCrypto.h
+++ b/lib/MessageCrypto.h
@@ -104,7 +104,7 @@ class MessageCrypto {
typedef std::unique_lock<std::mutex> Lock;
std::mutex mutex_;
- int dataKeyLen_;
+ size_t dataKeyLen_;
boost::scoped_array<unsigned char> dataKey_;
int tagLen_;
@@ -125,8 +125,12 @@ class MessageCrypto {
EVP_MD_CTX* mdCtx_;
- RSA* loadPublicKey(std::string& pubKeyStr);
- RSA* loadPrivateKey(std::string& privateKeyStr);
+ EVP_PKEY* loadPublicKey(std::string& pubKeyStr);
+ EVP_PKEY* loadPrivateKey(std::string& privateKeyStr);
+ bool rsaDecrypt(EVP_PKEY_CTX* ctx, const std::string& in,
boost::scoped_array<unsigned char>& out,
+ size_t& outLen);
+ bool rsaEncrypt(EVP_PKEY_CTX* ctx, boost::scoped_array<unsigned char>& in,
size_t inLen,
+ boost::scoped_array<unsigned char>& out, size_t& outLen);
bool getDigest(const std::string& keyName, const void* input, unsigned int
inputLen,
unsigned char keyDigest[], unsigned int& digestLen);
void removeExpiredDataKey();
diff --git a/lib/auth/athenz/ZTSClient.cc b/lib/auth/athenz/ZTSClient.cc
index 35387d9..7d511f4 100644
--- a/lib/auth/athenz/ZTSClient.cc
+++ b/lib/auth/athenz/ZTSClient.cc
@@ -226,9 +226,9 @@ const std::string ZTSClient::getPrincipalToken() const {
const char *unsignedToken = unsignedTokenString.c_str();
unsigned char signature[BUFSIZ] = {};
unsigned char hash[SHA256_DIGEST_LENGTH] = {};
- unsigned int siglen;
+ size_t siglen;
FILE *fp;
- RSA *privateKey;
+ EVP_PKEY *privateKey;
if (privateKeyUri_.scheme == "data") {
if (privateKeyUri_.mediaTypeAndEncodingType !=
"application/x-pem-file;base64") {
@@ -249,7 +249,7 @@ const std::string ZTSClient::getPrincipalToken() const {
free(decodeStr);
return "";
}
- privateKey = PEM_read_bio_RSAPrivateKey(bio, NULL, NULL, NULL);
+ privateKey = PEM_read_bio_PrivateKey(bio, NULL, NULL, NULL);
BIO_free(bio);
free(decodeStr);
if (privateKey == NULL) {
@@ -263,7 +263,7 @@ const std::string ZTSClient::getPrincipalToken() const {
return "";
}
- privateKey = PEM_read_RSAPrivateKey(fp, NULL, NULL, NULL);
+ privateKey = PEM_read_PrivateKey(fp, NULL, NULL, NULL);
fclose(fp);
if (privateKey == NULL) {
LOG_ERROR("Failed to read private key: " << privateKeyUri_.path);
@@ -275,16 +275,38 @@ const std::string ZTSClient::getPrincipalToken() const {
}
SHA256((unsigned char *)unsignedToken, unsignedTokenString.length(), hash);
- RSA_sign(NID_sha256, hash, SHA256_DIGEST_LENGTH, signature, &siglen,
privateKey);
+ auto *ctx = EVP_MD_CTX_new();
+ if (ctx == NULL) {
+ LOG_ERROR("Failed to create EVP_MD_CTX.");
+ return "";
+ }
+
+ bool sign = rsaSign(ctx, privateKey, signature, &siglen, hash);
+ EVP_MD_CTX_free(ctx);
+ if (!sign) {
+ LOG_ERROR("Failed to sign with " << privateKeyUri_.path);
+ return "";
+ }
std::string principalToken = unsignedTokenString + ";s=" +
ybase64Encode(signature, siglen);
LOG_DEBUG("Created signed principal token: " << principalToken);
- RSA_free(privateKey);
+ EVP_PKEY_free(privateKey);
return principalToken;
}
+bool ZTSClient::rsaSign(EVP_MD_CTX *ctx, EVP_PKEY *privateKey, unsigned char
*signature, size_t *siglen,
+ unsigned char *hash) const {
+ if (EVP_DigestSignInit(ctx, NULL, EVP_sha256(), NULL, privateKey) != 1) {
+ return false;
+ }
+ if (EVP_DigestSign(ctx, signature, siglen, hash, SHA256_DIGEST_LENGTH) !=
1) {
+ return false;
+ }
+ return true;
+}
+
std::mutex cacheMtx_;
const std::string ZTSClient::getRoleToken() {
RoleToken roleToken;
diff --git a/lib/auth/athenz/ZTSClient.h b/lib/auth/athenz/ZTSClient.h
index 6fcbd69..fa41577 100644
--- a/lib/auth/athenz/ZTSClient.h
+++ b/lib/auth/athenz/ZTSClient.h
@@ -16,6 +16,7 @@
* specific language governing permissions and limitations
* under the License.
*/
+#include <openssl/evp.h>
#include <pulsar/defines.h>
#include <map>
@@ -63,6 +64,8 @@ class PULSAR_PUBLIC ZTSClient {
static UriSt parseUri(const char* uri);
static bool checkRequiredParams(std::map<std::string, std::string>& params,
const std::vector<std::string>&
requiredParams);
+ bool rsaSign(EVP_MD_CTX* ctx, EVP_PKEY* privateKey, unsigned char*
signature, size_t* siglen,
+ unsigned char* hash) const;
friend class ZTSClientWrapper;
};