summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile.am5
-rw-r--r--common/Crypto.cpp141
-rw-r--r--common/Crypto.hpp37
-rw-r--r--configure.ac9
-rw-r--r--tools/Config.cpp61
5 files changed, 242 insertions, 11 deletions
diff --git a/Makefile.am b/Makefile.am
index 5e0d64b24..0d2d4884b 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 000000000..aa268ae3c
--- /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 000000000..94b194cc2
--- /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 854d91526..f5b8a4a07 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 bf8c1e28a..986940c74 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);