]> git.ipfire.org Git - thirdparty/kea.git/commitdiff
[29-cryptolink-random-generator] Added RNG support
authorFrancis Dupont <fdupont@isc.org>
Thu, 23 Aug 2018 16:10:10 +0000 (18:10 +0200)
committerFrancis Dupont <fdupont@isc.org>
Sun, 4 Nov 2018 06:05:08 +0000 (01:05 -0500)
src/lib/cryptolink/Makefile.am
src/lib/cryptolink/botan1_link.cc
src/lib/cryptolink/botan_link.cc
src/lib/cryptolink/crypto_rng.cc [new file with mode: 0644]
src/lib/cryptolink/crypto_rng.h [new file with mode: 0644]
src/lib/cryptolink/cryptolink.cc
src/lib/cryptolink/cryptolink.h
src/lib/cryptolink/openssl_link.cc
src/lib/cryptolink/tests/crypto_unittests.cc

index b7e14ca55dead2c223c1cd3b1d6cb2d51b8305dc..9b3c9fde013a17ed2006cf6c2e0b183459311bcb 100644 (file)
@@ -11,6 +11,7 @@ lib_LTLIBRARIES = libkea-cryptolink.la
 libkea_cryptolink_la_SOURCES = cryptolink.h cryptolink.cc
 libkea_cryptolink_la_SOURCES += crypto_hash.h crypto_hash.cc
 libkea_cryptolink_la_SOURCES += crypto_hmac.h crypto_hmac.cc
+libkea_cryptolink_la_SOURCES += crypto_rng.h crypto_rng.cc
 if HAVE_BOTAN1
 libkea_cryptolink_la_SOURCES += botan1_link.cc
 libkea_cryptolink_la_SOURCES += botan_common.h
index a367c4ea6e11d0d3648ca3bce37b04150122a323..ce6bd8d6fa070562872c1144bac762ab61b94d4c 100644 (file)
@@ -9,9 +9,11 @@
 #include <cryptolink/cryptolink.h>
 #include <cryptolink/crypto_hash.h>
 #include <cryptolink/crypto_hmac.h>
+#include <cryptolink/crypto_rng.h>
 
 #include <botan/botan.h>
 #include <botan/init.h>
+#include <botan/auto_rng.h>
 
 namespace isc {
 namespace cryptolink {
@@ -23,19 +25,55 @@ private:
 };
 
 CryptoLink::~CryptoLink() {
+    rng_.reset();
     delete impl_;
 }
 
+/// \brief Botan implementation of RNG.
+class RNGImpl : public RNG {
+public:
+    RNGImpl() {
+        rng.reset(new Botan::AutoSeeded_RNG());
+    }
+
+    ~RNGImpl() {
+    }
+
+private:
+    std::vector<uint8_t> random(size_t len) {
+        std::vector<uint8_t> data;
+        if (len > 0) {
+            data.resize(len);
+            try {
+                rng->randomize(&data[0], len);
+            } catch (const Botan::Exception& ex) {
+                isc_throw(isc::cryptolink::LibraryError,
+                          "Botan error: " << ex.what());
+            }
+        }
+        return (data);
+    }
+
+    boost::shared_ptr<Botan::RandomNumberGenerator> rng;
+};
+
 void
 CryptoLink::initialize() {
     CryptoLink& c = getCryptoLinkInternal();
-    if (c.impl_ == NULL) {
+    if (!c.impl_) {
         try {
             c.impl_ = new CryptoLinkImpl();
         } catch (const Botan::Exception& ex) {
             isc_throw(InitializationError, "Botan error: " << ex.what());
         }
     }
+    if (!c.rng_) {
+        try {
+            c.rng_.reset(new RNGImpl());
+        } catch (const Botan::Exception& ex) {
+            isc_throw(InitializationError, "Botan error: " << ex.what());
+        }
+    }
 }
 
 std::string
index c7f40cb18244fe26782c35812bb85a676d8070f6..714663d507f2d781e12b0b7c39c0622f359a4c6c 100644 (file)
@@ -9,9 +9,11 @@
 #include <cryptolink/cryptolink.h>
 #include <cryptolink/crypto_hash.h>
 #include <cryptolink/crypto_hmac.h>
+#include <cryptolink/crypto_rng.h>
 
 #include <botan/exceptn.h>
 #include <botan/version.h>
+#include <botan/auto_rng.h>
 
 namespace isc {
 namespace cryptolink {
@@ -25,16 +27,53 @@ CryptoLink::~CryptoLink() {
     delete impl_;
 }
 
+/// \brief Botan implementation of RNG.
+class RNGImpl : public RNG {
+public:
+    RNGImpl() {
+        rng.reset(new Botan::AutoSeeded_RNG());
+    }
+
+    ~RNGImpl() {
+    }
+
+private:
+    std::vector<uint8_t> random(size_t len) {
+        std::vector<uint8_t> data;
+        if (len > 0) {
+            data.resize(len);
+            try {
+                rng->randomize(&data[0], len);
+            } catch (const Botan::Exception& ex) {
+                isc_throw(isc::cryptolink::LibraryError,
+                          "Botan error: " << ex.what());
+            }
+        }
+        return (data);
+    }
+
+    boost::shared_ptr<Botan::RandomNumberGenerator> rng;
+};
+
 void
 CryptoLink::initialize() {
     CryptoLink& c = getCryptoLinkInternal();
-    if (c.impl_ == NULL) {
+    if (!c.impl_) {
         try {
             c.impl_ = new CryptoLinkImpl();
         } catch (const Botan::Exception& ex) {
             isc_throw(InitializationError, "Botan error: " << ex.what());
         }
     }
+    if (!c.rng_) {
+        try {
+            c.rng_.reset(new RNGImpl());
+        } catch (const Botan::Exception& ex) {
+            isc_throw(InitializationError, "Botan error: " << ex.what());
+        }
+    }
+    // A not yet fixed bug makes RNG to be destroyed after memory pool...
+    atexit([]{ getCryptoLink().getRNG().reset(); });
 }
 
 std::string
diff --git a/src/lib/cryptolink/crypto_rng.cc b/src/lib/cryptolink/crypto_rng.cc
new file mode 100644 (file)
index 0000000..54dacce
--- /dev/null
@@ -0,0 +1,33 @@
+// Copyright (C) 2018 Internet Systems Consortium, Inc. ("ISC")
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#include <config.h>
+
+#include <cryptolink.h>
+#include <cryptolink/crypto_rng.h>
+
+#include <boost/scoped_ptr.hpp>
+
+#include <cstring>
+
+namespace isc {
+namespace cryptolink {
+
+RNG::RNG() {
+}
+
+RNG::~RNG() {
+}
+
+std::vector<uint8_t>
+random(size_t len)
+{
+    RNGPtr rng(CryptoLink::getCryptoLink().getRNG());
+    return (rng->random(len));
+}
+
+} // namespace cryptolink
+} // namespace isc
diff --git a/src/lib/cryptolink/crypto_rng.h b/src/lib/cryptolink/crypto_rng.h
new file mode 100644 (file)
index 0000000..916321e
--- /dev/null
@@ -0,0 +1,64 @@
+// Copyright (C) 2018 Internet Systems Consortium, Inc. ("ISC")
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#include <boost/noncopyable.hpp>
+
+#include <cryptolink/cryptolink.h>
+
+#ifndef ISC_CRYPTO_RNG_H
+#define ISC_CRYPTO_RNG_H
+
+namespace isc {
+namespace cryptolink {
+
+/// \brief RNG support
+///
+/// This class is used to get the RNG.
+/// The global instance can be get with CryptoLink::getRNG()
+///
+class RNG : private boost::noncopyable {
+public:
+    /// \brief Constructor from a Random Number Generator
+    ///
+    /// \exception LibraryError if there was any unexpected exception
+    ///                         in the underlying library
+    RNG();
+
+    /// \brief Destructor
+    virtual ~RNG();
+
+    /// \brief Generate random value.
+    ///
+    /// The result will be returned as a std::vector<uint8_t>
+    ///
+    /// \exception LibraryError if there was any unexpected exception
+    ///                         in the underlying library
+    ///
+    /// \param len The number of bytes from the result to generate.
+    /// \return a vector containing random value.
+    virtual std::vector<uint8_t> random(size_t len) = 0;
+
+private:
+    friend RNGPtr& CryptoLink::getRNG();
+};
+
+/// \brief Generate random value. 
+///
+/// This is a convenience function that generate random data
+/// given a fixed amount of data. Internally it does the same as
+/// creating an RNG object and generating the resulting value.
+///
+/// \exception LibraryError if there was any unexpected exception
+///                         in the underlying library
+///
+/// \param len The length of the data
+std::vector<uint8_t> random(size_t len);
+
+} // namespace cryptolink
+} // namespace isc
+
+#endif // ISC_CRYPTO_RNG_H
+
index 3bae155ce5f84c0e9326569ee74e9317367cb649..a768ee206b7e95ff6634019fbd078c779a7bfa2c 100644 (file)
@@ -41,6 +41,11 @@ CryptoLink::createHMAC(const void* secret, size_t secret_len,
     return (new HMAC(secret, secret_len, hash_algorithm));
 }
 
+RNGPtr&
+CryptoLink::getRNG() {
+    return (rng_);
+}
+
 } // namespace cryptolink
 } // namespace isc
 
index 1856b34137a7dda837bad7ac5ce3a7104194b035..b3e357835dde36e572f9cf285d0ec1e90b09496d 100644 (file)
@@ -12,7 +12,7 @@
 #include <exceptions/exceptions.h>
 
 #include <boost/noncopyable.hpp>
-#include <boost/scoped_ptr.hpp>
+#include <boost/shared_ptr.hpp>
 
 #include <memory>
 
@@ -42,6 +42,10 @@ class Hash;
 // Forward declaration for createHMAC()
 class HMAC;
 
+// Forward declaration for getRNG()
+class RNG;
+typedef boost::shared_ptr<RNG> RNGPtr;
+
 /// General exception class that is the base for all crypto-related
 /// exceptions
 class CryptoLinkError : public Exception {
@@ -84,8 +88,9 @@ public:
         CryptoLinkError(file, line, what) {}
 };
 
-/// Forward declaration for pimpl
+/// Forward declarations for pimpl
 class CryptoLinkImpl;
+class RNGImpl;
 
 /// \brief Singleton entry point and factory class
 ///
@@ -209,6 +214,14 @@ public:
     HMAC* createHMAC(const void* secret, size_t secret_len,
                      const HashAlgorithm hash_algorithm);
 
+    /// \brief Get the global RNG
+    ///
+    /// \exception NotImplemented if the method was not implemented
+    ///                           in a derived class
+    /// \exception LibraryError if there was any unexpected exception
+    ///                         in the underlying library
+    virtual RNGPtr& getRNG();
+
 private:
     // To enable us to use an optional explicit initialization call,
     // the 'real' instance getter is private
@@ -220,6 +233,8 @@ private:
     ~CryptoLink();
 
     CryptoLinkImpl* impl_;
+
+    RNGPtr rng_;
 };
 
 } // namespace cryptolink
index dac6ee4fd1b0905dd603891d65e2b8f393c10938..1a573f7c41756552613eeab9b428656b802ba392 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright (C) 2014-2015 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2014-2018 Internet Systems Consortium, Inc. ("ISC")
 //
 // This Source Code Form is subject to the terms of the Mozilla Public
 // License, v. 2.0. If a copy of the MPL was not distributed with this
@@ -7,27 +7,49 @@
 #include <config.h>
 
 #include <cryptolink/cryptolink.h>
+#include <cryptolink/crypto_rng.h>
 #include <cryptolink/crypto_hash.h>
 #include <cryptolink/crypto_hmac.h>
 
 #include <openssl/crypto.h>
+#include <openssl/rand.h>
 
 namespace isc {
 namespace cryptolink {
 
 // For OpenSSL, we use the CryptoLink class object in RAII style
 class CryptoLinkImpl {
-    // empty class
 };
 
 CryptoLink::~CryptoLink() {
     delete impl_;
 }
 
+/// \brief OpenSSL implementation of RNG.
+class RNGImpl : public RNG {
+public:
+    RNGImpl() { }
+
+    ~RNGImpl() { }
+
+private:
+    std::vector<uint8_t> random(size_t len) {
+        std::vector<uint8_t> data;
+        if (len > 0) {
+            data.resize(len);
+            if (RAND_bytes(&data[0], len) != 1) {
+                isc_throw(isc::cryptolink::LibraryError,
+                          "OpenSSL RAND_bytes() failed");
+            }
+        }
+        return (data);
+    }
+};
+
 void
 CryptoLink::initialize() {
     CryptoLink& c = getCryptoLinkInternal();
-    if (c.impl_ == NULL) {
+    if (!c.impl_) {
         try {
             c.impl_ = new CryptoLinkImpl();
         } catch (const std::exception &ex) {
@@ -40,6 +62,19 @@ CryptoLink::initialize() {
                       "Error during OpenSSL initialization");
         }
     }
+    if (!c.rng_) {
+        try {
+            c.rng_.reset(new RNGImpl());
+        } catch (const std::exception &ex) {
+            // Should never happen
+            isc_throw(InitializationError,
+                      "Error during OpenSSL RNG initialization:" << ex.what());
+        } catch (...) {
+            // Should never happen
+            isc_throw(InitializationError,
+                      "Error during OpenSSL RNG initialization");
+        }
+    }
 }
 
 std::string
@@ -49,4 +84,3 @@ CryptoLink::getVersion() {
 
 } // namespace cryptolink
 } // namespace isc
-
index d512ecaa5ae80ce81822154e01c4c3e1f760db2b..39dc20740021f98a8c1e9c6aca9b24cff835e637 100644 (file)
@@ -11,7 +11,9 @@
 #include <util/encode/hex.h>
 
 #include <cryptolink/cryptolink.h>
+#include <cryptolink/crypto_rng.h>
 
+using namespace std;
 using namespace isc::cryptolink;
 
 // Test get version
@@ -25,3 +27,29 @@ TEST(CryptoLinkTest, Singleton) {
     const CryptoLink& c2 = CryptoLink::getCryptoLink();
     ASSERT_EQ(&c1, &c2);
 }
+
+// Tests whether getRNG() returns a global value
+TEST(CryptoLinkTest, GlobalRNG) {
+    CryptoLink& c = CryptoLink::getCryptoLink();
+    RNGPtr rng1 = c.getRNG();
+    RNGPtr rng2 = c.getRNG();
+    ASSERT_EQ(rng1, rng2);
+}
+
+// Tests whether RNG works
+TEST(CryptoLinkTest, RNG) {
+    RNGPtr rng = CryptoLink::getCryptoLink().getRNG();
+    vector<uint8_t> data;
+    ASSERT_NO_THROW(data = rng->random(16));
+    ASSERT_EQ(16, data.size());
+    vector<uint8_t> zero;
+    zero.resize(16);
+    EXPECT_NE(0, memcmp(&zero[0], &data[0], zero.size()));
+
+    // Retry with the function (vs method)
+    vector<uint8_t> dataf;
+    ASSERT_NO_THROW(dataf = random(16));
+    ASSERT_EQ(16, dataf.size());
+    EXPECT_NE(0, memcmp(&zero[0], &dataf[0], zero.size()));
+    EXPECT_NE(0, memcmp(&data[0], &dataf[0], zero.size()));
+}