[Libreoffice-commits] online.git: common/Crypto.cpp common/Crypto.hpp configure.ac Makefile.am tools/Config.cpp

Michael Meeks michael.meeks at collabora.com
Tue Oct 3 19:53:05 UTC 2017


 Makefile.am       |    5 +
 common/Crypto.cpp |  141 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 common/Crypto.hpp |   37 ++++++++++++++
 configure.ac      |    9 +++
 tools/Config.cpp  |   61 +++++++++++++++++++----
 5 files changed, 242 insertions(+), 11 deletions(-)

New commits:
commit 79053911fc51bd0144144c34db944c24b42d3756
Author: Michael Meeks <michael.meeks at collabora.com>
Date:   Fri Jul 21 15:33:19 2017 +0100

    Support key logic and verification.
    
    Change-Id: Ie55150b99df3e80239236571af185502196ad3e9
    Reviewed-on: https://gerrit.libreoffice.org/43097
    Reviewed-by: Jan Holesovsky <kendy at collabora.com>
    Tested-by: Jan Holesovsky <kendy at collabora.com>
    (cherry picked from commit 56385cb8ac2a57af4eb70bc8bc7313a9299533c3)
    Reviewed-on: https://gerrit.libreoffice.org/43099

diff --git a/Makefile.am b/Makefile.am
index 5e0d64b2..0d2d4884 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -130,7 +130,10 @@ loolstress_SOURCES = tools/Stress.cpp \
                      common/Log.cpp \
 		     common/Util.cpp
 
-loolconfig_SOURCES = tools/Config.cpp
+loolconfig_SOURCES = tools/Config.cpp \
+		     common/Crypto.cpp \
+		     common/Log.cpp \
+		     common/Util.cpp
 
 wsd_headers = wsd/Admin.hpp \
               wsd/AdminModel.hpp \
diff --git a/common/Crypto.cpp b/common/Crypto.cpp
new file mode 100644
index 00000000..aa268ae3
--- /dev/null
+++ b/common/Crypto.cpp
@@ -0,0 +1,141 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * 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"
+
+#if ENABLE_SUPPORT_KEY
+
+#include <Poco/DigestStream.h>
+#include <Poco/Base64Decoder.h>
+#include <Poco/DateTimeParser.h>
+#include <Poco/Crypto/RSADigestEngine.h>
+
+#include <fstream>
+#include <sstream>
+#include <iostream>
+
+#include "Log.hpp"
+#include "Crypto.hpp"
+
+using namespace Poco;
+using namespace Poco::Crypto;
+
+struct SupportKeyImpl
+{
+    bool _invalid;
+    std::string _key;
+    std::string _data;
+    std::string _signature;
+    DateTime _expiry;
+    // Key format: iso-expiry-date:field1:field2:field:...:<signature>
+    SupportKeyImpl(const std::string &key)
+        : _invalid(true), _key(key)
+    {
+        LOG_INF("Support key '" << key << "' provided");
+        size_t firstColon = key.find(':');
+        if (firstColon != std::string::npos)
+        {
+            std::string expiry(key.substr(0, firstColon));
+            LOG_INF("Support key with expiry '" << expiry << "'");
+
+            try {
+                int timeZoneDifferential = 0;
+                Poco::DateTimeParser::parse(expiry, _expiry, timeZoneDifferential);
+
+                size_t lastColon = key.rfind(":");
+                if (lastColon != std::string::npos)
+                {
+                    _signature = key.substr(lastColon + 1,
+                                            key.length() - lastColon);
+                    _data = key.substr(0, lastColon);
+                    std::cout << "signature '" << _signature << "' data '" << _data << "'\n";
+
+                    _invalid = false;
+                }
+            } catch (SyntaxException &e) {
+                LOG_ERR("Invalid support key expiry '" << expiry << "'");
+            }
+        }
+    }
+};
+
+SupportKey::SupportKey(const std::string &key) :
+    _impl(new SupportKeyImpl(key))
+{
+}
+
+SupportKey::~SupportKey()
+{
+}
+
+bool SupportKey::verify()
+{
+    if (_impl->_invalid)
+    {
+        LOG_ERR("Basic key structure is invalid.");
+        return false;
+    }
+
+    std::ifstream pubStream;
+    try {
+        pubStream.open ("pubKey.pub", std::ifstream::in);
+        if (pubStream.fail())
+        {
+            LOG_ERR("Failed to open support public key.");
+            return false;
+        }
+    } catch (...) {
+        LOG_ERR("Exception opening public key");
+        return false;
+    }
+    try {
+        RSAKey keyPub(&pubStream);
+        RSADigestEngine rsaEngine(keyPub, RSADigestEngine::DigestType::DIGEST_SHA1);
+        rsaEngine.update(_impl->_data);
+
+        std::istringstream sigStream(_impl->_signature);
+        Poco::Base64Decoder rawStream(sigStream);
+
+        std::istreambuf_iterator<char> eos;
+        std::vector<unsigned char> rawSignature(std::istreambuf_iterator<char>(rawStream), eos);
+        LOG_INF("Signature of length " << rawSignature.size()
+                << " data size: " << _impl->_data.length());
+        if (!rsaEngine.verify(rawSignature))
+        {
+            LOG_ERR("Support key is not correctly signed.");
+            return false;
+        }
+    } catch (...) {
+        LOG_ERR("Exception validating support key.");
+        return false;
+    }
+    LOG_INF("Support key correctly signed.");
+    return true;
+}
+
+int SupportKey::validDaysRemaining()
+{
+    if (!verify())
+    {
+        LOG_ERR("Support key signature is invalid.");
+        return 0;
+    }
+    Timespan remaining = _impl->_expiry - DateTime();
+    int days = remaining.days();
+    if (days > 0)
+        LOG_INF("Support key has " << days << " remaining");
+    else
+        LOG_ERR("Support key has expired for " << -days << " days");
+
+    return days;
+}
+
+#endif // ENABLE_SUPPORT_KEY
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/common/Crypto.hpp b/common/Crypto.hpp
new file mode 100644
index 00000000..94b194cc
--- /dev/null
+++ b/common/Crypto.hpp
@@ -0,0 +1,37 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * 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/.
+ */
+
+#ifndef INCLUDED_CRYPTO_HPP
+#define INCLUDED_CRYPTO_HPP
+
+#if ENABLE_SUPPORT_KEY
+
+#include <memory>
+
+struct SupportKeyImpl;
+
+class SupportKey {
+    std::unique_ptr<SupportKeyImpl> _impl;
+
+public:
+    SupportKey(const std::string &key);
+    virtual ~SupportKey();
+
+    /// Check the key is validly signed.
+    bool verify();
+
+    /// How many days until key expires
+    int validDaysRemaining();
+};
+
+#endif
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/configure.ac b/configure.ac
index 854d9152..f5b8a4a0 100644
--- a/configure.ac
+++ b/configure.ac
@@ -96,6 +96,10 @@ AC_ARG_ENABLE([ssl],
             AS_HELP_STRING([--disable-ssl],
                            [Compile without SSL support]))
 
+AC_ARG_ENABLE([support-key],
+            AS_HELP_STRING([--enable-support-key],
+                [Implements signed key with expiration required for support. Almost certainly you don't want to enable this.]))
+
 AC_ARG_WITH([max-connections],
             AS_HELP_STRING([--max-connections],
                            [Set the limit on the total number of client connections. Def: 20, Min: 3.]))
@@ -291,6 +295,11 @@ fi
 
 AC_SUBST(ENABLE_SSL)
 
+AS_IF([test "$enable_support_key" == "yes"],
+      [AC_DEFINE([ENABLE_SUPPORT_KEY],1,[Whether to enable support key])],
+      [AC_DEFINE([ENABLE_SUPPORT_KEY],0,[Whether to enable support key])])
+AC_SUBST(ENABLE_SUPPORT_KEY)
+
 LIBS="$LIBS -lPocoNet${POCO_DEBUG_SUFFIX} -lPocoUtil${POCO_DEBUG_SUFFIX} -lPocoJSON${POCO_DEBUG_SUFFIX} -lPocoFoundation${POCO_DEBUG_SUFFIX} -lPocoXML${POCO_DEBUG_SUFFIX} -lPocoNetSSL${POCO_DEBUG_SUFFIX} -lPocoCrypto${POCO_DEBUG_SUFFIX}"
 
 AC_CHECK_HEADERS([LibreOfficeKit/LibreOfficeKit.h],
diff --git a/tools/Config.cpp b/tools/Config.cpp
index bf8c1e28..986940c7 100644
--- a/tools/Config.cpp
+++ b/tools/Config.cpp
@@ -25,6 +25,7 @@
 #include <Poco/Util/XMLConfiguration.h>
 
 #include "Util.hpp"
+#include "Crypto.hpp"
 
 using Poco::Util::Application;
 using Poco::Util::HelpFormatter;
@@ -80,7 +81,11 @@ void Config::displayHelp()
     helpFormatter.format(std::cout);
     std::cout << std::endl
               << "Commands:" << std::endl
-              << "  set-admin-password" << std::endl;
+              << "  set-admin-password" << std::endl
+#if ENABLE_SUPPORT_KEY
+              << "  set-support-key" << std::endl
+#endif
+        ;
 }
 
 void Config::defineOptions(OptionSet& optionSet)
@@ -165,12 +170,14 @@ int Config::main(const std::vector<std::string>& args)
         return Application::EXIT_NOINPUT;
     }
 
-#if HAVE_PKCS5_PBKDF2_HMAC
+    bool changed = false;
     _loolConfig.load(ConfigFile);
 
-    for (unsigned i = 0; i < args.size(); i++) {
+    for (unsigned i = 0; i < args.size(); i++)
+    {
         if (args[i] == "set-admin-password")
         {
+#if HAVE_PKCS5_PBKDF2_HMAC
             unsigned char pwdhash[_adminConfig.pwdHashLength];
             unsigned char salt[_adminConfig.pwdSaltLength];
             RAND_bytes(salt, _adminConfig.pwdSaltLength);
@@ -226,18 +233,52 @@ int Config::main(const std::vector<std::string>& args)
                                   "Salt and password hash combination generated using PBKDF2 with SHA512 digest.");
             _loolConfig.setString("admin_console.secure_password", pwdConfigValue.str());
 
-            std::cout << "Saving configuration to : " << ConfigFile << " ..." << std::endl;
-            _loolConfig.save(ConfigFile);
-            std::cout << "Saved" << std::endl;
+            changed = true;
+#else
+            std::cerr << "This application was compiled with old OpenSSL. Operation not supported. You can use plain text password in /etc/loolwsd/loolwsd.xml." << std::endl;
+            return Application::EXIT_UNAVAILABLE;
+#endif
         }
+#if ENABLE_SUPPORT_KEY
+        else if (args[i] == "set-support-key")
+        {
+            std::string supportKeyString;
+            std::cout << "Enter support key: ";
+            std::cin >> supportKeyString;
+            if (supportKeyString.length() > 0)
+            {
+                SupportKey key(supportKeyString);
+                if (!key.verify())
+                    std::cerr << "Invalid key\n";
+                else {
+                    int validDays =  key.validDaysRemaining();
+                    if (validDays <= 0)
+                        std::cerr << "Valid but expired key\n";
+                    else
+                    {
+                        std::cerr << "Valid for " << validDays << " days - setting to config\n";
+                        _loolConfig.setString("support_key", supportKeyString);
+                    }
+                }
+            }
+            else
+            {
+                std::cerr << "Removing empty support key\n";
+                _loolConfig.remove("support_key");
+            }
+            changed = true;
+        }
+#endif
+    }
+    if (changed)
+    {
+        std::cout << "Saving configuration to : " << ConfigFile << " ..." << std::endl;
+        _loolConfig.save(ConfigFile);
+        std::cout << "Saved" << std::endl;
     }
 
     // This tool only handles options, nothing to do here
     return Application::EXIT_OK;
-#else
-    std::cerr << "This application was compiled with old OpenSSL. Operation not supported. You can use plain text password in /etc/loolwsd/loolwsd.xml." << std::endl;
-    return Application::EXIT_UNAVAILABLE;
-#endif
 }
 
 POCO_APP_MAIN(Config);


More information about the Libreoffice-commits mailing list