Skip to content

Commit

Permalink
Extend XAdES LTA signatures
Browse files Browse the repository at this point in the history
IB-7995

Signed-off-by: Raul Metsma <[email protected]>
  • Loading branch information
metsma committed Sep 9, 2024
1 parent 72437de commit 53e1842
Show file tree
Hide file tree
Showing 20 changed files with 331 additions and 263 deletions.
4 changes: 2 additions & 2 deletions examples/DigiDocCSharp/DigiDocCSharp.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
<TargetFramework>net472</TargetFramework>
<OutputType>Exe</OutputType>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<AssemblyVersion>0.4.0.0</AssemblyVersion>
<FileVersion>0.4.0.0</FileVersion>
<AssemblyVersion>0.5.0.0</AssemblyVersion>
<FileVersion>0.5.0.0</FileVersion>
<Copyright>Copyright © 2015</Copyright>
</PropertyGroup>
<PropertyGroup Condition=" '$(OS)' == 'Windows_NT' ">
Expand Down
11 changes: 8 additions & 3 deletions examples/DigiDocCSharp/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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));
Expand Down Expand Up @@ -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");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
{
Expand All @@ -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 {
Expand Down
206 changes: 89 additions & 117 deletions libdigidocpp.i
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,9 @@ extern "C"
SWIGEXPORT int SWIGSTDCALL ByteVector_size(void *ptr) {
return static_cast<std::vector<unsigned char>*>(ptr)->size();
}
SWIGEXPORT void SWIGSTDCALL ByteVector_free(void *ptr) {
delete static_cast<std::vector<unsigned char>*>(ptr);
}
SWIGEXPORT void* SWIGSTDCALL ByteVector_to(unsigned char *data, int size) {
return new std::vector<unsigned char>(data, data + size);
}
Expand All @@ -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
Expand All @@ -138,45 +91,95 @@ extern "C"
jenv->ReleaseByteArrayElements($input, $input_ptr, JNI_ABORT);
%}
%typemap(out) std::vector<unsigned char> %{
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<unsigned char> "byte[]"
%typemap(out) digidoc::X509Cert %{
std::vector<unsigned char> temp = $1;
$result = jenv->NewByteArray(temp.size());
jenv->SetByteArrayRegion($result, 0, temp.size(), (const jbyte*)temp.data());
%}
%typemap(out) digidoc::X509Cert * %{
std::vector<unsigned char> temp = *$1;
$result = jenv->NewByteArray(temp.size());
jenv->SetByteArrayRegion($result, 0, temp.size(), (const jbyte*)temp.data());
%}
%typemap(jtype) std::vector<unsigned char>, digidoc::X509Cert, digidoc::X509Cert * "byte[]"
%typemap(jstype) std::vector<unsigned char> "byte[]"
%typemap(jni) std::vector<unsigned char> "jbyteArray"
%typemap(javain) std::vector<unsigned char> "$javainput"
%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, 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<unsigned char> "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<unsigned char> "handleRef$csinput"
%typemap(freearg) std::vector<unsigned char>
%{ delete $1; %}
%typemap(csout, excode=SWIGEXCODE) std::vector<unsigned char> {
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<unsigned char> %{
if (PyBytes_Check($input)) {
const char *data = PyBytes_AsString($input);
$1 = new std::vector<unsigned char>(data, data + PyBytes_Size($input));
} else if (PyString_Check($input)) {
const char *data = PyString_AsString($input);
$1 = new std::vector<unsigned char>(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<unsigned char> %{ $result = new std::vector<unsigned char>(std::move($1)); %}
%typemap(out) digidoc::X509Cert %{ $result = new std::vector<unsigned char>($1); %}

#elif defined(SWIGPYTHON)
%typemap(in) std::vector<unsigned char> %{
if (PyBytes_Check($input)) {
const char *data = PyBytes_AsString($input);
$1 = new std::vector<unsigned char>(data, data + PyBytes_Size($input));
} else if (PyString_Check($input)) {
const char *data = PyString_AsString($input);
$1 = new std::vector<unsigned char>(data, data + PyString_Size($input));
} else {
PyErr_SetString(PyExc_TypeError, "not a bytes");
SWIG_fail;
}
%}
%typemap(out) std::vector<unsigned char>
%{ $result = PyBytes_FromStringAndSize((const char*)(&result)->data(), (&result)->size()); %}
%typemap(freearg) std::vector<unsigned char>
%{ delete $1; %}
%typemap(out) digidoc::X509Cert {
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
%apply std::vector<unsigned char> { std::vector<unsigned char> const & };

Expand Down Expand Up @@ -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);
Expand All @@ -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 %{
Expand Down Expand Up @@ -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
Expand All @@ -293,32 +289,8 @@ namespace std {
%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>;

// override X509Cert methods to return byte array
%extend digidoc::Signer {
std::vector<unsigned char> cert() const
{
return $self->cert();
}
}
%extend digidoc::Signature {
std::vector<unsigned char> signingCertificateDer() const
{
return $self->signingCertificate();
}
std::vector<unsigned char> OCSPCertificateDer() const
{
return $self->OCSPCertificate();
}
std::vector<unsigned char> TimeStampCertificateDer() const
{
return $self->TimeStampCertificate();
}
std::vector<unsigned char> ArchiveTimeStampCertificateDer() const
{
return $self->ArchiveTimeStampCertificate();
}
}
%extend digidoc::Container {
static digidoc::Container* open(const std::string &path, digidoc::ContainerOpenCB *cb)
{
Expand Down
11 changes: 8 additions & 3 deletions src/DataFile.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -98,9 +98,8 @@ DataFilePrivate::DataFilePrivate(unique_ptr<istream> &&is, string filename, stri
m_size = pos < 0 ? 0 : (unsigned long)pos;
}

vector<unsigned char> DataFilePrivate::calcDigest(const string &method) const
void DataFilePrivate::digest(const Digest &digest) const
{
Digest digest(method);
array<unsigned char, 10240> buf{};
m_is->clear();
m_is->seekg(0);
Expand All @@ -110,7 +109,13 @@ vector<unsigned char> 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<unsigned char> DataFilePrivate::calcDigest(const string &method) const
{
Digest d(method);
digest(d);
return d.result();
}

void DataFilePrivate::saveAs(const string& path) const
Expand Down
2 changes: 2 additions & 0 deletions src/DataFile_p.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
namespace digidoc
{

class Digest;
class DataFilePrivate final: public DataFile
{
public:
Expand All @@ -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<unsigned char> calcDigest(const std::string &method) const final;
void saveAs(std::ostream &os) const final;
void saveAs(const std::string& path) const final;
Expand Down
2 changes: 1 addition & 1 deletion src/SiVaContainer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -362,7 +362,7 @@ unique_ptr<istream> 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()));
Expand Down
5 changes: 5 additions & 0 deletions src/Signature.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,11 @@ X509Cert Signature::ArchiveTimeStampCertificate() const { return X509Cert(); }
*/
string Signature::ArchiveTimeStampTime() const { return {}; }

/**
* Returns signature Archive TimeStampTokens.
*/
vector<TSAInfo> Signature::ArchiveTimeStamps() const { return {}; }

struct Signature::Validator::Private
{
Status result = Valid;
Expand Down
Loading

0 comments on commit 53e1842

Please sign in to comment.