diff --git a/examples/DigiDocCSharp/DigiDocCSharp.csproj b/examples/DigiDocCSharp/DigiDocCSharp.csproj
index 8fb78a012..e92bcdf38 100644
--- a/examples/DigiDocCSharp/DigiDocCSharp.csproj
+++ b/examples/DigiDocCSharp/DigiDocCSharp.csproj
@@ -3,8 +3,8 @@
net472
Exe
true
- 0.4.0.0
- 0.4.0.0
+ 0.5.0.0
+ 0.5.0.0
Copyright © 2015
diff --git a/examples/DigiDocCSharp/Program.cs b/examples/DigiDocCSharp/Program.cs
index ed3accb6b..4da521af5 100644
--- a/examples/DigiDocCSharp/Program.cs
+++ b/examples/DigiDocCSharp/Program.cs
@@ -154,8 +154,7 @@ private static void Websign(string[] args)
b.addDataFile(args[i], "application/octet-stream");
}
- X509Certificate cert = new X509Certificate();
- cert.Import(args[args.Length - 2]);
+ var cert = new X509Certificate(args[args.Length - 2]);
Signature c = b.prepareWebSignature(cert.Export(X509ContentType.Cert), "time-stamp");
Console.WriteLine("Signature method: " + c.signatureMethod());
Console.WriteLine("Digest to sign: " + BitConverter.ToString(c.dataToSign()).Replace("-", string.Empty));
@@ -207,7 +206,13 @@ private static void Verify(string file)
Console.WriteLine();
Console.WriteLine("Time: " + s.trustedSigningTime());
- Console.WriteLine("Cert: " + new X509Certificate2(s.signingCertificateDer()).Subject);
+ Console.WriteLine("Cert: " + s.signingCertificate().Subject);
+ Console.WriteLine("TimeStamp: " + s.TimeStampCertificate().Subject);
+ foreach (TSAInfo tsaInfo in s.ArchiveTimeStamps())
+ {
+ Console.WriteLine("Archive Time: " + tsaInfo.time);
+ Console.WriteLine("Archive Cert: " + tsaInfo.cert.Subject);
+ }
s.validate();
Console.WriteLine("Signature is valid");
diff --git a/examples/java/src/main/java/ee/ria/libdigidocpp/libdigidocpp.java b/examples/java/src/main/java/ee/ria/libdigidocpp/libdigidocpp.java
index bbe59f2bc..b78820468 100644
--- a/examples/java/src/main/java/ee/ria/libdigidocpp/libdigidocpp.java
+++ b/examples/java/src/main/java/ee/ria/libdigidocpp/libdigidocpp.java
@@ -149,7 +149,12 @@ static void verify(String file) {
System.out.println();
System.out.println("Time: " + signature.trustedSigningTime());
- System.out.println("Cert: " + toX509(signature.signingCertificateDer()).getSubjectDN().toString());
+ System.out.println("Cert: " + signature.signingCertificate().getSubjectDN().toString());
+ System.out.println("TimeStamp Cert: " + signature.TimeStampCertificate().getSubjectDN().toString());
+ for(TSAInfo tsaInfo : signature.ArchiveTimeStamps()) {
+ System.out.println("Archive Time: " + tsaInfo.getTime());
+ System.out.println("Archive Cert: " + tsaInfo.getCert().getSubjectDN().toString());
+ }
try
{
@@ -171,7 +176,7 @@ static void verify(String file) {
}
static void version() {
- System.out.println("DigiDocJAVA 0.3 libdigidocpp " + digidoc.version());
+ System.out.println("DigiDocJAVA 0.4 libdigidocpp " + digidoc.version());
}
static X509Certificate toX509(byte[] der) throws CertificateException {
diff --git a/libdigidocpp.i b/libdigidocpp.i
index f64ba3ee0..d609ed911 100644
--- a/libdigidocpp.i
+++ b/libdigidocpp.i
@@ -60,6 +60,9 @@ extern "C"
SWIGEXPORT int SWIGSTDCALL ByteVector_size(void *ptr) {
return static_cast*>(ptr)->size();
}
+ SWIGEXPORT void SWIGSTDCALL ByteVector_free(void *ptr) {
+ delete static_cast*>(ptr);
+ }
SWIGEXPORT void* SWIGSTDCALL ByteVector_to(unsigned char *data, int size) {
return new std::vector(data, data + size);
}
@@ -72,61 +75,11 @@ extern "C"
public static extern global::System.IntPtr ByteVector_data(global::System.IntPtr data);
[global::System.Runtime.InteropServices.DllImport("$dllimport", EntryPoint="ByteVector_size")]
public static extern int ByteVector_size(global::System.IntPtr data);
+ [global::System.Runtime.InteropServices.DllImport("$dllimport", EntryPoint="ByteVector_free")]
+ public static extern void ByteVector_free(global::System.IntPtr data);
[global::System.Runtime.InteropServices.DllImport("$dllimport", EntryPoint="ByteVector_to")]
public static extern global::System.IntPtr ByteVector_to(
- [global::System.Runtime.InteropServices.MarshalAs(global::System.Runtime.InteropServices.UnmanagedType.LPArray)]byte[] data, int size);
-
- public class UTF8Marshaler : global::System.Runtime.InteropServices.ICustomMarshaler {
- static UTF8Marshaler static_instance = new UTF8Marshaler();
-
- public global::System.IntPtr MarshalManagedToNative(object managedObj) {
- if (managedObj == null)
- return global::System.IntPtr.Zero;
- if (!(managedObj is string))
- throw new global::System.Runtime.InteropServices.MarshalDirectiveException(
- "UTF8Marshaler must be used on a string.");
-
- // not null terminated
- byte[] strbuf = global::System.Text.Encoding.UTF8.GetBytes((string)managedObj);
- global::System.IntPtr buffer = global::System.Runtime.InteropServices.Marshal.AllocHGlobal(strbuf.Length + 1);
- global::System.Runtime.InteropServices.Marshal.Copy(strbuf, 0, buffer, strbuf.Length);
-
- // write the terminating null
- global::System.Runtime.InteropServices.Marshal.WriteByte(buffer + strbuf.Length, 0);
- return buffer;
- }
-
- public unsafe object MarshalNativeToManaged(global::System.IntPtr pNativeData) {
- byte* walk = (byte*)pNativeData;
-
- // find the end of the string
- while (*walk != 0) {
- walk++;
- }
- int length = (int)(walk - (byte*)pNativeData);
-
- // should not be null terminated
- byte[] strbuf = new byte[length];
- // skip the trailing null
- global::System.Runtime.InteropServices.Marshal.Copy((global::System.IntPtr)pNativeData, strbuf, 0, length);
- return global::System.Text.Encoding.UTF8.GetString(strbuf);
- }
-
- public void CleanUpNativeData(global::System.IntPtr pNativeData) {
- global::System.Runtime.InteropServices.Marshal.FreeHGlobal(pNativeData);
- }
-
- public void CleanUpManagedData(object managedObj) {
- }
-
- public int GetNativeDataSize() {
- return -1;
- }
-
- public static global::System.Runtime.InteropServices.ICustomMarshaler GetInstance(string cookie) {
- return static_instance;
- }
- }
+ [global::System.Runtime.InteropServices.MarshalAs(global::System.Runtime.InteropServices.UnmanagedType.LPArray)]byte[] data, int size);
%}
#ifdef SWIGJAVA
@@ -138,45 +91,95 @@ extern "C"
jenv->ReleaseByteArrayElements($input, $input_ptr, JNI_ABORT);
%}
%typemap(out) std::vector %{
- jresult = jenv->NewByteArray((&result)->size());
- jenv->SetByteArrayRegion(jresult, 0, (&result)->size(), (const jbyte*)(&result)->data());
+ $result = jenv->NewByteArray((&result)->size());
+ jenv->SetByteArrayRegion($result, 0, (&result)->size(), (const jbyte*)(&result)->data());
%}
-%typemap(jtype) std::vector "byte[]"
+%typemap(out) digidoc::X509Cert %{
+ std::vector temp = $1;
+ $result = jenv->NewByteArray(temp.size());
+ jenv->SetByteArrayRegion($result, 0, temp.size(), (const jbyte*)temp.data());
+%}
+%typemap(out) digidoc::X509Cert * %{
+ std::vector temp = *$1;
+ $result = jenv->NewByteArray(temp.size());
+ jenv->SetByteArrayRegion($result, 0, temp.size(), (const jbyte*)temp.data());
+%}
+%typemap(jtype) std::vector, digidoc::X509Cert, digidoc::X509Cert * "byte[]"
%typemap(jstype) std::vector "byte[]"
-%typemap(jni) std::vector "jbyteArray"
-%typemap(javain) std::vector "$javainput"
+%typemap(jstype) digidoc::X509Cert, digidoc::X509Cert* "java.security.cert.X509Certificate"
+%typemap(jni) std::vector, digidoc::X509Cert, digidoc::X509Cert * "jbyteArray"
+%typemap(javain) std::vector, digidoc::X509Cert "$javainput"
%typemap(javaout) std::vector {
return $jnicall;
}
+%typemap(javaout, throws="java.security.cert.CertificateException, java.io.IOException") digidoc::X509Cert, digidoc::X509Cert * {
+ byte[] der = $jnicall;
+ java.security.cert.CertificateFactory cf = java.security.cert.CertificateFactory.getInstance("X509");
+ try (java.io.ByteArrayInputStream is = new java.io.ByteArrayInputStream(der)) {
+ return (java.security.cert.X509Certificate) cf.generateCertificate(is);
+ }
+ }
+
#elif defined(SWIGCSHARP)
%typemap(cstype) std::vector "byte[]"
-%typemap(csin,
- pre= " global::System.IntPtr cPtr$csinput = digidocPINVOKE.ByteVector_to($csinput, $csinput.Length);
- global::System.Runtime.InteropServices.HandleRef handleRef$csinput = new global::System.Runtime.InteropServices.HandleRef(this, cPtr$csinput);"
+%typemap(cstype) digidoc::X509Cert, digidoc::X509Cert* "System.Security.Cryptography.X509Certificates.X509Certificate2"
+%typemap(csin, pre= " global::System.IntPtr cPtr$csinput = digidocPINVOKE.ByteVector_to($csinput, $csinput.Length);
+ var handleRef$csinput = new global::System.Runtime.InteropServices.HandleRef(this, cPtr$csinput);"
) std::vector "handleRef$csinput"
+%typemap(freearg) std::vector
+%{ delete $1; %}
%typemap(csout, excode=SWIGEXCODE) std::vector {
- global::System.IntPtr data = $imcall;$excode
- byte[] result = new byte[$modulePINVOKE.ByteVector_size(data)];
- global::System.Runtime.InteropServices.Marshal.Copy($modulePINVOKE.ByteVector_data(data), result, 0, result.Length);
- return result;
-}
-#elif defined(SWIGPYTHON)
- %typemap(in) std::vector %{
- if (PyBytes_Check($input)) {
- const char *data = PyBytes_AsString($input);
- $1 = new std::vector(data, data + PyBytes_Size($input));
- } else if (PyString_Check($input)) {
- const char *data = PyString_AsString($input);
- $1 = new std::vector(data, data + PyString_Size($input));
- } else {
- PyErr_SetString(PyExc_TypeError, "not a bytes");
- SWIG_fail;
+ global::System.IntPtr cPtr = $imcall;$excode
+ byte[] result = new byte[$modulePINVOKE.ByteVector_size(cPtr)];
+ global::System.Runtime.InteropServices.Marshal.Copy($modulePINVOKE.ByteVector_data(cPtr), result, 0, result.Length);
+ $modulePINVOKE.ByteVector_free(cPtr);
+ return result;
+ }
+%typemap(csout, excode=SWIGEXCODE) digidoc::X509Cert {
+ global::System.IntPtr cPtr = $imcall;$excode
+ byte[] der = new byte[$modulePINVOKE.ByteVector_size(cPtr)];
+ global::System.Runtime.InteropServices.Marshal.Copy($modulePINVOKE.ByteVector_data(cPtr), der, 0, der.Length);
+ var result = new System.Security.Cryptography.X509Certificates.X509Certificate2(der);
+ $modulePINVOKE.ByteVector_free(cPtr);
+ return result;
}
- %}
+%typemap(csvarout, excode=SWIGEXCODE2) digidoc::X509Cert * %{
+ get {
+ global::System.IntPtr cPtr = $imcall;$excode
+ byte[] der = new byte[$modulePINVOKE.ByteVector_size(cPtr)];
+ global::System.Runtime.InteropServices.Marshal.Copy($modulePINVOKE.ByteVector_data(cPtr), der, 0, der.Length);
+ var result = new System.Security.Cryptography.X509Certificates.X509Certificate2(der);
+ $modulePINVOKE.ByteVector_free(cPtr);
+ return result;
+ } %}
+%typemap(out) std::vector %{ $result = new std::vector(std::move($1)); %}
+%typemap(out) digidoc::X509Cert %{ $result = new std::vector($1); %}
+
+#elif defined(SWIGPYTHON)
+%typemap(in) std::vector %{
+ if (PyBytes_Check($input)) {
+ const char *data = PyBytes_AsString($input);
+ $1 = new std::vector(data, data + PyBytes_Size($input));
+ } else if (PyString_Check($input)) {
+ const char *data = PyString_AsString($input);
+ $1 = new std::vector(data, data + PyString_Size($input));
+ } else {
+ PyErr_SetString(PyExc_TypeError, "not a bytes");
+ SWIG_fail;
+ }
+%}
%typemap(out) std::vector
%{ $result = PyBytes_FromStringAndSize((const char*)(&result)->data(), (&result)->size()); %}
%typemap(freearg) std::vector
%{ delete $1; %}
+%typemap(out) digidoc::X509Cert {
+ std::vector temp = $1;
+ $result = PyBytes_FromStringAndSize((const char*)temp.data(), temp.size());
+}
+%typemap(out) digidoc::X509Cert * {
+ std::vector temp = *$1;
+ $result = PyBytes_FromStringAndSize((const char*)temp.data(), temp.size());
+}
#endif
%apply std::vector { std::vector const & };
@@ -208,11 +211,6 @@ extern "C"
%ignore digidoc::ConfV2::verifyServiceCert;
%ignore digidoc::ConfV4::verifyServiceCerts;
%ignore digidoc::ConfV5::TSCerts;
-%ignore digidoc::Signer::cert;
-%ignore digidoc::Signature::signingCertificate;
-%ignore digidoc::Signature::OCSPCertificate;
-%ignore digidoc::Signature::TimeStampCertificate;
-%ignore digidoc::Signature::ArchiveTimeStampCertificate;
// hide stream methods, swig cannot generate usable wrappers
%ignore digidoc::DataFile::saveAs(std::ostream &os) const;
%ignore digidoc::Container::addAdESSignature(std::istream &signature);
@@ -231,6 +229,9 @@ extern "C"
%newobject digidoc::Container::open;
%newobject digidoc::Container::create;
+%immutable digidoc::TSAInfo::cert;
+%immutable digidoc::TSAInfo::time;
+
%feature("director") digidoc::ContainerOpenCB;
%typemap(javacode) digidoc::Conf %{
@@ -260,15 +261,10 @@ def transfer(self):
%include "std_vector.i"
%include "std_map.i"
#ifdef SWIGCSHARP
-namespace std {
- %typemap(imtype,
- inattributes="[global::System.Runtime.InteropServices.MarshalAs(global::System.Runtime.InteropServices.UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(UTF8Marshaler))]",
- outattributes="[return: global::System.Runtime.InteropServices.MarshalAs(global::System.Runtime.InteropServices.UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(UTF8Marshaler))]")
- string "string"
- %typemap(imtype,
- inattributes="[global::System.Runtime.InteropServices.MarshalAs(global::System.Runtime.InteropServices.UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(UTF8Marshaler))]",
- outattributes="[return: global::System.Runtime.InteropServices.MarshalAs(global::System.Runtime.InteropServices.UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(UTF8Marshaler))]") const string & "string"
-}
+%typemap(imtype,
+ inattributes="[global::System.Runtime.InteropServices.MarshalAs(global::System.Runtime.InteropServices.UnmanagedType.LPUTF8Str)]",
+ outattributes="[return: global::System.Runtime.InteropServices.MarshalAs(global::System.Runtime.InteropServices.UnmanagedType.LPUTF8Str)]")
+ std::string, const std::string & "string"
#endif
// Handle DigiDoc Export declarations
@@ -293,32 +289,8 @@ namespace std {
%template(StringMap) std::map;
%template(DataFiles) std::vector;
%template(Signatures) std::vector;
+%template(TSAInfos) std::vector;
-// override X509Cert methods to return byte array
-%extend digidoc::Signer {
- std::vector cert() const
- {
- return $self->cert();
- }
-}
-%extend digidoc::Signature {
- std::vector signingCertificateDer() const
- {
- return $self->signingCertificate();
- }
- std::vector OCSPCertificateDer() const
- {
- return $self->OCSPCertificate();
- }
- std::vector TimeStampCertificateDer() const
- {
- return $self->TimeStampCertificate();
- }
- std::vector ArchiveTimeStampCertificateDer() const
- {
- return $self->ArchiveTimeStampCertificate();
- }
-}
%extend digidoc::Container {
static digidoc::Container* open(const std::string &path, digidoc::ContainerOpenCB *cb)
{
diff --git a/src/DataFile.cpp b/src/DataFile.cpp
index d363f50e7..f4ba156bf 100644
--- a/src/DataFile.cpp
+++ b/src/DataFile.cpp
@@ -98,9 +98,8 @@ DataFilePrivate::DataFilePrivate(unique_ptr &&is, string filename, stri
m_size = pos < 0 ? 0 : (unsigned long)pos;
}
-vector DataFilePrivate::calcDigest(const string &method) const
+void DataFilePrivate::digest(const Digest &digest) const
{
- Digest digest(method);
array buf{};
m_is->clear();
m_is->seekg(0);
@@ -110,7 +109,13 @@ vector DataFilePrivate::calcDigest(const string &method) const
if(m_is->gcount() > 0)
digest.update(buf.data(), size_t(m_is->gcount()));
}
- return digest.result();
+}
+
+std::vector DataFilePrivate::calcDigest(const string &method) const
+{
+ Digest d(method);
+ digest(d);
+ return d.result();
}
void DataFilePrivate::saveAs(const string& path) const
diff --git a/src/DataFile_p.h b/src/DataFile_p.h
index 2e197794b..07fb29955 100644
--- a/src/DataFile_p.h
+++ b/src/DataFile_p.h
@@ -27,6 +27,7 @@
namespace digidoc
{
+class Digest;
class DataFilePrivate final: public DataFile
{
public:
@@ -37,6 +38,7 @@ class DataFilePrivate final: public DataFile
unsigned long fileSize() const final { return m_size; }
std::string mediaType() const final { return m_mediatype; }
+ void digest(const Digest &method) const;
std::vector calcDigest(const std::string &method) const final;
void saveAs(std::ostream &os) const final;
void saveAs(const std::string& path) const final;
diff --git a/src/SiVaContainer.cpp b/src/SiVaContainer.cpp
index 0d4fc96a1..bbb0e69ba 100644
--- a/src/SiVaContainer.cpp
+++ b/src/SiVaContainer.cpp
@@ -362,7 +362,7 @@ unique_ptr SiVaContainer::parseDDoc(bool useHashCode)
if(!useHashCode)
continue;
Digest calc(URI_SHA1);
- doc.c14n(&calc, XMLDocument::C14D_ID_1_0, dataFile);
+ doc.c14n(calc, XMLDocument::C14D_ID_1_0, dataFile);
dataFile.setProperty("ContentType", "HASHCODE");
dataFile.setProperty("DigestType", "sha1");
dataFile.setProperty("DigestValue", to_base64(calc.result()));
diff --git a/src/Signature.cpp b/src/Signature.cpp
index abe30ed2f..1b13ad5d1 100644
--- a/src/Signature.cpp
+++ b/src/Signature.cpp
@@ -214,6 +214,11 @@ X509Cert Signature::ArchiveTimeStampCertificate() const { return X509Cert(); }
*/
string Signature::ArchiveTimeStampTime() const { return {}; }
+/**
+ * Returns signature Archive TimeStampTokens.
+ */
+vector Signature::ArchiveTimeStamps() const { return {}; }
+
struct Signature::Validator::Private
{
Status result = Valid;
diff --git a/src/Signature.h b/src/Signature.h
index c078e1e04..58e74e2d9 100644
--- a/src/Signature.h
+++ b/src/Signature.h
@@ -21,12 +21,17 @@
#include "Exception.h"
-#include
-#include
+#include "crypto/X509Cert.h"
namespace digidoc
{
class X509Cert;
+
+ struct TSAInfo {
+ X509Cert cert;
+ std::string time;
+ };
+
class DIGIDOCPP_EXPORT Signature
{
public:
@@ -85,18 +90,18 @@ namespace digidoc
virtual std::string countryName() const;
virtual std::vector signerRoles() const;
- //TM profile properties
+ // TM profile properties
virtual std::string OCSPProducedAt() const;
virtual X509Cert OCSPCertificate() const;
DIGIDOCPP_DEPRECATED virtual std::vector OCSPNonce() const;
- //TS profile properties
+ // TS profile properties
virtual X509Cert TimeStampCertificate() const;
virtual std::string TimeStampTime() const;
- //TSA profile properties
- virtual X509Cert ArchiveTimeStampCertificate() const;
- virtual std::string ArchiveTimeStampTime() const;
+ // TSA profile properties
+ DIGIDOCPP_DEPRECATED virtual X509Cert ArchiveTimeStampCertificate() const;
+ DIGIDOCPP_DEPRECATED virtual std::string ArchiveTimeStampTime() const;
// Xades properties
virtual std::string streetAddress() const;
@@ -110,6 +115,9 @@ namespace digidoc
// Other
virtual std::vector messageImprint() const;
+ //TSA profile properties
+ virtual std::vector ArchiveTimeStamps() const;
+
protected:
Signature();
diff --git a/src/SignatureXAdES_B.cpp b/src/SignatureXAdES_B.cpp
index 157456074..b06953401 100644
--- a/src/SignatureXAdES_B.cpp
+++ b/src/SignatureXAdES_B.cpp
@@ -284,7 +284,7 @@ SignatureXAdES_B::SignatureXAdES_B(unsigned int id, ASiContainer *container, Sig
}
Digest calc(digestMethod);
- signatures->c14n(&calc, canonMethod, signedProperties);
+ signatures->c14n(calc, canonMethod, signedProperties);
addReference("#" + nr + "-SignedProperties", calc.uri(), calc.result(), REF_TYPE, canonMethod);
}
@@ -343,6 +343,9 @@ SignatureXAdES_B::SignatureXAdES_B(const std::shared_ptr &signatures
"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);
@@ -566,7 +569,7 @@ vector SignatureXAdES_B::dataToSign() const
{
Digest calc(signatureMethod());
auto signedInfo = signature/"SignedInfo";
- signatures->c14n(&calc, (signedInfo/CanonicalizationMethod)["Algorithm"], signedInfo);
+ signatures->c14n(calc, (signedInfo/CanonicalizationMethod)["Algorithm"], signedInfo);
return calc.result();
}
diff --git a/src/SignatureXAdES_LTA.cpp b/src/SignatureXAdES_LTA.cpp
index 965dd0e03..92ec3ad03 100644
--- a/src/SignatureXAdES_LTA.cpp
+++ b/src/SignatureXAdES_LTA.cpp
@@ -29,7 +29,6 @@
#include "util/File.h"
#include
-#include
using namespace digidoc;
using namespace digidoc::util;
@@ -40,8 +39,7 @@ namespace digidoc
constexpr XMLName ArchiveTimeStamp {"ArchiveTimeStamp", XADESv141_NS};
}
-void SignatureXAdES_LTA::calcArchiveDigest(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++)
{
@@ -66,16 +64,7 @@ void SignatureXAdES_LTA::calcArchiveDigest(Digest *digest,
if(file == files.cend())
THROW("Filed to find reference URI in container");
- std::istream *is = static_cast(*file)->m_is.get();
- array buf{};
- is->clear();
- is->seekg(0);
- while(*is)
- {
- is->read((char*)buf.data(), streamsize(buf.size()));
- if(is->gcount() > 0)
- digest->update(buf.data(), size_t(is->gcount()));
- }
+ dynamic_cast(*file)->digest(digest);
}
for(const auto *name: {"SignedInfo", "SignatureValue", "KeyInfo"})
@@ -86,65 +75,60 @@ void SignatureXAdES_LTA::calcArchiveDigest(Digest *digest,
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(const string &profile)
{
- SignatureXAdES_LT::extendSignatureProfile(profile);
+ if(SignatureXAdES_LTA::profile().find(ASiC_E::ASIC_TS_PROFILE) == string::npos)
+ SignatureXAdES_LT::extendSignatureProfile(profile);
if(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(CONF(TSUrl), calc);
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
+X509Cert SignatureXAdES_LTA::ArchiveTimeStampCertificate() const
{
- try {
- return {unsignedSignatureProperties()/ArchiveTimeStamp/EncapsulatedTimeStamp};
- } catch(const Exception &) {}
- return {};
+ if(auto list = ArchiveTimeStamps(); !list.empty())
+ return list.back().cert;
+ return X509Cert();
}
-X509Cert SignatureXAdES_LTA::ArchiveTimeStampCertificate() const
+string SignatureXAdES_LTA::ArchiveTimeStampTime() const
{
- return tsaFromBase64().cert();
+ if(auto list = ArchiveTimeStamps(); !list.empty())
+ return list.back().time;
+ return {};
}
-string SignatureXAdES_LTA::ArchiveTimeStampTime() const
+vector SignatureXAdES_LTA::ArchiveTimeStamps() const
{
- return date::to_string(tsaFromBase64().time());
+ vector 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
@@ -168,9 +152,12 @@ void SignatureXAdES_LTA::validate(const string &policy) const
auto ts = unsignedSignatureProperties()/ArchiveTimeStamp;
if(!ts)
THROW("Missing ArchiveTimeStamp element");
- verifyTS(ts, exception, [this](Digest *digest, string_view canonicalizationMethod) {
- calcArchiveDigest(digest, canonicalizationMethod);
- });
+ for(; ts; ts++)
+ {
+ verifyTS(ts, exception, [this, ts](const Digest &digest, string_view canonicalizationMethod) {
+ calcArchiveDigest(digest, canonicalizationMethod, ts);
+ });
+ }
} catch(const Exception &e) {
exception.addCause(e);
}
diff --git a/src/SignatureXAdES_LTA.h b/src/SignatureXAdES_LTA.h
index 9972a39da..c73d183f9 100644
--- a/src/SignatureXAdES_LTA.h
+++ b/src/SignatureXAdES_LTA.h
@@ -31,15 +31,14 @@ class SignatureXAdES_LTA final: public SignatureXAdES_LT
X509Cert ArchiveTimeStampCertificate() const final;
std::string ArchiveTimeStampTime() const final;
+ std::vector ArchiveTimeStamps() const final;
void validate(const std::string &policy) const final;
void extendSignatureProfile(const std::string &profile) final;
private:
DISABLE_COPY(SignatureXAdES_LTA);
- void calcArchiveDigest(Digest *digest,
- std::string_view canonicalizationMethod) const;
- TS tsaFromBase64() const;
+ void calcArchiveDigest(const Digest &digest, std::string_view canonicalizationMethod, XMLNode node) const;
};
}
diff --git a/src/SignatureXAdES_T.cpp b/src/SignatureXAdES_T.cpp
index 39ae1ef19..5dfea49d0 100644
--- a/src/SignatureXAdES_T.cpp
+++ b/src/SignatureXAdES_T.cpp
@@ -70,7 +70,7 @@ void SignatureXAdES_T::extendSignatureProfile(const std::string &profile)
Digest calc;
auto method = canonicalizationMethod();
- signatures->c14n(&calc, method, signatureValue());
+ signatures->c14n(calc, method, signatureValue());
TS tsa(CONF(TSUrl), calc);
auto ts = usp + "SignatureTimeStamp";
@@ -109,7 +109,7 @@ void SignatureXAdES_T::validate(const std::string &policy) const
if(ts + 1)
THROW("More than one SignatureTimeStamp is not supported");
- TS tsa = verifyTS(ts, exception, [this](Digest *digest, string_view canonicalizationMethod) {
+ TS tsa = verifyTS(ts, exception, [this](const Digest &digest, string_view canonicalizationMethod) {
signatures->c14n(digest, canonicalizationMethod, signatureValue());
});
@@ -163,7 +163,7 @@ void SignatureXAdES_T::validate(const std::string &policy) const
for(auto sigAndRefsTS = usp/"SigAndRefsTimeStamp"; sigAndRefsTS; sigAndRefsTS++)
{
- verifyTS(sigAndRefsTS, exception, [this, usp](Digest *digest, string_view canonicalizationMethod) {
+ verifyTS(sigAndRefsTS, exception, [this, usp](const Digest &digest, string_view canonicalizationMethod) {
signatures->c14n(digest, canonicalizationMethod, signatureValue());
for(const auto *name: {
"SignatureTimeStamp",
@@ -195,7 +195,7 @@ XMLNode SignatureXAdES_T::unsignedSignatureProperties() const
}
TS SignatureXAdES_T::verifyTS(XMLNode timestamp, digidoc::Exception &exception,
- std::function &&calcDigest)
+ std::function &&calcDigest)
{
auto ets = timestamp/EncapsulatedTimeStamp;
if(!ets)
@@ -205,7 +205,7 @@ TS SignatureXAdES_T::verifyTS(XMLNode timestamp, digidoc::Exception &exception,
TS ts(ets);
Digest calc(ts.digestMethod());
- calcDigest(&calc, (timestamp/CanonicalizationMethod)["Algorithm"]);
+ calcDigest(calc, (timestamp/CanonicalizationMethod)["Algorithm"]);
ts.verify(calc.result());
if(ts.digestMethod() == URI_SHA1 &&
diff --git a/src/SignatureXAdES_T.h b/src/SignatureXAdES_T.h
index 5d618097a..a0cdcb833 100644
--- a/src/SignatureXAdES_T.h
+++ b/src/SignatureXAdES_T.h
@@ -47,7 +47,7 @@ class SignatureXAdES_T: public SignatureXAdES_B
TS TimeStamp() const;
static TS verifyTS(XMLNode timestamp, Exception &exception,
- std::function &&calcDigest);
+ std::function &&calcDigest);
private:
DISABLE_COPY(SignatureXAdES_T);
diff --git a/src/XMLDocument.h b/src/XMLDocument.h
index cdd03f4b4..1ea44485e 100644
--- a/src/XMLDocument.h
+++ b/src/XMLDocument.h
@@ -159,6 +159,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;
@@ -355,7 +360,7 @@ struct XMLDocument: public unique_xml_t, public XMLNode
return doc;
}
- void c14n(Digest *digest, std::string_view algo, XMLNode node)
+ void c14n(const Digest &digest, std::string_view algo, XMLNode node)
{
xmlC14NMode mode = XML_C14N_1_0;
int with_comments = 0;
@@ -383,7 +388,7 @@ struct XMLDocument: public unique_xml_t, public XMLNode
auto *digest = static_cast(context);
digest->update(pcxmlChar(buffer), size_t(len));
return len;
- }, nullptr, digest, nullptr), xmlOutputBufferClose);
+ }, nullptr, const_cast(&digest), nullptr), xmlOutputBufferClose);
int size = xmlC14NExecute(get(), [](void *root, xmlNodePtr node, xmlNodePtr parent) constexpr noexcept {
if(root == node)
return 1;
diff --git a/src/crypto/Digest.cpp b/src/crypto/Digest.cpp
index 312da8338..b65638e22 100644
--- a/src/crypto/Digest.cpp
+++ b/src/crypto/Digest.cpp
@@ -44,11 +44,6 @@ Digest::Digest(string_view uri)
THROW_OPENSSLEXCEPTION("Failed to initialize %.*s digest calculator", int(uri.size()), uri.data());
}
-/**
- * Destroys OpenSSL digest calculator.
- */
-Digest::~Digest() = default;
-
vector Digest::addDigestInfo(vector digest, string_view uri)
{
switch(toMethod(uri))
@@ -224,7 +219,7 @@ std::string Digest::toUri(int nid)
* @throws Exception throws exception if update failed.
* @see result()
*/
-void Digest::update(const unsigned char *data, size_t length)
+void Digest::update(const unsigned char *data, size_t length) const
{
if(!data)
THROW("Can not update digest value from NULL pointer.");
diff --git a/src/crypto/Digest.h b/src/crypto/Digest.h
index 876b84844..05d8917ea 100644
--- a/src/crypto/Digest.h
+++ b/src/crypto/Digest.h
@@ -71,8 +71,7 @@ namespace digidoc
{
public:
Digest(std::string_view uri = {});
- ~Digest();
- void update(const unsigned char *data, size_t length);
+ void update(const unsigned char *data, size_t length) const;
std::vector result(const std::vector &data);
std::vector result() const;
std::string uri() const;
@@ -88,7 +87,6 @@ namespace digidoc
static std::string digestInfoUri(const std::vector &digest);
private:
- DISABLE_COPY(Digest);
std::unique_ptr d;
};
diff --git a/src/digidoc-tool.1.cmake b/src/digidoc-tool.1.cmake
index 857a9e18d..aab8f2280 100644
--- a/src/digidoc-tool.1.cmake
+++ b/src/digidoc-tool.1.cmake
@@ -68,6 +68,13 @@ Command sign:
--tsurl - option to change TS URL (default http://demo.sk.ee/tsa)
--dontValidate - Don't validate container on signature creation
+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
diff --git a/src/digidoc-tool.cpp b/src/digidoc-tool.cpp
index 731830079..3c0585554 100644
--- a/src/digidoc-tool.cpp
+++ b/src/digidoc-tool.cpp
@@ -297,6 +297,19 @@ class ToolConfig final: public XmlConfCurrent
static string_view RED, GREEN, YELLOW, RESET;
};
+struct value: std::string_view {
+ constexpr value(std::string_view arg, std::string_view param) noexcept
+ : std::string_view(arg.size() > param.size() && arg.compare(0, param.size(), param) == 0 ?
+ arg.substr(param.size()) : std::string_view{})
+ {}
+
+ constexpr operator bool() const noexcept
+ {
+ return !empty();
+ }
+};
+
+
/**
@@ -367,6 +380,12 @@ static int printUsage(const char *executable)
<< " --rsapss - Use RSA PSS padding" << endl
<< " --tsurl - option to change TS URL (default " << CONF(TSUrl) << ")" << endl
<< " --dontValidate - Don't validate container on signature creation" << 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
@@ -384,40 +403,39 @@ ToolConfig::ToolConfig(int argc, char *argv[])
for(int i = 2; i < argc; i++)
{
string_view arg(argv[i]);
- if(arg.find("--profile=") == 0)
- profile = arg.substr(10);
- else if(arg.find("--file=") == 0)
+ if(value v{arg, "--profile="}) profile = v;
+ else if(value v{arg, "--file="})
{
- string_view arg2(i+1 < argc ? argv[i+1] : string_view());
- files.emplace(arg.substr(7),
- arg2.find("--mime=") == 0 ? toUTF8(arg2.substr(7)) : "application/octet-stream");
+ value mime(i+1 < argc ? argv[i+1] : string_view(), "--mime=");
+ files.emplace(v,
+ mime ? toUTF8(mime) : "application/octet-stream");
}
#ifdef _WIN32
else if(arg == "--cng") cng = true;
else if(arg == "--selectFirst") selectFirst = true;
- else if(arg.find("--thumbprint=") == 0) thumbprint = File::hexToBin(arg.substr(arg.find('=') + 1));
+ else if(value v{arg, "--thumbprint="}) thumbprint = File::hexToBin(v);
#endif
else if(arg.find("--pkcs11") == 0)
{
cng = false;
- if(arg.find('=') != string::npos)
- pkcs11 = toUTF8(arg.substr(arg.find('=') + 1));
+ if(value v{arg, "--pkcs11="})
+ pkcs11 = toUTF8(v);
}
- else if(arg.find("--pkcs12=") == 0)
+ else if(value v{arg, "--pkcs12="})
{
cng = false;
- pkcs12 = toUTF8(arg.substr(9));
+ pkcs12 = toUTF8(v);
}
else if(arg == "--dontValidate") dontValidate = true;
else if(arg == "--XAdESEN") XAdESEN = true;
- else if(arg.find("--pin=") == 0) pin = arg.substr(6);
- else if(arg.find("--cert=") == 0) cert = toUTF8(arg.substr(7));
- else if(arg.find("--city=") == 0) city = toUTF8(arg.substr(7));
- else if(arg.find("--street=") == 0) street = toUTF8(arg.substr(9));
- else if(arg.find("--state=") == 0) state = toUTF8(arg.substr(8));
- else if(arg.find("--postalCode=") == 0) postalCode = toUTF8(arg.substr(13));
- else if(arg.find("--country=") == 0) country = toUTF8(arg.substr(10));
- else if(arg.find("--role=") == 0) roles.push_back(toUTF8(arg.substr(7)));
+ else if(value v{arg, "--pin="}) pin = v;
+ else if(value v{arg, "--cert="}) cert = toUTF8(v);
+ else if(value v{arg, "--city="}) city = toUTF8(v);
+ else if(value v{arg, "--street="}) street = toUTF8(v);
+ else if(value v{arg, "--state="}) state = toUTF8(v);
+ else if(value v{arg, "--postalCode="}) postalCode = toUTF8(v);
+ else if(value v{arg, "--country="}) country = toUTF8(v);
+ else if(value v{arg, "--role="}) roles.push_back(toUTF8(v));
else if(arg == "--sha224") uri = URI_SHA224;
else if(arg == "--sha256") uri = URI_SHA256;
else if(arg == "--sha384") uri = URI_SHA384;
@@ -432,14 +450,14 @@ ToolConfig::ToolConfig(int argc, char *argv[])
else if(arg == "--sigpsssha512") { siguri = URI_SHA512; rsaPss = true; }
else if(arg == "--rsapkcs15") rsaPss = false;
else if(arg == "--rsapss") rsaPss = true;
- else if(arg.find("--tsurl") == 0) tsurl = arg.substr(8);
- else if(arg.find("--tslurl=") == 0) tslurl = arg.substr(9);
- else if(arg.find("--tslcert=") == 0) tslcerts = vector{ X509Cert(toUTF8(arg.substr(10))) };
+ else if(value v{arg, "--tsurl="}) tsurl = v;
+ else if(value v{arg, "--tslurl="}) tslurl = v;
+ else if(value v{arg, "--tslcert="}) tslcerts = vector{ X509Cert(toUTF8(v)) };
else if(arg == "--TSLAllowExpired") expired = true;
else if(arg == "--dontsign") doSign = false;
else if(arg == "--nocolor") RED = GREEN = YELLOW = RESET = {};
- else if(arg.find("--loglevel=") == 0) _logLevel = atoi(arg.substr(11).data());
- else if(arg.find("--logfile=") == 0) _logFile = toUTF8(arg.substr(10));
+ else if(value v{arg, "--loglevel="}) _logLevel = atoi(v.data());
+ else if(value v{arg, "--logfile="}) _logFile = toUTF8(v);
else path = toUTF8(arg);
}
}
@@ -471,7 +489,7 @@ unique_ptr ToolConfig::getSigner(bool getwebsigner) const
#ifdef _WIN32
else if(cng)
{
- unique_ptr win = make_unique(pin, selectFirst);
+ auto win = make_unique(pin, selectFirst);
win->setThumbprint(thumbprint);
signer = std::move(win);
}
@@ -489,6 +507,12 @@ unique_ptr ToolConfig::getSigner(bool getwebsigner) const
return signer;
}
+/**
+ * Validate signature.
+ *
+ * @param signature Signature to validated
+ * @return EXIT_FAILURE (1) - failure, EXIT_SUCCESS (0) - success
+ */
static int validateSignature(const Signature *s, ToolConfig::Warning warning = ToolConfig::WWarning)
{
int returnCode = EXIT_SUCCESS;
@@ -549,20 +573,20 @@ static int open(int argc, char* argv[])
// Parse command line arguments.
for(int i = 2; i < argc; i++)
{
- string arg(ToolConfig::toUTF8(argv[i]));
+ string_view arg(argv[i]);
if(arg == "--list")
continue;
- if(arg.find("--warnings=") == 0)
+ if(value v{arg, "--warnings="})
{
- if(arg.substr(11, 6) == "ignore") reportwarnings = ToolConfig::WIgnore;
- if(arg.substr(11, 5) == "error") reportwarnings = ToolConfig::WError;
+ if(v == "ignore") reportwarnings = ToolConfig::WIgnore;
+ if(v == "error") reportwarnings = ToolConfig::WError;
}
else if(arg.find("--extractAll") == 0)
{
extractPath = fs::current_path();
if(auto pos = arg.find('='); pos != string::npos)
{
- fs::path newPath = fs::u8path(arg.substr(pos + 1));
+ fs::path newPath = fs::path(arg.substr(pos + 1));
extractPath = newPath.is_relative() ? extractPath / newPath : std::move(newPath);
}
if(!fs::is_directory(extractPath))
@@ -570,12 +594,12 @@ static int open(int argc, char* argv[])
}
else if(arg == "--validateOnExtract")
validateOnExtract = true;
- else if(arg.find("--policy=") == 0)
- policy = arg.substr(9);
- else if(arg.find("--offline") == 0)
+ else if(value v{arg, "--policy="})
+ policy = v;
+ else if(arg == "--offline")
cb.online = false;
else
- path = std::move(arg);
+ path = ToolConfig::toUTF8(arg);
}
if(path.empty())
@@ -664,15 +688,69 @@ static int open(int argc, char* argv[])
<< " OCSP Responder: " << s->OCSPCertificate() << endl
<< " Message imprint (" << msgImprint.size() << "): " << msgImprint << endl
<< " TS: " << s->TimeStampCertificate() << endl
- << " TS time: " << s->TimeStampTime() << endl
- << " TSA: " << s->ArchiveTimeStampCertificate() << endl
- << " TSA time: " << s->ArchiveTimeStampTime() << endl;
+ << " TS time: " << s->TimeStampTime() << endl;
+ for(const auto &tsaInfo: s->ArchiveTimeStamps())
+ {
+ cout
+ << " TSA: " << tsaInfo.cert << '\n'
+ << " TSA time: " << tsaInfo.time << '\n';
+ }
}
if(returnCode == EXIT_SUCCESS && !extractPath.empty())
return extractFiles();
return returnCode;
}
+/**
+ * Extend signatures in container.
+ *
+ * @param argc number of command line arguments.
+ * @param argv command line arguments.
+ * @return EXIT_FAILURE (1) - failure, EXIT_SUCCESS (0) - success
+ */
+static int extend(int argc, char *argv[])
+{
+ vector signatures;
+ bool dontValidate = false;
+ string path, profile;
+ for(int i = 2; i < argc; i++)
+ {
+ string_view arg(argv[i]);
+ if(value v{arg, "--profile="})
+ profile = v;
+ else if(value v{arg, "--signature="})
+ signatures.push_back(unsigned(atoi(v.data())));
+ else if(arg == "--dontValidate")
+ dontValidate = true;
+ else
+ path = ToolConfig::toUTF8(arg);
+ }
+
+ if(path.empty())
+ return printUsage(argv[0]);
+
+ unique_ptr doc;
+ try {
+ doc = Container::openPtr(path);
+ } catch(const Exception &e) {
+ cout << "Failed to parse container" << endl;
+ cout << " Exception:" << endl << e;
+ return EXIT_FAILURE;
+ }
+
+ for(unsigned int i : signatures)
+ {
+ cout << " Extending signature " << i << " to " << profile << endl;
+ Signature *s = doc->signatures().at(i);
+ s->extendSignatureProfile(profile);
+ if(!dontValidate)
+ validateSignature(s);
+ }
+
+ doc->save();
+ return EXIT_SUCCESS;
+}
+
/**
* Remove items from container.
*
@@ -686,13 +764,13 @@ static int remove(int argc, char *argv[])
string path;
for(int i = 2; i < argc; i++)
{
- string arg(ToolConfig::toUTF8(argv[i]));
- if(arg.find("--document=") == 0)
- documents.push_back(unsigned(stoi(arg.substr(11))));
- else if(arg.find("--signature=") == 0)
- signatures.push_back(unsigned(stoi(arg.substr(12))));
+ string_view arg(argv[i]);
+ if(value v{arg, "--document="})
+ documents.push_back(unsigned(atoi(v.data())));
+ else if(value v{arg, "--signature="})
+ signatures.push_back(unsigned(atoi(v.data())));
else
- path = std::move(arg);
+ path = ToolConfig::toUTF8(arg);
}
if(path.empty())
@@ -764,18 +842,7 @@ static int add(const ToolConfig &p, const char *program)
static int signContainer(Container *doc, const unique_ptr &signer, bool dontValidate = false)
{
if(Signature *signature = doc->sign(signer.get()))
- {
- if(dontValidate)
- return EXIT_SUCCESS;
- try {
- signature->validate();
- cout << " Validation: " << ToolConfig::GREEN << "OK" << ToolConfig::RESET << endl;
- return EXIT_SUCCESS;
- } catch(const Exception &e) {
- cout << " Validation: " << ToolConfig::RED << "FAILED" << ToolConfig::RESET << endl;
- cout << " Exception:" << endl << e;
- }
- }
+ return dontValidate ? EXIT_SUCCESS : validateSignature(signature);
return EXIT_FAILURE;
}
@@ -1027,6 +1094,8 @@ int main(int argc, char *argv[]) try
return remove(argc, argv);
if(command == "sign")
return sign(*conf, argv[0]);
+ if(command == "extend")
+ return extend(argc, argv);
if(command == "websign")
return websign(*conf, argv[0]);
if(command == "tsl")
diff --git a/test/libdigidocpp_boost.cpp b/test/libdigidocpp_boost.cpp
index 13da2fc84..8d6284c28 100644
--- a/test/libdigidocpp_boost.cpp
+++ b/test/libdigidocpp_boost.cpp
@@ -354,8 +354,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.profile()));
+ 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);