Implement proper proof-key value attribute

Change-Id: I3f2ad960ce6d3dad4d0b064492355b5643f345c8
Reviewed-on: https://gerrit.libreoffice.org/c/online/+/87148
Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoffice@gmail.com>
Reviewed-by: Mike Kaganski <mike.kaganski@collabora.com>
Reviewed-by: Michael Meeks <michael.meeks@collabora.com>
This commit is contained in:
Mike Kaganski 2020-01-21 18:35:01 +03:00
parent b06ec9c71b
commit 0c0510cccf

View file

@ -12,10 +12,12 @@
#include "ProofKey.hpp"
#include "LOOLWSD.hpp"
#include <algorithm>
#include <cassert>
#include <chrono>
#include <cstdlib>
#include <memory>
#include <vector>
#include <Poco/Base64Decoder.h>
#include <Poco/Base64Encoder.h>
@ -40,6 +42,58 @@
namespace{
std::vector<unsigned char> getBytesLE(const unsigned char* bytesInSystemOrder, const size_t n)
{
std::vector<unsigned char> ret(n);
#if !defined __BYTE_ORDER__
static_assert(false, "Byte order is not detected on this platform!");
#elif __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
std::copy_n(bytesInSystemOrder, n, ret.begin());
#else
std::copy_n(bytesInSystemOrder, n, ret.rbegin());
#endif
return ret;
}
// Returns a number as vector of bytes (little-endian)
template <typename T>
std::vector<unsigned char> getBytesLE(const T& x)
{
return getBytesLE(reinterpret_cast<const unsigned char*>(&x), sizeof(x));
}
// https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-mqqb/ade9efde-3ec8-4e47-9ae9-34b64d8081bb
std::vector<unsigned char> RSA2CapiBlob(const std::vector<unsigned char>& modulus,
const std::vector<unsigned char>& exponent)
{
std::vector<unsigned char> capiBlob = {
0x06, 0x02, 0x00, 0x00,
0x00, 0xA4, 0x00, 0x00,
0x52, 0x53, 0x41, 0x31,
};
// modulus size in bits - 4 bytes (little-endian)
const auto bitLen = getBytesLE<std::uint32_t>(modulus.size() * 8);
capiBlob.reserve(capiBlob.size() + bitLen.size() + exponent.size() + modulus.size());
std::copy(bitLen.begin(), bitLen.end(), std::back_inserter(capiBlob));
// exponent - 4 bytes (little-endian)
std::copy(exponent.rbegin(), exponent.rend(), std::back_inserter(capiBlob));
// modulus (little-endian)
std::copy(modulus.rbegin(), modulus.rend(), std::back_inserter(capiBlob));
return capiBlob;
}
std::string BytesToBase64(const std::vector<unsigned char>& bytes)
{
std::ostringstream oss;
// The signature generated contains CRLF line endings.
// Use a line ending converter to remove these CRLF
Poco::OutputLineEndingConverter lineEndingConv(oss, "");
Poco::Base64Encoder encoder(lineEndingConv);
encoder << std::string(bytes.begin(), bytes.end());
encoder.close();
return oss.str();
}
class Proof {
public:
Proof();
@ -84,46 +138,13 @@ Proof::Proof()
{
if (m_pKey)
{
{
// TODO: This is definitely not correct at the moment. The proof key must be
// base64-encoded blob in "unmanaged Microsoft Cryptographic API (CAPI)" format
// (as .Net's RSACryptoServiceProvider::ExportCspBlob returns).
std::ostringstream oss;
Poco::OutputLineEndingConverter lineEndingConv(oss, "");
m_pKey->save(&lineEndingConv);
std::string sKey = oss.str();
const std::string sBegin = "-----BEGIN RSA PUBLIC KEY-----";
const std::string sEnd = "-----END RSA PUBLIC KEY-----";
auto pos = sKey.find(sBegin);
if (pos != std::string::npos)
sKey = sKey.substr(pos + sBegin.length());
pos = sKey.find(sEnd);
if (pos != std::string::npos)
sKey = sKey.substr(0, pos);
m_aAttribs.emplace_back("value", sKey);
}
{
std::ostringstream oss;
// The signature generated contains CRLF line endings.
// Use a line ending converter to remove these CRLF
Poco::OutputLineEndingConverter lineEndingConv(oss, "");
Poco::Base64Encoder encoder(lineEndingConv);
const auto m = m_pKey->modulus();
encoder << std::string(m.begin(), m.end());
encoder.close();
m_aAttribs.emplace_back("modulus", oss.str());
}
{
std::ostringstream oss;
// The signature generated contains CRLF line endings.
// Use a line ending converter to remove these CRLF
Poco::OutputLineEndingConverter lineEndingConv(oss, "");
Poco::Base64Encoder encoder(lineEndingConv);
const auto e = m_pKey->encryptionExponent();
encoder << std::string(e.begin(), e.end());
encoder.close();
m_aAttribs.emplace_back("exponent", oss.str());
}
const auto capiBlob = RSA2CapiBlob(m, e);
m_aAttribs.emplace_back("value", BytesToBase64(capiBlob));
m_aAttribs.emplace_back("modulus", BytesToBase64(m));
m_aAttribs.emplace_back("exponent", BytesToBase64(e));
}
}