Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Extend XAdES LTA signatures #622

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
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
5 changes: 5 additions & 0 deletions examples/DigiDocCSharp/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,11 @@ private static void Verify(string file)
Console.WriteLine("Time: " + s.trustedSigningTime());
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");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,10 @@ static void verify(String file) {
System.out.println("Time: " + signature.trustedSigningTime());
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
{
Expand Down
28 changes: 23 additions & 5 deletions libdigidocpp.i
Original file line number Diff line number Diff line change
Expand Up @@ -96,15 +96,17 @@ static std::vector<unsigned char>* SWIG_JavaArrayToVectorUnsignedChar(JNIEnv *je
%{ $1 = SWIG_JavaArrayToVectorUnsignedChar(jenv, $input); %}
%typemap(out, fragment="SWIG_VectorUnsignedCharToJavaArray") std::vector<unsigned char>, digidoc::X509Cert
%{ $result = SWIG_VectorUnsignedCharToJavaArray(jenv, $1); %}
%typemap(jtype) std::vector<unsigned char>, digidoc::X509Cert "byte[]"
%typemap(out, fragment="SWIG_VectorUnsignedCharToJavaArray") digidoc::X509Cert *
%{ $result = SWIG_VectorUnsignedCharToJavaArray(jenv, *$1); %}
%typemap(jtype) std::vector<unsigned char>, digidoc::X509Cert, digidoc::X509Cert * "byte[]"
%typemap(jstype) std::vector<unsigned char> "byte[]"
%typemap(jstype) digidoc::X509Cert "java.security.cert.X509Certificate"
%typemap(jni) std::vector<unsigned char>, digidoc::X509Cert "jbyteArray"
%typemap(jstype) digidoc::X509Cert, digidoc::X509Cert* "java.security.cert.X509Certificate"
%typemap(jni) std::vector<unsigned char>, digidoc::X509Cert, digidoc::X509Cert * "jbyteArray"
%typemap(javain) std::vector<unsigned char>, digidoc::X509Cert "$javainput"
%typemap(javaout) std::vector<unsigned char> {
return $jnicall;
}
%typemap(javaout, throws="java.security.cert.CertificateException, java.io.IOException") digidoc::X509Cert {
%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)) {
Expand All @@ -114,7 +116,7 @@ static std::vector<unsigned char>* SWIG_JavaArrayToVectorUnsignedChar(JNIEnv *je

#elif defined(SWIGCSHARP)
%typemap(cstype) std::vector<unsigned char> "byte[]"
%typemap(cstype) digidoc::X509Cert "System.Security.Cryptography.X509Certificates.X509Certificate2"
%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<unsigned char> "handleRef$csinput"
Expand All @@ -132,6 +134,14 @@ static std::vector<unsigned char>* SWIG_JavaArrayToVectorUnsignedChar(JNIEnv *je
$modulePINVOKE.ByteVector_free(cPtr);
return new System.Security.Cryptography.X509Certificates.X509Certificate2(der);
}
%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);
$modulePINVOKE.ByteVector_free(cPtr);
return new System.Security.Cryptography.X509Certificates.X509Certificate2(der);
} %}
%typemap(out) std::vector<unsigned char> %{ $result = new std::vector<unsigned char>(std::move($1)); %}
%typemap(out) digidoc::X509Cert %{ $result = new std::vector<unsigned char>($1); %}

Expand All @@ -154,6 +164,10 @@ static std::vector<unsigned char>* SWIG_JavaArrayToVectorUnsignedChar(JNIEnv *je
std::vector<unsigned char> temp = $1;
$result = PyBytes_FromStringAndSize((const char*)temp.data(), temp.size());
}
%typemap(out) digidoc::X509Cert * {
std::vector<unsigned char> temp = *$1;
$result = PyBytes_FromStringAndSize((const char*)temp.data(), temp.size());
}
#endif
%typemap(freearg) std::vector<unsigned char>
%{ delete $1; %}
Expand Down Expand Up @@ -205,6 +219,9 @@ static std::vector<unsigned char>* SWIG_JavaArrayToVectorUnsignedChar(JNIEnv *je
%newobject digidoc::Container::open;
%newobject digidoc::Container::create;

%immutable digidoc::TSAInfo::cert;
%immutable digidoc::TSAInfo::time;

%feature("director") digidoc::ContainerOpenCB;

%typemap(javacode) digidoc::Conf %{
Expand Down Expand Up @@ -262,6 +279,7 @@ def transfer(self):
%template(StringMap) std::map<std::string,std::string>;
%template(DataFiles) std::vector<digidoc::DataFile*>;
%template(Signatures) std::vector<digidoc::Signature*>;
%template(TSAInfos) std::vector<digidoc::TSAInfo>;

%extend digidoc::Container {
static digidoc::Container* open(const std::string &path, digidoc::ContainerOpenCB *cb)
Expand Down
19 changes: 17 additions & 2 deletions src/Signature.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -223,12 +223,27 @@ 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.
*/
vector<TSAInfo> Signature::ArchiveTimeStamps() const { return {}; }

struct Signature::Validator::Private
{
Expand Down
22 changes: 15 additions & 7 deletions src/Signature.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,18 @@

#include "Exception.h"

#include <string>
#include <vector>
#include "crypto/X509Cert.h"

namespace digidoc
{
class Signer;
class X509Cert;

struct TSAInfo {
X509Cert cert;
std::string time;
};

class DIGIDOCPP_EXPORT Signature
{
public:
Expand Down Expand Up @@ -86,18 +91,18 @@ namespace digidoc
virtual std::string countryName() const;
virtual std::vector<std::string> signerRoles() const;

//TM profile properties
// TM profile properties
virtual std::string OCSPProducedAt() const;
virtual X509Cert OCSPCertificate() const;
DIGIDOCPP_DEPRECATED virtual std::vector<unsigned char> 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;
Expand All @@ -114,6 +119,9 @@ namespace digidoc
// DSig properties
virtual void extendSignatureProfile(Signer *signer);

//TSA profile properties
virtual std::vector<TSAInfo> ArchiveTimeStamps() const;

protected:
Signature();

Expand Down
3 changes: 3 additions & 0 deletions src/SignatureXAdES_B.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -344,6 +344,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
72 changes: 28 additions & 44 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 All @@ -64,7 +64,7 @@ void SignatureXAdES_LTA::calcArchiveDigest(const Digest &digest, string_view can
if(file == files.cend())
THROW("Filed to find reference URI in container");

static_cast<const DataFilePrivate*>(*file)->digest(digest);
dynamic_cast<const DataFilePrivate*>(*file)->digest(digest);
}

for(const auto *name: {"SignedInfo", "SignatureValue", "KeyInfo"})
Expand All @@ -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 @@ -157,9 +138,12 @@ void SignatureXAdES_LTA::validate(const string &policy) const
auto ts = unsignedSignatureProperties()/ArchiveTimeStamp;
if(!ts)
THROW("Missing ArchiveTimeStamp element");
verifyTS(ts, exception, [this](const 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);
}
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 @@ -141,6 +141,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
Loading
Loading