Skip to content

Commit c8b8683

Browse files
committed
Use archiveTimeStamps from SiVa
IB-8920 Signed-off-by: Raul Metsma <[email protected]>
1 parent 68ec5bf commit c8b8683

3 files changed

Lines changed: 46 additions & 74 deletions

File tree

src/SiVaContainer.cpp

Lines changed: 11 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@
2929
#include "DataFile_p.h"
3030
#include "XMLDocument.h"
3131
#include "crypto/Connect.h"
32+
#include "crypto/TS.h"
33+
#include "util/DateTime.h"
3234
#include "util/File.h"
3335

3436
#include "json.hpp"
@@ -41,47 +43,6 @@ using namespace digidoc::util;
4143
using namespace std;
4244
using json = nlohmann::json;
4345

44-
template <class T>
45-
constexpr T base64_enc_size(T n) noexcept
46-
{
47-
return ((n + 2) / 3) << 2;
48-
}
49-
50-
static auto base64_decode(string_view data) {
51-
static constexpr array<uint8_t, 128> T{
52-
0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64,
53-
0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64,
54-
0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x3E, 0x64, 0x64, 0x64, 0x3F,
55-
0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64,
56-
0x64, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E,
57-
0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x64, 0x64, 0x64, 0x64, 0x64,
58-
0x64, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,
59-
0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30, 0x31, 0x32, 0x33, 0x64, 0x64, 0x64, 0x64, 0x64
60-
};
61-
62-
string buf;
63-
buf.reserve(base64_enc_size(data.size()));
64-
auto out = make_unique<stringstream>(std::move(buf));
65-
int value = 0;
66-
int bits = -8;
67-
for(auto c: data)
68-
{
69-
if(c == '\r' || c == '\n' || c == ' ' || static_cast<uint8_t>(c) > 128)
70-
continue;
71-
uint8_t check = T[c];
72-
if(check == 0x64)
73-
break;
74-
value = (value << 6) + check;
75-
if(bits += 6; bits < 0)
76-
continue;
77-
out->put(char((value >> bits) & 0xFF));
78-
bits -= 8;
79-
}
80-
return out;
81-
}
82-
83-
84-
8546
class SiVaContainer::Private
8647
{
8748
public:
@@ -197,7 +158,7 @@ SiVaContainer::SiVaContainer(const string &path, ContainerOpenCB *cb, bool useHa
197158
break;
198159

199160
size_t pos = b64.size();
200-
b64.resize(b64.size() + base64_enc_size(buf.size()));
161+
b64.resize(b64.size() + ((buf.size() + 2) / 3) * 4);
201162
int size = EVP_EncodeBlock((unsigned char*)&b64[pos], buf.data(), int(is->gcount()));
202163
b64.resize(pos + size);
203164
}
@@ -255,6 +216,11 @@ SiVaContainer::SiVaContainer(const string &path, ContainerOpenCB *cb, bool useHa
255216
s->_postalCode = signatureProductionPlace.value<string>("postalCode", {});
256217
s->_country = signatureProductionPlace.value<string>("countryName", {});
257218
}
219+
for(const json &tsa: info.value<json>("archiveTimeStamps", {}))
220+
{
221+
TS ts(from_base64(tsa.value<string_view>("content", {})));
222+
s->_archiveTimeStamps.push_back({ts.cert(), util::date::to_string(ts.time())});
223+
}
258224
}
259225
for(const json &certificate: signature.value<json>("certificates", {}))
260226
{
@@ -265,8 +231,8 @@ SiVaContainer::SiVaContainer(const string &path, ContainerOpenCB *cb, bool useHa
265231
s->_ocspCertificate = X509Cert(der, X509Cert::Der);
266232
if(certificate["type"] == "SIGNATURE_TIMESTAMP")
267233
s->_tsCertificate = X509Cert(der, X509Cert::Der);
268-
if(certificate["type"] == "ARCHIVE_TIMESTAMP")
269-
s->_tsaCertificate = X509Cert(der, X509Cert::Der);
234+
if(certificate["type"] == "ARCHIVE_TIMESTAMP" && s->_archiveTimeStamps.empty())
235+
s->_archiveTimeStamps.push_back({X509Cert(der, X509Cert::Der), {}});
270236
}
271237
for(const json &error: signature.value<json>("errors", {}))
272238
{
@@ -353,7 +319,7 @@ unique_ptr<istream> SiVaContainer::parseDDoc(const unique_ptr<istream> &ddoc, bo
353319
THROW("Currently supports only content types EMBEDDED_BASE64 for DDOC format");
354320
if(contentType != "EMBEDDED_BASE64")
355321
continue;
356-
d->dataFiles.push_back(new DataFilePrivate(base64_decode(dataFile),
322+
d->dataFiles.push_back(new DataFilePrivate(make_unique<stringstream>(from_base64<string>(dataFile)),
357323
string(dataFile["Filename"]),
358324
string(dataFile["MimeType"]),
359325
string(dataFile["Id"])));

src/SiVaContainer.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ class SignatureSiVa final: public Signature
5959
std::string TimeStampTime() const final { return _tsTime; }
6060

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

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

71-
X509Cert _signingCertificate, _ocspCertificate, _tsCertificate, _tsaCertificate;
71+
X509Cert _signingCertificate, _ocspCertificate, _tsCertificate;
72+
std::vector<TSAInfo> _archiveTimeStamps;
7273
std::string _id, _profile, _signedBy, _signatureMethod, _signingTime, _indication, _subIndication, _signatureLevel;
7374
std::string _bestTime, _tsTime, _ocspTime;
7475
std::string _city, _stateOrProvince, _postalCode, _country;

src/XMLDocument.h

Lines changed: 32 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -32,40 +32,45 @@
3232
#include <xmlsec/crypto.h>
3333
#include <xmlsec/parser.h>
3434

35-
#include <openssl/evp.h>
36-
35+
#include <array>
3736
#include <istream>
3837

3938
namespace digidoc {
4039

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

43-
static std::vector<unsigned char> from_base64(std::string_view data)
42+
template<class R = std::vector<unsigned char>>
43+
static constexpr R from_base64(std::string_view data)
4444
{
45-
static constexpr std::string_view whitespace {" \n\r\f\t\v"};
46-
std::vector<unsigned char> result(EVP_DECODE_LENGTH(data.size()), 0);
47-
size_t dataPos = 0;
48-
int size = 0;
49-
auto ctx = make_unique_ptr<EVP_ENCODE_CTX_free>(EVP_ENCODE_CTX_new());
50-
EVP_DecodeInit(ctx.get());
51-
52-
for(auto pos = data.find_first_of(whitespace);
53-
!data.empty();
54-
pos = data.find_first_of(whitespace), dataPos += size_t(size))
55-
{
56-
auto sub = data.substr(0, pos);
57-
if(pos == std::string_view::npos)
58-
data = {};
59-
else
60-
data.remove_prefix(pos + 1);
61-
if(EVP_DecodeUpdate(ctx.get(), &result[dataPos], &size, (const unsigned char*)sub.data(), int(sub.size())) == -1)
62-
THROW("Invalid Base64 Binary");
63-
}
64-
65-
if(EVP_DecodeFinal(ctx.get(), &result[dataPos], &size) == 1)
66-
result.resize(dataPos + size_t(size));
67-
else
68-
result.clear();
45+
constexpr auto T = std::to_array<uint8_t>({
46+
0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64,
47+
0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64,
48+
0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x3E, 0x64, 0x64, 0x64, 0x3F,
49+
0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64,
50+
0x64, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E,
51+
0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x64, 0x64, 0x64, 0x64, 0x64,
52+
0x64, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,
53+
0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30, 0x31, 0x32, 0x33, 0x64, 0x64, 0x64, 0x64, 0x64
54+
});
55+
R result(data.size() * 3 / 4 + 2, 0);
56+
auto it = result.begin();
57+
uint32_t value = 0;
58+
int bits = -8;
59+
for(auto c: data)
60+
{
61+
constexpr std::string_view whitespace{" \t\n\r\f\v"};
62+
if(static_cast<uint8_t>(c) > 127 || whitespace.contains(c))
63+
continue;
64+
uint8_t check = T[static_cast<uint8_t>(c)];
65+
if(check == 0x64)
66+
break;
67+
value = (value << 6) + check;
68+
if(bits += 6; bits < 0)
69+
continue;
70+
*it++ = typename R::value_type((value >> bits) & 0xFF);
71+
bits -= 8;
72+
}
73+
result.erase(it, result.end());
6974
return result;
7075
}
7176

0 commit comments

Comments
 (0)