Skip to content
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
37 changes: 32 additions & 5 deletions libdigidocpp.i
Original file line number Diff line number Diff line change
Expand Up @@ -102,15 +102,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 @@ -120,7 +122,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($csinput, cPtr$csinput);"
) std::vector<unsigned char> "handleRef$csinput"
Expand All @@ -132,6 +134,14 @@ static std::vector<unsigned char>* SWIG_JavaArrayToVectorUnsignedChar(JNIEnv *je
global::System.IntPtr cPtr = $imcall;$excode
return new System.Security.Cryptography.X509Certificates.X509Certificate2($modulePINVOKE.To_ByteArray(cPtr));
}
%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.operator std::vector<unsigned char>()); %}

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 @@ -201,9 +215,14 @@ static std::vector<unsigned char>* SWIG_JavaArrayToVectorUnsignedChar(JNIEnv *je
// std::unique_ptr is since swig 4.1
%ignore digidoc::Container::createPtr;
%ignore digidoc::Container::openPtr;
%ignore digidoc::Container::extendContainerValidity;

%newobject digidoc::Container::open;
%newobject digidoc::Container::create;
%newobject digidoc::Container::extendContainerValidity;

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

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

Expand Down Expand Up @@ -262,8 +281,16 @@ 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>;

%rename("%s") digidoc::Container::extendContainerValidity;

%extend digidoc::Container {
static Container* extendContainerValidity(Container &doc, Signer *signer)
{
return digidoc::Container::extendContainerValidity(doc, signer).release();
}

static digidoc::Container* open(const std::string &path, digidoc::ContainerOpenCB *cb)
{
return digidoc::Container::openPtr(path, cb).release();
Expand Down
186 changes: 82 additions & 104 deletions src/ASiC_E.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -51,21 +51,89 @@ class ASiC_E::Private
/**
* Initialize BDOC container.
*/
ASiC_E::ASiC_E()
: ASiContainer(MIMETYPE_ASIC_E)
ASiC_E::ASiC_E(const string &path, bool create)
: ASiContainer(path, MIMETYPE_ASIC_E)
, d(make_unique<Private>())
{
}
if(create)
return;
auto z = load(true, {MIMETYPE_ASIC_E, MIMETYPE_ADOC});

/**
* Opens ASiC container from a file
*/
ASiC_E::ASiC_E(const string &path)
: ASiContainer(MIMETYPE_ASIC_E)
, d(make_unique<Private>())
{
auto zip = load(path, true, {MIMETYPE_ASIC_E, MIMETYPE_ADOC});
parseManifestAndLoadFiles(zip);
try
{
auto manifestdata = z.extract<stringstream>("META-INF/manifest.xml");
auto doc = XMLDocument::openStream(manifestdata, {"manifest", MANIFEST_NS});
doc.validateSchema(File::path(Conf::instance()->xsdPath(), "OpenDocument_manifest_v1_2.xsd"));

set<string_view> manifestFiles;
bool mimeFound = false;
for(auto file = doc/"file-entry"; file; file++)
{
auto full_path = file[{"full-path", MANIFEST_NS}];
auto media_type = file[{"media-type", MANIFEST_NS}];
DEBUG("full_path = '%s', media_type = '%s'", full_path.data(), media_type.data());

if(manifestFiles.find(full_path) != manifestFiles.end())
THROW("Manifest multiple entries defined for file '%s'.", full_path.data());

// ODF does not specify that mimetype should be first in manifest
if(full_path == "/")
{
if(mediaType() != media_type)
THROW("Manifest has incorrect container media type defined '%s', expecting '%s'.", media_type.data(), mediaType().c_str());
mimeFound = true;
continue;
}
if(full_path.back() == '/') // Skip Directory entries
continue;

manifestFiles.insert(full_path);
if(mediaType() == MIMETYPE_ADOC &&
(full_path.compare(0, 9, "META-INF/") == 0 ||
full_path.compare(0, 9, "metadata/") == 0))
d->metadata.push_back(new DataFilePrivate(dataStream(full_path, z), string(full_path), string(media_type)));
else
addDataFilePrivate(dataStream(full_path, z), string(full_path), string(media_type));
}
if(!mimeFound)
THROW("Manifest is missing mediatype file entry.");

for(const string &file: z.list())
{
/**
* http://www.etsi.org/deliver/etsi_ts/102900_102999/102918/01.03.01_60/ts_102918v010301p.pdf
* 6.2.2 Contents of Container
* 3) The root element of each "*signatures*.xml" content shall be either:
*/
if(file.compare(0, 9, "META-INF/") == 0 &&
file.find("signatures") != string::npos)
{
try
{
auto data = z.extract<stringstream>(file);
loadSignatures(data, file);
}
catch(const Exception &e)
{
THROW_CAUSE(e, "Failed to parse signature '%s'.", file.c_str());
}
continue;
}

if(file == "mimetype" || file.compare(0, 8,"META-INF") == 0)
continue;
if(manifestFiles.count(file) == 0)
THROW("File '%s' found in container is not described in manifest.", file.c_str());
}
}
catch(const Exception &e)
{
THROW_CAUSE(e, "Failed to parse manifest");
}
catch(...)
{
THROW("Failed to parse manifest XML: Unknown exception");
}
}

ASiC_E::~ASiC_E()
Expand Down Expand Up @@ -110,9 +178,7 @@ void ASiC_E::save(const ZipSerialize &s)
unique_ptr<Container> ASiC_E::createInternal(const string &path)
{
DEBUG("ASiC_E::createInternal(%s)", path.c_str());
unique_ptr<ASiC_E> doc = unique_ptr<ASiC_E>(new ASiC_E);
doc->zpath(path);
return doc;
return unique_ptr<Container>(new ASiC_E(path, true));
}

/**
Expand Down Expand Up @@ -146,7 +212,7 @@ void ASiC_E::canSave()
unique_ptr<Container> ASiC_E::openInternal(const string &path)
{
DEBUG("ASiC_E::openInternal(%s)", path.c_str());
return unique_ptr<Container>(new ASiC_E(path));
return unique_ptr<Container>(new ASiC_E(path, false));
}

void ASiC_E::loadSignatures(istream &data, const string &file)
Expand All @@ -157,94 +223,6 @@ void ASiC_E::loadSignatures(istream &data, const string &file)
addSignature(make_unique<SignatureXAdES_LTA>(signatures, s, this));
}

/**
* Parses manifest file and checks that files described in manifest exist, also
* checks that no extra file do exist that are not described in manifest.xml.
*
* @param path directory on disk of the BDOC container.
* @throws Exception exception is thrown if the manifest.xml file parsing failed.
*/
void ASiC_E::parseManifestAndLoadFiles(const ZipSerialize &z)
{
DEBUG("ASiC_E::readManifest()");

try
{
auto manifestdata = z.extract<stringstream>("META-INF/manifest.xml");
auto doc = XMLDocument::openStream(manifestdata, {"manifest", MANIFEST_NS});
doc.validateSchema(File::path(Conf::instance()->xsdPath(), "OpenDocument_manifest_v1_2.xsd"));

set<string_view> manifestFiles;
bool mimeFound = false;
for(auto file = doc/"file-entry"; file; file++)
{
auto full_path = file[{"full-path", MANIFEST_NS}];
auto media_type = file[{"media-type", MANIFEST_NS}];
DEBUG("full_path = '%s', media_type = '%s'", full_path.data(), media_type.data());

if(manifestFiles.find(full_path) != manifestFiles.end())
THROW("Manifest multiple entries defined for file '%s'.", full_path.data());

// ODF does not specify that mimetype should be first in manifest
if(full_path == "/")
{
if(mediaType() != media_type)
THROW("Manifest has incorrect container media type defined '%s', expecting '%s'.", media_type.data(), mediaType().c_str());
mimeFound = true;
continue;
}
if(full_path.back() == '/') // Skip Directory entries
continue;

manifestFiles.insert(full_path);
if(mediaType() == MIMETYPE_ADOC &&
(full_path.compare(0, 9, "META-INF/") == 0 ||
full_path.compare(0, 9, "metadata/") == 0))
d->metadata.push_back(new DataFilePrivate(dataStream(full_path, z), string(full_path), string(media_type)));
else
addDataFilePrivate(dataStream(full_path, z), string(full_path), string(media_type));
}
if(!mimeFound)
THROW("Manifest is missing mediatype file entry.");

for(const string &file: z.list())
{
/**
* http://www.etsi.org/deliver/etsi_ts/102900_102999/102918/01.03.01_60/ts_102918v010301p.pdf
* 6.2.2 Contents of Container
* 3) The root element of each "*signatures*.xml" content shall be either:
*/
if(file.compare(0, 9, "META-INF/") == 0 &&
file.find("signatures") != string::npos)
{
try
{
auto data = z.extract<stringstream>(file);
loadSignatures(data, file);
}
catch(const Exception &e)
{
THROW_CAUSE(e, "Failed to parse signature '%s'.", file.c_str());
}
continue;
}

if(file == "mimetype" || file.compare(0, 8,"META-INF") == 0)
continue;
if(manifestFiles.count(file) == 0)
THROW("File '%s' found in container is not described in manifest.", file.c_str());
}
}
catch(const Exception &e)
{
THROW_CAUSE(e, "Failed to parse manifest");
}
catch(...)
{
THROW("Failed to parse manifest XML: Unknown exception");
}
}

Signature* ASiC_E::prepareSignature(Signer *signer)
{
if(mediaType() != MIMETYPE_ASIC_E)
Expand Down
4 changes: 1 addition & 3 deletions src/ASiC_E.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,12 +50,10 @@ namespace digidoc
static std::unique_ptr<Container> openInternal(const std::string &path);

private:
ASiC_E();
ASiC_E(const std::string &path);
ASiC_E(const std::string &path, bool create);
DISABLE_COPY(ASiC_E);
void canSave() final;
void loadSignatures(std::istream &data, const std::string &file);
void parseManifestAndLoadFiles(const ZipSerialize &z);
void save(const ZipSerialize &s) final;

class Private;
Expand Down
Loading
Loading