Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
O
onlyoffice_core
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Boris Kocherov
onlyoffice_core
Commits
ed7661b9
Commit
ed7661b9
authored
May 16, 2017
by
Oleg Korshul
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
ooxmlsignature library & test (full work version)
parent
f582a9b6
Changes
15
Show whitespace changes
Inline
Side-by-side
Showing
15 changed files
with
275 additions
and
128 deletions
+275
-128
DesktopEditor/xml/build/qt/libxml2.pri
DesktopEditor/xml/build/qt/libxml2.pri
+15
-0
DesktopEditor/xmlsec/src/XmlCertificate.h
DesktopEditor/xmlsec/src/XmlCertificate.h
+0
-17
DesktopEditor/xmlsec/src/include/OOXMLSigner.h
DesktopEditor/xmlsec/src/include/OOXMLSigner.h
+23
-0
DesktopEditor/xmlsec/src/include/OOXMLVerifier.h
DesktopEditor/xmlsec/src/include/OOXMLVerifier.h
+48
-0
DesktopEditor/xmlsec/src/include/XmlCertificate.h
DesktopEditor/xmlsec/src/include/XmlCertificate.h
+10
-18
DesktopEditor/xmlsec/src/src/OOXMLSigner.cpp
DesktopEditor/xmlsec/src/src/OOXMLSigner.cpp
+34
-10
DesktopEditor/xmlsec/src/src/OOXMLVerifier.cpp
DesktopEditor/xmlsec/src/src/OOXMLVerifier.cpp
+71
-22
DesktopEditor/xmlsec/src/src/XmlCanonicalizator.h
DesktopEditor/xmlsec/src/src/XmlCanonicalizator.h
+5
-5
DesktopEditor/xmlsec/src/src/XmlCertificate.cpp
DesktopEditor/xmlsec/src/src/XmlCertificate.cpp
+26
-0
DesktopEditor/xmlsec/src/src/XmlRels.h
DesktopEditor/xmlsec/src/src/XmlRels.h
+0
-0
DesktopEditor/xmlsec/src/src/XmlSigner_mscrypto.h
DesktopEditor/xmlsec/src/src/XmlSigner_mscrypto.h
+4
-1
DesktopEditor/xmlsec/src/src/XmlTransform.cpp
DesktopEditor/xmlsec/src/src/XmlTransform.cpp
+21
-0
DesktopEditor/xmlsec/src/src/XmlTransform.h
DesktopEditor/xmlsec/src/src/XmlTransform.h
+0
-20
DesktopEditor/xmlsec/test/windows_list_serts/main.cpp
DesktopEditor/xmlsec/test/windows_list_serts/main.cpp
+17
-16
DesktopEditor/xmlsec/test/windows_list_serts/test.pro
DesktopEditor/xmlsec/test/windows_list_serts/test.pro
+1
-19
No files found.
DesktopEditor/xml/build/qt/libxml2.pri
View file @
ed7661b9
DEFINES += HAVE_VA_COPY
core_static_link_xml_full {
DEFINES += \
LIBXML_READER_ENABLED \
LIBXML_PUSH_ENABLED \
LIBXML_HTML_ENABLED \
LIBXML_XPATH_ENABLED \
LIBXML_OUTPUT_ENABLED \
LIBXML_C14N_ENABLED \
LIBXML_SAX1_ENABLED \
LIBXML_TREE_ENABLED \
LIBXML_XPTR_ENABLED \
IN_LIBXML \
LIBXML_STATIC
}
INCLUDEPATH += \
$$PWD/../../libxml2/include \
$$PWD/../../libxml2/include/libxml \
...
...
DesktopEditor/xmlsec/src/XmlCertificate.h
deleted
100644 → 0
View file @
f582a9b6
#ifndef _XMLSIGNER_CERTIFICATE_H_
#define _XMLSIGNER_CERTIFICATE_H_
#ifdef WIN32
#include "XmlSigner_mscrypto.h"
#define CCertificate CCertificate_mscrypto
#endif
#if defined(_LINUX) && !defined(_MAC)
#endif
#ifdef _MAC
#endif
#endif // _XMLSIGNER_CERTIFICATE_H_
DesktopEditor/xmlsec/src/include/OOXMLSigner.h
0 → 100644
View file @
ed7661b9
#ifndef _XML_OOXMLSIGNER_H_
#define _XML_OOXMLSIGNER_H_
#include "./XmlCertificate.h"
class
COOXMLSigner_private
;
class
Q_DECL_EXPORT
COOXMLSigner
{
public:
COOXMLSigner
(
const
std
::
wstring
&
sFolder
,
ICertificate
*
pContext
);
~
COOXMLSigner
();
void
SetGuid
(
const
std
::
wstring
&
guid
);
void
SetImageValid
(
const
std
::
wstring
&
file
);
void
SetImageInvalid
(
const
std
::
wstring
&
file
);
void
Sign
();
private:
COOXMLSigner_private
*
m_internal
;
};
#endif //_XML_OOXMLSIGNER_H_
DesktopEditor/xmlsec/src/include/OOXMLVerifier.h
0 → 100644
View file @
ed7661b9
#ifndef _XML_OOXMLVERIFIER_H_
#define _XML_OOXMLVERIFIER_H_
#include "./XmlCertificate.h"
#define OOXML_SIGNATURE_VALID 0
#define OOXML_SIGNATURE_INVALID 1
#define OOXML_SIGNATURE_NOTSUPPORTED 2
#define OOXML_SIGNATURE_BAD 3
class
COOXMLSignature_private
;
class
Q_DECL_EXPORT
COOXMLSignature
{
public:
COOXMLSignature
();
~
COOXMLSignature
();
public:
int
GetValid
();
std
::
string
GetGuid
();
ICertificate
*
GetCertificate
();
std
::
string
GetImageValidBase64
();
std
::
string
GetImageInvalidBase64
();
public:
void
Check
();
friend
class
COOXMLVerifier_private
;
friend
class
COOXMLVerifier
;
private:
COOXMLSignature_private
*
m_internal
;
};
class
COOXMLVerifier_private
;
class
Q_DECL_EXPORT
COOXMLVerifier
{
public:
COOXMLVerifier
(
const
std
::
wstring
&
sFolder
);
~
COOXMLVerifier
();
int
GetSignatureCount
();
COOXMLSignature
*
GetSignature
(
const
int
&
index
);
private:
COOXMLVerifier_private
*
m_internal
;
};
#endif //_XML_OOXMLVERIFIER_H_
DesktopEditor/xmlsec/src/
XmlSignerBas
e.h
→
DesktopEditor/xmlsec/src/
include/XmlCertificat
e.h
View file @
ed7661b9
#ifndef _XMLSIGNER_BASE_H_
#define _XMLSIGNER_BASE_H_
#include "../../common/File.h"
#include "../../common/BigInteger.h"
#ifndef _XML_SERTIFICATE_BASE_H_
#define _XML_SERTIFICATE_BASE_H_
#include <string>
#include <vector>
#include
<map>
#include
"../../../common/base_export.h"
#define OOXML_HASH_ALG_SHA1 0
#define OOXML_HASH_ALG_INVALID 1
class
ICertificate
class
Q_DECL_EXPORT
ICertificate
{
public:
ICertificate
()
...
...
@@ -37,19 +34,14 @@ public:
virtual
bool
Verify
(
std
::
string
&
sXml
,
std
::
string
&
sXmlSignature
,
int
nAlg
)
=
0
;
virtual
bool
LoadFromBase64Data
(
const
std
::
string
&
data
)
=
0
;
virtual
int
ShowCertificate
()
=
0
;
public:
virtual
bool
ShowSelectDialog
()
=
0
;
virtual
int
ShowCertificate
()
=
0
;
static
int
GetOOXMLHashAlg
(
const
std
::
string
&
sAlg
)
{
if
(
"http://www.w3.org/2000/09/xmldsig#rsa-sha1"
==
sAlg
||
"http://www.w3.org/2000/09/xmldsig#sha1"
==
sAlg
)
return
OOXML_HASH_ALG_SHA1
;
return
OOXML_HASH_ALG_INVALID
;
}
public:
static
int
GetOOXMLHashAlg
(
const
std
::
string
&
sAlg
);
static
ICertificate
*
CreateInstance
();
};
#endif // _XML
SIGNER
_BASE_H_
#endif // _XML
_SERTIFICATE
_BASE_H_
DesktopEditor/xmlsec/src/
OOXMLSigner.h
→
DesktopEditor/xmlsec/src/
src/OOXMLSigner.cpp
View file @
ed7661b9
#i
fndef _XML_OOXMLSIGNER_H_
#
define _XML_OOXMLSIGNER_H_
#i
nclude "./../include/OOXMLSigner.h"
#
include "./../src/XmlTransform.h"
#include "./XmlCanonicalizator.h"
#include "./XmlSignerBase.h"
#include "./XmlTransform.h"
class
COOXMLSigner
class
COOXMLSigner_private
{
public:
ICertificate
*
m_certificate
;
...
...
@@ -25,7 +21,7 @@ public:
std
::
wstring
m_guid
;
public:
COOXMLSigner
(
const
std
::
wstring
&
sFolder
,
ICertificate
*
pContext
)
COOXMLSigner
_private
(
const
std
::
wstring
&
sFolder
,
ICertificate
*
pContext
)
{
m_sFolder
=
sFolder
;
m_certificate
=
pContext
;
...
...
@@ -35,7 +31,7 @@ public:
m_signed_info
.
WriteString
(
"<CanonicalizationMethod Algorithm=
\"
http://www.w3.org/TR/2001/REC-xml-c14n-20010315
\"
/>"
);
m_signed_info
.
WriteString
(
"<SignatureMethod Algorithm=
\"
http://www.w3.org/2000/09/xmldsig#rsa-sha1
\"
/>"
);
}
~
COOXMLSigner
()
~
COOXMLSigner
_private
()
{
}
...
...
@@ -560,4 +556,32 @@ Type=\"http://schemas.openxmlformats.org/package/2006/relationships/digital-sign
}
};
#endif //_XML_OOXMLSIGNER_H_
COOXMLSigner
::
COOXMLSigner
(
const
std
::
wstring
&
sFolder
,
ICertificate
*
pContext
)
{
m_internal
=
new
COOXMLSigner_private
(
sFolder
,
pContext
);
}
COOXMLSigner
::~
COOXMLSigner
()
{
RELEASEOBJECT
(
m_internal
);
}
void
COOXMLSigner
::
SetGuid
(
const
std
::
wstring
&
guid
)
{
m_internal
->
SetGuid
(
guid
);
}
void
COOXMLSigner
::
SetImageValid
(
const
std
::
wstring
&
file
)
{
m_internal
->
SetImageValid
(
file
);
}
void
COOXMLSigner
::
SetImageInvalid
(
const
std
::
wstring
&
file
)
{
m_internal
->
SetImageInvalid
(
file
);
}
void
COOXMLSigner
::
Sign
()
{
m_internal
->
Sign
();
}
DesktopEditor/xmlsec/src/
OOXMLVerifier.h
→
DesktopEditor/xmlsec/src/
src/OOXMLVerifier.cpp
View file @
ed7661b9
#ifndef _XML_OOXMLVERIFIER_H_
#define _XML_OOXMLVERIFIER_H_
#include "./XmlCanonicalizator.h"
#include "./XmlTransform.h"
#include "./XmlCertificate.h"
#define OOXML_SIGNATURE_VALID 0
#define OOXML_SIGNATURE_INVALID 1
#define OOXML_SIGNATURE_NOTSUPPORTED 2
#define OOXML_SIGNATURE_BAD 3
#include "./../include/OOXMLVerifier.h"
class
COOXMLSignature
class
COOXMLSignature
_private
{
p
rivate
:
p
ublic
:
int
m_valid
;
std
::
string
m_guid
;
ICertificate
*
m_cert
;
...
...
@@ -22,7 +14,6 @@ private:
std
::
wstring
m_sFolder
;
private:
XmlUtils
::
CXmlNode
m_node
;
// signature file
class
CXmlStackNamespaces
...
...
@@ -133,13 +124,13 @@ private:
};
public:
COOXMLSignature
()
COOXMLSignature
_private
()
{
m_valid
=
OOXML_SIGNATURE_INVALID
;
m_guid
=
""
;
m_cert
=
NULL
;
}
~
COOXMLSignature
()
~
COOXMLSignature
_private
()
{
RELEASEOBJECT
(
m_cert
);
}
...
...
@@ -176,7 +167,7 @@ public:
m_valid
=
OOXML_SIGNATURE_NOTSUPPORTED
;
return
;
}
m_cert
=
new
CCertificat
e
();
m_cert
=
ICertificate
::
CreateInstanc
e
();
if
(
!
m_cert
->
LoadFromBase64Data
(
U_TO_UTF8
(
oNodeCert
.
GetText
())))
{
m_valid
=
OOXML_SIGNATURE_NOTSUPPORTED
;
...
...
@@ -273,7 +264,7 @@ public:
friend
class
COOXMLVerifier
;
p
rivate
:
p
ublic
:
int
CheckManifestReference
(
XmlUtils
::
CXmlNode
&
node
)
{
...
...
@@ -391,14 +382,54 @@ private:
}
};
class
COOXMLVerifier
COOXMLSignature
::
COOXMLSignature
()
{
m_internal
=
new
COOXMLSignature_private
();
}
COOXMLSignature
::~
COOXMLSignature
()
{
RELEASEOBJECT
(
m_internal
);
}
int
COOXMLSignature
::
GetValid
()
{
return
m_internal
->
GetValid
();
}
std
::
string
COOXMLSignature
::
GetGuid
()
{
return
m_internal
->
GetGuid
();
}
ICertificate
*
COOXMLSignature
::
GetCertificate
()
{
return
m_internal
->
GetCertificate
();
}
std
::
string
COOXMLSignature
::
GetImageValidBase64
()
{
return
m_internal
->
GetImageValidBase64
();
}
std
::
string
COOXMLSignature
::
GetImageInvalidBase64
()
{
return
m_internal
->
GetImageInvalidBase64
();
}
void
COOXMLSignature
::
Check
()
{
m_internal
->
Check
();
}
class
COOXMLVerifier_private
{
public:
std
::
wstring
m_sFolder
;
std
::
vector
<
COOXMLSignature
*>
m_arSignatures
;
public:
COOXMLVerifier
(
const
std
::
wstring
&
sFolder
)
COOXMLVerifier
_private
(
const
std
::
wstring
&
sFolder
)
{
m_sFolder
=
sFolder
;
...
...
@@ -429,14 +460,14 @@ public:
continue
;
COOXMLSignature
*
pSignature
=
new
COOXMLSignature
();
pSignature
->
m_node
=
nodeSig
;
pSignature
->
m_sFolder
=
m_sFolder
;
pSignature
->
m_
internal
->
m_
node
=
nodeSig
;
pSignature
->
m_
internal
->
m_
sFolder
=
m_sFolder
;
pSignature
->
Check
();
m_arSignatures
.
push_back
(
pSignature
);
}
}
~
COOXMLVerifier
()
~
COOXMLVerifier
_private
()
{
for
(
std
::
vector
<
COOXMLSignature
*>::
iterator
i
=
m_arSignatures
.
begin
();
i
!=
m_arSignatures
.
end
();
i
++
)
{
...
...
@@ -447,4 +478,22 @@ public:
}
};
#endif //_XML_OOXMLVERIFIER_H_
COOXMLVerifier
::
COOXMLVerifier
(
const
std
::
wstring
&
sFolder
)
{
m_internal
=
new
COOXMLVerifier_private
(
sFolder
);
}
COOXMLVerifier
::~
COOXMLVerifier
()
{
RELEASEOBJECT
(
m_internal
);
}
int
COOXMLVerifier
::
GetSignatureCount
()
{
return
(
int
)
m_internal
->
m_arSignatures
.
size
();
}
COOXMLSignature
*
COOXMLVerifier
::
GetSignature
(
const
int
&
index
)
{
return
m_internal
->
m_arSignatures
[
index
];
}
DesktopEditor/xmlsec/src/XmlCanonicalizator.h
→
DesktopEditor/xmlsec/src/
src/
XmlCanonicalizator.h
View file @
ed7661b9
#ifndef _XML_CANONICALIZATOR_H_
#define _XML_CANONICALIZATOR_H_
#include "../../common/File.h"
#include "../../common/Directory.h"
#include "../../
../
common/File.h"
#include "../../
../
common/Directory.h"
#include "../../common/StringBuilder.h"
#include "../../xml/include/xmlutils.h"
#include "../../xml/libxml2/include/libxml/c14n.h"
#include "../../
../
common/StringBuilder.h"
#include "../../
../
xml/include/xmlutils.h"
#include "../../
../
xml/libxml2/include/libxml/c14n.h"
#ifndef XML_UNUSED
#define XML_UNUSED( arg ) ( (arg) = (arg) )
...
...
DesktopEditor/xmlsec/src/src/XmlCertificate.cpp
0 → 100644
View file @
ed7661b9
#ifdef WIN32
#include "./XmlSigner_mscrypto.h"
#define CCertificate CCertificate_mscrypto
#endif
#if defined(_LINUX) && !defined(_MAC)
#endif
#ifdef _MAC
#endif
int
ICertificate
::
GetOOXMLHashAlg
(
const
std
::
string
&
sAlg
)
{
if
(
"http://www.w3.org/2000/09/xmldsig#rsa-sha1"
==
sAlg
||
"http://www.w3.org/2000/09/xmldsig#sha1"
==
sAlg
)
return
OOXML_HASH_ALG_SHA1
;
return
OOXML_HASH_ALG_INVALID
;
}
ICertificate
*
ICertificate
::
CreateInstance
()
{
return
new
CCertificate
();
}
DesktopEditor/xmlsec/src/XmlRels.h
→
DesktopEditor/xmlsec/src/
src/
XmlRels.h
View file @
ed7661b9
File moved
DesktopEditor/xmlsec/src/XmlSigner_mscrypto.h
→
DesktopEditor/xmlsec/src/
src/
XmlSigner_mscrypto.h
View file @
ed7661b9
#ifndef _XMLSIGNER_MSCRYPTO_H_
#define _XMLSIGNER_MSCRYPTO_H_
#include "./
XmlSignerBas
e.h"
#include "./
include/XmlCertificat
e.h"
#include <stdio.h>
#include <windows.h>
#include <wincrypt.h>
#include <cryptuiapi.h>
#include "../../../common/File.h"
#include "../../../common/BigInteger.h"
class
CCertificate_mscrypto
:
public
ICertificate
{
public:
...
...
DesktopEditor/xmlsec/src/src/XmlTransform.cpp
0 → 100644
View file @
ed7661b9
#include "./XmlTransform.h"
IXmlTransform
*
IXmlTransform
::
GetFromType
(
const
std
::
string
&
alg
)
{
if
(
true
)
{
CXmlTransformRelationship
*
transform
=
new
CXmlTransformRelationship
();
if
(
transform
->
m_algorithm
==
alg
)
return
transform
;
RELEASEOBJECT
(
transform
);
}
if
(
true
)
{
CXmlTransformC14N
*
transform
=
new
CXmlTransformC14N
();
if
(
transform
->
CheckC14NTransform
(
alg
))
return
transform
;
RELEASEOBJECT
(
transform
);
}
return
NULL
;
}
DesktopEditor/xmlsec/src/XmlTransform.h
→
DesktopEditor/xmlsec/src/
src/
XmlTransform.h
View file @
ed7661b9
...
...
@@ -122,26 +122,6 @@ public:
}
};
IXmlTransform
*
IXmlTransform
::
GetFromType
(
const
std
::
string
&
alg
)
{
if
(
true
)
{
CXmlTransformRelationship
*
transform
=
new
CXmlTransformRelationship
();
if
(
transform
->
m_algorithm
==
alg
)
return
transform
;
RELEASEOBJECT
(
transform
);
}
if
(
true
)
{
CXmlTransformC14N
*
transform
=
new
CXmlTransformC14N
();
if
(
transform
->
CheckC14NTransform
(
alg
))
return
transform
;
RELEASEOBJECT
(
transform
);
}
return
NULL
;
}
class
CXmlTransforms
{
protected:
...
...
DesktopEditor/xmlsec/test/windows_list_serts/main.cpp
View file @
ed7661b9
#include "../../src/XmlCertificate.h"
#include "../../src/OOXMLSigner.h"
#include "../../src/OOXMLVerifier.h"
#include "../../src/
include/
XmlCertificate.h"
#include "../../src/
include/
OOXMLSigner.h"
#include "../../src/
include/
OOXMLVerifier.h"
#pragma comment (lib, "crypt32.lib")
#pragma comment (lib, "cryptui.lib")
#pragma comment (lib, "Advapi32.lib")
#include "../../../common/File.h"
void
main
(
void
)
{
...
...
@@ -17,31 +15,34 @@ void main(void)
{
std
::
wstring
sSignId
=
L"{9792D33F-AB37-4E5B-A465-481B9465818B}"
;
CCertificate
oCertificate
;
if
(
!
oCertificate
.
ShowSelectDialog
())
ICertificate
*
pCertificate
=
ICertificate
::
CreateInstance
();
if
(
!
pCertificate
->
ShowSelectDialog
())
{
RELEASEOBJECT
(
pCertificate
);
return
;
}
COOXMLSigner
oOOXMLSigner
(
sFolderOOXML
,
&
o
Certificate
);
COOXMLSigner
oOOXMLSigner
(
sFolderOOXML
,
p
Certificate
);
oOOXMLSigner
.
SetGuid
(
sSignId
);
oOOXMLSigner
.
SetImageValid
(
NSFile
::
GetProcessDirectory
()
+
L"/../../../resources/valid.png"
);
oOOXMLSigner
.
SetImageInvalid
(
NSFile
::
GetProcessDirectory
()
+
L"/../../../resources/invalid.png"
);
oOOXMLSigner
.
Sign
();
RELEASEOBJECT
(
pCertificate
);
}
else
{
COOXMLVerifier
oVerifier
(
sFolderOOXML
);
size_t
nCount
=
oVerifier
.
m_arSignatures
.
size
();
for
(
std
::
vector
<
COOXMLSignature
*>::
iterator
i
=
oVerifier
.
m_arSignatures
.
begin
();
i
!=
oVerifier
.
m_arSignatures
.
end
()
;
i
++
)
int
nCount
=
oVerifier
.
GetSignatureCount
();
for
(
int
i
=
0
;
i
<
nCount
;
i
++
)
{
COOXMLSignature
*
pSign
=
*
i
;
COOXMLSignature
*
pSign
=
oVerifier
.
GetSignature
(
i
)
;
int
nRes
=
pSign
->
GetValid
();
XML_UNUSED
(
pSign
)
;
XML_UNUSED
(
nRes
)
;
pSign
=
pSign
;
nRes
=
nRes
;
}
XML_UNUSED
(
nCount
);
}
}
DesktopEditor/xmlsec/test/windows_list_serts/test.pro
View file @
ed7661b9
...
...
@@ -10,26 +10,8 @@ CORE_ROOT_DIR = $$PWD/../../../../
PWD_ROOT_DIR
=
$$
PWD
include
(
$$
CORE_ROOT_DIR
/
Common
/
base
.
pri
)
DEFINES
-=
UNICODE
DEFINES
+=
\
LIBXML_READER_ENABLED
\
LIBXML_PUSH_ENABLED
\
LIBXML_HTML_ENABLED
\
LIBXML_XPATH_ENABLED
\
LIBXML_OUTPUT_ENABLED
\
LIBXML_C14N_ENABLED
\
LIBXML_SAX1_ENABLED
\
LIBXML_TREE_ENABLED
\
LIBXML_XPTR_ENABLED
\
LIBXML_STATIC
SOURCES
+=
main
.
cpp
LIBS
+=
-
L
$$
CORE_BUILDS_LIBRARIES_PATH
-
llibxml
INCLUDEPATH
+=
\
$$
CORE_ROOT_DIR
/
DesktopEditor
/
xml
/
libxml2
/
include
\
$$
CORE_ROOT_DIR
/
DesktopEditor
/
xml
/
libxml2
/
include
/
libxml
LIBS
+=
-
L
$$
CORE_BUILDS_LIBRARIES_PATH
-
looxmlsignature
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment