From b7959f5b0171234a4b2988fd1fb01c5a743e4dda Mon Sep 17 00:00:00 2001
From: Guillaume Roguez <guillaume.roguez@savoirfairelinux.com>
Date: Mon, 20 Nov 2017 15:23:28 -0500
Subject: [PATCH] security: extract DhParams from TlsSession

TlsSession will be refactored to handle DTLS and TLS.
This patch cleanup TlsSession files to process further.

Change-Id: I76b6ac73d9fe46ee6a18c6c9d725f6fcadb465d9
Reviewed-by: Olivier Soldano <olivier.soldano@savoirfairelinux.com>
---
 src/ringdht/ringaccount.h       |   1 +
 src/security/Makefile.am        |   4 +-
 src/security/diffie-hellman.cpp | 103 ++++++++++++++++++++++++++++++++
 src/security/diffie-hellman.h   |  71 ++++++++++++++++++++++
 src/security/tls_session.cpp    |  76 +----------------------
 src/security/tls_session.h      |  42 +------------
 6 files changed, 181 insertions(+), 116 deletions(-)
 create mode 100644 src/security/diffie-hellman.cpp
 create mode 100644 src/security/diffie-hellman.h

diff --git a/src/ringdht/ringaccount.h b/src/ringdht/ringaccount.h
index 5b36df9647..f850d978ba 100644
--- a/src/ringdht/ringaccount.h
+++ b/src/ringdht/ringaccount.h
@@ -26,6 +26,7 @@
 #endif
 
 #include "security/tls_session.h"
+#include "security/diffie-hellman.h"
 #include "sip/sipaccountbase.h"
 
 #include "noncopyable.h"
diff --git a/src/security/Makefile.am b/src/security/Makefile.am
index 382d357323..5ef080c08b 100644
--- a/src/security/Makefile.am
+++ b/src/security/Makefile.am
@@ -11,4 +11,6 @@ libsecurity_la_SOURCES = \
 		certstore.cpp \
 		certstore.h \
 		memory.cpp \
-		memory.h
+		memory.h \
+		diffie-hellman.cpp \
+		diffie-hellman.h
diff --git a/src/security/diffie-hellman.cpp b/src/security/diffie-hellman.cpp
new file mode 100644
index 0000000000..aea39992f6
--- /dev/null
+++ b/src/security/diffie-hellman.cpp
@@ -0,0 +1,103 @@
+/*
+ *  Copyright (C) 2004-2017 Savoir-faire Linux Inc.
+ *
+ *  Author: Guillaume Roguez <guillaume.roguez@savoirfairelinux.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA.
+ */
+
+#include "diffie-hellman.h"
+#include "logger.h"
+
+#include <chrono>
+
+namespace ring { namespace tls {
+
+DhParams::DhParams(const std::vector<uint8_t>& data)
+{
+    gnutls_dh_params_t new_params_;
+    int ret = gnutls_dh_params_init(&new_params_);
+    if (ret)
+        throw std::runtime_error(std::string("Error initializing DH params: ") + gnutls_strerror(ret));
+    params_.reset(new_params_);
+    const gnutls_datum_t dat {(uint8_t*)data.data(), (unsigned)data.size()};
+    if (int ret_pem = gnutls_dh_params_import_pkcs3(params_.get(), &dat, GNUTLS_X509_FMT_PEM))
+        if (int ret_der = gnutls_dh_params_import_pkcs3(params_.get(), &dat, GNUTLS_X509_FMT_DER))
+            throw std::runtime_error(std::string("Error importing DH params: ") + gnutls_strerror(ret_pem) + " " + gnutls_strerror(ret_der));
+}
+
+DhParams&
+DhParams::operator=(const DhParams& other)
+{
+    if (not params_) {
+        // We need a valid DH params pointer for the copy
+        gnutls_dh_params_t new_params_;
+        auto err = gnutls_dh_params_init(&new_params_);
+        if (err != GNUTLS_E_SUCCESS)
+            throw std::runtime_error(std::string("Error initializing DH params: ") + gnutls_strerror(err));
+        params_.reset(new_params_);
+    }
+
+    auto err = gnutls_dh_params_cpy(params_.get(), other.get());
+    if (err != GNUTLS_E_SUCCESS)
+        throw std::runtime_error(std::string("Error copying DH params: ") + gnutls_strerror(err));
+
+    return *this;
+}
+
+std::vector<uint8_t>
+DhParams::serialize() const
+{
+    if (!params_) {
+        RING_WARN("serialize() called on an empty DhParams");
+        return {};
+    }
+    gnutls_datum_t out;
+    if (gnutls_dh_params_export2_pkcs3(params_.get(), GNUTLS_X509_FMT_PEM, &out))
+        return {};
+    std::vector<uint8_t> ret {out.data, out.data+out.size};
+    gnutls_free(out.data);
+    return ret;
+}
+
+DhParams
+DhParams::generate()
+{
+    using clock = std::chrono::high_resolution_clock;
+
+    auto bits = gnutls_sec_param_to_pk_bits(GNUTLS_PK_DH, /* GNUTLS_SEC_PARAM_HIGH */ GNUTLS_SEC_PARAM_HIGH);
+    RING_DBG("Generating DH params with %u bits", bits);
+    auto start = clock::now();
+
+    gnutls_dh_params_t new_params_;
+    int ret = gnutls_dh_params_init(&new_params_);
+    if (ret != GNUTLS_E_SUCCESS) {
+        RING_ERR("Error initializing DH params: %s", gnutls_strerror(ret));
+        return {};
+    }
+    DhParams params {new_params_};
+
+    ret = gnutls_dh_params_generate2(params.get(), bits);
+    if (ret != GNUTLS_E_SUCCESS) {
+        RING_ERR("Error generating DH params: %s", gnutls_strerror(ret));
+        return {};
+    }
+
+    std::chrono::duration<double> time_span = clock::now() - start;
+    RING_DBG("Generated DH params with %u bits in %lfs", bits, time_span.count());
+    return params;
+}
+
+}} // namespace ring::tls
diff --git a/src/security/diffie-hellman.h b/src/security/diffie-hellman.h
new file mode 100644
index 0000000000..9bab03e6b1
--- /dev/null
+++ b/src/security/diffie-hellman.h
@@ -0,0 +1,71 @@
+/*
+ *  Copyright (C) 2004-2017 Savoir-faire Linux Inc.
+ *
+ *  Author: Adrien Béraud <adrien.beraud@savoirfairelinux.com>
+ *  Author: Guillaume Roguez <guillaume.roguez@savoirfairelinux.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA.
+ */
+
+#pragma once
+
+#include <gnutls/gnutls.h>
+#include <vector>
+#include <memory>
+#include <cstdint>
+
+namespace ring { namespace tls {
+
+class DhParams {
+public:
+    DhParams() = default;
+    DhParams(DhParams&&) = default;
+    DhParams(const DhParams& other) {
+        *this = other;
+    }
+
+    DhParams& operator=(DhParams&& other) = default;
+    DhParams& operator=(const DhParams& other);
+
+    /// \brief Construct by taking ownership of given gnutls DH params
+    ///
+    /// User should not call gnutls_dh_params_deinit on given \a raw_params.
+    /// The object is stolen and its live is manager by our object.
+    explicit DhParams(gnutls_dh_params_t p) : params_ {p, gnutls_dh_params_deinit} {}
+
+    /** Deserialize DER or PEM encoded DH-params */
+    DhParams(const std::vector<uint8_t>& data);
+
+    gnutls_dh_params_t get() {
+        return params_.get();
+    }
+    gnutls_dh_params_t get() const {
+        return params_.get();
+    }
+
+    explicit inline operator bool() const {
+        return bool(params_);
+    }
+
+    /** Serialize data in PEM format */
+    std::vector<uint8_t> serialize() const;
+
+    static DhParams generate();
+
+private:
+    std::unique_ptr<gnutls_dh_params_int, decltype(gnutls_dh_params_deinit)*> params_ {nullptr, gnutls_dh_params_deinit};
+};
+
+}} // namespace ring::tls
diff --git a/src/security/tls_session.cpp b/src/security/tls_session.cpp
index 3c220ae52c..566476728d 100644
--- a/src/security/tls_session.cpp
+++ b/src/security/tls_session.cpp
@@ -32,6 +32,7 @@
 #include "manager.h"
 #include "certstore.h"
 #include "array_size.h"
+#include "diffie-hellman.h"
 
 #include <gnutls/gnutls.h>
 #include <gnutls/dtls.h>
@@ -83,53 +84,6 @@ array2uint(const std::array<uint8_t, 8>& a)
     return res;
 }
 
-DhParams::DhParams(const std::vector<uint8_t>& data)
-{
-    gnutls_dh_params_t new_params_;
-    int ret = gnutls_dh_params_init(&new_params_);
-    if (ret)
-        throw std::runtime_error(std::string("Error initializing DH params: ") + gnutls_strerror(ret));
-    params_.reset(new_params_);
-    const gnutls_datum_t dat {(uint8_t*)data.data(), (unsigned)data.size()};
-    if (int ret_pem = gnutls_dh_params_import_pkcs3(params_.get(), &dat, GNUTLS_X509_FMT_PEM))
-        if (int ret_der = gnutls_dh_params_import_pkcs3(params_.get(), &dat, GNUTLS_X509_FMT_DER))
-            throw std::runtime_error(std::string("Error importing DH params: ") + gnutls_strerror(ret_pem) + " " + gnutls_strerror(ret_der));
-}
-
-DhParams&
-DhParams::operator=(const DhParams& other)
-{
-    if (not params_) {
-        // We need a valid DH params pointer for the copy
-        gnutls_dh_params_t new_params_;
-        auto err = gnutls_dh_params_init(&new_params_);
-        if (err != GNUTLS_E_SUCCESS)
-            throw std::runtime_error(std::string("Error initializing DH params: ") + gnutls_strerror(err));
-        params_.reset(new_params_);
-    }
-
-    auto err = gnutls_dh_params_cpy(params_.get(), other.get());
-    if (err != GNUTLS_E_SUCCESS)
-        throw std::runtime_error(std::string("Error copying DH params: ") + gnutls_strerror(err));
-
-    return *this;
-}
-
-std::vector<uint8_t>
-DhParams::serialize() const
-{
-    if (!params_) {
-        RING_WARN("serialize() called on an empty DhParams");
-        return {};
-    }
-    gnutls_datum_t out;
-    if (gnutls_dh_params_export2_pkcs3(params_.get(), GNUTLS_X509_FMT_PEM, &out))
-        return {};
-    std::vector<uint8_t> ret {out.data, out.data+out.size};
-    gnutls_free(out.data);
-    return ret;
-}
-
 class TlsSession::TlsCertificateCredendials
 {
     using T = gnutls_certificate_credentials_t;
@@ -1085,34 +1039,6 @@ TlsSession::process()
         callbacks_.onStateChange(new_state);
 }
 
-DhParams
-DhParams::generate()
-{
-    using clock = std::chrono::high_resolution_clock;
-
-    auto bits = gnutls_sec_param_to_pk_bits(GNUTLS_PK_DH, /* GNUTLS_SEC_PARAM_HIGH */ GNUTLS_SEC_PARAM_HIGH);
-    RING_DBG("Generating DH params with %u bits", bits);
-    auto start = clock::now();
-
-    gnutls_dh_params_t new_params_;
-    int ret = gnutls_dh_params_init(&new_params_);
-    if (ret != GNUTLS_E_SUCCESS) {
-        RING_ERR("Error initializing DH params: %s", gnutls_strerror(ret));
-        return {};
-    }
-    DhParams params {new_params_};
-
-    ret = gnutls_dh_params_generate2(params.get(), bits);
-    if (ret != GNUTLS_E_SUCCESS) {
-        RING_ERR("Error generating DH params: %s", gnutls_strerror(ret));
-        return {};
-    }
-
-    std::chrono::duration<double> time_span = clock::now() - start;
-    RING_DBG("Generated DH params with %u bits in %lfs", bits, time_span.count());
-    return params;
-}
-
 uint16_t
 TlsSession::getMtu()
 {
diff --git a/src/security/tls_session.h b/src/security/tls_session.h
index 17fce2c9ce..71d3e9b095 100644
--- a/src/security/tls_session.h
+++ b/src/security/tls_session.h
@@ -57,6 +57,8 @@ struct PrivateKey;
 
 namespace ring { namespace tls {
 
+class DhParams;
+
 static constexpr uint8_t MTUS_TO_TEST = 3; //number of mtus to test in path mtu discovery.
 static constexpr int DTLS_MTU {1232}; // (1280 from IPv6 minimum MTU - 40 IPv6 header - 8 UDP header)
 static constexpr uint16_t MIN_MTU {512};
@@ -70,46 +72,6 @@ enum class TlsSessionState {
     SHUTDOWN
 };
 
-class DhParams {
-public:
-    DhParams() = default;
-    DhParams(DhParams&&) = default;
-    DhParams(const DhParams& other) {
-        *this = other;
-    }
-
-    DhParams& operator=(DhParams&& other) = default;
-    DhParams& operator=(const DhParams& other);
-
-    /// \brief Construct by taking ownership of given gnutls DH params
-    ///
-    /// User should not call gnutls_dh_params_deinit on given \a raw_params.
-    /// The object is stolen and its live is manager by our object.
-    explicit DhParams(gnutls_dh_params_t p) : params_ {p, gnutls_dh_params_deinit} {}
-
-    /** Deserialize DER or PEM encoded DH-params */
-    DhParams(const std::vector<uint8_t>& data);
-
-    gnutls_dh_params_t get() {
-        return params_.get();
-    }
-    gnutls_dh_params_t get() const {
-        return params_.get();
-    }
-
-    explicit inline operator bool() const {
-        return bool(params_);
-    }
-
-    /** Serialize data in PEM format */
-    std::vector<uint8_t> serialize() const;
-
-    static DhParams generate();
-
-private:
-    std::unique_ptr<gnutls_dh_params_int, decltype(gnutls_dh_params_deinit)*> params_ {nullptr, gnutls_dh_params_deinit};
-};
-
 struct TlsParams {
     // User CA list for session credentials
     std::string ca_list;
-- 
GitLab