Skip to content

Commit 1c99e5d

Browse files
authored
Fix Java/C# memory leaks and handle X509Cert as native type where possible (#631)
IB-8235 Signed-off-by: Raul Metsma <[email protected]>
1 parent 5d0dfb4 commit 1c99e5d

File tree

5 files changed

+85
-136
lines changed

5 files changed

+85
-136
lines changed

examples/DigiDocCSharp/DigiDocCSharp.csproj

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,8 @@
22
<PropertyGroup>
33
<TargetFramework>net472</TargetFramework>
44
<OutputType>Exe</OutputType>
5-
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
6-
<AssemblyVersion>0.4.0.0</AssemblyVersion>
7-
<FileVersion>0.4.0.0</FileVersion>
5+
<AssemblyVersion>0.5.0.0</AssemblyVersion>
6+
<FileVersion>0.5.0.0</FileVersion>
87
<Copyright>Copyright © 2015</Copyright>
98
</PropertyGroup>
109
<PropertyGroup Condition=" '$(OS)' == 'Windows_NT' ">

examples/DigiDocCSharp/Program.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -154,8 +154,7 @@ private static void Websign(string[] args)
154154
b.addDataFile(args[i], "application/octet-stream");
155155
}
156156

157-
X509Certificate cert = new X509Certificate();
158-
cert.Import(args[args.Length - 2]);
157+
var cert = new X509Certificate(args[args.Length - 2]);
159158
Signature c = b.prepareWebSignature(cert.Export(X509ContentType.Cert), "time-stamp");
160159
Console.WriteLine("Signature method: " + c.signatureMethod());
161160
Console.WriteLine("Digest to sign: " + BitConverter.ToString(c.dataToSign()).Replace("-", string.Empty));
@@ -207,7 +206,8 @@ private static void Verify(string file)
207206
Console.WriteLine();
208207

209208
Console.WriteLine("Time: " + s.trustedSigningTime());
210-
Console.WriteLine("Cert: " + new X509Certificate2(s.signingCertificateDer()).Subject);
209+
Console.WriteLine("Cert: " + s.signingCertificate().Subject);
210+
Console.WriteLine("TimeStamp: " + s.TimeStampCertificate().Subject);
211211

212212
s.validate();
213213
Console.WriteLine("Signature is valid");

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

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,8 @@ static void verify(String file) {
149149
System.out.println();
150150

151151
System.out.println("Time: " + signature.trustedSigningTime());
152-
System.out.println("Cert: " + toX509(signature.signingCertificateDer()).getSubjectDN().toString());
152+
System.out.println("Cert: " + signature.signingCertificate().getSubjectDN().toString());
153+
System.out.println("TimeStamp Cert: " + signature.TimeStampCertificate().getSubjectDN().toString());
153154

154155
try
155156
{
@@ -171,7 +172,7 @@ static void verify(String file) {
171172
}
172173

173174
static void version() {
174-
System.out.println("DigiDocJAVA 0.3 libdigidocpp " + digidoc.version());
175+
System.out.println("DigiDocJAVA 0.4 libdigidocpp " + digidoc.version());
175176
}
176177

177178
static X509Certificate toX509(byte[] der) throws CertificateException {

libdigidocpp.i

Lines changed: 76 additions & 127 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,9 @@ extern "C"
6060
SWIGEXPORT int SWIGSTDCALL ByteVector_size(void *ptr) {
6161
return static_cast<std::vector<unsigned char>*>(ptr)->size();
6262
}
63+
SWIGEXPORT void SWIGSTDCALL ByteVector_free(void *ptr) {
64+
delete static_cast<std::vector<unsigned char>*>(ptr);
65+
}
6366
SWIGEXPORT void* SWIGSTDCALL ByteVector_to(unsigned char *data, int size) {
6467
return new std::vector<unsigned char>(data, data + size);
6568
}
@@ -72,112 +75,93 @@ extern "C"
7275
public static extern global::System.IntPtr ByteVector_data(global::System.IntPtr data);
7376
[global::System.Runtime.InteropServices.DllImport("$dllimport", EntryPoint="ByteVector_size")]
7477
public static extern int ByteVector_size(global::System.IntPtr data);
78+
[global::System.Runtime.InteropServices.DllImport("$dllimport", EntryPoint="ByteVector_free")]
79+
public static extern void ByteVector_free(global::System.IntPtr data);
7580
[global::System.Runtime.InteropServices.DllImport("$dllimport", EntryPoint="ByteVector_to")]
7681
public static extern global::System.IntPtr ByteVector_to(
77-
[global::System.Runtime.InteropServices.MarshalAs(global::System.Runtime.InteropServices.UnmanagedType.LPArray)]byte[] data, int size);
78-
79-
public class UTF8Marshaler : global::System.Runtime.InteropServices.ICustomMarshaler {
80-
static UTF8Marshaler static_instance = new UTF8Marshaler();
81-
82-
public global::System.IntPtr MarshalManagedToNative(object managedObj) {
83-
if (managedObj == null)
84-
return global::System.IntPtr.Zero;
85-
if (!(managedObj is string))
86-
throw new global::System.Runtime.InteropServices.MarshalDirectiveException(
87-
"UTF8Marshaler must be used on a string.");
88-
89-
// not null terminated
90-
byte[] strbuf = global::System.Text.Encoding.UTF8.GetBytes((string)managedObj);
91-
global::System.IntPtr buffer = global::System.Runtime.InteropServices.Marshal.AllocHGlobal(strbuf.Length + 1);
92-
global::System.Runtime.InteropServices.Marshal.Copy(strbuf, 0, buffer, strbuf.Length);
93-
94-
// write the terminating null
95-
global::System.Runtime.InteropServices.Marshal.WriteByte(buffer + strbuf.Length, 0);
96-
return buffer;
97-
}
98-
99-
public unsafe object MarshalNativeToManaged(global::System.IntPtr pNativeData) {
100-
byte* walk = (byte*)pNativeData;
101-
102-
// find the end of the string
103-
while (*walk != 0) {
104-
walk++;
105-
}
106-
int length = (int)(walk - (byte*)pNativeData);
107-
108-
// should not be null terminated
109-
byte[] strbuf = new byte[length];
110-
// skip the trailing null
111-
global::System.Runtime.InteropServices.Marshal.Copy((global::System.IntPtr)pNativeData, strbuf, 0, length);
112-
return global::System.Text.Encoding.UTF8.GetString(strbuf);
113-
}
114-
115-
public void CleanUpNativeData(global::System.IntPtr pNativeData) {
116-
global::System.Runtime.InteropServices.Marshal.FreeHGlobal(pNativeData);
117-
}
118-
119-
public void CleanUpManagedData(object managedObj) {
120-
}
121-
122-
public int GetNativeDataSize() {
123-
return -1;
124-
}
125-
126-
public static global::System.Runtime.InteropServices.ICustomMarshaler GetInstance(string cookie) {
127-
return static_instance;
128-
}
129-
}
82+
[global::System.Runtime.InteropServices.MarshalAs(global::System.Runtime.InteropServices.UnmanagedType.LPArray)]byte[] data, int size);
13083
%}
13184

13285
#ifdef SWIGJAVA
133-
%typemap(in) std::vector<unsigned char> %{
134-
jbyte *$input_ptr = jenv->GetByteArrayElements($input, NULL);
135-
jsize $input_size = jenv->GetArrayLength($input);
136-
std::vector<unsigned char> $1_data($input_ptr, $input_ptr+$input_size);
137-
$1 = &$1_data;
138-
jenv->ReleaseByteArrayElements($input, $input_ptr, JNI_ABORT);
139-
%}
140-
%typemap(out) std::vector<unsigned char> %{
141-
jresult = jenv->NewByteArray((&result)->size());
142-
jenv->SetByteArrayRegion(jresult, 0, (&result)->size(), (const jbyte*)(&result)->data());
143-
%}
144-
%typemap(jtype) std::vector<unsigned char> "byte[]"
86+
%fragment("SWIG_VectorUnsignedCharToJavaArray", "header") {
87+
static jbyteArray SWIG_VectorUnsignedCharToJavaArray(JNIEnv *jenv, const std::vector<unsigned char> &data) {
88+
jbyteArray jresult = JCALL1(NewByteArray, jenv, data.size());
89+
if (!jresult)
90+
return nullptr;
91+
JCALL4(SetByteArrayRegion, jenv, jresult, 0, data.size(), (const jbyte*)data.data());
92+
return jresult;
93+
}}
94+
%fragment("SWIG_JavaArrayToVectorUnsignedChar", "header") {
95+
static std::vector<unsigned char>* SWIG_JavaArrayToVectorUnsignedChar(JNIEnv *jenv, jbyteArray data) {
96+
std::vector<unsigned char> *result = new std::vector<unsigned char>(JCALL1(GetArrayLength, jenv, data));
97+
JCALL4(GetByteArrayRegion, jenv, data, 0, result->size(), (jbyte*)result->data());
98+
return result;
99+
}}
100+
%typemap(in, fragment="SWIG_JavaArrayToVectorUnsignedChar") std::vector<unsigned char>
101+
%{ $1 = SWIG_JavaArrayToVectorUnsignedChar(jenv, $input); %}
102+
%typemap(out, fragment="SWIG_VectorUnsignedCharToJavaArray") std::vector<unsigned char>, digidoc::X509Cert
103+
%{ $result = SWIG_VectorUnsignedCharToJavaArray(jenv, $1); %}
104+
%typemap(jtype) std::vector<unsigned char>, digidoc::X509Cert "byte[]"
145105
%typemap(jstype) std::vector<unsigned char> "byte[]"
146-
%typemap(jni) std::vector<unsigned char> "jbyteArray"
147-
%typemap(javain) std::vector<unsigned char> "$javainput"
106+
%typemap(jstype) digidoc::X509Cert "java.security.cert.X509Certificate"
107+
%typemap(jni) std::vector<unsigned char>, digidoc::X509Cert "jbyteArray"
108+
%typemap(javain) std::vector<unsigned char>, digidoc::X509Cert "$javainput"
148109
%typemap(javaout) std::vector<unsigned char> {
149110
return $jnicall;
150111
}
112+
%typemap(javaout, throws="java.security.cert.CertificateException, java.io.IOException") digidoc::X509Cert {
113+
byte[] der = $jnicall;
114+
java.security.cert.CertificateFactory cf = java.security.cert.CertificateFactory.getInstance("X509");
115+
try (java.io.ByteArrayInputStream is = new java.io.ByteArrayInputStream(der)) {
116+
return (java.security.cert.X509Certificate) cf.generateCertificate(is);
117+
}
118+
}
119+
151120
#elif defined(SWIGCSHARP)
152121
%typemap(cstype) std::vector<unsigned char> "byte[]"
153-
%typemap(csin,
154-
pre= " global::System.IntPtr cPtr$csinput = digidocPINVOKE.ByteVector_to($csinput, $csinput.Length);
155-
global::System.Runtime.InteropServices.HandleRef handleRef$csinput = new global::System.Runtime.InteropServices.HandleRef(this, cPtr$csinput);"
122+
%typemap(cstype) digidoc::X509Cert "System.Security.Cryptography.X509Certificates.X509Certificate2"
123+
%typemap(csin, pre= " global::System.IntPtr cPtr$csinput = digidocPINVOKE.ByteVector_to($csinput, $csinput.Length);
124+
var handleRef$csinput = new global::System.Runtime.InteropServices.HandleRef(this, cPtr$csinput);"
156125
) std::vector<unsigned char> "handleRef$csinput"
157126
%typemap(csout, excode=SWIGEXCODE) std::vector<unsigned char> {
158-
global::System.IntPtr data = $imcall;$excode
159-
byte[] result = new byte[$modulePINVOKE.ByteVector_size(data)];
160-
global::System.Runtime.InteropServices.Marshal.Copy($modulePINVOKE.ByteVector_data(data), result, 0, result.Length);
161-
return result;
162-
}
163-
#elif defined(SWIGPYTHON)
164-
%typemap(in) std::vector<unsigned char> %{
165-
if (PyBytes_Check($input)) {
166-
const char *data = PyBytes_AsString($input);
167-
$1 = new std::vector<unsigned char>(data, data + PyBytes_Size($input));
168-
} else if (PyString_Check($input)) {
169-
const char *data = PyString_AsString($input);
170-
$1 = new std::vector<unsigned char>(data, data + PyString_Size($input));
171-
} else {
172-
PyErr_SetString(PyExc_TypeError, "not a bytes");
173-
SWIG_fail;
127+
global::System.IntPtr cPtr = $imcall;$excode
128+
byte[] result = new byte[$modulePINVOKE.ByteVector_size(cPtr)];
129+
global::System.Runtime.InteropServices.Marshal.Copy($modulePINVOKE.ByteVector_data(cPtr), result, 0, result.Length);
130+
$modulePINVOKE.ByteVector_free(cPtr);
131+
return result;
132+
}
133+
%typemap(csout, excode=SWIGEXCODE) digidoc::X509Cert {
134+
global::System.IntPtr cPtr = $imcall;$excode
135+
byte[] der = new byte[$modulePINVOKE.ByteVector_size(cPtr)];
136+
global::System.Runtime.InteropServices.Marshal.Copy($modulePINVOKE.ByteVector_data(cPtr), der, 0, der.Length);
137+
$modulePINVOKE.ByteVector_free(cPtr);
138+
return new System.Security.Cryptography.X509Certificates.X509Certificate2(der);
174139
}
175-
%}
140+
%typemap(out) std::vector<unsigned char> %{ $result = new std::vector<unsigned char>(std::move($1)); %}
141+
%typemap(out) digidoc::X509Cert %{ $result = new std::vector<unsigned char>($1); %}
142+
143+
#elif defined(SWIGPYTHON)
144+
%typemap(in) std::vector<unsigned char> %{
145+
if (PyBytes_Check($input)) {
146+
const char *data = PyBytes_AsString($input);
147+
$1 = new std::vector<unsigned char>(data, data + PyBytes_Size($input));
148+
} else if (PyString_Check($input)) {
149+
const char *data = PyString_AsString($input);
150+
$1 = new std::vector<unsigned char>(data, data + PyString_Size($input));
151+
} else {
152+
PyErr_SetString(PyExc_TypeError, "not a bytes");
153+
SWIG_fail;
154+
}
155+
%}
176156
%typemap(out) std::vector<unsigned char>
177157
%{ $result = PyBytes_FromStringAndSize((const char*)(&result)->data(), (&result)->size()); %}
158+
%typemap(out) digidoc::X509Cert {
159+
std::vector<unsigned char> temp = $1;
160+
$result = PyBytes_FromStringAndSize((const char*)temp.data(), temp.size());
161+
}
162+
#endif
178163
%typemap(freearg) std::vector<unsigned char>
179164
%{ delete $1; %}
180-
#endif
181165
%apply std::vector<unsigned char> { std::vector<unsigned char> const & };
182166

183167
%exception %{
@@ -208,11 +192,6 @@ extern "C"
208192
%ignore digidoc::ConfV2::verifyServiceCert;
209193
%ignore digidoc::ConfV4::verifyServiceCerts;
210194
%ignore digidoc::ConfV5::TSCerts;
211-
%ignore digidoc::Signer::cert;
212-
%ignore digidoc::Signature::signingCertificate;
213-
%ignore digidoc::Signature::OCSPCertificate;
214-
%ignore digidoc::Signature::TimeStampCertificate;
215-
%ignore digidoc::Signature::ArchiveTimeStampCertificate;
216195
// hide stream methods, swig cannot generate usable wrappers
217196
%ignore digidoc::DataFile::saveAs(std::ostream &os) const;
218197
%ignore digidoc::Container::addAdESSignature(std::istream &signature);
@@ -260,15 +239,10 @@ def transfer(self):
260239
%include "std_vector.i"
261240
%include "std_map.i"
262241
#ifdef SWIGCSHARP
263-
namespace std {
264-
%typemap(imtype,
265-
inattributes="[global::System.Runtime.InteropServices.MarshalAs(global::System.Runtime.InteropServices.UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(UTF8Marshaler))]",
266-
outattributes="[return: global::System.Runtime.InteropServices.MarshalAs(global::System.Runtime.InteropServices.UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(UTF8Marshaler))]")
267-
string "string"
268-
%typemap(imtype,
269-
inattributes="[global::System.Runtime.InteropServices.MarshalAs(global::System.Runtime.InteropServices.UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(UTF8Marshaler))]",
270-
outattributes="[return: global::System.Runtime.InteropServices.MarshalAs(global::System.Runtime.InteropServices.UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(UTF8Marshaler))]") const string & "string"
271-
}
242+
%typemap(imtype,
243+
inattributes="[global::System.Runtime.InteropServices.MarshalAs(global::System.Runtime.InteropServices.UnmanagedType.LPUTF8Str)]",
244+
outattributes="[return: global::System.Runtime.InteropServices.MarshalAs(global::System.Runtime.InteropServices.UnmanagedType.LPUTF8Str)]")
245+
std::string, const std::string & "string"
272246
#endif
273247

274248
// Handle DigiDoc Export declarations
@@ -294,31 +268,6 @@ namespace std {
294268
%template(DataFiles) std::vector<digidoc::DataFile*>;
295269
%template(Signatures) std::vector<digidoc::Signature*>;
296270

297-
// override X509Cert methods to return byte array
298-
%extend digidoc::Signer {
299-
std::vector<unsigned char> cert() const
300-
{
301-
return $self->cert();
302-
}
303-
}
304-
%extend digidoc::Signature {
305-
std::vector<unsigned char> signingCertificateDer() const
306-
{
307-
return $self->signingCertificate();
308-
}
309-
std::vector<unsigned char> OCSPCertificateDer() const
310-
{
311-
return $self->OCSPCertificate();
312-
}
313-
std::vector<unsigned char> TimeStampCertificateDer() const
314-
{
315-
return $self->TimeStampCertificate();
316-
}
317-
std::vector<unsigned char> ArchiveTimeStampCertificateDer() const
318-
{
319-
return $self->ArchiveTimeStampCertificate();
320-
}
321-
}
322271
%extend digidoc::Container {
323272
static digidoc::Container* open(const std::string &path, digidoc::ContainerOpenCB *cb)
324273
{

src/CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -202,7 +202,7 @@ if(SWIG_FOUND)
202202
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/digidoc.py DESTINATION ${Python3_SITELIB})
203203
endif()
204204

205-
set(CMAKE_SWIG_FLAGS -dllimport digidoc_csharp -namespace digidoc)
205+
set(CMAKE_SWIG_FLAGS -namespace digidoc)
206206
set(CMAKE_SWIG_OUTDIR ${CMAKE_CURRENT_BINARY_DIR}/csharp)
207207
swig_add_library(digidoc_csharp LANGUAGE csharp SOURCES ../libdigidocpp.i)
208208
target_compile_definitions(digidoc_csharp PRIVATE TARGET_NAME="$<TARGET_NAME:digidoc_csharp>")

0 commit comments

Comments
 (0)