You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@kudu.apache.org by to...@apache.org on 2017/01/25 01:10:42 UTC

[1/2] kudu git commit: Use C++11 constructor deletion for DISALLOW_COPY_AND_ASSIGN

Repository: kudu
Updated Branches:
  refs/heads/master ff38c6b5a -> e367b4e0b


Use C++11 constructor deletion for DISALLOW_COPY_AND_ASSIGN

Change-Id: Ida3f92ee9651d4540c886a5e7846bff0eedbb226
Reviewed-on: http://gerrit.cloudera.org:8080/5781
Reviewed-by: Dan Burkert <da...@apache.org>
Tested-by: Kudu Jenkins


Project: http://git-wip-us.apache.org/repos/asf/kudu/repo
Commit: http://git-wip-us.apache.org/repos/asf/kudu/commit/6719da04
Tree: http://git-wip-us.apache.org/repos/asf/kudu/tree/6719da04
Diff: http://git-wip-us.apache.org/repos/asf/kudu/diff/6719da04

Branch: refs/heads/master
Commit: 6719da0449e22dfc1055ded08f276b351003a3f3
Parents: ff38c6b
Author: Todd Lipcon <to...@apache.org>
Authored: Tue Jan 24 11:33:06 2017 -0800
Committer: Todd Lipcon <to...@apache.org>
Committed: Tue Jan 24 21:46:01 2017 +0000

----------------------------------------------------------------------
 src/kudu/gutil/macros.h | 13 +------------
 1 file changed, 1 insertion(+), 12 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/kudu/blob/6719da04/src/kudu/gutil/macros.h
----------------------------------------------------------------------
diff --git a/src/kudu/gutil/macros.h b/src/kudu/gutil/macros.h
index 7ebb4b4..f271bd4 100644
--- a/src/kudu/gutil/macros.h
+++ b/src/kudu/gutil/macros.h
@@ -93,21 +93,10 @@ struct CompileAssert {
 // Note, that most uses of DISALLOW_ASSIGN and DISALLOW_COPY are broken
 // semantically, one should either use disallow both or neither. Try to
 // avoid these in new code.
-//
-// The LANG_CXX11 branch is a workaround for
-// http://gcc.gnu.org/PR51213 in gcc-4.7 / Crosstool v16.
-// TODO(user): Remove "&& !defined(__clang_)" when =delete is
-// gcc-4.7 before =delete is allowed, go back to the C++98 definition.
 #ifndef DISALLOW_COPY_AND_ASSIGN
-#if LANG_CXX11 && !defined(__clang__)
 #define DISALLOW_COPY_AND_ASSIGN(TypeName) \
   TypeName(const TypeName&) = delete;      \
   void operator=(const TypeName&) = delete
-#else
-#define DISALLOW_COPY_AND_ASSIGN(TypeName) \
-  TypeName(const TypeName&);               \
-  void operator=(const TypeName&)
-#endif
 #endif
 
 // An older, politically incorrect name for the above.
@@ -121,7 +110,7 @@ struct CompileAssert {
 // that wants to prevent anyone from instantiating it. This is
 // especially useful for classes containing only static methods.
 #define DISALLOW_IMPLICIT_CONSTRUCTORS(TypeName) \
-  TypeName();                                    \
+  TypeName() = delete;                           \
   DISALLOW_COPY_AND_ASSIGN(TypeName)
 
 // The arraysize(arr) macro returns the # of elements in an array arr.


[2/2] kudu git commit: [security] separated OpenSSL wrappers from CA

Posted by to...@apache.org.
[security] separated OpenSSL wrappers from CA

Moved common wrappers around OpenSSL objects from cert_management.h
into a openssl_util.h header.  The motivation for this change is to
allow other components to use those generic wrappers without dependency
on CA-specific code.

Change-Id: I37729a865739c5702e92238b9d2375f5bf71543d
Reviewed-on: http://gerrit.cloudera.org:8080/5779
Reviewed-by: Dan Burkert <da...@apache.org>
Tested-by: Kudu Jenkins


Project: http://git-wip-us.apache.org/repos/asf/kudu/repo
Commit: http://git-wip-us.apache.org/repos/asf/kudu/commit/e367b4e0
Tree: http://git-wip-us.apache.org/repos/asf/kudu/tree/e367b4e0
Diff: http://git-wip-us.apache.org/repos/asf/kudu/diff/e367b4e0

Branch: refs/heads/master
Commit: e367b4e0b6e1cae60ffb8cbf2a661589b92fa9c5
Parents: 6719da0
Author: Alexey Serbin <as...@cloudera.com>
Authored: Mon Jan 23 23:19:03 2017 -0800
Committer: Alexey Serbin <as...@cloudera.com>
Committed: Tue Jan 24 23:29:09 2017 +0000

----------------------------------------------------------------------
 src/kudu/security/ca/cert_management.cc | 234 ++-------------------------
 src/kudu/security/ca/cert_management.h  |  90 -----------
 src/kudu/security/openssl_util.cc       | 209 +++++++++++++++++++++++-
 src/kudu/security/openssl_util.h        | 123 ++++++++++++++
 4 files changed, 347 insertions(+), 309 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/kudu/blob/e367b4e0/src/kudu/security/ca/cert_management.cc
----------------------------------------------------------------------
diff --git a/src/kudu/security/ca/cert_management.cc b/src/kudu/security/ca/cert_management.cc
index f699a9e..99168aa 100644
--- a/src/kudu/security/ca/cert_management.cc
+++ b/src/kudu/security/ca/cert_management.cc
@@ -47,231 +47,29 @@ using std::shared_ptr;
 using std::string;
 using strings::Substitute;
 
-#define CERT_CHECK_OK(call) \
-  CHECK_GT((call), 0)
-
-#define CERT_RET_NOT_OK(call, msg) \
-  if ((call) <= 0) { \
-    return Status::RuntimeError(Substitute("$0: $1", \
-        (msg), GetOpenSSLErrors())); \
-  }
-
-#define CERT_RET_IF_NULL(call, msg) \
-  if ((call) == nullptr) { \
-    return Status::RuntimeError(Substitute("$0: $1", \
-        (msg), GetOpenSSLErrors())); \
-  }
-
 namespace kudu {
 namespace security {
-namespace ca {
 
-
-namespace {
-
-// Writing the private key from an EVP_PKEY has a different
-// signature than the rest of the write functions, so we
-// have to provide this wrapper.
-int PemWritePrivateKey(BIO* bio, EVP_PKEY* key);
-
-// For each SSL type, the Traits class provides the important OpenSSL
-// API functions.
-template<class SSL_TYPE>
-struct SslTypeTraits {};
-
-template<> struct SslTypeTraits<X509> {
-  static constexpr auto free = &X509_free;
-  static constexpr auto read_pem = &PEM_read_bio_X509;
-  static constexpr auto read_der = &d2i_X509_bio;
-  static constexpr auto write_pem = &PEM_write_bio_X509;
-  static constexpr auto write_der = &i2d_X509_bio;
-};
-template<> struct SslTypeTraits<X509_REQ> {
-  static constexpr auto free = &X509_REQ_free;
-  static constexpr auto read_pem = &PEM_read_bio_X509_REQ;
-  static constexpr auto read_der = &d2i_X509_REQ_bio;
-  static constexpr auto write_pem = &PEM_write_bio_X509_REQ;
-  static constexpr auto write_der = &i2d_X509_REQ_bio;
-};
-template<> struct SslTypeTraits<EVP_PKEY> {
-  static constexpr auto free = &EVP_PKEY_free;
-  static constexpr auto read_pem = &PEM_read_bio_PrivateKey;
-  static constexpr auto read_der = &d2i_PrivateKey_bio;
-  static constexpr auto write_pem = &PemWritePrivateKey;
-  static constexpr auto write_der = &i2d_PrivateKey_bio;
-};
 template<> struct SslTypeTraits<ASN1_INTEGER> {
   static constexpr auto free = &ASN1_INTEGER_free;
 };
-template<> struct SslTypeTraits<BIO> {
-  static constexpr auto free = &BIO_free;
-};
 template<> struct SslTypeTraits<BIGNUM> {
   static constexpr auto free = &BN_free;
 };
-template<> struct SslTypeTraits<RSA> {
-  static constexpr auto free = &RSA_free;
+template<> struct SslTypeTraits<X509> {
+  static constexpr auto free = &X509_free;
+};
+template<> struct SslTypeTraits<X509_REQ> {
+  static constexpr auto free = &X509_REQ_free;
 };
 template<> struct SslTypeTraits<X509_EXTENSION> {
   static constexpr auto free = &X509_EXTENSION_free;
 };
+template<> struct SslTypeTraits<EVP_PKEY> {
+  static constexpr auto free = &EVP_PKEY_free;
+};
 
-template<class SSL_TYPE>
-static c_unique_ptr<SSL_TYPE> make_ssl_unique(SSL_TYPE* d) {
-  return {d, SslTypeTraits<SSL_TYPE>::free};
-}
-
-int PemWritePrivateKey(BIO* bio, EVP_PKEY* key) {
-  auto rsa = make_ssl_unique(EVP_PKEY_get1_RSA(key));
-  return PEM_write_bio_RSAPrivateKey(
-      bio, rsa.get(), nullptr, nullptr, 0, nullptr, nullptr);
-}
-
-template<class TYPE>
-Status ToBIO(BIO* bio, DataFormat format, TYPE* obj) {
-  using Traits = SslTypeTraits<TYPE>;
-  CHECK(bio);
-  CHECK(obj);
-  switch (format) {
-    case DataFormat::DER:
-      CERT_RET_NOT_OK(Traits::write_der(bio, obj), "error exporting DER format");
-      break;
-    case DataFormat::PEM:
-      CERT_RET_NOT_OK(Traits::write_pem(bio, obj), "error exporting PEM format");
-      break;
-  }
-  CERT_RET_NOT_OK(BIO_flush(bio), "error flushing BIO");
-  return Status::OK();
-}
-
-template<class TYPE>
-Status FromBIO(BIO* bio, DataFormat format, c_unique_ptr<TYPE>* ret) {
-  using Traits = SslTypeTraits<TYPE>;
-  CHECK(bio);
-  switch (format) {
-    case DataFormat::DER:
-      *ret = make_ssl_unique(Traits::read_der(bio, nullptr));
-      break;
-    case DataFormat::PEM:
-      *ret = make_ssl_unique(Traits::read_pem(bio, nullptr, nullptr, nullptr));
-      break;
-  }
-  if (PREDICT_FALSE(!*ret)) {
-    return Status::RuntimeError(GetOpenSSLErrors());
-  }
-  return Status::OK();
-}
-} // anonymous namespace
-
-
-const string& DataFormatToString(DataFormat fmt) {
-  static const string kStrFormatUnknown = "UNKNOWN";
-  static const string kStrFormatDer = "DER";
-  static const string kStrFormatPem = "PEM";
-  switch (fmt) {
-    case DataFormat::DER:
-      return kStrFormatDer;
-    case DataFormat::PEM:
-      return kStrFormatPem;
-    default:
-      return kStrFormatUnknown;
-  }
-}
-
-Status BasicWrapper::FromFile(const string& fpath, DataFormat format) {
-  auto bio = make_ssl_unique(BIO_new(BIO_s_file()));
-  CERT_RET_NOT_OK(BIO_read_filename(bio.get(), fpath.c_str()),
-                  Substitute("$0: could not read from file", fpath));
-  RETURN_NOT_OK_PREPEND(FromBIO(bio.get(), format),
-                        Substitute("$0: unable to load data key from file",
-                                   fpath));
-  return Status::OK();
-}
-
-Status BasicWrapper::FromString(const string& data, DataFormat format) {
-  const void* mdata = reinterpret_cast<const void*>(data.data());
-  auto bio = make_ssl_unique(BIO_new_mem_buf(
-#if OPENSSL_VERSION_NUMBER < 0x10002000L
-      const_cast<void*>(mdata),
-#else
-      mdata,
-#endif
-      data.size()));
-  RETURN_NOT_OK_PREPEND(FromBIO(bio.get(), format),
-                        "unable to load data from memory");
-  return Status::OK();
-}
-
-Status BasicWrapper::ToString(std::string* data, DataFormat format) const {
-  CHECK(data);
-  auto bio = make_ssl_unique(BIO_new(BIO_s_mem()));
-  RETURN_NOT_OK_PREPEND(ToBIO(bio.get(), format), "error serializing data");
-  BUF_MEM* membuf;
-  CERT_CHECK_OK(BIO_get_mem_ptr(bio.get(), &membuf));
-  data->assign(membuf->data, membuf->length);
-  return Status::OK();
-}
-
-void Key::AdoptRawData(RawDataType* data) {
-  data_ = make_ssl_unique(data);
-}
-
-Status Key::FromBIO(BIO* bio, DataFormat format) {
-  RETURN_NOT_OK_PREPEND(ca::FromBIO(bio, format, &data_),
-                        "unable to read private key");
-  return Status::OK();
-}
-
-Status Key::ToBIO(BIO* bio, DataFormat format) const {
-  RETURN_NOT_OK_PREPEND(ca::ToBIO(bio, format, data_.get()), "could not export cert");
-  return Status::OK();
-}
-
-void Cert::AdoptRawData(RawDataType* data) {
-  data_ = make_ssl_unique(data);
-}
-
-Status Cert::FromBIO(BIO* bio, DataFormat format) {
-  RETURN_NOT_OK_PREPEND(ca::FromBIO(bio, format, &data_), "could not read cert");
-  return Status::OK();
-}
-
-Status Cert::ToBIO(BIO* bio, DataFormat format) const {
-  RETURN_NOT_OK_PREPEND(ca::ToBIO(bio, format, data_.get()), "could not export cert");
-  return Status::OK();
-}
-
-void CertSignRequest::AdoptRawData(RawDataType* data) {
-  data_ = make_ssl_unique(data);
-}
-
-Status CertSignRequest::FromBIO(BIO* bio, DataFormat format) {
-  RETURN_NOT_OK_PREPEND(ca::FromBIO(bio, format, &data_), "could not read X509 CSR");
-  return Status::OK();
-}
-
-Status CertSignRequest::ToBIO(BIO* bio, DataFormat format) const {
-  RETURN_NOT_OK_PREPEND(ca::ToBIO(bio, format, data_.get()), "could not export X509 CSR");
-  return Status::OK();
-}
-
-Status GeneratePrivateKey(int num_bits, Key* ret) {
-  CHECK(ret);
-  InitializeOpenSSL();
-  auto key = make_ssl_unique(EVP_PKEY_new());
-  {
-    auto bn = make_ssl_unique(BN_new());
-    CERT_CHECK_OK(BN_set_word(bn.get(), RSA_F4));
-    auto rsa = make_ssl_unique(RSA_new());
-    CERT_RET_NOT_OK(RSA_generate_key_ex(rsa.get(), num_bits, bn.get(), nullptr),
-                    "error generating RSA key");
-    CERT_RET_NOT_OK(EVP_PKEY_set1_RSA(key.get(), rsa.get()),
-                    "error assigning RSA key");
-  }
-  ret->AdoptRawData(key.release());
-
-  return Status::OK();
-}
+namespace ca {
 
 CertRequestGeneratorBase::CertRequestGeneratorBase(Config config)
     : config_(move(config)) {
@@ -285,7 +83,7 @@ Status CertRequestGeneratorBase::GenerateRequest(const Key& key,
                                                  CertSignRequest* ret) const {
   CHECK(ret);
   CHECK(Initialized());
-  auto req = make_ssl_unique(X509_REQ_new());
+  auto req = ssl_make_unique(X509_REQ_new());
   CERT_RET_NOT_OK(X509_REQ_set_pubkey(req.get(), key.GetRawData()),
                   "error setting X509 public key");
   X509_NAME* name = X509_REQ_get_subject_name(req.get());
@@ -322,7 +120,7 @@ Status CertRequestGeneratorBase::GenerateRequest(const Key& key,
 
 Status CertRequestGeneratorBase::PushExtension(stack_st_X509_EXTENSION* st,
                                                int32_t nid, const char* value) {
-  auto ex = make_ssl_unique(
+  auto ex = ssl_make_unique(
       X509V3_EXT_conf_nid(nullptr, nullptr, nid, const_cast<char*>(value)));
   if (!ex) {
     return Status::RuntimeError("error configuring extension");
@@ -554,7 +352,7 @@ const Key& CertSigner::ca_private_key() const {
 Status CertSigner::Sign(const CertSignRequest& req, Cert* ret) const {
   CHECK(ret);
   CHECK(Initialized());
-  auto x509 = make_ssl_unique(X509_new());
+  auto x509 = ssl_make_unique(X509_new());
   RETURN_NOT_OK(FillCertTemplateFromRequest(req.GetRawData(), x509.get()));
   RETURN_NOT_OK(DoSign(EVP_sha256(), exp_interval_sec_, x509.get()));
   ret->AdoptRawData(x509.release());
@@ -578,7 +376,7 @@ Status CertSigner::CopyExtensions(X509_REQ* req, X509* x) {
     if (idx != -1) {
       // If extension exits, delete all extensions of same type.
       do {
-        auto tmpext = make_ssl_unique(X509_get_ext(x, idx));
+        auto tmpext = ssl_make_unique(X509_get_ext(x, idx));
         X509_delete_ext(x, idx);
         idx = X509_get_ext_by_OBJ(x, obj, -1);
       } while (idx != -1);
@@ -597,7 +395,7 @@ Status CertSigner::FillCertTemplateFromRequest(X509_REQ* req, X509* tmpl) {
       !req->req_info->pubkey->public_key->data) {
     return Status::RuntimeError("corrupted CSR: no public key");
   }
-  auto pub_key = make_ssl_unique(X509_REQ_get_pubkey(req));
+  auto pub_key = ssl_make_unique(X509_REQ_get_pubkey(req));
   if (!pub_key) {
     return Status::RuntimeError("error unpacking public key from CSR");
   }
@@ -622,10 +420,10 @@ Status CertSigner::DigestSign(const EVP_MD* md, EVP_PKEY* pkey, X509* x) {
 }
 
 Status CertSigner::GenerateSerial(c_unique_ptr<ASN1_INTEGER>* ret) {
-  auto btmp = make_ssl_unique(BN_new());
+  auto btmp = ssl_make_unique(BN_new());
   CERT_RET_NOT_OK(BN_pseudo_rand(btmp.get(), 64, 0, 0),
                   "error generating random number");
-  auto serial = make_ssl_unique(ASN1_INTEGER_new());
+  auto serial = ssl_make_unique(ASN1_INTEGER_new());
   CERT_RET_IF_NULL(BN_to_ASN1_INTEGER(btmp.get(), serial.get()),
                    "error converting number into ASN1 representation");
   if (ret) {

http://git-wip-us.apache.org/repos/asf/kudu/blob/e367b4e0/src/kudu/security/ca/cert_management.h
----------------------------------------------------------------------
diff --git a/src/kudu/security/ca/cert_management.h b/src/kudu/security/ca/cert_management.h
index 2d623d8..4a222f4 100644
--- a/src/kudu/security/ca/cert_management.h
+++ b/src/kudu/security/ca/cert_management.h
@@ -34,103 +34,13 @@
 // in addition to openssl_util.h.
 typedef struct asn1_string_st ASN1_INTEGER;
 typedef struct env_md_st EVP_MD;
-typedef struct evp_pkey_st EVP_PKEY;
 typedef struct rsa_st RSA;
-typedef struct x509_st X509;
-typedef struct X509_req_st X509_REQ;
 struct stack_st_X509_EXTENSION; // STACK_OF(X509_EXTENSION)
 
 namespace kudu {
 namespace security {
 namespace ca {
 
-template <typename T>
-using c_unique_ptr = std::unique_ptr<T, std::function<void(T*)>>;
-
-// Acceptable formats for X509 certificates, X509 CSRs, and private keys.
-enum class DataFormat {
-  DER = 0,    // DER/ASN1 format (binary)
-  PEM = 1,    // PEM format (ASCII)
-};
-
-// Data format representation as a string.
-const std::string& DataFormatToString(DataFormat fmt);
-
-// Basic wrapper for objects of xxx_st type in the OpenSSL crypto library.
-class BasicWrapper {
- public:
-  virtual ~BasicWrapper() = default;
-
-  Status FromFile(const std::string& fpath, DataFormat format);
-  Status FromString(const std::string& data, DataFormat format);
-
-  Status ToString(std::string* data, DataFormat format) const;
-
- protected:
-  virtual Status FromBIO(BIO* bio, DataFormat format) = 0;
-  virtual Status ToBIO(BIO* bio, DataFormat format) const = 0;
-};
-
-// A wrapper for a private key.
-class Key : public BasicWrapper {
- public:
-  typedef EVP_PKEY RawDataType;
-
-  RawDataType* GetRawData() const {
-    return data_.get();
-  }
-
-  void AdoptRawData(RawDataType* data);
-
- protected:
-  Status FromBIO(BIO* bio, DataFormat format) override;
-  Status ToBIO(BIO* bio, DataFormat format) const override;
-
- private:
-  c_unique_ptr<RawDataType> data_;
-};
-
-// A wrapper for a X509 certificate.
-class Cert : public BasicWrapper {
- public:
-  typedef X509 RawDataType;
-
-  RawDataType* GetRawData() const {
-    return data_.get();
-  }
-
-  void AdoptRawData(RawDataType* data);
-
- protected:
-  Status FromBIO(BIO* bio, DataFormat format) override;
-  Status ToBIO(BIO* bio, DataFormat format) const override;
-
- private:
-  c_unique_ptr<RawDataType> data_;
-};
-
-// A wrapper for a X509 CSR (certificate signing request).
-class CertSignRequest : public BasicWrapper {
- public:
-  typedef X509_REQ RawDataType;
-
-  RawDataType* GetRawData() const {
-    return data_.get();
-  }
-
-  void AdoptRawData(RawDataType* data);
-
- protected:
-  Status FromBIO(BIO* bio, DataFormat format) override;
-  Status ToBIO(BIO* bio, DataFormat format) const override;
-
- private:
-  c_unique_ptr<RawDataType> data_;
-};
-
-// Utility method to generate private RSA keys.
-Status GeneratePrivateKey(int num_bits, Key* ret);
-
 // Base utility class for issuing X509 CSRs.
 class CertRequestGeneratorBase {
  public:

http://git-wip-us.apache.org/repos/asf/kudu/blob/e367b4e0/src/kudu/security/openssl_util.cc
----------------------------------------------------------------------
diff --git a/src/kudu/security/openssl_util.cc b/src/kudu/security/openssl_util.cc
index c6699db..e460611 100644
--- a/src/kudu/security/openssl_util.cc
+++ b/src/kudu/security/openssl_util.cc
@@ -17,22 +17,28 @@
 
 #include "kudu/security/openssl_util.h"
 
+#include <cstdio>
+#include <cstdlib>
 #include <mutex>
 #include <sstream>
 #include <string>
 #include <vector>
 
+#include <glog/logging.h>
 #include <openssl/err.h>
 #include <openssl/rand.h>
 #include <openssl/ssl.h>
 
+#include "kudu/gutil/strings/substitute.h"
 #include "kudu/util/debug/leakcheck_disabler.h"
 #include "kudu/util/mutex.h"
+#include "kudu/util/status.h"
 #include "kudu/util/thread.h"
 
 using std::ostringstream;
 using std::string;
 using std::vector;
+using strings::Substitute;
 
 namespace kudu {
 namespace security {
@@ -77,7 +83,8 @@ void DoInitializeOpenSSL() {
   CRYPTO_set_locking_callback(LockingCB);
   CRYPTO_THREADID_set_callback(ThreadIdCB);
 }
-} // namespace
+
+} // anonymous namespace
 
 void InitializeOpenSSL() {
   static std::once_flag ssl_once;
@@ -107,5 +114,205 @@ string GetOpenSSLErrors() {
   return serr.str();
 }
 
+namespace {
+
+// Writing the private key from an EVP_PKEY has a different
+// signature than the rest of the write functions, so we
+// have to provide this wrapper.
+int PemWritePrivateKey(BIO* bio, EVP_PKEY* key) {
+  auto rsa = ssl_make_unique(EVP_PKEY_get1_RSA(key));
+  return PEM_write_bio_RSAPrivateKey(
+      bio, rsa.get(), nullptr, nullptr, 0, nullptr, nullptr);
+}
+
+} // anonymous namespace
+
+template<> struct SslTypeTraits<BIO> {
+  static constexpr auto free = &BIO_free;
+};
+template<> struct SslTypeTraits<BIGNUM> {
+  static constexpr auto free = &BN_free;
+};
+template<> struct SslTypeTraits<EVP_PKEY> {
+  static constexpr auto free = &EVP_PKEY_free;
+  static constexpr auto read_pem = &PEM_read_bio_PrivateKey;
+  static constexpr auto read_der = &d2i_PrivateKey_bio;
+  static constexpr auto write_pem = &PemWritePrivateKey;
+  static constexpr auto write_der = &i2d_PrivateKey_bio;
+};
+template<> struct SslTypeTraits<RSA> {
+  static constexpr auto free = &RSA_free;
+};
+template<> struct SslTypeTraits<X509> {
+  static constexpr auto free = &X509_free;
+  static constexpr auto read_pem = &PEM_read_bio_X509;
+  static constexpr auto read_der = &d2i_X509_bio;
+  static constexpr auto write_pem = &PEM_write_bio_X509;
+  static constexpr auto write_der = &i2d_X509_bio;
+};
+template<> struct SslTypeTraits<X509_REQ> {
+  static constexpr auto free = &X509_REQ_free;
+  static constexpr auto read_pem = &PEM_read_bio_X509_REQ;
+  static constexpr auto read_der = &d2i_X509_REQ_bio;
+  static constexpr auto write_pem = &PEM_write_bio_X509_REQ;
+  static constexpr auto write_der = &i2d_X509_REQ_bio;
+};
+
+namespace {
+
+template<class TYPE>
+Status ToBIO(BIO* bio, DataFormat format, TYPE* obj) {
+  using Traits = SslTypeTraits<TYPE>;
+  CHECK(bio);
+  CHECK(obj);
+  switch (format) {
+    case DataFormat::DER:
+      CERT_RET_NOT_OK(Traits::write_der(bio, obj),
+          "error exporting data in DER format");
+      break;
+    case DataFormat::PEM:
+      CERT_RET_NOT_OK(Traits::write_pem(bio, obj),
+          "error exporting data in PEM format");
+      break;
+  }
+  CERT_RET_NOT_OK(BIO_flush(bio), "error flushing BIO");
+  return Status::OK();
+}
+
+template<class TYPE>
+Status FromBIO(BIO* bio, DataFormat format, c_unique_ptr<TYPE>* ret) {
+  using Traits = SslTypeTraits<TYPE>;
+  CHECK(bio);
+  switch (format) {
+    case DataFormat::DER:
+      *ret = ssl_make_unique(Traits::read_der(bio, nullptr));
+      break;
+    case DataFormat::PEM:
+      *ret = ssl_make_unique(Traits::read_pem(bio, nullptr, nullptr, nullptr));
+      break;
+  }
+  if (PREDICT_FALSE(!*ret)) {
+    return Status::RuntimeError(GetOpenSSLErrors());
+  }
+  return Status::OK();
+}
+
+} // anonymous namespace
+
+
+const string& DataFormatToString(DataFormat fmt) {
+  static const string kStrFormatUnknown = "UNKNOWN";
+  static const string kStrFormatDer = "DER";
+  static const string kStrFormatPem = "PEM";
+  switch (fmt) {
+    case DataFormat::DER:
+      return kStrFormatDer;
+    case DataFormat::PEM:
+      return kStrFormatPem;
+    default:
+      return kStrFormatUnknown;
+  }
+}
+
+Status BasicWrapper::FromFile(const string& fpath, DataFormat format) {
+  auto bio = ssl_make_unique(BIO_new(BIO_s_file()));
+  CERT_RET_NOT_OK(BIO_read_filename(bio.get(), fpath.c_str()),
+                  Substitute("$0: could not read from file", fpath));
+  RETURN_NOT_OK_PREPEND(FromBIO(bio.get(), format),
+                        Substitute("$0: unable to load data key from file",
+                                   fpath));
+  return Status::OK();
+}
+
+Status BasicWrapper::FromString(const string& data, DataFormat format) {
+  const void* mdata = reinterpret_cast<const void*>(data.data());
+  auto bio = ssl_make_unique(BIO_new_mem_buf(
+#if OPENSSL_VERSION_NUMBER < 0x10002000L
+      const_cast<void*>(mdata),
+#else
+      mdata,
+#endif
+      data.size()));
+  RETURN_NOT_OK_PREPEND(FromBIO(bio.get(), format),
+                        "unable to load data from memory");
+  return Status::OK();
+}
+
+Status BasicWrapper::ToString(std::string* data, DataFormat format) const {
+  CHECK(data);
+  auto bio = ssl_make_unique(BIO_new(BIO_s_mem()));
+  RETURN_NOT_OK_PREPEND(ToBIO(bio.get(), format), "error serializing data");
+  BUF_MEM* membuf;
+  CERT_CHECK_OK(BIO_get_mem_ptr(bio.get(), &membuf));
+  data->assign(membuf->data, membuf->length);
+  return Status::OK();
+}
+
+void Key::AdoptRawData(RawDataType* data) {
+  data_ = ssl_make_unique(data);
+}
+
+Status Key::FromBIO(BIO* bio, DataFormat format) {
+  RETURN_NOT_OK_PREPEND(::kudu::security::FromBIO(bio, format, &data_),
+      "unable to read private key");
+  return Status::OK();
+}
+
+Status Key::ToBIO(BIO* bio, DataFormat format) const {
+  RETURN_NOT_OK_PREPEND(::kudu::security::ToBIO(bio, format, data_.get()),
+      "could not export cert");
+  return Status::OK();
+}
+
+void Cert::AdoptRawData(RawDataType* data) {
+  data_ = ssl_make_unique(data);
+}
+
+Status Cert::FromBIO(BIO* bio, DataFormat format) {
+  RETURN_NOT_OK_PREPEND(::kudu::security::FromBIO(bio, format, &data_),
+      "could not read cert");
+  return Status::OK();
+}
+
+Status Cert::ToBIO(BIO* bio, DataFormat format) const {
+  RETURN_NOT_OK_PREPEND(::kudu::security::ToBIO(bio, format, data_.get()),
+      "could not export cert");
+  return Status::OK();
+}
+
+void CertSignRequest::AdoptRawData(RawDataType* data) {
+  data_ = ssl_make_unique(data);
+}
+
+Status CertSignRequest::FromBIO(BIO* bio, DataFormat format) {
+  RETURN_NOT_OK_PREPEND(::kudu::security::FromBIO(bio, format, &data_),
+      "could not read X509 CSR");
+  return Status::OK();
+}
+
+Status CertSignRequest::ToBIO(BIO* bio, DataFormat format) const {
+  RETURN_NOT_OK_PREPEND(::kudu::security::ToBIO(bio, format, data_.get()),
+      "could not export X509 CSR");
+  return Status::OK();
+}
+
+Status GeneratePrivateKey(int num_bits, Key* ret) {
+  CHECK(ret);
+  InitializeOpenSSL();
+  auto key = ssl_make_unique(EVP_PKEY_new());
+  {
+    auto bn = ssl_make_unique(BN_new());
+    CERT_CHECK_OK(BN_set_word(bn.get(), RSA_F4));
+    auto rsa = ssl_make_unique(RSA_new());
+    CERT_RET_NOT_OK(RSA_generate_key_ex(rsa.get(), num_bits, bn.get(), nullptr),
+                    "error generating RSA key");
+    CERT_RET_NOT_OK(EVP_PKEY_set1_RSA(key.get(), rsa.get()),
+                    "error assigning RSA key");
+  }
+  ret->AdoptRawData(key.release());
+
+  return Status::OK();
+}
+
 } // namespace security
 } // namespace kudu

http://git-wip-us.apache.org/repos/asf/kudu/blob/e367b4e0/src/kudu/security/openssl_util.h
----------------------------------------------------------------------
diff --git a/src/kudu/security/openssl_util.h b/src/kudu/security/openssl_util.h
index 1bfdb0d..426f0a1 100644
--- a/src/kudu/security/openssl_util.h
+++ b/src/kudu/security/openssl_util.h
@@ -17,12 +17,37 @@
 
 #pragma once
 
+#include <functional>
+#include <memory>
 #include <string>
 
+#include <glog/logging.h>
+
+#include "kudu/util/status.h"
+#include "kudu/gutil/strings/substitute.h"
+
 // Forward declarations for the OpenSSL typedefs.
 typedef struct bio_st BIO;
+typedef struct evp_pkey_st EVP_PKEY;
 typedef struct ssl_ctx_st SSL_CTX;
 typedef struct ssl_st SSL;
+typedef struct x509_st X509;
+typedef struct X509_req_st X509_REQ;
+
+#define CERT_CHECK_OK(call) \
+  CHECK_GT((call), 0)
+
+#define CERT_RET_NOT_OK(call, msg) \
+  if ((call) <= 0) { \
+    return Status::RuntimeError(Substitute("$0: $1", \
+        (msg), GetOpenSSLErrors())); \
+  }
+
+#define CERT_RET_IF_NULL(call, msg) \
+  if ((call) == nullptr) { \
+    return Status::RuntimeError(Substitute("$0: $1", \
+        (msg), GetOpenSSLErrors())); \
+  }
 
 namespace kudu {
 namespace security {
@@ -35,5 +60,103 @@ void InitializeOpenSSL();
 // Fetch the last error message from the OpenSSL library.
 std::string GetOpenSSLErrors();
 
+// A generic wrapper for OpenSSL structures.
+template <typename T>
+using c_unique_ptr = std::unique_ptr<T, std::function<void(T*)>>;
+
+// For each SSL type, the Traits class provides the important OpenSSL
+// API functions.
+template<class SSL_TYPE>
+struct SslTypeTraits {};
+
+template<class SSL_TYPE>
+c_unique_ptr<SSL_TYPE> ssl_make_unique(SSL_TYPE* d) {
+  return {d, SslTypeTraits<SSL_TYPE>::free};
+}
+
+// Acceptable formats for X509 certificates, X509 CSRs, and private keys.
+enum class DataFormat {
+  DER = 0,    // DER/ASN1 format (binary)
+  PEM = 1,    // PEM format (ASCII)
+};
+
+// Data format representation as a string.
+const std::string& DataFormatToString(DataFormat fmt);
+
+// Basic wrapper for objects of xxx_st type in the OpenSSL crypto library.
+class BasicWrapper {
+ public:
+  virtual ~BasicWrapper() = default;
+
+  Status FromFile(const std::string& fpath, DataFormat format);
+  Status FromString(const std::string& data, DataFormat format);
+
+  Status ToString(std::string* data, DataFormat format) const;
+
+ protected:
+  virtual Status FromBIO(BIO* bio, DataFormat format) = 0;
+  virtual Status ToBIO(BIO* bio, DataFormat format) const = 0;
+};
+
+// A wrapper for a private key.
+class Key : public BasicWrapper {
+ public:
+  typedef EVP_PKEY RawDataType;
+
+  RawDataType* GetRawData() const {
+    return data_.get();
+  }
+
+  void AdoptRawData(RawDataType* data);
+
+ protected:
+  Status FromBIO(BIO* bio, DataFormat format) override;
+  Status ToBIO(BIO* bio, DataFormat format) const override;
+
+ private:
+  c_unique_ptr<RawDataType> data_;
+};
+
+// A wrapper for a X509 certificate.
+class Cert : public BasicWrapper {
+ public:
+  typedef X509 RawDataType;
+
+  RawDataType* GetRawData() const {
+    return data_.get();
+  }
+
+  void AdoptRawData(RawDataType* data);
+
+ protected:
+  Status FromBIO(BIO* bio, DataFormat format) override;
+  Status ToBIO(BIO* bio, DataFormat format) const override;
+
+ private:
+  c_unique_ptr<RawDataType> data_;
+};
+
+// A wrapper for a X509 CSR (certificate signing request).
+class CertSignRequest : public BasicWrapper {
+ public:
+  typedef X509_REQ RawDataType;
+
+  RawDataType* GetRawData() const {
+    return data_.get();
+  }
+
+  void AdoptRawData(RawDataType* data);
+
+ protected:
+  Status FromBIO(BIO* bio, DataFormat format) override;
+  Status ToBIO(BIO* bio, DataFormat format) const override;
+
+ private:
+  c_unique_ptr<RawDataType> data_;
+};
+
+// Utility method to generate private RSA keys.
+Status GeneratePrivateKey(int num_bits, Key* ret);
+
 } // namespace security
 } // namespace kudu