You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@kudu.apache.org by al...@apache.org on 2023/03/18 01:20:54 UTC

[kudu] branch master updated: KUDU-3448 Plumbing for encrypting key material

This is an automated email from the ASF dual-hosted git repository.

alexey pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/kudu.git


The following commit(s) were added to refs/heads/master by this push:
     new dfdaa69b3 KUDU-3448 Plumbing for encrypting key material
dfdaa69b3 is described below

commit dfdaa69b34b1030677b7049c6b717957d32c7af4
Author: Attila Bukor <ab...@apache.org>
AuthorDate: Mon Mar 13 13:32:41 2023 +0100

    KUDU-3448 Plumbing for encrypting key material
    
    Key material for the internal PKI and token signing keys are stored in
    the syscatalog table in clear text, which is okay when volume-level
    encryption or Kudu's built-in data at rest encryption is used, but in
    some cases, this is either not used, or it's not enough (FISMA).
    
    To allow storing these key materials in encrypted form in the syscatalog
    table, this patch adds the necessary plumbing in Kudu's OpenSSL wrapper.
    It is now possible to pass a password callback function to the utility
    functions responsible for reading from and writing to OpenSSL BIO and
    strings.
    
    Change-Id: I24c5ac8ea0f9a4cab0f35ecccb1b7b00f3acefa8
    Reviewed-on: http://gerrit.cloudera.org:8080/19615
    Tested-by: Kudu Jenkins
    Reviewed-by: Alexey Serbin <al...@apache.org>
---
 src/kudu/security/crypto.cc      | 62 ++++++++++++++++++++++++++++++++++++++++
 src/kudu/security/crypto.h       |  5 ++++
 src/kudu/util/openssl_util_bio.h | 13 +++++----
 3 files changed, 75 insertions(+), 5 deletions(-)

diff --git a/src/kudu/security/crypto.cc b/src/kudu/security/crypto.cc
index 1e0f07a44..be2ebf0f0 100644
--- a/src/kudu/security/crypto.cc
+++ b/src/kudu/security/crypto.cc
@@ -75,6 +75,12 @@ struct RsaPrivateKeyTraits : public SslTypeTraits<EVP_PKEY> {
   static constexpr auto kWritePemFunc = &PemWritePrivateKey;
   static constexpr auto kWriteDerFunc = &i2d_PrivateKey_bio;
 };
+struct RsaEncryptedPrivateKeyTraits : public SslTypeTraits<EVP_PKEY> {
+  static constexpr auto kReadPemFunc = &PEM_read_bio_PrivateKey;
+  static constexpr auto kReadDerFunc = &d2i_PKCS8PrivateKey_bio;
+  static constexpr auto kWritePemFunc = &PEM_write_bio_PKCS8PrivateKey;
+  static constexpr auto kWriteDerFunc = &i2d_PKCS8PrivateKey_bio;
+};
 struct RsaPublicKeyTraits : public SslTypeTraits<EVP_PKEY> {
   static constexpr auto kReadPemFunc = &PEM_read_bio_PUBKEY;
   static constexpr auto kReadDerFunc = &d2i_PUBKEY_bio;
@@ -92,6 +98,50 @@ template<> struct SslTypeTraits<EVP_MD_CTX> {
 #endif
 };
 
+template<>
+Status FromBIO<EVP_PKEY, RsaEncryptedPrivateKeyTraits>(BIO* bio, DataFormat format,
+    c_unique_ptr<EVP_PKEY>* ret, const PasswordCallback& cb) {
+  CHECK(bio);
+  switch (format) {
+    case DataFormat::DER:
+      *ret = ssl_make_unique(RsaEncryptedPrivateKeyTraits::kReadDerFunc(
+            bio, nullptr, &TLSPasswordCB, const_cast<PasswordCallback*>(&cb)));
+      break;
+    case DataFormat::PEM:
+      *ret = ssl_make_unique(RsaEncryptedPrivateKeyTraits::kReadPemFunc(
+            bio, nullptr, &TLSPasswordCB, const_cast<PasswordCallback*>(&cb)));
+      break;
+  }
+  if (PREDICT_FALSE(!*ret)) {
+    return Status::RuntimeError("error reading private key", GetOpenSSLErrors());
+  }
+  return Status::OK();
+}
+
+template<>
+Status ToBIO<EVP_PKEY, RsaEncryptedPrivateKeyTraits>(BIO* bio, DataFormat format,
+    EVP_PKEY* obj, const PasswordCallback& cb) {
+  CHECK(bio);
+  CHECK(obj);
+  switch (format) {
+    case DataFormat::DER:
+      OPENSSL_RET_NOT_OK(RsaEncryptedPrivateKeyTraits::kWriteDerFunc(
+            bio, obj, EVP_aes_256_cbc(), nullptr, 0, &TLSPasswordCB,
+            const_cast<PasswordCallback*>(&cb)),
+          "error exporting data in DER format");
+      break;
+    case DataFormat::PEM:
+      OPENSSL_RET_NOT_OK(RsaEncryptedPrivateKeyTraits::kWritePemFunc(
+            bio, obj, EVP_aes_256_cbc(), nullptr, 0, &TLSPasswordCB,
+            const_cast<PasswordCallback*>(&cb)),
+          "error exporting data in PEM format");
+      break;
+  }
+  OPENSSL_RET_NOT_OK(BIO_flush(bio), "error flushing BIO");
+  return Status::OK();
+}
+
+
 namespace {
 
 const EVP_MD* GetMessageDigest(DigestType digest_type) {
@@ -184,11 +234,23 @@ Status PrivateKey::FromString(const std::string& data, DataFormat format) {
       data, format, &data_);
 }
 
+Status PrivateKey::FromEncryptedString(const std::string& data, DataFormat format,
+                                       const PasswordCallback& password_cb) {
+  return ::kudu::security::FromString<RawDataType, RsaEncryptedPrivateKeyTraits>(
+      data, format, &data_, password_cb);
+}
+
 Status PrivateKey::ToString(std::string* data, DataFormat format) const {
   return ::kudu::security::ToString<RawDataType, RsaPrivateKeyTraits>(
       data, format, data_.get());
 }
 
+Status PrivateKey::ToEncryptedString(std::string* data, DataFormat format,
+                                  const PasswordCallback& password_cb) const {
+  return ::kudu::security::ToString<RawDataType, RsaEncryptedPrivateKeyTraits>(
+        data, format, data_.get(), password_cb);
+}
+
 Status PrivateKey::FromFile(const std::string& fpath, DataFormat format,
                             const PasswordCallback& password_cb) {
   return ::kudu::security::FromFile<RawDataType, RsaPrivateKeyTraits>(
diff --git a/src/kudu/security/crypto.h b/src/kudu/security/crypto.h
index db5d24f83..51fdc2ec6 100644
--- a/src/kudu/security/crypto.h
+++ b/src/kudu/security/crypto.h
@@ -75,6 +75,11 @@ class PrivateKey : public RawDataWrapper<EVP_PKEY> {
   Status FromString(const std::string& data, DataFormat format) WARN_UNUSED_RESULT;
   Status ToString(std::string* data, DataFormat format) const WARN_UNUSED_RESULT;
 
+  Status FromEncryptedString(const std::string& data, DataFormat format,
+                             const PasswordCallback& password_cb) WARN_UNUSED_RESULT;
+  Status ToEncryptedString(std::string* data, DataFormat format,
+                           const PasswordCallback& password_cb) const WARN_UNUSED_RESULT;
+
   // If 'cb' is set, it will be called to obtain the password necessary to decrypt
   // the private key file in 'fpath'.
   Status FromFile(const std::string& fpath, DataFormat format,
diff --git a/src/kudu/util/openssl_util_bio.h b/src/kudu/util/openssl_util_bio.h
index 4eff7682e..92861ac82 100644
--- a/src/kudu/util/openssl_util_bio.h
+++ b/src/kudu/util/openssl_util_bio.h
@@ -33,7 +33,8 @@ namespace security {
 
 
 template<typename TYPE, typename Traits = SslTypeTraits<TYPE>>
-Status ToBIO(BIO* bio, DataFormat format, TYPE* obj) {
+Status ToBIO(BIO* bio, DataFormat format, TYPE* obj,
+    const PasswordCallback& /*cb*/ = PasswordCallback()) {
   CHECK(bio);
   CHECK(obj);
   switch (format) {
@@ -85,7 +86,8 @@ Status FromBIO(BIO* bio, DataFormat format, c_unique_ptr<TYPE>* ret,
 
 template<typename Type, typename Traits = SslTypeTraits<Type>>
 Status FromString(const std::string& data, DataFormat format,
-                  c_unique_ptr<Type>* ret) {
+                  c_unique_ptr<Type>* ret,
+                  const PasswordCallback& cb = PasswordCallback()) {
   const void* mdata = reinterpret_cast<const void*>(data.data());
   auto bio = ssl_make_unique(BIO_new_mem_buf(
 #if OPENSSL_VERSION_NUMBER < 0x10002000L
@@ -94,16 +96,17 @@ Status FromString(const std::string& data, DataFormat format,
       mdata,
 #endif
       data.size()));
-  RETURN_NOT_OK_PREPEND((FromBIO<Type, Traits>(bio.get(), format, ret)),
+  RETURN_NOT_OK_PREPEND((FromBIO<Type, Traits>(bio.get(), format, ret, cb)),
                         "unable to load data from memory");
   return Status::OK();
 }
 
 template<typename Type, typename Traits = SslTypeTraits<Type>>
-Status ToString(std::string* data, DataFormat format, Type* obj) {
+Status ToString(std::string* data, DataFormat format, Type* obj,
+                const PasswordCallback& cb = PasswordCallback()) {
   CHECK(data);
   auto bio = ssl_make_unique(BIO_new(BIO_s_mem()));
-  RETURN_NOT_OK_PREPEND((ToBIO<Type, Traits>(bio.get(), format, obj)),
+  RETURN_NOT_OK_PREPEND((ToBIO<Type, Traits>(bio.get(), format, obj, cb)),
                         "error serializing data");
   BUF_MEM* membuf;
   OPENSSL_CHECK_OK(BIO_get_mem_ptr(bio.get(), &membuf));