diff options
author | Tomaž Vajngerl <tomaz.vajngerl@collabora.co.uk> | 2018-11-09 08:47:49 +0100 |
---|---|---|
committer | Tomaž Vajngerl <quikee@gmail.com> | 2018-11-09 09:06:51 +0100 |
commit | 37e1e208c218077c46c5370d2caf5be722e7452e (patch) | |
tree | dd46c674be49a6dffec9e0eaf0a90a4ae0a3fb73 | |
parent | 40442bfaa6da0730422ba7e057a3ef2ecde88ffc (diff) |
add "sign" function to infobar to sign with a one-time cert.
In addition:
- add methods to transport the certificate chain, signing
certificate and signing certificate to WSD
- add conversion of PEM cert. format to DER
- add transporting the certificate chain to the LO core
- run the signing function with the signing cert. and the
private key
Change-Id: I1a005e88cacbd81144df40d315197561401db427
Reviewed-on: https://gerrit.libreoffice.org/63156
Reviewed-by: Tomaž Vajngerl <quikee@gmail.com>
Tested-by: Tomaž Vajngerl <quikee@gmail.com>
-rw-r--r-- | kit/ChildSession.cpp | 100 | ||||
-rw-r--r-- | loleaflet/js/toolbar.js | 4 | ||||
-rw-r--r-- | loleaflet/src/control/Signing.js | 17 |
3 files changed, 118 insertions, 3 deletions
diff --git a/kit/ChildSession.cpp b/kit/ChildSession.cpp index 4e6c3ef7a..b775c6784 100644 --- a/kit/ChildSession.cpp +++ b/kit/ChildSession.cpp @@ -21,8 +21,11 @@ #include <Poco/Net/WebSocket.h> #include <Poco/StringTokenizer.h> #include <Poco/URI.h> +#include <Poco/BinaryReader.h> +#include <Poco/Base64Decoder.h> #include <common/FileUtil.hpp> +#include <common/JsonUtil.hpp> #include "KitHelper.hpp" #include <Log.hpp> #include <Png.hpp> @@ -245,7 +248,9 @@ bool ChildSession::_handleInput(const char *buffer, int length) tokens[0] == "saveas" || tokens[0] == "useractive" || tokens[0] == "userinactive" || - tokens[0] == "windowcommand"); + tokens[0] == "windowcommand" || + tokens[0] == "asksignaturestatus" || + tokens[0] == "signdocument"); if (tokens[0] == "clientzoom") { @@ -1112,9 +1117,98 @@ bool ChildSession::sendWindowCommand(const char* /*buffer*/, int /*length*/, con return true; } -bool ChildSession::signDocumentContent(const char* /*buffer*/, int /*length*/, const std::vector<std::string>& /*tokens*/) +namespace { - return true; + +std::string extractCertificate(const std::string & certificate) +{ + const std::string header("-----BEGIN CERTIFICATE-----"); + const std::string footer("-----END CERTIFICATE-----"); + + std::string result; + + size_t pos1 = certificate.find(header); + if (pos1 == std::string::npos) + return result; + + size_t pos2 = certificate.find(footer, pos1 + 1); + if (pos2 == std::string::npos) + return result; + + pos1 = pos1 + std::string(header).length(); + pos2 = pos2 - pos1; + + return certificate.substr(pos1, pos2); +} + +std::string extractPrivateKey(const std::string & privateKey) +{ + const std::string header("-----BEGIN PRIVATE KEY-----"); + const std::string footer("-----END PRIVATE KEY-----"); + + std::string result; + + size_t pos1 = privateKey.find(header); + if (pos1 == std::string::npos) + return result; + + size_t pos2 = privateKey.find(footer, pos1 + 1); + if (pos2 == std::string::npos) + return result; + + pos1 = pos1 + std::string(header).length(); + pos2 = pos2 - pos1; + + return privateKey.substr(pos1, pos2); +} + +std::vector<unsigned char> decodeBase64(const std::string & inputBase64) +{ + std::istringstream stream(inputBase64); + Poco::Base64Decoder base64Decoder(stream); + std::istreambuf_iterator<char> eos; + return std::vector<unsigned char>(std::istreambuf_iterator<char>(base64Decoder), eos); +} + +} + +bool ChildSession::signDocumentContent(const char* buffer, int length, const std::vector<std::string>& /*tokens*/) +{ + bool bResult = true; + + const std::string firstLine = getFirstLine(buffer, length); + const char* data = buffer + firstLine.size() + 1; + const int size = length - firstLine.size() - 1; + std::string json(data, size); + + Poco::JSON::Parser parser; + Poco::JSON::Object::Ptr root = parser.parse(json).extract<Poco::JSON::Object::Ptr>(); + + for (auto& chainPtr : *root->getArray("chain")) + { + assert(chainPtr.isString()); + std::string chainCertificate = chainPtr; + std::vector<unsigned char> binaryChainCertificate = decodeBase64(extractCertificate(chainCertificate)); + + bResult = getLOKitDocument()->addCertificate( + binaryChainCertificate.data(), + binaryChainCertificate.size()); + + if (!bResult) + return false; + } + + std::string x509Certificate = JsonUtil::getJSONValue<std::string>(root, "x509Certificate"); + std::vector<unsigned char> binaryCertificate = decodeBase64(extractCertificate(x509Certificate)); + + std::string privateKey = JsonUtil::getJSONValue<std::string>(root, "privateKey"); + std::vector<unsigned char> binaryPrivateKey = decodeBase64(extractPrivateKey(privateKey)); + + bResult = getLOKitDocument()->insertCertificate( + binaryCertificate.data(), binaryCertificate.size(), + binaryPrivateKey.data(), binaryPrivateKey.size()); + + return bResult; } bool ChildSession::askSignatureStatus(const char* /*buffer*/, int /*length*/, const std::vector<std::string>& /*tokens*/) diff --git a/loleaflet/js/toolbar.js b/loleaflet/js/toolbar.js index 53a3a1b7b..51b84902c 100644 --- a/loleaflet/js/toolbar.js +++ b/loleaflet/js/toolbar.js @@ -234,6 +234,9 @@ function onClick(e, id, item, subItem) { else if (id === 'logout') { map.signingLogout(); } + else if (id === 'sign') { + map.signDocument(); + } } function setBorders(left, right, bottom, top, horiz, vert) { @@ -767,6 +770,7 @@ function createToolbar() { items: [ {type: 'html', id: 'left'}, {type: 'html', id: 'logo', html: '<p><b>Vereign</b></p>'}, + {type: 'button', id: 'sign', caption: 'Sign', img: '', hint: _('Sign document')}, {type: 'break' }, {type: 'html', id: 'user-label', html: '<p>User:</p>'}, {type: 'html', id: 'user', html: '<none>'}, diff --git a/loleaflet/src/control/Signing.js b/loleaflet/src/control/Signing.js index 58191aa4d..0264d2b0c 100644 --- a/loleaflet/src/control/Signing.js +++ b/loleaflet/src/control/Signing.js @@ -34,6 +34,23 @@ L.Map.include({ showSignDocument: function() { this.signingLogin(); }, + signDocument: function() { + if (library) { + var map = this; + library.getCurrentlyLoggedInUUID().then(function(result) { + if (isSuccess(result)) { + var UUID = result.data; + library.getOneTimeCertificateByPassport(UUID).then(function(result) { + if (isSuccess(result)) { + var otp = result.data; + var blob = new Blob(['signdocument\n', JSON.stringify(otp)]); + map._socket.sendMessage(blob); + } + }); + } + }); + } + }, signingLogout: function() { if (library) { library.logout().then(function(result) { |