Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 11 additions & 45 deletions src/SiVaContainer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@
#include "DataFile_p.h"
#include "XMLDocument.h"
#include "crypto/Connect.h"
#include "crypto/TS.h"
#include "util/DateTime.h"
#include "util/File.h"

#include "json.hpp"
Expand All @@ -41,47 +43,6 @@ using namespace digidoc::util;
using namespace std;
using json = nlohmann::json;

template <class T>
constexpr T base64_enc_size(T n) noexcept
{
return ((n + 2) / 3) << 2;
}

static auto base64_decode(string_view data) {
static constexpr array<uint8_t, 128> T{
0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64,
0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64,
0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x3E, 0x64, 0x64, 0x64, 0x3F,
0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64,
0x64, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E,
0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x64, 0x64, 0x64, 0x64, 0x64,
0x64, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,
0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30, 0x31, 0x32, 0x33, 0x64, 0x64, 0x64, 0x64, 0x64
};

string buf;
buf.reserve(base64_enc_size(data.size()));
auto out = make_unique<stringstream>(std::move(buf));
int value = 0;
int bits = -8;
for(auto c: data)
{
if(c == '\r' || c == '\n' || c == ' ' || static_cast<uint8_t>(c) > 128)
continue;
uint8_t check = T[c];
if(check == 0x64)
break;
value = (value << 6) + check;
if(bits += 6; bits < 0)
continue;
out->put(char((value >> bits) & 0xFF));
bits -= 8;
}
return out;
}



class SiVaContainer::Private
{
public:
Expand Down Expand Up @@ -197,7 +158,7 @@ SiVaContainer::SiVaContainer(const string &path, ContainerOpenCB *cb, bool useHa
break;

size_t pos = b64.size();
b64.resize(b64.size() + base64_enc_size(buf.size()));
b64.resize(b64.size() + ((buf.size() + 2) / 3) * 4);
int size = EVP_EncodeBlock((unsigned char*)&b64[pos], buf.data(), int(is->gcount()));
b64.resize(pos + size);
}
Expand Down Expand Up @@ -255,6 +216,11 @@ SiVaContainer::SiVaContainer(const string &path, ContainerOpenCB *cb, bool useHa
s->_postalCode = signatureProductionPlace.value<string>("postalCode", {});
s->_country = signatureProductionPlace.value<string>("countryName", {});
}
for(const json &tsa: info.value<json>("archiveTimeStamps", {}))
{
TS ts(from_base64(tsa.value<string_view>("content", {})));
s->_archiveTimeStamps.push_back({ts.cert(), util::date::to_string(ts.time())});
}
}
for(const json &certificate: signature.value<json>("certificates", {}))
{
Expand All @@ -265,8 +231,8 @@ SiVaContainer::SiVaContainer(const string &path, ContainerOpenCB *cb, bool useHa
s->_ocspCertificate = X509Cert(der, X509Cert::Der);
if(certificate["type"] == "SIGNATURE_TIMESTAMP")
s->_tsCertificate = X509Cert(der, X509Cert::Der);
if(certificate["type"] == "ARCHIVE_TIMESTAMP")
s->_tsaCertificate = X509Cert(der, X509Cert::Der);
if(certificate["type"] == "ARCHIVE_TIMESTAMP" && s->_archiveTimeStamps.empty())
s->_archiveTimeStamps.push_back({X509Cert(der, X509Cert::Der), {}});
}
for(const json &error: signature.value<json>("errors", {}))
{
Expand Down Expand Up @@ -353,7 +319,7 @@ unique_ptr<istream> SiVaContainer::parseDDoc(const unique_ptr<istream> &ddoc, bo
THROW("Currently supports only content types EMBEDDED_BASE64 for DDOC format");
if(contentType != "EMBEDDED_BASE64")
continue;
d->dataFiles.push_back(new DataFilePrivate(base64_decode(dataFile),
d->dataFiles.push_back(new DataFilePrivate(make_unique<stringstream>(from_base64<string>(dataFile)),
string(dataFile["Filename"]),
string(dataFile["MimeType"]),
string(dataFile["Id"])));
Expand Down
5 changes: 3 additions & 2 deletions src/SiVaContainer.h
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ class SignatureSiVa final: public Signature
std::string TimeStampTime() const final { return _tsTime; }

//TSA profile properties
X509Cert ArchiveTimeStampCertificate() const final { return _tsaCertificate; }
std::vector<TSAInfo> ArchiveTimeStamps() const final { return _archiveTimeStamps; }

// Other
std::vector<unsigned char> messageImprint() const final { return _messageImprint; }
Expand All @@ -68,7 +68,8 @@ class SignatureSiVa final: public Signature
SignatureSiVa() = default;
DISABLE_COPY(SignatureSiVa);

X509Cert _signingCertificate, _ocspCertificate, _tsCertificate, _tsaCertificate;
X509Cert _signingCertificate, _ocspCertificate, _tsCertificate;
std::vector<TSAInfo> _archiveTimeStamps;
std::string _id, _profile, _signedBy, _signatureMethod, _signingTime, _indication, _subIndication, _signatureLevel;
std::string _bestTime, _tsTime, _ocspTime;
std::string _city, _stateOrProvince, _postalCode, _country;
Expand Down
59 changes: 32 additions & 27 deletions src/XMLDocument.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,40 +32,45 @@
#include <xmlsec/crypto.h>
#include <xmlsec/parser.h>

#include <openssl/evp.h>

#include <array>
#include <istream>

namespace digidoc {

#define VERSION_CHECK(major, minor, patch) (((major)<<16)|((minor)<<8)|(patch))

static std::vector<unsigned char> from_base64(std::string_view data)
template<class R = std::vector<unsigned char>>
static constexpr R from_base64(std::string_view data)
{
static constexpr std::string_view whitespace {" \n\r\f\t\v"};
std::vector<unsigned char> result(EVP_DECODE_LENGTH(data.size()), 0);
size_t dataPos = 0;
int size = 0;
auto ctx = make_unique_ptr<EVP_ENCODE_CTX_free>(EVP_ENCODE_CTX_new());
EVP_DecodeInit(ctx.get());

for(auto pos = data.find_first_of(whitespace);
!data.empty();
pos = data.find_first_of(whitespace), dataPos += size_t(size))
{
auto sub = data.substr(0, pos);
if(pos == std::string_view::npos)
data = {};
else
data.remove_prefix(pos + 1);
if(EVP_DecodeUpdate(ctx.get(), &result[dataPos], &size, (const unsigned char*)sub.data(), int(sub.size())) == -1)
THROW("Invalid Base64 Binary");
}

if(EVP_DecodeFinal(ctx.get(), &result[dataPos], &size) == 1)
result.resize(dataPos + size_t(size));
else
result.clear();
constexpr auto T = std::to_array<uint8_t>({
0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64,
0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64,
0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x3E, 0x64, 0x64, 0x64, 0x3F,
0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64,
0x64, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E,
0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x64, 0x64, 0x64, 0x64, 0x64,
0x64, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,
0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30, 0x31, 0x32, 0x33, 0x64, 0x64, 0x64, 0x64, 0x64
});
R result(data.size() * 3 / 4 + 2, 0);
auto it = result.begin();
uint32_t value = 0;
int bits = -8;
for(auto c: data)
{
constexpr std::string_view whitespace{" \t\n\r\f\v"};
if(static_cast<uint8_t>(c) > 127 || whitespace.contains(c))
continue;
uint8_t check = T[static_cast<uint8_t>(c)];
if(check == 0x64)
break;
value = (value << 6) + check;
if(bits += 6; bits < 0)
continue;
*it++ = typename R::value_type((value >> bits) & 0xFF);
bits -= 8;
}
result.erase(it, result.end());
return result;
}

Expand Down
Loading