Skip to content
Merged
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
14 changes: 12 additions & 2 deletions src/Signature.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -223,12 +223,22 @@ string Signature::TimeStampTime() const { return {}; }
/**
* Returns signature Archive TimeStampToken certificate.
*/
X509Cert Signature::ArchiveTimeStampCertificate() const { return X509Cert(); }
X509Cert Signature::ArchiveTimeStampCertificate() const
{
if(auto list = ArchiveTimeStamps(); !list.empty())
return list.back().cert;
return X509Cert();
}

/**
* Returns signature Archive TimeStampToken time.
*/
string Signature::ArchiveTimeStampTime() const { return {}; }
string Signature::ArchiveTimeStampTime() const
{
if(auto list = ArchiveTimeStamps(); !list.empty())
return list.back().time;
return {};
}

/**
* Returns signature Archive TimeStampTokens.
Expand Down
14 changes: 0 additions & 14 deletions src/SignatureTST.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -111,20 +111,6 @@ SignatureTST::SignatureTST(ASiC_S *asicSDoc, Signer *signer)

SignatureTST::~SignatureTST() = default;

X509Cert SignatureTST::ArchiveTimeStampCertificate() const
{
if(auto list = ArchiveTimeStamps(); !list.empty())
return list.front().cert;
return X509Cert();
}

string SignatureTST::ArchiveTimeStampTime() const
{
if(auto list = ArchiveTimeStamps(); !list.empty())
return list.front().time;
return {};
}

vector<TSAInfo> SignatureTST::ArchiveTimeStamps() const
{
vector<TSAInfo> result;
Expand Down
2 changes: 0 additions & 2 deletions src/SignatureTST.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,6 @@ class SignatureTST final: public Signature
std::string profile() const final;

//TSA profile properties
X509Cert ArchiveTimeStampCertificate() const final;
std::string ArchiveTimeStampTime() const final;
std::vector<TSAInfo> ArchiveTimeStamps() const final;

void save(const ZipSerialize &s) const;
Expand Down
3 changes: 3 additions & 0 deletions src/SignatureXAdES_B.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -333,6 +333,9 @@ SignatureXAdES_B::SignatureXAdES_B(const shared_ptr<Signatures> &signatures, XML
"AttrAuthoritiesCertValues", "AttributeRevocationValues", "ArchiveTimeStamp"})
if(usp/elem)
THROW("%s is not supported", elem);
for(const char *elem: {"CompleteCertificateRefsV2", "AttributeCertificateRefsV2", "SigAndRefsTimeStampV2", "RefsOnlyTimeStampV2"})
if(usp/XMLName{elem, XADESv141_NS})
THROW("%s is not supported", elem);
for(const char *elem: {"CompleteCertificateRefs", "CompleteRevocationRefs", "SigAndRefsTimeStamp", "TimeStampValidationData"})
if(usp/elem)
WARN("%s are not supported", elem);
Expand Down
73 changes: 27 additions & 46 deletions src/SignatureXAdES_LTA.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ namespace digidoc
constexpr XMLName ArchiveTimeStamp {"ArchiveTimeStamp", XADESv141_NS};
}

void SignatureXAdES_LTA::calcArchiveDigest(const Digest &digest, string_view canonicalizationMethod) const
void SignatureXAdES_LTA::calcArchiveDigest(const Digest &digest, string_view canonicalizationMethod, XMLNode ts) const
{
for(auto ref = signature/"SignedInfo"/"Reference"; ref; ref++)
{
Expand Down Expand Up @@ -75,65 +75,46 @@ void SignatureXAdES_LTA::calcArchiveDigest(const Digest &digest, string_view can
DEBUG("Element %s not found", name);
}

auto usp = unsignedSignatureProperties();
for(const auto *name: {
"SignatureTimeStamp",
"CounterSignature",
"CompleteCertificateRefs",
"CompleteRevocationRefs",
"AttributeCertificateRefs",
"AttributeRevocationRefs",
"CertificateValues",
"RevocationValues",
"SigAndRefsTimeStamp",
"RefsOnlyTimeStamp" })
for(auto elem: unsignedSignatureProperties())
{
if(auto elem = usp/name)
signatures->c14n(digest, canonicalizationMethod, elem);
else
DEBUG("Element %s not found", name);
}

if(auto elem = usp/XMLName{"TimeStampValidationData", XADESv141_NS})
if(elem == ts)
break;
signatures->c14n(digest, canonicalizationMethod, elem);
else
DEBUG("Element TimeStampValidationData not found");
}
//ds:Object
}

void SignatureXAdES_LTA::extendSignatureProfile(Signer *signer)
{
SignatureXAdES_LT::extendSignatureProfile(signer);
if(SignatureXAdES_LTA::profile().find(ASiC_E::ASIC_TS_PROFILE) == string::npos)
SignatureXAdES_LT::extendSignatureProfile(signer);
if(signer->profile() != ASiC_E::ASIC_TSA_PROFILE)
return;

int i = 0;
for(auto ts = unsignedSignatureProperties()/ArchiveTimeStamp; ts; ts++, ++i);

Digest calc;
auto method = canonicalizationMethod();
calcArchiveDigest(calc, method);
calcArchiveDigest(calc, method, {});

TS tsa(calc, signer->userAgent());
auto ts = unsignedSignatureProperties() + ArchiveTimeStamp;
ts.setNS(ts.addNS(XADESv141_NS, "xades141"));
ts.setProperty("Id", id() + "-A0");
ts.setProperty("Id", id() + "-A" + to_string(i));
(ts + CanonicalizationMethod).setProperty("Algorithm", method);
ts + EncapsulatedTimeStamp = tsa;
}

TS SignatureXAdES_LTA::tsaFromBase64() const
{
try {
return {unsignedSignatureProperties()/ArchiveTimeStamp/EncapsulatedTimeStamp};
} catch(const Exception &) {}
return {};
}

X509Cert SignatureXAdES_LTA::ArchiveTimeStampCertificate() const
{
return tsaFromBase64().cert();
}

string SignatureXAdES_LTA::ArchiveTimeStampTime() const
vector<TSAInfo> SignatureXAdES_LTA::ArchiveTimeStamps() const
{
return date::to_string(tsaFromBase64().time());
vector<TSAInfo> result;
for(auto ts = unsignedSignatureProperties()/ArchiveTimeStamp; ts; ts++)
{
TS t(ts/EncapsulatedTimeStamp);
result.push_back({t.cert(), util::date::to_string(t.time())});
}
return result;
}

void SignatureXAdES_LTA::validate(const string &policy) const
Expand All @@ -154,12 +135,12 @@ void SignatureXAdES_LTA::validate(const string &policy) const
}

try {
auto ts = unsignedSignatureProperties()/ArchiveTimeStamp;
if(!ts)
THROW("Missing ArchiveTimeStamp element");
verifyTS(ts, exception, [this](const Digest &digest, string_view canonicalizationMethod) {
calcArchiveDigest(digest, canonicalizationMethod);
});
for(auto ts = unsignedSignatureProperties()/ArchiveTimeStamp; ts; ts++)
{
verifyTS(ts, exception, [this, ts](const Digest &digest, string_view canonicalizationMethod) {
calcArchiveDigest(digest, canonicalizationMethod, ts);
});
}
} catch(const Exception &e) {
exception.addCause(e);
} catch(...) {
Expand Down
6 changes: 2 additions & 4 deletions src/SignatureXAdES_LTA.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,16 +29,14 @@ class SignatureXAdES_LTA final: public SignatureXAdES_LT
public:
using SignatureXAdES_LT::SignatureXAdES_LT;

X509Cert ArchiveTimeStampCertificate() const final;
std::string ArchiveTimeStampTime() const final;
std::vector<TSAInfo> ArchiveTimeStamps() const final;
void validate(const std::string &policy) const final;
void extendSignatureProfile(Signer *signer) final;

private:
DISABLE_COPY(SignatureXAdES_LTA);

void calcArchiveDigest(const Digest &digest, std::string_view canonicalizationMethod) const;
TS tsaFromBase64() const;
void calcArchiveDigest(const Digest &digest, std::string_view canonicalizationMethod, XMLNode node) const;
};

}
5 changes: 5 additions & 0 deletions src/XMLDocument.h
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,11 @@ struct XMLElem
return bool(d);
}

constexpr bool operator==(XMLElem other) const noexcept
{
return d == other.d;
}

constexpr auto& operator++() noexcept
{
d = d ? find(d->next, d->type) : nullptr;
Expand Down
7 changes: 7 additions & 0 deletions src/digidoc-tool.1.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,13 @@ Command sign:
--dontValidate - Don't validate container on signature creation
--userAgent - Additional info info that is sent to TSA or OCSP service

Command extend:
Example: " << executable << " extend --signature=0 demo-container.asice
Available options:
--profile= - signature profile, TS, TSA, time-stamp, time-stamp-archive
--signature= - signature to extend
--dontValidate - Don't validate container on signature creation

All commands:
--nocolor - Disable terminal colors
--loglevel=[0,1,2,3,4] - Log level 0 - none, 1 - error, 2 - warning, 3 - info, 4 - debug
Expand Down
21 changes: 18 additions & 3 deletions src/digidoc-tool.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -401,6 +401,12 @@ static int printUsage(const char *executable)
<< " --tsurl - option to change TS URL (default " << CONF(TSUrl) << ")" << endl
<< " --dontValidate - Don't validate container on signature creation" << endl << endl
<< " --userAgent - Additional info info that is sent to TSA or OCSP service" << endl << endl
<< " Command extend:" << endl
<< " Example: " << executable << " extend --signature=0 demo-container.asice" << endl
<< " Available options:" << endl
<< " --profile= - signature profile, TS, TSA, time-stamp, time-stamp-archive" << endl
<< " --signature= - signature to extend" << endl
<< " --dontValidate - Don't validate container on signature creation" << endl << endl
<< " All commands:" << endl
<< " --nocolor - Disable terminal colors" << endl
<< " --loglevel=[0,1,2,3,4] - Log level 0 - none, 1 - error, 2 - warning, 3 - info, 4 - debug" << endl
Expand Down Expand Up @@ -711,7 +717,7 @@ static int open(int argc, char* argv[])
*/
static int extend(int argc, char *argv[])
{
vector<unsigned int> signatures;
vector<unsigned int> extendId;
bool dontValidate = false;
CertSigner signer(X509Cert{});
value path;
Expand All @@ -721,7 +727,7 @@ static int extend(int argc, char *argv[])
if(value v{arg, "--profile="})
signer.setProfile(v);
else if(value v{arg, "--signature="})
signatures.push_back(unsigned(atoi(v.data())));
extendId.push_back(unsigned(atoi(v.data())));
else if(arg == "--dontValidate")
dontValidate = true;
else
Expand All @@ -740,8 +746,17 @@ static int extend(int argc, char *argv[])
return EXIT_FAILURE;
}

for(unsigned int i : signatures)
auto signatures = doc->signatures();
if(signatures.empty())
{
cout << " Container does not contain signatures\n";
return EXIT_SUCCESS;
}

for(unsigned int i : extendId)
{
if(i >= signatures.size())
THROW("Incorrect signature id %u, there are only %zu signatures in container.", i, signatures.size());
cout << " Extending signature " << i << " to " << signer.profile() << endl;
Signature *s = doc->signatures().at(i);
s->extendSignatureProfile(&signer);
Expand Down
26 changes: 13 additions & 13 deletions src/util/File.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -346,22 +346,25 @@ string File::toUriPath(const string &path)
return dst.str();
}

constexpr bool fromHexChar(auto pos, auto end, auto &value)
{
return distance(pos, end) >= 2 && from_chars(&*pos, &*(pos + 2), value, 16).ec == std::errc{};
}

string File::fromUriPath(string_view path)
{
string ret;
ret.reserve(path.size());
char data[] = "00";
uint8_t value = 0;
for(auto i = path.begin(); i != path.end(); ++i)
{
if(*i == '%' && (distance(i, path.end()) > 2) && isxdigit(*(i+1)) && isxdigit(*(i+2)))
if(*i == '%' && fromHexChar(i + 1, path.end(), value))
{
data[0] = *(++i);
data[1] = *(++i);
ret += static_cast<char>(strtoul(data, nullptr, 16));
ret += static_cast<char>(value);
i += 2;
}
else {
else
ret += *i;
}
}
return ret;
}
Expand All @@ -370,11 +373,8 @@ vector<unsigned char> File::hexToBin(string_view in)
{
vector<unsigned char> out;
out.reserve(in.size() / 2);
uint8_t result{};
for(size_t pos{}; pos + 1 < in.size(); pos += 2)
{
if(auto i = next(in.data(), pos); from_chars(i, i + 2, result, 16).ec == std::errc{})
out.push_back(result);
}
uint8_t value = 0;
for(auto i = in.begin(); fromHexChar(i, in.end(), value); i += 2)
out.emplace_back(value);
return out;
}
17 changes: 15 additions & 2 deletions test/libdigidocpp_boost.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -350,8 +350,11 @@ BOOST_AUTO_TEST_CASE_TEMPLATE(signature, Doc, DocTypes)
// TSA signature
signer2.setProfile("time-stamp-archive");
BOOST_CHECK_NO_THROW(s3 = d->sign(&signer2));
//BOOST_CHECK_EQUAL(s3->TSCertificate(), signer2.cert());
//BOOST_CHECK_NO_THROW(s3->validate());
BOOST_CHECK_EQUAL(s3->signingCertificate(), signer2.cert());
BOOST_CHECK_NO_THROW(s3->validate());
// Extend TSA
BOOST_CHECK_NO_THROW(s3->extendSignatureProfile(&signer2));
BOOST_CHECK_NO_THROW(s3->validate());
BOOST_CHECK_NO_THROW(d->save(Doc::EXT + "-TSA.tmp"));
BOOST_CHECK_NO_THROW(d->removeSignature(1U));
BOOST_CHECK_EQUAL(d->signatures().size(), 1U);
Expand Down Expand Up @@ -500,6 +503,16 @@ BOOST_AUTO_TEST_CASE(FromUriPathPreservesTrailingPercentageSign)

BOOST_CHECK_EQUAL(expectedDecodedStr, result);
}

BOOST_AUTO_TEST_CASE(HexToBinConvertsHexEncodedStringToBinaryData)
{
const string asciiEncodedStr = "3031323334";
const vector<unsigned char> expectedDecodedData { '0', '1', '2', '3', '4' };

auto result = util::File::hexToBin(asciiEncodedStr);

BOOST_CHECK_EQUAL(expectedDecodedData, result);
}
BOOST_AUTO_TEST_SUITE_END()

BOOST_AUTO_TEST_SUITE(ASiCSTestSuite)
Expand Down