Skip to content

Commit e5b2014

Browse files
committed
Extend XAdES LTA signatures
IB-7994, IB-7995 Signed-off-by: Raul Metsma <[email protected]>
1 parent 82729b4 commit e5b2014

File tree

12 files changed

+237
-119
lines changed

12 files changed

+237
-119
lines changed

examples/DigiDocCSharp/Program.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,11 @@ private static void Verify(string file)
208208
Console.WriteLine("Time: " + s.trustedSigningTime());
209209
Console.WriteLine("Cert: " + s.signingCertificate().Subject);
210210
Console.WriteLine("TimeStamp: " + s.TimeStampCertificate().Subject);
211+
foreach (TSAInfo tsaInfo in s.ArchiveTimeStamps())
212+
{
213+
Console.WriteLine("Archive Time: " + tsaInfo.time);
214+
Console.WriteLine("Archive Cert: " + tsaInfo.cert.Subject);
215+
}
211216

212217
s.validate();
213218
Console.WriteLine("Signature is valid");

examples/java/src/main/java/ee/ria/libdigidocpp/libdigidocpp.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,10 @@ static void verify(String file) {
151151
System.out.println("Time: " + signature.trustedSigningTime());
152152
System.out.println("Cert: " + signature.signingCertificate().getSubjectDN().toString());
153153
System.out.println("TimeStamp Cert: " + signature.TimeStampCertificate().getSubjectDN().toString());
154+
for(TSAInfo tsaInfo : signature.ArchiveTimeStamps()) {
155+
System.out.println("Archive Time: " + tsaInfo.getTime());
156+
System.out.println("Archive Cert: " + tsaInfo.getCert().getSubjectDN().toString());
157+
}
154158

155159
try
156160
{

libdigidocpp.i

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -101,15 +101,17 @@ static std::vector<unsigned char>* SWIG_JavaArrayToVectorUnsignedChar(JNIEnv *je
101101
%{ $1 = SWIG_JavaArrayToVectorUnsignedChar(jenv, $input); %}
102102
%typemap(out, fragment="SWIG_VectorUnsignedCharToJavaArray") std::vector<unsigned char>, digidoc::X509Cert
103103
%{ $result = SWIG_VectorUnsignedCharToJavaArray(jenv, $1); %}
104-
%typemap(jtype) std::vector<unsigned char>, digidoc::X509Cert "byte[]"
104+
%typemap(out, fragment="SWIG_VectorUnsignedCharToJavaArray") digidoc::X509Cert *
105+
%{ $result = SWIG_VectorUnsignedCharToJavaArray(jenv, *$1); %}
106+
%typemap(jtype) std::vector<unsigned char>, digidoc::X509Cert, digidoc::X509Cert * "byte[]"
105107
%typemap(jstype) std::vector<unsigned char> "byte[]"
106-
%typemap(jstype) digidoc::X509Cert "java.security.cert.X509Certificate"
107-
%typemap(jni) std::vector<unsigned char>, digidoc::X509Cert "jbyteArray"
108+
%typemap(jstype) digidoc::X509Cert, digidoc::X509Cert* "java.security.cert.X509Certificate"
109+
%typemap(jni) std::vector<unsigned char>, digidoc::X509Cert, digidoc::X509Cert * "jbyteArray"
108110
%typemap(javain) std::vector<unsigned char>, digidoc::X509Cert "$javainput"
109111
%typemap(javaout) std::vector<unsigned char> {
110112
return $jnicall;
111113
}
112-
%typemap(javaout, throws="java.security.cert.CertificateException, java.io.IOException") digidoc::X509Cert {
114+
%typemap(javaout, throws="java.security.cert.CertificateException, java.io.IOException") digidoc::X509Cert, digidoc::X509Cert * {
113115
byte[] der = $jnicall;
114116
java.security.cert.CertificateFactory cf = java.security.cert.CertificateFactory.getInstance("X509");
115117
try (java.io.ByteArrayInputStream is = new java.io.ByteArrayInputStream(der)) {
@@ -119,7 +121,7 @@ static std::vector<unsigned char>* SWIG_JavaArrayToVectorUnsignedChar(JNIEnv *je
119121

120122
#elif defined(SWIGCSHARP)
121123
%typemap(cstype) std::vector<unsigned char> "byte[]"
122-
%typemap(cstype) digidoc::X509Cert "System.Security.Cryptography.X509Certificates.X509Certificate2"
124+
%typemap(cstype) digidoc::X509Cert, digidoc::X509Cert* "System.Security.Cryptography.X509Certificates.X509Certificate2"
123125
%typemap(csin, pre= " global::System.IntPtr cPtr$csinput = digidocPINVOKE.ByteVector_to($csinput, $csinput.Length);
124126
var handleRef$csinput = new global::System.Runtime.InteropServices.HandleRef(this, cPtr$csinput);"
125127
) std::vector<unsigned char> "handleRef$csinput"
@@ -137,6 +139,14 @@ static std::vector<unsigned char>* SWIG_JavaArrayToVectorUnsignedChar(JNIEnv *je
137139
$modulePINVOKE.ByteVector_free(cPtr);
138140
return new System.Security.Cryptography.X509Certificates.X509Certificate2(der);
139141
}
142+
%typemap(csvarout, excode=SWIGEXCODE2) digidoc::X509Cert * %{
143+
get {
144+
global::System.IntPtr cPtr = $imcall;$excode
145+
byte[] der = new byte[$modulePINVOKE.ByteVector_size(cPtr)];
146+
global::System.Runtime.InteropServices.Marshal.Copy($modulePINVOKE.ByteVector_data(cPtr), der, 0, der.Length);
147+
$modulePINVOKE.ByteVector_free(cPtr);
148+
return new System.Security.Cryptography.X509Certificates.X509Certificate2(der);
149+
} %}
140150
%typemap(out) std::vector<unsigned char> %{ $result = new std::vector<unsigned char>(std::move($1)); %}
141151
%typemap(out) digidoc::X509Cert %{ $result = new std::vector<unsigned char>($1); %}
142152

@@ -159,6 +169,10 @@ static std::vector<unsigned char>* SWIG_JavaArrayToVectorUnsignedChar(JNIEnv *je
159169
std::vector<unsigned char> temp = $1;
160170
$result = PyBytes_FromStringAndSize((const char*)temp.data(), temp.size());
161171
}
172+
%typemap(out) digidoc::X509Cert * {
173+
std::vector<unsigned char> temp = *$1;
174+
$result = PyBytes_FromStringAndSize((const char*)temp.data(), temp.size());
175+
}
162176
#endif
163177
%typemap(freearg) std::vector<unsigned char>
164178
%{ delete $1; %}
@@ -210,6 +224,9 @@ static std::vector<unsigned char>* SWIG_JavaArrayToVectorUnsignedChar(JNIEnv *je
210224
%newobject digidoc::Container::open;
211225
%newobject digidoc::Container::create;
212226

227+
%immutable digidoc::TSAInfo::cert;
228+
%immutable digidoc::TSAInfo::time;
229+
213230
%feature("director") digidoc::ContainerOpenCB;
214231

215232
%typemap(javacode) digidoc::Conf %{
@@ -267,6 +284,7 @@ def transfer(self):
267284
%template(StringMap) std::map<std::string,std::string>;
268285
%template(DataFiles) std::vector<digidoc::DataFile*>;
269286
%template(Signatures) std::vector<digidoc::Signature*>;
287+
%template(TSAInfos) std::vector<digidoc::TSAInfo>;
270288

271289
%extend digidoc::Container {
272290
static digidoc::Container* open(const std::string &path, digidoc::ContainerOpenCB *cb)

src/Signature.cpp

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -207,12 +207,27 @@ string Signature::TimeStampTime() const { return {}; }
207207
/**
208208
* Returns signature Archive TimeStampToken certificate.
209209
*/
210-
X509Cert Signature::ArchiveTimeStampCertificate() const { return X509Cert(); }
210+
X509Cert Signature::ArchiveTimeStampCertificate() const
211+
{
212+
if(auto list = ArchiveTimeStamps(); !list.empty())
213+
return list.back().cert;
214+
return X509Cert();
215+
}
211216

212217
/**
213218
* Returns signature Archive TimeStampToken time.
214219
*/
215-
string Signature::ArchiveTimeStampTime() const { return {}; }
220+
string Signature::ArchiveTimeStampTime() const
221+
{
222+
if(auto list = ArchiveTimeStamps(); !list.empty())
223+
return list.back().time;
224+
return {};
225+
}
226+
227+
/**
228+
* Returns signature Archive TimeStampTokens.
229+
*/
230+
vector<TSAInfo> Signature::ArchiveTimeStamps() const { return {}; }
216231

217232
struct Signature::Validator::Private
218233
{

src/Signature.h

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -21,12 +21,17 @@
2121

2222
#include "Exception.h"
2323

24-
#include <string>
25-
#include <vector>
24+
#include "crypto/X509Cert.h"
2625

2726
namespace digidoc
2827
{
2928
class X509Cert;
29+
30+
struct TSAInfo {
31+
X509Cert cert;
32+
std::string time;
33+
};
34+
3035
class DIGIDOCPP_EXPORT Signature
3136
{
3237
public:
@@ -85,18 +90,18 @@ namespace digidoc
8590
virtual std::string countryName() const;
8691
virtual std::vector<std::string> signerRoles() const;
8792

88-
//TM profile properties
93+
// TM profile properties
8994
virtual std::string OCSPProducedAt() const;
9095
virtual X509Cert OCSPCertificate() const;
9196
DIGIDOCPP_DEPRECATED virtual std::vector<unsigned char> OCSPNonce() const;
9297

93-
//TS profile properties
98+
// TS profile properties
9499
virtual X509Cert TimeStampCertificate() const;
95100
virtual std::string TimeStampTime() const;
96101

97-
//TSA profile properties
98-
virtual X509Cert ArchiveTimeStampCertificate() const;
99-
virtual std::string ArchiveTimeStampTime() const;
102+
// TSA profile properties
103+
DIGIDOCPP_DEPRECATED virtual X509Cert ArchiveTimeStampCertificate() const;
104+
DIGIDOCPP_DEPRECATED virtual std::string ArchiveTimeStampTime() const;
100105

101106
// Xades properties
102107
virtual std::string streetAddress() const;
@@ -110,6 +115,9 @@ namespace digidoc
110115
// Other
111116
virtual std::vector<unsigned char> messageImprint() const;
112117

118+
//TSA profile properties
119+
virtual std::vector<TSAInfo> ArchiveTimeStamps() const;
120+
113121
protected:
114122
Signature();
115123

src/SignatureXAdES_B.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -343,6 +343,9 @@ SignatureXAdES_B::SignatureXAdES_B(const shared_ptr<Signatures> &signatures, XML
343343
"AttrAuthoritiesCertValues", "AttributeRevocationValues", "ArchiveTimeStamp"})
344344
if(usp/elem)
345345
THROW("%s is not supported", elem);
346+
for(const char *elem: {"CompleteCertificateRefsV2", "AttributeCertificateRefsV2", "SigAndRefsTimeStampV2", "RefsOnlyTimeStampV2"})
347+
if(usp/XMLName{elem, XADESv141_NS})
348+
THROW("%s is not supported", elem);
346349
for(const char *elem: {"CompleteCertificateRefs", "CompleteRevocationRefs", "SigAndRefsTimeStamp", "TimeStampValidationData"})
347350
if(usp/elem)
348351
WARN("%s are not supported", elem);

src/SignatureXAdES_LTA.cpp

Lines changed: 28 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ namespace digidoc
3939
constexpr XMLName ArchiveTimeStamp {"ArchiveTimeStamp", XADESv141_NS};
4040
}
4141

42-
void SignatureXAdES_LTA::calcArchiveDigest(const Digest &digest, string_view canonicalizationMethod) const
42+
void SignatureXAdES_LTA::calcArchiveDigest(const Digest &digest, string_view canonicalizationMethod, XMLNode ts) const
4343
{
4444
for(auto ref = signature/"SignedInfo"/"Reference"; ref; ref++)
4545
{
@@ -64,7 +64,7 @@ void SignatureXAdES_LTA::calcArchiveDigest(const Digest &digest, string_view can
6464
if(file == files.cend())
6565
THROW("Filed to find reference URI in container");
6666

67-
static_cast<const DataFilePrivate*>(*file)->digest(digest);
67+
dynamic_cast<const DataFilePrivate*>(*file)->digest(digest);
6868
}
6969

7070
for(const auto *name: {"SignedInfo", "SignatureValue", "KeyInfo"})
@@ -75,65 +75,46 @@ void SignatureXAdES_LTA::calcArchiveDigest(const Digest &digest, string_view can
7575
DEBUG("Element %s not found", name);
7676
}
7777

78-
auto usp = unsignedSignatureProperties();
79-
for(const auto *name: {
80-
"SignatureTimeStamp",
81-
"CounterSignature",
82-
"CompleteCertificateRefs",
83-
"CompleteRevocationRefs",
84-
"AttributeCertificateRefs",
85-
"AttributeRevocationRefs",
86-
"CertificateValues",
87-
"RevocationValues",
88-
"SigAndRefsTimeStamp",
89-
"RefsOnlyTimeStamp" })
78+
for(auto elem: unsignedSignatureProperties())
9079
{
91-
if(auto elem = usp/name)
92-
signatures->c14n(digest, canonicalizationMethod, elem);
93-
else
94-
DEBUG("Element %s not found", name);
95-
}
96-
97-
if(auto elem = usp/XMLName{"TimeStampValidationData", XADESv141_NS})
80+
if(elem == ts)
81+
break;
9882
signatures->c14n(digest, canonicalizationMethod, elem);
99-
else
100-
DEBUG("Element TimeStampValidationData not found");
83+
}
10184
//ds:Object
10285
}
10386

10487
void SignatureXAdES_LTA::extendSignatureProfile(const string &profile)
10588
{
106-
SignatureXAdES_LT::extendSignatureProfile(profile);
89+
if(SignatureXAdES_LTA::profile().find(ASiC_E::ASIC_TS_PROFILE) == string::npos)
90+
SignatureXAdES_LT::extendSignatureProfile(profile);
10791
if(profile != ASiC_E::ASIC_TSA_PROFILE)
10892
return;
93+
94+
int i = 0;
95+
for(auto ts = unsignedSignatureProperties()/ArchiveTimeStamp; ts; ts++, ++i);
96+
10997
Digest calc;
11098
auto method = canonicalizationMethod();
111-
calcArchiveDigest(calc, method);
99+
calcArchiveDigest(calc, method, {});
112100

113101
TS tsa(CONF(TSUrl), calc);
114102
auto ts = unsignedSignatureProperties() + ArchiveTimeStamp;
115103
ts.setNS(ts.addNS(XADESv141_NS, "xades141"));
116-
ts.setProperty("Id", id() + "-A0");
104+
ts.setProperty("Id", id() + "-A" + to_string(i));
117105
(ts + CanonicalizationMethod).setProperty("Algorithm", method);
118106
ts + EncapsulatedTimeStamp = tsa;
119107
}
120108

121-
TS SignatureXAdES_LTA::tsaFromBase64() const
122-
{
123-
try {
124-
return {unsignedSignatureProperties()/ArchiveTimeStamp/EncapsulatedTimeStamp};
125-
} catch(const Exception &) {}
126-
return {};
127-
}
128-
129-
X509Cert SignatureXAdES_LTA::ArchiveTimeStampCertificate() const
130-
{
131-
return tsaFromBase64().cert();
132-
}
133-
134-
string SignatureXAdES_LTA::ArchiveTimeStampTime() const
109+
vector<TSAInfo> SignatureXAdES_LTA::ArchiveTimeStamps() const
135110
{
136-
return date::to_string(tsaFromBase64().time());
111+
vector<TSAInfo> result;
112+
for(auto ts = unsignedSignatureProperties()/ArchiveTimeStamp; ts; ts++)
113+
{
114+
TS t(ts/EncapsulatedTimeStamp);
115+
result.push_back({t.cert(), util::date::to_string(t.time())});
116+
}
117+
return result;
137118
}
138119

139120
void SignatureXAdES_LTA::validate(const string &policy) const
@@ -157,9 +138,12 @@ void SignatureXAdES_LTA::validate(const string &policy) const
157138
auto ts = unsignedSignatureProperties()/ArchiveTimeStamp;
158139
if(!ts)
159140
THROW("Missing ArchiveTimeStamp element");
160-
verifyTS(ts, exception, [this](const Digest &digest, string_view canonicalizationMethod) {
161-
calcArchiveDigest(digest, canonicalizationMethod);
162-
});
141+
for(; ts; ts++)
142+
{
143+
verifyTS(ts, exception, [this, ts](const Digest &digest, string_view canonicalizationMethod) {
144+
calcArchiveDigest(digest, canonicalizationMethod, ts);
145+
});
146+
}
163147
} catch(const Exception &e) {
164148
exception.addCause(e);
165149
}

src/SignatureXAdES_LTA.h

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,16 +29,14 @@ class SignatureXAdES_LTA final: public SignatureXAdES_LT
2929
public:
3030
using SignatureXAdES_LT::SignatureXAdES_LT;
3131

32-
X509Cert ArchiveTimeStampCertificate() const final;
33-
std::string ArchiveTimeStampTime() const final;
32+
std::vector<TSAInfo> ArchiveTimeStamps() const final;
3433
void validate(const std::string &policy) const final;
3534
void extendSignatureProfile(const std::string &profile) final;
3635

3736
private:
3837
DISABLE_COPY(SignatureXAdES_LTA);
3938

40-
void calcArchiveDigest(const Digest &digest, std::string_view canonicalizationMethod) const;
41-
TS tsaFromBase64() const;
39+
void calcArchiveDigest(const Digest &digest, std::string_view canonicalizationMethod, XMLNode node) const;
4240
};
4341

4442
}

src/XMLDocument.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,11 @@ struct XMLElem
159159
return bool(d);
160160
}
161161

162+
constexpr bool operator==(XMLElem other) const noexcept
163+
{
164+
return d == other.d;
165+
}
166+
162167
constexpr auto& operator++() noexcept
163168
{
164169
d = d ? find(d->next, d->type) : nullptr;

src/digidoc-tool.1.cmake

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,13 @@ Command sign:
6868
--tsurl - option to change TS URL (default http://demo.sk.ee/tsa)
6969
--dontValidate - Don't validate container on signature creation
7070

71+
Command extend:
72+
Example: " << executable << " extend --signature=0 demo-container.asice
73+
Available options:
74+
--profile= - signature profile, TS, TSA, time-stamp, time-stamp-archive
75+
--signature= - signature to extend
76+
--dontValidate - Don't validate container on signature creation
77+
7178
All commands:
7279
--nocolor - Disable terminal colors
7380
--loglevel=[0,1,2,3,4] - Log level 0 - none, 1 - error, 2 - warning, 3 - info, 4 - debug

0 commit comments

Comments
 (0)