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:
parent
b06ec9c71b
commit
0c0510cccf
1 changed files with 61 additions and 40 deletions
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue