summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.travis.yml31
-rw-r--r--AUTHORS4
-rw-r--r--CMakeLists.txt55
-rw-r--r--CONTRIBUTING.md1
-rw-r--r--LICENSE.LGPL504
-rw-r--r--README.md110
-rw-r--r--RELEASE-NOTES.txt168
-rw-r--r--cmake/README.txt1
-rw-r--r--cmake/modules/FindIconv.cmake58
-rw-r--r--cmake/modules/FindLdap.cmake35
-rw-r--r--cmake/modules/FindLibDigiDoc.cmake28
-rw-r--r--cmake/modules/FindLibDigiDocpp.cmake28
-rw-r--r--cmake/modules/FindMiniZip.cmake30
-rw-r--r--cmake/modules/FindPCSCLite.cmake44
-rw-r--r--cmake/modules/FindPKCS11.cmake24
-rw-r--r--cmake/modules/FindXSD.cmake52
-rw-r--r--cmake/modules/FindXercesC.cmake30
-rw-r--r--cmake/modules/FindXmlSecurityC.cmake38
-rw-r--r--cmake/modules/MacOSXBundleInfo.plist.in36
-rw-r--r--cmake/modules/VersionInfo.cmake95
-rw-r--r--cmake/modules/win81.exe.manifest24
-rw-r--r--config.h.cmake7
-rw-r--r--debian/changelog5
-rw-r--r--debian/compat1
-rw-r--r--debian/control129
-rw-r--r--debian/copyright28
-rw-r--r--debian/libdigidoc-common.install2
-rw-r--r--debian/libdigidoc-dev.install4
-rw-r--r--debian/libdigidoc-doc.install1
-rw-r--r--debian/libdigidoc-tools.install2
-rw-r--r--debian/libdigidoc2.install1
-rw-r--r--debian/patches/01-manpage.patch32
-rw-r--r--debian/patches/02-no-rpath.patch12
-rw-r--r--debian/patches/series2
-rwxr-xr-xdebian/rules23
-rw-r--r--debian/source/format1
-rw-r--r--debian/watch3
-rw-r--r--doc/SK-CDD-PRG-GUIDE.docxbin0 -> 783618 bytes
-rw-r--r--doc/SK-CDD-PRG-GUIDE.pdfbin0 -> 1050094 bytes
-rw-r--r--doc/SK-COM-PRG-GUIDE.docxbin0 -> 764984 bytes
-rw-r--r--doc/SK-COM-PRG-GUIDE.pdfbin0 -> 1110158 bytes
-rw-r--r--doc/doxygen-license.txt8
-rw-r--r--doc/mit-license.txt26
-rw-r--r--doc/openssl-license.txt131
-rw-r--r--doc/sample_files_CDD.zipbin0 -> 38033 bytes
-rw-r--r--doc/zlib-license.txt25
-rw-r--r--etc/Doxyfile.in1804
-rw-r--r--etc/certs/EECCRCA.crt24
-rw-r--r--etc/certs/EID-SK 2007 OCSP 2010.crt21
-rw-r--r--etc/certs/EID-SK 2007 OCSP.crt17
-rw-r--r--etc/certs/EID-SK 2007.crt20
-rw-r--r--etc/certs/EID-SK 2011.crt29
-rw-r--r--etc/certs/EID-SK OCSP 2006.crt18
-rw-r--r--etc/certs/EID-SK OCSP.crt20
-rw-r--r--etc/certs/EID-SK.crt24
-rw-r--r--etc/certs/ESTEID-SK 2007 OCSP 2010.crt23
-rw-r--r--etc/certs/ESTEID-SK 2007 OCSP.crt19
-rw-r--r--etc/certs/ESTEID-SK 2007.crt20
-rw-r--r--etc/certs/ESTEID-SK 2011.crt29
-rw-r--r--etc/certs/ESTEID-SK OCSP 2005.crt20
-rw-r--r--etc/certs/ESTEID-SK OCSP.crt22
-rw-r--r--etc/certs/ESTEID-SK.crt29
-rw-r--r--etc/certs/JUUR-SK.crt29
-rw-r--r--etc/certs/KLASS3-SK 2010 EECCRCA.crt27
-rw-r--r--etc/certs/KLASS3-SK 2010 OCSP.crt25
-rw-r--r--etc/certs/KLASS3-SK 2010.crt23
-rw-r--r--etc/certs/KLASS3-SK OCSP 2006.crt18
-rw-r--r--etc/certs/KLASS3-SK OCSP 2009.crt20
-rw-r--r--etc/certs/KLASS3-SK OCSP.crt21
-rw-r--r--etc/certs/KLASS3-SK.crt24
-rw-r--r--etc/certs/README.txt1
-rw-r--r--etc/certs/SK OCSP 2011.crt28
-rw-r--r--etc/certs/TEST EECCRCA.crt24
-rw-r--r--etc/certs/TEST EID-SK 2011.crt28
-rw-r--r--etc/certs/TEST ESTEID-SK 2011.crt28
-rw-r--r--etc/certs/TEST Juur-SK.crt23
-rw-r--r--etc/certs/TEST KLASS3 2010.crt28
-rw-r--r--etc/certs/TEST SK OCSP 2011.crt27
-rw-r--r--etc/certs/TEST-SK OCSP 2005.crt17
-rw-r--r--etc/certs/TEST-SK.crt21
-rw-r--r--etc/digidoc.conf.cmake172
-rw-r--r--libdigidoc.spec69
-rw-r--r--libdigidoc.wxs111
-rw-r--r--libdigidoc/CMakeLists.txt153
-rw-r--r--libdigidoc/DigiCrypt.c1006
-rw-r--r--libdigidoc/DigiCrypt.h28
-rw-r--r--libdigidoc/DigiDocCert.c1981
-rw-r--r--libdigidoc/DigiDocCert.h364
-rw-r--r--libdigidoc/DigiDocConfig.c2211
-rw-r--r--libdigidoc/DigiDocConfig.h425
-rw-r--r--libdigidoc/DigiDocConvert.c1373
-rw-r--r--libdigidoc/DigiDocConvert.h303
-rw-r--r--libdigidoc/DigiDocCsp.c2229
-rw-r--r--libdigidoc/DigiDocCsp.h132
-rw-r--r--libdigidoc/DigiDocDebug.c170
-rw-r--r--libdigidoc/DigiDocDebug.h75
-rw-r--r--libdigidoc/DigiDocDefs.h180
-rw-r--r--libdigidoc/DigiDocDfExtract.c405
-rw-r--r--libdigidoc/DigiDocDfExtract.h48
-rw-r--r--libdigidoc/DigiDocEnc.c2743
-rw-r--r--libdigidoc/DigiDocEnc.h917
-rw-r--r--libdigidoc/DigiDocEncGen.c522
-rw-r--r--libdigidoc/DigiDocEncGen.h74
-rw-r--r--libdigidoc/DigiDocEncSAXParser.c1155
-rw-r--r--libdigidoc/DigiDocEncSAXParser.h70
-rw-r--r--libdigidoc/DigiDocError.c604
-rw-r--r--libdigidoc/DigiDocError.h310
-rw-r--r--libdigidoc/DigiDocGen.c1925
-rw-r--r--libdigidoc/DigiDocGen.h200
-rw-r--r--libdigidoc/DigiDocGlobals.c65
-rw-r--r--libdigidoc/DigiDocGlobals.h69
-rw-r--r--libdigidoc/DigiDocHTTP.c44
-rw-r--r--libdigidoc/DigiDocHTTP.h4
-rw-r--r--libdigidoc/DigiDocLib.c1173
-rw-r--r--libdigidoc/DigiDocLib.h239
-rw-r--r--libdigidoc/DigiDocMem.c291
-rw-r--r--libdigidoc/DigiDocMem.h108
-rw-r--r--libdigidoc/DigiDocOCSP.c1670
-rw-r--r--libdigidoc/DigiDocOCSP.h152
-rw-r--r--libdigidoc/DigiDocObj.c4415
-rw-r--r--libdigidoc/DigiDocObj.h1291
-rw-r--r--libdigidoc/DigiDocPKCS11.c956
-rw-r--r--libdigidoc/DigiDocPKCS11.h86
-rw-r--r--libdigidoc/DigiDocParser.c1243
-rw-r--r--libdigidoc/DigiDocParser.h107
-rw-r--r--libdigidoc/DigiDocSAXParser.c3237
-rw-r--r--libdigidoc/DigiDocSAXParser.h105
-rw-r--r--libdigidoc/DigiDocService.c341
-rw-r--r--libdigidoc/DigiDocService.h102
-rw-r--r--libdigidoc/DigiDocStack.c315
-rw-r--r--libdigidoc/DigiDocStack.h137
-rw-r--r--libdigidoc/DigiDocVerify.c1972
-rw-r--r--libdigidoc/DigiDocVerify.h178
-rw-r--r--libdigidoc/DlgUnit.c688
-rw-r--r--libdigidoc/DlgUnit.h3
-rw-r--r--libdigidoc/DlgUnit.manifest23
-rw-r--r--libdigidoc/DlgUnit.rc134
-rw-r--r--libdigidoc/DlgUnitS.c476
-rw-r--r--libdigidoc/cdigidoc.1.cmake244
-rw-r--r--libdigidoc/cdigidoc.c2559
-rw-r--r--libdigidoc/cdigidoc.rc43
-rw-r--r--libdigidoc/libdigidoc.pc.cmake10
-rw-r--r--libdigidoc/libdigidoc.rc43
-rw-r--r--libdigidoc/pkcs11/cryptoki.h96
-rw-r--r--libdigidoc/pkcs11/pkcs11.h288
-rw-r--r--libdigidoc/pkcs11/pkcs11f.h898
-rw-r--r--libdigidoc/pkcs11/pkcs11t.h1334
-rw-r--r--libdigidoc/pkcs11/unix.h24
-rw-r--r--libdigidoc/rc.rctbin0 -> 488 bytes
-rw-r--r--libdigidoc/res.rc94
-rw-r--r--libdigidoc/resource.h16
-rw-r--r--libxml2-2.9.2-patches.zipbin0 -> 7018 bytes
-rw-r--r--prepare_win_build_environment.ps199
-rw-r--r--vc2008/cdigidoc.vcproj207
-rw-r--r--vc2008/libdigidoc.ncbbin0 -> 27675648 bytes
-rw-r--r--vc2008/libdigidoc.sln37
-rw-r--r--vc2008/libdigidoc.suobin0 -> 53248 bytes
-rw-r--r--vc2008/libdigidoc.vcproj406
-rw-r--r--vc2008/libdigidoc_vs.sln37
-rw-r--r--vc2010/DigiDocLib.vcxproj206
-rw-r--r--vc2010/digidoc.vcxproj146
-rw-r--r--vc2010/libdigidoc.sln61
162 files changed, 50817 insertions, 0 deletions
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..528953b
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,31 @@
+before_install: if [ "${TRAVIS_OS_NAME}" = "osx" ]; then
+ brew update;
+ else
+ sudo apt-get update -qq;
+ sudo apt-get install -y cmake libxml2-dev libssl-dev;
+ fi
+script:
+- mkdir build
+- cd build
+- cmake ..
+- make
+
+os:
+ - linux
+ - osx
+
+env:
+ global:
+ # The next declaration is the encrypted COVERITY_SCAN_TOKEN, created
+ # via the "travis encrypt" command using the project repo's public key
+ - secure: "AhDg868E2SgZbGhsFyDQd19IVCZcQ2a7shdojRTxIxF10TGhAleFEtm4EAoXjjgCPcGY52o1aVaEMea/GRnLR6oLQ592igxNHjTlTGKcDp5w28xVq9m7d4JVrvUeYvKoi+szS4Ah8zhraGdssMaq8LtZzLbaoEXCaMCDRlXPGro="
+
+addons:
+ coverity_scan:
+ project:
+ name: "open-eid/libdigidoc"
+ description: "Build submitted via Travis CI"
+ notification_email: raul@metsma.ee
+ build_command_prepend: "mkdir coverity; cd coverity; cmake .."
+ build_command: make
+ branch_pattern: coverity_scan
diff --git a/AUTHORS b/AUTHORS
new file mode 100644
index 0000000..139c00c
--- /dev/null
+++ b/AUTHORS
@@ -0,0 +1,4 @@
+Veiko Sinivee <veiko.sinivee@seb.se>
+ The main project leader and author of DigiDoc library.
+Martin Paljak <martin@paljak.pri.ee>
+ Integrator, fixer, packaging maintainer.
diff --git a/CMakeLists.txt b/CMakeLists.txt
new file mode 100644
index 0000000..c55cd36
--- /dev/null
+++ b/CMakeLists.txt
@@ -0,0 +1,55 @@
+cmake_minimum_required( VERSION 2.8 )
+project( libdigidoc )
+
+set( CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake/modules" )
+set( CMAKE_FIND_ROOT_PATH ${CMAKE_OSX_SYSROOT} )
+set( INSTALL_DOC false CACHE BOOL "Install documentation" )
+if( APPLE )
+ set( FRAMEWORK YES CACHE BOOL "Build library as Mac OS X Framework" )
+endif()
+
+include( CheckIncludeFiles )
+include( VersionInfo )
+include( GNUInstallDirs )
+
+if( WIN32 )
+ set( DIGIDOC_CONF_NAME "digidoc.ini" )
+else()
+ set( DIGIDOC_CONF_NAME "digidoc.conf" )
+endif()
+
+find_package( Doxygen )
+find_package( LibXml2 REQUIRED )
+find_package( OpenSSL REQUIRED )
+find_package( PKCS11 )
+find_package( ZLIB REQUIRED )
+find_package( Iconv )
+
+if( INSTALL_DOC )
+ if( DOXYGEN_FOUND )
+ configure_file( ${CMAKE_SOURCE_DIR}/etc/Doxyfile.in Doxyfile @ONLY )
+ add_custom_target( docs ALL
+ ${DOXYGEN_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile
+ WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
+ COMMENT "Generating API documentation with Doxygen" VERBATIM
+ )
+ install( DIRECTORY ${CMAKE_BINARY_DIR}/doc/ DESTINATION ${CMAKE_INSTALL_DATADIR}/doc/libdigidoc )
+ endif()
+ install( DIRECTORY doc/ DESTINATION ${CMAKE_INSTALL_DATADIR}/doc/libdigidoc PATTERN ".svn" EXCLUDE )
+endif()
+
+configure_file( config.h.cmake config.h )
+
+include_directories(
+ ${CMAKE_CURRENT_SOURCE_DIR}
+ ${CMAKE_CURRENT_BINARY_DIR}
+ ${LIBXML2_INCLUDE_DIR}
+ ${OPENSSL_INCLUDE_DIR}
+ ${ZLIB_INCLUDE_DIR}
+)
+if( ICONV_FOUND )
+ include_directories( ${ICONV_INCLUDE_DIR} )
+endif()
+
+add_subdirectory( libdigidoc )
+
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
new file mode 100644
index 0000000..7e717b5
--- /dev/null
+++ b/CONTRIBUTING.md
@@ -0,0 +1 @@
+Please read the [common contributing guidelines](https://github.com/open-eid/org/blob/master/CONTRIBUTING.md) before you continue!
diff --git a/LICENSE.LGPL b/LICENSE.LGPL
new file mode 100644
index 0000000..5ab7695
--- /dev/null
+++ b/LICENSE.LGPL
@@ -0,0 +1,504 @@
+ GNU LESSER GENERAL PUBLIC LICENSE
+ Version 2.1, February 1999
+
+ Copyright (C) 1991, 1999 Free Software Foundation, Inc.
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the Lesser GPL. It also counts
+ as the successor of the GNU Library Public License, version 2, hence
+ the version number 2.1.]
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+ This license, the Lesser General Public License, applies to some
+specially designated software packages--typically libraries--of the
+Free Software Foundation and other authors who decide to use it. You
+can use it too, but we suggest you first think carefully about whether
+this license or the ordinary General Public License is the better
+strategy to use in any particular case, based on the explanations below.
+
+ When we speak of free software, we are referring to freedom of use,
+not price. Our General Public Licenses are designed to make sure that
+you have the freedom to distribute copies of free software (and charge
+for this service if you wish); that you receive source code or can get
+it if you want it; that you can change the software and use pieces of
+it in new free programs; and that you are informed that you can do
+these things.
+
+ To protect your rights, we need to make restrictions that forbid
+distributors to deny you these rights or to ask you to surrender these
+rights. These restrictions translate to certain responsibilities for
+you if you distribute copies of the library or if you modify it.
+
+ For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you. You must make sure that they, too, receive or can get the source
+code. If you link other code with the library, you must provide
+complete object files to the recipients, so that they can relink them
+with the library after making changes to the library and recompiling
+it. And you must show them these terms so they know their rights.
+
+ We protect your rights with a two-step method: (1) we copyright the
+library, and (2) we offer you this license, which gives you legal
+permission to copy, distribute and/or modify the library.
+
+ To protect each distributor, we want to make it very clear that
+there is no warranty for the free library. Also, if the library is
+modified by someone else and passed on, the recipients should know
+that what they have is not the original version, so that the original
+author's reputation will not be affected by problems that might be
+introduced by others.
+
+ Finally, software patents pose a constant threat to the existence of
+any free program. We wish to make sure that a company cannot
+effectively restrict the users of a free program by obtaining a
+restrictive license from a patent holder. Therefore, we insist that
+any patent license obtained for a version of the library must be
+consistent with the full freedom of use specified in this license.
+
+ Most GNU software, including some libraries, is covered by the
+ordinary GNU General Public License. This license, the GNU Lesser
+General Public License, applies to certain designated libraries, and
+is quite different from the ordinary General Public License. We use
+this license for certain libraries in order to permit linking those
+libraries into non-free programs.
+
+ When a program is linked with a library, whether statically or using
+a shared library, the combination of the two is legally speaking a
+combined work, a derivative of the original library. The ordinary
+General Public License therefore permits such linking only if the
+entire combination fits its criteria of freedom. The Lesser General
+Public License permits more lax criteria for linking other code with
+the library.
+
+ We call this license the "Lesser" General Public License because it
+does Less to protect the user's freedom than the ordinary General
+Public License. It also provides other free software developers Less
+of an advantage over competing non-free programs. These disadvantages
+are the reason we use the ordinary General Public License for many
+libraries. However, the Lesser license provides advantages in certain
+special circumstances.
+
+ For example, on rare occasions, there may be a special need to
+encourage the widest possible use of a certain library, so that it becomes
+a de-facto standard. To achieve this, non-free programs must be
+allowed to use the library. A more frequent case is that a free
+library does the same job as widely used non-free libraries. In this
+case, there is little to gain by limiting the free library to free
+software only, so we use the Lesser General Public License.
+
+ In other cases, permission to use a particular library in non-free
+programs enables a greater number of people to use a large body of
+free software. For example, permission to use the GNU C Library in
+non-free programs enables many more people to use the whole GNU
+operating system, as well as its variant, the GNU/Linux operating
+system.
+
+ Although the Lesser General Public License is Less protective of the
+users' freedom, it does ensure that the user of a program that is
+linked with the Library has the freedom and the wherewithal to run
+that program using a modified version of the Library.
+
+ The precise terms and conditions for copying, distribution and
+modification follow. Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library". The
+former contains code derived from the library, whereas the latter must
+be combined with the library in order to run.
+
+ GNU LESSER GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License Agreement applies to any software library or other
+program which contains a notice placed by the copyright holder or
+other authorized party saying it may be distributed under the terms of
+this Lesser General Public License (also called "this License").
+Each licensee is addressed as "you".
+
+ A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+ The "Library", below, refers to any such software library or work
+which has been distributed under these terms. A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language. (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+ "Source code" for a work means the preferred form of the work for
+making modifications to it. For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+ Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it). Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+
+ 1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+ You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+
+ 2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) The modified work must itself be a software library.
+
+ b) You must cause the files modified to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ c) You must cause the whole of the work to be licensed at no
+ charge to all third parties under the terms of this License.
+
+ d) If a facility in the modified Library refers to a function or a
+ table of data to be supplied by an application program that uses
+ the facility, other than as an argument passed when the facility
+ is invoked, then you must make a good faith effort to ensure that,
+ in the event an application does not supply such function or
+ table, the facility still operates, and performs whatever part of
+ its purpose remains meaningful.
+
+ (For example, a function in a library to compute square roots has
+ a purpose that is entirely well-defined independent of the
+ application. Therefore, Subsection 2d requires that any
+ application-supplied function or table used by this function must
+ be optional: if the application does not supply it, the square
+ root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library. To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License. (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.) Do not make any other change in
+these notices.
+
+ Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+ This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+ 4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+ If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library". Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+ However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library". The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+ When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library. The
+threshold for this to be true is not precisely defined by law.
+
+ If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work. (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+ Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+
+ 6. As an exception to the Sections above, you may also combine or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+ You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License. You must supply a copy of this License. If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License. Also, you must do one
+of these things:
+
+ a) Accompany the work with the complete corresponding
+ machine-readable source code for the Library including whatever
+ changes were used in the work (which must be distributed under
+ Sections 1 and 2 above); and, if the work is an executable linked
+ with the Library, with the complete machine-readable "work that
+ uses the Library", as object code and/or source code, so that the
+ user can modify the Library and then relink to produce a modified
+ executable containing the modified Library. (It is understood
+ that the user who changes the contents of definitions files in the
+ Library will not necessarily be able to recompile the application
+ to use the modified definitions.)
+
+ b) Use a suitable shared library mechanism for linking with the
+ Library. A suitable mechanism is one that (1) uses at run time a
+ copy of the library already present on the user's computer system,
+ rather than copying library functions into the executable, and (2)
+ will operate properly with a modified version of the library, if
+ the user installs one, as long as the modified version is
+ interface-compatible with the version that the work was made with.
+
+ c) Accompany the work with a written offer, valid for at
+ least three years, to give the same user the materials
+ specified in Subsection 6a, above, for a charge no more
+ than the cost of performing this distribution.
+
+ d) If distribution of the work is made by offering access to copy
+ from a designated place, offer equivalent access to copy the above
+ specified materials from the same place.
+
+ e) Verify that the user has already received a copy of these
+ materials or that you have already sent this user a copy.
+
+ For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it. However, as a special exception,
+the materials to be distributed need not include anything that is
+normally distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+ It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system. Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+
+ 7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+ a) Accompany the combined library with a copy of the same work
+ based on the Library, uncombined with any other library
+ facilities. This must be distributed under the terms of the
+ Sections above.
+
+ b) Give prominent notice with the combined library of the fact
+ that part of it is a work based on the Library, and explaining
+ where to find the accompanying uncombined form of the same work.
+
+ 8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License. Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License. However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+ 9. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Library or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+ 10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties with
+this License.
+
+ 11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all. For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded. In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+ 13. The Free Software Foundation may publish revised and/or new
+versions of the Lesser General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation. If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+
+ 14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission. For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this. Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+ NO WARRANTY
+
+ 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Libraries
+
+ If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change. You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+ To apply these terms, attach the following notices to the library. It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the library's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the
+ library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+ <signature of Ty Coon>, 1 April 1990
+ Ty Coon, President of Vice
+
+That's all there is to it!
+
+
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..d263ab8
--- /dev/null
+++ b/README.md
@@ -0,0 +1,110 @@
+# libdigidoc
+
+ * License: LGPL 2.1
+ * &copy; Estonian Information System Authority
+
+Dependencies
+---------------------------
+You need the following dependent librarys to build libdigidoc:
+- openssl - https://www.openssl.org/ - Apache style license
+- libxml2 - http://xmlsoft.org/ - MIT license
+- zlib - http://www.zlib.net/ - zlib license
+- iconv - https://www.gnu.org/software/libiconv/ - LGPL license
+- doxygen - http://www.stack.nl/~dimitri/doxygen/ - doxygen license
+
+
+Full documentation
+----------------------------
+For documentation please see in doc folder SK-CDD-PRG-GUIDE
+Contact for assistance by email abi@id.ee or http://www.id.ee
+
+## Building
+[![Build Status](https://travis-ci.org/open-eid/libdigidoc.svg?branch=master)](https://travis-ci.org/open-eid/libdigidoc)
+[![Coverity Scan Build Status](https://scan.coverity.com/projects/724/badge.svg)](https://scan.coverity.com/projects/724)
+
+### Ubuntu
+
+1. Install dependencies
+
+ sudo apt-get install cmake libxml2-dev libssl-dev
+
+2. Fetch the source
+
+ git clone --recursive https://github.com/open-eid/libdigidoc
+ cd libdigidoc
+
+3. Configure
+
+ mkdir build
+ cd build
+ cmake ..
+
+4. Build
+
+ make
+
+5. Install
+
+ sudo make install
+
+6. Execute
+
+ /usr/local/bin/cdigidoc
+
+### OSX
+
+1. Install dependencies from [http://www.cmake.org](http://www.cmake.org)
+
+2. Fetch the source
+
+ git clone --recursive https://github.com/open-eid/libdigidoc
+ cd libdigidoc
+
+3. Configure
+
+ mkdir build
+ cd build
+ cmake ..
+
+4. Build
+
+ make
+
+5. Install
+
+ sudo make install
+
+6. Execute
+
+ /usr/local/bin/cdigidoc
+
+### Windows
+
+1. Install dependencies from
+ * [Visual Studio Express 2013 for Windows Desktop](http://www.visualstudio.com/en-us/products/visual-studio-express-vs.aspx)
+ * [Libxml2](http://xmlsoft.org/downloads.html)
+ * [OpenSSL Win32 binaries](https://slproweb.com/products/Win32OpenSSL.html) or [OpenSSL source](https://www.openssl.org/source/)
+ * [ZLib source](http://zlib.net/zlib128.zip)
+2. Fetch the source
+
+ git clone --recursive https://github.com/open-eid/libdigidoc
+ cd libdigidoc
+
+3. Configure
+
+ mkdir build
+ cd build
+ cmake ..
+
+4. Build
+
+ make
+
+5. Execute
+
+ libdigidoc/cdigidoc.exe
+
+## Support
+Official builds are provided through official distribution point [installer.id.ee](https://installer.id.ee). If you want support, you need to be using official builds. Contact for assistance by email [abi@id.ee](mailto:abi@id.ee) or [www.id.ee](http://www.id.ee).
+
+Source code is provided on "as is" terms with no warranty (see license for more information). Do not file Github issues with generic support requests.
diff --git a/RELEASE-NOTES.txt b/RELEASE-NOTES.txt
new file mode 100644
index 0000000..3ca40ce
--- /dev/null
+++ b/RELEASE-NOTES.txt
@@ -0,0 +1,168 @@
+DigiDoc C library 3.10 release notes
+-----------------------------------
+Changes compared to ver 3.9.1
+
+- Changed validation process of OCSP response so that the responder’s certificate reference is taken from the response instead of the signature’s XML.
+- Improved DDOC document validation. It is now checked that the issuance time of the OCSP response would be in the validity period of the signer's certificate.
+- Changed the validation of DDOC documents so that multiple data files with the same name would be allowed in the container.
+- Improved utility program's output during DDOC document validation. If the signer's certificate is from live CA chain but OCSP confirmation has been issued from test OCSP responder then warning 172 "Signer from LIVE CA-chain but OCSP from TEST CA-chain!" is returned.
+- Removed duplicate configuration file entry CA_CERT_6 to fix KLASS3-SK 2010 (KLASS3-SK 2010 EECCRCA.crt) certificate's configuration settings.
+- Removed Finnish CA certificates from digidoc.ini default configuration file. It is recommended to use BDOC format and relevant software instead.
+- Development of the software can now be monitored in GitHub environment: https://github.com/open-eid/libdigidoc
+
+Known issues:
+- Validation of documents in DDOC 1.0 format fails on Ubuntu LTS upgrade 14.4.1 and newer due to incompatibility in OpenSSL base library openssl_1.0.1f-1ubuntu2.8. The problem does not occur on Ubuntu 14.4 with openssl_1.0.1f-1ubuntu2.7, OSX and Windows platforms.
+
+
+
+DigiDoc C library 3.9.1 release notes
+-----------------------------------
+Changes compared to ver 3.9
+
+- DDOC security fixes:
+ - Improved XML structure validation for DDOC files. This is a highly relevant security fix having an effect on the validation of DDOC files. The unfixed library can mistakenly give positive results on validation of invalid DDOC files with incorrect XML elements' ordering.
+
+
+
+DigiDoc C library 3.9 release notes
+-----------------------------------
+Changes compared to ver 3.8
+
+- Improved checking of signer certificate's CA chain length during signature creation and validation. Previously it was not possible to create signature if there was only one CA certificate in the certificate chain.
+- Improved DDOC files' validation, added check that the signer certificate's data would match the X509SerialNumber and X509IssuerName elements' contents.
+- Improved DDOC files validation, added check for Transforms elements which are not supported in DDOC files.
+- Changed signature adding and removal restrictions in case of erroneous files (incl. files that are valid with warnings). No restrictions are made to adding or removing signatures, except of in case of files that are in old format (DIGIDOC-XML 1.0, 1.1, 1.2).
+- Fixed error of handling quotation marks in ClaimedRole and SignatureProductionPlace elements during signature creation and validation. Quotation marks are not replaced during canonicalization according to Canonical XML Version 1.0. Note that as a result, the files that contain quotation marks in the respective elements and have been created with v3.9 might not be compatible with v3.8 of the library.
+- Fixed handling of special characters <, >, & and carriage return in X509IssuerName and ResponderID elements. The characters are now replaced during canonicalization according to Canonical XML Version 1.0. Note that as a result, the files that contain these special characters in the respective elements and have been created with v3.9 might not be compatible with v3.8 of the library.
+- Fixed error which occurred when parsing DDOC document's data file name that contains '&' special character. Previously, the character was erroneously displayed in escaped form.
+- Fixed error that occurred during signature creation when Windows redirected directories were used. Occasionally, writing the ddoc file to redirected directory did not succeed due to synchronization problems.
+- Fixed error that caused the library to exit unexpectedly when trying to parse a DDOC file that contained a large number of validation errors.
+- Changed compression functionality during CDOC encryption process to deprecated, by default the data is never compressed. Removed DENC_COMPRESS_MODE configuration file parameter.
+- Updated cdigidoc.exe utility program's commands "-encrypt-sk", "-encrypt-file" and "-encrypt" so that "MimeType", "OriginalMimeType" and "orig_file" encryption properties are set according to CDOC 1.0 specification.
+- Changed ddsGetStatus() function in DigiDocService.h source file to deprecated status, use ddsGetStatusWithFile() instead. The ddsGetStatusWithFile() function enables to determine the DDOC file name to which the signature value is added.
+- Added command "-mid-test" to cdigidoc-exe utility program, to be used for testing purposes only. The command enables to test the whole Mobile-ID signing process, including creating new DDOC container, adding data file, creating signature, validating the created signature and extracting data files.
+- Fixed cdigidoc utility program's "-libraryerrors" parameter functionality. When the parameter is set then only the errors that are returned by the library are now displayed as "LIBRARY-ERROR".
+- Used coverity.com static analysis tool to find source code defects and vulnerabilities.
+
+
+
+DigiDoc C library 3.8 release notes
+-----------------------------------
+Changes compared to ver 3.7.2
+
+- Started using coverity.com static analysis tool to find source code defects and vulnerabilities. Fixed resource leak and NULL pointer problems that were discovered.
+- Fixed createDataFileInMemory() method, added fixed SHA-1 digest type value when creating new data file.
+- Added support for new KLASS3-SK 2010 CA certificate.
+- Improved the validation of signer's certificate path, added check if all of the chain's certificates validity period includes the signature creation time (producedAt field's value in OCSP response).
+- Improved error handling in case of missing CA certificates and certificates in wrong format, error code 36 is returned in this case. Only PEM format is supported for CA certificates.
+- Added support for extracting data files from container so that the data is kept only in internal memory buffers. Added command –extract-mem to cdigidoc.c utility program.
+- Added validation support for DDOC signatures that are created with Finnish live and test certificates. The certificate files have to be installed with separate packages. The live certificates package contains Finnish root CA certificate (http://fineid.fi/default.aspx?id=596) and certificates which are included in the Finnish national Trust Service List (TSL) (https://www.viestintavirasto.fi/attachments/TSL-Ficora.xml). Finnish test certificates (http://fineid.fi/default.aspx?id=597) are included in the overall test certificates package.
+- Fixed error handling in case of NULL values in DDOC file’s format and version variables. Acknowledgements. Sertifitseerimiskeskus and RIA thank Aivar Liimets for his contribution.
+- Added possibility get all validation error codes that were found during DDOC file’s parsing and validation process instead of only one error code returned by the validation function verifySignatureAndNotary(). Added error code 173, which is returned in case of multiple errors. Library user must check the list of multiple errors by using new API functions getLastErrorsIdx(), getErrorsInfo() (in source file DigiDocError.c).
+- Added warnings system to the library. In case of minor technical errors in the signed DigiDoc file, validation result VALID WITH WARNINGS is used, meaning that the file is legally valid but further alterations (adding/removing signatures) are restricted. It is recommended for the programmers to implement the usage validation status VALID WITH WARNINGS as described in documentation. The warnings system is implemented in cdigidoc.c utility program (identically to DigiDoc3 Client desktop applicaton), warning situations include:
+ - DDOC file's <DataFile> element's xmlns attribute is missing (error code 169)
+ - The DigiDoc file format is older than officially accepted, i.e. the file is DDOC 1.0, 1.1, 1.2 (error code 171).
+ - DDOC file's <X509IssuerName> or <X509SerialNumber> element's xmlns attribute is missing (error code 170).
+ - The signature has been created with a test certificate (error code 172).
+- Changed the priorities of DigiDoc file's validation result statuses.
+- Added error codes 168 (ERR_DF_NAME), 169 (ERR_DF_WRONG_DIG), 170 (ERR_ISSUER_XMLNS), 171 (ERR_OLD_VERSION), 172 (ERR_TEST_SIGNATURE), 173 (ERR_UNKNOWN_ERROR).
+- Fixed nonce asn.1 prefix verification if nonce has no prefix but first 2 bytes match required prefix value.
+- Added validation check of signer’s roles. Maximum 2 <ClaimedRole> elements are supported by the library in a DDOC file.
+- Added check for duplicate <DataFile> element’s fileName attribute. Multiple data files with the same file name in a single container are not supported.
+- Improved <DataFile> element's Id attribute validation. Added support for <DataFile> element’s Id attribute value DO (capital O, not zero).
+- Improved error handling of invalid DDOC files with a missing <DataFile> element. Error 44 ERR_BAD_DATAFILE_COUNT is produced in case of such files.
+- Fixed CDOC file’s <EncryptionProperty Name="DocumentFormat"> element’s value, ENCDOC-XML 1.0 is used instead of ENCDOC-XML 1.1.
+- Fixed –validate command’s output in cdigidoc.c utility program to show validation result correctly in case if one signature among multiple signatures is erroneous.
+- Removed -list command line parameter from cdigidoc.c utility program, changed -verify command so that it replaces the –list command (validates the file and also prints out the data file list).
+- Fixed error handling in cdigidoc.c utility program if input DDOC file name contained also “.cdoc” in the file’s name.
+- It is not allowed to add or remove signatures from DigiDoc files with missing <DataFile> element’s xmlns attribute.
+- Removed configuration file parameter CHECK_SIGNATURE_VALUE_ASN1. Signature values with erroneous ASN.1 prefix values are regarded as not valid.
+- Changed function verifiedByWrongDataFileHash() to deprecated.
+
+- DDOC/CDOC security fixes:
+- Added check that <DigestValue> and <ClaimedRole> elements that are verified are within signed content. This is a highly relevant security fix. Without this fix malicious ddoc files with data not signed by original signer but added by third parties later could have been verified to be valid.
+- Fixed validation of OCSP response, added check that the OCSP response corresponds to the signer’s certificate. This is a highly relevant security fix. Without this fix specially generated ddoc file with changed OCSP response could have been verified to be valid.
+- Changed process of searching for CA certificates. The certificates are searched from the secure Program Files directory that is specified with CA_CERT_PATH configuration file parameter, not from the working directory. This is a highly relevant security fix. Without this fix, CA certificate files that may have been added to the working directory with malicious intent would be used by the library.
+- Fixed the opening of DDOC container with a faulty <DigestValue> tag. This is a highly relevant security fix that has an effect on the validation of DDOC files. Acknowledgements. Sertifitseerimiskeskus and RIA thank Aivar Liimets for his contribution.
+
+
+
+DigiDoc C library 3.7.2 release notes
+--------------------------------------
+Changes compared to ver 3.7.1.992
+
+- DDOC/CDOC security fixes:
+ - Fixed the opening of DDOC container with a faulty DataFile name tag. This is a highly relevant security fix having an effect on the verification of DDOC files. The unfixed library can result in overwrite arbitrary files on the system with the privileges of the victim.
+
+
+
+DigiDoc C library 3.7.1 release notes
+-----------------------------------
+Changes compared to ver 3.7.0.910
+
+- Changed the handling of DigiDoc container which has no xmlns attribute in the <DataFile> element.
+
+
+
+DigiDoc C library 3.7 release notes
+-----------------------------------
+Changes compared to ver 3.6.0.26
+
+- Added the support of slot choice option for CDOC decryption with utility
+- Fixed the search of the signer’s certificate issuer for DDOC verification
+- Fixed the OCSP hash check error handling for DDOC verification: error messages are correct when there are several errors associated with a container
+- Fixed the error handling of the DDOC verification function verifySignatureInfoCERT
+- Added the decrypted transport key option for testing CDOC decryption with utility
+- Fixed padding control for CDOC
+- Fixed padding handling of CDOC PKCS#7: now PKCS#7 padding is managed by the openssl
+- Fixed the DDOC signing function ddocLocateSlotWithSignatureCert: the use of the digital stamp has improved
+- Fixed the OCSP response handling for DDOC signing
+- Fixed CDOC packaging according xml-enc standard
+- Fixed the handling of the initial CDOC file name: the directory path is not added to the CDOC container
+- Fixed the handling of special characters in the CDOC decryption
+- Added Mac OSX keychain support for OCSP server access certificates in DDOC signing
+- Fixed the error handling of DDOC verification in case of the lack of issuer certificates
+- Fixed the DDOC verification function readAuthorityKeyIdentifier
+- Added the function signDocumentWithSlotAndSigner to the signing of DDOC to allow signature over CAPI/CNG
+- Added the support of signing DDOC files in the memory: no temporary files are saved
+- Added the support of encryption and decryption of CDOC in the memory: no temporary files are saved
+- Fixed the logic of the xmlns mirroring in the XML root element in the DDOC signing and verification
+- Added the PKCS12 support for DDOC signing
+- Fixed the EVP_DecodeUpdate CDOC decryption function: buffer size improvement
+- Fixed the notarizeSignatureWithIp and finalizeAndVerifyNotary2 functions for DDOC signing and verification: the setting is supported if the ocsp responder certificate has been issued from another chain than the signer’s certificate
+- Fixed the hash description handling of the ASN.1 signature value for DDOC signing and verification: 13-byte and 15-byte values are supported
+- Added BOM (Byte order mark) support on DDOC verification
+- Fixed error handling of the missing OCSP responder certificate for DDOC verification
+- Removed support for DDOC format version 1.0, 1.1, 1.2 for DDOC signing. Only DDOC verification and exctracting files from container are supported. Creating container, signing and removing signature are not supported
+
+
+- DDOC/CDOC security fixes:
+ - Added the check of the ASN.1 structure of the nonce field for DDOC signing and verification. This is a highly relevant security fix having an effect on the verification of DDOC files. The unfixed library can mistakenly give positive results on verificaton invalid DDOC container with wrong ASN.1 structure on the nonce field.
+ - Added the check of the ASN.1 structure of the signature value for DDOC signing and verification. This is a highly relevant security fix having an effect on the verification of DDOC files. The unfixed library can mistakenly give positive results on verificaton invalid DDOC container with wrong ASN.1 structure on the signature value.
+ - Added the check of the nonce field of the signature for DDOC signing and verification. This is a highly relevant security fix having an effect on the verification of DDOC files. The unfixed library can mistakenly give positive results on verificaton invalid DDOC container with the wrong nonce field value on the signature.
+ - Removed the EMBEDDED type DDOC file support for verification. This is a highly relevant security fix having an effect on the verification of DDOC files. The unfixed library can mistakenly give positive results on verificaton invalid EMBEDDED type DDOC container.
+ - Fixed the signature verification of a DDOC with a faulty DataFile tag. This is a highly relevant security fix having an effect on the verification of DDOC files. The unfixed library can result in the crashing of the application or unauthorized code execution in opening of a DDOC file created with malicious intent.
+
+
+
+
+
+DigiDoc C library 3.6 release notes
+-----------------------------------
+Changes compared to ver 2.6.0.18
+
+- Changes according ETSI Plug test results
+- Changes according Cross library (jdigidoc & libdigidoc & libdigidocpp) test results (DDOC, CDOC)
+- Removed DETACHED, HASHCODE, DDOC 1.4, BDOC support
+- CDOC padding improvements
+- Updated documentation in doc folder SK-CDD-PRG-GUIDE
+- Support for software based private keys
+- Versioning switched to same schema (3.5, 3.6 ...) as other middleware components
+- Added Mobiil-ID signing support for cdigidoc utility
+- API change in functions dencOrigContent_findByIndex, dencMetaInfo_GetLibVersion, dencMetaInfo_GetFormatVersion
+- DDOC/CDOC security updates:
+ - Fix for decrypting or content viewing of CDOC files with broken orig_file tag. This is a significant security fix which affects CDOC decrypting. A library without this security fix can cause application crashes or allow running malicious code upon opening a deliberately created CDOC file.
+ - Fix for decrypting or content viewing of CDOC files with broken EncryptionProperty tag. This is a significant security fix which affects CDOC decrypting. A library without this security fix can cause application crashes or allow running malicious code upon opening a deliberately created CDOC file
+ - DigiDocService intermediate resultate file (DDOC file hashcode) verification fix. This is a significant security fix which affects verification of DDOC files. A library without this security fix can mistakenly give positive results on verificaton of invalid DDOC hashcode container.
+ - Detached DDOC file verification fix. This is a significant security fix which affects verification of DDOC files. A library without this security fix can mistakenly give positive results on verificaton of invalid DDOC container.
+ - Added key usage check in certificate on verification of a signature. This is a significant security fix which affects verification of DDOC files. A library without this security fix can mistakenly give positive results on verificaton of a signature created with incorrect certificate.
diff --git a/cmake/README.txt b/cmake/README.txt
new file mode 100644
index 0000000..6c6e4ab
--- /dev/null
+++ b/cmake/README.txt
@@ -0,0 +1 @@
+Inner component, do not use. Contact for assistance by email abi@id.ee or http://www.id.ee
diff --git a/cmake/modules/FindIconv.cmake b/cmake/modules/FindIconv.cmake
new file mode 100644
index 0000000..7fe482d
--- /dev/null
+++ b/cmake/modules/FindIconv.cmake
@@ -0,0 +1,58 @@
+# /kde/kdesupport/strigi/cmake
+# - Try to find Iconv
+# Once done this will define
+#
+# ICONV_FOUND - system has Iconv
+# ICONV_INCLUDE_DIR - the Iconv include directory
+# ICONV_LIBRARIES - Link these to use Iconv
+# ICONV_SECOND_ARGUMENT_IS_CONST - the second argument for iconv() is const
+#
+include(CheckCSourceCompiles)
+
+IF (ICONV_INCLUDE_DIR AND ICONV_LIBRARIES)
+ # Already in cache, be silent
+ SET(ICONV_FIND_QUIETLY TRUE)
+ENDIF (ICONV_INCLUDE_DIR AND ICONV_LIBRARIES)
+
+FIND_PATH(ICONV_INCLUDE_DIR iconv.h)
+
+FIND_LIBRARY(ICONV_LIBRARIES NAMES iconv libiconv libiconv-2 c)
+
+IF(ICONV_INCLUDE_DIR AND ICONV_LIBRARIES)
+ SET(ICONV_FOUND TRUE)
+ENDIF(ICONV_INCLUDE_DIR AND ICONV_LIBRARIES)
+
+set(CMAKE_REQUIRED_INCLUDES ${ICONV_INCLUDE_DIR})
+set(CMAKE_REQUIRED_LIBRARIES ${ICONV_LIBRARIES})
+IF(ICONV_FOUND)
+ check_c_source_compiles("
+ #include <iconv.h>
+ int main(){
+ iconv_t conv = 0;
+ const char* in = 0;
+ size_t ilen = 0;
+ char* out = 0;
+ size_t olen = 0;
+ iconv(conv, &in, &ilen, &out, &olen);
+ return 0;
+ }
+" ICONV_SECOND_ARGUMENT_IS_CONST )
+ENDIF(ICONV_FOUND)
+set(CMAKE_REQUIRED_INCLUDES)
+set(CMAKE_REQUIRED_LIBRARIES)
+
+IF(ICONV_FOUND)
+ IF(NOT ICONV_FIND_QUIETLY)
+ MESSAGE(STATUS "Found Iconv: ${ICONV_LIBRARIES}")
+ ENDIF(NOT ICONV_FIND_QUIETLY)
+ELSE(ICONV_FOUND)
+ IF(Iconv_FIND_REQUIRED)
+ MESSAGE(FATAL_ERROR "Could not find Iconv")
+ ENDIF(Iconv_FIND_REQUIRED)
+ENDIF(ICONV_FOUND)
+
+MARK_AS_ADVANCED(
+ ICONV_INCLUDE_DIR
+ ICONV_LIBRARIES
+ ICONV_SECOND_ARGUMENT_IS_CONST
+)
diff --git a/cmake/modules/FindLdap.cmake b/cmake/modules/FindLdap.cmake
new file mode 100644
index 0000000..188debd
--- /dev/null
+++ b/cmake/modules/FindLdap.cmake
@@ -0,0 +1,35 @@
+# - Try to find the LDAP client libraries
+# Once done this will define
+#
+# LDAP_FOUND - system has libldap
+# LDAP_INCLUDE_DIR - the ldap include directory
+# LDAP_LIBRARIES - libldap + liblber (if found) library
+# LBER_LIBRARIES - liblber library
+
+if(LDAP_INCLUDE_DIR AND LDAP_LIBRARIES)
+ # Already in cache, be silent
+ set(Ldap_FIND_QUIETLY TRUE)
+endif()
+
+FIND_PATH(LDAP_INCLUDE_DIR ldap.h)
+FIND_LIBRARY(LDAP_LIBRARIES NAMES ldap)
+FIND_LIBRARY(LBER_LIBRARIES NAMES lber)
+
+if(LDAP_INCLUDE_DIR AND LDAP_LIBRARIES)
+ set(LDAP_FOUND TRUE)
+ if(LBER_LIBRARIES)
+ set(LDAP_LIBRARIES ${LDAP_LIBRARIES} ${LBER_LIBRARIES})
+ endif()
+endif()
+
+if(LDAP_FOUND)
+ if(NOT Ldap_FIND_QUIETLY)
+ message(STATUS "Found ldap: ${LDAP_LIBRARIES}")
+ endif()
+else()
+ if(Ldap_FIND_REQUIRED)
+ message(FATAL_ERROR "Could NOT find ldap")
+ endif()
+endif()
+
+MARK_AS_ADVANCED(LDAP_INCLUDE_DIR LDAP_LIBRARIES LBER_LIBRARIES)
diff --git a/cmake/modules/FindLibDigiDoc.cmake b/cmake/modules/FindLibDigiDoc.cmake
new file mode 100644
index 0000000..47ccf00
--- /dev/null
+++ b/cmake/modules/FindLibDigiDoc.cmake
@@ -0,0 +1,28 @@
+# - Find LibDigiDoc
+# Find the native LibDigiDoc includes and library
+#
+# LIBDIGIDOC_INCLUDE_DIR - where to find winscard.h, wintypes.h, etc.
+# LIBDIGIDOC_LIBRARIES - List of libraries when using LibDigiDoc.
+# LIBDIGIDOC_FOUND - True if LibDigiDoc found.
+
+
+IF (LIBDIGIDOC_INCLUDE_DIR)
+ # Already in cache, be silent
+ SET(LIBDIGIDOC_FIND_QUIETLY TRUE)
+ENDIF (LIBDIGIDOC_INCLUDE_DIR)
+
+FIND_PATH(LIBDIGIDOC_INCLUDE_DIR libdigidoc/DigiDocDefs.h PATH_SUFFIXES include)
+FIND_LIBRARY(LIBDIGIDOC_LIBRARY NAMES digidoc)
+
+# handle the QUIETLY and REQUIRED arguments and set LIBDIGIDOC_FOUND to TRUE if
+# all listed variables are TRUE
+INCLUDE(FindPackageHandleStandardArgs)
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(LibDigiDoc DEFAULT_MSG LIBDIGIDOC_LIBRARY LIBDIGIDOC_INCLUDE_DIR)
+
+IF(LIBDIGIDOC_FOUND)
+ SET( LIBDIGIDOC_LIBRARIES ${LIBDIGIDOC_LIBRARY} )
+ELSE(LIBDIGIDOC_FOUND)
+ SET( LIBDIGIDOC_LIBRARIES )
+ENDIF(LIBDIGIDOC_FOUND)
+
+MARK_AS_ADVANCED(LIBDIGIDOC_LIBRARY LIBDIGIDOC_INCLUDE_DIR)
diff --git a/cmake/modules/FindLibDigiDocpp.cmake b/cmake/modules/FindLibDigiDocpp.cmake
new file mode 100644
index 0000000..8ec6371
--- /dev/null
+++ b/cmake/modules/FindLibDigiDocpp.cmake
@@ -0,0 +1,28 @@
+# - Find LibDigiDocpp
+# Find the native LibDigiDocpp includes and library
+#
+# LIBDIGIDOCPP_INCLUDE_DIR - where to find winscard.h, wintypes.h, etc.
+# LIBDIGIDOCPP_LIBRARIES - List of libraries when using LibDigiDocpp.
+# LIBDIGIDOCPP_FOUND - True if LibDigiDocpp found.
+
+
+IF (LIBDIGIDOCPP_INCLUDE_DIR)
+ # Already in cache, be silent
+ SET(LIBDIGIDOCPP_FIND_QUIETLY TRUE)
+ENDIF (LIBDIGIDOCPP_INCLUDE_DIR)
+
+FIND_PATH(LIBDIGIDOCPP_INCLUDE_DIR digidocpp/Container.h PATH_SUFFIXES include)
+FIND_LIBRARY(LIBDIGIDOCPP_LIBRARY NAMES digidocpp)
+
+# handle the QUIETLY and REQUIRED arguments and set LIBDIGIDOCPP_FOUND to TRUE if
+# all listed variables are TRUE
+INCLUDE(FindPackageHandleStandardArgs)
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(LibDigiDocpp DEFAULT_MSG LIBDIGIDOCPP_LIBRARY LIBDIGIDOCPP_INCLUDE_DIR)
+
+IF(LIBDIGIDOCPP_FOUND)
+ SET( LIBDIGIDOCPP_LIBRARIES ${LIBDIGIDOCPP_LIBRARY} )
+ELSE(LIBDIGIDOCPP_FOUND)
+ SET( LIBDIGIDOCPP_LIBRARIES )
+ENDIF(LIBDIGIDOCPP_FOUND)
+
+MARK_AS_ADVANCED(LIBDIGIDOCPP_LIBRARY LIBDIGIDOCPP_INCLUDE_DIR)
diff --git a/cmake/modules/FindMiniZip.cmake b/cmake/modules/FindMiniZip.cmake
new file mode 100644
index 0000000..04fb521
--- /dev/null
+++ b/cmake/modules/FindMiniZip.cmake
@@ -0,0 +1,30 @@
+# - Find minizip
+# Find the native MINIZIP includes and library
+#
+# MINIZIP_INCLUDE_DIR - where to find minizip.h, etc.
+# MINIZIP_LIBRARIES - List of libraries when using minizip.
+# MINIZIP_FOUND - True if minizip found.
+
+
+IF (MINIZIP_INCLUDE_DIR)
+ # Already in cache, be silent
+ SET(MINIZIP_FIND_QUIETLY TRUE)
+ENDIF (MINIZIP_INCLUDE_DIR)
+
+FIND_PATH(MINIZIP_INCLUDE_DIR zip.h PATH_SUFFIXES minizip)
+
+SET(MINIZIP_NAMES minizip)
+FIND_LIBRARY(MINIZIP_LIBRARY NAMES ${MINIZIP_NAMES} )
+
+# handle the QUIETLY and REQUIRED arguments and set MINIZIP_FOUND to TRUE if
+# all listed variables are TRUE
+INCLUDE(FindPackageHandleStandardArgs)
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(MiniZip DEFAULT_MSG MINIZIP_LIBRARY MINIZIP_INCLUDE_DIR)
+
+IF(MINIZIP_FOUND)
+ SET( MINIZIP_LIBRARIES ${MINIZIP_LIBRARY} )
+ELSE(MINIZIP_FOUND)
+ SET( MINIZIP_LIBRARIES )
+ENDIF(MINIZIP_FOUND)
+
+MARK_AS_ADVANCED( MINIZIP_LIBRARY MINIZIP_INCLUDE_DIR )
diff --git a/cmake/modules/FindPCSCLite.cmake b/cmake/modules/FindPCSCLite.cmake
new file mode 100644
index 0000000..f6cbc55
--- /dev/null
+++ b/cmake/modules/FindPCSCLite.cmake
@@ -0,0 +1,44 @@
+# - Find PCSC-Lite
+# Find the native PCSC-Lite includes and library
+#
+# PCSCLITE_INCLUDE_DIR - where to find winscard.h, wintypes.h, etc.
+# PCSCLITE_LIBRARIES - List of libraries when using PCSC-Lite.
+# PCSCLITE_FOUND - True if PCSC-Lite found.
+
+
+IF (PCSCLITE_INCLUDE_DIR AND PCSCLITE_LIBRARIES)
+ # Already in cache, be silent
+ SET(PCSCLITE_FIND_QUIETLY TRUE)
+ENDIF (PCSCLITE_INCLUDE_DIR AND PCSCLITE_LIBRARIES)
+
+IF (NOT WIN32)
+ FIND_PACKAGE(PkgConfig)
+ PKG_CHECK_MODULES(PC_PCSCLITE libpcsclite)
+ENDIF (NOT WIN32)
+
+FIND_PATH(PCSCLITE_INCLUDE_DIR winscard.h
+ HINTS
+ /usr/include/PCSC
+ ${PC_PCSCLITE_INCLUDEDIR}
+ ${PC_PCSCLITE_INCLUDE_DIRS}
+ ${PC_PCSCLITE_INCLUDE_DIRS}/PCSC
+ )
+
+FIND_LIBRARY(PCSCLITE_LIBRARY NAMES pcsclite libpcsclite PCSC
+ HINTS
+ ${PC_PCSCLITE_LIBDIR}
+ ${PC_PCSCLITE_LIBRARY_DIRS}
+ )
+
+# handle the QUIETLY and REQUIRED arguments and set PCSCLITE_FOUND to TRUE if
+# all listed variables are TRUE
+INCLUDE(FindPackageHandleStandardArgs)
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(PCSC-Lite DEFAULT_MSG PCSCLITE_LIBRARY PCSCLITE_INCLUDE_DIR)
+
+IF(PCSCLITE_FOUND)
+ SET( PCSCLITE_LIBRARIES ${PCSCLITE_LIBRARY} )
+ELSE(PCSCLITE_FOUND)
+ SET( PCSCLITE_LIBRARIES )
+ENDIF(PCSCLITE_FOUND)
+
+MARK_AS_ADVANCED( PCSCLITE_LIBRARY PCSCLITE_INCLUDE_DIR )
diff --git a/cmake/modules/FindPKCS11.cmake b/cmake/modules/FindPKCS11.cmake
new file mode 100644
index 0000000..d4e3110
--- /dev/null
+++ b/cmake/modules/FindPKCS11.cmake
@@ -0,0 +1,24 @@
+# - Find pkcs11
+# Find the PKCS11 module
+#
+# PKCS11_MODULE - pkcs11 module path and name
+# PKCS11_MODULE_FOUND - True if pkcs11 module found.
+
+if( WIN32 )
+ set( PKCS11_NAME esteid-pkcs11.dll opensc-pkcs11.dll )
+else()
+ set( PKCS11_NAME esteid-pkcs11.so opensc-pkcs11.so )
+endif()
+
+if( APPLE )
+ find_library( PKCS11_MODULE NAMES ${PKCS11_NAME} HINTS /Library/EstonianIDCard/lib /Library/OpenSC/lib )
+else()
+ list( GET PKCS11_NAME 1 PKCS11_MODULE )
+endif()
+
+# handle the QUIETLY and REQUIRED arguments and set PKCS11_MODULE_FOUND to TRUE if
+# all listed variables are TRUE
+include( FindPackageHandleStandardArgs )
+FIND_PACKAGE_HANDLE_STANDARD_ARGS( PKCS11_Module DEFAULT_MSG PKCS11_MODULE )
+
+MARK_AS_ADVANCED( PKCS11_MODULE )
diff --git a/cmake/modules/FindXSD.cmake b/cmake/modules/FindXSD.cmake
new file mode 100644
index 0000000..2e168f1
--- /dev/null
+++ b/cmake/modules/FindXSD.cmake
@@ -0,0 +1,52 @@
+# - Find XSD
+# Find XSD includes and executable
+#
+# XSD_INCLUDE_DIR - Where to find xsd include sub-directory.
+# XSD_EXECUTABLE - XSD compiler.
+# XSD_FOUND - True if XSD found.
+
+
+IF (XSD_INCLUDE_DIR)
+ # Already in cache, be silent.
+ SET(XSD_FIND_QUIETLY TRUE)
+ENDIF (XSD_INCLUDE_DIR)
+
+FIND_PATH(XSD_INCLUDE_DIR xsd/cxx/parser/elements.hxx HINTS /Library/EstonianIDCard/include)
+
+SET(XSD_NAMES xsdcxx xsdgen xsd)
+FIND_PROGRAM(XSD_EXECUTABLE NAMES ${XSD_NAMES} HINTS /Library/EstonianIDCard/bin)
+if(XSD_EXECUTABLE)
+ execute_process (COMMAND ${XSD_EXECUTABLE} "--version" OUTPUT_VARIABLE EXEC_OUT)
+ string(REGEX REPLACE ".*compiler ([0-9]+)\\.([0-9]+)\\.([0-9]+).*" "\\1" XSD_VERSION_MAJOR ${EXEC_OUT})
+ string(REGEX REPLACE ".*compiler ([0-9]+)\\.([0-9]+)\\.([0-9]+).*" "\\2" XSD_VERSION_MINOR ${EXEC_OUT})
+ string(REGEX REPLACE ".*compiler ([0-9]+)\\.([0-9]+)\\.([0-9]+).*" "\\3" XSD_VERSION_PATCH ${EXEC_OUT})
+ set(XSD_VERSION "${XSD_VERSION_MAJOR}.${XSD_VERSION_MINOR}.${XSD_VERSION_PATCH}")
+ set(XSD_VERSION_COUNT 3)
+endif()
+
+# Handle the QUIETLY and REQUIRED arguments and set XSD_FOUND to
+# TRUE if all listed variables are TRUE.
+INCLUDE(FindPackageHandleStandardArgs)
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(XSD REQUIRED_VARS XSD_EXECUTABLE XSD_INCLUDE_DIR VERSION_VAR XSD_VERSION)
+
+MARK_AS_ADVANCED( XSD_EXECUTABLE XSD_INCLUDE_DIR )
+
+macro( XSD_SCHEMA SOURCES HEADERS OUTPUT INPUT )
+ get_filename_component( NAME "${INPUT}" NAME )
+ get_filename_component( BASE "${NAME}" NAME_WE )
+ list( APPEND ${SOURCES} ${OUTPUT}/${BASE}.cxx )
+ list( APPEND ${HEADERS} ${OUTPUT}/${BASE}.hxx )
+ add_custom_command(
+ OUTPUT ${OUTPUT}/${BASE}.cxx ${OUTPUT}/${BASE}.hxx
+ COMMAND ${CMAKE_COMMAND} -E make_directory ${OUTPUT}
+ COMMAND ${XSD_EXECUTABLE} cxx-tree
+ --type-naming ucc
+ --function-naming lcc
+ --generate-serialization
+ --std c++11
+ --output-dir ${OUTPUT}
+ ${ARGN}
+ ${INPUT}
+ DEPENDS ${INPUT}
+ )
+endmacro()
diff --git a/cmake/modules/FindXercesC.cmake b/cmake/modules/FindXercesC.cmake
new file mode 100644
index 0000000..2d5c1cf
--- /dev/null
+++ b/cmake/modules/FindXercesC.cmake
@@ -0,0 +1,30 @@
+# - Find Xerces-C
+# Find the Xerces-C includes and library
+#
+# XERCESC_INCLUDE_DIR - Where to find xercesc include sub-directory.
+# XERCESC_LIBRARIES - List of libraries when using Xerces-C.
+# XERCESC_FOUND - True if Xerces-C found.
+
+
+IF (XERCESC_INCLUDE_DIR)
+ # Already in cache, be silent.
+ SET(XERCESC_FIND_QUIETLY TRUE)
+ENDIF (XERCESC_INCLUDE_DIR)
+
+FIND_PATH(XERCESC_INCLUDE_DIR xercesc/dom/DOM.hpp HINTS /Library/EstonianIDCard/include)
+
+SET(XERCESC_NAMES xerces-c xerces-c_3 xerces-c_2)
+FIND_LIBRARY(XERCESC_LIBRARY NAMES ${XERCESC_NAMES} HINTS /Library/EstonianIDCard/lib)
+
+# Handle the QUIETLY and REQUIRED arguments and set XERCESC_FOUND to
+# TRUE if all listed variables are TRUE.
+INCLUDE(FindPackageHandleStandardArgs)
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(XercesC DEFAULT_MSG XERCESC_LIBRARY XERCESC_INCLUDE_DIR)
+
+IF(XERCESC_FOUND)
+ SET( XERCESC_LIBRARIES ${XERCESC_LIBRARY} )
+ELSE(XERCESC_FOUND)
+ SET( XERCESC_LIBRARIES )
+ENDIF(XERCESC_FOUND)
+
+MARK_AS_ADVANCED( XERCESC_LIBRARY XERCESC_INCLUDE_DIR )
diff --git a/cmake/modules/FindXmlSecurityC.cmake b/cmake/modules/FindXmlSecurityC.cmake
new file mode 100644
index 0000000..9912c81
--- /dev/null
+++ b/cmake/modules/FindXmlSecurityC.cmake
@@ -0,0 +1,38 @@
+# - Find XML-Security-C
+# Find the XML-Security-C includes and library
+#
+# XMLSECURITYC_INCLUDE_DIR - Where to find xsec include sub-directory.
+# XMLSECURITYC_LIBRARIES - List of libraries when using XML-Security-C.
+# XMLSECURITYC_FOUND - True if XML-Security-C found.
+
+
+IF (XMLSECURITYC_INCLUDE_DIR)
+ # Already in cache, be silent.
+ SET(XMLSECURITYC_FIND_QUIETLY TRUE)
+ENDIF (XMLSECURITYC_INCLUDE_DIR)
+
+#FIND_PATH(XALANC_INCLUDE_DIR xalanc/XalanTransformer/XalanTransformer.hpp HINTS /Library/EstonianIDCard/include)
+FIND_PATH(XMLSECURITYC_INCLUDE_DIR xsec/utils/XSECPlatformUtils.hpp HINTS /Library/EstonianIDCard/include)
+
+#FIND_LIBRARY(XALANC_LIBRARY NAMES xalan-c xalan-C_1 HINTS /Library/EstonianIDCard/lib)
+#FIND_LIBRARY(XALANMSG_LIBRARY NAMES xalanMsg XalanMessages_1 HINTS /Library/EstonianIDCard/lib)
+FIND_LIBRARY(XMLSECURITYC_LIBRARY NAMES xml-security-c xsec_1 HINTS /Library/EstonianIDCard/lib)
+
+# Handle the QUIETLY and REQUIRED arguments and set XMLSECURITYC_FOUND to
+# TRUE if all listed variables are TRUE.
+INCLUDE(FindPackageHandleStandardArgs)
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(XmlSecurityC DEFAULT_MSG XMLSECURITYC_LIBRARY XMLSECURITYC_INCLUDE_DIR)
+
+IF(XMLSECURITYC_FOUND)
+ SET(XMLSECURITYC_INCLUDE_DIRS ${XMLSECURITYC_INCLUDE_DIR})
+ SET(XMLSECURITYC_LIBRARIES ${XMLSECURITYC_LIBRARY})
+ IF(XALANC_LIBRARY)
+ LIST(APPEND XMLSECURITYC_INCLUDE_DIRS ${XALANC_INCLUDE_DIR})
+ LIST(APPEND XMLSECURITYC_LIBRARIES ${XALANC_LIBRARY})
+ ENDIF()
+ELSE()
+ SET(XMLSECURITYC_INCLUDE_DIRS)
+ SET(XMLSECURITYC_LIBRARIES)
+ENDIF()
+
+MARK_AS_ADVANCED(XMLSECURITYC_LIBRARY XMLSECURITYC_INCLUDE_DIR XALANC_LIBRARY XALANC_INCLUDE_DIR XALANMSG_LIBRARY)
diff --git a/cmake/modules/MacOSXBundleInfo.plist.in b/cmake/modules/MacOSXBundleInfo.plist.in
new file mode 100644
index 0000000..e7f2177
--- /dev/null
+++ b/cmake/modules/MacOSXBundleInfo.plist.in
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>CFBundleDevelopmentRegion</key>
+ <string>English</string>
+ <key>CFBundleExecutable</key>
+ <string>${MACOSX_BUNDLE_EXECUTABLE_NAME}</string>
+ <key>CFBundleIconFile</key>
+ <string>${MACOSX_BUNDLE_ICON_FILE}</string>
+ <key>CFBundleIdentifier</key>
+ <string>${MACOSX_BUNDLE_GUI_IDENTIFIER}</string>
+ <key>CFBundleInfoDictionaryVersion</key>
+ <string>6.0</string>
+ <key>CFBundleName</key>
+ <string>${MACOSX_BUNDLE_BUNDLE_NAME}</string>
+ <key>CFBundlePackageType</key>
+ <string>APPL</string>
+ <key>CFBundleShortVersionString</key>
+ <string>${MACOSX_BUNDLE_SHORT_VERSION_STRING}</string>
+ <key>CFBundleVersion</key>
+ <string>${MACOSX_BUNDLE_BUNDLE_VERSION}</string>
+ <key>NSHumanReadableCopyright</key>
+ <string>${MACOSX_BUNDLE_COPYRIGHT}</string>
+ <key>NSPrincipalClass</key>
+ <string>NSApplication</string>
+ <key>NSHighResolutionCapable</key>
+ <true/>
+ <key>LSHasLocalizedDisplayName</key>
+ <true/>
+ <key>LSApplicationCategoryType</key>
+ <string>public.app-category.utilities</string>
+ <key>LSMinimumSystemVersion</key>
+ <string>10.7</string>
+</dict>
+</plist>
diff --git a/cmake/modules/VersionInfo.cmake b/cmake/modules/VersionInfo.cmake
new file mode 100644
index 0000000..2955ce1
--- /dev/null
+++ b/cmake/modules/VersionInfo.cmake
@@ -0,0 +1,95 @@
+set( MAJOR_VER 3 )
+set( MINOR_VER 10 )
+set( RELEASE_VER 1 )
+set( BUILD_VER 1208 )
+if( $ENV{BUILD_NUMBER} )
+ set( BUILD_VER 1208 )
+endif()
+
+if( WIN32 )
+ execute_process( COMMAND "cmd.exe" "/C date /T" OUTPUT_VARIABLE BUILD_DATE )
+ string( REGEX REPLACE ".*([0-3][0-9]).([0-1][0-9]).([0-9][0-9][0-9][0-9]).*" "\\1.\\2.\\3" BUILD_DATE ${BUILD_DATE} )
+elseif( UNIX )
+ execute_process( COMMAND "date" "+%d.%m.%Y" OUTPUT_VARIABLE BUILD_DATE OUTPUT_STRIP_TRAILING_WHITESPACE )
+else()
+ message( SEND_ERROR "date not implemented")
+ set( BUILD_DATE "00.00.0000" )
+endif()
+
+set( VERSION ${MAJOR_VER}.${MINOR_VER}.${RELEASE_VER}.${BUILD_VER} )
+add_definitions(
+ -DMAJOR_VER=${MAJOR_VER}
+ -DMINOR_VER=${MINOR_VER}
+ -DRELEASE_VER=${RELEASE_VER}
+ -DBUILD_VER=${BUILD_VER}
+ -DVER_SUFFIX=\"$ENV{VER_SUFFIX}\"
+ -DBUILD_DATE=\"${BUILD_DATE}\"
+ -DDOMAINURL=\"ria.ee\"
+ -DORG=\"RIA\"
+)
+
+set( MACOSX_BUNDLE_COPYRIGHT "(C) 2010-2015 Estonian Information System Authority" )
+set( MACOSX_BUNDLE_SHORT_VERSION_STRING ${MAJOR_VER}.${MINOR_VER}.${RELEASE_VER} )
+set( MACOSX_BUNDLE_BUNDLE_VERSION ${BUILD_VER} )
+set( MACOSX_BUNDLE_ICON_FILE Icon.icns )
+set( MACOSX_FRAMEWORK_SHORT_VERSION_STRING ${MAJOR_VER}.${MINOR_VER}.${RELEASE_VER} )
+set( MACOSX_FRAMEWORK_BUNDLE_VERSION ${BUILD_VER} )
+
+macro( SET_APP_NAME OUTPUT NAME )
+ set( ${OUTPUT} "${NAME}" )
+ add_definitions( -DAPP=\"${NAME}\" )
+ set( MACOSX_BUNDLE_BUNDLE_NAME ${NAME} )
+ set( MACOSX_BUNDLE_GUI_IDENTIFIER "ee.ria.${NAME}" )
+ if( APPLE )
+ file( GLOB_RECURSE RESOURCE_FILES
+ ${CMAKE_CURRENT_SOURCE_DIR}/mac/Resources/*.icns
+ ${CMAKE_CURRENT_SOURCE_DIR}/mac/Resources/*.strings )
+ foreach( _file ${RESOURCE_FILES} )
+ get_filename_component( _file_dir ${_file} PATH )
+ file( RELATIVE_PATH _file_dir ${CMAKE_CURRENT_SOURCE_DIR}/mac ${_file_dir} )
+ set_source_files_properties( ${_file} PROPERTIES MACOSX_PACKAGE_LOCATION ${_file_dir} )
+ endforeach( _file )
+ endif( APPLE )
+endmacro()
+
+macro( add_manifest TARGET )
+ if( WIN32 )
+ add_custom_command(TARGET ${TARGET} POST_BUILD
+ COMMAND mt -manifest "${CMAKE_MODULE_PATH}/win81.exe.manifest" -outputresource:"$<TARGET_FILE:${TARGET}>")
+ endif()
+endmacro()
+
+macro( SET_EX NAME VAR DEF )
+ if( "${VAR}" STREQUAL "" )
+ set( ${NAME} ${DEF} ${ARGN} )
+ else()
+ set( ${NAME} ${VAR} ${ARGN} )
+ endif()
+endmacro()
+
+if(CMAKE_COMPILER_IS_GNUCC OR __COMPILER_GNU)
+ if(NOT DEFINED ENABLE_VISIBILITY)
+ set(CMAKE_C_FLAGS "${CMAKE_CXX_FLAGS} -fvisibility=hidden")
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fvisibility=hidden -fvisibility-inlines-hidden")
+ #set( CMAKE_C_VISIBILITY_PRESET hidden )
+ #set( CMAKE_CXX_VISIBILITY_PRESET hidden )
+ #set( CMAKE_VISIBILITY_INLINES_HIDDEN 1 )
+ endif()
+
+ if(NOT DISABLE_CXX11)
+ include(CheckCXXCompilerFlag)
+ CHECK_CXX_COMPILER_FLAG(-std=c++11 C11)
+ CHECK_CXX_COMPILER_FLAG(-std=c++0x C0X)
+ if(C11)
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
+ elseif(C0X)
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x")
+ endif()
+ set(CMAKE_XCODE_ATTRIBUTE_CLANG_CXX_LANGUAGE_STANDARD "c++0x")
+ endif()
+ if(APPLE)
+ set(CMAKE_XCODE_ATTRIBUTE_CLANG_CXX_LIBRARY "libc++")
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++")
+ set(CMAKE_OSX_DEPLOYMENT_TARGET "10.7")
+ endif()
+endif()
diff --git a/cmake/modules/win81.exe.manifest b/cmake/modules/win81.exe.manifest
new file mode 100644
index 0000000..e74e0f6
--- /dev/null
+++ b/cmake/modules/win81.exe.manifest
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
+ <trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
+ <security>
+ <requestedPrivileges>
+ <requestedExecutionLevel level="asInvoker" uiAccess="false"></requestedExecutionLevel>
+ </requestedPrivileges>
+ </security>
+ </trustInfo>
+ <compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
+ <application>
+ <!-- Windows Vista -->
+ <supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}"/>
+ <!-- Windows 7 -->
+ <supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/>
+ <!-- Windows 8 -->
+ <supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"/>
+ <!-- Windows 8.1 -->
+ <supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/>
+ <!-- Windows 10 -->
+ <supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"/>
+ </application>
+ </compatibility>
+</assembly>
diff --git a/config.h.cmake b/config.h.cmake
new file mode 100644
index 0000000..e8318f9
--- /dev/null
+++ b/config.h.cmake
@@ -0,0 +1,7 @@
+/* default config file for libdigidoc */
+#define SYSCONFDIR "@CMAKE_INSTALL_FULL_SYSCONFDIR@"
+
+/* Version number of package */
+#define VERSION "@VERSION@"
+#define DIGIDOC_VERSION "@VERSION@"
+#define VERSION_COMMA @MAJOR_VER@,@MINOR_VER@,@RELEASE_VER@,@BUILD_VER@
diff --git a/debian/changelog b/debian/changelog
new file mode 100644
index 0000000..8c8aeb2
--- /dev/null
+++ b/debian/changelog
@@ -0,0 +1,5 @@
+libdigidoc (3.10.1.1208-1) unstable; urgency=medium
+
+ * Initial upload (Closes: #658300).
+
+ -- Andrew Shadura <andrewsh@debian.org> Sun, 01 Nov 2015 19:41:28 +0100
diff --git a/debian/compat b/debian/compat
new file mode 100644
index 0000000..ec63514
--- /dev/null
+++ b/debian/compat
@@ -0,0 +1 @@
+9
diff --git a/debian/control b/debian/control
new file mode 100644
index 0000000..a5bff60
--- /dev/null
+++ b/debian/control
@@ -0,0 +1,129 @@
+Source: libdigidoc
+Section: libs
+Priority: extra
+Maintainer: Andrew Shadura <andrewsh@debian.org>
+Build-Depends:
+ debhelper (>= 9),
+ cmake,
+ libssl-dev,
+ libxml2-dev,
+ zlib1g-dev
+Standards-Version: 3.9.6
+Homepage: https://github.com/open-eid/libdigidoc
+
+Package: libdigidoc-common
+Architecture: all
+Section: misc
+Multi-Arch: foreign
+Depends:
+ ${misc:Depends}
+Breaks:
+ libdigidoc2 (<< ${binary:Version})
+Replaces:
+ libdigidoc2 (<< ${binary:Version})
+Description: DigiDoc digital signature library common files
+ DigiDoc is an XML file format for documents with digital signatures in use by
+ the Estonian ID card infrastructure. This library allows for creation and
+ reading of DigiDoc files.
+ .
+ This library implements a subset of the XAdES digital signature standard on
+ top of Estonian-specific .ddoc container format.
+ .
+ This package contains common architecture-independent files for the
+ applications using the DigiDoc digital signature library.
+
+Package: libdigidoc2
+Replaces:
+ libdigidoc
+Breaks:
+ libdigidoc
+Architecture: any
+Multi-Arch: same
+Pre-Depends:
+ ${misc:Pre-Depends}
+Depends:
+ libdigidoc-common (= ${source:Version}),
+ opensc,
+ pcscd,
+ ${misc:Depends},
+ ${shlibs:Depends}
+Description: DigiDoc digital signature library
+ DigiDoc is an XML file format for documents with digital signatures in use by
+ the Estonian ID card infrastructure. This library allows for creation and
+ reading of DigiDoc files.
+ .
+ This library implements a subset of the XAdES digital signature standard on
+ top of Estonian-specific .ddoc container format.
+ .
+ This package provides the shared libraries.
+
+Package: libdigidoc-tools
+Architecture: any
+Section: misc
+Depends:
+ libdigidoc2 (= ${binary:Version}),
+ ${misc:Depends},
+ ${shlibs:Depends}
+Description: DigiDoc digital signature library tools
+ DigiDoc is an XML file format for documents with digital signatures in use by
+ the Estonian ID card infrastructure. This library allows for creation and
+ reading of DigiDoc files.
+ .
+ This library implements a subset of the XAdES digital signature standard on
+ top of Estonian-specific .ddoc container format.
+ .
+ This package contains tools for manipulating signatures created with the
+ DigiDoc digital signature library.
+
+Package: libdigidoc-dbg
+Architecture: any
+Section: debug
+Multi-Arch: same
+Depends:
+ libdigidoc2 (= ${binary:Version}),
+ libssl1.0.0-dbg,
+ libxml2-dbg,
+ ${misc:Depends}
+Description: debugging symbols for DigiDoc digital signature library
+ DigiDoc is an XML file format for documents with digital signatures in use by
+ the Estonian ID card infrastructure. This library allows for creation and
+ reading of DigiDoc files.
+ .
+ This library implements a subset of the XAdES digital signature standard on
+ top of Estonian-specific .ddoc container format.
+ .
+ This package provides the debugging symbols.
+
+Package: libdigidoc-dev
+Architecture: any
+Section: libdevel
+Depends:
+ libdigidoc2 (= ${binary:Version}),
+ libssl-dev,
+ libxml2-dev,
+ ${misc:Depends}
+Description: DigiDoc digital signature development files
+ DigiDoc is an XML file format for documents with digital signatures in use by
+ the Estonian ID card infrastructure. This library allows for creation and
+ reading of DigiDoc files.
+ .
+ This library implements a subset of the XAdES digital signature standard on
+ top of Estonian-specific .ddoc container format.
+ .
+ This package provides the development files.
+
+Package: libdigidoc-doc
+Architecture: all
+Section: doc
+Depends:
+ ${misc:Depends}
+Description: DigiDoc digital signature library documentation
+ DigiDoc is an XML file format for documents with digital signatures in use by
+ the Estonian ID card infrastructure. This library allows for creation and
+ reading of DigiDoc files.
+ .
+ This library implements a subset of the XAdES digital signature standard on
+ top of Estonian-specific .ddoc container format.
+ .
+ This package contains documentation for developing applications with the
+ DigiDoc digital signature library.
diff --git a/debian/copyright b/debian/copyright
new file mode 100644
index 0000000..fc1f191
--- /dev/null
+++ b/debian/copyright
@@ -0,0 +1,28 @@
+Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
+Upstream-Name: libdigidoc
+Upstream-Contact: abi@id.ee
+Source: https://github.com/open-eid/libdigidoc
+
+Files: *
+Copyright: 2012—2015 Estonian Information System's Authority
+License: LGPL-2.1+
+
+Files: debian/*
+Copyright:
+ 2012—2015 Estonian Information System's Authority
+ 2015 Andrew Shadura <andrewsh@debian.org>
+License: LGPL-2.1+
+
+License: LGPL-2.1+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+ .
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+ .
+ On Debian systems, the complete text of the GNU Lesser General Public
+ License can be found in </usr/share/common-licenses/LGPL-2.1>.
diff --git a/debian/libdigidoc-common.install b/debian/libdigidoc-common.install
new file mode 100644
index 0000000..468beba
--- /dev/null
+++ b/debian/libdigidoc-common.install
@@ -0,0 +1,2 @@
+debian/tmp/etc
+debian/tmp/usr/share/libdigidoc
diff --git a/debian/libdigidoc-dev.install b/debian/libdigidoc-dev.install
new file mode 100644
index 0000000..af8a8e5
--- /dev/null
+++ b/debian/libdigidoc-dev.install
@@ -0,0 +1,4 @@
+usr/include
+usr/lib/*/lib*.so
+usr/lib/*/pkgconfig
+usr/share/libdigidoc/TEST*
diff --git a/debian/libdigidoc-doc.install b/debian/libdigidoc-doc.install
new file mode 100644
index 0000000..7276ecd
--- /dev/null
+++ b/debian/libdigidoc-doc.install
@@ -0,0 +1 @@
+usr/share/doc
diff --git a/debian/libdigidoc-tools.install b/debian/libdigidoc-tools.install
new file mode 100644
index 0000000..a65408f
--- /dev/null
+++ b/debian/libdigidoc-tools.install
@@ -0,0 +1,2 @@
+usr/bin
+usr/share/man
diff --git a/debian/libdigidoc2.install b/debian/libdigidoc2.install
new file mode 100644
index 0000000..3ddde58
--- /dev/null
+++ b/debian/libdigidoc2.install
@@ -0,0 +1 @@
+usr/lib/*/lib*.so.*
diff --git a/debian/patches/01-manpage.patch b/debian/patches/01-manpage.patch
new file mode 100644
index 0000000..f79a6a6
--- /dev/null
+++ b/debian/patches/01-manpage.patch
@@ -0,0 +1,32 @@
+From fa90da1834c255ed72e377a96e5c92f8e1a858de Mon Sep 17 00:00:00 2001
+From: Andrew Shadura <andrew@shadura.me>
+Date: Sun, 1 Nov 2015 19:07:15 +0100
+Subject: [PATCH] Fix spelling in the manpage
+
+Signed-off-by: Andrew Shadura <andrew@shadura.me>
+---
+ libdigidoc/cdigidoc.1.cmake | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/libdigidoc/cdigidoc.1.cmake b/libdigidoc/cdigidoc.1.cmake
+index 20ad67e..effe492 100644
+--- a/libdigidoc/cdigidoc.1.cmake
++++ b/libdigidoc/cdigidoc.1.cmake
+@@ -200,7 +200,7 @@ Decrypts and possibly decompresses the encrypted file just read in and writes to
+ Input file (required) specifies the input file’s name.
+ Pin (required) represents the recipient’s pin1 (in context of Estonian ID cards).
+ pkcs12-file (optional) specifies the PKCS#12 file if decrypting is done with a software token.
+-slot deafult is slot 0 containing Estonian ID cards authentication keypair. This parameter can be used to decrypt with a key from the second id card attached to the computer etc.
++slot default is slot 0 containing Estonian ID cards authentication keypair. This parameter can be used to decrypt with a key from the second id card attached to the computer etc.
+ Note: There are also alternative commands for decryption, depending on the encrypted file’s format, size and the certificate type used for decrypting it.
+ .RS
+ .TP
+@@ -209,7 +209,7 @@ Offers same functionality as -decrypt-sk, should be used for decrypting small fi
+ Input file (required) specifies the input file’s name.
+ Pin (required) represents the recipient’s pin1 (in contexts of Estonian ID cards).
+ pkcs12-file (optional) specifies the PKCS#12 file if decrypting is done with a software token.
+-slot deafult is slot 0 containing Estonian ID cards authentication keypair. This parameter can be used to decrypt with a key from the second id card attached to the computer etc.
++slot default is slot 0 containing Estonian ID cards authentication keypair. This parameter can be used to decrypt with a key from the second id card attached to the computer etc.
+ .TP
+ .I "-decrypt-file <input-file> <output-file> <pin> [pkcs12-file]"
+ Offers same functionality as -decrypt for decrypting documents, should be used for decrypting large files (which do not need to be inside a DigiDoc container). Expects the encrypted data not to be compressed. Note that the command is not currently tested.
diff --git a/debian/patches/02-no-rpath.patch b/debian/patches/02-no-rpath.patch
new file mode 100644
index 0000000..9e03800
--- /dev/null
+++ b/debian/patches/02-no-rpath.patch
@@ -0,0 +1,12 @@
+Subject: No rpath, please.
+
+--- a/libdigidoc/CMakeLists.txt
++++ b/libdigidoc/CMakeLists.txt
+@@ -94,7 +94,6 @@
+ )
+
+ add_executable(cdigidoc cdigidoc.c cdigidoc.rc)
+-set_target_properties(cdigidoc PROPERTIES INSTALL_RPATH "@loader_path/../../../..;@loader_path/../..")
+ target_link_libraries(cdigidoc digidoc)
+
+ install( TARGETS digidoc
diff --git a/debian/patches/series b/debian/patches/series
new file mode 100644
index 0000000..b8d86dd
--- /dev/null
+++ b/debian/patches/series
@@ -0,0 +1,2 @@
+01-manpage.patch
+02-no-rpath.patch
diff --git a/debian/rules b/debian/rules
new file mode 100755
index 0000000..3104e56
--- /dev/null
+++ b/debian/rules
@@ -0,0 +1,23 @@
+#!/usr/bin/make -f
+
+DEB_HOST_MULTIARCH ?= $(shell dpkg-architecture -qDEB_HOST_MULTIARCH)
+
+DEB_CMAKE_EXTRA_FLAGS = \
+ -DCMAKE_INSTALL_SYSCONFDIR="/etc" \
+ -DCMAKE_INSTALL_LIBDIR="lib/$(DEB_HOST_MULTIARCH)" \
+ -DINSTALL_DOC=YES
+
+%:
+ dh "$@" --buildsystem=cmake
+
+override_dh_auto_configure:
+ dh_auto_configure -- $(DEB_CMAKE_EXTRA_FLAGS)
+
+override_dh_strip:
+ dh_strip --dbg-package=libdigidoc-dbg
+
+override_dh_install:
+ dh_install -plibdigidoc-common --exclude=TEST
+ dh_install --remaining-packages --list-missing
+
+.PHONY: override_dh_auto_configure
diff --git a/debian/source/format b/debian/source/format
new file mode 100644
index 0000000..163aaf8
--- /dev/null
+++ b/debian/source/format
@@ -0,0 +1 @@
+3.0 (quilt)
diff --git a/debian/watch b/debian/watch
new file mode 100644
index 0000000..2785dc9
--- /dev/null
+++ b/debian/watch
@@ -0,0 +1,3 @@
+version=3
+
+https://github.com/open-eid/libdigidoc/releases /open-eid/libdigidoc/releases/download/.*/libdigidoc-([\d.]*).tar.gz
diff --git a/doc/SK-CDD-PRG-GUIDE.docx b/doc/SK-CDD-PRG-GUIDE.docx
new file mode 100644
index 0000000..028444f
--- /dev/null
+++ b/doc/SK-CDD-PRG-GUIDE.docx
Binary files differ
diff --git a/doc/SK-CDD-PRG-GUIDE.pdf b/doc/SK-CDD-PRG-GUIDE.pdf
new file mode 100644
index 0000000..5cff0aa
--- /dev/null
+++ b/doc/SK-CDD-PRG-GUIDE.pdf
Binary files differ
diff --git a/doc/SK-COM-PRG-GUIDE.docx b/doc/SK-COM-PRG-GUIDE.docx
new file mode 100644
index 0000000..7f03d56
--- /dev/null
+++ b/doc/SK-COM-PRG-GUIDE.docx
Binary files differ
diff --git a/doc/SK-COM-PRG-GUIDE.pdf b/doc/SK-COM-PRG-GUIDE.pdf
new file mode 100644
index 0000000..4c89c72
--- /dev/null
+++ b/doc/SK-COM-PRG-GUIDE.pdf
Binary files differ
diff --git a/doc/doxygen-license.txt b/doc/doxygen-license.txt
new file mode 100644
index 0000000..56d505c
--- /dev/null
+++ b/doc/doxygen-license.txt
@@ -0,0 +1,8 @@
+Doxygen license
+
+Copyright © 1997-2014 by Dimitri van Heesch.
+
+Permission to use, copy, modify, and distribute this software and its documentation under the terms of the GNU General Public License is hereby granted. No representations are made about the suitability of this software for any purpose. It is provided "as is" without express or implied warranty. See the GNU General Public License for more details.
+
+Documents produced by doxygen are derivative works derived from the input used in their production; they are not affected by this license.
+
diff --git a/doc/mit-license.txt b/doc/mit-license.txt
new file mode 100644
index 0000000..4a5892d
--- /dev/null
+++ b/doc/mit-license.txt
@@ -0,0 +1,26 @@
+
+The MIT License (MIT)
+[OSI Approved License]
+
+The MIT License (MIT)
+
+Copyright (c) <year> <copyright holders>
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
diff --git a/doc/openssl-license.txt b/doc/openssl-license.txt
new file mode 100644
index 0000000..1c4fd9b
--- /dev/null
+++ b/doc/openssl-license.txt
@@ -0,0 +1,131 @@
+License
+This is a copy of the current LICENSE file inside the CVS repository.
+
+
+ LICENSE ISSUES
+ ==============
+
+ The OpenSSL toolkit stays under a dual license, i.e. both the conditions of
+ the OpenSSL License and the original SSLeay license apply to the toolkit.
+ See below for the actual license texts. Actually both licenses are BSD-style
+ Open Source licenses. In case of any license issues related to OpenSSL
+ please contact openssl-core@openssl.org.
+
+ OpenSSL License
+ ---------------
+
+/* ====================================================================
+ * Copyright (c) 1998-2011 The OpenSSL Project. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgment:
+ * "This product includes software developed by the OpenSSL Project
+ * for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
+ *
+ * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
+ * endorse or promote products derived from this software without
+ * prior written permission. For written permission, please contact
+ * openssl-core@openssl.org.
+ *
+ * 5. Products derived from this software may not be called "OpenSSL"
+ * nor may "OpenSSL" appear in their names without prior written
+ * permission of the OpenSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by the OpenSSL Project
+ * for use in the OpenSSL Toolkit (http://www.openssl.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This product includes cryptographic software written by Eric Young
+ * (eay@cryptsoft.com). This product includes software written by Tim
+ * Hudson (tjh@cryptsoft.com).
+ *
+ */
+
+ Original SSLeay License
+ -----------------------
+
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to. The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code. The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * "This product includes cryptographic software written by
+ * Eric Young (eay@cryptsoft.com)"
+ * The word 'cryptographic' can be left out if the rouines from the library
+ * being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ * the apps directory (application code) you must include an acknowledgement:
+ * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed. i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.]
+ */
+
+
diff --git a/doc/sample_files_CDD.zip b/doc/sample_files_CDD.zip
new file mode 100644
index 0000000..454474a
--- /dev/null
+++ b/doc/sample_files_CDD.zip
Binary files differ
diff --git a/doc/zlib-license.txt b/doc/zlib-license.txt
new file mode 100644
index 0000000..7d05cf5
--- /dev/null
+++ b/doc/zlib-license.txt
@@ -0,0 +1,25 @@
+zlib.h -- interface of the 'zlib' general purpose compression library
+ version 1.2.8, April 28th, 2013
+
+ Copyright (C) 1995-2013 Jean-loup Gailly and Mark Adler
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+
+ Jean-loup Gailly Mark Adler
+ jloup@gzip.org madler@alumni.caltech.edu
+
+
diff --git a/etc/Doxyfile.in b/etc/Doxyfile.in
new file mode 100644
index 0000000..4856712
--- /dev/null
+++ b/etc/Doxyfile.in
@@ -0,0 +1,1804 @@
+# Doxyfile 1.8.1.2
+
+# This file describes the settings to be used by the documentation system
+# doxygen (www.doxygen.org) for a project.
+#
+# All text after a hash (#) is considered a comment and will be ignored.
+# The format is:
+# TAG = value [value, ...]
+# For lists items can also be appended using:
+# TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (" ").
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+
+# This tag specifies the encoding used for all characters in the config file
+# that follow. The default is UTF-8 which is also the encoding used for all
+# text before the first occurrence of this tag. Doxygen uses libiconv (or the
+# iconv built into libc) for the transcoding. See
+# http://www.gnu.org/software/libiconv for the list of possible encodings.
+
+DOXYFILE_ENCODING = UTF-8
+
+# The PROJECT_NAME tag is a single word (or sequence of words) that should
+# identify the project. Note that if you do not use Doxywizard you need
+# to put quotes around the project name if it contains spaces.
+
+PROJECT_NAME = "Estonian ID Card C-library"
+
+# The PROJECT_NUMBER tag can be used to enter a project or revision number.
+# This could be handy for archiving the generated documentation or
+# if some version control system is used.
+
+PROJECT_NUMBER = @DIGIDOC_VERSION@
+
+# Using the PROJECT_BRIEF tag one can provide an optional one line description
+# for a project that appears at the top of each page and should give viewer
+# a quick idea about the purpose of the project. Keep the description short.
+
+PROJECT_BRIEF =
+
+# With the PROJECT_LOGO tag one can specify an logo or icon that is
+# included in the documentation. The maximum height of the logo should not
+# exceed 55 pixels and the maximum width should not exceed 200 pixels.
+# Doxygen will copy the logo to the output directory.
+
+PROJECT_LOGO =
+
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute)
+# base path where the generated documentation will be put.
+# If a relative path is entered, it will be relative to the location
+# where doxygen was started. If left blank the current directory will be used.
+
+OUTPUT_DIRECTORY = @CMAKE_BINARY_DIR@/doc/
+
+# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create
+# 4096 sub-directories (in 2 levels) under the output directory of each output
+# format and will distribute the generated files over these directories.
+# Enabling this option can be useful when feeding doxygen a huge amount of
+# source files, where putting all generated files in the same directory would
+# otherwise cause performance problems for the file system.
+
+CREATE_SUBDIRS = NO
+
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all
+# documentation generated by doxygen is written. Doxygen will use this
+# information to generate all constant output in the proper language.
+# The default language is English, other supported languages are:
+# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional,
+# Croatian, Czech, Danish, Dutch, Esperanto, Farsi, Finnish, French, German,
+# Greek, Hungarian, Italian, Japanese, Japanese-en (Japanese with English
+# messages), Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian,
+# Polish, Portuguese, Romanian, Russian, Serbian, Serbian-Cyrillic, Slovak,
+# Slovene, Spanish, Swedish, Ukrainian, and Vietnamese.
+
+OUTPUT_LANGUAGE = English
+
+# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will
+# include brief member descriptions after the members that are listed in
+# the file and class documentation (similar to JavaDoc).
+# Set to NO to disable this.
+
+BRIEF_MEMBER_DESC = YES
+
+# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend
+# the brief description of a member or function before the detailed description.
+# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
+# brief descriptions will be completely suppressed.
+
+REPEAT_BRIEF = YES
+
+# This tag implements a quasi-intelligent brief description abbreviator
+# that is used to form the text in various listings. Each string
+# in this list, if found as the leading text of the brief description, will be
+# stripped from the text and the result after processing the whole list, is
+# used as the annotated text. Otherwise, the brief description is used as-is.
+# If left blank, the following values are used ("$name" is automatically
+# replaced with the name of the entity): "The $name class" "The $name widget"
+# "The $name file" "is" "provides" "specifies" "contains"
+# "represents" "a" "an" "the"
+
+ABBREVIATE_BRIEF = "The $name class" \
+ "The $name widget" \
+ "The $name file" \
+ is \
+ provides \
+ specifies \
+ contains \
+ represents \
+ a \
+ an \
+ the
+
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
+# Doxygen will generate a detailed section even if there is only a brief
+# description.
+
+ALWAYS_DETAILED_SEC = NO
+
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all
+# inherited members of a class in the documentation of that class as if those
+# members were ordinary class members. Constructors, destructors and assignment
+# operators of the base classes will not be shown.
+
+INLINE_INHERITED_MEMB = NO
+
+# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full
+# path before files name in the file list and in the header files. If set
+# to NO the shortest path that makes the file name unique will be used.
+
+FULL_PATH_NAMES = NO
+
+# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag
+# can be used to strip a user-defined part of the path. Stripping is
+# only done if one of the specified strings matches the left-hand part of
+# the path. The tag can be used to show relative paths in the file list.
+# If left blank the directory from which doxygen is run is used as the
+# path to strip.
+
+STRIP_FROM_PATH =
+
+# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of
+# the path mentioned in the documentation of a class, which tells
+# the reader which header file to include in order to use a class.
+# If left blank only the name of the header file containing the class
+# definition is used. Otherwise one should specify the include paths that
+# are normally passed to the compiler using the -I flag.
+
+STRIP_FROM_INC_PATH =
+
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter
+# (but less readable) file names. This can be useful if your file system
+# doesn't support long names like on DOS, Mac, or CD-ROM.
+
+SHORT_NAMES = NO
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen
+# will interpret the first line (until the first dot) of a JavaDoc-style
+# comment as the brief description. If set to NO, the JavaDoc
+# comments will behave just like regular Qt-style comments
+# (thus requiring an explicit @brief command for a brief description.)
+
+JAVADOC_AUTOBRIEF = NO
+
+# If the QT_AUTOBRIEF tag is set to YES then Doxygen will
+# interpret the first line (until the first dot) of a Qt-style
+# comment as the brief description. If set to NO, the comments
+# will behave just like regular Qt-style comments (thus requiring
+# an explicit \brief command for a brief description.)
+
+QT_AUTOBRIEF = NO
+
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen
+# treat a multi-line C++ special comment block (i.e. a block of //! or ///
+# comments) as a brief description. This used to be the default behaviour.
+# The new default is to treat a multi-line C++ comment block as a detailed
+# description. Set this tag to YES if you prefer the old behaviour instead.
+
+MULTILINE_CPP_IS_BRIEF = NO
+
+# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented
+# member inherits the documentation from any documented member that it
+# re-implements.
+
+INHERIT_DOCS = YES
+
+# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce
+# a new page for each member. If set to NO, the documentation of a member will
+# be part of the file/class/namespace that contains it.
+
+SEPARATE_MEMBER_PAGES = NO
+
+# The TAB_SIZE tag can be used to set the number of spaces in a tab.
+# Doxygen uses this value to replace tabs by spaces in code fragments.
+
+TAB_SIZE = 8
+
+# This tag can be used to specify a number of aliases that acts
+# as commands in the documentation. An alias has the form "name=value".
+# For example adding "sideeffect=\par Side Effects:\n" will allow you to
+# put the command \sideeffect (or @sideeffect) in the documentation, which
+# will result in a user-defined paragraph with heading "Side Effects:".
+# You can put \n's in the value part of an alias to insert newlines.
+
+ALIASES =
+
+# This tag can be used to specify a number of word-keyword mappings (TCL only).
+# A mapping has the form "name=value". For example adding
+# "class=itcl::class" will allow you to use the command class in the
+# itcl::class meaning.
+
+TCL_SUBST =
+
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C
+# sources only. Doxygen will then generate output that is more tailored for C.
+# For instance, some of the names that are used will be different. The list
+# of all members will be omitted, etc.
+
+OPTIMIZE_OUTPUT_FOR_C = NO
+
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java
+# sources only. Doxygen will then generate output that is more tailored for
+# Java. For instance, namespaces will be presented as packages, qualified
+# scopes will look different, etc.
+
+OPTIMIZE_OUTPUT_JAVA = NO
+
+# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran
+# sources only. Doxygen will then generate output that is more tailored for
+# Fortran.
+
+OPTIMIZE_FOR_FORTRAN = NO
+
+# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL
+# sources. Doxygen will then generate output that is tailored for
+# VHDL.
+
+OPTIMIZE_OUTPUT_VHDL = NO
+
+# Doxygen selects the parser to use depending on the extension of the files it
+# parses. With this tag you can assign which parser to use for a given extension.
+# Doxygen has a built-in mapping, but you can override or extend it using this
+# tag. The format is ext=language, where ext is a file extension, and language
+# is one of the parsers supported by doxygen: IDL, Java, Javascript, CSharp, C,
+# C++, D, PHP, Objective-C, Python, Fortran, VHDL, C, C++. For instance to make
+# doxygen treat .inc files as Fortran files (default is PHP), and .f files as C
+# (default is Fortran), use: inc=Fortran f=C. Note that for custom extensions
+# you also need to set FILE_PATTERNS otherwise the files are not read by doxygen.
+
+EXTENSION_MAPPING =
+
+# If MARKDOWN_SUPPORT is enabled (the default) then doxygen pre-processes all
+# comments according to the Markdown format, which allows for more readable
+# documentation. See http://daringfireball.net/projects/markdown/ for details.
+# The output of markdown processing is further processed by doxygen, so you
+# can mix doxygen, HTML, and XML commands with Markdown formatting.
+# Disable only in case of backward compatibilities issues.
+
+MARKDOWN_SUPPORT = YES
+
+# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want
+# to include (a tag file for) the STL sources as input, then you should
+# set this tag to YES in order to let doxygen match functions declarations and
+# definitions whose arguments contain STL classes (e.g. func(std::string); v.s.
+# func(std::string) {}). This also makes the inheritance and collaboration
+# diagrams that involve STL classes more complete and accurate.
+
+BUILTIN_STL_SUPPORT = NO
+
+# If you use Microsoft's C++/CLI language, you should set this option to YES to
+# enable parsing support.
+
+CPP_CLI_SUPPORT = NO
+
+# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only.
+# Doxygen will parse them like normal C++ but will assume all classes use public
+# instead of private inheritance when no explicit protection keyword is present.
+
+SIP_SUPPORT = NO
+
+# For Microsoft's IDL there are propget and propput attributes to indicate getter
+# and setter methods for a property. Setting this option to YES (the default)
+# will make doxygen replace the get and set methods by a property in the
+# documentation. This will only work if the methods are indeed getting or
+# setting a simple type. If this is not the case, or you want to show the
+# methods anyway, you should set this option to NO.
+
+IDL_PROPERTY_SUPPORT = YES
+
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
+# tag is set to YES, then doxygen will reuse the documentation of the first
+# member in the group (if any) for the other members of the group. By default
+# all members of a group must be documented explicitly.
+
+DISTRIBUTE_GROUP_DOC = NO
+
+# Set the SUBGROUPING tag to YES (the default) to allow class member groups of
+# the same type (for instance a group of public functions) to be put as a
+# subgroup of that type (e.g. under the Public Functions section). Set it to
+# NO to prevent subgrouping. Alternatively, this can be done per class using
+# the \nosubgrouping command.
+
+SUBGROUPING = YES
+
+# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and
+# unions are shown inside the group in which they are included (e.g. using
+# @ingroup) instead of on a separate page (for HTML and Man pages) or
+# section (for LaTeX and RTF).
+
+INLINE_GROUPED_CLASSES = NO
+
+# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and
+# unions with only public data fields will be shown inline in the documentation
+# of the scope in which they are defined (i.e. file, namespace, or group
+# documentation), provided this scope is documented. If set to NO (the default),
+# structs, classes, and unions are shown on a separate page (for HTML and Man
+# pages) or section (for LaTeX and RTF).
+
+INLINE_SIMPLE_STRUCTS = NO
+
+# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum
+# is documented as struct, union, or enum with the name of the typedef. So
+# typedef struct TypeS {} TypeT, will appear in the documentation as a struct
+# with name TypeT. When disabled the typedef will appear as a member of a file,
+# namespace, or class. And the struct will be named TypeS. This can typically
+# be useful for C code in case the coding convention dictates that all compound
+# types are typedef'ed and only the typedef is referenced, never the tag name.
+
+TYPEDEF_HIDES_STRUCT = NO
+
+# The SYMBOL_CACHE_SIZE determines the size of the internal cache use to
+# determine which symbols to keep in memory and which to flush to disk.
+# When the cache is full, less often used symbols will be written to disk.
+# For small to medium size projects (<1000 input files) the default value is
+# probably good enough. For larger projects a too small cache size can cause
+# doxygen to be busy swapping symbols to and from disk most of the time
+# causing a significant performance penalty.
+# If the system has enough physical memory increasing the cache will improve the
+# performance by keeping more symbols in memory. Note that the value works on
+# a logarithmic scale so increasing the size by one will roughly double the
+# memory usage. The cache size is given by this formula:
+# 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0,
+# corresponding to a cache size of 2^16 = 65536 symbols.
+
+SYMBOL_CACHE_SIZE = 0
+
+# Similar to the SYMBOL_CACHE_SIZE the size of the symbol lookup cache can be
+# set using LOOKUP_CACHE_SIZE. This cache is used to resolve symbols given
+# their name and scope. Since this can be an expensive process and often the
+# same symbol appear multiple times in the code, doxygen keeps a cache of
+# pre-resolved symbols. If the cache is too small doxygen will become slower.
+# If the cache is too large, memory is wasted. The cache size is given by this
+# formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range is 0..9, the default is 0,
+# corresponding to a cache size of 2^16 = 65536 symbols.
+
+LOOKUP_CACHE_SIZE = 0
+
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+
+# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in
+# documentation are documented, even if no documentation was available.
+# Private class members and static file members will be hidden unless
+# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES
+
+EXTRACT_ALL = NO
+
+# If the EXTRACT_PRIVATE tag is set to YES all private members of a class
+# will be included in the documentation.
+
+EXTRACT_PRIVATE = NO
+
+# If the EXTRACT_PACKAGE tag is set to YES all members with package or internal scope will be included in the documentation.
+
+EXTRACT_PACKAGE = NO
+
+# If the EXTRACT_STATIC tag is set to YES all static members of a file
+# will be included in the documentation.
+
+EXTRACT_STATIC = NO
+
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs)
+# defined locally in source files will be included in the documentation.
+# If set to NO only classes defined in header files are included.
+
+EXTRACT_LOCAL_CLASSES = NO
+
+# This flag is only useful for Objective-C code. When set to YES local
+# methods, which are defined in the implementation section but not in
+# the interface are included in the documentation.
+# If set to NO (the default) only methods in the interface are included.
+
+EXTRACT_LOCAL_METHODS = YES
+
+# If this flag is set to YES, the members of anonymous namespaces will be
+# extracted and appear in the documentation as a namespace called
+# 'anonymous_namespace{file}', where file will be replaced with the base
+# name of the file that contains the anonymous namespace. By default
+# anonymous namespaces are hidden.
+
+EXTRACT_ANON_NSPACES = NO
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all
+# undocumented members of documented classes, files or namespaces.
+# If set to NO (the default) these members will be included in the
+# various overviews, but no documentation section is generated.
+# This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_MEMBERS = NO
+
+# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all
+# undocumented classes that are normally visible in the class hierarchy.
+# If set to NO (the default) these classes will be included in the various
+# overviews. This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_CLASSES = NO
+
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all
+# friend (class|struct|union) declarations.
+# If set to NO (the default) these declarations will be included in the
+# documentation.
+
+HIDE_FRIEND_COMPOUNDS = NO
+
+# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any
+# documentation blocks found inside the body of a function.
+# If set to NO (the default) these blocks will be appended to the
+# function's detailed documentation block.
+
+HIDE_IN_BODY_DOCS = NO
+
+# The INTERNAL_DOCS tag determines if documentation
+# that is typed after a \internal command is included. If the tag is set
+# to NO (the default) then the documentation will be excluded.
+# Set it to YES to include the internal documentation.
+
+INTERNAL_DOCS = NO
+
+# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate
+# file names in lower-case letters. If set to YES upper-case letters are also
+# allowed. This is useful if you have classes or files whose names only differ
+# in case and if your file system supports case sensitive file names. Windows
+# and Mac users are advised to set this option to NO.
+
+CASE_SENSE_NAMES = NO
+
+# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen
+# will show members with their full class and namespace scopes in the
+# documentation. If set to YES the scope will be hidden.
+
+HIDE_SCOPE_NAMES = NO
+
+# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen
+# will put a list of the files that are included by a file in the documentation
+# of that file.
+
+SHOW_INCLUDE_FILES = YES
+
+# If the FORCE_LOCAL_INCLUDES tag is set to YES then Doxygen
+# will list include files with double quotes in the documentation
+# rather than with sharp brackets.
+
+FORCE_LOCAL_INCLUDES = NO
+
+# If the INLINE_INFO tag is set to YES (the default) then a tag [inline]
+# is inserted in the documentation for inline members.
+
+INLINE_INFO = YES
+
+# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen
+# will sort the (detailed) documentation of file and class members
+# alphabetically by member name. If set to NO the members will appear in
+# declaration order.
+
+SORT_MEMBER_DOCS = YES
+
+# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the
+# brief documentation of file, namespace and class members alphabetically
+# by member name. If set to NO (the default) the members will appear in
+# declaration order.
+
+SORT_BRIEF_DOCS = NO
+
+# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen
+# will sort the (brief and detailed) documentation of class members so that
+# constructors and destructors are listed first. If set to NO (the default)
+# the constructors will appear in the respective orders defined by
+# SORT_MEMBER_DOCS and SORT_BRIEF_DOCS.
+# This tag will be ignored for brief docs if SORT_BRIEF_DOCS is set to NO
+# and ignored for detailed docs if SORT_MEMBER_DOCS is set to NO.
+
+SORT_MEMBERS_CTORS_1ST = NO
+
+# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the
+# hierarchy of group names into alphabetical order. If set to NO (the default)
+# the group names will appear in their defined order.
+
+SORT_GROUP_NAMES = NO
+
+# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be
+# sorted by fully-qualified names, including namespaces. If set to
+# NO (the default), the class list will be sorted only by class name,
+# not including the namespace part.
+# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
+# Note: This option applies only to the class list, not to the
+# alphabetical list.
+
+SORT_BY_SCOPE_NAME = NO
+
+# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to
+# do proper type resolution of all parameters of a function it will reject a
+# match between the prototype and the implementation of a member function even
+# if there is only one candidate or it is obvious which candidate to choose
+# by doing a simple string match. By disabling STRICT_PROTO_MATCHING doxygen
+# will still accept a match between prototype and implementation in such cases.
+
+STRICT_PROTO_MATCHING = NO
+
+# The GENERATE_TODOLIST tag can be used to enable (YES) or
+# disable (NO) the todo list. This list is created by putting \todo
+# commands in the documentation.
+
+GENERATE_TODOLIST = YES
+
+# The GENERATE_TESTLIST tag can be used to enable (YES) or
+# disable (NO) the test list. This list is created by putting \test
+# commands in the documentation.
+
+GENERATE_TESTLIST = YES
+
+# The GENERATE_BUGLIST tag can be used to enable (YES) or
+# disable (NO) the bug list. This list is created by putting \bug
+# commands in the documentation.
+
+GENERATE_BUGLIST = YES
+
+# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or
+# disable (NO) the deprecated list. This list is created by putting
+# \deprecated commands in the documentation.
+
+GENERATE_DEPRECATEDLIST= YES
+
+# The ENABLED_SECTIONS tag can be used to enable conditional
+# documentation sections, marked by \if sectionname ... \endif.
+
+ENABLED_SECTIONS =
+
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines
+# the initial value of a variable or macro consists of for it to appear in
+# the documentation. If the initializer consists of more lines than specified
+# here it will be hidden. Use a value of 0 to hide initializers completely.
+# The appearance of the initializer of individual variables and macros in the
+# documentation can be controlled using \showinitializer or \hideinitializer
+# command in the documentation regardless of this setting.
+
+MAX_INITIALIZER_LINES = 30
+
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated
+# at the bottom of the documentation of classes and structs. If set to YES the
+# list will mention the files that were used to generate the documentation.
+
+SHOW_USED_FILES = YES
+
+# Set the SHOW_FILES tag to NO to disable the generation of the Files page.
+# This will remove the Files entry from the Quick Index and from the
+# Folder Tree View (if specified). The default is YES.
+
+SHOW_FILES = YES
+
+# Set the SHOW_NAMESPACES tag to NO to disable the generation of the
+# Namespaces page.
+# This will remove the Namespaces entry from the Quick Index
+# and from the Folder Tree View (if specified). The default is YES.
+
+SHOW_NAMESPACES = YES
+
+# The FILE_VERSION_FILTER tag can be used to specify a program or script that
+# doxygen should invoke to get the current version for each file (typically from
+# the version control system). Doxygen will invoke the program by executing (via
+# popen()) the command <command> <input-file>, where <command> is the value of
+# the FILE_VERSION_FILTER tag, and <input-file> is the name of an input file
+# provided by doxygen. Whatever the program writes to standard output
+# is used as the file version. See the manual for examples.
+
+FILE_VERSION_FILTER =
+
+# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed
+# by doxygen. The layout file controls the global structure of the generated
+# output files in an output format independent way. To create the layout file
+# that represents doxygen's defaults, run doxygen with the -l option.
+# You can optionally specify a file name after the option, if omitted
+# DoxygenLayout.xml will be used as the name of the layout file.
+
+LAYOUT_FILE =
+
+# The CITE_BIB_FILES tag can be used to specify one or more bib files
+# containing the references data. This must be a list of .bib files. The
+# .bib extension is automatically appended if omitted. Using this command
+# requires the bibtex tool to be installed. See also
+# http://en.wikipedia.org/wiki/BibTeX for more info. For LaTeX the style
+# of the bibliography can be controlled using LATEX_BIB_STYLE. To use this
+# feature you need bibtex and perl available in the search path.
+
+CITE_BIB_FILES =
+
+#---------------------------------------------------------------------------
+# configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+# The QUIET tag can be used to turn on/off the messages that are generated
+# by doxygen. Possible values are YES and NO. If left blank NO is used.
+
+QUIET = NO
+
+# The WARNINGS tag can be used to turn on/off the warning messages that are
+# generated by doxygen. Possible values are YES and NO. If left blank
+# NO is used.
+
+WARNINGS = YES
+
+# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings
+# for undocumented members. If EXTRACT_ALL is set to YES then this flag will
+# automatically be disabled.
+
+WARN_IF_UNDOCUMENTED = YES
+
+# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for
+# potential errors in the documentation, such as not documenting some
+# parameters in a documented function, or documenting parameters that
+# don't exist or using markup commands wrongly.
+
+WARN_IF_DOC_ERROR = YES
+
+# The WARN_NO_PARAMDOC option can be enabled to get warnings for
+# functions that are documented, but have no documentation for their parameters
+# or return value. If set to NO (the default) doxygen will only warn about
+# wrong or incomplete parameter documentation, but not about the absence of
+# documentation.
+
+WARN_NO_PARAMDOC = NO
+
+# The WARN_FORMAT tag determines the format of the warning messages that
+# doxygen can produce. The string should contain the $file, $line, and $text
+# tags, which will be replaced by the file and line number from which the
+# warning originated and the warning text. Optionally the format may contain
+# $version, which will be replaced by the version of the file (if it could
+# be obtained via FILE_VERSION_FILTER)
+
+WARN_FORMAT = "$file:$line: $text"
+
+# The WARN_LOGFILE tag can be used to specify a file to which warning
+# and error messages should be written. If left blank the output is written
+# to stderr.
+
+WARN_LOGFILE =
+
+#---------------------------------------------------------------------------
+# configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag can be used to specify the files and/or directories that contain
+# documented source files. You may enter file names like "myfile.cpp" or
+# directories like "/usr/src/myproject". Separate the files or directories
+# with spaces.
+
+INPUT = @CMAKE_SOURCE_DIR@/libdigidoc
+
+# This tag can be used to specify the character encoding of the source files
+# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is
+# also the default input encoding. Doxygen uses libiconv (or the iconv built
+# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for
+# the list of possible encodings.
+
+INPUT_ENCODING = UTF-8
+
+# If the value of the INPUT tag contains directories, you can use the
+# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
+# and *.h) to filter out the source-files in the directories. If left
+# blank the following patterns are tested:
+# *.c *.cc *.cxx *.cpp *.c++ *.d *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh
+# *.hxx *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.dox *.py
+# *.f90 *.f *.for *.vhd *.vhdl
+
+FILE_PATTERNS = *.c \
+ *.cpp \
+ *.h
+
+# The RECURSIVE tag can be used to turn specify whether or not subdirectories
+# should be searched for input files as well. Possible values are YES and NO.
+# If left blank NO is used.
+
+RECURSIVE = YES
+
+# The EXCLUDE tag can be used to specify files and/or directories that should be
+# excluded from the INPUT source files. This way you can easily exclude a
+# subdirectory from a directory tree whose root is specified with the INPUT tag.
+# Note that relative paths are relative to the directory from which doxygen is
+# run.
+
+EXCLUDE =
+
+# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or
+# directories that are symbolic links (a Unix file system feature) are excluded
+# from the input.
+
+EXCLUDE_SYMLINKS = NO
+
+# If the value of the INPUT tag contains directories, you can use the
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
+# certain files from those directories. Note that the wildcards are matched
+# against the file with absolute path, so to exclude all test directories
+# for example use the pattern */test/*
+
+EXCLUDE_PATTERNS =
+
+# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
+# (namespaces, classes, functions, etc.) that should be excluded from the
+# output. The symbol name can be a fully qualified name, a word, or if the
+# wildcard * is used, a substring. Examples: ANamespace, AClass,
+# AClass::ANamespace, ANamespace::*Test
+
+EXCLUDE_SYMBOLS =
+
+# The EXAMPLE_PATH tag can be used to specify one or more files or
+# directories that contain example code fragments that are included (see
+# the \include command).
+
+EXAMPLE_PATH =
+
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
+# and *.h) to filter out the source-files in the directories. If left
+# blank all files are included.
+
+EXAMPLE_PATTERNS =
+
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
+# searched for input files to be used with the \include or \dontinclude
+# commands irrespective of the value of the RECURSIVE tag.
+# Possible values are YES and NO. If left blank NO is used.
+
+EXAMPLE_RECURSIVE = NO
+
+# The IMAGE_PATH tag can be used to specify one or more files or
+# directories that contain image that are included in the documentation (see
+# the \image command).
+
+IMAGE_PATH =
+
+# The INPUT_FILTER tag can be used to specify a program that doxygen should
+# invoke to filter for each input file. Doxygen will invoke the filter program
+# by executing (via popen()) the command <filter> <input-file>, where <filter>
+# is the value of the INPUT_FILTER tag, and <input-file> is the name of an
+# input file. Doxygen will then use the output that the filter program writes
+# to standard output.
+# If FILTER_PATTERNS is specified, this tag will be
+# ignored.
+
+INPUT_FILTER =
+
+# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
+# basis.
+# Doxygen will compare the file name with each pattern and apply the
+# filter if there is a match.
+# The filters are a list of the form:
+# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further
+# info on how filters are used. If FILTER_PATTERNS is empty or if
+# non of the patterns match the file name, INPUT_FILTER is applied.
+
+FILTER_PATTERNS =
+
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
+# INPUT_FILTER) will be used to filter the input files when producing source
+# files to browse (i.e. when SOURCE_BROWSER is set to YES).
+
+FILTER_SOURCE_FILES = NO
+
+# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file
+# pattern. A pattern will override the setting for FILTER_PATTERN (if any)
+# and it is also possible to disable source filtering for a specific pattern
+# using *.ext= (so without naming a filter). This option only has effect when
+# FILTER_SOURCE_FILES is enabled.
+
+FILTER_SOURCE_PATTERNS =
+
+#---------------------------------------------------------------------------
+# configuration options related to source browsing
+#---------------------------------------------------------------------------
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will
+# be generated. Documented entities will be cross-referenced with these sources.
+# Note: To get rid of all source code in the generated output, make sure also
+# VERBATIM_HEADERS is set to NO.
+
+SOURCE_BROWSER = NO
+
+# Setting the INLINE_SOURCES tag to YES will include the body
+# of functions and classes directly in the documentation.
+
+INLINE_SOURCES = NO
+
+# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct
+# doxygen to hide any special comment blocks from generated source code
+# fragments. Normal C, C++ and Fortran comments will always remain visible.
+
+STRIP_CODE_COMMENTS = YES
+
+# If the REFERENCED_BY_RELATION tag is set to YES
+# then for each documented function all documented
+# functions referencing it will be listed.
+
+REFERENCED_BY_RELATION = NO
+
+# If the REFERENCES_RELATION tag is set to YES
+# then for each documented function all documented entities
+# called/used by that function will be listed.
+
+REFERENCES_RELATION = NO
+
+# If the REFERENCES_LINK_SOURCE tag is set to YES (the default)
+# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from
+# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will
+# link to the source code.
+# Otherwise they will link to the documentation.
+
+REFERENCES_LINK_SOURCE = YES
+
+# If the USE_HTAGS tag is set to YES then the references to source code
+# will point to the HTML generated by the htags(1) tool instead of doxygen
+# built-in source browser. The htags tool is part of GNU's global source
+# tagging system (see http://www.gnu.org/software/global/global.html). You
+# will need version 4.8.6 or higher.
+
+USE_HTAGS = NO
+
+# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen
+# will generate a verbatim copy of the header file for each class for
+# which an include is specified. Set to NO to disable this.
+
+VERBATIM_HEADERS = YES
+
+#---------------------------------------------------------------------------
+# configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index
+# of all compounds will be generated. Enable this if the project
+# contains a lot of classes, structs, unions or interfaces.
+
+ALPHABETICAL_INDEX = YES
+
+# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then
+# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns
+# in which this list will be split (can be a number in the range [1..20])
+
+COLS_IN_ALPHA_INDEX = 5
+
+# In case all classes in a project start with a common prefix, all
+# classes will be put under the same header in the alphabetical index.
+# The IGNORE_PREFIX tag can be used to specify one or more prefixes that
+# should be ignored while generating the index headers.
+
+IGNORE_PREFIX =
+
+#---------------------------------------------------------------------------
+# configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES (the default) Doxygen will
+# generate HTML output.
+
+GENERATE_HTML = YES
+
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `html' will be used as the default path.
+
+HTML_OUTPUT = html
+
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for
+# each generated HTML page (for example: .htm,.php,.asp). If it is left blank
+# doxygen will generate files with .html extension.
+
+HTML_FILE_EXTENSION = .html
+
+# The HTML_HEADER tag can be used to specify a personal HTML header for
+# each generated HTML page. If it is left blank doxygen will generate a
+# standard header. Note that when using a custom header you are responsible
+# for the proper inclusion of any scripts and style sheets that doxygen
+# needs, which is dependent on the configuration options used.
+# It is advised to generate a default header using "doxygen -w html
+# header.html footer.html stylesheet.css YourConfigFile" and then modify
+# that header. Note that the header is subject to change so you typically
+# have to redo this when upgrading to a newer version of doxygen or when
+# changing the value of configuration settings such as GENERATE_TREEVIEW!
+
+HTML_HEADER =
+
+# The HTML_FOOTER tag can be used to specify a personal HTML footer for
+# each generated HTML page. If it is left blank doxygen will generate a
+# standard footer.
+
+HTML_FOOTER =
+
+# The HTML_STYLESHEET tag can be used to specify a user-defined cascading
+# style sheet that is used by each HTML page. It can be used to
+# fine-tune the look of the HTML output. If the tag is left blank doxygen
+# will generate a default style sheet. Note that doxygen will try to copy
+# the style sheet file to the HTML output directory, so don't put your own
+# style sheet in the HTML output directory as well, or it will be erased!
+
+HTML_STYLESHEET =
+
+# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or
+# other source files which should be copied to the HTML output directory. Note
+# that these files will be copied to the base HTML output directory. Use the
+# $relpath$ marker in the HTML_HEADER and/or HTML_FOOTER files to load these
+# files. In the HTML_STYLESHEET file, use the file name only. Also note that
+# the files will be copied as-is; there are no commands or markers available.
+
+HTML_EXTRA_FILES =
+
+# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output.
+# Doxygen will adjust the colors in the style sheet and background images
+# according to this color. Hue is specified as an angle on a colorwheel,
+# see http://en.wikipedia.org/wiki/Hue for more information.
+# For instance the value 0 represents red, 60 is yellow, 120 is green,
+# 180 is cyan, 240 is blue, 300 purple, and 360 is red again.
+# The allowed range is 0 to 359.
+
+HTML_COLORSTYLE_HUE = 220
+
+# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of
+# the colors in the HTML output. For a value of 0 the output will use
+# grayscales only. A value of 255 will produce the most vivid colors.
+
+HTML_COLORSTYLE_SAT = 100
+
+# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to
+# the luminance component of the colors in the HTML output. Values below
+# 100 gradually make the output lighter, whereas values above 100 make
+# the output darker. The value divided by 100 is the actual gamma applied,
+# so 80 represents a gamma of 0.8, The value 220 represents a gamma of 2.2,
+# and 100 does not change the gamma.
+
+HTML_COLORSTYLE_GAMMA = 80
+
+# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML
+# page will contain the date and time when the page was generated. Setting
+# this to NO can help when comparing the output of multiple runs.
+
+HTML_TIMESTAMP = YES
+
+# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
+# documentation will contain sections that can be hidden and shown after the
+# page has loaded.
+
+HTML_DYNAMIC_SECTIONS = NO
+
+# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of
+# entries shown in the various tree structured indices initially; the user
+# can expand and collapse entries dynamically later on. Doxygen will expand
+# the tree to such a level that at most the specified number of entries are
+# visible (unless a fully collapsed tree already exceeds this amount).
+# So setting the number of entries 1 will produce a full collapsed tree by
+# default. 0 is a special value representing an infinite number of entries
+# and will result in a full expanded tree by default.
+
+HTML_INDEX_NUM_ENTRIES = 100
+
+# If the GENERATE_DOCSET tag is set to YES, additional index files
+# will be generated that can be used as input for Apple's Xcode 3
+# integrated development environment, introduced with OSX 10.5 (Leopard).
+# To create a documentation set, doxygen will generate a Makefile in the
+# HTML output directory. Running make will produce the docset in that
+# directory and running "make install" will install the docset in
+# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find
+# it at startup.
+# See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html
+# for more information.
+
+GENERATE_DOCSET = NO
+
+# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the
+# feed. A documentation feed provides an umbrella under which multiple
+# documentation sets from a single provider (such as a company or product suite)
+# can be grouped.
+
+DOCSET_FEEDNAME = "Doxygen generated docs"
+
+# When GENERATE_DOCSET tag is set to YES, this tag specifies a string that
+# should uniquely identify the documentation set bundle. This should be a
+# reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen
+# will append .docset to the name.
+
+DOCSET_BUNDLE_ID = org.doxygen.Project
+
+# When GENERATE_PUBLISHER_ID tag specifies a string that should uniquely identify
+# the documentation publisher. This should be a reverse domain-name style
+# string, e.g. com.mycompany.MyDocSet.documentation.
+
+DOCSET_PUBLISHER_ID = org.doxygen.Publisher
+
+# The GENERATE_PUBLISHER_NAME tag identifies the documentation publisher.
+
+DOCSET_PUBLISHER_NAME = Publisher
+
+# If the GENERATE_HTMLHELP tag is set to YES, additional index files
+# will be generated that can be used as input for tools like the
+# Microsoft HTML help workshop to generate a compiled HTML help file (.chm)
+# of the generated HTML documentation.
+
+GENERATE_HTMLHELP = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can
+# be used to specify the file name of the resulting .chm file. You
+# can add a path in front of the file if the result should not be
+# written to the html output directory.
+
+CHM_FILE =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can
+# be used to specify the location (absolute path including file name) of
+# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run
+# the HTML help compiler on the generated index.hhp.
+
+HHC_LOCATION =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag
+# controls if a separate .chi index file is generated (YES) or that
+# it should be included in the master .chm file (NO).
+
+GENERATE_CHI = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING
+# is used to encode HtmlHelp index (hhk), content (hhc) and project file
+# content.
+
+CHM_INDEX_ENCODING =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag
+# controls whether a binary table of contents is generated (YES) or a
+# normal table of contents (NO) in the .chm file.
+
+BINARY_TOC = NO
+
+# The TOC_EXPAND flag can be set to YES to add extra items for group members
+# to the contents of the HTML help documentation and to the tree view.
+
+TOC_EXPAND = NO
+
+# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and
+# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated
+# that can be used as input for Qt's qhelpgenerator to generate a
+# Qt Compressed Help (.qch) of the generated HTML documentation.
+
+GENERATE_QHP = NO
+
+# If the QHG_LOCATION tag is specified, the QCH_FILE tag can
+# be used to specify the file name of the resulting .qch file.
+# The path specified is relative to the HTML output folder.
+
+QCH_FILE =
+
+# The QHP_NAMESPACE tag specifies the namespace to use when generating
+# Qt Help Project output. For more information please see
+# http://doc.trolltech.com/qthelpproject.html#namespace
+
+QHP_NAMESPACE = org.doxygen.Project
+
+# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating
+# Qt Help Project output. For more information please see
+# http://doc.trolltech.com/qthelpproject.html#virtual-folders
+
+QHP_VIRTUAL_FOLDER = doc
+
+# If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to
+# add. For more information please see
+# http://doc.trolltech.com/qthelpproject.html#custom-filters
+
+QHP_CUST_FILTER_NAME =
+
+# The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the
+# custom filter to add. For more information please see
+# <a href="http://doc.trolltech.com/qthelpproject.html#custom-filters">
+# Qt Help Project / Custom Filters</a>.
+
+QHP_CUST_FILTER_ATTRS =
+
+# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this
+# project's
+# filter section matches.
+# <a href="http://doc.trolltech.com/qthelpproject.html#filter-attributes">
+# Qt Help Project / Filter Attributes</a>.
+
+QHP_SECT_FILTER_ATTRS =
+
+# If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can
+# be used to specify the location of Qt's qhelpgenerator.
+# If non-empty doxygen will try to run qhelpgenerator on the generated
+# .qhp file.
+
+QHG_LOCATION =
+
+# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files
+# will be generated, which together with the HTML files, form an Eclipse help
+# plugin. To install this plugin and make it available under the help contents
+# menu in Eclipse, the contents of the directory containing the HTML and XML
+# files needs to be copied into the plugins directory of eclipse. The name of
+# the directory within the plugins directory should be the same as
+# the ECLIPSE_DOC_ID value. After copying Eclipse needs to be restarted before
+# the help appears.
+
+GENERATE_ECLIPSEHELP = NO
+
+# A unique identifier for the eclipse help plugin. When installing the plugin
+# the directory name containing the HTML and XML files should also have
+# this name.
+
+ECLIPSE_DOC_ID = org.doxygen.Project
+
+# The DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs)
+# at top of each HTML page. The value NO (the default) enables the index and
+# the value YES disables it. Since the tabs have the same information as the
+# navigation tree you can set this option to NO if you already set
+# GENERATE_TREEVIEW to YES.
+
+DISABLE_INDEX = NO
+
+# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index
+# structure should be generated to display hierarchical information.
+# If the tag value is set to YES, a side panel will be generated
+# containing a tree-like index structure (just like the one that
+# is generated for HTML Help). For this to work a browser that supports
+# JavaScript, DHTML, CSS and frames is required (i.e. any modern browser).
+# Windows users are probably better off using the HTML help feature.
+# Since the tree basically has the same information as the tab index you
+# could consider to set DISABLE_INDEX to NO when enabling this option.
+
+GENERATE_TREEVIEW = NO
+
+# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values
+# (range [0,1..20]) that doxygen will group on one line in the generated HTML
+# documentation. Note that a value of 0 will completely suppress the enum
+# values from appearing in the overview section.
+
+ENUM_VALUES_PER_LINE = 4
+
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be
+# used to set the initial width (in pixels) of the frame in which the tree
+# is shown.
+
+TREEVIEW_WIDTH = 250
+
+# When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open
+# links to external symbols imported via tag files in a separate window.
+
+EXT_LINKS_IN_WINDOW = NO
+
+# Use this tag to change the font size of Latex formulas included
+# as images in the HTML documentation. The default is 10. Note that
+# when you change the font size after a successful doxygen run you need
+# to manually remove any form_*.png images from the HTML output directory
+# to force them to be regenerated.
+
+FORMULA_FONTSIZE = 10
+
+# Use the FORMULA_TRANPARENT tag to determine whether or not the images
+# generated for formulas are transparent PNGs. Transparent PNGs are
+# not supported properly for IE 6.0, but are supported on all modern browsers.
+# Note that when changing this option you need to delete any form_*.png files
+# in the HTML output before the changes have effect.
+
+FORMULA_TRANSPARENT = YES
+
+# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax
+# (see http://www.mathjax.org) which uses client side Javascript for the
+# rendering instead of using prerendered bitmaps. Use this if you do not
+# have LaTeX installed or if you want to formulas look prettier in the HTML
+# output. When enabled you may also need to install MathJax separately and
+# configure the path to it using the MATHJAX_RELPATH option.
+
+USE_MATHJAX = NO
+
+# When MathJax is enabled you need to specify the location relative to the
+# HTML output directory using the MATHJAX_RELPATH option. The destination
+# directory should contain the MathJax.js script. For instance, if the mathjax
+# directory is located at the same level as the HTML output directory, then
+# MATHJAX_RELPATH should be ../mathjax. The default value points to
+# the MathJax Content Delivery Network so you can quickly see the result without
+# installing MathJax.
+# However, it is strongly recommended to install a local
+# copy of MathJax from http://www.mathjax.org before deployment.
+
+MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest
+
+# The MATHJAX_EXTENSIONS tag can be used to specify one or MathJax extension
+# names that should be enabled during MathJax rendering.
+
+MATHJAX_EXTENSIONS =
+
+# When the SEARCHENGINE tag is enabled doxygen will generate a search box
+# for the HTML output. The underlying search engine uses javascript
+# and DHTML and should work on any modern browser. Note that when using
+# HTML help (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets
+# (GENERATE_DOCSET) there is already a search function so this one should
+# typically be disabled. For large projects the javascript based search engine
+# can be slow, then enabling SERVER_BASED_SEARCH may provide a better solution.
+
+SEARCHENGINE = YES
+
+# When the SERVER_BASED_SEARCH tag is enabled the search engine will be
+# implemented using a PHP enabled web server instead of at the web client
+# using Javascript. Doxygen will generate the search PHP script and index
+# file to put on the web server. The advantage of the server
+# based approach is that it scales better to large projects and allows
+# full text search. The disadvantages are that it is more difficult to setup
+# and does not have live searching capabilities.
+
+SERVER_BASED_SEARCH = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will
+# generate Latex output.
+
+GENERATE_LATEX = NO
+
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `latex' will be used as the default path.
+
+LATEX_OUTPUT = latex
+
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
+# invoked. If left blank `latex' will be used as the default command name.
+# Note that when enabling USE_PDFLATEX this option is only used for
+# generating bitmaps for formulas in the HTML output, but not in the
+# Makefile that is written to the output directory.
+
+LATEX_CMD_NAME = latex
+
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to
+# generate index for LaTeX. If left blank `makeindex' will be used as the
+# default command name.
+
+MAKEINDEX_CMD_NAME = makeindex
+
+# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact
+# LaTeX documents. This may be useful for small projects and may help to
+# save some trees in general.
+
+COMPACT_LATEX = NO
+
+# The PAPER_TYPE tag can be used to set the paper type that is used
+# by the printer. Possible values are: a4, letter, legal and
+# executive. If left blank a4wide will be used.
+
+PAPER_TYPE = a4wide
+
+# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX
+# packages that should be included in the LaTeX output.
+
+EXTRA_PACKAGES =
+
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for
+# the generated latex document. The header should contain everything until
+# the first chapter. If it is left blank doxygen will generate a
+# standard header. Notice: only use this tag if you know what you are doing!
+
+LATEX_HEADER =
+
+# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for
+# the generated latex document. The footer should contain everything after
+# the last chapter. If it is left blank doxygen will generate a
+# standard footer. Notice: only use this tag if you know what you are doing!
+
+LATEX_FOOTER =
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated
+# is prepared for conversion to pdf (using ps2pdf). The pdf file will
+# contain links (just like the HTML output) instead of page references
+# This makes the output suitable for online browsing using a pdf viewer.
+
+PDF_HYPERLINKS = YES
+
+# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of
+# plain latex in the generated Makefile. Set this option to YES to get a
+# higher quality PDF documentation.
+
+USE_PDFLATEX = YES
+
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode.
+# command to the generated LaTeX files. This will instruct LaTeX to keep
+# running if errors occur, instead of asking the user for help.
+# This option is also used when generating formulas in HTML.
+
+LATEX_BATCHMODE = NO
+
+# If LATEX_HIDE_INDICES is set to YES then doxygen will not
+# include the index chapters (such as File Index, Compound Index, etc.)
+# in the output.
+
+LATEX_HIDE_INDICES = NO
+
+# If LATEX_SOURCE_CODE is set to YES then doxygen will include
+# source code with syntax highlighting in the LaTeX output.
+# Note that which sources are shown also depends on other settings
+# such as SOURCE_BROWSER.
+
+LATEX_SOURCE_CODE = NO
+
+# The LATEX_BIB_STYLE tag can be used to specify the style to use for the
+# bibliography, e.g. plainnat, or ieeetr. The default style is "plain". See
+# http://en.wikipedia.org/wiki/BibTeX for more info.
+
+LATEX_BIB_STYLE = plain
+
+#---------------------------------------------------------------------------
+# configuration options related to the RTF output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output
+# The RTF output is optimized for Word 97 and may not look very pretty with
+# other RTF readers or editors.
+
+GENERATE_RTF = NO
+
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `rtf' will be used as the default path.
+
+RTF_OUTPUT = rtf
+
+# If the COMPACT_RTF tag is set to YES Doxygen generates more compact
+# RTF documents. This may be useful for small projects and may help to
+# save some trees in general.
+
+COMPACT_RTF = NO
+
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated
+# will contain hyperlink fields. The RTF file will
+# contain links (just like the HTML output) instead of page references.
+# This makes the output suitable for online browsing using WORD or other
+# programs which support those fields.
+# Note: wordpad (write) and others do not support links.
+
+RTF_HYPERLINKS = NO
+
+# Load style sheet definitions from file. Syntax is similar to doxygen's
+# config file, i.e. a series of assignments. You only have to provide
+# replacements, missing definitions are set to their default value.
+
+RTF_STYLESHEET_FILE =
+
+# Set optional variables used in the generation of an rtf document.
+# Syntax is similar to doxygen's config file.
+
+RTF_EXTENSIONS_FILE =
+
+#---------------------------------------------------------------------------
+# configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES (the default) Doxygen will
+# generate man pages
+
+GENERATE_MAN = NO
+
+# The MAN_OUTPUT tag is used to specify where the man pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `man' will be used as the default path.
+
+MAN_OUTPUT = man
+
+# The MAN_EXTENSION tag determines the extension that is added to
+# the generated man pages (default is the subroutine's section .3)
+
+MAN_EXTENSION = .3
+
+# If the MAN_LINKS tag is set to YES and Doxygen generates man output,
+# then it will generate one additional man file for each entity
+# documented in the real man page(s). These additional files
+# only source the real man page, but without them the man command
+# would be unable to find the correct page. The default is NO.
+
+MAN_LINKS = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_XML tag is set to YES Doxygen will
+# generate an XML file that captures the structure of
+# the code including all documentation.
+
+GENERATE_XML = NO
+
+# The XML_OUTPUT tag is used to specify where the XML pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `xml' will be used as the default path.
+
+XML_OUTPUT = xml
+
+# The XML_SCHEMA tag can be used to specify an XML schema,
+# which can be used by a validating XML parser to check the
+# syntax of the XML files.
+
+XML_SCHEMA =
+
+# The XML_DTD tag can be used to specify an XML DTD,
+# which can be used by a validating XML parser to check the
+# syntax of the XML files.
+
+XML_DTD =
+
+# If the XML_PROGRAMLISTING tag is set to YES Doxygen will
+# dump the program listings (including syntax highlighting
+# and cross-referencing information) to the XML output. Note that
+# enabling this will significantly increase the size of the XML output.
+
+XML_PROGRAMLISTING = YES
+
+#---------------------------------------------------------------------------
+# configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will
+# generate an AutoGen Definitions (see autogen.sf.net) file
+# that captures the structure of the code including all
+# documentation. Note that this feature is still experimental
+# and incomplete at the moment.
+
+GENERATE_AUTOGEN_DEF = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_PERLMOD tag is set to YES Doxygen will
+# generate a Perl module file that captures the structure of
+# the code including all documentation. Note that this
+# feature is still experimental and incomplete at the
+# moment.
+
+GENERATE_PERLMOD = NO
+
+# If the PERLMOD_LATEX tag is set to YES Doxygen will generate
+# the necessary Makefile rules, Perl scripts and LaTeX code to be able
+# to generate PDF and DVI output from the Perl module output.
+
+PERLMOD_LATEX = NO
+
+# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be
+# nicely formatted so it can be parsed by a human reader.
+# This is useful
+# if you want to understand what is going on.
+# On the other hand, if this
+# tag is set to NO the size of the Perl module output will be much smaller
+# and Perl will parse it just the same.
+
+PERLMOD_PRETTY = YES
+
+# The names of the make variables in the generated doxyrules.make file
+# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX.
+# This is useful so different doxyrules.make files included by the same
+# Makefile don't overwrite each other's variables.
+
+PERLMOD_MAKEVAR_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+
+# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will
+# evaluate all C-preprocessor directives found in the sources and include
+# files.
+
+ENABLE_PREPROCESSING = YES
+
+# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro
+# names in the source code. If set to NO (the default) only conditional
+# compilation will be performed. Macro expansion can be done in a controlled
+# way by setting EXPAND_ONLY_PREDEF to YES.
+
+MACRO_EXPANSION = NO
+
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES
+# then the macro expansion is limited to the macros specified with the
+# PREDEFINED and EXPAND_AS_DEFINED tags.
+
+EXPAND_ONLY_PREDEF = NO
+
+# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files
+# pointed to by INCLUDE_PATH will be searched when a #include is found.
+
+SEARCH_INCLUDES = YES
+
+# The INCLUDE_PATH tag can be used to specify one or more directories that
+# contain include files that are not input files but should be processed by
+# the preprocessor.
+
+INCLUDE_PATH =
+
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
+# patterns (like *.h and *.hpp) to filter out the header-files in the
+# directories. If left blank, the patterns specified with FILE_PATTERNS will
+# be used.
+
+INCLUDE_FILE_PATTERNS =
+
+# The PREDEFINED tag can be used to specify one or more macro names that
+# are defined before the preprocessor is started (similar to the -D option of
+# gcc). The argument of the tag is a list of macros of the form: name
+# or name=definition (no spaces). If the definition and the = are
+# omitted =1 is assumed. To prevent a macro definition from being
+# undefined via #undef or recursively expanded use the := operator
+# instead of the = operator.
+
+PREDEFINED =
+
+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then
+# this tag can be used to specify a list of macro names that should be expanded.
+# The macro definition that is found in the sources will be used.
+# Use the PREDEFINED tag if you want to use a different macro definition that
+# overrules the definition found in the source code.
+
+EXPAND_AS_DEFINED =
+
+# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then
+# doxygen's preprocessor will remove all references to function-like macros
+# that are alone on a line, have an all uppercase name, and do not end with a
+# semicolon, because these will confuse the parser if not removed.
+
+SKIP_FUNCTION_MACROS = YES
+
+#---------------------------------------------------------------------------
+# Configuration::additions related to external references
+#---------------------------------------------------------------------------
+
+# The TAGFILES option can be used to specify one or more tagfiles. For each
+# tag file the location of the external documentation should be added. The
+# format of a tag file without this location is as follows:
+#
+# TAGFILES = file1 file2 ...
+# Adding location for the tag files is done as follows:
+#
+# TAGFILES = file1=loc1 "file2 = loc2" ...
+# where "loc1" and "loc2" can be relative or absolute paths
+# or URLs. Note that each tag file must have a unique name (where the name does
+# NOT include the path). If a tag file is not located in the directory in which
+# doxygen is run, you must also specify the path to the tagfile here.
+
+TAGFILES =
+
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create
+# a tag file that is based on the input files it reads.
+
+GENERATE_TAGFILE =
+
+# If the ALLEXTERNALS tag is set to YES all external classes will be listed
+# in the class index. If set to NO only the inherited external classes
+# will be listed.
+
+ALLEXTERNALS = NO
+
+# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed
+# in the modules index. If set to NO, only the current project's groups will
+# be listed.
+
+EXTERNAL_GROUPS = YES
+
+# The PERL_PATH should be the absolute path and name of the perl script
+# interpreter (i.e. the result of `which perl').
+
+PERL_PATH = /usr/bin/perl
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+
+# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will
+# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base
+# or super classes. Setting the tag to NO turns the diagrams off. Note that
+# this option also works with HAVE_DOT disabled, but it is recommended to
+# install and use dot, since it yields more powerful graphs.
+
+CLASS_DIAGRAMS = YES
+
+# You can define message sequence charts within doxygen comments using the \msc
+# command. Doxygen will then run the mscgen tool (see
+# http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the
+# documentation. The MSCGEN_PATH tag allows you to specify the directory where
+# the mscgen tool resides. If left empty the tool is assumed to be found in the
+# default search path.
+
+MSCGEN_PATH =
+
+# If set to YES, the inheritance and collaboration graphs will hide
+# inheritance and usage relations if the target is undocumented
+# or is not a class.
+
+HIDE_UNDOC_RELATIONS = YES
+
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
+# available from the path. This tool is part of Graphviz, a graph visualization
+# toolkit from AT&T and Lucent Bell Labs. The other options in this section
+# have no effect if this option is set to NO (the default)
+
+HAVE_DOT = NO
+
+# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is
+# allowed to run in parallel. When set to 0 (the default) doxygen will
+# base this on the number of processors available in the system. You can set it
+# explicitly to a value larger than 0 to get control over the balance
+# between CPU load and processing speed.
+
+DOT_NUM_THREADS = 0
+
+# By default doxygen will use the Helvetica font for all dot files that
+# doxygen generates. When you want a differently looking font you can specify
+# the font name using DOT_FONTNAME. You need to make sure dot is able to find
+# the font, which can be done by putting it in a standard location or by setting
+# the DOTFONTPATH environment variable or by setting DOT_FONTPATH to the
+# directory containing the font.
+
+DOT_FONTNAME = Helvetica
+
+# The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs.
+# The default size is 10pt.
+
+DOT_FONTSIZE = 10
+
+# By default doxygen will tell dot to use the Helvetica font.
+# If you specify a different font using DOT_FONTNAME you can use DOT_FONTPATH to
+# set the path where dot can find it.
+
+DOT_FONTPATH =
+
+# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for each documented class showing the direct and
+# indirect inheritance relations. Setting this tag to YES will force the
+# CLASS_DIAGRAMS tag to NO.
+
+CLASS_GRAPH = YES
+
+# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for each documented class showing the direct and
+# indirect implementation dependencies (inheritance, containment, and
+# class references variables) of the class with other documented classes.
+
+COLLABORATION_GRAPH = YES
+
+# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for groups, showing the direct groups dependencies
+
+GROUP_GRAPHS = YES
+
+# If the UML_LOOK tag is set to YES doxygen will generate inheritance and
+# collaboration diagrams in a style similar to the OMG's Unified Modeling
+# Language.
+
+UML_LOOK = YES
+
+# If the UML_LOOK tag is enabled, the fields and methods are shown inside
+# the class node. If there are many fields or methods and many nodes the
+# graph may become too big to be useful. The UML_LIMIT_NUM_FIELDS
+# threshold limits the number of items for each type to make the size more
+# managable. Set this to 0 for no limit. Note that the threshold may be
+# exceeded by 50% before the limit is enforced.
+
+UML_LIMIT_NUM_FIELDS = 10
+
+# If set to YES, the inheritance and collaboration graphs will show the
+# relations between templates and their instances.
+
+TEMPLATE_RELATIONS = NO
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT
+# tags are set to YES then doxygen will generate a graph for each documented
+# file showing the direct and indirect include dependencies of the file with
+# other documented files.
+
+INCLUDE_GRAPH = YES
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and
+# HAVE_DOT tags are set to YES then doxygen will generate a graph for each
+# documented header file showing the documented files that directly or
+# indirectly include this file.
+
+INCLUDED_BY_GRAPH = YES
+
+# If the CALL_GRAPH and HAVE_DOT options are set to YES then
+# doxygen will generate a call dependency graph for every global function
+# or class method. Note that enabling this option will significantly increase
+# the time of a run. So in most cases it will be better to enable call graphs
+# for selected functions only using the \callgraph command.
+
+CALL_GRAPH = NO
+
+# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then
+# doxygen will generate a caller dependency graph for every global function
+# or class method. Note that enabling this option will significantly increase
+# the time of a run. So in most cases it will be better to enable caller
+# graphs for selected functions only using the \callergraph command.
+
+CALLER_GRAPH = NO
+
+# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen
+# will generate a graphical hierarchy of all classes instead of a textual one.
+
+GRAPHICAL_HIERARCHY = YES
+
+# If the DIRECTORY_GRAPH and HAVE_DOT tags are set to YES
+# then doxygen will show the dependencies a directory has on other directories
+# in a graphical way. The dependency relations are determined by the #include
+# relations between the files in the directories.
+
+DIRECTORY_GRAPH = YES
+
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
+# generated by dot. Possible values are svg, png, jpg, or gif.
+# If left blank png will be used. If you choose svg you need to set
+# HTML_FILE_EXTENSION to xhtml in order to make the SVG files
+# visible in IE 9+ (other browsers do not have this requirement).
+
+DOT_IMAGE_FORMAT = png
+
+# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to
+# enable generation of interactive SVG images that allow zooming and panning.
+# Note that this requires a modern browser other than Internet Explorer.
+# Tested and working are Firefox, Chrome, Safari, and Opera. For IE 9+ you
+# need to set HTML_FILE_EXTENSION to xhtml in order to make the SVG files
+# visible. Older versions of IE do not have SVG support.
+
+INTERACTIVE_SVG = NO
+
+# The tag DOT_PATH can be used to specify the path where the dot tool can be
+# found. If left blank, it is assumed the dot tool can be found in the path.
+
+DOT_PATH =
+
+# The DOTFILE_DIRS tag can be used to specify one or more directories that
+# contain dot files that are included in the documentation (see the
+# \dotfile command).
+
+DOTFILE_DIRS =
+
+# The MSCFILE_DIRS tag can be used to specify one or more directories that
+# contain msc files that are included in the documentation (see the
+# \mscfile command).
+
+MSCFILE_DIRS =
+
+# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of
+# nodes that will be shown in the graph. If the number of nodes in a graph
+# becomes larger than this value, doxygen will truncate the graph, which is
+# visualized by representing a node as a red box. Note that doxygen if the
+# number of direct children of the root node in a graph is already larger than
+# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note
+# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
+
+DOT_GRAPH_MAX_NODES = 50
+
+# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the
+# graphs generated by dot. A depth value of 3 means that only nodes reachable
+# from the root by following a path via at most 3 edges will be shown. Nodes
+# that lay further from the root node will be omitted. Note that setting this
+# option to 1 or 2 may greatly reduce the computation time needed for large
+# code bases. Also note that the size of a graph can be further restricted by
+# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.
+
+MAX_DOT_GRAPH_DEPTH = 0
+
+# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
+# background. This is disabled by default, because dot on Windows does not
+# seem to support this out of the box. Warning: Depending on the platform used,
+# enabling this option may lead to badly anti-aliased labels on the edges of
+# a graph (i.e. they become hard to read).
+
+DOT_TRANSPARENT = NO
+
+# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output
+# files in one run (i.e. multiple -o and -T options on the command line). This
+# makes dot run faster, but since only newer versions of dot (>1.8.10)
+# support this, this feature is disabled by default.
+
+DOT_MULTI_TARGETS = NO
+
+# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will
+# generate a legend page explaining the meaning of the various boxes and
+# arrows in the dot generated graphs.
+
+GENERATE_LEGEND = YES
+
+# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will
+# remove the intermediate dot files that are used to generate
+# the various graphs.
+
+DOT_CLEANUP = YES
diff --git a/etc/certs/EECCRCA.crt b/etc/certs/EECCRCA.crt
new file mode 100644
index 0000000..013d461
--- /dev/null
+++ b/etc/certs/EECCRCA.crt
@@ -0,0 +1,24 @@
+-----BEGIN CERTIFICATE-----
+MIIEAzCCAuugAwIBAgIQVID5oHPtPwBMyonY43HmSjANBgkqhkiG9w0BAQUFADB1
+MQswCQYDVQQGEwJFRTEiMCAGA1UECgwZQVMgU2VydGlmaXRzZWVyaW1pc2tlc2t1
+czEoMCYGA1UEAwwfRUUgQ2VydGlmaWNhdGlvbiBDZW50cmUgUm9vdCBDQTEYMBYG
+CSqGSIb3DQEJARYJcGtpQHNrLmVlMCIYDzIwMTAxMDMwMTAxMDMwWhgPMjAzMDEy
+MTcyMzU5NTlaMHUxCzAJBgNVBAYTAkVFMSIwIAYDVQQKDBlBUyBTZXJ0aWZpdHNl
+ZXJpbWlza2Vza3VzMSgwJgYDVQQDDB9FRSBDZXJ0aWZpY2F0aW9uIENlbnRyZSBS
+b290IENBMRgwFgYJKoZIhvcNAQkBFglwa2lAc2suZWUwggEiMA0GCSqGSIb3DQEB
+AQUAA4IBDwAwggEKAoIBAQDIIMDs4MVLqwd4lfNE7vsLDP90jmG7sWLqI9iroWUy
+euuOF0+W2Ap7kaJjbMeMTC55v6kF/GlclY1i+blw7cNRfdCT5mzrMEvhvH2/UpvO
+bntl8jixwKIy72KyaOBhU8E2lf/slLo2rpwcpzIP5Xy0xm90/XsY6KxX7QYgSzIw
+WFv9zajmofxwvI6Sc9uXp3whrj3B9UiHbCe9nyV0gVWw93X2PaRka9ZP585ArQ/d
+MtO8ihJTmMmJ+xAdTX7Nfh9WDSFwhfYggx/2uh8Ej+p3iDXE/+pOoYtNP2MbRMNE
+1CV2yreN1x5KZmTNXMWcg+HCCIia7E6j8T4cLNlsHaFLAgMBAAGjgYowgYcwDwYD
+VR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFBLyWj7qVhy/
+zQas8fElyalL1BSZMEUGA1UdJQQ+MDwGCCsGAQUFBwMCBggrBgEFBQcDAQYIKwYB
+BQUHAwMGCCsGAQUFBwMEBggrBgEFBQcDCAYIKwYBBQUHAwkwDQYJKoZIhvcNAQEF
+BQADggEBAHv25MANqhlHt01Xo/6tu7Fq1Q+e2+RjxY6hUFaTlrg4wCQiZrxTFGGV
+v9DHKpY5P30osxBAIWrEr7BSdxjhlthWXePdNl4dp1BUoMUq5KqMlIpPnTX/dqQG
+E5Gion0ARD9V04I8GtVbvFZMIi5GQ4okQC3zErg7cBqklrkar4dBGmoYDQZPxz5u
+uSlNDUmJEYcyW+ZLBMjkXOZ0c5RdFpgTlf7727FE5TpwrDdr5rMzcijJs1eg9gIW
+iAYLtqZLICjU3j2LrTcFU3T+bsy8QxdxXvnFzBqpYe73dgzzcvRyrc9yAjYHR8/v
+GVCJYMzpJJUPwssd8m92kMfMdcGWxZ0=
+-----END CERTIFICATE-----
diff --git a/etc/certs/EID-SK 2007 OCSP 2010.crt b/etc/certs/EID-SK 2007 OCSP 2010.crt
new file mode 100644
index 0000000..2c95b83
--- /dev/null
+++ b/etc/certs/EID-SK 2007 OCSP 2010.crt
@@ -0,0 +1,21 @@
+-----BEGIN CERTIFICATE-----
+MIIEMTCCAxmgAwIBAgIESxUA8TANBgkqhkiG9w0BAQUFADBqMQswCQYDVQQGEwJFRTEiMCAGA1UE
+ChMZQVMgU2VydGlmaXRzZWVyaW1pc2tlc2t1czEhMB8GA1UECxMYU2VydGlmaXRzZWVyaW1pc3Rl
+ZW51c2VkMRQwEgYDVQQDEwtFSUQtU0sgMjAwNzAeFw0wOTEyMDExMTQxMzBaFw0xNjA4MjYxMzIz
+MDBaMIGEMQswCQYDVQQGEwJFRTEiMCAGA1UEChMZQVMgU2VydGlmaXRzZWVyaW1pc2tlc2t1czEN
+MAsGA1UECxMET0NTUDEoMCYGA1UEAxMfRUlELVNLIDIwMDcgT0NTUCBSRVNQT05ERVIgMjAxMDEY
+MBYGCSqGSIb3DQEJARYJcGtpQHNrLmVlMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA
+so91KG7EHsjAxMairaCKUHSOyXp5rzxRq5Y9LfDyplVbHfh34fbB7M5G+wnu5CZgJsfJ7DF3MjpA
+7nlAHd5alAynIUl/CNXejf+XnJ/vyF1eQvAoWvnjBPVIS0mbaABgF54ybAGE2E7UKeZVOAj7RoQV
+AMHQcYVjxZW5OWz3yJX9KdaDZPOzqlGtRYKUASHiwAFwExKcqfaHOj0qO8+KdSvEBaVlpe5kunEV
+Evn+kgNKBtzdH2XFMjVFa4im31KW+iq7mNQwUiZDSe9ho6T6UrWu7g8yTQowx3SYLTqVxR0YVgcY
+NCx7nn1AVGNxK3oeonrHHqcBp6qSAIYXeQNfiQIDAQABo4HDMIHAMBMGA1UdJQQMMAoGCCsGAQUF
+BwMJMGkGA1UdIARiMGAwXgYKKwYBBAHOHwQBAjBQMCUGCCsGAQUFBwICMBkaF1NLIHRpbWUgc3Rh
+bXBpbmcgcG9saWN5MCcGCCsGAQUFBwIBFhtodHRwOi8vd3d3LnNrLmVlL2FqYXRlbXBlbC8wHwYD
+VR0jBBgwFoAUHAf0nL+kJWyztJ4iHx+USBtYeo0wHQYDVR0OBBYEFPBOCDPMR+kfp7Ozk5U68E68
+/AseMA0GCSqGSIb3DQEBBQUAA4IBAQCRaqmxZgJiJ+MLamb/P4vyS6azr6/tj8dZCK++V/3GnecR
+m7CiZpR47EnW0NyDzCecGyTWSkVlnZPnNvXRx700Nn0M4Inia5pNhSuVmWS3p5eV70vCbsfRD26+
+6CZhkHWnL/J2xpqeacULtgPPz9gBTyC2ybQr17dv7W5Qc+3UFywmE5N8ozQuEJroGz7P+yCbBEss
+WcmIUNDNdO0xs6aQZ1f+DV4FUB0lajuILYFz4xM+81akYFVqaGPCVwbQgFSWRKmamj8FxfWjA4DC
+rgkHVR1rA3tZyirfCBK9cfWpTCLr8zq9Ur0jTAeGrHRzHlUrB9mYZwyr0kNOyl9293xh
+-----END CERTIFICATE-----
diff --git a/etc/certs/EID-SK 2007 OCSP.crt b/etc/certs/EID-SK 2007 OCSP.crt
new file mode 100644
index 0000000..90ceaaa
--- /dev/null
+++ b/etc/certs/EID-SK 2007 OCSP.crt
@@ -0,0 +1,17 @@
+-----BEGIN CERTIFICATE-----
+MIIDOjCCAiKgAwIBAgIERh9YjTANBgkqhkiG9w0BAQUFADBqMQswCQYDVQQGEwJFRTEiMCAGA1UE
+ChMZQVMgU2VydGlmaXRzZWVyaW1pc2tlc2t1czEhMB8GA1UECxMYU2VydGlmaXRzZWVyaW1pc3Rl
+ZW51c2VkMRQwEgYDVQQDEwtFSUQtU0sgMjAwNzAeFw0wNzA0MTMxMDE2NDVaFw0xMDA0MTcwOTE2
+NDVaMH8xCzAJBgNVBAYTAkVFMSIwIAYDVQQKExlBUyBTZXJ0aWZpdHNlZXJpbWlza2Vza3VzMQ0w
+CwYDVQQLEwRPQ1NQMSMwIQYDVQQDExpFSUQtU0sgMjAwNyBPQ1NQIFJFU1BPTkRFUjEYMBYGCSqG
+SIb3DQEJARYJcGtpQHNrLmVlMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQD+Z0LZ6TjBzx4x
++UshExea1nIMsS86xAN6u/amLV8XQE+vodEld8iqtRsrvFiQ74isYOys1JKqiq+1ryic6j2FnMDZ
+ueLiXZl51QWyuhWu+aT4BwEaA8rUxMgKJ94zWksrqSf9cjoaap+9DlDhEsrDa+/89CPl2rlZIB5l
+qeHLQQIDAQABo1cwVTATBgNVHSUEDDAKBggrBgEFBQcDCTAfBgNVHSMEGDAWgBQcB/Scv6QlbLO0
+niIfH5RIG1h6jTAdBgNVHQ4EFgQUMsMzikmZqG6CcdgnD5VAXfQeCrgwDQYJKoZIhvcNAQEFBQAD
+ggEBAH0eUFQ7LznD4R8XWj/6rsNhe0fme3Os7cyZGNkx1EWenkgdMHCV/gN3SyIfrjW7sEJM62sS
+1X+8Ke2J+6b5YH0TcSmSDqYICn6zVbsq5MLtHW5wmwKucBJ5xFgoC3NNCEp8wVrzuQmm6xCvFWQV
+Q6uNhjuxCQxcDKgLwpL7iEcBEMmTTKkvqEtqrvu/LZ/a2OHytkEoXGheN8KlEcIv7AJBPVL8OCv4
+UpgyUOrVnmIeX2F/KG3wmo4U3kVupuF9kaPrOeOGYG3ZzK2HNwfRNkZ/Ej7AuPazkumAHdsJBbpT
+dBYq8d8er8XZKai24Ra/e5eEmcMye+O8IpxAA4ExY+I=
+-----END CERTIFICATE-----
diff --git a/etc/certs/EID-SK 2007.crt b/etc/certs/EID-SK 2007.crt
new file mode 100644
index 0000000..23efede
--- /dev/null
+++ b/etc/certs/EID-SK 2007.crt
@@ -0,0 +1,20 @@
+-----BEGIN CERTIFICATE-----
+MIID4jCCAsqgAwIBAgIERZ4nqjANBgkqhkiG9w0BAQUFADBdMRgwFgYJKoZIhvcNAQkBFglwa2lA
+c2suZWUxCzAJBgNVBAYTAkVFMSIwIAYDVQQKExlBUyBTZXJ0aWZpdHNlZXJpbWlza2Vza3VzMRAw
+DgYDVQQDEwdKdXVyLVNLMB4XDTA3MDEwNTEwMjU0NloXDTE2MDgyNjE0MjMwMVowajELMAkGA1UE
+BhMCRUUxIjAgBgNVBAoTGUFTIFNlcnRpZml0c2VlcmltaXNrZXNrdXMxITAfBgNVBAsTGFNlcnRp
+Zml0c2VlcmltaXN0ZWVudXNlZDEUMBIGA1UEAxMLRUlELVNLIDIwMDcwggEiMA0GCSqGSIb3DQEB
+AQUAA4IBDwAwggEKAoIBAQDifhEdyvuhk/3TJEGMJ1tEZOskE81yMqPGGXaPHXACJ7fncn1D1uQF
+t+RG8/ckh7zDquHV1m4HQk7dchaP00rvgsvRlYC9GPcFt6TW8w3t+BkxY1RNbmONgH3qzikljk7m
+6Nb8UGtL9hOmZdw5k5t9Ht8fgHTnoBkFrxYgsv9d4CCkBTSprNUK+vy/NTak4iAYinWtK6tRHHb1
+fxRsLUXiDLSO42Kz+rehhslANX+9Y5/h0wlh3pcmxLB1JWAP0O9fV6N1LUQ3Ym7wMp/lBXuPvl52
+yJuSZDWUF7GkIp+vUifOSefF6CeGh8K9BXDvuOqg+5c/6gkfEQxpRgdu+q5FAgMBAAGjgZwwgZkw
+EgYDVR0TAQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAf4wMwYDVR0fBCwwKjAooCagJIYiaHR0
+cDovL3d3dy5zay5lZS9jcmxzL2p1dXIvY3JsLmNybDAfBgNVHSMEGDAWgBQEqnpHo+SJrxrPCkCn
+GD9v7+l9vjAdBgNVHQ4EFgQUHAf0nL+kJWyztJ4iHx+USBtYeo0wDQYJKoZIhvcNAQEFBQADggEB
+ABaiEXv415Oh7AgHODwKRyNFqPcSSOgpLCy1XJB3hl3fi21fslccWuBhfzqHQCiQi0fewh109IJi
+Hq8n1PeKoHBCUVq6NFpxkVsUlUPBr0Qsya1O3SQjuOsBLzUWBvY25dtBuAkBMCo0V1Erf7iTeOzu
+L4LLbCoeOfeQT3HPmEfSqP5f8V10ST8erbiTVPJwzr66vXaT9YKxy8NyAQc2iaOHuYmGKxs8dgDQ
+RkG6b2a/f5q21YEQKDhvz7VvM6tH+F+rohA2wAvVz4tcPtyw5WEYcavr1KHgz4eZVWsqh2OsHUK9
+qMas5m/44O1/hXrjpMy5IQsiB4ASXDuXvdOTVbU=
+-----END CERTIFICATE-----
diff --git a/etc/certs/EID-SK 2011.crt b/etc/certs/EID-SK 2011.crt
new file mode 100644
index 0000000..d3222f4
--- /dev/null
+++ b/etc/certs/EID-SK 2011.crt
@@ -0,0 +1,29 @@
+-----BEGIN CERTIFICATE-----
+MIIFADCCA+igAwIBAgIQQyvUTmJDa0ZNgy+/fS0vWjANBgkqhkiG9w0BAQUFADB1
+MQswCQYDVQQGEwJFRTEiMCAGA1UECgwZQVMgU2VydGlmaXRzZWVyaW1pc2tlc2t1
+czEoMCYGA1UEAwwfRUUgQ2VydGlmaWNhdGlvbiBDZW50cmUgUm9vdCBDQTEYMBYG
+CSqGSIb3DQEJARYJcGtpQHNrLmVlMB4XDTExMDMxODEwMTExMVoXDTI0MDMxODEw
+MTExMVowYTELMAkGA1UEBhMCRUUxIjAgBgNVBAoMGUFTIFNlcnRpZml0c2Vlcmlt
+aXNrZXNrdXMxFDASBgNVBAMMC0VJRC1TSyAyMDExMRgwFgYJKoZIhvcNAQkBFglw
+a2lAc2suZWUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC2Q1zKMt7D
+ytbntSLoYAAVkEwV+5djSr0vSIG/Zm9seKyx+2PY8sVzXRoUD1CMIYnstDhBSKMj
+n2/+HpA7pOipAIAMrk6uKnpSTTdFbQ+0fzJVPokBgsdsQ6R5TZFPB1nu5zgRRlQm
+WIFxOpDiNHTt0LObUhWLXzUb31vc1Wmao2IYcDx1TCs/1E9+camiCl2B5lXrPEU3
+wBq4waD54izS20DK05+6+hHRg+TqoIg5YSmwbjStEyd/8AQeokwVloyyH49bnpel
+uADcZJgxxE9ZUvVWHoxYfmg1IeRU72jHTcIjNf1cQN2+9/FtHQMnGzDBgmAPpghw
+Wr3JtW0JWvMXAgMBAAGjggGeMIIBmjASBgNVHRMBAf8ECDAGAQH/AgEAMA4GA1Ud
+DwEB/wQEAwIBBjCB9AYDVR0gBIHsMIHpMIHmBgsrBgEEAc4fZAEBATCB1jCBsAYI
+KwYBBQUHAgIwgaMegaAASwBhAHMAdQB0AGEAdABhAGsAcwBlACAAZgD8APwAcwBp
+AGwAaQBzAHQAZQBsAGUAIABpAHMAaQBrAHUAdABlAGwAZQAgAHMAZQByAHQAaQBm
+AGkAawBhAGEAdABpAGQAZQAgAHYA5ABsAGoAYQBzAHQAYQBtAGkAcwBlAGsAcwAg
+AGsAbwBtAG0AZQByAHQAcwBhAGwAdQBzAGUAbAAuMCEGCCsGAQUFBwIBFhVodHRw
+czovL3d3dy5zay5lZS9DUFMwHQYDVR0OBBYEFLEQlwL63YbGeEGkwzKI+/4f58AF
+MB8GA1UdIwQYMBaAFBLyWj7qVhy/zQas8fElyalL1BSZMD0GA1UdHwQ2MDQwMqAw
+oC6GLGh0dHA6Ly93d3cuc2suZWUvcmVwb3NpdG9yeS9jcmxzL2VlY2NyY2EuY3Js
+MA0GCSqGSIb3DQEBBQUAA4IBAQAxau3ohdFkpvaiVUR7arNovQUZRCG9Ge3udqHY
+emovyU7N60Hgomc/ZG+uunScATTUhBcv9a5zkQxb1dQ1LYDRfNr9CqI0QvSEE4t9
+Sfu3fOhyLrlmb3s8xhhYLJBJ325uDvtO/qFeXLlcRXMF5nU8FE2IyaZP1CHYKVh5
+QNPPQiGZGSox5oOkCvmt4lUl4lZUwVie75us/WtrD6DJeREBTEDHORIfg8E9RA1y
+/7t2gT9vrU8tabeSZlD03qwXe0nJ9RscI/P0HT8vuo1PGzCfbH9xFqfoZ2jdJ0Hz
+xrFM8VsL/AtCw0dmrxRHLlZzqSw0G7b0W40mwOQauO2gbMfn
+-----END CERTIFICATE-----
diff --git a/etc/certs/EID-SK OCSP 2006.crt b/etc/certs/EID-SK OCSP 2006.crt
new file mode 100644
index 0000000..1809fb0
--- /dev/null
+++ b/etc/certs/EID-SK OCSP 2006.crt
@@ -0,0 +1,18 @@
+-----BEGIN CERTIFICATE-----
+MIIDVzCCAj+gAwIBAgIERCKL4zANBgkqhkiG9w0BAQUFADCBizEYMBYGCSqGSIb3DQEJARYJcGtp
+QHNrLmVlMQswCQYDVQQGEwJFRTEiMCAGA1UEChMZQVMgU2VydGlmaXRzZWVyaW1pc2tlc2t1czEh
+MB8GA1UECxMYU2VydGlmaXRzZWVyaW1pc3RlZW51c2VkMQowCAYDVQQFEwExMQ8wDQYDVQQDEwZF
+SUQtU0swHhcNMDYwMzIzMTE1MjAzWhcNMDkwMzI3MTE1MjAzWjB6MQswCQYDVQQGEwJFRTEiMCAG
+A1UEChMZQVMgU2VydGlmaXRzZWVyaW1pc2tlc2t1czENMAsGA1UECxMET0NTUDEeMBwGA1UEAxMV
+RUlELVNLIE9DU1AgUkVTUE9OREVSMRgwFgYJKoZIhvcNAQkBFglwa2lAc2suZWUwgZ8wDQYJKoZI
+hvcNAQEBBQADgY0AMIGJAoGBAJXYEhLiVs7JNpHWhoze68+oRFEcIsUzVvhXQIpNJowEs7blTp7C
+6UJKdK8DC6RpfiehJUdiZILl+wRGGP28Xg049Uku2oiZYX/B2EW829cGfsktDZGh8wJxya3vlyHj
+XOueAwZjNtK74LxpPXWCWSlePJyzvvW8dGJuYG5Uh0IvAgMBAAGjVzBVMBMGA1UdJQQMMAoGCCsG
+AQUFBwMJMB8GA1UdIwQYMBaAFLS8J3CeB8vFZMMyGWzcH3opLjelMB0GA1UdDgQWBBQRDqx+35L2
+TZfA3b9Xf7cnBm7zUTANBgkqhkiG9w0BAQUFAAOCAQEACUFA/IIgn9jZoB+mF05nU9SK/WOqqVhU
+CFVjYfGNltxtAJjM+HWuNWTpzPEATSxPexaNguNQBSLz57/rU3bgSX8bzwYFjBFQSZuJEWD30Svy
+nf3pSGuLA6yGkZlSH4mfccjXJML8kw7HKjb4RHJAtFCPE5nyxzhCqar6yx7o3OTg7ytf8M7RH0KE
+LbAjCYq9My/yjA8+ML/CzXDFRLWlurhSVJ/9MVZljdJ0Lg2vmnb1NGUcQQmXP/jfHIiJPDUGajYB
+Zd4nx5BiMlCAonuBWXYJ5pJUJ4uz3qMrrYAxp3BWn0NhysUX2fM92KQxxHHqvVWHKD5Q6Ja4W/Ws
+0QU3VA==
+-----END CERTIFICATE-----
diff --git a/etc/certs/EID-SK OCSP.crt b/etc/certs/EID-SK OCSP.crt
new file mode 100644
index 0000000..ae94e21
--- /dev/null
+++ b/etc/certs/EID-SK OCSP.crt
@@ -0,0 +1,20 @@
+-----BEGIN CERTIFICATE-----
+MIIDVzCCAj+gAwIBAgIEQJ+U4jANBgkqhkiG9w0BAQUFADCBizEYMBYGCSqGSIb3
+DQEJARYJcGtpQHNrLmVlMQswCQYDVQQGEwJFRTEiMCAGA1UEChMZQVMgU2VydGlm
+aXRzZWVyaW1pc2tlc2t1czEhMB8GA1UECxMYU2VydGlmaXRzZWVyaW1pc3RlZW51
+c2VkMQowCAYDVQQFEwExMQ8wDQYDVQQDEwZFSUQtU0swHhcNMDQwNTEwMTQ0MjQy
+WhcNMDcwNTE1MTM0MjQyWjB6MQswCQYDVQQGEwJFRTEiMCAGA1UEChMZQVMgU2Vy
+dGlmaXRzZWVyaW1pc2tlc2t1czENMAsGA1UECxMET0NTUDEeMBwGA1UEAxMVRUlE
+LVNLIE9DU1AgUkVTUE9OREVSMRgwFgYJKoZIhvcNAQkBFglwa2lAc2suZWUwgZ8w
+DQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBALXQF4I5tdllZwNfb3xap93XqGmL225J
+tPgv6SjBOP5pbPs8OwWkpBaqHEJ2WJy7rvEJPTMACNorrH1zBqyIh2t774iSxxGL
+TTDbQbmdM+hzGnAZMerAfHgQPtxx4ri3iluP/MHwWW5U1WKLyi4b1kSEfvqP8hzH
+RfbtKrkBLQLDAgMBAAGjVzBVMBMGA1UdJQQMMAoGCCsGAQUFBwMJMB8GA1UdIwQY
+MBaAFLS8J3CeB8vFZMMyGWzcH3opLjelMB0GA1UdDgQWBBTOliPaDCUNgr1qHIbI
+prQCQrnKzTANBgkqhkiG9w0BAQUFAAOCAQEAo4givhw0UMEOE/RVjSpdY+uoAz6Z
+uNkWYZrhamrLuziJHQdpvxy1ACAAFfDpHc0lRK+wcnFV8NCWxtohZgCzpWB8HzLV
+NgFnt/40CFBqkzRT6wL3jhVflu6lQdhBLmxPzs06BIEZixP0iEOKrIzezEePf3/e
+a6kapVsg5zjPq8iW9ua39cmBp4D0sQ4yd6BMnLPyn77k7zlEzbQfFhAtLis7z6uF
+S0XRJh9PAvcLRPhBGBBcBnGk+x+TAF35OBGL0BOmv/6XqByx/97ACcpOo8ga/CIo
+tOQgyddpBH6bX0HisicUGpLGcpLkZG0HaUKXOeyibYwE/IDM7jrDrzOrPw==
+-----END CERTIFICATE-----
diff --git a/etc/certs/EID-SK.crt b/etc/certs/EID-SK.crt
new file mode 100644
index 0000000..084ba01
--- /dev/null
+++ b/etc/certs/EID-SK.crt
@@ -0,0 +1,24 @@
+-----BEGIN CERTIFICATE-----
+MIIEBDCCAuygAwIBAgIEQJ9YpTANBgkqhkiG9w0BAQUFADBdMRgwFgYJKoZIhvcN
+AQkBFglwa2lAc2suZWUxCzAJBgNVBAYTAkVFMSIwIAYDVQQKExlBUyBTZXJ0aWZp
+dHNlZXJpbWlza2Vza3VzMRAwDgYDVQQDEwdKdXVyLVNLMB4XDTA0MDUxMDEwMjU0
+MVoXDTE0MDUwODA5MjU0MVowgYsxGDAWBgkqhkiG9w0BCQEWCXBraUBzay5lZTEL
+MAkGA1UEBhMCRUUxIjAgBgNVBAoTGUFTIFNlcnRpZml0c2VlcmltaXNrZXNrdXMx
+ITAfBgNVBAsTGFNlcnRpZml0c2VlcmltaXN0ZWVudXNlZDEKMAgGA1UEBRMBMTEP
+MA0GA1UEAxMGRUlELVNLMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA
+uj80U//DJVfCY5H+vW9xxzBV5tef7no+ehDez9TXtso0HtI1y2400CTHPZckOxdj
+LgOa0TSKcEboGYATujSpVXfR2w4NOK91cmRTPcmBlk3S/FrZvTbwTkYEMAUG3ED0
+Ofv7uq8rn4UnKiQxzeClJV2gectPu19FdM9pCqJV3DGn95BOng2tcwba0fISDPUh
+vUYnuF4f9ZxblFHJTd82dFh9Qc/EkQ+czl8l72wyMOfWJwO50IbyRJJ5hIglFZ6q
+BWFT4s53W6ubT2RfOOhqoBdywNk3W5u1sUXCnkIr4MVjwWSeUvv0caanXhYskKTx
+tOYXFe0Rq/IsGrxUasRB5QIDAQABo4GcMIGZMBIGA1UdEwEB/wQIMAYBAf8CAQAw
+DgYDVR0PAQH/BAQDAgHmMDMGA1UdHwQsMCowKKAmoCSGImh0dHA6Ly93d3cuc2su
+ZWUvY3Jscy9qdXVyL2NybC5jcmwwHwYDVR0jBBgwFoAUBKp6R6Pkia8azwpApxg/
+b+/pfb4wHQYDVR0OBBYEFLS8J3CeB8vFZMMyGWzcH3opLjelMA0GCSqGSIb3DQEB
+BQUAA4IBAQBXF6vhu1kgHOBzET0WK5JjgNHbB7vX0JR2r8SGoNnkmWsnqlNtZxCU
+5YdB/HK/TmNmQykmf1qSI0gmarvCZ0aZfNNDERT5I67o15zlsoI207XvYIJ1oHPb
+Ia5VVKUnzb7nP3xcWx7HhDGb5A2qVvrMoxsWv+CcvoTKx1nvCCsOXiiSCZYVqQK5
+lw/NptHqwRh/e4ywE5ReQrUmD2MzfEB4s4aBHfOWSH4+ucJVFRvsIJqAFXwueq9E
+LgJYEnaqVtmmCl3Gfaff0Pi6eTAfZDrJ9v7lKRYOLtImDpiJUMygTtnX0YFa/zaW
+oMNrPAZ4RYS3FOq+6+XfoXx+IDLl+oew
+-----END CERTIFICATE-----
diff --git a/etc/certs/ESTEID-SK 2007 OCSP 2010.crt b/etc/certs/ESTEID-SK 2007 OCSP 2010.crt
new file mode 100644
index 0000000..dd1a6a7
--- /dev/null
+++ b/etc/certs/ESTEID-SK 2007 OCSP 2010.crt
@@ -0,0 +1,23 @@
+-----BEGIN CERTIFICATE-----
+MIIEkjCCA3qgAwIBAgIESxUPmTANBgkqhkiG9w0BAQUFADBbMQswCQYDVQQGEwJFRTEiMCAGA1UE
+ChMZQVMgU2VydGlmaXRzZWVyaW1pc2tlc2t1czEPMA0GA1UECxMGRVNURUlEMRcwFQYDVQQDEw5F
+U1RFSUQtU0sgMjAwNzAeFw0wOTEyMDExMjQ1MDBaFw0xNjA4MjYxMzIzMDBaMIGHMQswCQYDVQQG
+EwJFRTEiMCAGA1UECgwZQVMgU2VydGlmaXRzZWVyaW1pc2tlc2t1czENMAsGA1UECwwET0NTUDEr
+MCkGA1UEAwwiRVNURUlELVNLIDIwMDcgT0NTUCBSRVNQT05ERVIgMjAxMDEYMBYGCSqGSIb3DQEJ
+ARYJcGtpQHNrLmVlMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA48pyM/QfeiU1Kbu4
+AdcAUKXBiwbYbBl4gCltZHC5fZ77fKj2mqfPX2/XW1EqzbVvG0PYIkapkQzBr3R1S6Uaxh1DLC2C
+c8BRnqmhXoE03o8En7N9xpN9dGGDBHp2aElBcVVZnAvF4jgbPDCNFAeo3cvpjIx18n0URiVOZFEd
+xDvF8PFo/exKXtjRM+jk3K6+9doHYvSXn9klFbT8Wge87Qdll3gQzZE3L8QMXF0z4xbBH1lyTmVL
+t5yZ0fxoE0jNlZFvn2w2EDnU4CKfId8w6Zjd5kdxomcwDzGuuLzdiJllPt05USJcY4FHn9YAVKWm
+ofYY/o6xOUzU8fAz6yA1tQIDAQABo4IBLzCCASswEwYDVR0lBAwwCgYIKwYBBQUHAwkwaQYDVR0g
+BGIwYDBeBgorBgEEAc4fBAECMFAwJQYIKwYBBQUHAgIwGRoXU0sgdGltZSBzdGFtcGluZyBwb2xp
+Y3kwJwYIKwYBBQUHAgEWG2h0dHA6Ly93d3cuc2suZWUvYWphdGVtcGVsLzCBiQYDVR0jBIGBMH+A
+FEgG3r6Mh1eVgHhj+pwjKyugOhh1oWGkXzBdMRgwFgYJKoZIhvcNAQkBFglwa2lAc2suZWUxCzAJ
+BgNVBAYTAkVFMSIwIAYDVQQKExlBUyBTZXJ0aWZpdHNlZXJpbWlza2Vza3VzMRAwDgYDVQQDEwdK
+dXVyLVNLggRFm6ANMB0GA1UdDgQWBBQ4AhAwumZ6EXROIl5wZQXedXpOFDANBgkqhkiG9w0BAQUF
+AAOCAQEAJ/LvPUevNRcBp+J78fZRofhk/ifKNLxCUoh8T3MjtU9u5R0KojRlye+1NU8MqH/zrKhr
+6TPxuXD0cRrFQ9Hy60II7IzzaegrQVNgq7UgQINvCuNxWZcGtEa3ba9M7tBpQeFxqp3CpBytGeVu
+Xn65hqOBKdp/zYEiMUUkYNAT5A6SSPYLAOgARCI/ydBx+cw0l0fwYvw72FKZa2Mlt5DmXBccCtrQ
+4l/sb95xfANCNe5n5sBvBhY4F+sIWZUVJ8fTVh7iGaVPSayQfeAAei0m/4/ksiXBwfx6qhzyB3yq
+cnSk489oBrrCegua/t+3LizfHpNZvDphKMPuAZ4uheLfQA==
+-----END CERTIFICATE-----
diff --git a/etc/certs/ESTEID-SK 2007 OCSP.crt b/etc/certs/ESTEID-SK 2007 OCSP.crt
new file mode 100644
index 0000000..cc56a7b
--- /dev/null
+++ b/etc/certs/ESTEID-SK 2007 OCSP.crt
@@ -0,0 +1,19 @@
+-----BEGIN CERTIFICATE-----
+MIIDnDCCAoSgAwIBAgIERZ0acjANBgkqhkiG9w0BAQUFADBbMQswCQYDVQQGEwJFRTEiMCAGA1UE
+ChMZQVMgU2VydGlmaXRzZWVyaW1pc2tlc2t1czEPMA0GA1UECxMGRVNURUlEMRcwFQYDVQQDEw5F
+U1RFSUQtU0sgMjAwNzAeFw0wNzAxMDQxNTE3MDZaFw0xMDAxMDgxNTE3MDZaMG8xCzAJBgNVBAYT
+AkVFMQ8wDQYDVQQKEwZFU1RFSUQxDTALBgNVBAsTBE9DU1AxJjAkBgNVBAMTHUVTVEVJRC1TSyAy
+MDA3IE9DU1AgUkVTUE9OREVSMRgwFgYJKoZIhvcNAQkBFglwa2lAc2suZWUwgZ8wDQYJKoZIhvcN
+AQEBBQADgY0AMIGJAoGBAJmoB3SJCpPzcoHNqK1J0tRNQjgr5iuB27uE1VacIbITjD/Nc1AefKz5
+ydNPIaBNehm4yKxBYGxEeWOSJHVXyhJMg53EAUOw/45c46gvznXupHuJ6TEiGjh1pxaXTeLSnTqz
+NDZDAGQsOTgIbwGLa5U5ad8rXYu2YkJKsAfo6jT5AgMBAAGjgdcwgdQwEwYDVR0lBAwwCgYIKwYB
+BQUHAwkwEgYJKwYEBQUHMAEFBAUwAwQBMDCBiQYDVR0jBIGBMH+AFEgG3r6Mh1eVgHhj+pwjKyug
+Ohh1oWGkXzBdMRgwFgYJKoZIhvcNAQkBFglwa2lAc2suZWUxCzAJBgNVBAYTAkVFMSIwIAYDVQQK
+ExlBUyBTZXJ0aWZpdHNlZXJpbWlza2Vza3VzMRAwDgYDVQQDEwdKdXVyLVNLggRFm6ANMB0GA1Ud
+DgQWBBRJ/snw1GDL3fUH9n9Cpn8yhXiC7DANBgkqhkiG9w0BAQUFAAOCAQEAYzGkZD/uaXlWPeye
+1z5IiI83nmAjiJyvoj/r3BB9ZFWMX+ZY4Fz6/V/fzD0xXoeDpWbBKxcuctPXzXYxEH17n0/3yGOz
+8jhdJNBUCwRmd+96oHsU9aWSf+D2tiq1jPw6HVCiUYOhC/OWjg/+JpFlWsBV4gTW8/2PSGig85Xl
+EsWLK7i7tIe60nnw/rWnfbCckMRcbrAF1L/JIlnUYUdkGOGQ9KPVqwR/MyWrwFIcSy2QIbcIaWMu
+iUc1nt8bmIXKoFZxbLzXYC00zba9cY7lSC4WPuhBtrQJ9JWb4OeoXd5j6O45UaH6XbarfrhER1GH
+L06cTyksT18p2L2GrMuEJg==
+-----END CERTIFICATE-----
diff --git a/etc/certs/ESTEID-SK 2007.crt b/etc/certs/ESTEID-SK 2007.crt
new file mode 100644
index 0000000..b36e3e2
--- /dev/null
+++ b/etc/certs/ESTEID-SK 2007.crt
@@ -0,0 +1,20 @@
+-----BEGIN CERTIFICATE-----
+MIID0zCCArugAwIBAgIERZugDTANBgkqhkiG9w0BAQUFADBdMRgwFgYJKoZIhvcNAQkBFglwa2lA
+c2suZWUxCzAJBgNVBAYTAkVFMSIwIAYDVQQKExlBUyBTZXJ0aWZpdHNlZXJpbWlza2Vza3VzMRAw
+DgYDVQQDEwdKdXVyLVNLMB4XDTA3MDEwMzEyMjIzN1oXDTE2MDgyNjE0MjMwMVowWzELMAkGA1UE
+BhMCRUUxIjAgBgNVBAoTGUFTIFNlcnRpZml0c2VlcmltaXNrZXNrdXMxDzANBgNVBAsTBkVTVEVJ
+RDEXMBUGA1UEAxMORVNURUlELVNLIDIwMDcwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB
+AQDtWp2jLCsA7K9AxoPDOL0geM1GoR0Q6wSUICCJYyFkUMboEMxpSzFB6tlb0ySlHEU6Fs+tjA4Q
+rSqwaw0uNk4BXv1lkoOr6DUc+20+AQd5jB6A0atrltZ1XG5IvDEep3DJPykkk2MPxUz7dZx7XUEr
+/kdUWI9cDIkFWic7y9oTBY9JaV6lxm08kweZ/qTw5PU8/bTvZCE0ygvBXU4TDS2FpUJ/+jTzM2oc
+Wa3QjFQv2Sir6LBvgNY3du/m+WLABq0dgN18R4nhFtmaVepqAeUuEi8eRBl6yLTSmMwYCY46LsK5
+CdjTCZSZv934FtNuyY6Ph9nCXJAgNAY+GfNJfdMXAgMBAAGjgZwwgZkwEgYDVR0TAQH/BAgwBgEB
+/wIBADAOBgNVHQ8BAf8EBAMCAf4wMwYDVR0fBCwwKjAooCagJIYiaHR0cDovL3d3dy5zay5lZS9j
+cmxzL2p1dXIvY3JsLmNybDAfBgNVHSMEGDAWgBQEqnpHo+SJrxrPCkCnGD9v7+l9vjAdBgNVHQ4E
+FgQUSAbevoyHV5WAeGP6nCMrK6A6GHUwDQYJKoZIhvcNAQEFBQADggEBACO6SJrjN5WZuiLSMy/t
+SmT/w3dd/KPErSAdUIJYkC7hOIauW7jZ3VNgNUMHSIkUoP8AviEMjGA4lkT61YScpJAdmgl8Y80H
+FdZV5CsThhddoIdZ3cZjSI4NZmTVkSduTjoySALxKL3ZEIPrepQDvNEeV1WSpI5+u/vMekUWJSPc
+8BK9O2av1e9ResKyPJidqrIksHFjNS+Yt8Ouw7F10MHaPPzMiwoa0DYTVsIKJncPTQmvdJG8M0DD
+ToiiNPQuUy5d1CA75Wtjs+yILGZXpOfbdoQhE7G4pbZaF1s69jKp+zc0ZT4g2OoKfI2TiIX9qeGJ
+MxkOENcd1DDqYVfePmo=
+-----END CERTIFICATE-----
diff --git a/etc/certs/ESTEID-SK 2011.crt b/etc/certs/ESTEID-SK 2011.crt
new file mode 100644
index 0000000..69cb046
--- /dev/null
+++ b/etc/certs/ESTEID-SK 2011.crt
@@ -0,0 +1,29 @@
+-----BEGIN CERTIFICATE-----
+MIIFBTCCA+2gAwIBAgIQKVKTqv2MxtRNgzCjwmRRDTANBgkqhkiG9w0BAQUFADB1
+MQswCQYDVQQGEwJFRTEiMCAGA1UECgwZQVMgU2VydGlmaXRzZWVyaW1pc2tlc2t1
+czEoMCYGA1UEAwwfRUUgQ2VydGlmaWNhdGlvbiBDZW50cmUgUm9vdCBDQTEYMBYG
+CSqGSIb3DQEJARYJcGtpQHNrLmVlMB4XDTExMDMxODEwMTQ1OVoXDTI0MDMxODEw
+MTQ1OVowZDELMAkGA1UEBhMCRUUxIjAgBgNVBAoMGUFTIFNlcnRpZml0c2Vlcmlt
+aXNrZXNrdXMxFzAVBgNVBAMMDkVTVEVJRC1TSyAyMDExMRgwFgYJKoZIhvcNAQkB
+Fglwa2lAc2suZWUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCz6Xxs
+Zh6r/aXcNe3kSpNMOqmQoAXUpzzcr4ZSaGZh/7JHIiplvNi6tbW/lK7sAiRsb65K
+zMWROEauld66ggbDPga6kU97C+AXGu7+DROXstjUOv6VlrHZVAnLmIOkycpWaxjM
++EfQPZuDxEbkw96B3/fG69Zbp3s9y6WEhwU5Y9IiQl8YTkGnNUxidQbON1BGQm+H
+VEsgTf22J6r6G3FsE07rnMNskNC3DjuLSCUKF4kH0rVGVK9BdiCdFaZjHEykjwjI
+GzqnyxyRKe4YbJ6B9ABm95eSFgMBHtZEYU+q0VUIQGhAGAurOTXjWi1TssA42mnL
+GQZEI5GXMXtabp51AgMBAAGjggGgMIIBnDASBgNVHRMBAf8ECDAGAQH/AgEAMA4G
+A1UdDwEB/wQEAwIBBjCB9gYDVR0gBIHuMIHrMIHoBgsrBgEEAc4fZAEBATCB2DCB
+sgYIKwYBBQUHAgIwgaUegaIASwBhAHMAdQB0AGEAdABhAGsAcwBlACAAaQBzAGkA
+awB1AHQAdAD1AGUAbgBkAGEAdgBhAGwAZQAgAGQAbwBrAHUAbQBlAG4AZABpAGwA
+ZQAgAGsAYQBuAHQAYQB2AGEAdABlACAAcwBlAHIAdABpAGYAaQBrAGEAYQB0AGkA
+ZABlACAAdgDkAGwAagBhAHMAdABhAG0AaQBzAGUAawBzAC4wIQYIKwYBBQUHAgEW
+FWh0dHBzOi8vd3d3LnNrLmVlL0NQUzAdBgNVHQ4EFgQUe2ryVVBcuNl6CIdBrvqi
+Kz1bV3YwHwYDVR0jBBgwFoAUEvJaPupWHL/NBqzx8SXJqUvUFJkwPQYDVR0fBDYw
+NDAyoDCgLoYsaHR0cDovL3d3dy5zay5lZS9yZXBvc2l0b3J5L2NybHMvZWVjY3Jj
+YS5jcmwwDQYJKoZIhvcNAQEFBQADggEBAKC4IN3FC2gVDIH05TNMgFrQOCGSnXhz
+oJclRLoQ81BCOXTZI4qn7N74FHEnrAy6uNG7SS5qANqSaPIL8dp63jg/L4qn4iWa
+B5q5GGJOV07SnTHS7gUrqChGClnUeHxiZbL13PkP37Lnc+TKl1SKfgtn5FbH5cqr
+hvbA/VF3Yzlimu+L7EVohW9HKxZ//z8kDn6ieiPFfZdTOov/0eXVLlxqklybUuS6
+LYRRDiqQupgBKQBTwNbC8x0UHX00HokW+dCVcQvsUbv4xLhRq/MvyTthE+RdbkrV
+0JuzbfZvADfj75nA3+ZAzFYS5ZpMOjZ9p4rQVKpzQTklrF0m6mkdcEo=
+-----END CERTIFICATE-----
diff --git a/etc/certs/ESTEID-SK OCSP 2005.crt b/etc/certs/ESTEID-SK OCSP 2005.crt
new file mode 100644
index 0000000..b534532
--- /dev/null
+++ b/etc/certs/ESTEID-SK OCSP 2005.crt
@@ -0,0 +1,20 @@
+-----BEGIN CERTIFICATE-----
+MIIDPDCCAiSgAwIBAgIEQi2iwTANBgkqhkiG9w0BAQUFADB8MRgwFgYJKoZIhvcN
+AQkBFglwa2lAc2suZWUxCzAJBgNVBAYTAkVFMSIwIAYDVQQKExlBUyBTZXJ0aWZp
+dHNlZXJpbWlza2Vza3VzMQ8wDQYDVQQLEwZFU1RFSUQxCjAIBgNVBAQTATExEjAQ
+BgNVBAMTCUVTVEVJRC1TSzAeFw0wNTAzMDgxMzA0MDFaFw0xMjAxMTIxMzA0MDFa
+MG8xCzAJBgNVBAYTAkVFMQ8wDQYDVQQKEwZFU1RFSUQxDTALBgNVBAsTBE9DU1Ax
+JjAkBgNVBAMTHUVTVEVJRC1TSyBPQ1NQIFJFU1BPTkRFUiAyMDA1MRgwFgYJKoZI
+hvcNAQkBFglwa2lAc2suZWUwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAI8m
+LeLkRHLxMNCB5Pz8R5DnvPdVxBS91PoHboLnbhjlp1ecByVosjwGpXCGu8tUPuv8
+1Azgqq97AsSugM1J7Pu0gj4bg0Mf6O/9XyoT7RI7H0BuEn4KJQlFcw7tXizI5KUW
+FFZ4Qg8kfg0xwrDrLIjusBtRbeRARG3DhH8dgZBpAgMBAAGjVzBVMBMGA1UdJQQM
+MAoGCCsGAQUFBwMJMB8GA1UdIwQYMBaAFHgXtQX5s1jNWYzeZ15EBkx1hmldMB0G
+A1UdDgQWBBRM+GJhloJeOPpJDgvA0clxQXdnVTANBgkqhkiG9w0BAQUFAAOCAQEA
+fD8dP+swtSeigLxL3uUXV/tmQkjre7Ww39Uey71LdtxQ6zC7MDjcsLW13JaU0pRu
+u/p/eGe6h4/w46tSMsBx/U+D1WnHeCj1ED9SFWwfNQFVz9FkM5JEkPDm7lw5hHox
+IghRHAC3NMbR3sCrVQA2YELf2WypslROoz8XlRT1LN4pwVehpBeWO7xbQPUtoaxK
+rSCGumtxtxA3KRJ7POHPTAH4cvipxaZhS1ZcXbKtxsesGW+7KLZirpTBT17ICXEA
+1CFXDWmJ8MHRhbeNWK3G1PERgTiGtBQV7Z00CzmJPHmb1yfcT27+WZ1W9tRQsjhG
+EWyMVkNnZooWHIjLpNucQA==
+-----END CERTIFICATE-----
diff --git a/etc/certs/ESTEID-SK OCSP.crt b/etc/certs/ESTEID-SK OCSP.crt
new file mode 100644
index 0000000..3113d04
--- /dev/null
+++ b/etc/certs/ESTEID-SK OCSP.crt
@@ -0,0 +1,22 @@
+-----BEGIN CERTIFICATE-----
+MIIDuDCCAqCgAwIBAgIEPJilyDANBgkqhkiG9w0BAQUFADB8MRgwFgYJKoZIhvcN
+AQkBFglwa2lAc2suZWUxCzAJBgNVBAYTAkVFMSIwIAYDVQQKExlBUyBTZXJ0aWZp
+dHNlZXJpbWlza2Vza3VzMQ8wDQYDVQQLEwZFU1RFSUQxCjAIBgNVBAQTATExEjAQ
+BgNVBAMTCUVTVEVJRC1TSzAeFw0wMjAzMjAxNTA3NTJaFw0wNTAzMjQxNTA3NTJa
+MGoxCzAJBgNVBAYTAkVFMQ8wDQYDVQQKEwZFU1RFSUQxDTALBgNVBAsTBE9DU1Ax
+ITAfBgNVBAMTGEVTVEVJRC1TSyBPQ1NQIFJFU1BPTkRFUjEYMBYGCSqGSIb3DQEJ
+ARYJcGtpQHNrLmVlMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC10BeCObXZ
+ZWcDX298Wqfd16hpi9tuSbT4L+kowTj+aWz7PDsFpKQWqhxCdlicu67xCT0zAAja
+K6x9cwasiIdre++IkscRi00w20G5nTPocxpwGTHqwHx4ED7cceK4t4pbj/zB8Flu
+VNVii8ouG9ZEhH76j/Icx0X27Sq5AS0CwwIDAQABo4HXMIHUMBMGA1UdJQQMMAoG
+CCsGAQUFBwMJMBIGCSsGBAUFBzABBQQFMAMEATAwgYkGA1UdIwSBgTB/gBR4F7UF
++bNYzVmM3mdeRAZMdYZpXaFhpF8wXTEYMBYGCSqGSIb3DQEJARYJcGtpQHNrLmVl
+MQswCQYDVQQGEwJFRTEiMCAGA1UEChMZQVMgU2VydGlmaXRzZWVyaW1pc2tlc2t1
+czEQMA4GA1UEAxMHSnV1ci1TS4IEPERcgjAdBgNVHQ4EFgQUzpYj2gwlDYK9ahyG
+yKa0AkK5ys0wDQYJKoZIhvcNAQEFBQADggEBADrq0tGkwsrddEqUbsOpXi75Xs4G
+VkOyseysNqZZCvLqCF7qTSMiC+fzRxQbXQDhuOT7QQvi3JAoA5zTIm2RvIO1fmrV
+nJ6CsObjxxvXtcSLI+bICG4uQYgEA+duDRgICpmtCCjtmxb+2/cSJLGioaKiwn0Y
+wgeEowOgjDMh2o4otm6FjtyT1GZsZm56U7WkFa7tSwkHKw427iZUWVrED6W9AfAT
+Y14rNnAk8Jqz06w4rPnGE4kYjO+UqMLmFU2KImdrTp1O7h4YLCVlxH/e/He8r7FS
+gzXSG4EqlD/TMEdCLu7DSWR3SEgJPvKWCpNWzv2DRldHp+kQO3k+R/f2c80=
+-----END CERTIFICATE-----
diff --git a/etc/certs/ESTEID-SK.crt b/etc/certs/ESTEID-SK.crt
new file mode 100644
index 0000000..678952b
--- /dev/null
+++ b/etc/certs/ESTEID-SK.crt
@@ -0,0 +1,29 @@
+-----BEGIN CERTIFICATE-----
+MIIFAjCCA+qgAwIBAgIEPERcgjANBgkqhkiG9w0BAQUFADBdMRgwFgYJKoZIhvcN
+AQkBFglwa2lAc2suZWUxCzAJBgNVBAYTAkVFMSIwIAYDVQQKExlBUyBTZXJ0aWZp
+dHNlZXJpbWlza2Vza3VzMRAwDgYDVQQDEwdKdXVyLVNLMB4XDTAyMDExNTE2NDQ1
+MFoXDTEyMDExMzE2NDQ1MFowfDEYMBYGCSqGSIb3DQEJARYJcGtpQHNrLmVlMQsw
+CQYDVQQGEwJFRTEiMCAGA1UEChMZQVMgU2VydGlmaXRzZWVyaW1pc2tlc2t1czEP
+MA0GA1UECxMGRVNURUlEMQowCAYDVQQEEwExMRIwEAYDVQQDEwlFU1RFSUQtU0sw
+ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCLeZO5NVo3zbwA8eFVCrrb
+eZQKvPDB7LUDPvzCqw7U2sC+IwEOdjjpJRF4lxFs+f8yC1bP+rqtWzrKhhJ2owfS
+AlIZMbly/OFjfLqOcyyi7qdfA/66u+69u/DY9tW5fqW93D73v5WNcNoIemCTydh9
+IFkQvMihWKH7LblBzCHa4W6qUcBZ7QsBgYpQS9n9fGJt5D2wCDeq0pF1Zy72G3CQ
+FrpuR/aPG28tv9r+C7oqncapbiJ7xIOa77Fm3o07M/9aarq/m1oHEp9CxYiH9nmD
+3kyMe8yxw5v02MTMmAcxOm83z5O4oXSDTALG5gDfZNPjJaNPno7J8FuGrI3vV8z3
+AgMBAAGjggGpMIIBpTAMBgNVHRMEBTADAQH/MA4GA1UdDwEB/wQEAwIB5jCCARYG
+A1UdIASCAQ0wggEJMIIBBQYKKwYBBAHOHwEBATCB9jCB0AYIKwYBBQUHAgIwgcMe
+gcAAUwBlAGUAIABzAGUAcgB0AGkAZgBpAGsAYQBhAHQAIABvAG4AIAB2AOQAbABq
+AGEAcwB0AGEAdAB1AGQAIABBAFMALQBpAHMAIABTAGUAcgB0AGkAZgBpAHQAcwBl
+AGUAcgBpAG0AaQBzAGsAZQBzAGsAdQBzACAAYQBsAGEAbQAtAFMASwAgAHMAZQBy
+AHQAaQBmAGkAawBhAGEAdABpAGQAZQAgAGsAaQBuAG4AaQB0AGEAbQBpAHMAZQBr
+AHMwIQYIKwYBBQUHAgEWFWh0dHA6Ly93d3cuc2suZWUvY3BzLzArBgNVHR8EJDAi
+MCCgHqAchhpodHRwOi8vd3d3LnNrLmVlL2p1dXIvY3JsLzAfBgNVHSMEGDAWgBQE
+qnpHo+SJrxrPCkCnGD9v7+l9vjAdBgNVHQ4EFgQUeBe1BfmzWM1ZjN5nXkQGTHWG
+aV0wDQYJKoZIhvcNAQEFBQADggEBAFIsMHaq4Ffkrxmzw38rHYh5Ia5JGxjtWfPp
+ag9pBtQNZHzY8j97xfPI15haE9Ah3u1WC+bsU2SndVSUGaZ0gKafMxDOy2DUw3B8
+4ymbNRiAFSWty+aKrMCjtdlPktbSQmxNSJAX9vVtM4Y2ory+dtAQ7g11GKHJ+l8B
+DUpOJA+l8hvS2l4K5whWDHCSqlplMiHPIKgBVArFRNzAq6dquMY+kS3e2PL+PM4G
+dDW5lRHR/6KUy0BHP2gX/BO4mYQ3BH2BHImUclNras0HISnV/pt6hIkgd1PsFt3r
+tEolAWP4DWBmc4zAYQJ5t0cEwFM329zCXSGIQIm3a1cMugF5Q/k=
+-----END CERTIFICATE-----
diff --git a/etc/certs/JUUR-SK.crt b/etc/certs/JUUR-SK.crt
new file mode 100644
index 0000000..269961b
--- /dev/null
+++ b/etc/certs/JUUR-SK.crt
@@ -0,0 +1,29 @@
+-----BEGIN CERTIFICATE-----
+MIIE5jCCA86gAwIBAgIEO45L/DANBgkqhkiG9w0BAQUFADBdMRgwFgYJKoZIhvcN
+AQkBFglwa2lAc2suZWUxCzAJBgNVBAYTAkVFMSIwIAYDVQQKExlBUyBTZXJ0aWZp
+dHNlZXJpbWlza2Vza3VzMRAwDgYDVQQDEwdKdXVyLVNLMB4XDTAxMDgzMDE0MjMw
+MVoXDTE2MDgyNjE0MjMwMVowXTEYMBYGCSqGSIb3DQEJARYJcGtpQHNrLmVlMQsw
+CQYDVQQGEwJFRTEiMCAGA1UEChMZQVMgU2VydGlmaXRzZWVyaW1pc2tlc2t1czEQ
+MA4GA1UEAxMHSnV1ci1TSzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB
+AIFxNj4zB9bjMI0TfncyRsvPGbJgMUaXhvSYRqTCZUXP00B841oiqBB4M8yIsdOB
+SvZiF3tfTQou0M+LI+5PAk676w7KvRhj6IAcjeEcjT3g/1tf6mTll+g/mX8MCgkz
+ABpTpyHhOEvWgxutr2TC+Rx6jGZITWYfGAriPrsfB2WThbkasLnE+w0R9vXW+RvH
+LCu3GFH+4Hv2qEivbDtPL+/40UceJlfwUR0zlv/vWT3aTdEVNMfqPxZIe5EcgEMP
+PbgFPtGzlc3Yyg/CQ2fbt5PgIoIuvvVoKIO5wTtpeyDaTpxt4brNj3pssAki14sL
+2xzVWiZbDcDq5WDQn/413z8CAwEAAaOCAawwggGoMA8GA1UdEwEB/wQFMAMBAf8w
+ggEWBgNVHSAEggENMIIBCTCCAQUGCisGAQQBzh8BAQEwgfYwgdAGCCsGAQUFBwIC
+MIHDHoHAAFMAZQBlACAAcwBlAHIAdABpAGYAaQBrAGEAYQB0ACAAbwBuACAAdgDk
+AGwAagBhAHMAdABhAHQAdQBkACAAQQBTAC0AaQBzACAAUwBlAHIAdABpAGYAaQB0
+AHMAZQBlAHIAaQBtAGkAcwBrAGUAcwBrAHUAcwAgAGEAbABhAG0ALQBTAEsAIABz
+AGUAcgB0AGkAZgBpAGsAYQBhAHQAaQBkAGUAIABrAGkAbgBuAGkAdABhAG0AaQBz
+AGUAawBzMCEGCCsGAQUFBwIBFhVodHRwOi8vd3d3LnNrLmVlL2Nwcy8wKwYDVR0f
+BCQwIjAgoB6gHIYaaHR0cDovL3d3dy5zay5lZS9qdXVyL2NybC8wHQYDVR0OBBYE
+FASqekej5ImvGs8KQKcYP2/v6X2+MB8GA1UdIwQYMBaAFASqekej5ImvGs8KQKcY
+P2/v6X2+MA4GA1UdDwEB/wQEAwIB5jANBgkqhkiG9w0BAQUFAAOCAQEAe8EYlFOi
+CfP+JmeaUOTDBS8rNXiRTHyoERF5TElZrMj3hWVcRrs7EKACr81Ptcw2Kuxd/u+g
+kcm2k298gFTsxwhwDY77guwqYHhpNjbRxZyLabVAyJRld/JXIWY7zoVAtjNjGr95
+HvxcHdMdkxuLDF2FvZkwMhgJkVLpfKG6/2SSmuz+Ne6ML678IIbsSt4beDI3poHS
+na9aEhbKmVv8b20OxaAehsmR0FyYgl9jDIpaq9iVpszLita/ZEuOyoqysOkhMp6q
+qIWYNIE5ITuoOlIyPfZrN4YGWhWY3PARZv40ILcD9EEQfTmEeZZyY7aWAuVrua0Z
+TbvGRNs2yyqcjg==
+-----END CERTIFICATE-----
diff --git a/etc/certs/KLASS3-SK 2010 EECCRCA.crt b/etc/certs/KLASS3-SK 2010 EECCRCA.crt
new file mode 100644
index 0000000..53dabc1
--- /dev/null
+++ b/etc/certs/KLASS3-SK 2010 EECCRCA.crt
@@ -0,0 +1,27 @@
+-----BEGIN CERTIFICATE-----
+MIIErDCCA5SgAwIBAgIQAznVp1LayatNgy6bN8f9QjANBgkqhkiG9w0BAQUFADB1
+MQswCQYDVQQGEwJFRTEiMCAGA1UECgwZQVMgU2VydGlmaXRzZWVyaW1pc2tlc2t1
+czEoMCYGA1UEAwwfRUUgQ2VydGlmaWNhdGlvbiBDZW50cmUgUm9vdCBDQTEYMBYG
+CSqGSIb3DQEJARYJcGtpQHNrLmVlMB4XDTExMDMxODEwMDYxOFoXDTI0MDMxODEw
+MDYxOFowbTELMAkGA1UEBhMCRUUxIjAgBgNVBAoTGUFTIFNlcnRpZml0c2Vlcmlt
+aXNrZXNrdXMxITAfBgNVBAsTGFNlcnRpZml0c2VlcmltaXN0ZWVudXNlZDEXMBUG
+A1UEAxMOS0xBU1MzLVNLIDIwMTAwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK
+AoIBAQCrlaYRX2v89k8Hd0ADaOfnUcIn7iM6aOXkAR+jp5827ZhDqDyNddF9ZUoB
+gPghGNIrkHbH7qwex39YnI0ka24lCjcwEMvQMPbyPnX/a4RyJ+wEZttmjBl++Ffr
+ZK54L+vD7Dyy4YYB0Og9ktB4qptsDBj+giiv/MGPeGeNs3TacJdNb7+3splTPtPK
+lDfrufvq4H6jNOv9S9bC+j2VVY9uCFXUro8AA3hoOEKJdSjlpYCa51N8KGLVJYRu
+c/K81xqi054Jz+Cy/HY/AcXkk2JkxlpJoEXmcuTkxjO/QE/Xbd+mRJHnq6+HurOi
+KcxKwZCPAa+d+dvRPkbyq9ohMXH9AgMBAAGjggE+MIIBOjASBgNVHRMBAf8ECDAG
+AQH/AgEAMA4GA1UdDwEB/wQEAwIBxjCBlAYDVR0gBIGMMIGJMIGGBgsrBgEEAc4f
+ZAEBATB3MCEGCCsGAQUFBwIBFhVodHRwczovL3d3dy5zay5lZS9jcHMwUgYIKwYB
+BQUHAgIwRh5EAEEAcwB1AHQAdQBzAGUAIABzAGUAcgB0AGkAZgBpAGsAYQBhAHQA
+LgAgAEMAbwByAHAAbwByAGEAdABlACAASQBEAC4wHQYDVR0OBBYEFF11FBGM9KWO
+Qo97skBEo+7WejtyMB8GA1UdIwQYMBaAFBLyWj7qVhy/zQas8fElyalL1BSZMD0G
+A1UdHwQ2MDQwMqAwoC6GLGh0dHA6Ly93d3cuc2suZWUvcmVwb3NpdG9yeS9jcmxz
+L2VlY2NyY2EuY3JsMA0GCSqGSIb3DQEBBQUAA4IBAQC3qNBgY2I9Wqm4LZYKAjCY
+kc2Nltm1RS9frMvQJ4aEE4Y4TtW2LPcQp2lenOf9aYdEB8G/E9CytZSPlFuvDdsd
+knj6fg1XCeu6ITR2wIkxJeAeLQvrFEfb1mcAa5tU9RNalZhYc7MFMFQTjQP+GBNx
+z+KIjNDVASFdv7TCe7GBjsW8Dfes9lQGHaWsBRkHCyuPGIHfH+cmMuhLtWqa4Qlg
+4f54kcsGO7s4buKtk6XqEj8Cj2ITdfk/aUs9QoxxkYWGwSUlCueTamzufXEJo9yz
+5Jp6IFdGjotmjb/EBUCf2sFfI83a4Cm1D3L3/KYb5g3cYlDEpPWNqbNuA1XosIqK
+-----END CERTIFICATE-----
diff --git a/etc/certs/KLASS3-SK 2010 OCSP.crt b/etc/certs/KLASS3-SK 2010 OCSP.crt
new file mode 100644
index 0000000..73ba848
--- /dev/null
+++ b/etc/certs/KLASS3-SK 2010 OCSP.crt
@@ -0,0 +1,25 @@
+-----BEGIN CERTIFICATE-----
+MIIELzCCAxegAwIBAgICAMswDQYJKoZIhvcNAQEFBQAwbTELMAkGA1UEBhMCRUUx
+IjAgBgNVBAoTGUFTIFNlcnRpZml0c2VlcmltaXNrZXNrdXMxITAfBgNVBAsTGFNl
+cnRpZml0c2VlcmltaXN0ZWVudXNlZDEXMBUGA1UEAxMOS0xBU1MzLVNLIDIwMTAw
+HhcNMTAwNDA4MDgwMTMxWhcNMTYwODI1MjIwMDAwWjCBgjEYMBYGCSqGSIb3DQEJ
+ARYJcGtpQHNrLmVlMQswCQYDVQQGEwJFRTEiMCAGA1UEChMZQVMgU2VydGlmaXRz
+ZWVyaW1pc2tlc2t1czENMAsGA1UECxMET0NTUDEmMCQGA1UEAxMdS0xBU1MzLVNL
+IDIwMTAgT0NTUCBSRVNQT05ERVIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK
+AoIBAQDhWwGpngF0sdGCgOgiyT12A/Vdm9sMPr/cUwZhU7DA5C8rU1yJhbrh28fM
+pv0eas6/+IC1oDxI24zjfWIKfHwpBmhUTFsmvmKRIu4a1F6VwNwYEdoAZrQDpzZS
+ve6H6R/+0Uy0BAolebdhPUK22pKd8V1CBY3de886Ray8uUJu09MAU8j+xsoUNOzy
+xiWdAVp1YTXRhhUt+EQVYJ22RBZ6+b9fPQvgb9aWgE/WwqUh7OrgTnrGZVzgO46p
+rfE7zkALG0FYZCzQTCMH8aIqqte0E3HwSVlKh9qwbRPB9WTDCtCqajh4qgGRTXvW
+T4vATlHvx8GpJ3roZkp5AlQno3hTAgMBAAGjgcIwgb8waAYDVR0gBGEwXzBdBgor
+BgEEAc4fBAECME8wJQYIKwYBBQUHAgIwGRoXU0sgdGltZSBzdGFtcGluZyBwb2xp
+Y3kwJgYIKwYBBQUHAgEWGmh0dHA6Ly93d3cuc2suZWUvYWphdGVtcGVsMBMGA1Ud
+JQQMMAoGCCsGAQUFBwMJMB8GA1UdIwQYMBaAFF11FBGM9KWOQo97skBEo+7Wejty
+MB0GA1UdDgQWBBQ3MJkXG2Go/6j4bem465aue3P5qjANBgkqhkiG9w0BAQUFAAOC
+AQEAKhoVTII1ECecFkyt9Ogr0XW3WEFprrqTDE4IycMlx+LNjWk30aknMldEtzIC
+5nCDX27NCWkpbN1o/3ddBv0cKMa05ZK8sHQxU6A5Oev8DCp72/LFEChq5IDqgqW2
+BiHhyfPfr93JIuV03b/Wgq3fpRyBd21VE9254W4A90xeNxDvdpqxlrD2Lonzm/V/
+oomzEHsp4kKxXkPmRU4vGtTnxxAnxYp9OuLkvpUCLNoAWMbYqb4cbYzaZ9tQIkBy
+3nJ352Rs5obYDb3R/ZVWuYLLSocWL7b2QwlDP7LA8VNDqmQvioHt8GcyKXQ5/eWM
+vj2ePt58waVhwfSdd4nANKtq1g==
+-----END CERTIFICATE-----
diff --git a/etc/certs/KLASS3-SK 2010.crt b/etc/certs/KLASS3-SK 2010.crt
new file mode 100644
index 0000000..dc85ca7
--- /dev/null
+++ b/etc/certs/KLASS3-SK 2010.crt
@@ -0,0 +1,23 @@
+-----BEGIN CERTIFICATE-----
+MIID5TCCAs2gAwIBAgIES7MTKDANBgkqhkiG9w0BAQUFADBdMRgwFgYJKoZIhvcN
+AQkBFglwa2lAc2suZWUxCzAJBgNVBAYTAkVFMSIwIAYDVQQKExlBUyBTZXJ0aWZp
+dHNlZXJpbWlza2Vza3VzMRAwDgYDVQQDEwdKdXVyLVNLMB4XDTEwMDMzMTA5MTcy
+OFoXDTE2MDgyNjE0MjMwMVowbTELMAkGA1UEBhMCRUUxIjAgBgNVBAoTGUFTIFNl
+cnRpZml0c2VlcmltaXNrZXNrdXMxITAfBgNVBAsTGFNlcnRpZml0c2VlcmltaXN0
+ZWVudXNlZDEXMBUGA1UEAxMOS0xBU1MzLVNLIDIwMTAwggEiMA0GCSqGSIb3DQEB
+AQUAA4IBDwAwggEKAoIBAQCrlaYRX2v89k8Hd0ADaOfnUcIn7iM6aOXkAR+jp582
+7ZhDqDyNddF9ZUoBgPghGNIrkHbH7qwex39YnI0ka24lCjcwEMvQMPbyPnX/a4Ry
+J+wEZttmjBl++FfrZK54L+vD7Dyy4YYB0Og9ktB4qptsDBj+giiv/MGPeGeNs3Ta
+cJdNb7+3splTPtPKlDfrufvq4H6jNOv9S9bC+j2VVY9uCFXUro8AA3hoOEKJdSjl
+pYCa51N8KGLVJYRuc/K81xqi054Jz+Cy/HY/AcXkk2JkxlpJoEXmcuTkxjO/QE/X
+bd+mRJHnq6+HurOiKcxKwZCPAa+d+dvRPkbyq9ohMXH9AgMBAAGjgZwwgZkwEgYD
+VR0TAQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAcYwMwYDVR0fBCwwKjAooCag
+JIYiaHR0cDovL3d3dy5zay5lZS9jcmxzL2p1dXIvY3JsLmNybDAfBgNVHSMEGDAW
+gBQEqnpHo+SJrxrPCkCnGD9v7+l9vjAdBgNVHQ4EFgQUXXUUEYz0pY5Cj3uyQESj
+7tZ6O3IwDQYJKoZIhvcNAQEFBQADggEBADFuAGtSoO8PsWRw/QxFzc5EZtbq2KXC
+9yZ8YQPWBLY4Mh3OVLFJqWyKC+8JHy9D5tJTG49F5UHyDJPufD/XvC2rjRlkqvS/
+W7sy3MqGh7e+6bg+aD4mo+98Oalnqi12UD+ki+N8JKPXjHNJ31AvH6E/xDsCsvtz
+ubylxI+FU8R0XODIUFbBqRtatRI1/zVaKRhD6LNGPt3rz/3IJKmuEv6b29mzL+p4
+oNULqpPr6aTmheZme8ZHuEIh3Zp5kdoX3i2D4hsmgClpevZifo196zeKRLk0Qs6n
+mRjoMxyk6jYIric3/VnV81oyhXSBY1GZnbM4qP1w2S5kSA2bb1pkwFo=
+-----END CERTIFICATE-----
diff --git a/etc/certs/KLASS3-SK OCSP 2006.crt b/etc/certs/KLASS3-SK OCSP 2006.crt
new file mode 100644
index 0000000..02133fc
--- /dev/null
+++ b/etc/certs/KLASS3-SK OCSP 2006.crt
@@ -0,0 +1,18 @@
+-----BEGIN CERTIFICATE-----
+MIIDXTCCAkWgAwIBAgIERCKLGDANBgkqhkiG9w0BAQUFADCBjjEYMBYGCSqGSIb3DQEJARYJcGtp
+QHNrLmVlMQswCQYDVQQGEwJFRTEiMCAGA1UEChMZQVMgU2VydGlmaXRzZWVyaW1pc2tlc2t1czEh
+MB8GA1UECxMYU2VydGlmaXRzZWVyaW1pc3RlZW51c2VkMQowCAYDVQQFEwExMRIwEAYDVQQDEwlL
+TEFTUzMtU0swHhcNMDYwMzIzMTE0ODQwWhcNMDkwMzI3MTE0ODQwWjB9MQswCQYDVQQGEwJFRTEi
+MCAGA1UEChMZQVMgU2VydGlmaXRzZWVyaW1pc2tlc2t1czENMAsGA1UECxMET0NTUDEhMB8GA1UE
+AxMYS0xBU1MzLVNLIE9DU1AgUkVTUE9OREVSMRgwFgYJKoZIhvcNAQkBFglwa2lAc2suZWUwgZ8w
+DQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAKKTI8Aex0Gva9eeeBkM3fGTiNOEvjj2McN3tOJBMAEv
+G/G7Npu0/2fAEKFFUv4NnPyH3MiC7s6R8PtPMhV5GBG6kWVztL/gQnlIjAbo1l654+jApIQjT3vd
+VZDIYyS6lKlYoAdG40CgLlVtRihargQ77azlfORkyRfhKZcSQe8tAgMBAAGjVzBVMBMGA1UdJQQM
+MAoGCCsGAQUFBwMJMB8GA1UdIwQYMBaAFOU/DJ1xPW+8Gb+a9G6/Cf5A652WMB0GA1UdDgQWBBQU
+QsudE6pYaIJSuWurylGItfy52DANBgkqhkiG9w0BAQUFAAOCAQEAV+Vu+qzrHe7HDjMHq9DdOQTz
+833QcMRY0huSgphMOgqNjqjPqTNpHPgNvE6HKGdQ0+VWr8IyRWcxnPMZNihmaCGMpFMpYuH0fx9n
+sjXDbjat8MfGuX2m1EADGOwjtjMuoYTEGEUe3MBeFkmPFDIYpeuS+I4Qv34tOsGvFOpsDkobSATq
+4EFw/5hI9WfWaEMYkmBXdeokoVjbNpt+gtdGKNBU42AlxLrcc+YzAE1hj5qH99/hl0X6r63pTjUb
+1ZMRjGQg7ELwmddms7wB5LKKi5kbfmag5hBtDKGs2s0xW1be4ylNOrT9lqUYuPn9lwcHNg1IS42m
+YVChV97Tlt/5vw==
+-----END CERTIFICATE-----
diff --git a/etc/certs/KLASS3-SK OCSP 2009.crt b/etc/certs/KLASS3-SK OCSP 2009.crt
new file mode 100644
index 0000000..af5f7d1
--- /dev/null
+++ b/etc/certs/KLASS3-SK OCSP 2009.crt
@@ -0,0 +1,20 @@
+-----BEGIN CERTIFICATE-----
+MIIDzzCCAregAwIBAgIEScskSjANBgkqhkiG9w0BAQUFADCBjjEYMBYGCSqGSIb3DQEJARYJcGtp
+QHNrLmVlMQswCQYDVQQGEwJFRTEiMCAGA1UEChMZQVMgU2VydGlmaXRzZWVyaW1pc2tlc2t1czEh
+MB8GA1UECxMYU2VydGlmaXRzZWVyaW1pc3RlZW51c2VkMQowCAYDVQQFEwExMRIwEAYDVQQDEwlL
+TEFTUzMtU0swHhcNMDkwMzI2MDY0NDI2WhcNMTIwNTA0MDU0NDI2WjCBgjELMAkGA1UEBhMCRUUx
+IjAgBgNVBAoTGUFTIFNlcnRpZml0c2VlcmltaXNrZXNrdXMxDTALBgNVBAsTBE9DU1AxJjAkBgNV
+BAMTHUtMQVNTMy1TSyBPQ1NQIFJFU1BPTkRFUiAyMDA5MRgwFgYJKoZIhvcNAQkBFglwa2lAc2su
+ZWUwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAKi6weNl7Wj7sL6JD4YUNt/JXQ79KL53x5m4
+QGRsijGJaV5YggE5rJyVZGlsX4FSd9JFIV597ypAUGDbLPf0nDdlSIGteP7zamyETI3GI6bKfkeU
+uIE707r7uC+8FFe9iHOOL20+pi7WFzwnyXT9yuWs0eCoKdjQvLpMiq0MBIm9AgMBAAGjgcIwgb8w
+EwYDVR0lBAwwCgYIKwYBBQUHAwkwaAYDVR0gBGEwXzBdBgorBgEEAc4fBAECME8wJQYIKwYBBQUH
+AgIwGRoXU0sgdGltZSBzdGFtcGluZyBwb2xpY3kwJgYIKwYBBQUHAgEWGmh0dHA6Ly93d3cuc2su
+ZWUvYWphdGVtcGVsMB8GA1UdIwQYMBaAFOU/DJ1xPW+8Gb+a9G6/Cf5A652WMB0GA1UdDgQWBBT5
+9PTkSIzYXNBxQQnAhqH3BtED0TANBgkqhkiG9w0BAQUFAAOCAQEAhyl3H6fo1bz3mD0JcD4eY1sl
+cwec92Qgkn6i9TsO5TlDQCJxiC/80zlh+H5dgIMcNQ6gNbr1cWsUw7xAanv2hGlg20IWq7uCyy5L
+DghFpO2BWDzTJjmiVTXzyVEvqST0W6efDiwi1tA8H7b+aAzc9ItWm7pYlucGvneKJq07t/UvU9ON
+SDUfVLPNMr8slwCMOexVDZ+eiBlvrLL3N7NouPs7UpFh/+m5JsERmeLbbrNYimHUUn2PJ/trJ3kB
+EVFToO+nFdBElfzC3bjSlbPXFxSOL+AqSgvRIaB4CEWUxa33wzoZNaVpCh5AupxQOGdr4u7ajw5h
+kV8Y9VZ7OFej6A==
+-----END CERTIFICATE-----
diff --git a/etc/certs/KLASS3-SK OCSP.crt b/etc/certs/KLASS3-SK OCSP.crt
new file mode 100644
index 0000000..af973e5
--- /dev/null
+++ b/etc/certs/KLASS3-SK OCSP.crt
@@ -0,0 +1,21 @@
+-----BEGIN CERTIFICATE-----
+MIIDXTCCAkWgAwIBAgIEPolzuzANBgkqhkiG9w0BAQUFADCBjjEYMBYGCSqGSIb3
+DQEJARYJcGtpQHNrLmVlMQswCQYDVQQGEwJFRTEiMCAGA1UEChMZQVMgU2VydGlm
+aXRzZWVyaW1pc2tlc2t1czEhMB8GA1UECxMYU2VydGlmaXRzZWVyaW1pc3RlZW51
+c2VkMQowCAYDVQQFEwExMRIwEAYDVQQDEwlLTEFTUzMtU0swHhcNMDMwNDAxMTEx
+MDUxWhcNMDYwNDA1MTAxMDUxWjB9MQswCQYDVQQGEwJFRTEiMCAGA1UEChMZQVMg
+U2VydGlmaXRzZWVyaW1pc2tlc2t1czENMAsGA1UECxMET0NTUDEhMB8GA1UEAxMY
+S0xBU1MzLVNLIE9DU1AgUkVTUE9OREVSMRgwFgYJKoZIhvcNAQkBFglwa2lAc2su
+ZWUwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBALXQF4I5tdllZwNfb3xap93X
+qGmL225JtPgv6SjBOP5pbPs8OwWkpBaqHEJ2WJy7rvEJPTMACNorrH1zBqyIh2t7
+74iSxxGLTTDbQbmdM+hzGnAZMerAfHgQPtxx4ri3iluP/MHwWW5U1WKLyi4b1kSE
+fvqP8hzHRfbtKrkBLQLDAgMBAAGjVzBVMBMGA1UdJQQMMAoGCCsGAQUFBwMJMB8G
+A1UdIwQYMBaAFOU/DJ1xPW+8Gb+a9G6/Cf5A652WMB0GA1UdDgQWBBTOliPaDCUN
+gr1qHIbIprQCQrnKzTANBgkqhkiG9w0BAQUFAAOCAQEAd/8FCyPC9zXxcAZN67KC
+NU4+XNJ8e+LmG602lBe+lS7Pw4pOgMKebgULKh1fEBHQ2K7FSUWMZdPWkDHaKVRh
+646yVbFZbfEmKNq4LhRf13/hoUdrG5uRVmCsV03WSfgfUVfb1cZf8tDMIwCmsNXu
+22k9wykeHallpUmGUfbVZygqfKE2NVQpm2FULiKWBFKXqbMtW5R3xmDS3bjrAIAd
+UdYhxhfdCHCphsQf/FJlxb8UFOUa8SeRNr5eL7s8znLnrC5pKPpWGbUNSlrhLJZH
+IeXfwbOamae6UVvjto6bMqRe2sxCsMA0dGz+tMiglfmTVInxpEKBkyvF/on/2qwt
+Vw==
+-----END CERTIFICATE-----
diff --git a/etc/certs/KLASS3-SK.crt b/etc/certs/KLASS3-SK.crt
new file mode 100644
index 0000000..2edcfa9
--- /dev/null
+++ b/etc/certs/KLASS3-SK.crt
@@ -0,0 +1,24 @@
+-----BEGIN CERTIFICATE-----
+MIIEBDCCAuygAwIBAgIEPNkU9TANBgkqhkiG9w0BAQUFADBdMRgwFgYJKoZIhvcN
+AQkBFglwa2lAc2suZWUxCzAJBgNVBAYTAkVFMSIwIAYDVQQKExlBUyBTZXJ0aWZp
+dHNlZXJpbWlza2Vza3VzMRAwDgYDVQQDEwdKdXVyLVNLMB4XDTAyMDUwODEyMDcx
+N1oXDTEyMDUwNTExMDcxN1owgY4xGDAWBgkqhkiG9w0BCQEWCXBraUBzay5lZTEL
+MAkGA1UEBhMCRUUxIjAgBgNVBAoTGUFTIFNlcnRpZml0c2VlcmltaXNrZXNrdXMx
+ITAfBgNVBAsTGFNlcnRpZml0c2VlcmltaXN0ZWVudXNlZDEKMAgGA1UEBRMBMTES
+MBAGA1UEAxMJS0xBU1MzLVNLMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC
+AQEAvIIeK3GJxoPCXVwan+HjJwYGaH3nb/rTPEqg5v9e1c7dnTDBdD2Yteg+lUdH
+BZDHLj1Tz+J/W9Foc0dzEr96S8+6nMXoonK2x0854JNH2UVbS/+YOGUM6iWSxkHw
+525tvn5tFaIQoaeh46aQFp9Dngcnv4Gatd0/7NCkLggjFrKmnNTPINpLAG9VoCpV
+yIMvcVCyTNvSQ+n33ToPO5vtULNYOtCF9MDVND+uNRE2o0tWIG0l84owYPA47tJO
+LgCpAxLNFR5Ys0nB/ofBYcO+YiCri0yc6t7ZPs/vcfbR6czIwW0GMjyHmVPLB+/W
+HS3P1sk29DdgIC42RTMthJS6ZQIDAQABo4GZMIGWMA8GA1UdEwQIMAYBAf8CAQAw
+DgYDVR0PAQH/BAQDAgHmMDMGA1UdHwQsMCowKKAmoCSGImh0dHA6Ly93d3cuc2su
+ZWUvY3Jscy9qdXVyL2NybC5jcmwwHwYDVR0jBBgwFoAUBKp6R6Pkia8azwpApxg/
+b+/pfb4wHQYDVR0OBBYEFOU/DJ1xPW+8Gb+a9G6/Cf5A652WMA0GCSqGSIb3DQEB
+BQUAA4IBAQASvWB+YrgN23EMLW7C5/XUwQLNN1RMDhr6UzOo5XHZ3pxUXq2Erk5g
+giS+UJIxkQaSg4OHRru8KTchoJDvS2neeYHOz05zJcAIwoy2GGkHq1iVN+QZaprD
+aDNYR5GGKgJb3FZrMtyX4dNwnrZzMFzd6t5YibCW+BDPAmqGJvNHzJ5YYdA7I3WT
+9Baan1ncKd4FtUVb54fppd19NkbCKKSUd7qRYDduNYqVs1C/C0qqLq4TrxoxoxSo
++WNLiD01896sIRiPIy8qDOAXJU67382J5XXETe9wZO6o7+NaG0CrpzVY1OaaD2O6
+Wv/vSpxE2ugqaf0WsP35+coFCWdM2uHZ
+-----END CERTIFICATE-----
diff --git a/etc/certs/README.txt b/etc/certs/README.txt
new file mode 100644
index 0000000..282a06d
--- /dev/null
+++ b/etc/certs/README.txt
@@ -0,0 +1 @@
+Internal component, do not use. Contact for assistance by email abi@id.ee or http://www.id.ee
diff --git a/etc/certs/SK OCSP 2011.crt b/etc/certs/SK OCSP 2011.crt
new file mode 100644
index 0000000..1f5b9e8
--- /dev/null
+++ b/etc/certs/SK OCSP 2011.crt
@@ -0,0 +1,28 @@
+-----BEGIN CERTIFICATE-----
+MIIEvDCCA6SgAwIBAgIQcpyVmdruRVxNgzI3N/NZQTANBgkqhkiG9w0BAQUFADB1
+MQswCQYDVQQGEwJFRTEiMCAGA1UECgwZQVMgU2VydGlmaXRzZWVyaW1pc2tlc2t1
+czEoMCYGA1UEAwwfRUUgQ2VydGlmaWNhdGlvbiBDZW50cmUgUm9vdCBDQTEYMBYG
+CSqGSIb3DQEJARYJcGtpQHNrLmVlMB4XDTExMDMxODEwMjE0M1oXDTI0MDMxODEw
+MjE0M1owgZ0xCzAJBgNVBAYTAkVFMQ4wDAYDVQQIEwVIYXJqdTEQMA4GA1UEBxMH
+VGFsbGlubjEiMCAGA1UEChMZQVMgU2VydGlmaXRzZWVyaW1pc2tlc2t1czENMAsG
+A1UECxMET0NTUDEfMB0GA1UEAxMWU0sgT0NTUCBSRVNQT05ERVIgMjAxMTEYMBYG
+CSqGSIb3DQEJARYJcGtpQHNrLmVlMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB
+CgKCAQEAihvGyhMVrgReHluKln1za6gvCE/mlSREmWjJFpL9llvuEUZoPFIypYA8
+g5u1VfgkeW5gDq25jAOq4FyXeDGIa+pJn2h0o2Wc2aeppVG/emfGm/jA8jjeyMrw
+H8fAJrqVQ7c9X2xSwJEch/P2d8CfMZt5YF6gqLtPvG1b+n6otBZA5wjIFfJ/inJB
+MUvqHSz3+PLfxO2/T3Wyk/c8M9HIMqTelqyiMGRgWehiU1OsL9armv3dQrHs1wm6
+vHaxfpfWB9YAFpeo9aYqhPCxVt/zo2NQB6vxyZS0hsOrXL7SxRToOJaqsnvlbf0e
+rPPFtRHUvbojYYgl+fzlz0Jt6QJoNwIDAQABo4IBHTCCARkwEwYDVR0lBAwwCgYI
+KwYBBQUHAwkwHQYDVR0OBBYEFKWhSGFt537NmJ50nCm7vYrecgxZMIGCBgNVHSAE
+ezB5MHcGCisGAQQBzh8EAQIwaTA+BggrBgEFBQcCAjAyHjAAUwBLACAAdABpAG0A
+ZQAgAHMAdABhAG0AcABpAG4AZwAgAHAAbwBsAGkAYwB5AC4wJwYIKwYBBQUHAgEW
+G2h0dHBzOi8vd3d3LnNrLmVlL2FqYXRlbXBlbDAfBgNVHSMEGDAWgBQS8lo+6lYc
+v80GrPHxJcmpS9QUmTA9BgNVHR8ENjA0MDKgMKAuhixodHRwOi8vd3d3LnNrLmVl
+L3JlcG9zaXRvcnkvY3Jscy9lZWNjcmNhLmNybDANBgkqhkiG9w0BAQUFAAOCAQEA
+w2sKwvTHtYGtD8Jw9mNUuj/mWiBSBEBeY2LhW8V6tjBPAPp3s6iWOh0FbVR2LUyr
+qRwgT3fyWiGsiDm/6cIqM+IblLp/8ztfRQjquhW6XCD9SK02OQ9ZSdBwcmoAApZL
+GXQC34wdgmV/hLTTNxONnDACBKz9U+Dy9a4ZT4tpNkbH8jq/BMne8FzbvRt1bjpX
+BP7gjLX+zdx8/hp0Wq4tD+f9NVX0+vm9ahEKuzx4QzPnSB7hhWM9OnLZT7noRQa+
+KWk5c+e5VoR5R2t7MjVl8Cd+2llxiSxqMSbU5/23BzAKgN+NQdrBZAzpZ7lfaAuL
+FaICP+bAm6uW2JUrM6abOw==
+-----END CERTIFICATE-----
diff --git a/etc/certs/TEST EECCRCA.crt b/etc/certs/TEST EECCRCA.crt
new file mode 100644
index 0000000..a752611
--- /dev/null
+++ b/etc/certs/TEST EECCRCA.crt
@@ -0,0 +1,24 @@
+-----BEGIN CERTIFICATE-----
+MIIEEzCCAvugAwIBAgIQc/jtqiMEFERMtVvsSsH7sjANBgkqhkiG9w0BAQUFADB9
+MQswCQYDVQQGEwJFRTEiMCAGA1UECgwZQVMgU2VydGlmaXRzZWVyaW1pc2tlc2t1
+czEwMC4GA1UEAwwnVEVTVCBvZiBFRSBDZXJ0aWZpY2F0aW9uIENlbnRyZSBSb290
+IENBMRgwFgYJKoZIhvcNAQkBFglwa2lAc2suZWUwIhgPMjAxMDEwMDcxMjM0NTZa
+GA8yMDMwMTIxNzIzNTk1OVowfTELMAkGA1UEBhMCRUUxIjAgBgNVBAoMGUFTIFNl
+cnRpZml0c2VlcmltaXNrZXNrdXMxMDAuBgNVBAMMJ1RFU1Qgb2YgRUUgQ2VydGlm
+aWNhdGlvbiBDZW50cmUgUm9vdCBDQTEYMBYGCSqGSIb3DQEJARYJcGtpQHNrLmVl
+MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA1gGpqCtDmNNEHUjC8LXq
+xRdC1kpjDgkzOTxQynzDxw/xCjy5hhyG3xX4RPrW9Z6k5ZNTNS+xzrZgQ9m5U6uM
+ywYpx3F3DVgbdQLd8DsLmuVOz02k/TwoRt1uP6xtV9qG0HsGvN81q3HvPR/zKtA7
+MmNZuwuDFQwsguKgDR2Jfk44eKmLfyzvh+Xe6Cr5+zRnsVYwMA9bgBaOZMv1TwTT
+VNi9H1ltK32Z+IhUX8W5f2qVP33R1wWCKapK1qTX/baXFsBJj++F8I8R6+gSyC3D
+kV5N/pOlWPzZYx+kHRkRe/oddURA9InJwojbnsH+zJOa2VrNKakNv2HnuYCIonzu
+pwIDAQABo4GKMIGHMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0G
+A1UdDgQWBBS1NAqdpS8QxechDr7EsWVHGwN2/jBFBgNVHSUEPjA8BggrBgEFBQcD
+AgYIKwYBBQUHAwEGCCsGAQUFBwMDBggrBgEFBQcDBAYIKwYBBQUHAwgGCCsGAQUF
+BwMJMA0GCSqGSIb3DQEBBQUAA4IBAQAj72VtxIw6p5lqeNmWoQ48j8HnUBM+6mI0
+I+VkQr0EfQhfmQ5KFaZwnIqxWrEPaxRjYwV0xKa1AixVpFOb1j+XuVmgf7khxXTy
+Bmd8JRLwl7teCkD1SDnU/yHmwY7MV9FbFBd+5XK4teHVvEVRsJ1oFwgcxVhyoviR
+SnbIPaOvk+0nxKClrlS6NW5TWZ+yG55z8OCESHaL6JcimkLFjRjSsQDWIEtDvP4S
+tH3vIMUPPiKdiNkGjVLSdChwkW3z+m0EvAjyD9rnGCmjeEm5diLFu7VMNVqupsbZ
+SfDzzBLc5+6TqgQTOG7GaZk2diMkn03iLdHGFrh8ML+mXG9SjEPI
+-----END CERTIFICATE-----
diff --git a/etc/certs/TEST EID-SK 2011.crt b/etc/certs/TEST EID-SK 2011.crt
new file mode 100644
index 0000000..54087de
--- /dev/null
+++ b/etc/certs/TEST EID-SK 2011.crt
@@ -0,0 +1,28 @@
+-----BEGIN CERTIFICATE-----
+MIIEuDCCA6CgAwIBAgIQWwOHv2K/GORNdNgZblP5YDANBgkqhkiG9w0BAQUFADB9
+MQswCQYDVQQGEwJFRTEiMCAGA1UECgwZQVMgU2VydGlmaXRzZWVyaW1pc2tlc2t1
+czEwMC4GA1UEAwwnVEVTVCBvZiBFRSBDZXJ0aWZpY2F0aW9uIENlbnRyZSBSb290
+IENBMRgwFgYJKoZIhvcNAQkBFglwa2lAc2suZWUwHhcNMTEwMzA3MTMwNTI5WhcN
+MjMwOTA3MTIwNTI5WjBpMQswCQYDVQQGEwJFRTEiMCAGA1UECgwZQVMgU2VydGlm
+aXRzZWVyaW1pc2tlc2t1czEcMBoGA1UEAwwTVEVTVCBvZiBFSUQtU0sgMjAxMTEY
+MBYGCSqGSIb3DQEJARYJcGtpQHNrLmVlMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A
+MIIBCgKCAQEAr5TNCQvKX1IApzLX5KLWSIOhyueYlpc5WKsFLdMWWG40QwJpHm0c
+dudK51IIvdoDX5/uJlyf6/wd4NNSOF5rCogfkzD696NFuiplvXBYKZdshXqsxRhM
+9mcp+9NqND5AGK4BtuUK2S83cxIRUiOxf7O43QxX3py5MDJRNa+kUOHBic8ekvR+
+MsdVpF+3A5V6WE6DNzxecBP6TF1+l/3B7L1Hz8hsaJ6QTsc6/O011WXG9y23dMpb
+ho+JMyy9y3fe791sP87rqWhaFNT5kTnH3JOHK9fxgx0TDP66dde4nvnykRCadEmq
+bOGLEar0xmnirAJgO/yrGrQ/A7gmDdhomwIDAQABo4IBRjCCAUIwDwYDVR0TAQH/
+BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwgZkGA1UdIASBkTCBjjCBiwYKKwYBBAHO
+HwMBATB9MFgGCCsGAQUFBwICMEweSgBBAGkAbgB1AGwAdAAgAHQAZQBzAHQAaQBt
+AGkAcwBlAGsAcwAuACAATwBuAGwAeQAgAGYAbwByACAAdABlAHMAdABpAG4AZwAu
+MCEGCCsGAQUFBwIBFhVodHRwczovL3d3dy5zay5lZS9DUFMwHQYDVR0OBBYEFNQi
+siFrcquz1GPk1pe0bVcUzgEuMB8GA1UdIwQYMBaAFLU0Cp2lLxDF5yEOvsSxZUcb
+A3b+MEMGA1UdHwQ8MDowOKA2oDSGMmh0dHBzOi8vd3d3LnNrLmVlL3JlcG9zaXRv
+cnkvY3Jscy90ZXN0X2VlY2NyY2EuY3JsMA0GCSqGSIb3DQEBBQUAA4IBAQA8uY6L
+qaZKfLx6iKpoAEGxbuFwzrT4BVGqEzpZJNVkM2hhoS9qrttzUrC2hLmfWBbbsScV
+GvcWNV7GIcHLYBioZV+ostku/jXXxzhNVhVvX5B8X10uKQDtcrkGbjUpF1JSes8T
+9EsUBSIh5MmpNKc1IP8FfvL3qMU2mxU30KQdQy4IjM4Pv7T+MAWMqjrn6txfOZDu
+5k6Sak/NBn4cozX0HenY/7301snxAT3BaWhwMKqleCyM7w3wfnFGevEs/4C7qn3S
+QncgCEZlvL3lYxSIJ697LyZo0Lsc3s8+gXPT4Q/V8UqjmecgzZWHvyxCrf02iAqU
+YRawXmDuuoGMwwlJ
+-----END CERTIFICATE-----
diff --git a/etc/certs/TEST ESTEID-SK 2011.crt b/etc/certs/TEST ESTEID-SK 2011.crt
new file mode 100644
index 0000000..f48bf6d
--- /dev/null
+++ b/etc/certs/TEST ESTEID-SK 2011.crt
@@ -0,0 +1,28 @@
+-----BEGIN CERTIFICATE-----
+MIIEuzCCA6OgAwIBAgIQSxRID7FoIaNNdNhBeucLvDANBgkqhkiG9w0BAQUFADB9
+MQswCQYDVQQGEwJFRTEiMCAGA1UECgwZQVMgU2VydGlmaXRzZWVyaW1pc2tlc2t1
+czEwMC4GA1UEAwwnVEVTVCBvZiBFRSBDZXJ0aWZpY2F0aW9uIENlbnRyZSBSb290
+IENBMRgwFgYJKoZIhvcNAQkBFglwa2lAc2suZWUwHhcNMTEwMzA3MTMwNjA5WhcN
+MjMwOTA3MTIwNjA5WjBsMQswCQYDVQQGEwJFRTEiMCAGA1UECgwZQVMgU2VydGlm
+aXRzZWVyaW1pc2tlc2t1czEfMB0GA1UEAwwWVEVTVCBvZiBFU1RFSUQtU0sgMjAx
+MTEYMBYGCSqGSIb3DQEJARYJcGtpQHNrLmVlMIIBIjANBgkqhkiG9w0BAQEFAAOC
+AQ8AMIIBCgKCAQEA0SMr+A2QGMJuNpu60MgqKG0yLL7JfvjNtgs2hqWADDn1AQeD
+79o+8r4SRYp9kowSFA8E1v38XXTHRq3nSZeToOC5DMAWjsKlm4x8hwwp31BXCs/H
+rl9VmikIgAlaHvv3Z+MzS6qeLdzyYi/glPVrY42A6/kBApOJlOVLvAFdySNmFkY+
+Ky7MZ9jbBr+Nx4py/V7xm9VD62Oe1lku4S4qd+VYcQ5jftbr4OFjBp9Nn58/5svQ
+xrLjv3B67i19d7sNh7UPnMiO6BeBb6yb3P1lqdHofE1lElStIPViJlzjPOh4puxW
+adHDvVYUCJgW2aM58mTfjFhZbVfcrVn5OyIiTQIDAQABo4IBRjCCAUIwDwYDVR0T
+AQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwgZkGA1UdIASBkTCBjjCBiwYKKwYB
+BAHOHwMBATB9MFgGCCsGAQUFBwICMEweSgBBAGkAbgB1AGwAdAAgAHQAZQBzAHQA
+aQBtAGkAcwBlAGsAcwAuACAATwBuAGwAeQAgAGYAbwByACAAdABlAHMAdABpAG4A
+ZwAuMCEGCCsGAQUFBwIBFhVodHRwczovL3d3dy5zay5lZS9DUFMwHQYDVR0OBBYE
+FEG2/sWxsbRTE4z6+mLQNG1tIjQKMB8GA1UdIwQYMBaAFLU0Cp2lLxDF5yEOvsSx
+ZUcbA3b+MEMGA1UdHwQ8MDowOKA2oDSGMmh0dHBzOi8vd3d3LnNrLmVlL3JlcG9z
+aXRvcnkvY3Jscy90ZXN0X2VlY2NyY2EuY3JsMA0GCSqGSIb3DQEBBQUAA4IBAQBd
+h5R23K7qkrO78j51xN6CR2qwxUcK/cgcTLWv0obPmJ7jRax3PX0pFhaUE6EhAR0d
+gS4u6XZrjPgVrt/mwq1h8lJP1MF2ueAHKyS0SGj7aFLkcC+ULwu1k6yiortFJ0Ds
+49ZGA+ioGzYWPQ+g1Zl4wSDIz52ot0cHUijnf39Szq7E2z7MDfZkYg8HZeHrO493
+EFghXcnSH7J7z47cgP3GWFNUKv1V2c0eVE4OxRulZ3KmBLPWbJKZ0TyGa/Aooc+T
+orEjxz//WzcF/Sklp4FeD0MU39UURIlg7LfEcm832bPzZzVGFd4drBd5Dy0Uquu6
+3kW7RDqr+wQFSxKr9DIH
+-----END CERTIFICATE-----
diff --git a/etc/certs/TEST Juur-SK.crt b/etc/certs/TEST Juur-SK.crt
new file mode 100644
index 0000000..f4433f5
--- /dev/null
+++ b/etc/certs/TEST Juur-SK.crt
@@ -0,0 +1,23 @@
+-----BEGIN CERTIFICATE-----
+MIID5TCCAs2gAwIBAgIEO43dLzANBgkqhkiG9w0BAQUFADBiMRgwFgYJKoZIhvcN
+AQkBFglwa2lAc2suZWUxCzAJBgNVBAYTAkVFMSIwIAYDVQQKExlBUyBTZXJ0aWZp
+dHNlZXJpbWlza2Vza3VzMRUwEwYDVQQDEwxURVNUIEp1dXItU0swHhcNMDEwODMw
+MDYyOTA0WhcNMTYwODI3MDUyOTA0WjBiMRgwFgYJKoZIhvcNAQkBFglwa2lAc2su
+ZWUxCzAJBgNVBAYTAkVFMSIwIAYDVQQKExlBUyBTZXJ0aWZpdHNlZXJpbWlza2Vz
+a3VzMRUwEwYDVQQDEwxURVNUIEp1dXItU0swggEiMA0GCSqGSIb3DQEBAQUAA4IB
+DwAwggEKAoIBAQDJIyr2hhDhkZgOJnsFv8VHQJGGK+vld0kGRvpl9Bx81/ZFvEwO
+LDfiReuHlTXCOin2FU3f+UJ2TriA+7K4jMCrkXW4oL9vmy99JmZY3esOSzMoAGvJ
+XTkSN3/U99LajIzZ718e1kslmxgjVrlmlWI2VR/dPNkZN2KVuT4s9zYHzM3frPsa
+DqFd7yMnuqF4YP4yt6DHtqaF+R4vgP/mPRsusoN4NJBiEin6Sm/8me3MS0y8o0qY
+fOw+wYgFM2o/XTsu3B7drY/9AoTCVTSp5Lo6xw33yxgVrtKqOSPeV6YBy8lgs8kl
+75BaEt+zJ06b/aD8JB81Mtn65Tfq1rMK/HrnAgMBAAGjgaIwgZ8wDwYDVR0TAQH/
+BAUwAwEB/zA8BgNVHR8ENTAzMDGgL6AthitodHRwOi8vd3d3LnNrLmVlL2NybHMv
+dGVzdC90ZXN0LWp1dXItc2suY3JsMB0GA1UdDgQWBBSBwuAMBRryEG40E0wsjD7c
+iCkyeDAfBgNVHSMEGDAWgBSBwuAMBRryEG40E0wsjD7ciCkyeDAOBgNVHQ8BAf8E
+BAMCAeYwDQYJKoZIhvcNAQEFBQADggEBAAvvh+xwmeD8wk2Fq0SycwqMXcVw8lFf
+osXCIhw/CKpnIzJUrYLyoonNatT7XLt/nmduewUrl3GzKSdTovJA2k1d4srJvU9s
+9AEyMJysgD/hwxBYfAThrxMsYV4NwLdQAv5AAgL3NNH/qpFZacDpGonJXH0jLE/M
+9r/rHI52nlkLQEfnwx5Abjq+xowzf9o1NiFUhYP8u4Fmie5EvnFnEn9S/X1aPNBU
+nH1C2jC3rLqca0qv4fj52w3iYRSwrg30saZA6/VFDXVNV7sCsdWDDQU6AYvonXf0
+mqWg61UrLBc0E0GtCW4vijVXotjpf517Au/9SIhdtDZ3cY+rfsU1sqw=
+-----END CERTIFICATE-----
diff --git a/etc/certs/TEST KLASS3 2010.crt b/etc/certs/TEST KLASS3 2010.crt
new file mode 100644
index 0000000..f3a1b6a
--- /dev/null
+++ b/etc/certs/TEST KLASS3 2010.crt
@@ -0,0 +1,28 @@
+-----BEGIN CERTIFICATE-----
+MIIExzCCA6+gAwIBAgIQIrzOHDuBOQRPabRVIaWqEzANBgkqhkiG9w0BAQUFADB9
+MQswCQYDVQQGEwJFRTEiMCAGA1UECgwZQVMgU2VydGlmaXRzZWVyaW1pc2tlc2t1
+czEwMC4GA1UEAwwnVEVTVCBvZiBFRSBDZXJ0aWZpY2F0aW9uIENlbnRyZSBSb290
+IENBMRgwFgYJKoZIhvcNAQkBFglwa2lAc2suZWUwHhcNMTIwMzIxMTA1ODI5WhcN
+MjUwMzIxMTA1ODI5WjB1MQswCQYDVQQGEwJFRTEiMCAGA1UECgwZQVMgU2VydGlm
+aXRzZWVyaW1pc2tlc2t1czEhMB8GA1UECwwYU2VydGlmaXRzZWVyaW1pc3RlZW51
+c2VkMR8wHQYDVQQDDBZURVNUIG9mIEtMQVNTMy1TSyAyMDEwMIIBIjANBgkqhkiG
+9w0BAQEFAAOCAQ8AMIIBCgKCAQEA7Ua/6IAAqXvy2COvRLW9yCSeImQ23XRAzf/x
+HmJ6fYiSs0LaR8c19IOSOkOarAgUrt0XDG5KWBdE5qwuVc0gQN9ZjYwmDg3dq4LV
+o89FdvATKk2Tao01Iu1N+2eGSEifgGBH5iWfYqu1hGJ2nJPHIG9bKXZXfw+ET2gy
+mO5bHnt8iOJmq+YynMXEvxtUTl2hKh0o6m28i3YKXru0jm5qe5/YCJ9HFw9yKn8e
+LnI2/9Jfruxe5F1AMOkVXhVtA57yeQARv18a8uEQZV0CS/WDmCPi+hl6GqSwhWZB
+dB9igOMsnZdNS1s7kr2/46doZQVPa2X3vJyYMTl/oaWB++VfAQIDAQABo4IBSTCC
+AUUwEgYDVR0TAQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAcYwgZkGA1UdIASB
+kTCBjjCBiwYKKwYBBAHOHwMBATB9MCEGCCsGAQUFBwIBFhVodHRwczovL3d3dy5z
+ay5lZS9jcHMwWAYIKwYBBQUHAgIwTB5KAEEAaQBuAHUAbAB0ACAAdABlAHMAdABp
+AG0AaQBzAGUAawBzAC4AIABPAG4AbAB5ACAAZgBvAHIAIAB0AGUAcwB0AGkAbgBn
+AC4wHQYDVR0OBBYEFNFoQ5JN1Wc5Ii9tzYgGEg662Wp2MB8GA1UdIwQYMBaAFLU0
+Cp2lLxDF5yEOvsSxZUcbA3b+MEMGA1UdHwQ8MDowOKA2oDSGMmh0dHBzOi8vd3d3
+LnNrLmVlL3JlcG9zaXRvcnkvY3Jscy90ZXN0X2VlY2NyY2EuY3JsMA0GCSqGSIb3
+DQEBBQUAA4IBAQCiE8G8gwZpeeHm0PoqHd54/KbfH2cAklqO5rcg2m9fhhvPNtMQ
+9Wc19JWauE2YuNsnJNKetglUAnA/yd64DhQKBf+2JUgYJas4dTscRgXXlz8huuve
+nNUpfPd3iispVc2WNBQ2qjBEZXdqhbkG0/RgM42Hb28+1v23HsoLhCGY2YjHhYyn
+mOk/8BULI/ArsgA7FJflXi5Xp/cdC8BJQ87vtPlAnxm0axZMvASNXMUvvQTUjCTg
+0yczX3d8+I3EBNBlzfPMsyU1LCn6Opbs2/DGF/4enhRGk/49L6ltfOyOA73buSog
+S2JkvCweSx6Y2cs1fXVyFszm2HJmQgwbZYfR
+-----END CERTIFICATE-----
diff --git a/etc/certs/TEST SK OCSP 2011.crt b/etc/certs/TEST SK OCSP 2011.crt
new file mode 100644
index 0000000..d9b6863
--- /dev/null
+++ b/etc/certs/TEST SK OCSP 2011.crt
@@ -0,0 +1,27 @@
+-----BEGIN CERTIFICATE-----
+MIIEijCCA3KgAwIBAgIQaI8x6BnacYdNdNwlYnn/mzANBgkqhkiG9w0BAQUFADB9
+MQswCQYDVQQGEwJFRTEiMCAGA1UECgwZQVMgU2VydGlmaXRzZWVyaW1pc2tlc2t1
+czEwMC4GA1UEAwwnVEVTVCBvZiBFRSBDZXJ0aWZpY2F0aW9uIENlbnRyZSBSb290
+IENBMRgwFgYJKoZIhvcNAQkBFglwa2lAc2suZWUwHhcNMTEwMzA3MTMyMjQ1WhcN
+MjQwOTA3MTIyMjQ1WjCBgzELMAkGA1UEBhMCRUUxIjAgBgNVBAoMGUFTIFNlcnRp
+Zml0c2VlcmltaXNrZXNrdXMxDTALBgNVBAsMBE9DU1AxJzAlBgNVBAMMHlRFU1Qg
+b2YgU0sgT0NTUCBSRVNQT05ERVIgMjAxMTEYMBYGCSqGSIb3DQEJARYJcGtpQHNr
+LmVlMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0cw6Cja17BbYbHi6
+frwccDI4BIQLk/fiCE8L45os0xhPgEGR+EHE8LPCIqofPgf4gwN1vDE6cQNUlK0O
+d+Ush39i9Z45esnfpGq+2HsDJaFmFr5+uC1MEz5Kn1TazEvKbRjkGnSQ9BertlGe
+r2BlU/kqOk5qA5RtJfhT0psc1ixKdPipv59wnf+nHx1+T+fPWndXVZLoDg4t3w8l
+IvIE/KhOSMlErvBIHIAKV7yH1hOxyeGLghqzMiAn3UeTEOgoOS9URv0C/T5C3mH+
+Y/uakMSxjNuz41PneimCzbEJZJRiEaMIj8qPAubcbL8GtY03MWmfNtX6/wh6u6TM
+fW8S2wIDAQABo4H+MIH7MBYGA1UdJQEB/wQMMAoGCCsGAQUFBwMJMB0GA1UdDgQW
+BBR9/5CuRokEgGiqSzYuZGYAogl8TzCBoAYDVR0gBIGYMIGVMIGSBgorBgEEAc4f
+AwEBMIGDMFgGCCsGAQUFBwICMEweSgBBAGkAbgB1AGwAdAAgAHQAZQBzAHQAaQBt
+AGkAcwBlAGsAcwAuACAATwBuAGwAeQAgAGYAbwByACAAdABlAHMAdABpAG4AZwAu
+MCcGCCsGAQUFBwIBFhtodHRwOi8vd3d3LnNrLmVlL2FqYXRlbXBlbC8wHwYDVR0j
+BBgwFoAUtTQKnaUvEMXnIQ6+xLFlRxsDdv4wDQYJKoZIhvcNAQEFBQADggEBAAba
+j7kTruTAPHqToye9ZtBdaJ3FZjiKug9/5RjsMwDpOeqFDqCorLd+DBI4tgdu0g4l
+haI3aVnKdRBkGV18kqp84uU97JRFWQEf6H8hpJ9k/LzAACkP3tD+0ym+md532mV+
+nRz1Jj+RPLAUk9xYMV7KPczZN1xnl2wZDJwBbQpcSVH1DjlZv3tFLHBLIYTS6qOK
+4SxStcgRq7KdRczfW6mfXzTCRWM3G9nmDei5Q3+XTED41j8szRWglzYf6zOv4djk
+ja64WYraQ5zb4x8Xh7qTCk6UupZ7je+0oRfuz0h/3zyRdjcRPkjloSpQp/NG8Rmr
+cnr874p8d9fdwCrRI7U=
+-----END CERTIFICATE-----
diff --git a/etc/certs/TEST-SK OCSP 2005.crt b/etc/certs/TEST-SK OCSP 2005.crt
new file mode 100644
index 0000000..3c8aac7
--- /dev/null
+++ b/etc/certs/TEST-SK OCSP 2005.crt
@@ -0,0 +1,17 @@
+-----BEGIN CERTIFICATE-----
+MIIDKDCCAhCgAwIBAgIEQi1s4zANBgkqhkiG9w0BAQUFADBfMQswCQYDVQQGEwJFRTEiMCAGA1UE
+ChMZQVMgU2VydGlmaXRzZWVyaW1pc2tlc2t1czEaMBgGA1UECxMRVGVzdHNlcnRpZmlrYWFkaWQx
+EDAOBgNVBAMTB1RFU1QtU0swHhcNMDUwMzA4MDkxNDEwWhcNMTIwNDA2MjEwMDAwWjB4MQswCQYD
+VQQGEwJFRTEaMBgGA1UECgwRVGVzdHNlcnRpZmlrYWFkaWQxDTALBgNVBAsMBE9DU1AxJDAiBgNV
+BAMMG1RFU1QtU0sgT0NTUCBSRVNQT05ERVIgMjAwNTEYMBYGCSqGSIb3DQEJARYJcGtpQHNrLmVl
+MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC2RdrY11V9ekC7Injanf4RshjWp6jf51tGOvzE
+cbG2Tmyo66H7AR6hauoUygIYrbEjAVXhIznnffngJtrG69I+6cGgCNHguPlpdyAwexUPi36cfJw2
+FKv9bbxyIqtxo+1uZ1XZWgcua6OXMLh0T0aZWglJ1OiAlZys6hxbOg1G8wIDAQABo1cwVTATBgNV
+HSUEDDAKBggrBgEFBQcDCTAfBgNVHSMEGDAWgBQCBSfdqHKHt4LAWzkqf+M48vpSCTAdBgNVHQ4E
+FgQUK9Rcl4ROS8UmFo8JH8ep5oRSJFgwDQYJKoZIhvcNAQEFBQADggEBAHZd/Bqzc7FsC05Hq8Zh
+PxK4lJVMwuC+mO843jsX8cWaGMBOYWqD96gFduMjiIXVIWFpiZ1o6q+JuRbPTRhpzRvv0Yc9oMaq
+j7sBhYr8mqcu0FOOMD8wlJzqFr9TZZ58ba9e/UDZPDUYvEfWEuW6giwSkPLuu0Jbz94QqmG0ErG8
+8h6B14Nge7P1pR4hZfvm4I2PX8sX619OdHRf7kxS+ZXve5BHGHX5YXSPreRAvriJc/cgRFokcPyt
+v7y+tebcqB+1/Dj7o2brNr+dKxIL5IseBeQD4lJ5UtvuPE7pZexUSt2EOcDAAMtHsUB30cIVwPw8
+/CwfT9FBP9H3tUUCtOQ=
+-----END CERTIFICATE-----
diff --git a/etc/certs/TEST-SK.crt b/etc/certs/TEST-SK.crt
new file mode 100644
index 0000000..fbbbaaa
--- /dev/null
+++ b/etc/certs/TEST-SK.crt
@@ -0,0 +1,21 @@
+-----BEGIN CERTIFICATE-----
+MIIECTCCAvGgAwIBAgIEPLKVuDANBgkqhkiG9w0BAQUFADBiMRgwFgYJKoZIhvcNAQkBFglwa2lA
+c2suZWUxCzAJBgNVBAYTAkVFMSIwIAYDVQQKExlBUyBTZXJ0aWZpdHNlZXJpbWlza2Vza3VzMRUw
+EwYDVQQDEwxURVNUIEp1dXItU0swHhcNMDIwNDA5MDcxODE2WhcNMTYwODI2MDYxODE2WjBfMQsw
+CQYDVQQGEwJFRTEiMCAGA1UEChMZQVMgU2VydGlmaXRzZWVyaW1pc2tlc2t1czEaMBgGA1UECxMR
+VGVzdHNlcnRpZmlrYWFkaWQxEDAOBgNVBAMTB1RFU1QtU0swggEiMA0GCSqGSIb3DQEBAQUAA4IB
+DwAwggEKAoIBAQCpEFGWIT863MTfk2NoRURZiP40ASAEcyq5ColRFkK08mdJ7uauO3nr9v8ac11/
+LCJPrFXb75kVt7vXRsR+1wM2jYKIWeuwUB84ByfPOGqJMs2nX+mJt+FbKIpTIS1PKL1RWKw1lOzK
+dt6/aTdvMbNo4IPHMv0Kr/yYaOym5+hfYBgh9tLQ1njgObJTLRuFSc7KE3oHOKsB0DxReLMtDvFy
+MLM2Mbt7Kf8SIxWJYjzVc2TxA2fhlnDlfypZmfJaaXc6vjfCbVbUiEML+AVaVbBFABmIzTfqs5WL
+KV5orvLZcvZr+NxAdTLK+MactUEnYNd6+x+k8TP19dIHytcFiENFAgMBAAGjgckwgcYwDwYDVR0T
+AQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAf4wJQYIKwYBBQUHAQEEGTAXMBUGCCsGAQUFBzACgQlw
+a2lAc2suZWUwPAYDVR0fBDUwMzAxoC+gLYYraHR0cDovL3d3dy5zay5lZS9jcmxzL3Rlc3QvdGVz
+dC1qdXVyLXNrLmNybDAfBgNVHSMEGDAWgBSBwuAMBRryEG40E0wsjD7ciCkyeDAdBgNVHQ4EFgQU
+AgUn3ahyh7eCwFs5Kn/jOPL6UgkwDQYJKoZIhvcNAQEFBQADggEBALk6ALjx0wJpvFdtCadHxYx2
+11YcThJqtywxfIl9yXVCDfu8JzrLnVowJJj+gBIkBrz7QyOYpxqnRRxRXSP3SXCdOCnNLRuX9nvT
+yJsMqhSql8Zw1roB8xYb133ztLAqVRoyo4e/c1VUZCVsXmmh5HGUepDU7QKQWQYKbq3tjrKvwXMZ
+QbXbp0L4eiuIbRzN00EOfnrIxBvsHfqZyc2gYqSHfM9YldlboGqNFGO5NQo2wOZ7jByi2aLaRkkN
+1Sx2EJX4Mudpb9RD08txailOBAcjl1j37ey1tU2AnGiyeYYPkXG88K6+L05ggIstR6kBU94wat8L
+qk3z5V5ScVGXOiw=
+-----END CERTIFICATE-----
diff --git a/etc/digidoc.conf.cmake b/etc/digidoc.conf.cmake
new file mode 100644
index 0000000..b2076a9
--- /dev/null
+++ b/etc/digidoc.conf.cmake
@@ -0,0 +1,172 @@
+#--------------------------------------------------
+# @DIGIDOC_CONF_NAME@
+# DigiDoc library global configuration file
+#--------------------------------------------------
+
+[ca]
+CA_CERT_PATH=@CMAKE_INSTALL_FULL_DATADIR@/libdigidoc
+CA_CERTS=17
+
+CA_CERT_1=JUUR-SK.crt
+CA_CERT_1_CN=Juur-SK
+CA_CERT_2=ESTEID-SK.crt
+CA_CERT_2_CN=ESTEID-SK
+CA_CERT_3=ESTEID-SK 2007.crt
+CA_CERT_3_CN=ESTEID-SK 2007
+CA_CERT_4=KLASS3-SK.crt
+CA_CERT_4_CN=KLASS3-SK
+CA_CERT_5=KLASS3-SK 2010.crt
+CA_CERT_5_CN=KLASS3-SK 2010
+CA_CERT_6=KLASS3-SK 2010 EECCRCA.crt
+CA_CERT_6_CN=KLASS3-SK 2010
+CA_CERT_7=EID-SK.crt
+CA_CERT_7_CN=EID-SK
+CA_CERT_8=EID-SK 2007.crt
+CA_CERT_8_CN=EID-SK 2007
+
+CA_CERT_9=EECCRCA.crt
+CA_CERT_9_CN=EE Certification Centre Root CA
+CA_CERT_10=ESTEID-SK 2011.crt
+CA_CERT_10_CN=ESTEID-SK 2011
+CA_CERT_11=EID-SK 2011.crt
+CA_CERT_11_CN=EID-SK 2011
+
+CA_CERT_12=TEST Juur-SK.crt
+CA_CERT_12_CN=TEST Juur-SK
+CA_CERT_13=TEST-SK.crt
+CA_CERT_13_CN=TEST-SK
+
+CA_CERT_14=TEST EECCRCA.crt
+CA_CERT_14_CN=TEST of EE Certification Centre Root CA
+CA_CERT_15=TEST ESTEID-SK 2011.crt
+CA_CERT_15_CN=TEST of ESTEID-SK 2011
+CA_CERT_16=TEST EID-SK 2011.crt
+CA_CERT_16_CN=TEST of EID-SK 2011
+CA_CERT_17=TEST KLASS3 2010.crt
+CA_CERT_17_CN=TEST of KLASS3-SK 2010
+
+
+
+
+DIGIDOC_DEFAULT_DRIVER=1
+DIGIDOC_DRIVERS=1
+DIGIDOC_DRIVER_1_NAME=OpenSC
+DIGIDOC_DRIVER_1_DESC=OpenSC projects PKCS#11 driver
+DIGIDOC_DRIVER_1_FILE=@PKCS11_MODULE@
+DIGIDOC_SIGNATURE_SLOT=1
+CHECK_OCSP_NONCE=0
+
+SIGN_OCSP=0
+USE_PROXY=0
+DIGIDOC_OCSP_URL=http://ocsp.sk.ee
+
+DIGIDOC_OCSP_RESPONDER_CERTS=24
+
+DIGIDOC_OCSP_RESPONDER_CERT_1=TEST-SK OCSP 2005.crt
+DIGIDOC_OCSP_RESPONDER_CERT_1_CN=TEST-SK OCSP RESPONDER 2005
+DIGIDOC_OCSP_RESPONDER_CERT_1_CA=TEST-SK
+DIGIDOC_OCSP_RESPONDER_CERT_1_URL=http://www.openxades.org/cgi-bin/ocsp.cgi
+
+DIGIDOC_OCSP_RESPONDER_CERT_2=KLASS3-SK OCSP 2009.crt
+DIGIDOC_OCSP_RESPONDER_CERT_2_CN=KLASS3-SK OCSP RESPONDER 2009
+DIGIDOC_OCSP_RESPONDER_CERT_2_CA=KLASS3-SK
+
+DIGIDOC_OCSP_RESPONDER_CERT_3=ESTEID-SK OCSP 2005.crt
+DIGIDOC_OCSP_RESPONDER_CERT_3_CN=ESTEID-SK OCSP RESPONDER 2005
+DIGIDOC_OCSP_RESPONDER_CERT_3_CA=ESTEID-SK
+
+DIGIDOC_OCSP_RESPONDER_CERT_4=ESTEID-SK 2007 OCSP.crt
+DIGIDOC_OCSP_RESPONDER_CERT_4_CN=ESTEID-SK 2007 OCSP RESPONDER
+DIGIDOC_OCSP_RESPONDER_CERT_4_CA=ESTEID-SK 2007
+
+DIGIDOC_OCSP_RESPONDER_CERT_5=EID-SK 2007 OCSP.crt
+DIGIDOC_OCSP_RESPONDER_CERT_5_CN=EID-SK 2007 OCSP RESPONDER
+DIGIDOC_OCSP_RESPONDER_CERT_5_CA=EID-SK 2007
+
+DIGIDOC_OCSP_RESPONDER_CERT_6=EID-SK OCSP 2006.crt
+DIGIDOC_OCSP_RESPONDER_CERT_6_1=EID-SK OCSP.crt
+DIGIDOC_OCSP_RESPONDER_CERT_6_CN=EID-SK OCSP RESPONDER
+DIGIDOC_OCSP_RESPONDER_CERT_6_CA=EID-SK
+
+DIGIDOC_OCSP_RESPONDER_CERT_7=ESTEID-SK OCSP.crt
+DIGIDOC_OCSP_RESPONDER_CERT_7_CN=ESTEID-SK OCSP RESPONDER
+DIGIDOC_OCSP_RESPONDER_CERT_7_CA=ESTEID-SK
+
+DIGIDOC_OCSP_RESPONDER_CERT_8=KLASS3-SK OCSP 2006.crt
+DIGIDOC_OCSP_RESPONDER_CERT_8_1=KLASS3-SK OCSP.crt
+DIGIDOC_OCSP_RESPONDER_CERT_8_CN=KLASS3-SK OCSP RESPONDER
+DIGIDOC_OCSP_RESPONDER_CERT_8_CA=KLASS3-SK
+
+DIGIDOC_OCSP_RESPONDER_CERT_9=EID-SK 2007 OCSP 2010.crt
+DIGIDOC_OCSP_RESPONDER_CERT_9_CN=EID-SK 2007 OCSP RESPONDER 2010
+DIGIDOC_OCSP_RESPONDER_CERT_9_CA=EID-SK 2007
+
+DIGIDOC_OCSP_RESPONDER_CERT_10=ESTEID-SK 2007 OCSP 2010.crt
+DIGIDOC_OCSP_RESPONDER_CERT_10_CN=ESTEID-SK 2007 OCSP RESPONDER 2010
+DIGIDOC_OCSP_RESPONDER_CERT_10_CA=ESTEID-SK 2007
+
+DIGIDOC_OCSP_RESPONDER_CERT_11=KLASS3-SK 2010 OCSP.crt
+DIGIDOC_OCSP_RESPONDER_CERT_11_CN=KLASS3-SK 2010 OCSP RESPONDER
+DIGIDOC_OCSP_RESPONDER_CERT_11_CA=KLASS3-SK 2010
+
+DIGIDOC_OCSP_RESPONDER_CERT_12=SK OCSP 2011.crt
+DIGIDOC_OCSP_RESPONDER_CERT_12_CN=SK OCSP RESPONDER 2011
+DIGIDOC_OCSP_RESPONDER_CERT_12_CA=EE Certification Centre Root CA
+
+DIGIDOC_OCSP_RESPONDER_CERT_13=SK OCSP 2011.crt
+DIGIDOC_OCSP_RESPONDER_CERT_13_CN=SK OCSP RESPONDER 2011
+DIGIDOC_OCSP_RESPONDER_CERT_13_CA=ESTEID-SK 2011
+
+DIGIDOC_OCSP_RESPONDER_CERT_14=SK OCSP 2011.crt
+DIGIDOC_OCSP_RESPONDER_CERT_14_CN=SK OCSP RESPONDER 2011
+DIGIDOC_OCSP_RESPONDER_CERT_14_CA=EID-SK 2011
+
+DIGIDOC_OCSP_RESPONDER_CERT_15=TEST SK OCSP 2011.crt
+DIGIDOC_OCSP_RESPONDER_CERT_15_CN=TEST of SK OCSP RESPONDER 2011
+DIGIDOC_OCSP_RESPONDER_CERT_15_CA=TEST of EE Certification Centre Root CA
+DIGIDOC_OCSP_RESPONDER_CERT_15_URL=http://www.openxades.org/cgi-bin/ocsp.cgi
+
+DIGIDOC_OCSP_RESPONDER_CERT_16=TEST SK OCSP 2011.crt
+DIGIDOC_OCSP_RESPONDER_CERT_16_CN=TEST of SK OCSP RESPONDER 2011
+DIGIDOC_OCSP_RESPONDER_CERT_16_CA=TEST of ESTEID-SK 2011
+DIGIDOC_OCSP_RESPONDER_CERT_16_URL=http://www.openxades.org/cgi-bin/ocsp.cgi
+
+DIGIDOC_OCSP_RESPONDER_CERT_17=TEST SK OCSP 2011.crt
+DIGIDOC_OCSP_RESPONDER_CERT_17_CN=TEST of SK OCSP RESPONDER 2011
+DIGIDOC_OCSP_RESPONDER_CERT_17_CA=TEST of EID-SK 2011
+DIGIDOC_OCSP_RESPONDER_CERT_17_URL=http://www.openxades.org/cgi-bin/ocsp.cgi
+
+DIGIDOC_OCSP_RESPONDER_CERT_18=TEST SK OCSP 2011.crt
+DIGIDOC_OCSP_RESPONDER_CERT_18_CN=TEST of SK OCSP RESPONDER 2011
+DIGIDOC_OCSP_RESPONDER_CERT_18_CA=TEST of KLASS3-SK 2010
+DIGIDOC_OCSP_RESPONDER_CERT_18_URL=http://www.openxades.org/cgi-bin/ocsp.cgi
+
+DIGIDOC_OCSP_RESPONDER_CERT_19=TEST SK OCSP 2011.crt
+DIGIDOC_OCSP_RESPONDER_CERT_19_CN=TEST of SK OCSP RESPONDER 2011
+DIGIDOC_OCSP_RESPONDER_CERT_19_CA=VRK CA for Test Purposes
+DIGIDOC_OCSP_RESPONDER_CERT_19_URL=http://www.openxades.org/cgi-bin/ocsp.cgi
+
+DIGIDOC_OCSP_RESPONDER_CERT_20=TEST SK OCSP 2011.crt
+DIGIDOC_OCSP_RESPONDER_CERT_20_CN=TEST of SK OCSP RESPONDER 2011
+DIGIDOC_OCSP_RESPONDER_CERT_20_CA=VRK TEST Root CA
+DIGIDOC_OCSP_RESPONDER_CERT_20_URL=http://www.openxades.org/cgi-bin/ocsp.cgi
+
+DIGIDOC_OCSP_RESPONDER_CERT_21=SK OCSP 2011.crt
+DIGIDOC_OCSP_RESPONDER_CERT_21_CN=SK OCSP RESPONDER 2011
+DIGIDOC_OCSP_RESPONDER_CERT_21_CA=VRK Gov. Root CA
+DIGIDOC_OCSP_RESPONDER_CERT_21_URL=http://ocsp.sk.ee/_proxy
+
+DIGIDOC_OCSP_RESPONDER_CERT_22=SK OCSP 2011.crt
+DIGIDOC_OCSP_RESPONDER_CERT_22_CN=SK OCSP RESPONDER 2011
+DIGIDOC_OCSP_RESPONDER_CERT_22_CA=VRK Gov. CA for Citizen Qualified Certificates
+DIGIDOC_OCSP_RESPONDER_CERT_22_URL=http://ocsp.sk.ee/_proxy
+
+DIGIDOC_OCSP_RESPONDER_CERT_23=SK OCSP 2011.crt
+DIGIDOC_OCSP_RESPONDER_CERT_23_CN=SK OCSP RESPONDER 2011
+DIGIDOC_OCSP_RESPONDER_CERT_23_CA=VRK CA for Healthcare Professionals Qualified Certificates
+DIGIDOC_OCSP_RESPONDER_CERT_23_URL=http://ocsp.sk.ee/_proxy
+
+DIGIDOC_OCSP_RESPONDER_CERT_24=SK OCSP 2011.crt
+DIGIDOC_OCSP_RESPONDER_CERT_24_CN=SK OCSP RESPONDER 2011
+DIGIDOC_OCSP_RESPONDER_CERT_24_CA=VRK CA for Qualified Certificates
+DIGIDOC_OCSP_RESPONDER_CERT_24_URL=http://ocsp.sk.ee/_proxy
diff --git a/libdigidoc.spec b/libdigidoc.spec
new file mode 100644
index 0000000..6bc0874
--- /dev/null
+++ b/libdigidoc.spec
@@ -0,0 +1,69 @@
+Name: libdigidoc
+Version: 3.3
+Release: 1%{?dist}
+Summary: DigiDoc library
+Group: System Environment/Libraries
+License: LGPLv2+
+URL: http://www.ria.ee
+Source0: libdigidoc.tar.gz
+BuildRoot: %{_tmppath}/-%{version}-%{release}-root-%(%{__id_u} -n)
+BuildRequires: cmake, gcc, libxml2-devel, openssl-devel
+Requires: opensc, esteidcerts
+%if %{defined suse_version}
+Requires: libpcsclite1
+%endif
+%description
+Library for creating DigiDoc signature files
+
+%if %{defined suse_version}
+%debug_package
+%endif
+
+%package devel
+Summary: DigiDoc library devel files
+Group: System Environment/Libraries
+Requires: %{name}%{?_isa} = %{version}-%{release}, libxml2-devel, esteidcerts-devel
+%description devel
+Devel files for DigiDoc library
+
+
+%prep
+%setup -q -n %{name}
+cmake . \
+ -DCMAKE_BUILD_TYPE=RelWithDebInfo \
+ -DCMAKE_INSTALL_PREFIX=/usr \
+ -DCMAKE_INSTALL_SYSCONFDIR=/etc \
+ -DCMAKE_VERBOSE_MAKEFILE=ON
+
+%build
+make
+
+%install
+rm -rf %{buildroot}
+cd %{_builddir}/%{name}
+make install DESTDIR=%{buildroot}
+
+%clean
+rm -rf %{buildroot}
+cd %{_builddir}/%{name}
+make clean
+
+%files
+%defattr(-,root,root,-)
+%{_bindir}/*
+%{_libdir}/*.so.*
+%{_mandir}
+%config(noreplace) %{_sysconfdir}/*
+
+%files devel
+%defattr(-,root,root,-)
+%{_includedir}/*
+%{_libdir}/*.so
+%{_libdir}/pkgconfig/*
+
+%changelog
+* Fri Aug 13 2010 RIA <info@ria.ee> 1.0-1
+- first build no changes
+
+%post -p /sbin/ldconfig
+%postun -p /sbin/ldconfig
diff --git a/libdigidoc.wxs b/libdigidoc.wxs
new file mode 100644
index 0000000..9c35308
--- /dev/null
+++ b/libdigidoc.wxs
@@ -0,0 +1,111 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<?ifdef env.VS120COMNTOOLS ?>
+<?define MergeModules="C:\Program Files (x86)\Common Files\Merge Modules\Microsoft_VC120" ?>
+<?else?>
+<?define MergeModules="C:\Program Files (x86)\Common Files\Merge Modules\Microsoft_VC110" ?>
+<?endif?>
+
+<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi" xmlns:util="http://schemas.microsoft.com/wix/UtilExtension">
+ <Product Name="Estonian ID Card C-library for developers" Id="*" UpgradeCode="{3EA5EA77-4660-4306-A8A2-7A56423E4EA6}"
+ Language="1033" Version="$(var.MSI_VERSION)" Codepage="1251" Manufacturer="RIA">
+ <Package Keywords="Installer" InstallerVersion="405" Compressed="yes"/>
+ <MediaTemplate EmbedCab="yes" CompressionLevel="high"/>
+
+ <Icon Id="IDIcon" SourceFile="ID.ico"/>
+ <Property Id="ARPPRODUCTICON" Value="Company.ico"/>
+ <Property Id="REINSTALLMODE" Value="amus"/>
+
+ <MajorUpgrade AllowSameVersionUpgrades="yes" DowngradeErrorMessage=
+ "A newer version of [ProductName] is already installed. If you are trying to downgrade, please uninstall the newer version first."/>
+
+ <Directory Id="TARGETDIR" Name="SourceDir">
+ <Merge Id='CRT' Language='0' SourceFile='$(var.MergeModules)_CRT_x86.msm' DiskId='1'/>
+ <Directory Id='ProgramFilesFolder'>
+ <Directory Id="DEVPACKAGESFOLDER" Name="Estonian ID Card Development">
+ <Directory Id="APPLICATIONFOLDER" Name="libdigidoc">
+ <Component Id="libdigidoc" Guid="fbc4572c-6256-4df7-a42d-b9c996e69092">
+ <File Source="C:/OpenSSL-Win32/bin/libeay32.dll"/>
+ <File Source="C:/OpenSSL-Win32/bin/ssleay32.dll"/>
+ <File Source="$(var.PREFIX)/zlib/x86/bin/zlib1.dll"/>
+ <File Source="$(var.PREFIX)/libxml2/x86/bin/libxml2.dll"/>
+ <File Source="$(var.libdigidoc)/x86/bin/digidoc.dll"/>
+ <File Source="$(var.libdigidoc)/x86/bin/digidoc.lib"/>
+ <File Source="$(var.libdigidoc)/x86/bin/cdigidoc.exe"/>
+ <File Source="$(var.libdigidoc)/x86/etc/digidoc.ini"/>
+ <IniFile Id="setCaCertPathX86" Action="addLine" Directory="APPLICATIONFOLDER" Section="ca"
+ Name="digidoc.ini" Key="CA_CERT_PATH" Value="[APPLICATIONFOLDER]certs"/>
+ <File Source="$(var.libdigidoc)/x86/bin/cdigidoc.pdb"/>
+ <File Source="$(var.libdigidoc)/x86/bin/digidoc.pdb"/>
+ </Component>
+ <Directory Id="CertificatesFolder" Name="certs"/>
+ <Directory Id="DocumentationFolder" Name="documentation"/>
+ <Directory Id="SourceFolder" Name="source"/>
+ <Directory Id="HeadersFolder" Name="."/>
+ </Directory>
+ </Directory>
+ </Directory>
+ </Directory>
+
+ <Property Id="WIXUI_INSTALLDIR" Value="APPLICATIONFOLDER" />
+ <UI Id="WixUI_InstallDir">
+ <TextStyle Id="WixUI_Font_Normal" FaceName="Tahoma" Size="8" />
+ <TextStyle Id="WixUI_Font_Bigger" FaceName="Tahoma" Size="12" />
+ <TextStyle Id="WixUI_Font_Title" FaceName="Tahoma" Size="9" Bold="yes" />
+
+ <Property Id="DefaultUIFont" Value="WixUI_Font_Normal" />
+ <Property Id="WixUI_Mode" Value="InstallDir" />
+
+ <DialogRef Id="BrowseDlg" />
+ <DialogRef Id="DiskCostDlg" />
+ <DialogRef Id="ErrorDlg" />
+ <DialogRef Id="FatalError" />
+ <DialogRef Id="FilesInUse" />
+ <DialogRef Id="MsiRMFilesInUse" />
+ <DialogRef Id="PrepareDlg" />
+ <DialogRef Id="ProgressDlg" />
+ <DialogRef Id="ResumeDlg" />
+ <DialogRef Id="UserExit" />
+
+ <Publish Dialog="BrowseDlg" Control="OK" Event="DoAction" Value="WixUIValidatePath" Order="3">1</Publish>
+ <Publish Dialog="BrowseDlg" Control="OK" Event="SpawnDialog" Value="InvalidDirDlg" Order="4"><![CDATA[WIXUI_INSTALLDIR_VALID<>"1"]]></Publish>
+
+ <Publish Dialog="ExitDialog" Control="Finish" Event="EndDialog" Value="Return" Order="999">1</Publish>
+
+ <Publish Dialog="WelcomeDlg" Control="Next" Event="NewDialog" Value="InstallDirDlg">NOT Installed</Publish>
+ <Publish Dialog="WelcomeDlg" Control="Next" Event="NewDialog" Value="VerifyReadyDlg">Installed AND PATCH</Publish>
+
+ <Publish Dialog="InstallDirDlg" Control="Back" Event="NewDialog" Value="WelcomeDlg">1</Publish>
+ <Publish Dialog="InstallDirDlg" Control="Next" Event="SetTargetPath" Value="[WIXUI_INSTALLDIR]" Order="1">1</Publish>
+ <Publish Dialog="InstallDirDlg" Control="Next" Event="DoAction" Value="WixUIValidatePath" Order="2">NOT WIXUI_DONTVALIDATEPATH</Publish>
+ <Publish Dialog="InstallDirDlg" Control="Next" Event="SpawnDialog" Value="InvalidDirDlg" Order="3"><![CDATA[NOT WIXUI_DONTVALIDATEPATH AND WIXUI_INSTALLDIR_VALID<>"1"]]></Publish>
+ <Publish Dialog="InstallDirDlg" Control="Next" Event="NewDialog" Value="VerifyReadyDlg" Order="4">WIXUI_DONTVALIDATEPATH OR WIXUI_INSTALLDIR_VALID="1"</Publish>
+ <Publish Dialog="InstallDirDlg" Control="ChangeFolder" Property="_BrowseProperty" Value="[WIXUI_INSTALLDIR]" Order="1">1</Publish>
+ <Publish Dialog="InstallDirDlg" Control="ChangeFolder" Event="SpawnDialog" Value="BrowseDlg" Order="2">1</Publish>
+
+ <Publish Dialog="VerifyReadyDlg" Control="Back" Event="NewDialog" Value="InstallDirDlg" Order="1">NOT Installed</Publish>
+ <Publish Dialog="VerifyReadyDlg" Control="Back" Event="NewDialog" Value="MaintenanceTypeDlg" Order="2">Installed AND NOT PATCH</Publish>
+ <Publish Dialog="VerifyReadyDlg" Control="Back" Event="NewDialog" Value="WelcomeDlg" Order="2">Installed AND PATCH</Publish>
+
+ <Publish Dialog="MaintenanceWelcomeDlg" Control="Next" Event="NewDialog" Value="MaintenanceTypeDlg">1</Publish>
+
+ <Publish Dialog="MaintenanceTypeDlg" Control="RepairButton" Event="NewDialog" Value="VerifyReadyDlg">1</Publish>
+ <Publish Dialog="MaintenanceTypeDlg" Control="RemoveButton" Event="NewDialog" Value="VerifyReadyDlg">1</Publish>
+ <Publish Dialog="MaintenanceTypeDlg" Control="Back" Event="NewDialog" Value="MaintenanceWelcomeDlg">1</Publish>
+
+ <Property Id="ARPNOMODIFY" Value="1" />
+ </UI>
+
+ <UIRef Id="WixUI_Common" />
+
+ <Feature Id="InstallLibdigidoc" Level="1" Title="C-teek">
+ <MergeRef Id="CRT"/>
+ <ComponentRef Id="libdigidoc"/>
+ <ComponentGroupRef Id="Certs"/>
+ <ComponentGroupRef Id="Source"/>
+ <ComponentGroupRef Id="Headers"/>
+ <ComponentGroupRef Id="Documentation"/>
+ </Feature>
+
+ </Product>
+</Wix>
diff --git a/libdigidoc/CMakeLists.txt b/libdigidoc/CMakeLists.txt
new file mode 100644
index 0000000..eceebfe
--- /dev/null
+++ b/libdigidoc/CMakeLists.txt
@@ -0,0 +1,153 @@
+configure_file(
+ ${CMAKE_SOURCE_DIR}/etc/digidoc.conf.cmake
+ ${CMAKE_CURRENT_BINARY_DIR}/${DIGIDOC_CONF_NAME}
+ @ONLY
+)
+FILE( GLOB CERTS ${CMAKE_SOURCE_DIR}/etc/certs/*.crt )
+
+set( PUBLIC_HEADER
+ DigiDocCert.h
+ DigiDocConfig.h
+ DigiDocConvert.h
+ DigiDocDebug.h
+ DigiDocDefs.h
+ DigiDocDfExtract.h
+ DigiDocEncGen.h
+ DigiDocEnc.h
+ DigiDocEncSAXParser.h
+ DigiDocError.h
+ DigiDocGen.h
+ DigiDocLib.h
+ DigiDocMem.h
+ DigiDocObj.h
+ DigiDocOCSP.h
+ DigiDocParser.h
+# DigiDocPKCS11.h
+ DigiDocSAXParser.h
+ DigiDocStack.h
+ DigiDocVerify.h
+ DigiDocHTTP.h
+ DigiDocService.h
+)
+
+if( WIN32 )
+ add_definitions( -DWITH_SOAPDEFS_H )
+ list( APPEND libdigidoc_SRCS DigiDocGlobals.c DigiDocCSP.c DigiCrypt.c DlgUnit.c DlgUnitS.c )
+ set( EXT_LIBRARIES Crypt32 Comctl32 )
+endif()
+
+if( MSVC )
+ add_definitions(
+ -D_CRT_NONSTDC_NO_DEPRECATE
+ -D_CRT_SECURE_NO_DEPRECATE
+ -D_CRT_SECURE_NO_WARNINGS
+ -D_SCL_SECURE_NO_WARNINGS
+ )
+endif()
+
+add_library( digidoc SHARED
+ ${PUBLIC_HEADER}
+ ${CMAKE_CURRENT_BINARY_DIR}/${DIGIDOC_CONF_NAME}
+ ${libdigidoc_SRCS}
+ ${CERTS}
+ libdigidoc.rc
+ DigiDocConfig.c
+ DigiDocLib.c
+ DigiDocObj.c
+ DigiDocPKCS11.c
+ DigiDocError.c
+ DigiDocParser.c
+ DigiDocDebug.c
+ DigiDocSAXParser.c
+ DigiDocMem.c
+ DigiDocStack.c
+ DigiDocEnc.c
+ DigiDocEncGen.c
+ DigiDocEncSAXParser.c
+ DigiDocCert.c
+ DigiDocConvert.c
+ DigiDocGen.c
+ DigiDocVerify.c
+ DigiDocOCSP.c
+ DigiDocDfExtract.c
+ DigiDocHTTP.c
+ DigiDocService.c
+)
+
+target_link_libraries( digidoc
+ ${CMAKE_DL_LIBS}
+ ${LIBXML2_LIBRARIES}
+ ${OPENSSL_LIBRARIES}
+ ${ZLIB_LIBRARIES}
+ ${EXT_LIBRARIES}
+)
+
+set_target_properties( digidoc PROPERTIES
+ VERSION ${MAJOR_VER}.${MINOR_VER}.${RELEASE_VER}
+ SOVERSION 2
+ PUBLIC_HEADER "${PUBLIC_HEADER}"
+ RESOURCE ${CMAKE_CURRENT_BINARY_DIR}/${DIGIDOC_CONF_NAME}
+ FRAMEWORK_VERSION 2
+ FRAMEWORK "${FRAMEWORK}"
+ MACOSX_FRAMEWORK_IDENTIFIER "ee.ria.libdigidoc"
+ MACOSX_RPATH YES
+)
+
+add_executable(cdigidoc cdigidoc.c cdigidoc.rc)
+target_link_libraries(cdigidoc digidoc)
+
+install( TARGETS digidoc
+ RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
+ LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
+ ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
+ RESOURCE DESTINATION ${CMAKE_INSTALL_SYSCONFDIR}
+ PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/libdigidoc
+ FRAMEWORK DESTINATION /Library/Frameworks
+)
+
+if(WIN32)
+ install( DIRECTORY ${PROJECT_BINARY_DIR}/libdigidoc/ DESTINATION ${CMAKE_INSTALL_LIBDIR} FILES_MATCHING PATTERN "*.pdb" )
+endif()
+
+if( FRAMEWORK )
+ set_target_properties( digidoc PROPERTIES
+ OUTPUT_NAME "libdigidoc"
+ COMPILE_DEFINITIONS "FRAMEWORK"
+ LINK_FLAGS "-framework CoreFoundation -framework Security"
+ RESOURCE "${CERTS};${CMAKE_CURRENT_BINARY_DIR}/${DIGIDOC_CONF_NAME}"
+ )
+ add_custom_command( TARGET cdigidoc POST_BUILD
+ COMMAND ${CMAKE_COMMAND} -E copy $<TARGET_FILE:cdigidoc> $<TARGET_FILE_DIR:digidoc>/Resources )
+ add_custom_target( codesign DEPENDS cdigidoc
+ COMMAND codesign -f -s \"$$SIGNCERT\" $<TARGET_FILE_DIR:digidoc>/Resources/cdigidoc
+ COMMAND codesign -f -s \"$$SIGNCERT\" $<TARGET_FILE_DIR:digidoc>/../..
+ COMMAND touch $<TARGET_FILE:cdigidoc>
+ )
+ add_custom_target( pkgbuild DEPENDS codesign
+ COMMAND make install DESTDIR=install \; pkgbuild
+ --root install
+ --sign \"$$INSTCERT\"
+ ${CMAKE_BINARY_DIR}/libdigidoc_${VERSION}$ENV{VER_SUFFIX}.pkg
+ )
+ add_custom_target( zipdebug DEPENDS cdigidoc
+ COMMAND dsymutil -o libdigidoc.dSYM $<TARGET_FILE:digidoc>
+ COMMAND dsymutil -o libdigidoc.dSYM $<TARGET_FILE:cdigidoc>
+ COMMAND zip -r ${CMAKE_BINARY_DIR}/libdigidoc-dbg_${VERSION}$ENV{VER_SUFFIX}.zip libdigidoc.dSYM
+ )
+else()
+ install( TARGETS cdigidoc DESTINATION ${CMAKE_INSTALL_BINDIR} )
+ configure_file( libdigidoc.pc.cmake libdigidoc.pc @ONLY )
+ configure_file( cdigidoc.1.cmake cdigidoc.1 )
+ install( FILES ${CMAKE_CURRENT_BINARY_DIR}/libdigidoc.pc DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig )
+ install( FILES ${CMAKE_CURRENT_BINARY_DIR}/cdigidoc.1 DESTINATION ${CMAKE_INSTALL_MANDIR}/man1 )
+ install( FILES ${CERTS} DESTINATION ${CMAKE_INSTALL_FULL_DATADIR}/libdigidoc )
+endif()
+
+#install( FILES
+# pkcs11/pkcs11.h
+# pkcs11/pkcs11f.h
+# pkcs11/pkcs11t.h
+# pkcs11/unix.h
+# pkcs11/cryptoki.h
+# DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/libdigidoc/pkcs11
+#)
diff --git a/libdigidoc/DigiCrypt.c b/libdigidoc/DigiCrypt.c
new file mode 100644
index 0000000..0930a31
--- /dev/null
+++ b/libdigidoc/DigiCrypt.c
@@ -0,0 +1,1006 @@
+//==========< HISTORY >=============================
+// 29.10.2003 Changes by AA
+// ReadCertFromCard adapted
+// from Tarmo's example
+// 09.10.2003 Changes by AA
+// 02.09.2003 Changes from Tarmo Milva
+//Changed functions:
+//DigiCrypt_GetDataFromCert
+//DigiCrypt_GetFirstAllowedCSPName
+//DigiCrypt_GetDefaultKeyContainerName
+//DigiCrypt_SelectFromAllKeysCerts
+//
+#include "DigiCrypt.h"
+#include "DigiDocDefs.h"
+#include "DigiDocConfig.h"
+#include <stdio.h>
+#include <tchar.h>
+
+#define MY_ENCODING_TYPE (PKCS_7_ASN_ENCODING | X509_ASN_ENCODING)
+
+#define dSTRING_ITEM_LEN 255
+#define dNAME_ITEM_LEN 1024
+#define dCSPTYPE_NOTDEFINED -1
+
+static char *psData_CSP_Path = "SOFTWARE\\Microsoft\\Cryptography\\Defaults\\Provider\\";
+static char *psData_Extra_CSP_Name = "Advanced Setec SetCSP";
+static char *psData_Ignore_CSP_Name ="XXXEstEID";
+static char *psData_Est_CSP_Name = "EstEID";
+
+//Global data
+static HCRYPTPROV oG_hProvider = 0;
+static char oG_sCSPName[dSTRING_ITEM_LEN+1];
+static char oG_sKeyContainerName[dNAME_ITEM_LEN+1];
+static BOOL oG_fDialogUserCancel;
+
+extern int RunDialogUnit(char *psList[], int iWinWidth, int iWinHeight);
+ PCCERT_CONTEXT DigiCrypt_ReadCertFromCard(void);
+static BOOL DigiCrypt_AddCertToStore(PCCERT_CONTEXT pCert);
+
+static BOOL OpenProvider(HCRYPTPROV *phProv, char *psProvider, DWORD dwFlags);
+static HCERTSTORE DigiCrypt_OpenStore(void);
+static char *DigiCrypt_GetFirstAllowedCSPNameNew(void);
+static char *DigiCrypt_GetFirstAllowedCSPName(void);
+static void DigiCrypt_ReleaseFirstAllowedCSP(void);
+static BOOL DigiCrypt_GetCSPFromCert(PCCERT_CONTEXT pCertContext, char *psResult, int iMaxResLen);
+static BOOL DigiCrypt_GetContainerFromCert(PCCERT_CONTEXT pCertContext, char *psResult, int iMaxResLen);
+static BOOL DigiCrypt_CertIsSig(PCCERT_CONTEXT pCertContext);
+
+static char *DigiCrypt_GetDefaultKeyContainerName(char *psCSPName);
+static char *DigiCrypt_GetDefaultKeyContainerNameSimple(char *psCSPName);
+static char *DigiCrypt_GetDefaultCSPName(void);
+static BOOL DigiCrypt_GetDataFromCert(PCCERT_CONTEXT pCertContext);
+static PCCERT_CONTEXT DigiCrypt_SelectFromAllCerts(void);
+static PCCERT_CONTEXT DigiCrypt_SelectFromAllKeysCerts(HCRYPTPROV hProvider);
+static void DigiCrypt_SelectCertsFromKeyContainer(HCRYPTPROV hProv, char *psContainerName);
+static void DigiCrypt_ChangeContainerName(char *psContainerName);
+
+static void RunDlg_Clear(void);
+static BOOL RunDlg_AddItem(PCCERT_CONTEXT pCertContext, BOOL fTimeCheck);
+static PCCERT_CONTEXT RunDlg_RunDlg(void);
+static BOOL RunDlg_FillItem(PCCERT_CONTEXT pCertContext, char *psRes, int len);
+
+static void IntLogToFile(char *psMsg, int iMsgLen);
+static BOOL IsLogEnabled(void);
+
+PCCERT_CONTEXT DigiCrypt_FindContext(BOOL fByKeyContainer, DWORD *dwResult)
+{
+ PCCERT_CONTEXT hCert = NULL;
+ char *psCSPName;
+ char *psDefaultKeyContainerName;
+ oG_fDialogUserCancel = FALSE;
+
+ *dwResult = dDigiCrypt_Okey;
+ memset(oG_sCSPName, 0, sizeof(oG_sCSPName));
+ memset(oG_sKeyContainerName, 0, sizeof(oG_sKeyContainerName));
+
+ if (fByKeyContainer == TRUE) {
+ hCert = DigiCrypt_ReadCertFromCard();
+ //TEST
+ //Test_ReadCertDataC(hCert);
+ //ENDTEST
+ if (hCert == NULL) {
+ psCSPName = DigiCrypt_GetFirstAllowedCSPNameNew();
+ if (psCSPName == NULL)
+ *dwResult = dDigiCrypt_Error_NotFoundCSP;
+ else {
+ psDefaultKeyContainerName = DigiCrypt_GetDefaultKeyContainerName(oG_sCSPName);
+ if (psDefaultKeyContainerName == NULL)
+ *dwResult = dDigiCrypt_Error_NoDefaultKey;
+ else
+ hCert = DigiCrypt_SelectFromAllKeysCerts(oG_hProvider);
+ }
+ }
+ } else {
+ hCert = DigiCrypt_SelectFromAllCerts();
+ if (hCert != NULL)
+ DigiCrypt_GetDataFromCert(hCert);
+ }
+ if (hCert == NULL) {
+ if (oG_fDialogUserCancel == TRUE)
+ *dwResult = dDigiCrypt_Error_UserCancel;
+ else {
+ if (*dwResult == dDigiCrypt_Okey)
+ *dwResult = dDIgiCrypt_Error_NotFoundCert;
+ }
+ }
+ return(hCert);
+}
+
+PCCERT_CONTEXT DigiCrypt_ReadCertFromCard(void)
+{
+HCRYPTPROV hCryptProv;
+BYTE *pbData = NULL;
+HCRYPTKEY hKey;
+DWORD cbData = 0;
+DWORD dwKeyType=0, dwKeySpec = AT_SIGNATURE;
+DWORD dwErrCode=0;
+DWORD cspType=0;
+DWORD cspFlag=CRYPT_SILENT;
+char *psCspName = NULL;
+char *psKeyContainer;
+BOOL fRes = FALSE;
+PCCERT_CONTEXT pCertContext = NULL;
+CRYPT_KEY_PROV_INFO KeyProvInfo;
+LPWSTR wszContainerName=NULL;
+LPWSTR wszProvName=NULL;
+DWORD cchContainerName;
+DWORD cchCSPName;
+HCRYPTPROV hProv;
+
+
+DigiCrypt_ReleaseFirstAllowedCSP();
+
+psCspName=DigiCrypt_GetFirstAllowedCSPNameNew();
+
+//very dummy thing.. i check from csp creators why i should do so...
+if(!lstrcmp(psCspName,"EstEID Card CSP"))
+ fRes = CryptAcquireContext(&hProv,"XXX",psCspName,2, CRYPT_SILENT);
+// end dummy//
+
+if (psCspName == NULL || strstr(psCspName,psData_Est_CSP_Name) == NULL)
+ return(pCertContext);
+
+cspType=DigiCrypt_FindContext_GetCSPType(psCspName);
+
+psKeyContainer=DigiCrypt_GetDefaultKeyContainerName(psCspName);
+
+fRes = CryptAcquireContext(&hCryptProv,psKeyContainer,psCspName,cspType, CRYPT_SILENT);
+if (fRes == FALSE)
+ return(pCertContext);
+
+// VS: use alsu auth keys if KEY_USAGE_CHECK=false
+dwKeySpec = ConfigItem_lookup_int("KEY_USAGE_CHECK", 1) ? AT_SIGNATURE : 0;
+
+fRes=CryptGetUserKey(hCryptProv, dwKeySpec, &hKey);
+if (fRes == TRUE)
+ {
+ fRes=CryptGetKeyParam(hKey, KP_CERTIFICATE, NULL, &cbData, 0);
+ if (fRes == TRUE)
+ {
+ pbData = malloc(cbData);
+ if (pbData == NULL)
+ fRes = FALSE;
+ }
+ if (fRes == TRUE)
+ fRes=CryptGetKeyParam(hKey, KP_CERTIFICATE, pbData, &cbData, 0);
+ if (fRes == TRUE)
+ {
+ pCertContext = CertCreateCertificateContext(MY_ENCODING_TYPE,pbData,cbData);
+ if (pCertContext != NULL)
+ {
+ wszContainerName=NULL;
+ wszProvName=NULL;
+ cchContainerName = (lstrlen(psKeyContainer) + 1) * sizeof(WCHAR);
+ cchCSPName = (lstrlen(psCspName) + 1) * sizeof(WCHAR);
+ wszContainerName = (LPWSTR) malloc(cchContainerName);
+ wszProvName = (LPWSTR) malloc(cchCSPName);
+ mbstowcs(wszContainerName, psKeyContainer,cchContainerName);
+ mbstowcs(wszProvName, psCspName, cchCSPName);
+ ZeroMemory((PVOID)&KeyProvInfo, sizeof(CRYPT_KEY_PROV_INFO));
+ KeyProvInfo.pwszContainerName = (LPWSTR) wszContainerName;
+ KeyProvInfo.pwszProvName = (LPWSTR) wszProvName;
+ KeyProvInfo.dwProvType = PROV_RSA_SIG;
+ KeyProvInfo.dwFlags = 0;
+ KeyProvInfo.dwKeySpec = dwKeyType;
+ fRes = CertSetCertificateContextProperty(pCertContext,CERT_KEY_PROV_INFO_PROP_ID, 0, (const void *) &KeyProvInfo);
+ if (wszContainerName != NULL)
+ free(wszContainerName);
+ if (wszProvName != NULL)
+ free(wszProvName);
+
+ }
+ }
+ }
+
+//if (pCertContext != NULL)
+// DigiCrypt_AddCertToStore(pCertContext);
+if (fRes == FALSE && pCertContext != NULL)
+ {
+ CertFreeCertificateContext(pCertContext);
+ pCertContext = NULL;
+ }
+if (pbData != NULL)
+ free(pbData);
+if (hCryptProv != 0)
+ CryptReleaseContext(hCryptProv, 0);
+return(pCertContext);
+}
+
+
+static BOOL DigiCrypt_AddCertToStore(PCCERT_CONTEXT pCert)
+{
+BOOL fRes = FALSE;
+HCERTSTORE hSystemStore = NULL; // The system store handle.
+if (pCert != NULL)
+ {
+ if (hSystemStore = CertOpenStore(
+ CERT_STORE_PROV_SYSTEM_A,
+ 0, // Encoding type not needed with this PROV.
+ 0, // Accept the default HCRYPTPROV.
+ CERT_STORE_NO_CRYPT_RELEASE_FLAG |
+ CERT_SYSTEM_STORE_CURRENT_USER,"MY"))
+ {
+ if (CertAddCertificateContextToStore(hSystemStore, pCert, CERT_STORE_ADD_REPLACE_EXISTING,NULL))
+ fRes = TRUE;
+ }
+ }
+if (hSystemStore != NULL)
+ CertCloseStore(hSystemStore, CERT_CLOSE_STORE_CHECK_FLAG);
+return(fRes);
+}
+
+
+char *DigiCrypt_FindContext_GetKeyName()
+{
+ if (lstrlen(oG_sKeyContainerName) > 0)
+ return(oG_sKeyContainerName);
+ else
+ return(NULL);
+}
+
+char *DigiCrypt_FindContext_GetCSPName()
+{
+ if (lstrlen(oG_sCSPName) > 0)
+ return(oG_sCSPName);
+ else
+ return(NULL);
+}
+
+DWORD DigiCrypt_FindContext_GetCSPType(char *psCSPName)
+{
+ DWORD dwRes = PROV_RSA_SIG;
+ DWORD dwType = REG_DWORD;
+ DWORD dwLen = dSTRING_ITEM_LEN;
+ DWORD *pdwVal;
+ HKEY hKey;
+ LONG lRes;
+ char sKeyNameBuf[dSTRING_ITEM_LEN+1];
+ char sValue[dSTRING_ITEM_LEN+1];
+
+ strncpy(sKeyNameBuf, psData_CSP_Path, sizeof(sKeyNameBuf));
+ strncat(sKeyNameBuf, psCSPName, sizeof(sKeyNameBuf) - strlen(sKeyNameBuf));
+ lRes = RegOpenKeyEx(HKEY_LOCAL_MACHINE,sKeyNameBuf, 0, KEY_READ, &hKey);
+ if (lRes == ERROR_SUCCESS) {
+ lRes = RegQueryValueEx(hKey, "Type", 0, &dwType, (LPBYTE)sValue, &dwLen);
+ if (lRes == ERROR_SUCCESS) {
+ pdwVal = (DWORD *)sValue;
+ dwRes = (*pdwVal);
+ }
+ RegCloseKey(hKey);
+ }
+ return(dwRes);
+}
+
+static BOOL OpenProvider(HCRYPTPROV *phProv, char *psProvider, DWORD dwFlags)
+{
+ BOOL fRes;
+ DWORD dwType = DigiCrypt_FindContext_GetCSPType(psProvider);
+ fRes = CryptAcquireContext(phProv,NULL,psProvider, dwType, dwFlags);
+ return(fRes);
+}
+
+static HCERTSTORE DigiCrypt_OpenStore(void)
+{
+HCERTSTORE hStore;
+hStore = CertOpenStore(CERT_STORE_PROV_SYSTEM,0,(HCRYPTPROV)NULL,CERT_SYSTEM_STORE_CURRENT_USER,L"MY");
+return(hStore);
+}
+
+
+static BOOL DigiCrypt_GetCSPFromCert(PCCERT_CONTEXT pCertContext, char *psResult, int iMaxResLen)
+{
+BOOL fRes = FALSE;
+CRYPT_KEY_PROV_INFO *poKeyInfo;
+DWORD pcbData;
+DWORD dwLen;
+if (pCertContext == NULL || psResult == 0)
+ return(fRes);
+fRes = CertGetCertificateContextProperty(pCertContext,CERT_KEY_PROV_INFO_PROP_ID,NULL,&pcbData);
+if (fRes == TRUE)
+ {
+ poKeyInfo = malloc(pcbData);
+ if (poKeyInfo != NULL)
+ {
+ fRes = CertGetCertificateContextProperty(pCertContext,CERT_KEY_PROV_INFO_PROP_ID,poKeyInfo,&pcbData);
+ if (fRes == TRUE)
+ {
+ if (poKeyInfo->pwszProvName != NULL)
+ {
+ dwLen = WideCharToMultiByte(CP_ACP,0,poKeyInfo->pwszProvName,-1,psResult,iMaxResLen,NULL,NULL);
+ }
+ else
+ fRes = FALSE;
+ }
+ free(poKeyInfo);
+ }
+ }
+return(fRes);
+}
+
+static BOOL DigiCrypt_GetContainerFromCert(PCCERT_CONTEXT pCertContext, char *psResult, int iMaxResLen)
+{
+BOOL fRes = FALSE;
+CRYPT_KEY_PROV_INFO *poKeyInfo;
+DWORD pcbData;
+DWORD dwLen;
+if (pCertContext == NULL || psResult == 0)
+ return(fRes);
+fRes = CertGetCertificateContextProperty(pCertContext,CERT_KEY_PROV_INFO_PROP_ID,NULL,&pcbData);
+if (fRes == TRUE)
+ {
+ poKeyInfo = malloc(pcbData);
+ if (poKeyInfo != NULL)
+ {
+ fRes = CertGetCertificateContextProperty(pCertContext,CERT_KEY_PROV_INFO_PROP_ID,poKeyInfo,&pcbData);
+ if (fRes == TRUE)
+ {
+ if (poKeyInfo->pwszContainerName != NULL)
+ {
+
+ dwLen = WideCharToMultiByte(CP_ACP,0,poKeyInfo->pwszContainerName,-1,psResult,iMaxResLen,NULL,NULL);
+ }
+ else
+ fRes = FALSE;
+ }
+ free(poKeyInfo);
+ }
+ }
+return(fRes);
+}
+
+static BOOL DigiCrypt_CertIsSig(PCCERT_CONTEXT pCertContext)
+{
+BOOL fRes = FALSE;
+CRYPT_KEY_PROV_INFO *poKeyInfo;
+DWORD pcbData;
+if (pCertContext == NULL)
+ return(fRes);
+fRes = CertGetCertificateContextProperty(pCertContext,CERT_KEY_PROV_INFO_PROP_ID,NULL,&pcbData);
+if (fRes == TRUE)
+ {
+ poKeyInfo = malloc(pcbData);
+ if (poKeyInfo != NULL)
+ {
+ fRes = CertGetCertificateContextProperty(pCertContext,CERT_KEY_PROV_INFO_PROP_ID,poKeyInfo,&pcbData);
+ if (fRes == TRUE)
+ {
+ if (poKeyInfo->dwProvType == PROV_RSA_SIG)
+ fRes = TRUE;
+ }
+ free(poKeyInfo);
+ }
+ }
+return(fRes);
+}
+
+
+static BOOL DigiCrypt_GetDataFromCert(PCCERT_CONTEXT pCertContext)
+{
+ BOOL fRes = FALSE;
+ char sContainer[dNAME_ITEM_LEN+1];
+ //DWORD dwLen;
+ if (pCertContext == NULL)
+ return(fRes);
+ fRes = DigiCrypt_GetCSPFromCert(pCertContext, oG_sCSPName,dSTRING_ITEM_LEN);
+
+ if (fRes == TRUE) {
+ // DigiCrypt_GetDefaultKeyContainerNameSimple(oG_sCSPName); //this is not usable. Tarmo changed that! Instead we should use the following:
+ if (DigiCrypt_GetContainerFromCert(pCertContext, sContainer, dNAME_ITEM_LEN) == TRUE) {
+ strncpy(oG_sKeyContainerName, sContainer, sizeof(oG_sKeyContainerName));
+ }
+ }
+ return(fRes);
+}
+
+static char *DigiCrypt_GetFirstAllowedCSPNameNew(void)
+{
+ char *psRes = NULL;
+ HKEY hKey = NULL;
+ LONG lRet=0;
+ DWORD dwIndex = 0;
+ BOOL fRes;
+ char sProvName[dSTRING_ITEM_LEN+1];
+ char sKeyNameBuf[dSTRING_ITEM_LEN+1];
+ HCRYPTPROV hProvide = 0;
+ DWORD dwBufLen;
+ FILETIME oTime;
+ //char buff[200];
+ BYTE pbData[dNAME_ITEM_LEN+1];
+ DWORD cbData=dNAME_ITEM_LEN+1;
+ //
+ DWORD dwProvType;
+
+ strncpy(sKeyNameBuf, psData_CSP_Path, sizeof(sKeyNameBuf));
+ lRet = RegOpenKeyEx(HKEY_LOCAL_MACHINE,sKeyNameBuf,0, KEY_READ, &hKey);
+
+ while (lRet == ERROR_SUCCESS) {
+ dwBufLen = dSTRING_ITEM_LEN;
+ lRet = RegEnumKeyEx(hKey,dwIndex,sProvName,&dwBufLen,NULL,NULL,0,&oTime);
+ if (lRet == ERROR_SUCCESS) {
+ if (lstrcmp(sProvName,psData_Ignore_CSP_Name) != 0) {
+ dwProvType = DigiCrypt_FindContext_GetCSPType(sProvName);
+ LOG("CSP %s",sProvName);
+ //printf("%s :",sProvName);
+ if ((lstrcmp(sProvName,psData_Extra_CSP_Name) != 0) && (lstrcmp(sProvName,"Belgium Identity Card CSP")!=0)) {
+ //fRes = OpenProvider(&hProvide, sProvName, CRYPT_SILENT);
+ fRes = CryptAcquireContext(&hProvide,NULL,sProvName,dwProvType, CRYPT_SILENT);
+ fRes=CryptGetProvParam(hProvide, PP_ENUMCONTAINERS, pbData, &cbData,CRYPT_FIRST);
+ // printf("X\n");
+ } else {
+ //fRes = OpenProvider(&hProvide, sProvName, CRYPT_VERIFYCONTEXT);
+ //fRes = CryptAcquireContext(&hProvide,"SetCARDKeyContainer",sProvName,dwProvType, CRYPT_SILENT);
+ fRes = CryptAcquireContext(&hProvide,NULL,sProvName,dwProvType, CRYPT_VERIFYCONTEXT);
+ if (fRes == TRUE) {
+ //the extra csp might give wrong answer. We should ask from provider, why.
+ //The following is the work-around -- try to lookup key container from the card.
+ //if the result is negative this is a not the csp what is needed.
+ fRes=CryptGetProvParam(hProvide, PP_ENUMCONTAINERS, pbData, &cbData,CRYPT_FIRST);
+ if (fRes == TRUE)
+ fRes=CryptAcquireContext(&hProvide,(char*)pbData,sProvName,dwProvType, CRYPT_SILENT);
+ }
+ }
+ //printf("fRes: %x\n",GetLastError());
+ if (fRes == TRUE) { // && dwProvType == 2)
+ // printf("OK %d %s\n",cbData, pbData);
+ //set global values
+ LOG("CSP %s accepted",sProvName);
+ //is it hardware token?
+ cbData=dNAME_ITEM_LEN+1;
+ if (CryptGetProvParam(hProvide, PP_IMPTYPE, pbData, &cbData, 0)) {
+ //printf("implementat: %d\n",pbData[0]);
+ if((pbData[0] & 1)) // hardware token
+ {
+ strncpy(oG_sCSPName, sProvName, sizeof(oG_sCSPName));
+ //CryptReleaseContext(hProvide, 0);
+ psRes = oG_sCSPName;
+ break;
+ }
+ }
+ }
+ }
+ }
+ //hProvide = 0;
+ CryptReleaseContext(hProvide, 0);
+ dwIndex++;
+ }
+ if (hKey != NULL)
+ RegCloseKey(hKey);
+ return(psRes);
+}
+
+
+static char *DigiCrypt_GetFirstAllowedCSPName(void)
+{
+ char *psRes = NULL;
+ HKEY hKey = NULL;
+ LONG lRet=0;
+ DWORD dwIndex = 0;
+ BOOL fRes;
+ char sProvName[dSTRING_ITEM_LEN+1];
+ char sKeyNameBuf[dSTRING_ITEM_LEN+1];
+ HCRYPTPROV hProvide = 0;
+ DWORD dwBufLen;
+ FILETIME oTime;
+ //char buff[200];
+ BYTE pbData[dNAME_ITEM_LEN+1];
+ DWORD cbData=dNAME_ITEM_LEN+1;
+ DWORD dwProvType;
+
+ strncpy(sKeyNameBuf, psData_CSP_Path, sizeof(sKeyNameBuf));
+ lRet = RegOpenKeyEx(HKEY_LOCAL_MACHINE,sKeyNameBuf,0, KEY_READ, &hKey);
+ while (lRet == ERROR_SUCCESS) {
+ dwBufLen = dSTRING_ITEM_LEN;
+ lRet = RegEnumKeyEx(hKey,dwIndex,sProvName,&dwBufLen,NULL,NULL,0,&oTime);
+ if (lRet == ERROR_SUCCESS) {
+ if (lstrcmp(sProvName,psData_Ignore_CSP_Name) != 0) {
+ dwProvType = DigiCrypt_FindContext_GetCSPType(sProvName);
+ LOG("CSP %s",sProvName);
+ if (lstrcmp(sProvName,psData_Extra_CSP_Name) != 0)
+ fRes = OpenProvider(&hProvide, sProvName, CRYPT_SILENT);
+ else {
+ fRes = OpenProvider(&hProvide, sProvName, CRYPT_VERIFYCONTEXT);
+ //fRes = CryptAcquireContext(&hProvide,"SetCARDKeyContainer",sProvName,dwProvType, CRYPT_SILENT);
+ fRes = CryptAcquireContext(&hProvide,NULL,sProvName,dwProvType, CRYPT_VERIFYCONTEXT);
+ if(fRes) {
+ //the extra csp might give wrong answer. We should ask from provider, why.
+ //The following is the work-around -- try to lookup key container from the card.
+ //if the result is negative this is a not the csp what is needed.
+ fRes=CryptGetProvParam(hProvide, PP_ENUMCONTAINERS, pbData, &cbData,CRYPT_FIRST);
+ }
+ }
+ if (fRes == TRUE) { // && dwProvType == 2)
+ //set global values
+ LOG("CSP %s accepted",sProvName);
+ strncpy(oG_sCSPName, sProvName, sizeof(oG_sCSPName));
+ CryptReleaseContext(hProvide, 0);
+ psRes = oG_sCSPName;
+ break;
+ }
+ }
+ }
+ //hProvide = 0;
+ CryptReleaseContext(hProvide, 0);
+ dwIndex++;
+ }
+ if (hKey != NULL)
+ RegCloseKey(hKey);
+ return(psRes);
+}
+
+
+static void DigiCrypt_ReleaseFirstAllowedCSP(void)
+{
+ //clear global values
+ if (oG_hProvider != 0)
+ CryptReleaseContext(oG_hProvider, 0);
+ oG_hProvider = 0;
+ oG_sCSPName[0] = 0;
+}
+
+static char *DigiCrypt_GetDefaultKeyContainerName(char *psCSPName)
+{
+ char *psRes = NULL;
+ HCRYPTPROV hProvider;
+ BOOL fRes;
+ DWORD dwFlags = CRYPT_VERIFYCONTEXT;
+ BYTE pbData[dNAME_ITEM_LEN+1];
+ DWORD cbData = dNAME_ITEM_LEN;
+ DWORD dwError;
+ DWORD dwProvType;
+
+ ZeroMemory(pbData,cbData);
+ ZeroMemory(oG_sKeyContainerName,1000);
+ dwProvType = DigiCrypt_FindContext_GetCSPType(psCSPName);
+ //LOG("GetDefaultKeyContainerName CSP=%s",psCSPName);
+ if (lstrcmp(psCSPName,psData_Extra_CSP_Name) != 0)
+ fRes = CryptAcquireContext(&hProvider,NULL,psCSPName,dwProvType, CRYPT_SILENT);
+ else
+ fRes = CryptAcquireContext(&hProvider,NULL,psCSPName,dwProvType, CRYPT_VERIFYCONTEXT);
+ if (fRes == FALSE && dwFlags == CRYPT_SILENT) {
+ //by description must be CRYPT_VERIFYCONTEXT
+ fRes = CryptAcquireContext(&hProvider,NULL,psCSPName,dwProvType, CRYPT_VERIFYCONTEXT);
+ }
+ if (fRes == TRUE) {
+ cbData = dNAME_ITEM_LEN;
+ fRes = CryptGetProvParam(hProvider, PP_CONTAINER, pbData, &cbData, 0);
+ /*if (fRes == FALSE)
+ dwError = GetLastError();*/
+ }
+ //Some cards should not have default key container
+ //let try to find key containers on the card.
+ if (fRes == FALSE) {
+ fRes=CryptGetProvParam(hProvider, PP_ENUMCONTAINERS, pbData, &cbData,CRYPT_FIRST);
+ if (fRes == FALSE)
+ dwError = GetLastError();
+ }
+ if (fRes == TRUE) {
+ //oG_hProvider = hProvider;
+ strncpy(oG_sKeyContainerName, (char *) pbData, sizeof(oG_sKeyContainerName));
+ //psRes = oG_sKeyContainerName;
+ DigiCrypt_ChangeContainerName(oG_sKeyContainerName);
+ } else {
+
+ }
+ if (psRes != NULL)
+ LOG("GetDefaultKeyContainerName CSP=%s",psCSPName);
+ else
+ LOG("GetDefaultKeyContainerName Not found");
+ if (hProvider != 0)
+ CryptReleaseContext(hProvider, 0);
+ return(oG_sKeyContainerName);
+}
+
+static char *DigiCrypt_GetDefaultKeyContainerNameSimple(char *psCSPName)
+{
+ char *psRes = NULL;
+ HCRYPTPROV hProvider=0;
+ BOOL fRes;
+ DWORD dwFlags = 0;
+ BYTE pbData[dNAME_ITEM_LEN+1];
+ DWORD cbData = dNAME_ITEM_LEN;
+ DWORD dwError;
+
+ fRes = OpenProvider(&hProvider, psCSPName, dwFlags);
+ //fRes = CryptAcquireContext(&hProvider,NULL,psCSPName,PROV_RSA_SIG, dwFlags);
+ if (fRes == TRUE) {
+ fRes = CryptGetProvParam(hProvider, PP_CONTAINER, pbData, &cbData, 0);
+ if (fRes == FALSE)
+ dwError = GetLastError();
+ }
+ if (fRes == TRUE) {
+ strncpy(oG_sKeyContainerName, pbData, sizeof(oG_sKeyContainerName));
+ psRes = oG_sKeyContainerName;
+ DigiCrypt_ChangeContainerName(oG_sKeyContainerName);
+ }
+ if (hProvider != 0)
+ CryptReleaseContext(hProvider, 0);
+ return(psRes);
+}
+
+
+static PCCERT_CONTEXT DigiCrypt_SelectFromAllCerts(void)
+{
+PCCERT_CONTEXT pCertContext = NULL;
+HCERTSTORE hStore;
+hStore = DigiCrypt_OpenStore();
+if (hStore != NULL)
+ {
+ while (TRUE)
+ {
+ pCertContext = CertEnumCertificatesInStore(hStore,pCertContext);
+ if (pCertContext == NULL)
+ break;
+ else
+ {
+ //TEST
+ //Test_ReadCertDataC(pCertContext);
+ //END TEST
+ RunDlg_AddItem(pCertContext,TRUE);
+ }
+ }
+ pCertContext = RunDlg_RunDlg();
+ }
+return(pCertContext);
+}
+
+static void DigiCrypt_SelectCertsFromKeyContainer(HCRYPTPROV hProv, char *psContainerName)
+{
+PCCERT_CONTEXT pCertContext = NULL;
+HCERTSTORE hStore;
+BOOL fRelease = FALSE;
+char sContainer[dNAME_ITEM_LEN+1];
+
+if (memcmp(psContainerName,"AUT",3) == 0)
+ {
+ LOG("Find1 Ignore AUT cert");
+ return;
+ }
+hStore = DigiCrypt_OpenStore();
+if (hStore != NULL)
+ {
+ while (TRUE)
+ {
+ pCertContext = CertEnumCertificatesInStore(hStore,pCertContext);
+ if (pCertContext == NULL)
+ break;
+ else
+ {
+ if (DigiCrypt_GetContainerFromCert(pCertContext, sContainer, dNAME_ITEM_LEN) == TRUE)
+ {
+
+ LOG("Find1 Container %s %s",sContainer,psContainerName);
+ if (lstrcmp(sContainer+3,psContainerName+3) == 0)
+ {
+ LOG("Find1 Container %s accepted",sContainer);
+ RunDlg_AddItem(pCertContext,TRUE);
+ }
+ }
+ }
+ }
+ }
+else
+ LOG("Find1 Can't open store");
+if (fRelease == TRUE)
+ CryptReleaseContext(hProv, 0);
+}
+
+static PCCERT_CONTEXT DigiCrypt_SelectFromAllKeysCerts(HCRYPTPROV hProvider)
+{
+PCCERT_CONTEXT pCertContext = NULL;
+HCRYPTPROV hProv;
+BYTE pbData[dNAME_ITEM_LEN+1];
+DWORD cbData = dNAME_ITEM_LEN;
+DWORD dwFlag;
+BOOL fRes;
+BOOL fRelease = FALSE;
+CRYPT_KEY_PROV_INFO* poKeyInfo = NULL;
+char sContainer[dNAME_ITEM_LEN+1];
+
+hProv = hProvider;
+
+
+if (hProv == 0)
+ {
+ fRes = OpenProvider(&hProv, oG_sCSPName, CRYPT_VERIFYCONTEXT);
+ //fRes = CryptAcquireContext(&hProv,NULL,oG_sCSPName,PROV_RSA_FULL, CRYPT_VERIFYCONTEXT);
+ if (fRes == FALSE)
+ {
+
+ LOG("Find1 - Can't open provider");
+ return(pCertContext);
+ }
+ fRelease = TRUE;
+ }
+ dwFlag = CRYPT_FIRST;
+ fRes = TRUE;
+ while (fRes == TRUE)
+ {
+ cbData = dNAME_ITEM_LEN;
+ cbData = 0;
+ fRes = CryptGetProvParam(hProv, PP_ENUMCONTAINERS, NULL, &cbData, dwFlag);
+ if (fRes == TRUE)
+ fRes = CryptGetProvParam(hProv, PP_ENUMCONTAINERS, pbData, &cbData, dwFlag);
+ dwFlag = 0;
+
+ if (fRes == FALSE)
+ {
+ if (GetLastError() == ERROR_NO_MORE_ITEMS)
+ {
+ LOG("Find1 End");
+ fRes = TRUE;
+ break;
+ }
+ }
+ else
+ {
+ LOG("Find1 select certs from %s",pbData);
+ DigiCrypt_SelectCertsFromKeyContainer(hProv, pbData);
+ }
+ }
+ pCertContext = RunDlg_RunDlg();
+ //we have selected the cert, but do we know corresponding key?
+ //let change values of globals when these are different
+ if(DigiCrypt_GetContainerFromCert(pCertContext, sContainer, dNAME_ITEM_LEN) == TRUE) {
+ strncpy(oG_sKeyContainerName, sContainer, sizeof(oG_sKeyContainerName));
+ }
+ if(fRelease == TRUE)
+ CryptReleaseContext(hProv, 0);
+ return(pCertContext);
+}
+
+
+static BOOL DigiCrypt_IsValidCert(PCCERT_CONTEXT pCertContext, BOOL fTimeCheck)
+{
+BOOL fIsValid = FALSE;
+BOOL fRes = FALSE;
+BOOL fKuCheck = TRUE;
+BYTE bKeyUsageBits = CERT_NON_REPUDIATION_KEY_USAGE;
+DWORD dwKeyUsageBytes = 1;
+// VS use auth certs if key_usage_check = 0
+fKuCheck = (BOOL)ConfigItem_lookup_int("KEY_USAGE_CHECK", 1);
+bKeyUsageBits = fKuCheck ? CERT_NON_REPUDIATION_KEY_USAGE : 0;
+//LOG("KEY_USAGE_CHECK: %d ku: %d", fKuCheck, bKeyUsageBits);
+//Old version
+//FILETIME oCurrentTime;
+if (pCertContext != NULL && pCertContext->pCertInfo != NULL)
+ {
+ //not needed (info from Tarmo Milva)
+ //if (DigiCrypt_CertIsSig(pCertContext) == TRUE)
+ fRes = CertGetIntendedKeyUsage(X509_ASN_ENCODING,pCertContext->pCertInfo,&bKeyUsageBits,dwKeyUsageBytes);
+ //else
+ // fRes = FALSE;
+ if (fRes == TRUE)
+ {
+ //LOG("KU non-repu: %d", (bKeyUsageBits & CERT_NON_REPUDIATION_KEY_USAGE));
+ if(!fKuCheck || (bKeyUsageBits & CERT_NON_REPUDIATION_KEY_USAGE))
+ fIsValid = TRUE;
+ if(bKeyUsageBits & CERT_KEY_CERT_SIGN_KEY_USAGE) // don't display CA certs
+ fIsValid = FALSE;
+ }
+ if (fIsValid == TRUE && fTimeCheck == TRUE)
+ {
+ //Old version
+ //GetSystemTimeAsFileTime(&oCurrentTime);
+ //if (CompareFileTime(&oCurrentTime, &pCertContext->pCertInfo->NotBefore) < 0 ||
+ // CompareFileTime(&oCurrentTime, &pCertContext->pCertInfo->NotAfter) > 0 )
+ // fIsValid = FALSE;
+ //New version
+ //NULL, if current datetime
+ if (CertVerifyTimeValidity(NULL,pCertContext->pCertInfo) != 0)
+ fIsValid = FALSE;
+ }
+ }
+return(fIsValid);
+}
+
+static void DigiCrypt_ChangeContainerName(char *psContainerName)
+{
+if (memcmp(psContainerName,"AUT",3) == 0)
+ memmove(psContainerName,"SIG",3);
+}
+
+//dialog functions
+#define DLGMAXIEMS 512
+static char *psListItems[DLGMAXIEMS];
+static PCCERT_CONTEXT psListItemsCert[DLGMAXIEMS];
+static int iListItems=0;
+
+static void RunDlg_Clear(void)
+{
+int iI;
+for (iI=0; iI < DLGMAXIEMS;++iI)
+ {
+ psListItems[iI] = NULL;
+ psListItemsCert[iI] = NULL;
+ }
+iListItems=0;
+}
+
+static BOOL RunDlg_AddItem(PCCERT_CONTEXT pCertContext, BOOL fTimeCheck)
+{
+BOOL fRes = TRUE;
+BOOL fAddToList = TRUE;
+char *psData;
+int iI, len;
+if (iListItems == (DLGMAXIEMS-1))
+ return(FALSE);
+if (iListItems == 0)
+ {
+ for (iI=0; iI < DLGMAXIEMS;++iI)
+ {
+ psListItems[iI] = NULL;
+ psListItemsCert[iI] = NULL;
+ }
+ }
+if (pCertContext != NULL)
+ {
+ fAddToList = DigiCrypt_IsValidCert(pCertContext,fTimeCheck);
+ if (fAddToList == TRUE)
+ {
+ len = dSTRING_ITEM_LEN*4;
+ psListItems[iListItems] = (char *)LocalAlloc(LMEM_ZEROINIT,(len));
+ psListItemsCert[iListItems] = CertDuplicateCertificateContext(pCertContext);
+ //Make data buffer for list
+ psData = psListItems[iListItems];
+ RunDlg_FillItem(pCertContext, psData, len);
+ ++iListItems;
+ }
+ }
+return(fRes);
+}
+
+
+static PCCERT_CONTEXT RunDlg_RunDlg(void)
+{
+PCCERT_CONTEXT hCert = NULL;
+int iRes = -1;
+int iI;
+oG_fDialogUserCancel = FALSE;
+if (iListItems > 1)
+ {
+ LOG("StartDialog");
+ iRes = RunDialogUnit(psListItems, 450,300);
+ if (iRes < 0)
+ oG_fDialogUserCancel = TRUE;
+ LOG("EndDialog");
+ }
+else
+ {
+ if (iListItems == 1)
+ iRes = 0;
+ }
+for (iI=0; iI < iListItems;++iI)
+ {
+ LocalFree(psListItems[iI]);
+ if (iRes != iI)
+ CertFreeCertificateContext(psListItemsCert[iI]);
+ else
+ hCert = psListItemsCert[iI];
+ }
+iListItems = 0;
+return(hCert);
+}
+
+static BOOL RunDlg_FillItem(PCCERT_CONTEXT pCertContext, char *psRes, int len)
+{
+ char sTemp[dSTRING_ITEM_LEN+1];
+ SYSTEMTIME oT;
+ PCERT_INFO pCertInfo;
+ BOOL fRes = TRUE;
+ *psRes = 0;
+
+ if (pCertContext == NULL || pCertContext->pCertInfo == NULL || psRes == NULL)
+ return(FALSE);
+ pCertInfo = pCertContext->pCertInfo;
+ CertGetNameString(pCertContext,CERT_NAME_SIMPLE_DISPLAY_TYPE,CERT_NAME_ISSUER_FLAG,NULL,sTemp,dSTRING_ITEM_LEN);
+ if (lstrlen(sTemp) > 0) {
+ strncat(psRes, sTemp, len - strlen(psRes));
+ strncat(psRes, " \t", len - strlen(psRes));
+ }
+ CertGetNameString(pCertContext,CERT_NAME_SIMPLE_DISPLAY_TYPE,0,NULL,sTemp,dSTRING_ITEM_LEN);
+ //CorrectCharacters(sTemp);
+ if (lstrlen(sTemp) > 0) {
+ strncat(psRes, sTemp, len - strlen(psRes));
+ strncat(psRes, " \t", len - strlen(psRes));
+ }
+ if (FileTimeToSystemTime(&pCertInfo->NotBefore,&oT) == TRUE) {
+ snprintf(sTemp, sizeof(sTemp), "%02d/%02d/%02d \t",oT.wYear,oT.wMonth,oT.wDay);
+ strncat(psRes, sTemp, len - strlen(psRes));
+ }
+ else
+ fRes = FALSE;
+ if (FileTimeToSystemTime(&pCertInfo->NotAfter,&oT) == TRUE) {
+ snprintf(sTemp, sizeof(sTemp), "02d/%02d/%02d \t",oT.wYear,oT.wMonth,oT.wDay);
+ strncat(psRes,sTemp, len - strlen(psRes));
+ }
+ else
+ fRes = FALSE;
+ if (DigiCrypt_GetCSPFromCert(pCertContext, sTemp, dSTRING_ITEM_LEN) == TRUE)
+ strncat(psRes,sTemp, len - strlen(psRes));
+ return(fRes);
+}
+
+static char sLogLine[4096];
+static char sLogFile[256];
+static int iLogCheck = -1;
+
+static BOOL IsLogEnabled(void)
+{
+ BOOL fRes = FALSE;
+ DWORD dwRes;
+ char cVal;
+ HANDLE hSearch;
+ WIN32_FIND_DATA oF;
+
+ if(iLogCheck == -1) {
+ iLogCheck = 0;
+ dwRes = GetModuleFileName(NULL, sLogFile, 255);
+ //strcpy(sLogFile, "z:\\digicrypt.log"); dwRes=1;iLogCheck = 1;
+ //MessageBox(NULL,sLogFile,"LogFile=",MB_OK|MB_SYSTEMMODAL|MB_ICONERROR);
+ while (dwRes > 1) {
+ cVal = sLogFile[dwRes-1];
+ if (cVal == '.') {
+ strncat(sLogFile, "log", sizeof(sLogFile) - strlen(sLogFile));
+ hSearch = FindFirstFile(sLogFile,&oF);
+ if (hSearch != INVALID_HANDLE_VALUE) {
+ iLogCheck = 1;
+ FindClose(hSearch);
+ }
+ break;
+ }
+ --dwRes;
+ }
+ }
+ fRes = (BOOL)iLogCheck;
+ return(fRes);
+}
+
+void LOG(char *psMsgFmt, ...)
+{
+ int iLen;
+ char buff[200];
+ va_list ArgList;
+ va_start(ArgList, psMsgFmt);
+ iLen = wvsprintf((LPTSTR)sLogLine, (LPTSTR)psMsgFmt, ArgList);
+ snprintf(buff, sizeof(buff), (LPTSTR)psMsgFmt,ArgList);
+ //MessageBox(NULL,(LPTSTR)sLogLine,"Teade",0);
+ va_end(ArgList);
+ if (IsLogEnabled() == TRUE)
+ IntLogToFile(sLogLine,iLen);
+}
+
+static void IntLogToFile(char *psMsg, int iMsgLen)
+{
+char sLogFormat1[]="%02d%02d%02d %02d:%02d.%02d ";
+char sTimeBuf[64];
+HANDLE hFile;
+DWORD dwLen;
+SYSTEMTIME oTime;
+if (psMsg == NULL || iMsgLen == 0)
+ return;
+GetLocalTime(&oTime);
+wsprintf((LPTSTR)sTimeBuf,(LPTSTR)sLogFormat1, oTime.wYear-2000, oTime.wMonth, oTime.wDay,
+ oTime.wHour, oTime.wMinute, oTime.wSecond);
+hFile = CreateFile((LPCTSTR)sLogFile,
+ GENERIC_READ|GENERIC_WRITE,FILE_SHARE_WRITE, NULL,
+ OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
+
+if (hFile != INVALID_HANDLE_VALUE)
+ {
+ if (psMsg != NULL)
+ {
+ SetFilePointer(hFile,0,NULL,FILE_END);
+ WriteFile(hFile,sTimeBuf, strlen(sTimeBuf), &dwLen, NULL);
+ if (iMsgLen < 0)
+ iMsgLen = strlen(psMsg);
+ if (iMsgLen > 0)
+ WriteFile(hFile,psMsg, iMsgLen, &dwLen, NULL);
+ WriteFile(hFile,"\r\n", 2, &dwLen, NULL);
+ }
+ CloseHandle(hFile);
+ }
+}
+
+
+
diff --git a/libdigidoc/DigiCrypt.h b/libdigidoc/DigiCrypt.h
new file mode 100644
index 0000000..a2ee1f4
--- /dev/null
+++ b/libdigidoc/DigiCrypt.h
@@ -0,0 +1,28 @@
+#ifndef DigiCryptH
+#define DigiCryptH
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+#include <windows.h>
+#include <wincrypt.h>
+
+#define dDigiCrypt_Okey 0
+#define dDigiCrypt_Error_NotFoundCSP 1
+#define dDigiCrypt_Error_UserCancel 2
+#define dDigiCrypt_Error_NoDefaultKey 3
+#define dDIgiCrypt_Error_NotFoundCert 4
+
+PCCERT_CONTEXT DigiCrypt_FindContext(BOOL fByKeyContainer, DWORD *dwResult);
+char *DigiCrypt_FindContext_GetCSPName(void);
+char *DigiCrypt_FindContext_GetKeyName(void);
+DWORD DigiCrypt_FindContext_GetCSPType(char *psCSPName);
+void LOG(char *psMsgFmt, ...);
+
+#ifdef __cplusplus
+}
+#endif
+#endif \ No newline at end of file
diff --git a/libdigidoc/DigiDocCert.c b/libdigidoc/DigiDocCert.c
new file mode 100644
index 0000000..3d248bd
--- /dev/null
+++ b/libdigidoc/DigiDocCert.c
@@ -0,0 +1,1981 @@
+//==================================================
+// FILE: DigiDocCert.c
+// PROJECT: Digi Doc
+// DESCRIPTION: Digi Doc functions for certificate handling
+// AUTHOR: Veiko Sinivee, S|E|B IT Partner Estonia
+//==================================================
+// Copyright (C) AS Sertifitseerimiskeskus
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+// GNU Lesser General Public Licence is available at
+// http://www.gnu.org/copyleft/lesser.html
+//==========< HISTORY >=============================
+// 09.09.2004 Veiko Sinivee
+// Creation
+//==================================================
+
+#include <libdigidoc/DigiDocDefs.h>
+#include <libdigidoc/DigiDocCert.h>
+#include <libdigidoc/DigiDocConvert.h>
+#include <libdigidoc/DigiDocLib.h>
+#include <libdigidoc/DigiDocError.h>
+#include <libdigidoc/DigiDocDebug.h>
+#include <libdigidoc/DigiDocMem.h>
+#include <libdigidoc/DigiDocOCSP.h>
+
+#include <openssl/sha.h>
+#include <openssl/rsa.h>
+#include <openssl/evp.h>
+#include <openssl/objects.h>
+#include <openssl/x509.h>
+#include <openssl/x509v3.h>
+#include <openssl/err.h>
+#include <openssl/pem.h>
+#include <openssl/ssl.h>
+#include <openssl/ocsp.h>
+#include <openssl/pkcs12.h>
+#include <openssl/rand.h>
+#include <string.h>
+
+//==========< forward declarations >====================
+
+extern int createOCSPRequest(SignedDoc* pSigDoc, OCSP_REQUEST **req,
+ X509 *cert, X509 *pCA, byte* nonce, int nlen);
+extern int signOCSPRequestPKCS12(OCSP_REQUEST *req, const char* filename, const char* passwd);
+
+extern int verifyOCSPResponse(OCSP_RESPONSE* pResp,
+ const X509** caCerts, const char *CApath,
+ const X509* notCert);
+extern int hasUmlauts(const char* str);
+extern int checkNonceAndCertbyOCSP(OCSP_RESPONSE* resp, X509* cert, byte* nonce1, int nonceLen);
+
+
+//==========< utility functions >====================
+
+
+//--------------------------------------------------
+// Reads a certificate file
+// certfile - name of the certificate file
+//--------------------------------------------------
+EXP_OPTION int ReadCertificate(X509 **x509, const char *szCertfile)
+{
+ BIO *in;
+
+ RETURN_IF_NULL_PARAM(szCertfile);
+ if((in = BIO_new_file(szCertfile, "rb")) != NULL) {
+ *x509 = PEM_read_bio_X509(in, NULL, NULL, 0);
+ BIO_free(in);
+ if(!*x509) SET_LAST_ERROR_RETURN_CODE(ERR_NULL_CERT_POINTER);
+ } else
+ SET_LAST_ERROR_RETURN_CODE(ERR_FILE_READ);
+ return ERR_OK;
+}
+
+//--------------------------------------------------
+// Reads a certificate file
+// certfile - name of the certificate file
+//--------------------------------------------------
+EXP_OPTION int ReadCertificateNoErr(X509 **x509, const char *szCertfile)
+{
+ BIO *in;
+
+ RETURN_IF_NULL_PARAM(szCertfile);
+ if((in = BIO_new_file(szCertfile, "rb")) != NULL) {
+ *x509 = PEM_read_bio_X509(in, NULL, NULL, 0);
+ BIO_free(in);
+ if(!*x509) return ERR_NULL_CERT_POINTER;
+ } else
+ return ERR_FILE_READ;
+ return ERR_OK;
+}
+
+
+//--------------------------------------------------
+// Reads a certificate from pkcs12 conteiner
+//--------------------------------------------------
+EXP_OPTION int ReadCertificateByPKCS12(X509 **x509, const char *pkcs12file, const char *passwd, EVP_PKEY **pkey)
+{
+ BIO *bio;
+ PKCS12 *p12;
+
+ //memset(debugBuf,0,sizeof(debugBuf));
+ RETURN_IF_NULL_PARAM(pkcs12file);
+ bio=BIO_new_file(pkcs12file, "rb");
+ RETURN_IF_NULL(bio);
+ p12 = d2i_PKCS12_bio(bio, NULL);
+ BIO_free(bio);
+ RETURN_IF_NOT(p12, ERR_OCSP_PKCS12_CONTAINER);
+ PKCS12_parse(p12, passwd, pkey, x509, NULL);
+ // Hack: clear PKCS12_parse error "ERROR: 185073780 - error:0B080074:x509 certificate routines:X509_check_private_key:key values mismatch
+ ERR_get_error();
+ PKCS12_free(p12);
+
+ RETURN_IF_NOT(*x509, ERR_OCSP_PKCS12_CONTAINER);
+ return ERR_OK;
+}
+
+//--------------------------------------------------
+// Reads certificates serial number
+// szSerial - buffer for serial number
+// nMaxLen - maximum serial number buffer length
+// certfile - name of the certificate file
+//--------------------------------------------------
+EXP_OPTION int GetCertSerialNumber(char *szSerial, int nMaxLen, const char *szCertfile)
+{
+ BIO *in;
+ X509 *x509;
+
+ RETURN_IF_NULL_PARAM(szSerial);
+ RETURN_IF_NULL_PARAM(szCertfile);
+ if((in = BIO_new_file(szCertfile, "rb")) != NULL) {
+ x509 = PEM_read_bio_X509(in, NULL, NULL, 0);
+ BIO_free(in);
+ RETURN_IF_NOT(x509, ERR_NULL_CERT_POINTER);
+ ReadCertSerialNumber(szSerial, nMaxLen, x509);
+ X509_free(x509);
+ }
+ else
+ SET_LAST_ERROR_RETURN_CODE(ERR_FILE_READ);
+ return ERR_OK;
+}
+
+//--------------------------------------------------
+// Reads certificates serial number
+// x509 - certificate object
+//--------------------------------------------------
+int ReadCertSerialNumber(char* szSerial, int nMaxLen, X509 *x509)
+{
+ ASN1_INTEGER *bs = NULL;
+ BIGNUM* bn;
+ char* str;
+ int err = ERR_OK;
+
+ RETURN_IF_NOT(x509, ERR_NULL_CERT_POINTER);
+ RETURN_IF_NOT(szSerial, ERR_NULL_POINTER);
+ bs = X509_get_serialNumber(x509);
+ RETURN_IF_NOT(bs, ERR_NULL_SER_NUM_POINTER);
+ bn = ASN1_INTEGER_to_BN(bs, NULL);
+ RETURN_IF_NOT(bn, ERR_NULL_SER_NUM_POINTER);
+ str = BN_bn2dec(bn);
+ RETURN_IF_NOT(str, ERR_NULL_SER_NUM_POINTER);
+ memset(szSerial, 0, nMaxLen);
+ strncpy(szSerial, str, nMaxLen -1);
+ if(strlen(str) > (unsigned int)nMaxLen) {
+ err = ERR_BUF_LEN;
+ SET_LAST_ERROR(ERR_BUF_LEN);
+ }
+ //AM 28.05.08 bn should be freed too
+ if(bn)
+ BN_free(bn);
+ OPENSSL_free(str);
+ checkErrors();
+ return err;
+}
+
+
+
+//--------------------------------------------------
+// Reads a public key file
+// certfile - name of the certificate file
+//--------------------------------------------------
+int ReadPublicKey(EVP_PKEY **PublicKey, const char *szCertfile)
+{
+ EVP_PKEY *pkey = NULL;
+ X509 *x509 = NULL;
+ int err = ERR_OK;
+
+ RETURN_IF_NULL_PARAM(szCertfile);
+ RETURN_IF_NULL_PARAM(PublicKey); // SVEN - ver 1.92 - crashbug fixed
+ if((err = ReadCertificate(&x509, szCertfile)) == ERR_OK) {
+ pkey = X509_extract_key(x509);
+ X509_free(x509);
+ RETURN_IF_NOT(pkey, ERR_NULL_KEY_POINTER);
+ *PublicKey = pkey;
+ return ERR_OK;
+ } else
+ SET_LAST_ERROR_RETURN_CODE(err);
+}
+
+
+//--------------------------------------------------
+// Reads a public key file
+// certfile - name of the certificate file
+//--------------------------------------------------
+int GetPublicKey(EVP_PKEY **pubKey, const X509* x509)
+{
+ EVP_PKEY *pkey = NULL;
+
+ RETURN_IF_NULL_PARAM(x509);
+ // SET_LAST_ERROR_RETURN_IF_NOT(x509, ERR_NULL_CERT_POINTER, pkey);
+ // pkey = X509_extract_key((X509*)x509);
+ pkey = X509_get_pubkey((X509*)x509);
+ RETURN_IF_NOT(pkey, ERR_NULL_KEY_POINTER);
+ *pubKey = pkey;
+ return ERR_OK;
+}
+
+
+//--------------------------------------------------
+// Callback routine for passing key password
+//--------------------------------------------------
+int pemkey_callback(char *buf, int size, int rwflag, void *userdata)
+{
+ RETURN_OBJ_IF_NULL(buf, 0);
+ RETURN_OBJ_IF_NULL(userdata, 0);
+ memset(buf, 0, size);
+ strncpy(buf, (char*)userdata, size);
+ return strlen(buf);
+}
+
+
+//--------------------------------------------------
+// Reads a private key file
+// keyfile - name of the private key file
+// passwd - key password (problems with encrypted passwwords!)
+// format - file format (PEM or DER)
+//--------------------------------------------------
+EXP_OPTION int ReadPrivateKey(EVP_PKEY **privKey, const char *keyfile, const char* passwd, int format)
+{
+ BIO *in;
+ EVP_PKEY *pkey = NULL;
+
+ RETURN_IF_NULL_PARAM(keyfile);
+ RETURN_IF_NULL_PARAM(passwd);
+ if((in = BIO_new_file(keyfile, "rb")) != NULL) {
+ switch(format) {
+ case FILE_FORMAT_ASN1:
+ pkey = d2i_PrivateKey_bio(in,NULL);
+ break;
+ case FILE_FORMAT_PEM:
+ PEM_read_bio_PrivateKey(in, &pkey, pemkey_callback, (void*)passwd);
+ break;
+ }
+ BIO_free(in);
+ RETURN_IF_NOT(pkey, ERR_NULL_KEY_POINTER);
+ *privKey = pkey;
+ }
+ else
+ SET_LAST_ERROR_RETURN_CODE(ERR_FILE_READ);
+ return ERR_OK;
+}
+
+//--------------------------------------------------
+// Writes a private key file
+// keyfile - name of the private key file
+// passwd - key password (problems with encrypted passwwords!)
+// format - file format (PEM or DER)
+//--------------------------------------------------
+EXP_OPTION int WritePrivateKey(EVP_PKEY *privKey, const char *keyfile, const char* passwd, int format)
+{
+ BIO *out = NULL;
+ EVP_PKEY *pkey = privKey;
+
+ RETURN_IF_NULL_PARAM(privKey);
+ RETURN_IF_NULL_PARAM(keyfile);
+ if((out = BIO_new_file(keyfile, "wb")) != NULL) {
+ switch(format) {
+ case FILE_FORMAT_ASN1:
+ i2d_PUBKEY_bio(out, pkey);
+ break;
+ case FILE_FORMAT_PEM:
+ PEM_write_bio_PrivateKey(out, pkey, (passwd ? EVP_des_ede3_cbc() : NULL),
+ (unsigned char*)passwd, strlen(passwd), pemkey_callback, (void*)passwd) ;
+ break;
+ }
+ BIO_free(out);
+ }
+ else
+ SET_LAST_ERROR_RETURN_CODE(ERR_FILE_WRITE);
+ return ERR_OK;
+}
+
+//--------------------------------------------------
+// Writes a private key and cert to a PEM file
+// privKey - private key
+// pCert - certificate
+// keyfile - name of the private key file
+// passwd - key password (problems with encrypted passwwords!)
+//--------------------------------------------------
+EXP_OPTION int ddocWriteKeyAndCertPem(EVP_PKEY *privKey, X509* pCert,
+ const char *keyfile, const char* passwd)
+{
+ BIO *out = NULL;
+
+ RETURN_IF_NULL_PARAM(pCert);
+ RETURN_IF_NULL_PARAM(privKey);
+ RETURN_IF_NULL_PARAM(keyfile);
+ if((out = BIO_new_file(keyfile, "wb")) != NULL) {
+ PEM_write_bio_X509(out, pCert);
+ PEM_write_bio_PrivateKey(out, privKey, (passwd ? EVP_des_ede3_cbc() : NULL),
+ (unsigned char*)passwd, (passwd ? strlen(passwd) : 0), pemkey_callback, (void*)passwd);
+ BIO_free(out);
+ }
+ else
+ SET_LAST_ERROR_RETURN_CODE(ERR_FILE_WRITE);
+ return ERR_OK;
+}
+
+
+
+//--------------------------------------------------
+// Reads an RSA private key file
+// keyfile - name of the private key file
+// passwd - key password (problems with encrypted passwwords!)
+// format - file format (PEM or DER)
+//--------------------------------------------------
+int ReadRSAPrivateKey(RSA **privKey, const char *keyfile, const char* passwd, int format)
+{
+
+ BIO *in = 0;
+ RSA *pkey = 0;
+
+ RETURN_IF_NULL_PARAM(keyfile);
+ RETURN_IF_NULL_PARAM(passwd);
+ if((in = BIO_new_file(keyfile, "rb")) != 0) {
+ switch(format) {
+ case FILE_FORMAT_ASN1:
+ pkey = d2i_RSAPrivateKey_bio(in,NULL);
+ break;
+ case FILE_FORMAT_PEM:
+ PEM_read_bio_RSAPrivateKey(in, &pkey, pemkey_callback, (void*)passwd);
+ break;
+ }
+ BIO_free(in);
+ RETURN_IF_NOT(pkey, ERR_NULL_KEY_POINTER);
+ *privKey = pkey;
+ }
+ else
+ SET_LAST_ERROR_RETURN_CODE(ERR_FILE_READ);
+ return ERR_OK;
+}
+
+//--------------------------------------------------
+// Verifys a certificate by sending an OCSP_REQUEST object
+// to the notary server and checking the response.
+// Uses servers timestamps hash code as nonce value.
+// pCert - certificate to test
+// caCerts - responder CA certs chain
+// notaryCert - notarys cert search
+// proxyHost - proxy servers name
+// proxyPort - proxy servers port
+// notaryURL - notarys URL
+// ppResp - address to return OCSP response. Use NULL if
+// you don't want OCSP response to be returned
+// return 0 for OK, or error code
+//--------------------------------------------------
+EXP_OPTION int verifyCertificateByOCSP(X509* pCert, const X509** caCerts,
+ const X509* notaryCert, char* notaryURL,
+ char* proxyHost, char* proxyPort,
+ const char* pkcs12file, const char* pkcs12paswd,
+ OCSP_RESPONSE **ppResp)
+{
+ return verifyCertificateByOCSPWithIp(pCert, caCerts, notaryCert,
+ notaryURL, proxyHost, proxyPort, pkcs12file, pkcs12paswd, ppResp, 0);
+}
+
+//--------------------------------------------------
+// Verifys a certificate by sending an OCSP_REQUEST object
+// to the notary server and checking the response.
+// Uses servers timestamps hash code as nonce value.
+// pCert - certificate to test
+// caCerts - responder CA certs chain
+// notaryCert - notarys cert search
+// proxyHost - proxy servers name
+// proxyPort - proxy servers port
+// notaryURL - notarys URL
+// ppResp - address to return OCSP response. Use NULL if
+// you don't want OCSP response to be returned
+// return 0 for OK, or error code
+//--------------------------------------------------
+EXP_OPTION int verifyCertificateByOCSPWithIp(X509* pCert, const X509** caCerts,
+ const X509* notaryCert, char* notaryURL,
+ char* proxyHost, char* proxyPort,
+ const char* pkcs12file, const char* pkcs12paswd,
+ OCSP_RESPONSE **ppResp, unsigned long ip)
+
+{
+ OCSP_REQUEST *req = 0;
+ OCSP_RESPONSE *resp = 0;
+ int err = ERR_OK, l1, i;
+ byte nonce1[DIGEST_LEN+2];
+ time_t tNow;
+ X509* pCA = NULL;
+
+ RETURN_IF_NULL(pCert);
+ //RETURN_IF_NULL(notaryCert);
+ //RETURN_IF_NULL(caCerts);
+ RETURN_IF_NULL(notaryURL);
+
+ // mark as not found yet
+ if(ppResp)
+ *ppResp = 0;
+ time(&tNow);
+ l1 = sizeof(nonce1);
+ calculateDigest((const byte*)&tNow, sizeof(tNow), DIGEST_SHA1, nonce1, &l1);
+ // find lowest CA
+ for(i = 0; (caCerts != NULL) && (caCerts[i] != NULL); i++)
+ pCA = (X509*)caCerts[i];
+ err = createOCSPRequest(NULL, &req, pCert, pCA, nonce1, l1);
+ if(err == ERR_OK && pkcs12file)
+ err = signOCSPRequestPKCS12(req, pkcs12file, pkcs12paswd);
+ if(err == ERR_OK) {
+ //WriteOCSPRequest("test1.req", req);
+ err = sendOCSPRequest(&resp, req, notaryURL, proxyHost, proxyPort, ip);
+ //WriteOCSPResponse("test1.resp", resp);
+ //printf("sendOCSPRequest returned %d\n", err);
+ if(err == ERR_OK) {
+ if(caCerts && notaryCert) {
+ ddocDebug(1, "verifyCertificateByOCSPWithIp", "Verify OCSP resp with known CA certs");
+ // check the response signature
+ err = verifyOCSPResponse(resp, (const X509**)caCerts, NULL, notaryCert);
+ }
+ if(err == ERR_OK)
+ err = checkNonceAndCertbyOCSP(resp, pCert, nonce1, l1);
+ //WriteOCSPResponse("test1.resp", resp);
+ }
+ }
+ // free OCSP request, if allocated;
+ if (req)
+ OCSP_REQUEST_free(req);
+ // return OCSP response if required
+ if(ppResp)
+ *ppResp = resp;
+ else
+ OCSP_RESPONSE_free(resp);
+ return err;
+}
+
+//============================================================
+// Decodes binary (DER) cert data and returns a cert object
+// certData - binary (DER) cert data
+// certLen - cert data length
+//============================================================
+EXP_OPTION int ddocDecodeX509Data(X509 **ppX509, const byte* certData, int certLen)
+{
+ BIO* b1 = NULL;
+
+ // check input params
+ RETURN_IF_NULL_PARAM(certData);
+ RETURN_IF_NULL_PARAM(ppX509);
+ // mark as not read yet
+ *ppX509 = 0;
+ // create memory BIO on it
+ b1 = BIO_new_mem_buf((void*)certData, certLen);
+ RETURN_IF_NOT(b1, ERR_CERT_INVALID);
+ *ppX509 = d2i_X509_bio(b1, NULL);
+ ddocDebug(4, "ddocDecodeX509Data", "Decoding %d bytes DER data - cert %s", certLen, (*ppX509 ? "OK" : "ERROR"));
+ // cleanup
+ BIO_free(b1);
+ RETURN_IF_NOT(*ppX509, ERR_CERT_INVALID);
+ return ERR_OK;
+}
+
+//============================================================
+// Decodes base64 (PEM) cert data and returns a cert object
+// certData - base64 (PEM) cert data
+// certLen - cert data length
+//============================================================
+EXP_OPTION int ddocDecodeX509PEMData(X509 **ppX509, const char* certData, int certLen)
+{
+ byte* p1 = 0;
+ int l1 = 0, err = ERR_OK;
+
+ // check input params
+ RETURN_IF_NULL_PARAM(certData);
+ RETURN_IF_NULL_PARAM(ppX509);
+ // mark as not read yet
+ *ppX509 = 0;
+ // allocate memory for decoding
+ l1 = certLen; // should be enough as it shrinks
+ p1 = (byte*)malloc(l1);
+ RETURN_IF_BAD_ALLOC(p1);
+ memset(p1, 0, l1);
+ // decode base64 data
+ decode((const byte*)certData, certLen, p1, &l1);
+ // decode cert
+ err = ddocDecodeX509Data(ppX509, p1, l1);
+ ddocDebug(4, "ddocDecodeX509PEMData",
+ "Decoding %d bytes PEM data - cert %s", certLen, (*ppX509 ? "OK" : "ERROR"));
+ // cleanup
+ if(p1)
+ free(p1);
+ return err;
+}
+
+//============================================================
+// Checks if the cert is valid (between begin and end date)
+// cert - certificate object
+// tDate - date to check the cert
+//============================================================
+EXP_OPTION int isCertValid(X509* cert, time_t tDate)
+{
+ int err = ERR_OK;
+ ASN1_TIME *tm = 0;
+ time_t tStart, tEnd;
+
+ RETURN_IF_NULL_PARAM(cert);
+ tm = X509_get_notBefore(cert);
+ RETURN_IF_NULL(tm);
+ asn1time2time_t_local(tm, &tStart);
+ tm = X509_get_notAfter(cert);
+ RETURN_IF_NULL(tm);
+ asn1time2time_t_local(tm, &tEnd);
+ if(tDate < tStart || tDate > tEnd) {
+ err = ERR_CERT_INVALID;
+ SET_LAST_ERROR(err);
+ }
+ return err;
+}
+
+//============================================================
+// Retrieves the certificates first validity time as tim_t in GMT zone
+// pCert - certificate object
+// returns certificates first validity time as tim_t in GMT zone
+//============================================================
+EXP_OPTION time_t getCertNotBeforeTimeT(X509* pCert)
+{
+ time_t t1 = 0;
+ ASN1_TIME *tm = 0;
+
+ if(pCert) {
+ tm = X509_get_notBefore(pCert);
+ if(tm)
+ asn1time2time_t_local(tm, &t1);
+ }
+ return t1;
+}
+
+//============================================================
+// Retrieves the certificates last validity time as tim_t in GMT zone
+// pCert - certificate object
+// returns certificates last validity time as tim_t in GMT zone
+//============================================================
+EXP_OPTION time_t getCertNotAfterTimeT(X509* pCert)
+{
+ time_t t1 = 0;
+ ASN1_TIME *tm = 0;
+
+ if(pCert) {
+ tm = X509_get_notAfter(pCert);
+ if(tm)
+ asn1time2time_t_local(tm, &t1);
+ }
+ return t1;
+}
+
+//============================================================
+// Checks if the cert has been signed by this CA-cert
+// cert - certificate object
+// cafile - CA cert file
+//============================================================
+EXP_OPTION int isCertSignedBy(X509* cert, const char* cafile)
+{
+ int err = ERR_OK;
+ EVP_PKEY* pubkey = NULL; // SVEN - ver 1.92 - crashbug fixed
+
+ (void)ReadPublicKey(&pubkey, cafile);
+ RETURN_IF_NOT(pubkey, ERR_PUBKEY_READ);
+
+ err = X509_verify(cert, pubkey);
+ if(err == ERR_LIB_NONE)
+ err = ERR_OK;
+ else {
+ err = ERR_CERT_ISSUER;
+ SET_LAST_ERROR(err);
+ }
+ // checkErrors();
+ //332:error:0D0890A1:lib(13):func(137):reason(161):.\crypto\asn1\a_verify.c:141:
+ EVP_PKEY_free(pubkey);
+ return err;
+}
+
+//============================================================
+// Writes cert to file without the usual PEM headers
+// bout - output file
+// cert - certificate object
+// returns error code
+//============================================================
+int writeCertToXMLFile(BIO* bout, X509* cert)
+{
+ int l1, l2;
+ char *p1, *p2;
+
+ RETURN_IF_NULL_PARAM(bout);
+ RETURN_IF_NULL_PARAM(cert);
+ l1 = i2d_X509(cert, NULL);
+ p1 = (char*)malloc(l1+10);
+ RETURN_IF_BAD_ALLOC(p1);
+ p2 = p1;
+ i2d_X509(cert, (unsigned char**)&p2);
+ l2 = l1 * 2;
+ p2 = (char*)malloc(l2);
+ if (p2 == NULL) {
+ free(p1);
+ RETURN_IF_BAD_ALLOC(p2);
+ }
+ encode((const byte*)p1, l1, (byte*)p2, &l2);
+ BIO_puts(bout, p2);
+ free(p2);
+ free(p1);
+ return ERR_OK;
+}
+
+//============================================================
+// Converts the certificate to PEM form with or without headers
+// cert - certificate object
+// bHeaders - 1= with headers, 0=no headers
+// buf - output buffer newly allocated
+// returns error code
+//============================================================
+EXP_OPTION int getCertPEM(X509* cert, int bHeaders, char** buf)
+{
+ int l1, l2;
+ char *p1, *p2;
+
+ RETURN_IF_NULL_PARAM(buf);
+ RETURN_IF_NULL_PARAM(cert);
+ l1 = i2d_X509(cert, NULL);
+ p1 = (char*)malloc(l1+10);
+ RETURN_IF_BAD_ALLOC(p1);
+ p2 = p1;
+ i2d_X509(cert, (unsigned char**)&p2);
+ l2 = l1 * 2 + 200;
+ *buf = (char*)malloc(l2);
+ if(*buf == NULL) {
+ free(p1);
+ RETURN_IF_BAD_ALLOC(*buf);
+ }
+ memset(*buf, 0, l2);
+ if(bHeaders)
+ strncpy(*buf, "-----BEGIN CERTIFICATE-----\n", l2);
+ encode((const byte*)p1, l1, (byte*)strchr(*buf, 0), &l2);
+ l2 = l1 * 2 + 200 - strlen(*buf);
+ if(bHeaders)
+ strncat(*buf, "\n-----END CERTIFICATE-----", l2);
+ free(p1);
+ return ERR_OK;
+}
+
+
+
+//--------------------------------------------------
+// Returns the certificates validity first date
+// cert - certificate data
+// timestamp - timestamp buffer
+// returns error code or ERR_OK
+//--------------------------------------------------
+EXP_OPTION int getCertNotBefore(const SignedDoc* pSigDoc, X509* cert, char* timestamp, int len)
+{
+ int err = ERR_OK;
+ ASN1_TIME *tm = 0;
+ RETURN_IF_NULL_PARAM(cert);
+ RETURN_IF_NULL_PARAM(timestamp);
+
+ tm = X509_get_notBefore(cert);
+ RETURN_IF_NULL(tm);
+ err = asn1time2strYear(pSigDoc, tm, timestamp, 1900, len);
+
+ if (err != ERR_OK) SET_LAST_ERROR(err);
+ return err;
+}
+
+
+//--------------------------------------------------
+// Returns the certificates validity last date
+// cert - certificate data
+// timestamp - timestamp buffer
+// returns error code or ERR_OK
+//--------------------------------------------------
+EXP_OPTION int getCertNotAfter(const SignedDoc* pSigDoc, X509* cert, char* timestamp, int len)
+{
+ int err = ERR_OK;
+ ASN1_TIME *tm = 0;
+
+ RETURN_IF_NULL_PARAM(cert);
+ RETURN_IF_NULL_PARAM(timestamp);
+
+ tm = X509_get_notAfter(cert);
+ RETURN_IF_NULL(tm);
+ err = asn1time2strYear(pSigDoc, tm, timestamp, 1900, len);
+
+ if (err != ERR_OK) SET_LAST_ERROR(err);
+ return err;
+}
+
+
+//--------------------------------------------------
+// Saves the certificate in a file
+// cert - certificate data
+// szFileName - destination filename
+// nFormat - cert format
+// returns error code or ERR_OK
+//--------------------------------------------------
+EXP_OPTION int saveCert(X509* cert, const char* szFileName, int nFormat)
+{
+ // int err = ERR_OK;
+ BIO* b;
+
+ RETURN_IF_NULL_PARAM(cert);
+ RETURN_IF_NULL_PARAM(szFileName);
+
+ if((b = BIO_new_file(szFileName, "w")) != NULL) {
+ if(nFormat == FILE_FORMAT_PEM)
+ PEM_write_bio_X509(b, cert);
+ if(nFormat == FILE_FORMAT_ASN1)
+ i2d_X509_bio(b, cert);
+ BIO_free(b);
+ } else
+ SET_LAST_ERROR_RETURN_CODE(ERR_FILE_WRITE);
+ return ERR_OK;
+}
+
+// new functions for Win client
+
+EXP_OPTION void* decodeCert(const char* pemData)
+{
+ BIO* b1;
+ X509* x509;
+ int l1;
+
+ RETURN_OBJ_IF_NULL(pemData, NULL);
+ l1 = strlen(pemData);
+ b1 = BIO_new_mem_buf((void*)pemData, l1);
+ RETURN_OBJ_IF_NULL(b1, 0);
+ x509 = PEM_read_bio_X509(b1, NULL, NULL, 0);
+ if(!x509)
+ SET_LAST_ERROR(ERR_CERT_READ);
+ // checkErrors();
+ BIO_free(b1);
+ return x509;
+}
+
+
+
+
+//===========================================================
+// Encodes certificate from X509 to binary
+//===========================================================
+EXP_OPTION void encodeCert(const X509* x509, char * encodedCert, int* encodedCertLen)
+{
+ if(x509==NULL){
+ *encodedCertLen = 0;
+ return;
+ }
+ if(encodedCert==NULL){
+ *encodedCertLen = 0;
+ return;
+ }
+ *encodedCertLen = i2d_X509((X509*)x509, NULL);
+ i2d_X509((X509*)x509, (unsigned char**)&encodedCert);
+}
+
+//============================================================
+// Checks if the cert has been signed by this CA-cert
+// cert - certificate object
+// cafile - CA cert file
+//============================================================
+EXP_OPTION int isCertSignedByCERT(const X509* cert, const X509* caCert)
+{
+ int err = ERR_OK;
+ EVP_PKEY* pubkey;
+ DigiDocMemBuf mbuf1, mbuf2, mbuf3;
+
+ mbuf1.pMem = 0;
+ mbuf1.nLen = 0;
+ mbuf2.pMem = 0;
+ mbuf2.nLen = 0;
+ mbuf3.pMem = 0;
+ mbuf3.nLen = 0;
+ RETURN_IF_NULL_PARAM(cert);
+ RETURN_IF_NULL_PARAM(caCert);
+ err = ddocCertGetSubjectCN((X509*)caCert, &mbuf1);
+ err = ddocCertGetSubjectCN((X509*)cert, &mbuf2);
+ err = ddocCertGetIssuerCN((X509*)cert, &mbuf3);
+ ddocDebug(3, "isCertSignedByCERT",
+ "Issuer: %s, Subject: %s, Subjects-issuer: %s",
+ (const char*)mbuf1.pMem, (const char*)mbuf2.pMem,
+ (const char*)mbuf3.pMem);
+ ddocMemBuf_free(&mbuf1);
+ ddocMemBuf_free(&mbuf2);
+ ddocMemBuf_free(&mbuf3);
+ err = GetPublicKey(&pubkey, caCert);
+ if(err == ERR_OK) {
+ err = X509_verify((X509*)cert, pubkey);
+ ddocDebug(3, "isCertSignedByCERT", "verify: %d", err);
+ if(err == ERR_LIB_NONE)
+ err = ERR_OK;
+ else
+ err = ERR_CERT_ISSUER;
+ if(err != ERR_OK) {
+ ddocDebug(3, "isCertSignedByCERT", "Cert not issued by ca verify: %d", err);
+ checkErrors();
+ }
+ EVP_PKEY_free(pubkey);
+ }
+ else
+ err = ERR_PUBKEY_READ;
+ if (err != ERR_OK) SET_LAST_ERROR(err);
+ return err;
+}
+
+
+/*int utc2latin1(const char* data, int len, char* dest)
+{
+ int i, j;
+
+ for(i = j = 0; i < len; i++) {
+ if(data[i]) {
+ dest[j] = data[i];
+ j++;
+ }
+ }
+ dest[j] = 0;
+ return j;
+ }*/
+
+//--------------------------------------------------------
+// Checks if the desired key-usage bit is set on a given cert
+// pCert - certificate
+// nBit - flag index
+// return 1 if bit is set
+//--------------------------------------------------------
+EXP_OPTION int ddocCertCheckKeyUsage(X509 *pCert, int nBit)
+{
+ int crit = -1, extIdx = -1;
+ ASN1_BIT_STRING *keyUsage;
+
+ if(pCert && nBit >= 0 && nBit < 8) {
+ keyUsage = (ASN1_BIT_STRING *)X509_get_ext_d2i(pCert, NID_key_usage, &crit, &extIdx);
+ if(keyUsage) {
+ ddocDebug(3, "ddocCertCheckKeyUsage", "Bit: %d set: %d", nBit, ASN1_BIT_STRING_get_bit(keyUsage, nBit));
+ return ASN1_BIT_STRING_get_bit(keyUsage, nBit);
+ }
+ }
+ return 0;
+}
+
+
+//--------------------------------------------------------
+// Finds and copies a substring from source string that is
+// prefixed by szLabel and terminated by szTerminator
+// szSrc - source string
+// szLabel - prefix of searched string
+// szTerminator - terminator string
+// szDest - found string. Caller must free this mem.
+//--------------------------------------------------------
+int ddocCertCopySubstring(const char* szSrc, const char* szLabel, const char* szTerminator, char** szDest)
+{
+ ptrdiff_t l;
+ char *p1, *p2;
+
+ RETURN_IF_NULL_PARAM(szSrc);
+ RETURN_IF_NULL_PARAM(szLabel);
+ RETURN_IF_NULL_PARAM(szTerminator);
+ RETURN_IF_NULL_PARAM(szDest);
+ *szDest = 0; // mark as empty
+ p1 = strstr(szSrc, szLabel);
+ if(p1) {
+ p1 += strlen(szLabel);
+ p2 = strstr(p1, szTerminator);
+ if(!p2)
+ p2 = strchr(p1, 0);
+ if(p2 && p2 > p1) {
+ l = p2 - p1 + 1;
+ *szDest = (char*)malloc(l);
+ if(*szDest) {
+ memset(*szDest, 0, l);
+ strncpy(*szDest, p1, p2 - p1);
+ }
+ }
+ }
+ return ERR_OK;
+}
+
+EXP_OPTION int readCertPoliciesFromOU(X509* pX509, PolicyIdentifier** pPolicies, int* nPols)
+{
+ DigiDocMemBuf mbuf1;
+ int err = ERR_OK;
+ char *pUri, *pDesc, *pOid;
+ PolicyIdentifier *pTmp;
+
+ RETURN_IF_NULL_PARAM(pX509);
+ RETURN_IF_NULL_PARAM(pPolicies);
+ RETURN_IF_NULL_PARAM(nPols);
+ mbuf1.nLen = 0;
+ mbuf1.pMem = 0;
+ pUri = pDesc = pOid = 0;
+ err = ddocCertGetSubjectOrganizationUnit(pX509, &mbuf1);
+ if(!err && mbuf1.pMem) {
+ err = ddocCertCopySubstring((const char*)mbuf1.pMem, "SP Desc:", "\n", &pDesc);
+ if(!err) {
+ err = ddocCertCopySubstring((const char*)mbuf1.pMem, "SP URI:", "\n", &pUri);
+ if(!err) {
+ err = ddocCertCopySubstring((const char*)mbuf1.pMem, "SP OID:", "\n", &pOid);
+ if(!err && (pDesc || pUri || pOid)) {
+ pTmp = (PolicyIdentifier*)realloc(*pPolicies, sizeof(PolicyIdentifier) * ((*nPols) + 1));
+ if(pTmp) {
+ *pPolicies = pTmp;
+ pTmp = (*pPolicies) + (*nPols);
+ *nPols = (*nPols) + 1;
+ pTmp->szOID = (pOid ? strdup((const char*)pOid) : 0);
+ pTmp->szUserNotice = (pDesc ? strdup((const char*)pDesc) : 0);
+ pTmp->szCPS = (pUri ? strdup((const char*)pUri) : 0);
+ }
+ }
+ free(pOid);
+ }
+ free(pUri);
+ }
+ free(pDesc);
+ }
+ ddocMemBuf_free(&mbuf1);
+ return err;
+}
+
+//--------------------------------------------------
+// Reads certificates PolicyIdentifiers and returns
+// them in a newly allocated structure. Caller must
+// free this, regardless of function return status.
+// pX509 - certificate
+// pPolicies - returned PolicyIdentifiers array
+// nPols - number of returned policies
+//--------------------------------------------------
+EXP_OPTION int readCertPolicies(X509* pX509, PolicyIdentifier** pPolicies, int* nPols)
+{
+ char buf[512], *p;
+ int err = 0, i, k, j, pos, l;
+ PolicyIdentifier *pPol, *pTmp;
+
+ RETURN_IF_NULL_PARAM(pX509);
+ RETURN_IF_NULL_PARAM(pPolicies);
+ RETURN_IF_NULL_PARAM(nPols);
+ *pPolicies = NULL;
+ *nPols = 0;
+ // try read from certificates OU first
+ if(!err)
+ err = readCertPoliciesFromOU(pX509, pPolicies, nPols);
+ // read from usual place
+ pos = X509_get_ext_by_NID(pX509, NID_certificate_policies, -1);
+ if(pos >= 0) {
+ POLICYINFO *pol;
+ STACK_OF(POLICYINFO)* pPols;
+ STACK_OF(POLICYQUALINFO)* pQuals;
+ POLICYQUALINFO* pQual;
+ X509_EXTENSION* pExt = X509_get_ext(pX509, pos);
+ // X509V3_EXT_METHOD *method = X509V3_EXT_get(pExt);
+ //pPols = (STACK*)X509V3_EXT_d2i(pExt);
+ pPols = X509V3_EXT_d2i(pExt);
+ for(i = 0; i < sk_POLICYINFO_num(pPols); i++) {
+ pol = sk_POLICYINFO_value(pPols, i);
+ if(*pPolicies && *nPols) {
+ pTmp = (PolicyIdentifier*)realloc(*pPolicies, sizeof(PolicyIdentifier) * ((*nPols) + 1));
+ if (pTmp != NULL) {
+ *pPolicies = pTmp;
+ *nPols = (*nPols) + 1;
+ pPol = (*pPolicies) + ((*nPols) - 1);
+ } else
+ SET_LAST_ERROR_RETURN_CODE(ERR_BAD_ALLOC);
+ } else {
+ pTmp = (PolicyIdentifier*)malloc(sizeof(PolicyIdentifier));
+ if (pTmp != NULL) {
+ *pPolicies = pTmp;
+ pPol = *pPolicies;
+ *nPols = 1;
+ } else
+ SET_LAST_ERROR_RETURN_CODE(ERR_BAD_ALLOC);
+ }
+ pPol->szCPS = pPol->szOID = pPol->szUserNotice = NULL;
+ // check
+ i2t_ASN1_OBJECT(buf, sizeof(buf), pol->policyid);
+ pPol->szOID = strdup(buf);
+ pQuals = pol->qualifiers;
+ for(k = 0; k < sk_POLICYQUALINFO_num(pQuals); k++) {
+ pQual = sk_POLICYQUALINFO_value(pQuals, k);
+ switch(OBJ_obj2nid(pQual->pqualid)) {
+ case NID_id_qt_cps:
+ pPol->szCPS = strdup((const char*)pQual->d.cpsuri->data);
+ // if strdup fails, szCPS will be NULL
+ break;
+ case NID_id_qt_unotice:
+ ddocDebug(4, "readCertPolicies", "Exptext: %d - \'%s\'",
+ pQual->d.usernotice->exptext->length, pQual->d.usernotice->exptext->data);
+ if(pQual->d.usernotice->exptext) {
+ if(pQual->d.usernotice->exptext->type == V_ASN1_UTF8STRING) {
+ pPol->szUserNotice = strdup((const char*)pQual->d.usernotice->exptext->data);
+ } else {
+ p = 0;
+ l = ASN1_STRING_to_UTF8((unsigned char**)&p, pQual->d.usernotice->exptext);
+ pPol->szUserNotice = strdup(p);
+ OPENSSL_free(p);
+ }
+ /*if(pQual->d.usernotice->exptext->data[0]) {
+ pPol->szUserNotice = strdup((const char*)pQual->d.usernotice->exptext->data);
+ } else {
+ utc2latin1((const char*)pQual->d.usernotice->exptext->data,
+ pQual->d.usernotice->exptext->length, buf);
+ pPol->szUserNotice = strdup(buf);
+ // if strdup fails, szUserNotice will be NULL
+ }*/
+ }
+ if(pQual->d.usernotice->noticeref) {
+ NOTICEREF *ref = pQual->d.usernotice->noticeref;
+ p = 0;
+ l = 0;
+ // calculate the memory required
+ l += strlen((const char*)ref->organization->data) + 1;
+ for(j = 0; j < sk_ASN1_INTEGER_num(ref->noticenos); j++) {
+ ASN1_INTEGER *num;
+ char *tmp;
+ num = sk_ASN1_INTEGER_value(ref->noticenos, j);
+ tmp = i2s_ASN1_INTEGER(NULL, num);
+ l += strlen(tmp) + 2;
+ OPENSSL_free(tmp);
+ }
+ // now alloc mem and copy data
+ l += 10; // alloc with a little extra
+ p = (char*)malloc(l);
+ if(p) {
+ memset(p, 0, l);
+ strncpy(p, (const char*)ref->organization->data, l);
+ strncat(p, " ", l - strlen(p));
+ for(j = 0; j < sk_ASN1_INTEGER_num(ref->noticenos); j++) {
+ ASN1_INTEGER *num;
+ char *tmp;
+ num = sk_ASN1_INTEGER_value(ref->noticenos, j);
+ if (j) strncat(p, ", ", l - strlen(p));
+ tmp = i2s_ASN1_INTEGER(NULL, num);
+ strncat(buf, tmp, sizeof(buf) - strlen(buf));
+ OPENSSL_free(tmp);
+ }
+ pPol->szUserNotice = p;
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ sk_POLICYINFO_pop_free(pPols, POLICYINFO_free);
+ }
+ ddocDebug(4, "readCertPolicies", "End");
+ return err;
+}
+
+
+
+//--------------------------------------------------
+// Frees policy identifiers array
+// pPolicies - PolicyIdentifiers array
+// nPols - number of policies
+//--------------------------------------------------
+EXP_OPTION void PolicyIdentifiers_free(PolicyIdentifier* pPolicies, int nPols)
+{
+ int i;
+ for(i = 0; i < nPols; i++) {
+ free(pPolicies[i].szOID);
+ free(pPolicies[i].szCPS);
+ free(pPolicies[i].szUserNotice);
+ //free(pPolicies[i]);
+ }
+ free(pPolicies);
+}
+
+//--------------------------------------------------
+// Reads certificates extension value
+// pCert - certificate
+// pMemBuf - memory buffer to return data
+// nExt - extension code
+//--------------------------------------------------
+EXP_OPTION int readCertExtData(X509* pCert, DigiDocMemBuf* pMemBuf, int nExt, int nOff)
+{
+ int err = ERR_OK, pos;
+ X509_EXTENSION* pExt;
+/* char buf1[300];
+ int l1;*/
+
+ RETURN_IF_NULL_PARAM(pCert);
+ RETURN_IF_NULL_PARAM(pMemBuf);
+ pMemBuf->pMem = 0;
+ pMemBuf->nLen = 0;
+ pos = X509_get_ext_by_NID(pCert, nExt, -1);
+ if(pos >= 0) {
+ pExt = X509_get_ext(pCert, pos);
+ if(pExt && pExt->value && pExt->value->data) {
+ /* memset(buf1, 0, sizeof(buf1));
+ l1 = sizeof(buf1);
+ bin2hex(pExt->value->data, pExt->value->length, buf1, &l1);
+ ddocDebug(3, "readCertExtData", "Ext: %d len: %d data: %s", nExt, pExt->value->length, buf1);*/
+ if(pExt->value->length > 20 && nOff)
+ //ddocMemAssignData(pMemBuf, ((char*)pExt->value->data) + (pExt->value->length - 20), 20);
+ ddocMemAssignData(pMemBuf, ((char*)pExt->value->data) + nOff, 20);
+ else
+ ddocMemAssignData(pMemBuf, ((char*)pExt->value->data), pExt->value->length);
+ }
+ }
+ return err;
+}
+
+//--------------------------------------------------
+// Reads certificates authority key identifier
+// pCert - certificate
+// pMemBuf - memory buffer to return data
+//--------------------------------------------------
+EXP_OPTION int readAuthorityKeyIdentifier(X509* pCert, DigiDocMemBuf* pMemBuf)
+{
+ int err = ERR_OK;
+ int crit = 0, l1;
+ char *p = 0;
+
+ AUTHORITY_KEYID *pAkid = X509_get_ext_d2i(pCert, NID_authority_key_identifier, &crit, NULL);
+ if(pAkid) {
+ l1 = i2d_ASN1_OCTET_STRING(pAkid->keyid, (unsigned char **)&p);
+ if(l1 > 20)
+ ddocMemAssignData(pMemBuf, p + (l1 - 20), 20);
+ else
+ ddocMemAssignData(pMemBuf, (char*)p, l1);
+ OPENSSL_free(p);
+ AUTHORITY_KEYID_free(pAkid);
+ }
+ return err;
+ //return readCertExtData(pCert, pMemBuf, NID_authority_key_identifier, 5);
+}
+
+//--------------------------------------------------
+// Reads certificates subject key identifier
+// pCert - certificate
+// pMemBuf - memory buffer to return data
+//--------------------------------------------------
+EXP_OPTION int readSubjectKeyIdentifier(X509* pCert, DigiDocMemBuf* pMemBuf)
+{
+ return readCertExtData(pCert, pMemBuf, NID_subject_key_identifier, 2);
+}
+
+
+//--------------------------------------------------
+// Checks if this is a company CPS policy
+// pPolicy - PolicyIdentifier to be checked
+//--------------------------------------------------
+EXP_OPTION int isCompanyCPSPolicy(PolicyIdentifier* pPolicy)
+{
+ //return (strstr(pPolicy->szCPS, "1.3.6.4.1.10015.7") != NULL);
+ if(pPolicy && pPolicy->szCPS)
+ return (strstr(pPolicy->szCPS, "1.3.6.1.4.1.10015.5") != NULL);
+ else
+ return 0;
+}
+
+
+//--------------------------------------------------
+// Returns the certificates sha1 hash.
+// pCert - certificate data
+// pMemBuf - memory buffer object for storing DN
+// returns error code or ERR_OK
+//--------------------------------------------------
+int ddocCertGetDigest(X509* pCert, DigiDocMemBuf* pMemBuf)
+{
+ int err = ERR_OK;
+ unsigned int l1;
+
+ RETURN_IF_NULL_PARAM(pCert);
+ RETURN_IF_NULL_PARAM(pMemBuf);
+ pMemBuf->pMem = 0;
+ pMemBuf->nLen = 0;
+ l1 = 30;
+ err = ddocMemSetLength(pMemBuf, l1);
+ X509_digest(pCert, EVP_sha1(), (unsigned char*)pMemBuf->pMem, &l1);
+ pMemBuf->nLen = l1;
+ return err;
+}
+
+//--------------------------------------------------
+// Returns the certificates public key sha1 hash.
+// pCert - certificate data
+// pMemBuf - memory buffer object for storing DN
+// returns error code or ERR_OK
+//--------------------------------------------------
+int ddocCertGetPubkeyDigest(X509* pCert, DigiDocMemBuf* pMemBuf)
+{
+ int err = ERR_OK;
+ unsigned int l1;
+
+ RETURN_IF_NULL_PARAM(pCert);
+ RETURN_IF_NULL_PARAM(pMemBuf);
+ pMemBuf->pMem = 0;
+ pMemBuf->nLen = 0;
+ l1 = 30;
+ err = ddocMemSetLength(pMemBuf, l1);
+ X509_pubkey_digest(pCert, EVP_sha1(), (unsigned char*)pMemBuf->pMem, &l1);
+ pMemBuf->nLen = l1;
+ return err;
+}
+
+//--------------------------------------------------
+// Returns the certificates subject name sha1 hash.
+// pCert - certificate data
+// pMemBuf - memory buffer object for storing DN
+// returns error code or ERR_OK
+//--------------------------------------------------
+int ddocCertGetSubjectNameDigest(X509* pCert, DigiDocMemBuf* pMemBuf)
+{
+ int err = ERR_OK;
+ unsigned int l1;
+ X509_NAME *iname;
+
+ RETURN_IF_NULL_PARAM(pCert);
+ RETURN_IF_NULL_PARAM(pMemBuf);
+ pMemBuf->pMem = 0;
+ pMemBuf->nLen = 0;
+ l1 = 30;
+ err = ddocMemSetLength(pMemBuf, l1);
+ iname = X509_get_subject_name(pCert);
+ X509_NAME_digest(iname, EVP_sha1(), (unsigned char*)pMemBuf->pMem, &l1);
+ pMemBuf->nLen = l1;
+ return err;
+}
+
+//--------------------------------------------------
+// Returns the certificates issuer name sha1 hash.
+// pCert - certificate data
+// pMemBuf - memory buffer object for storing DN
+// returns error code or ERR_OK
+//--------------------------------------------------
+int ddocCertGetIssuerNameDigest(X509* pCert, DigiDocMemBuf* pMemBuf)
+{
+ int err = ERR_OK;
+ unsigned int l1;
+ X509_NAME *iname;
+
+ RETURN_IF_NULL_PARAM(pCert);
+ RETURN_IF_NULL_PARAM(pMemBuf);
+ pMemBuf->pMem = 0;
+ pMemBuf->nLen = 0;
+ l1 = 30;
+ err = ddocMemSetLength(pMemBuf, l1);
+ iname = X509_get_issuer_name(pCert);
+ X509_NAME_digest(iname, EVP_sha1(), (unsigned char*)pMemBuf->pMem, &l1);
+ pMemBuf->nLen = l1;
+ return err;
+}
+
+//--------------------------------------------------
+// Returns the certificates DN. Internal function.
+// Do not call directly, subject to change
+// pCert - certificate data
+// pMemBuf - memory buffer object for storing DN
+// bIssuer - 1=issuer, 0=subject
+// returns error code or ERR_OK
+//--------------------------------------------------
+int ddocCertGetDN(X509* pCert, DigiDocMemBuf* pMemBuf, int bIssuer)
+{
+ int err = ERR_OK;
+ X509_NAME *pName = 0;
+ X509_NAME_ENTRY *pNe = 0;
+ int i, n, l, t, b = 0;
+ const char *s;
+ unsigned char* p;
+
+ RETURN_IF_NULL_PARAM(pCert);
+ RETURN_IF_NULL_PARAM(pMemBuf);
+
+ // initialize
+ if(pMemBuf->pMem)
+ err = ddocMemBuf_free(pMemBuf);
+ pMemBuf->pMem = 0;
+ pMemBuf->nLen = 0;
+
+ // iterate over name entries
+ if(bIssuer)
+ pName = X509_get_issuer_name(pCert);
+ else
+ pName = X509_get_subject_name(pCert);
+ RETURN_IF_NULL(pName)
+ for(i = 0; (err == ERR_OK) && (i < sk_X509_NAME_ENTRY_num(pName->entries)); i++) {
+ pNe = sk_X509_NAME_ENTRY_value(pName->entries, i);
+ n = OBJ_obj2nid(pNe->object);
+ s = OBJ_nid2sn(n);
+ t = pNe->value->type;
+ // mostly we find here:
+ // V_ASN1_PRINTABLESTRING, V_ASN1_TELETEXSTRING or V_ASN1_BMPSTRING
+ // that we convert to UTF, but V_ASN1_UTF8STRING allready is in UTF8
+ // handle only the enry types we know
+ if(n != NID_undef && s != NULL) {
+ // convert to UTF8 only
+ p = 0;
+ if(t == V_ASN1_UTF8STRING) {
+ p = pNe->value->data;
+ l = pNe->value->length;
+ } else
+ l = ASN1_STRING_to_UTF8(&p, pNe->value);
+ ddocDebug(5, "ddocCertGetDN",
+ "NameEntry nid: %d type: %d len: %d item: %s value: \'%s\'",
+ n, t, l, s, (p ? (const char*)p : "NULL"));
+ // append separator if necessary
+ if(b)
+ err = ddocMemAppendData(pMemBuf, ",", -1); // RFC2253 must use ,
+ else
+ b = 1;
+ // print the entry
+ err = ddocMemAppendData(pMemBuf, s, -1);
+ err = ddocMemAppendData(pMemBuf, "=", -1);
+ err = ddocMemAppendData(pMemBuf, (const char*)p, l);
+ // cleanup
+ if(p && t != V_ASN1_UTF8STRING)
+ OPENSSL_free(p);
+ }
+ ddocDebug(5, "ddocCertGetDN", "Subject: \'%s\' len: %d",
+ (const char*)pMemBuf->pMem, pMemBuf->nLen);
+ } // for
+
+ return err;
+}
+
+//--------------------------------------------------
+// Returns the certificates issuer name.
+// pCert - certificate data
+// pMemBuf - memory buffer object for storing DN
+// returns error code or ERR_OK
+//--------------------------------------------------
+EXP_OPTION int ddocCertGetIssuerDN(X509* pCert, DigiDocMemBuf* pMemBuf)
+{
+ return ddocCertGetDN(pCert, pMemBuf, 1);
+}
+
+
+//--------------------------------------------------
+// Returns the certificates subject name.
+// pCert - certificate data
+// pMemBuf - memory buffer object for storing DN
+// returns error code or ERR_OK
+//--------------------------------------------------
+EXP_OPTION int ddocCertGetSubjectDN(X509* pCert, DigiDocMemBuf* pMemBuf)
+{
+ return ddocCertGetDN(pCert, pMemBuf, 0);
+}
+
+//--------------------------------------------------
+// Returns the certificates DN.
+// Do not call directly, subject to change
+// pCert - certificate data
+// pMemBuf - memory buffer object for storing DN
+// bIssuer - 1=issuer, 0=subject
+// returns error code or ERR_OK
+//--------------------------------------------------
+EXP_OPTION int ddocCertGetDNFromName(X509_NAME* pName, DigiDocMemBuf* pMemBuf)
+{
+ int err = ERR_OK;
+ X509_NAME_ENTRY *pNe = 0;
+ int i, n, l, t, b = 0;
+ const char *s;
+ unsigned char* p;
+
+ RETURN_IF_NULL_PARAM(pMemBuf);
+
+ // initialize
+ if(pMemBuf->pMem)
+ err = ddocMemBuf_free(pMemBuf);
+ pMemBuf->pMem = 0;
+ pMemBuf->nLen = 0;
+
+ for(i = 0; (err == ERR_OK) && (i < sk_X509_NAME_ENTRY_num(pName->entries)); i++) {
+ pNe = sk_X509_NAME_ENTRY_value(pName->entries, i);
+ n = OBJ_obj2nid(pNe->object);
+ s = OBJ_nid2sn(n);
+ t = pNe->value->type;
+ // mostly we find here:
+ // V_ASN1_PRINTABLESTRING, V_ASN1_TELETEXSTRING or V_ASN1_BMPSTRING
+ // that we convert to UTF, but V_ASN1_UTF8STRING allready is in UTF8
+ // handle only the enry types we know
+ if(n != NID_undef && s != NULL) {
+ // convert to UTF8 only
+ p = 0;
+ if(t == V_ASN1_UTF8STRING) {
+ p = pNe->value->data;
+ l = pNe->value->length;
+ } else
+ l = ASN1_STRING_to_UTF8(&p, pNe->value);
+ ddocDebug(5, "ddocCertGetDN",
+ "NameEntry nid: %d type: %d len: %d item: %s value: \'%s\'",
+ n, t, l, s, (p ? (const char*)p : "NULL"));
+ // append separator if necessary
+ if(b)
+ err = ddocMemAppendData(pMemBuf, "/", -1);
+ else
+ b = 1;
+ // print the entry
+ err = ddocMemAppendData(pMemBuf, s, -1);
+ err = ddocMemAppendData(pMemBuf, "=", -1);
+ err = ddocMemAppendData(pMemBuf, (const char*)p, l);
+ // cleanup
+ if(p && t != V_ASN1_UTF8STRING)
+ OPENSSL_free(p);
+ }
+ ddocDebug(5, "ddocCertGetDN", "Subject: \'%s\' len: %d",
+ (const char*)pMemBuf->pMem, pMemBuf->nLen);
+ } // for
+
+ return err;
+}
+
+//--------------------------------------------------
+// Returns the certificates subject name and returns
+// the desired item from it.
+// pCert - certificate data
+// pMemBuf - memory buffer object for storing result
+// nNid - cert name part NID
+// bIssuer - 1=from issuer DN, 0=from subject DN
+// returns error code or ERR_OK
+//--------------------------------------------------
+int ddocCertGetDNPart(X509* pCert, DigiDocMemBuf* pMemBuf, int nNid, int bIssuer)
+{
+ int err = ERR_OK;
+ X509_NAME *pName = 0;
+ X509_NAME_ENTRY *pNe = 0;
+ int i, n, l, t, m, j;
+ const char *s;
+ unsigned char* p = 0;
+
+ RETURN_IF_NULL_PARAM(pCert);
+ RETURN_IF_NULL_PARAM(pMemBuf);
+
+ // initialize
+ if(pMemBuf->pMem)
+ err = ddocMemBuf_free(pMemBuf);
+ pMemBuf->pMem = 0;
+ pMemBuf->nLen = 0;
+
+ // iterate over name entries
+ if(bIssuer)
+ pName = X509_get_issuer_name(pCert);
+ else
+ pName = X509_get_subject_name(pCert);
+ for(i = 0; (err == ERR_OK) && (i < sk_X509_NAME_ENTRY_num(pName->entries)); i++) {
+ pNe = sk_X509_NAME_ENTRY_value(pName->entries, i);
+ n = OBJ_obj2nid(pNe->object);
+ s = OBJ_nid2sn(n);
+ t = pNe->value->type;
+ // mostly we find here:
+ // V_ASN1_PRINTABLESTRING, V_ASN1_TELETEXSTRING or V_ASN1_BMPSTRING
+ // that we convert to UTF, but V_ASN1_UTF8STRING allready is in UTF8
+ // handle only the enry types we know
+ if(n == nNid && s != NULL) {
+ // convert to UTF8 only
+ if(t == V_ASN1_UTF8STRING) {
+ p = pNe->value->data;
+ l = pNe->value->length;
+ } else
+ l = ASN1_STRING_to_UTF8(&p, pNe->value);
+ // test for 0x0
+ m = (p ? strlen(p) : 0);
+ if(m < l && p) {
+ for(j = 0; j < l; j++)
+ if(p[j] == 0)
+ p[j] = ' ';
+ }
+ ddocDebug(5, "ddocCertGetDNPart",
+ "NameEntry type: %d len: %d item: %s value: \'%s\'",
+ t, l, s, (p ? (const char*)p : "NULL"));
+ if(pMemBuf->pMem && strlen(pMemBuf->pMem))
+ ddocMemAppendData(pMemBuf, "\n", -1);
+ err = ddocMemAppendData(pMemBuf, (const char*)p, l);
+ // cleanup
+ if(p && t != V_ASN1_UTF8STRING)
+ OPENSSL_free(p);
+ // continue search
+ }
+ } // for
+
+ return err;
+}
+
+//--------------------------------------------------
+// Returns the certificates subject CN
+// pCert - certificate data
+// pMemBuf - memory buffer object for storing result
+// returns error code or ERR_OK
+//--------------------------------------------------
+EXP_OPTION int ddocCertGetSubjectCN(X509* pCert, DigiDocMemBuf* pMemBuf)
+{
+ return ddocCertGetDNPart(pCert, pMemBuf, NID_commonName, 0);
+}
+
+
+//--------------------------------------------------
+// Returns the certificates issuer CN
+// pCert - certificate data
+// pMemBuf - memory buffer object for storing result
+// returns error code or ERR_OK
+//--------------------------------------------------
+EXP_OPTION int ddocCertGetIssuerCN(X509* pCert, DigiDocMemBuf* pMemBuf)
+{
+ return ddocCertGetDNPart(pCert, pMemBuf, NID_commonName, 1);
+}
+
+
+//--------------------------------------------------
+// Returns the certificates subject first name
+// pCert - certificate data
+// pMemBuf - memory buffer object for storing result
+// returns error code or ERR_OK
+//--------------------------------------------------
+EXP_OPTION int ddocCertGetSubjectFirstName(X509* pCert, DigiDocMemBuf* pMemBuf)
+{
+ return ddocCertGetDNPart(pCert, pMemBuf, NID_firstName, 0);
+}
+
+
+//--------------------------------------------------
+// Returns the certificates subject last name
+// pCert - certificate data
+// pMemBuf - memory buffer object for storing result
+// returns error code or ERR_OK
+//--------------------------------------------------
+EXP_OPTION int ddocCertGetSubjectLastName(X509* pCert, DigiDocMemBuf* pMemBuf)
+{
+ return ddocCertGetDNPart(pCert, pMemBuf, NID_lastName, 0);
+}
+
+
+//--------------------------------------------------
+// Returns the certificates subject personal code
+// pCert - certificate data
+// pMemBuf - memory buffer object for storing result
+// returns error code or ERR_OK
+//--------------------------------------------------
+EXP_OPTION int ddocCertGetSubjectPerCode(X509* pCert, DigiDocMemBuf* pMemBuf)
+{
+ return ddocCertGetDNPart(pCert, pMemBuf, NID_perCode, 0);
+}
+
+//--------------------------------------------------
+// Returns the certificates subject country code
+// pCert - certificate data
+// pMemBuf - memory buffer object for storing result
+// returns error code or ERR_OK
+//--------------------------------------------------
+EXP_OPTION int ddocCertGetSubjectCountryName(X509* pCert, DigiDocMemBuf* pMemBuf)
+{
+ return ddocCertGetDNPart(pCert, pMemBuf, NID_countryName, 0);
+}
+
+//--------------------------------------------------
+// Returns the certificates subject organization
+// pCert - certificate data
+// pMemBuf - memory buffer object for storing result
+// returns error code or ERR_OK
+//--------------------------------------------------
+EXP_OPTION int ddocCertGetSubjectOrganization(X509* pCert, DigiDocMemBuf* pMemBuf)
+{
+ return ddocCertGetDNPart(pCert, pMemBuf, NID_organization, 0);
+}
+
+//--------------------------------------------------
+// Returns the certificates subject organization unit
+// pCert - certificate data
+// pMemBuf - memory buffer object for storing result
+// returns error code or ERR_OK
+//--------------------------------------------------
+EXP_OPTION int ddocCertGetSubjectOrganizationUnit(X509* pCert, DigiDocMemBuf* pMemBuf)
+{
+ return ddocCertGetDNPart(pCert, pMemBuf, NID_organizationUnit, 0);
+}
+
+//--------------------------------------------------
+// Returns the desired item from string rep of DN
+// sDn - certificate DN
+// sId - searched DN part
+// pMBuf - memory buffer object for storing result
+// returns error code or ERR_OK
+//--------------------------------------------------
+int ddocGetDNPartFromString(const char* sDn, const char* sId, DigiDocMemBuf* pMBuf)
+{
+ int err = ERR_OK, j, l;
+ char *p0 = 0, *p1 = 0;
+ char buf1[30];
+
+ RETURN_IF_NULL_PARAM(sDn);
+ RETURN_IF_NULL_PARAM(sId);
+ RETURN_IF_NULL_PARAM(pMBuf);
+ // initialize
+ if(pMBuf->pMem)
+ err = ddocMemBuf_free(pMBuf);
+ pMBuf->pMem = 0;
+ pMBuf->nLen = 0;
+ memset(buf1, 0, sizeof(buf1));
+ snprintf(buf1, sizeof(buf1)-1, "%s=", sId);
+ p0 = strstr(sDn, buf1);
+ if(p0) {
+ p0 += strlen(buf1);
+ p1 = strchr(p0, ',');
+ if(p1) {
+ while(p1 && *(p1-1) == '\\')
+ p1 = strchr(p1, ',');
+ if(p1 && *p1 == ',') p1--;
+ } else {
+ p1 = strchr(p0, '/');
+ if(p1) {
+ while(p1 && *(p1-1) == '\\')
+ p1 = strchr(p1, '/');
+ if(p1 && *p1 == '/') p1--;
+ } else
+ p1 = (char*)sDn + strlen(sDn);
+ }
+ //
+ if(p0 && p1 && (int)(p1 - p0) > 0) {
+ l = (int)(p1 - p0) + 1;
+ ddocMemAppendData(pMBuf, (const char*)p0, l);
+ ((char*)pMBuf->pMem)[l] = 0;
+ }
+ }
+ return err;
+}
+
+//AM 06.03.08
+//--------------------------------------------------
+// Returns the certificates DN. Internal function.
+// Do not call directly, subject to change
+// pCert - certificate data
+// pMemBuf - memory buffer object for storing DN
+// bIssuer - 1=issuer, 0=subject
+// returns error code or ERR_OK
+//--------------------------------------------------
+int bdocCertGetDN(X509* pCert, DigiDocMemBuf* pMemBuf, int bIssuer)
+{
+ int err = ERR_OK;
+ X509_NAME *pName = 0;
+ X509_NAME_ENTRY *pNe = 0;
+ int i, n, l, t, b = 0;
+ const char *s;
+ unsigned char* p;
+
+ RETURN_IF_NULL_PARAM(pCert);
+ RETURN_IF_NULL_PARAM(pMemBuf);
+
+ // initialize
+ if(pMemBuf->pMem)
+ err = ddocMemBuf_free(pMemBuf);
+ pMemBuf->pMem = 0;
+ pMemBuf->nLen = 0;
+
+ // iterate over name entries
+ if(bIssuer)
+ pName = X509_get_issuer_name(pCert);
+ else
+ pName = X509_get_subject_name(pCert);
+ for(i = 0; (err == ERR_OK) && (i < sk_X509_NAME_ENTRY_num(pName->entries)); i++) {
+ pNe = sk_X509_NAME_ENTRY_value(pName->entries, i);
+ n = OBJ_obj2nid(pNe->object);
+ s = OBJ_nid2sn(n);
+ t = pNe->value->type;
+ // mostly we find here:
+ // V_ASN1_PRINTABLESTRING, V_ASN1_TELETEXSTRING or V_ASN1_BMPSTRING
+ // that we convert to UTF, but V_ASN1_UTF8STRING allready is in UTF8
+ // handle only the enry types we know
+ if(n != NID_undef && s != NULL) {
+ // convert to UTF8 only
+ p = 0;
+ if(t == V_ASN1_UTF8STRING) {
+ p = pNe->value->data;
+ l = pNe->value->length;
+ } else
+ l = ASN1_STRING_to_UTF8(&p, pNe->value);
+ ddocDebug(5, "ddocCertGetDN",
+ "NameEntry nid: %d type: %d len: %d item: %s value: \'%s\'",
+ n, t, l, s, (p ? (const char*)p : "NULL"));
+ // append separator if necessary
+ if(b)
+ err = ddocMemAppendData(pMemBuf, ",", -1);
+ else
+ b = 1;
+ // print the entry
+ err = ddocMemAppendData(pMemBuf, s, -1);
+ err = ddocMemAppendData(pMemBuf, "=", -1);
+ err = ddocMemAppendData(pMemBuf, (const char*)p, l);
+ // cleanup
+ if(p && t != V_ASN1_UTF8STRING)
+ OPENSSL_free(p);
+ }
+ ddocDebug(5, "ddocCertGetDN", "Subject: \'%s\' len: %d",
+ (const char*)pMemBuf->pMem, pMemBuf->nLen);
+ } // for
+
+ return err;
+}
+
+//================< deprecated functions> =================================
+
+#ifdef WITH_DEPRECATED_FUNCTIONS
+
+//============================================================
+// Decodes base64 (PEM) cert data and returns a cert object
+// certData - base64 (PEM) cert data
+// certLen - cert data length
+//============================================================
+// FIXME : Ugly as hell...
+#pragma message ("Function decodeCertificateData may be removed from future releases. Please use function ddocDecodeX509PEMData() instead.")
+EXP_OPTION int decodeCertificateData(X509 **newX509, const byte* certData, int certLen)
+{
+ int l1, l2;
+ char *buf1;
+ BIO* b1 = NULL;
+ X509* x509 = NULL;
+
+ RETURN_IF_NULL_PARAM(certData);
+
+ l2 = certLen * 2;
+ buf1 = (char*)malloc(l2);
+ RETURN_IF_BAD_ALLOC(buf1);
+ memset(buf1, 0, l2);
+ strncpy(buf1, "-----BEGIN CERTIFICATE-----\r\n", l2);
+ l1 = l2 - strlen(buf1);
+ encode(certData, certLen, (byte*)strchr(buf1,0), &l1);
+ l1 = l2 - strlen(buf1);
+ strncat(buf1, "\n-----END CERTIFICATE-----", l1);
+ l1 = strlen(buf1);
+ b1 = BIO_new_mem_buf(buf1, l1);
+ if (!b1) {
+ free(buf1);
+ SET_LAST_ERROR_RETURN_CODE(ERR_NULL_POINTER);
+ }
+ x509 = PEM_read_bio_X509(b1, NULL, NULL, 0);
+ BIO_free(b1);
+ free(buf1);
+ RETURN_IF_NOT(x509, ERR_CERT_INVALID);
+
+ *newX509 = x509;
+ return ERR_OK;
+}
+
+//--------------------------------------------------
+// Returns the certificates issuer name
+// cert - certificate data
+// buf - usser name buffer
+// buflen - pointer to buffer length (will be modified)
+// returns error code or ERR_OK
+//--------------------------------------------------
+EXP_OPTION int getCertIssuerName(X509* cert, char* buf, int* buflen)
+{
+ int l1;
+ char buf1[X509_NAME_BUF_LEN];
+
+ RETURN_IF_NULL_PARAM(cert);
+ RETURN_IF_NULL_PARAM(buf);
+ RETURN_IF_NULL_PARAM(buflen);
+
+ if(*buflen >= X509_NAME_LEN) {
+ l1 = sizeof(buf1);
+ memset(buf1,0,l1);
+ memset(buf, 0, *buflen);
+ X509_NAME_oneline(X509_get_issuer_name(cert), buf1, l1);
+ unicode2ascii(buf1, buf);
+ ddocDebug(5, "getCertIssuerName", "Issuer: \'%s\' -> \'%s\'", buf1, buf);
+ *buflen = strlen(buf);
+ } else
+ SET_LAST_ERROR_RETURN_CODE(ERR_BUF_LEN);
+ return ERR_OK;
+}
+
+//--------------------------------------------------
+// Returns the certificates subject name. This finction
+// is also used in the COM library
+// cert - certificate data
+// buf - user name buffer
+// buflen - pointer to buffer length (will be modified)
+// returns error code or ERR_OK
+//--------------------------------------------------
+#pragma message ("Function getCertSubjectName may be removed from future releases. Please use function ddocCertGetSubjectDN() instead.")
+EXP_OPTION int getCertSubjectName(X509* cert, char* buf, int* buflen)
+{
+ int err = ERR_OK;
+ DigiDocMemBuf mbuf;
+
+ mbuf.pMem = 0;
+ mbuf.nLen = 0;
+ err = ddocCertGetSubjectDN(cert, &mbuf);
+ if(err == ERR_OK) {
+ if(*buflen >= X509_NAME_LEN) {
+#ifdef WIN32
+ utf82oem((const char*)mbuf.pMem, buf, buflen);
+#else
+ utf82ascii((const char*)mbuf.pMem, buf, buflen);
+#endif
+ *buflen = strlen(buf);
+ } else
+ SET_LAST_ERROR(ERR_BUF_LEN);
+ ddocMemBuf_free(&mbuf);
+ }
+
+ return err;
+}
+
+//--------------------------------------------------
+// Returns the certificates subjects DN
+// cert - certificate data
+// buf - usser name buffer
+// buflen - pointer to buffer length (will be modified)
+// returns error code or ERR_OK
+//--------------------------------------------------
+EXP_OPTION int getCertSubjectDN(X509* cert, char* buf, int* buflen, int bUTF8)
+{
+ int l1;
+ char buf1[X509_NAME_BUF_LEN];
+
+ RETURN_IF_NULL_PARAM(cert);
+ RETURN_IF_NULL_PARAM(buf);
+ RETURN_IF_NULL_PARAM(buflen);
+ if(*buflen >= X509_NAME_LEN) {
+ l1 = sizeof(buf1);
+ memset(buf1, 0, l1);
+ memset(buf, 0, *buflen);
+ X509_NAME_oneline(X509_get_subject_name(cert), buf1, l1);
+ if (bUTF8) {
+ unicode2ascii(buf1, buf);
+ *buflen = strlen(buf);
+ } else {
+ ascii2utf8(buf1, buf, buflen);
+ }
+ }
+ else
+ SET_LAST_ERROR_RETURN_CODE(ERR_BUF_LEN);
+ return ERR_OK;
+}
+
+
+//--------------------------------------------------
+// Returns the certificates subjects name's CN part
+// cert - certificate data
+// buf - usser name buffer
+// buflen - pointer to buffer length (will be modified)
+// returns error code or ERR_OK
+//--------------------------------------------------
+EXP_OPTION int getCertSubjectCN(X509* cert, char* buf, int* buflen, int bUTF8)
+{
+ int l1, err = ERR_OK;
+ char buf1[X509_NAME_BUF_LEN], *p , *p2, buf2[X509_NAME_BUF_LEN];
+
+ RETURN_IF_NULL_PARAM(cert);
+ RETURN_IF_NULL_PARAM(buf);
+ RETURN_IF_NULL_PARAM(buflen);
+
+ if(*buflen >= X509_NAME_LEN) {
+ l1 = sizeof(buf1);
+ memset(buf1,0,l1);
+ memset(buf, 0, *buflen);
+ err = getCertSubjectName(cert, buf1, &l1);
+ if(bUTF8 && hasUmlauts(buf1)) {
+ //printf("Converting umlauts toi UTF8\n");
+ l1 = sizeof(buf2);
+ ascii2utf8(buf1, buf2, &l1);
+ strncpy(buf1, buf2, sizeof(buf1));
+ ddocDebug(4, "getCertSubjectCN", "Subject: \'%s\'", buf1);
+ }
+ /*if (!bUTF8) {
+ l1 = sizeof(buf2);
+ utf82ascii(buf1, buf2, &l1);
+ //strcpy(buf1, buf2);
+ }*/
+ //printf("SUBJECT: %s\n", buf1);
+ p = strstr(buf1, "CN=");
+ if(p) {
+ p += 3;
+ p2 = strchr(p, '/');
+ if(!p2)
+ p2 = p + strlen(p);
+ if(p2) {
+ strncpy(buf, p, p2-p);
+ buf[p2-p] = 0;
+ }
+ }
+ *buflen = strlen(buf);
+ }
+ else
+ SET_LAST_ERROR_RETURN_CODE(ERR_BUF_LEN);
+ return ERR_OK;
+}
+
+//--------------------------------------------------
+// Returns the certificates issuer name's CN part
+// cert - certificate data
+// buf - usser name buffer
+// buflen - pointer to buffer length (will be modified)
+// returns error code or ERR_OK
+//--------------------------------------------------
+EXP_OPTION int getCertIssuerCN(X509* cert, char* buf, int* buflen, int bUTF8)
+{
+ int l1;
+ char buf1[X509_NAME_BUF_LEN], *p , *p2, buf2[X509_NAME_BUF_LEN];
+
+ RETURN_IF_NULL_PARAM(cert);
+ RETURN_IF_NULL_PARAM(buf);
+ RETURN_IF_NULL_PARAM(buflen);
+
+ if(*buflen >= X509_NAME_LEN) {
+ l1 = sizeof(buf1);
+ memset(buf1,0,l1);
+ memset(buf, 0, *buflen);
+ X509_NAME_oneline(X509_get_issuer_name(cert), buf1, l1);
+ if (bUTF8) {
+ unicode2ascii(buf1, buf2);
+ } else {
+ l1 = sizeof(buf2);
+ ascii2utf8(buf1, buf2, &l1);
+ }
+ //printf("SUBJECT: %s\n", buf2);
+ p = strstr(buf2, "CN=");
+ if(p) {
+ p += 3;
+ p2 = strchr(p, '/');
+ if(!p2)
+ p2 = p + strlen(p);
+ if(p2) {
+ strncpy(buf, p, p2-p);
+ buf[p2-p] = 0;
+ }
+ }
+ *buflen = strlen(buf);
+ }
+ else
+ SET_LAST_ERROR_RETURN_CODE(ERR_BUF_LEN);
+ return ERR_OK;
+}
+
+// get cert owners id-code
+EXP_OPTION int getCertOwnerCode(const X509* pCert, char* buf, int len)
+{
+ int err, l1;
+ char buf1[500], *p;
+
+ RETURN_IF_NULL_PARAM(pCert);
+ RETURN_IF_NULL_PARAM(buf);
+ l1 = sizeof(buf1);
+ err = getCertSubjectName((void*)pCert, buf1, &l1);
+ if (err != ERR_OK) SET_LAST_ERROR_RETURN_CODE(err);
+ err = ERR_CERT_READ;
+ p = strstr(buf1, "CN=");
+ if (p) {
+ p = strchr(p, ',');
+ if(p) {
+ p = strchr(p+1, ',');
+ if(p) {
+ strncpy(buf, p+1, 1en);
+ buf[1en] = 0;
+ err = ERR_OK;
+ }
+ } else { // no comma -> no id-code !
+ buf[0] = 0;
+ // is this really an error ?
+ err = ERR_WRONG_CERT;
+ }
+ }
+ if (err != ERR_OK) SET_LAST_ERROR(err);
+ return err;
+}
+
+
+#endif // WITH_DEPRECATED_FUNCTIONS
diff --git a/libdigidoc/DigiDocCert.h b/libdigidoc/DigiDocCert.h
new file mode 100644
index 0000000..4fd86ff
--- /dev/null
+++ b/libdigidoc/DigiDocCert.h
@@ -0,0 +1,364 @@
+#ifndef __DIGI_DOC_CERT_H__
+#define __DIGI_DOC_CERT_H__
+//==================================================
+// FILE: DigiDocCert.h
+// PROJECT: Digi Doc
+// DESCRIPTION: Digi Doc functions for certificate handling
+// AUTHOR: Veiko Sinivee, S|E|B IT Partner Estonia
+//==================================================
+// Copyright (C) AS Sertifitseerimiskeskus
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.ode
+// GNU Lesser General Public Licence is available at
+// http://www.gnu.org/copyleft/lesser.html
+//==========< HISTORY >=============================
+//==================================================
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <openssl/evp.h>
+#include <openssl/objects.h>
+#include <openssl/x509.h>
+#include <openssl/x509v3.h>
+
+#include <libdigidoc/DigiDocDefs.h>
+#include <libdigidoc/DigiDocLib.h>
+
+// structure for reading certificate policies
+typedef struct PolicyIdentifier_st {
+ char* szOID; // stringified OID
+ char* szCPS; // CPS URL
+ char* szUserNotice; // user notice
+} PolicyIdentifier;
+
+
+EXP_OPTION int ReadPrivateKey(EVP_PKEY **privKey, const char *keyfile, const char* passwd, int format);
+EXP_OPTION int WritePrivateKey(EVP_PKEY *privKey, const char *keyfile, const char* passwd, int format);
+int ReadPublicKey(EVP_PKEY **pkey, const char *certfile);
+int GetPublicKey(EVP_PKEY **pubKey, const X509* x509);
+
+//--------------------------------------------------
+// Writes a private key and cert to a PEM file
+// privKey - private key
+// pCert - certificate
+// keyfile - name of the private key file
+// passwd - key password (problems with encrypted passwwords!)
+//--------------------------------------------------
+EXP_OPTION int ddocWriteKeyAndCertPem(EVP_PKEY *privKey, X509* pCert,
+ const char *keyfile, const char* passwd);
+
+
+EXP_OPTION int ReadCertificate(X509 **x509, const char *certfile);
+EXP_OPTION int ReadCertificateNoErr(X509 **x509, const char *szCertfile);
+EXP_OPTION int ReadCertSerialNumber(char* szSerial, int nMaxLen, X509 *x509);
+EXP_OPTION int ReadCertificateByPKCS12(X509 **x509, const char *pkcs12file, const char *passwd, EVP_PKEY **pkey);
+
+// Decodes binary (DER) cert data and returns a cert object
+EXP_OPTION int ddocDecodeX509Data(X509 **ppX509, const byte* certData, int certLen);
+
+// Decodes base64 (PEM) cert data and returns a cert object
+EXP_OPTION int ddocDecodeX509PEMData(X509 **ppX509, const char* certData, int certLen);
+
+// get certificate PEM form
+EXP_OPTION int getCertPEM(X509* cert, int bHeaders, char** buf);
+
+
+// retrieves this certificates serial number
+EXP_OPTION int GetCertSerialNumber(char* szSerial, int nMaxLen, const char *szCertfile);
+// Returns the certificates validity first date
+EXP_OPTION int getCertNotBefore(const SignedDoc* pSigDoc, X509* cert, char* timestamp, int len);
+
+// Retrieves the certificates first validity time as tim_t in GMT zone
+EXP_OPTION time_t getCertNotBeforeTimeT(X509* pCert);
+// Retrieves the certificates last validity time as tim_t in GMT zone
+EXP_OPTION time_t getCertNotAfterTimeT(X509* pCert);
+
+// Returns the certificates validity last date
+EXP_OPTION int getCertNotAfter(const SignedDoc* pSigDoc, X509* cert, char* timestamp, int len);
+// Saves the certificate in a file
+EXP_OPTION int saveCert(X509* cert, const char* szFileName, int nFormat);
+// decodes PEM cert data
+EXP_OPTION void* decodeCert(const char* pemData);
+// encodes certificate
+EXP_OPTION void encodeCert(const X509* x509, char * encodedCert, int* encodedCertLen);
+
+// Reads certificates PolicyIdentifiers and returns
+// them in a newly allocated structure
+EXP_OPTION int readCertPolicies(X509* pX509, PolicyIdentifier** pPolicies, int* nPols);
+
+// Frees policy identifiers array
+EXP_OPTION void PolicyIdentifiers_free(PolicyIdentifier* pPolicies, int nPols);
+
+// Checks if this is a company CPS policy
+EXP_OPTION int isCompanyCPSPolicy(PolicyIdentifier* pPolicy);
+
+EXP_OPTION int isCertValid(X509* cert, time_t tDate);
+EXP_OPTION int isCertSignedBy(X509* cert, const char* cafile);
+int writeCertToXMLFile(BIO* bout, X509* cert);
+
+//--------------------------------------------------
+// Verifys a certificate by sending an OCSP_REQUEST object
+// to the notary server and checking the response.
+// Uses servers timestamps hash code as nonce value.
+// pCert - certificate to test
+// caCerts - responder CA certs chain
+// notaryCert - notarys cert search
+// proxyHost - proxy servers name
+// proxyPort - proxy servers port
+// notaryURL - notarys URL
+// ppResp - address to return OCSP response. Use NULL if
+// you don't want OCSP response to be returned
+// return 0 for OK, or error code
+//--------------------------------------------------
+EXP_OPTION int verifyCertificateByOCSP(X509* pCert, const X509** caCerts,
+ const X509* notaryCert, char* notaryURL,
+ char* proxyHost, char* proxyPort,
+ const char* pkcs12file, const char* pkcs12paswd,
+ OCSP_RESPONSE **ppResp);
+
+//--------------------------------------------------
+// Verifys a certificate by sending an OCSP_REQUEST object
+// to the notary server and checking the response.
+// Uses servers timestamps hash code as nonce value.
+// pCert - certificate to test
+// caCerts - responder CA certs chain
+// notaryCert - notarys cert search
+// proxyHost - proxy servers name
+// proxyPort - proxy servers port
+// notaryURL - notarys URL
+// ppResp - address to return OCSP response. Use NULL if
+// you don't want OCSP response to be returned
+// return 0 for OK, or error code
+//--------------------------------------------------
+EXP_OPTION int verifyCertificateByOCSPWithIp(X509* pCert, const X509** caCerts,
+ const X509* notaryCert, char* notaryURL,
+ char* proxyHost, char* proxyPort,
+ const char* pkcs12file, const char* pkcs12paswd,
+ OCSP_RESPONSE **ppResp, unsigned long ip);
+
+ //--------------------------------------------------
+ // Returns the certificates sha1 hash.
+ // pCert - certificate data
+ // pMemBuf - memory buffer object for storing DN
+ // returns error code or ERR_OK
+ //--------------------------------------------------
+ int ddocCertGetDigest(X509* pCert, DigiDocMemBuf* pMemBuf);
+
+ //--------------------------------------------------
+ // Returns the certificates public key sha1 hash.
+ // pCert - certificate data
+ // pMemBuf - memory buffer object for storing DN
+ // returns error code or ERR_OK
+ //--------------------------------------------------
+ int ddocCertGetPubkeyDigest(X509* pCert, DigiDocMemBuf* pMemBuf);
+
+ //--------------------------------------------------
+ // Returns the certificates issuer name.
+ // pCert - certificate data
+ // pMemBuf - memory buffer object for storing DN
+ // returns error code or ERR_OK
+ //--------------------------------------------------
+ EXP_OPTION int ddocCertGetIssuerDN(X509* pCert, DigiDocMemBuf* pMemBuf);
+
+ //--------------------------------------------------
+ // Returns the certificates subject name.
+ // pCert - certificate data
+ // pMemBuf - memory buffer object for storing DN
+ // returns error code or ERR_OK
+ //--------------------------------------------------
+ EXP_OPTION int ddocCertGetSubjectDN(X509* pCert, DigiDocMemBuf* pMemBuf);
+
+ //--------------------------------------------------
+ // Returns the certificates subject name sha1 hash.
+ // pCert - certificate data
+ // pMemBuf - memory buffer object for storing DN
+ // returns error code or ERR_OK
+ //--------------------------------------------------
+ int ddocCertGetSubjectNameDigest(X509* pCert, DigiDocMemBuf* pMemBuf);
+
+ //--------------------------------------------------
+ // Returns the certificates issuer name sha1 hash.
+ // pCert - certificate data
+ // pMemBuf - memory buffer object for storing DN
+ // returns error code or ERR_OK
+ //--------------------------------------------------
+ int ddocCertGetIssuerNameDigest(X509* pCert, DigiDocMemBuf* pMemBuf);
+
+ //--------------------------------------------------
+ // Returns the certificates DN.
+ // Do not call directly, subject to change
+ // pName - certificate X509 name
+ // pMemBuf - memory buffer object for storing DN
+ // bIssuer - 1=issuer, 0=subject
+ // returns error code or ERR_OK
+ //--------------------------------------------------
+ EXP_OPTION int ddocCertGetDNFromName(X509_NAME* pName, DigiDocMemBuf* pMemBuf);
+
+#define KUIDX_DIGITAL_SIGNATURE 0
+#define KUIDX_NON_REPUDIATION 1
+#define KUIDX_KEY_ENCIPHERMENT 2
+#define KUIDX_DATA_ENCIPHERMENT 3
+#define KUIDX_KEY_AGREEMENT 4
+#define KUIDX_KEY_CERT_SIGN 5
+#define KUIDX_CRL_SIGN 6
+#define KUIDX_ENCIPHERMENT_ONLY 7
+#define KUIDX_DECIPHERMENT_ONLY 8
+
+#define NID_firstName 99
+#define NID_lastName 100
+#define NID_perCode 105
+#define NID_countryName 14
+#define NID_serialNumber 105
+#define NID_organization 17
+#define NID_organizationUnit 18
+#define NID_commonName 13
+#define NID_emailAddress 48
+
+
+ //--------------------------------------------------------
+ // Checks if the desired key-usage bit is set on a given cert
+ // pCert - certificate
+ // nBit - flag index
+ // return 1 if bit is set
+ //--------------------------------------------------------
+ EXP_OPTION int ddocCertCheckKeyUsage(X509 *pCert, int nBit);
+
+ //--------------------------------------------------
+ // Returns the certificates subject CN
+ // pCert - certificate data
+ // pMemBuf - memory buffer object for storing result
+ // returns error code or ERR_OK
+ //--------------------------------------------------
+ EXP_OPTION int ddocCertGetSubjectCN(X509* pCert, DigiDocMemBuf* pMemBuf);
+
+ //--------------------------------------------------
+ // Returns the certificates issuer CN
+ // pCert - certificate data
+ // pMemBuf - memory buffer object for storing result
+ // returns error code or ERR_OK
+ //--------------------------------------------------
+ EXP_OPTION int ddocCertGetIssuerCN(X509* pCert, DigiDocMemBuf* pMemBuf);
+
+ //--------------------------------------------------
+ // Returns the certificates subject first name
+ // pCert - certificate data
+ // pMemBuf - memory buffer object for storing result
+ // returns error code or ERR_OK
+ //--------------------------------------------------
+ EXP_OPTION int ddocCertGetSubjectFirstName(X509* pCert, DigiDocMemBuf* pMemBuf);
+
+ //--------------------------------------------------
+ // Returns the certificates subject last name
+ // pCert - certificate data
+ // pMemBuf - memory buffer object for storing result
+ // returns error code or ERR_OK
+ //--------------------------------------------------
+ EXP_OPTION int ddocCertGetSubjectLastName(X509* pCert, DigiDocMemBuf* pMemBuf);
+
+ //--------------------------------------------------
+ // Returns the certificates subject personal code
+ // pCert - certificate data
+ // pMemBuf - memory buffer object for storing result
+ // returns error code or ERR_OK
+ //--------------------------------------------------
+ EXP_OPTION int ddocCertGetSubjectPerCode(X509* pCert, DigiDocMemBuf* pMemBuf);
+
+ //--------------------------------------------------
+ // Returns the certificates subject country code
+ // pCert - certificate data
+ // pMemBuf - memory buffer object for storing result
+ // returns error code or ERR_OK
+ //--------------------------------------------------
+ EXP_OPTION int ddocCertGetSubjectCountryName(X509* pCert, DigiDocMemBuf* pMemBuf);
+
+ //--------------------------------------------------
+ // Returns the certificates subject organization
+ // pCert - certificate data
+ // pMemBuf - memory buffer object for storing result
+ // returns error code or ERR_OK
+ //--------------------------------------------------
+ EXP_OPTION int ddocCertGetSubjectOrganization(X509* pCert, DigiDocMemBuf* pMemBuf);
+
+ //--------------------------------------------------
+ // Returns the certificates subject organization unit
+ // pCert - certificate data
+ // pMemBuf - memory buffer object for storing result
+ // returns error code or ERR_OK
+ //--------------------------------------------------
+ EXP_OPTION int ddocCertGetSubjectOrganizationUnit(X509* pCert, DigiDocMemBuf* pMemBuf);
+
+ //--------------------------------------------------
+ // Reads certificates authority key identifier
+ // pCert - certificate
+ // pMemBuf - memory buffer to return data
+ //--------------------------------------------------
+ EXP_OPTION int readAuthorityKeyIdentifier(X509* pCert, DigiDocMemBuf* pMemBuf);
+
+ //--------------------------------------------------
+ // Reads certificates subject key identifier
+ // pCert - certificate
+ // pMemBuf - memory buffer to return data
+ //--------------------------------------------------
+ EXP_OPTION int readSubjectKeyIdentifier(X509* pCert, DigiDocMemBuf* pMemBuf);
+
+//================< deprecated functions> =================================
+// these functions are deprecated. Use the replacements in DigiDocCert.h
+// these functions will be removed in future releases!
+#ifdef WITH_DEPRECATED_FUNCTIONS
+
+// decodes cert data - deprecated!
+// USE ddocDecodeX509PEMData() instead!
+EXP_OPTION int decodeCertificateData(X509 **newX509, const byte* certData, int certLen);
+
+// Returns the certificates issuer name
+// USE: ddocCertGetIssuerDN()
+EXP_OPTION int getCertIssuerName(X509* cert, char* buf, int* buflen);
+
+// Returns the certificates subject name
+// USE: ddocCertGetSubjectDN()
+EXP_OPTION int getCertSubjectName(X509* cert, char* buf, int* buflen);
+
+
+// reads cert issuers CN
+// USE: ddocCertGetIssuerCN()
+EXP_OPTION int getCertIssuerCN(X509* cert, char* buf, int* buflen, int bUTF8);
+
+// Returns the certificates subjects DN
+// USE: ddocCertGetSubjectDN()
+EXP_OPTION int getCertSubjectDN(X509* cert, char* buf, int* buflen, int bUTF8);
+
+// reads cert subjects CN
+// USE: ddocCertGetSubjectCN()
+EXP_OPTION int getCertSubjectCN(X509* cert, char* buf, int* buflen, int bUTF8);
+
+// get certificate owners id-code
+// USE: ddocCertGetSubjectPerCode()
+EXP_OPTION int getCertOwnerCode(const X509* pCert, char* buf, int len);
+
+//--------------------------------------------------
+// Returns the desired item from string rep of DN
+// sDn - certificate DN
+// sId - searched DN part
+// pMBuf - memory buffer object for storing result
+// returns error code or ERR_OK
+//--------------------------------------------------
+EXP_OPTION int ddocGetDNPartFromString(const char* sDn, const char* sId, DigiDocMemBuf* pMBuf);
+
+#endif // WITH_DEPRECATED_FUNCTIONS
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif // __DIGI_DOC_CERT_H__
+
diff --git a/libdigidoc/DigiDocConfig.c b/libdigidoc/DigiDocConfig.c
new file mode 100644
index 0000000..67db4d7
--- /dev/null
+++ b/libdigidoc/DigiDocConfig.c
@@ -0,0 +1,2211 @@
+//==================================================
+// FILE: DigiDocCfonfig.c
+// PROJECT: Digi Doc
+// DESCRIPTION: Digi Doc functions for configuration management
+// AUTHOR: Veiko Sinivee, S|E|B IT Partner Estonia
+//==================================================
+// Copyright (C) AS Sertifitseerimiskeskus
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+// GNU Lesser General Public Licence is available at
+// http://www.gnu.org/copyleft/lesser.html
+//==========< HISTORY >=============================
+// 17.06.2004 Fixed buffer overflow vulnerability in setPrivateConfigFile()
+// 27.03.2004 Fixed ConfigItem_lookup_bool()
+// 20.03.2004 Added functions createOrReplacePrivateConfigItem()
+// writeConfigFile(), writePrivateConfigFile()
+// 20.03.2004 changed function notarizeSignature to check for PKCS12 arguments
+// 10.02.2004 Integrated
+// 29.01.2004 changed function notarizeSignature
+// 26.01.2004 Added <Windows.h> include
+// 08.01.2004 Veiko Sinivee
+// Creation
+//==================================================
+
+// config data comes from there
+#include <config.h>
+
+//AA 04/01/26
+#ifdef WIN32
+#include <windows.h>
+#define snprintf _snprintf
+#elif defined(__APPLE__)
+#include <CoreFoundation/CoreFoundation.h>
+#endif
+
+#include "libdigidoc/DigiDocConfig.h"
+#include "libdigidoc/DigiDocPKCS11.h"
+#include "libdigidoc/DigiDocDebug.h"
+#include "libdigidoc/DigiDocCert.h"
+#include "libdigidoc/DigiDocObj.h"
+#include "libdigidoc/DigiDocOCSP.h"
+#include "libdigidoc/DigiDocConvert.h"
+#ifdef WIN32
+#include "libdigidoc/DigiDocCsp.h"
+#endif
+#include <stdio.h>
+#include <stdlib.h>
+#include <memory.h>
+#include <string.h>
+#include <ctype.h>
+
+#ifndef _MAX_PATH
+ #define _MAX_PATH 200
+#endif
+
+#ifdef WIN32
+ #define DIGIDOC_CONF_NAME "digidoc.ini"
+ #define HOME_ENV "USERPROFILE"
+ #define DIGIDOC_CONF_FMT "%s\\%s"
+ char g_szGlobalConfigFile[_MAX_PATH];
+#else
+ #define DIGIDOC_CONF_NAME "digidoc.conf"
+ #define HOME_ENV "HOME"
+ #define DIGIDOC_CONF_FMT "%s/.%s"
+ char g_szGlobalConfigFile[_MAX_PATH] = SYSCONFDIR "/" DIGIDOC_CONF_NAME;
+# ifdef FRAMEWORK
+ char g_frameworkResources[_MAX_PATH];
+# endif
+#endif
+
+char g_szPrivateConfigFile[_MAX_PATH];
+
+#define NUM_SEARCH_CAS 10
+
+//==========< private types and functions >====================
+
+
+// forward deklarations of private helper functions
+int ConfigItem_new(ConfigItem** pItem, const char* key, const char* value, int type, int status);
+void ConfigItem_free(ConfigItem* pItem);
+ConfigItem* ConfigItem_find(const char* key);
+
+int CertificateItem_new(CertificateItem** pItem, const char* key, X509* pCert);
+void CertificateItem_free(CertificateItem* pItem);
+CertificateItem* CertificateItem_find(const char* key);
+X509* Cert_find(const char* key);
+
+
+//==========< global variables >====================
+
+// currently I see the need only for one common configuration store
+// Distinction can be made by item type
+ConfigurationStore g_configStore = {0, 0, 0, 0};
+
+//==========< win32 specific functions >===================
+
+#ifdef WIN32
+
+
+//--------------------------------------------------
+// Retrieves a Windows registry key value
+// key - key name
+// buf - value buffer
+// len - value buffer length
+//--------------------------------------------------
+void getRegKey(const char* key, LPBYTE buf, DWORD* len)
+{
+ LONG rc;
+ HKEY hKey;
+
+ memset(buf, 0, *len);
+ rc = RegOpenKeyEx(HKEY_LOCAL_MACHINE, TEXT(key),
+ 0, KEY_QUERY_VALUE, &hKey );
+ if(rc == ERROR_SUCCESS) {
+ rc = RegQueryValueEx(hKey, NULL, NULL, NULL, buf, len);
+ RegCloseKey( hKey );
+ if(rc == ERROR_SUCCESS) {
+ buf[*len] = 0;
+ } else {
+ buf[0] = 0;
+ }
+ }
+}
+
+//--------------------------------------------------
+// Retrieves a Windows registry key value. If the key
+// is not set then uses the default value and sets it
+// key - key name
+// buf - value buffer
+// len - value buffer length
+// defValue - default value
+//--------------------------------------------------
+void getOrSetRegKey(const char* key, LPBYTE buf, DWORD* len, const char* defValue)
+{
+ LONG rc;
+ HKEY hKey;
+
+ memset(buf, 0, *len);
+ rc = RegOpenKeyEx(HKEY_LOCAL_MACHINE, TEXT(key),
+ 0, KEY_QUERY_VALUE, &hKey );
+ if(rc == ERROR_SUCCESS) {
+ rc = RegQueryValueEx(hKey, TEXT(""), NULL, NULL, buf, len);
+ RegCloseKey( hKey );
+ if(rc == ERROR_SUCCESS) {
+ buf[*len] = 0;
+ }
+ } else {
+ rc = RegCreateKeyEx(HKEY_LOCAL_MACHINE, TEXT(key),
+ 0, "", 0, KEY_READ | KEY_WRITE, 0, &hKey, 0);
+ if(rc == ERROR_SUCCESS) {
+ rc = RegSetValueEx(hKey, TEXT(""), 0, REG_SZ,
+ (const BYTE*)defValue, lstrlen(defValue));
+ RegCloseKey(hKey);
+ }
+ }
+}
+
+//--------------------------------------------------
+// Sets a Windows registry key value
+// key - key name
+// buf - value buffer
+// len - value buffer length
+//--------------------------------------------------
+void setRegKey(const char* key, LPBYTE buf, DWORD len)
+{
+ LONG rc;
+ HKEY hKey;
+
+ rc = RegCreateKeyEx(HKEY_LOCAL_MACHINE, TEXT(key),
+ 0, "", 0, KEY_READ | KEY_WRITE, 0, &hKey, 0);
+ if(rc == ERROR_SUCCESS) {
+ rc = RegSetValueEx(hKey, TEXT(""), 0, REG_SZ, buf, len);
+ RegCloseKey(hKey);
+ }
+}
+
+
+//--------------------------------------------------
+// Retrieves the number of subkeys Windows registry
+// key value.
+// returns number of subkeys
+//--------------------------------------------------
+int getNumSubKeys(const char* key)
+{
+ int n = 0;
+ HKEY hKey;
+ DWORD num;
+
+ if(RegOpenKeyEx(HKEY_LOCAL_MACHINE, TEXT(key),
+ 0, KEY_QUERY_VALUE, &hKey ) == ERROR_SUCCESS) {
+ if(RegQueryInfoKey(hKey, NULL, NULL, NULL, &num,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
+ n = (int)num;
+ RegCloseKey( hKey );
+ }
+ return n;
+}
+
+//--------------------------------------------------
+// Deletes a subkey from Windows registry
+// key - parent key
+// subkey - subkey to be deleted
+//--------------------------------------------------
+void deleteSubKey(const char* key, const char* subkey)
+{
+ HKEY hKey;
+
+ if(RegOpenKeyEx(HKEY_LOCAL_MACHINE, TEXT(key),
+ 0, KEY_QUERY_VALUE, &hKey ) == ERROR_SUCCESS) {
+ RegDeleteKey(hKey, subkey);
+ RegCloseKey(hKey);
+ }
+}
+
+char* g_regDigiDocRoot = "SOFTWARE\\DigiDocLib";
+
+//--------------------------------------------------
+// Retrieves the digidoc librarys config items from registry
+// returns error coder or ERR_OK
+//--------------------------------------------------
+EXP_OPTION int readConfigFromRegistry()
+{
+ HKEY hKey;
+ DWORD rc, l, i;
+ int err = 0;
+ char keyName[255], fullName[500];
+ char keyValue[3000];
+ FILETIME ft;
+
+ if(RegOpenKeyEx(HKEY_LOCAL_MACHINE, TEXT(g_regDigiDocRoot),
+ 0, KEY_READ, &hKey ) != ERROR_SUCCESS )
+ return ERR_CONF_FILE;
+
+ i = 0;
+ do {
+ l = sizeof(keyName);
+ *keyName = 0;
+ rc = RegEnumKeyEx(hKey, i, keyName, &l, NULL, NULL, NULL, &ft);
+ if ( (rc == ERROR_SUCCESS) && *keyName ) {
+ l = sizeof(keyValue);
+ *keyValue = 0;
+ snprintf(fullName, sizeof(fullName), "%s\\%s", g_regDigiDocRoot, keyName);
+ getRegKey(fullName, (BYTE*)keyValue, &l);
+ if (*keyValue) {
+ ddocDebug(3, "readConfigFromRegistry", "Reg key: %s val: %s", (const char*)keyName, (const char*)keyValue);
+ err = addConfigItem(NULL, (const char*)keyName, (const char*)keyValue, ITEM_TYPE_PRIVATE, ITEM_STATUS_OK);
+ }
+ SET_LAST_ERROR_IF_NOT(err == ERR_OK, err);
+ }
+ i++;
+ } while ( (rc == ERROR_SUCCESS) && *keyName );
+ RegCloseKey(hKey);
+ return err;
+}
+
+#endif // WIN32
+
+//==========< item handling functions >====================
+
+//--------------------------------------------------
+// Returns true (not 0) if config store structure has been inited
+//--------------------------------------------------
+EXP_OPTION int isConfigInited()
+{
+ return g_configStore.pItems && g_configStore.nItems;
+}
+
+//--------------------------------------------------
+// Initializes configuration store
+// szConfigFile - name of config file. Use NULL for default
+//--------------------------------------------------
+EXP_OPTION int initConfigStore(const char* szConfigFile)
+{
+ int err = ERR_OK, at_least_one_conf = 0;
+
+ //g_configStore.nItems = 0;
+ //g_configStore.pItems = 0;
+ if (szConfigFile && checkFileExists(szConfigFile)) {
+ err = readConfigFile(szConfigFile, ITEM_TYPE_GLOBAL);
+ //printf("config file: %s rc: %d", szConfigFile, err);
+ return err;
+ }
+
+#ifdef WIN32
+ snprintf(g_szGlobalConfigFile, sizeof(g_szGlobalConfigFile), "%s\\%s", getenv("SystemRoot"), DIGIDOC_CONF_NAME);
+ /*if(!*g_szGlobalConfigFile && getenv("SystemRoot")) {
+ strncpy(g_szGlobalConfigFile, getenv("SystemRoot"), sizeof(g_szGlobalConfigFile));
+ printf("Init win32 2: %s\n", g_szGlobalConfigFile);
+ if(!g_szGlobalConfigFile[strlen(g_szGlobalConfigFile)-1] == '\\')
+ strncat(g_szGlobalConfigFile, "\\", sizeof(g_szGlobalConfigFile) - strlen(g_szGlobalConfigFile));
+ printf("Init win32 3: %s\n", g_szGlobalConfigFile);
+ strncat(g_szGlobalConfigFile, DIGIDOC_CONF_NAME, sizeof(g_szGlobalConfigFile) - strlen(g_szGlobalConfigFile));
+ }*/
+#endif
+#ifdef FRAMEWORK
+ CFStringRef identifier = CFStringCreateWithCString(0, "ee.ria.libdigidoc", kCFStringEncodingUTF8);
+ CFBundleRef bundle = CFBundleGetBundleWithIdentifier(identifier);
+ if(bundle)
+ {
+ CFURLRef url = CFBundleCopyResourcesDirectoryURL(bundle);
+ if(url)
+ {
+ if(CFURLGetFileSystemRepresentation(url, TRUE, (UInt8 *)g_frameworkResources, _MAX_PATH))
+ snprintf(g_szGlobalConfigFile, _MAX_PATH, "%s/%s", g_frameworkResources, DIGIDOC_CONF_NAME);
+ CFRelease(url);
+ }
+ CFRelease(bundle);
+ }
+ CFRelease(identifier);
+#endif
+ //printf( "Reading global config file: %s\n", g_szGlobalConfigFile);
+ ddocDebug(3, "initConfigStore", "Reading global config file: %s", g_szGlobalConfigFile);
+ if(checkFileExists(g_szGlobalConfigFile))
+ err = readConfigFile(g_szGlobalConfigFile, ITEM_TYPE_GLOBAL); // MEMLEAK: ???
+ if(err == ERR_CONF_FILE)
+ err = ERR_OK;
+ else
+ at_least_one_conf = 1;
+ if(err)
+ return err;
+
+ setPrivateConfigFile(NULL); // set default private conf file
+ if(g_szPrivateConfigFile[0]) {
+ //printf( "Reading private config file: %s\n", g_szPrivateConfigFile);
+ ddocDebug(3, "initConfigStore", "Reading private config file: %s", (g_szPrivateConfigFile ? g_szPrivateConfigFile : "NULL"));
+ if(checkFileExists(g_szPrivateConfigFile))
+ err = readConfigFile(g_szPrivateConfigFile, ITEM_TYPE_PRIVATE);
+ if(err == ERR_CONF_FILE)
+ err = ERR_OK;
+ else
+ at_least_one_conf = 1;
+ if(err)
+ return err;
+ }
+ if(DIGIDOC_CONF_NAME) {
+ //printf( "Reading config file: %s\n", DIGIDOC_CONF_NAME);
+ ddocDebug(2, "initConfigStore", "Reading config file: %s", (DIGIDOC_CONF_NAME ? DIGIDOC_CONF_NAME: "NULL"));
+ if(checkFileExists(DIGIDOC_CONF_NAME))
+ err = readConfigFile(DIGIDOC_CONF_NAME, ITEM_TYPE_PRIVATE);
+ if(err == ERR_CONF_FILE)
+ err = ERR_OK;
+ else
+ at_least_one_conf = 1;
+ if(err)
+ return err;
+ }
+#ifdef WIN32
+ err = readConfigFromRegistry();
+ if(err == ERR_CONF_FILE)
+ err = ERR_OK;
+ else
+ at_least_one_conf = 1;
+ if(err)
+ return err;
+#endif
+ // init certs
+ err = initCertificateItems();
+
+ if(!at_least_one_conf)
+ err = ERR_CONF_FILE;
+ return err;
+}
+
+
+//--------------------------------------------------
+// Cleans memory of configuration store
+// pConfStore - configuration collection (use NULL for default)
+//--------------------------------------------------
+EXP_OPTION void cleanupConfigStore(ConfigurationStore *pConfStore)
+{
+ int i;
+
+ if(!pConfStore)
+ pConfStore = &g_configStore;
+ for(i = 0; (i < pConfStore->nItems) && pConfStore->pItems && pConfStore->pItems[i]; i++)
+ ConfigItem_free(pConfStore->pItems[i]);
+ free(pConfStore->pItems);
+ pConfStore->pItems = 0;
+ pConfStore->nItems = 0;
+ for(i = 0; (i < pConfStore->nCerts) && pConfStore->pCerts && pConfStore->pCerts[i]; i++)
+ CertificateItem_free(pConfStore->pCerts[i]);
+ free(pConfStore->pCerts);
+ pConfStore->pCerts = 0;
+ pConfStore->nCerts = 0;
+}
+
+//--------------------------------------------------
+// Creates a new configration item
+// pItem - address of new pointer location
+// key - items key
+// value - items value
+// type - item type
+// status - item status
+// returns ERR_OK on success
+//--------------------------------------------------
+int ConfigItem_new(ConfigItem** pItem, const char* key, const char* value, int type, int status)
+{
+ RETURN_IF_NULL_PARAM(key);
+ RETURN_IF_NULL_PARAM(value);
+ RETURN_IF_NULL_PARAM(pItem);
+
+ if((*pItem = (ConfigItem*)malloc(sizeof(ConfigItem))) != NULL) {
+ (*pItem)->szKey = strdup(key);
+ (*pItem)->szValue = strdup(value);
+ (*pItem)->nType = type;
+ (*pItem)->nStatus = status;
+ if(!(*pItem)->szKey || !(*pItem)->szValue) {
+ ConfigItem_free(*pItem);
+ *pItem = NULL;
+ SET_LAST_ERROR_RETURN_CODE(ERR_BAD_ALLOC);
+ }
+ } else
+ SET_LAST_ERROR_RETURN_CODE(ERR_BAD_ALLOC);
+ return ERR_OK;
+}
+
+//--------------------------------------------------
+// Cleanup of config items memory
+// pItem - address of config item
+//--------------------------------------------------
+void ConfigItem_free(ConfigItem* pItem)
+{
+ if(pItem) {
+ if(pItem->szKey)
+ free(pItem->szKey);
+ if(pItem->szValue)
+ free(pItem->szValue);
+ free(pItem);
+ }
+}
+
+
+//--------------------------------------------------
+// Adds a new configration item
+// pConfStore - configuration collection (use NULL for default)
+// key - items key
+// value - items value
+// type - item type
+// status - item status
+// returns ERR_OK on success
+//--------------------------------------------------
+EXP_OPTION int addConfigItem(ConfigurationStore *pConfStore, const char* key, const char* value, int type, int status)
+{
+ int err = ERR_OK;
+ ConfigItem* pItem;
+ ConfigItem** pItems;
+
+ if(!pConfStore)
+ pConfStore = &g_configStore;
+ if((err = ConfigItem_new(&pItem, key, value, type, status)) == ERR_OK) {
+ if((pItems = (ConfigItem**)realloc(pConfStore->pItems,
+ sizeof(void*) * (pConfStore->nItems + 1))) != NULL) {
+ pItems[pConfStore->nItems] = pItem;
+ pConfStore->nItems++;
+ pConfStore->pItems = pItems;
+ } else
+ SET_LAST_ERROR_RETURN_CODE(ERR_BAD_ALLOC);
+ } else
+ SET_LAST_ERROR_RETURN_CODE(err);
+ return ERR_OK;
+}
+
+
+//--------------------------------------------------
+// Creates a new cert item
+// pItem - address of new pointer location
+// key - items key
+// pCert - certificate
+// returns ERR_OK on success
+//--------------------------------------------------
+int CertificateItem_new(CertificateItem** pItem, const char* key, X509* pCert)
+{
+ RETURN_IF_NULL_PARAM(key);
+ RETURN_IF_NULL_PARAM(pCert);
+ RETURN_IF_NULL_PARAM(pItem);
+
+ if((*pItem = (CertificateItem*)malloc(sizeof(CertificateItem))) != NULL) {
+ (*pItem)->szKey = strdup(key);
+ (*pItem)->pCert = pCert; // take ownership !
+ } else
+ SET_LAST_ERROR_RETURN_CODE(ERR_BAD_ALLOC);
+ return ERR_OK;
+}
+
+//--------------------------------------------------
+// Cleanup of cert items memory
+// pItem - address of cert item
+//--------------------------------------------------
+void CertificateItem_free(CertificateItem* pItem)
+{
+ if(pItem) {
+ if(pItem->szKey)
+ free(pItem->szKey);
+ if(pItem->pCert)
+ X509_free(pItem->pCert);
+ free(pItem);
+ }
+}
+
+//--------------------------------------------------
+// Adds a new cert item
+// pConfStore - configuration collection (use NULL for default)
+// key - items key
+// pCert - certificate
+// returns ERR_OK on success
+//--------------------------------------------------
+EXP_OPTION int addCertificateItem(ConfigurationStore *pConfStore, const char* key, X509* pCert)
+{
+ int err = ERR_OK;
+ CertificateItem* pItem;
+ CertificateItem** pItems;
+
+ if(!pConfStore)
+ pConfStore = &g_configStore;
+ if((err = CertificateItem_new(&pItem, key, pCert)) == ERR_OK) {
+ if((pItems = (CertificateItem**)realloc(pConfStore->pCerts, sizeof(void*) * (pConfStore->nCerts + 1))) != NULL) {
+ pItems[pConfStore->nCerts] = pItem;
+ pConfStore->nCerts++;
+ pConfStore->pCerts = pItems;
+ } else
+ SET_LAST_ERROR_RETURN_CODE(ERR_BAD_ALLOC);
+ } else
+ SET_LAST_ERROR_RETURN_CODE(err);
+ return ERR_OK;
+}
+
+//--------------------------------------------------
+// Finds a new cert item by key
+// key - items key
+// returns item pointer or NULL if not found
+//--------------------------------------------------
+CertificateItem* CertificateItem_find(const char* key)
+{
+ int i;
+
+ for(i = 0; (i < g_configStore.nCerts) && g_configStore.pCerts && g_configStore.pCerts[i]; i++) {
+ if(g_configStore.pCerts[i]->szKey && !strcmp(g_configStore.pCerts[i]->szKey, key))
+ return g_configStore.pCerts[i];
+ }
+ return NULL;
+}
+
+//--------------------------------------------------
+// Finds a cert by key
+// key - items key
+// returns X509 pointer or NULL if not found. Must be X509_free()-d because it will be duplicated here
+//--------------------------------------------------
+X509* Cert_find(const char* key)
+{
+ int i;
+ X509* pCert = 0;
+
+ for(i = 0; (i < g_configStore.nCerts) && g_configStore.pCerts && g_configStore.pCerts[i] && !pCert; i++) {
+ if(g_configStore.pCerts[i]->szKey && !strcmp(g_configStore.pCerts[i]->szKey, key))
+ pCert = g_configStore.pCerts[i]->pCert;
+ }
+ ddocDebug(3, "Cert_find", "%s cache %s", key, (pCert ? "OK" : "NULL"));
+ return X509_dup(pCert);
+}
+
+//--------------------------------------------------
+// Adds a new private configration item or modifies
+// an existing one
+// pConfStore - configuration collection (use NULL for default)
+// key - items key
+// value - items value
+// returns ERR_OK on success
+//--------------------------------------------------
+EXP_OPTION int createOrReplacePrivateConfigItem(ConfigurationStore *pConfStore, const char* key, const char* value)
+{
+ int err = ERR_OK, i;
+ ConfigItem* pItem = NULL;
+#ifdef WIN32
+ char keyName[500];
+#endif
+ ddocDebug(3, "createOrReplacePrivateConfigItem", "%s = %s", (key ? key : "NULL"), (value ? value : "NULL"));
+ if(!pConfStore)
+ pConfStore = &g_configStore;
+ // first try to find a private config item
+ for(i = 0; (i < pConfStore->nItems) && pConfStore->pItems && pConfStore->pItems[i]; i++) {
+ if(pConfStore->pItems[i]->szKey && !strcmp(pConfStore->pItems[i]->szKey, key) &&
+ pConfStore->pItems[i]->nType == ITEM_TYPE_PRIVATE) {
+ pItem = pConfStore->pItems[i];
+ break;
+ }
+ }
+ if(pItem) { // if found then modify it
+ if(pItem->szValue)
+ free(pItem->szValue);
+ pItem->szValue = (char*)malloc(strlen(value)+1);
+ if(pItem->szValue)
+ strncpy(pItem->szValue, value, strlen(value)+1);
+ else
+ SET_LAST_ERROR_RETURN_CODE(ERR_BAD_ALLOC);
+ pItem->nStatus = ITEM_STATUS_MODIFIED;
+ } else { // else create a new private config item
+ err = addConfigItem(pConfStore, key, value, ITEM_TYPE_PRIVATE, ITEM_STATUS_MODIFIED);
+ }
+#ifdef WIN32
+ snprintf(keyName, sizeof(keyName), "%s\\%s", g_regDigiDocRoot, key);
+ setRegKey(keyName, (BYTE*)value, (value ? (DWORD)strlen(value) : (DWORD)0));
+ if(pItem)
+ pItem->nStatus = ITEM_STATUS_OK;
+#endif
+ return err;
+}
+
+//--------------------------------------------------
+// Deletes configration item
+// key - items key
+// returns ERR_OK on success
+//--------------------------------------------------
+EXP_OPTION int ConfigItem_delete(const char* key)
+{
+ int err = ERR_OK, i, j;
+
+ // first try to find a private config item
+ for(i = j = 0; (i < g_configStore.nItems) && g_configStore.pItems && g_configStore.pItems[i]; i++) {
+ if(g_configStore.pItems[i]->szKey && !strcmp(g_configStore.pItems[i]->szKey, key) &&
+ g_configStore.pItems[i]->nType == ITEM_TYPE_PRIVATE) {
+ ConfigItem_free(g_configStore.pItems[i]);
+ g_configStore.pItems[i] = 0;
+ continue;
+ }
+ g_configStore.pItems[j] = g_configStore.pItems[i]; // no-op until moving the last items forward
+ j++;
+ }
+ g_configStore.nItems = j;
+#ifdef WIN32
+ deleteSubKey(g_regDigiDocRoot, key);
+#endif
+ return err;
+}
+
+
+//--------------------------------------------------
+// Finds a new configration item by key
+// key - items key
+// returns item pointer or NULL if not found
+//--------------------------------------------------
+ConfigItem* ConfigItem_find(const char* key)
+{
+ int i;
+
+ for(i = 0; (i < g_configStore.nItems) && g_configStore.pItems && g_configStore.pItems[i]; i++) {
+ if(g_configStore.pItems[i]->szKey && !strcmp(g_configStore.pItems[i]->szKey, key))
+ return g_configStore.pItems[i];
+ }
+ return NULL;
+}
+
+//--------------------------------------------------
+// Finds a all configration items that start with this prefix
+// prefix - item keys prefix
+// returns error code or ERR_OK
+//--------------------------------------------------
+int ConfigItem_findByPrefix(ConfigurationStore *pConfStore, const char* prefix)
+{
+ int i, err = ERR_OK;
+
+ for(i = 0; (i < g_configStore.nItems) && g_configStore.pItems && g_configStore.pItems[i]; i++) {
+ if(g_configStore.pItems[i]->szKey && !strncmp(g_configStore.pItems[i]->szKey, prefix, strlen(prefix)))
+ err = addConfigItem(pConfStore, g_configStore.pItems[i]->szKey,
+ g_configStore.pItems[i]->szValue,
+ g_configStore.pItems[i]->nType,
+ g_configStore.pItems[i]->nStatus);
+ }
+ return err;
+}
+
+
+//--------------------------------------------------
+// Finds a new configration items value by key
+// key - items key
+// returns value of config item or NULL if not found
+//--------------------------------------------------
+EXP_OPTION const char* ConfigItem_lookup(const char* key)
+{
+#ifdef FRAMEWORK
+ if(strcmp(key, "CA_CERT_PATH") == 0)
+ return g_frameworkResources;
+#endif
+ int i;
+ // first try to find a private item
+ for(i = 0; (i < g_configStore.nItems) && g_configStore.pItems && g_configStore.pItems[i]; i++) {
+ if(g_configStore.pItems[i]->szKey && !strcmp(g_configStore.pItems[i]->szKey, key) &&
+ g_configStore.pItems[i]->nType == ITEM_TYPE_PRIVATE)
+ return g_configStore.pItems[i]->szValue;
+ } // if not found use any type of item with the given key
+ for(i = 0; (i < g_configStore.nItems) && g_configStore.pItems && g_configStore.pItems[i]; i++) {
+ if(g_configStore.pItems[i]->szKey && !strcmp(g_configStore.pItems[i]->szKey, key))
+ return g_configStore.pItems[i]->szValue;
+ }
+ return NULL;
+}
+
+//--------------------------------------------------
+// Finds a new configration items value by key from the store
+// key - items key
+// pConfStore - store to search in
+// returns value of config item or NULL if not found
+//--------------------------------------------------
+EXP_OPTION const char* ConfigItem_lookup_fromStore(ConfigurationStore *pConfStore, const char* key)
+{
+ int i;
+
+ for(i = 0; pConfStore && (i < pConfStore->nItems) &&
+ pConfStore->pItems && pConfStore->pItems[i]; i++) {
+ if(pConfStore->pItems[i]->szKey && !strcmp(pConfStore->pItems[i]->szKey, key))
+ return pConfStore->pItems[i]->szValue;
+ }
+ return NULL;
+}
+
+//--------------------------------------------------
+// Finds a numeric configration items value by key
+// key - items key
+// defValue - default value to be returned
+// returns value of config item or defValue if not found
+//--------------------------------------------------
+EXP_OPTION int ConfigItem_lookup_int(const char* key, int defValue)
+{
+ int rc = defValue;
+ const char* p = ConfigItem_lookup(key);
+ if (p)
+ rc = atoi(p);
+ return rc;
+}
+
+//--------------------------------------------------
+// Finds a new configration items value by key
+// key - items key
+// returns value of config item or NULL if not found
+//--------------------------------------------------
+EXP_OPTION const char* ConfigItem_lookup_str(const char* key, const char* defValue)
+{
+ const char* p = ConfigItem_lookup(key);
+ if (p)
+ return p;
+ else
+ return defValue;
+}
+
+//--------------------------------------------------
+// Finds a bolean configration items value by key
+// key - items key
+// defValue - default value to be returned
+// returns value of config item or defValue if not found
+//--------------------------------------------------
+EXP_OPTION int ConfigItem_lookup_bool(const char* key, int defValue)
+{
+ int rc = defValue;
+ const char* p = ConfigItem_lookup(key);
+ if(p)
+#ifdef WIN32
+ rc = (!stricmp(p, "true")) ? 1 : 0;
+#else
+ rc = (!strcasecmp(p, "TRUE")) ? 1 : 0;
+#endif
+ return rc;
+}
+
+
+//--------------------------------------------------
+// Reads and parses configuration file
+// fileName - configuration file name
+// type - type of config file global/private
+// return error code or 0 for success
+//--------------------------------------------------
+EXP_OPTION int readConfigFile(const char* fileName, int type)
+{
+ FILE* hFile;
+ char buf[5000];
+ char *p;
+ int err = ERR_OK;
+
+ if((hFile = fopen(fileName, "rt")) != NULL) {
+ ddocDebug(2, "readConfigFile", "Reading config file: %s", fileName);
+ while(fgets(buf, sizeof(buf), hFile) != NULL && !err) {
+ // trim line separators and spaces
+ while(strlen(buf) && (buf[strlen(buf)-1] == '\n' ||
+ buf[strlen(buf)-1] == '\r' ||
+ buf[strlen(buf)-1] == '\t' ||
+ buf[strlen(buf)-1] == ' '))
+ buf[strlen(buf)-1] = 0;
+ if(strlen(buf) && buf[0] != '#') {
+ if((p = strchr(buf, '=')) != NULL) {
+ *p = 0;
+ p++;
+ err = addConfigItem(NULL, (const char*)buf, (const char*)p, type, ITEM_STATUS_OK);
+ SET_LAST_ERROR_IF_NOT(err == ERR_OK, err);
+ //printf("CONF: %s = %s\n", buf, p);
+ }
+ }
+ }
+ fclose(hFile);
+ return err;
+ } else {
+ ddocDebug(1, "readConfigFile", "Error opening config file: %s", fileName);
+ SET_LAST_ERROR_RETURN_CODE(ERR_CONF_FILE); // MEMLEAK: ???
+ }
+}
+
+
+//--------------------------------------------------
+// Writes a configuration file
+// fileName - configuration file name
+// type - type of config file global/private
+// return error code or 0 for success
+//--------------------------------------------------
+EXP_OPTION int writeConfigFile(const char* fileName, int type)
+{
+ FILE* hFile;
+ //char buf[300];
+ //char *p;
+ int err = ERR_OK, i;
+
+ if((hFile = fopen(fileName, "wt")) != NULL) {
+ // first try to find a private item
+ for(i = 0; (i < g_configStore.nItems) &&
+ g_configStore.pItems && g_configStore.pItems[i]; i++) {
+ if(g_configStore.pItems[i]->nType == type) {
+ fprintf(hFile, "%s=%s\n", g_configStore.pItems[i]->szKey,
+ g_configStore.pItems[i]->szValue);
+ g_configStore.pItems[i]->nStatus = ITEM_STATUS_OK;
+ }
+ }
+ fclose(hFile);
+ return err;
+ } else
+ SET_LAST_ERROR_RETURN_CODE(ERR_CONF_FILE);
+}
+
+//--------------------------------------------------
+// Saves all private config items in correct file
+// return error code or 0 for success
+//--------------------------------------------------
+EXP_OPTION int writePrivateConfigFile()
+{
+#ifndef WIN32
+ return writeConfigFile(g_szPrivateConfigFile, ITEM_TYPE_PRIVATE);
+#else
+ return ERR_OK;
+#endif
+}
+
+//--------------------------------------------------
+// Sets a new name for private config file. Can be
+// used to override default of env(HOME)/.digidoc.conf
+// Use NULL to restore default value
+//--------------------------------------------------
+EXP_OPTION void setPrivateConfigFile(const char* fileName)
+{
+ if (fileName) {
+ strncpy( g_szPrivateConfigFile, fileName, sizeof(g_szPrivateConfigFile) );
+ } else { // use default
+ snprintf(g_szPrivateConfigFile, sizeof(g_szPrivateConfigFile)-1,
+ DIGIDOC_CONF_FMT, getenv(HOME_ENV), DIGIDOC_CONF_NAME);
+ }
+}
+
+//--------------------------------------------------
+// Finds CA certificates index by it's CN
+// idx - address if index
+// cn - CN of the CA
+// return -1 if not found or 0 for success
+//--------------------------------------------------
+int findCAindexByCN(int* idx, const char* cn)
+{
+ int i, n;
+ char buf1[100];
+ const char* p;
+
+ *idx = 0;
+ p = ConfigItem_lookup("CA_CERTS");
+ RETURN_IF_NOT(p != NULL, ERR_CONF_LINE);
+ n = atoi(p);
+ for(i = 1; (i <= n) && !(*idx); i++) {
+ snprintf(buf1, sizeof(buf1), "CA_CERT_%d_CN", i);
+ p = ConfigItem_lookup(buf1);
+ ddocDebug(1, "findCAindexByCN", "ERR112 Unknown CA: %s", buf1);
+ RETURN_IF_NOT(p != NULL, ERR_UNKNOWN_CA);
+ if(!strcmp(p, cn)) { // found it
+ *idx = i;
+ break;
+ }
+ }
+ return ERR_OK;
+}
+
+//--------------------------------------------------
+// Finds Responder certificates index by it's CN
+// idx - address if index
+// cn - CN of the responder cert
+// hash - responder certs hash in base64 form
+// ca - responder CA CN
+// return error code or 0 for success
+//--------------------------------------------------
+int findResponderIndex(int* idx, const char* cn, const char* hash, const char* ca)
+{
+ int err = ERR_OK, i, n;
+ char buf1[100];
+ const char* p;
+
+ *idx = 0;
+ ddocDebug(3, "findResponderIndex", "Find CA: %s hash: %s ca-cn: %s", (cn ? cn : "NULL"),
+ (hash ? hash : "NULL"), (ca ? ca : "NULL"));
+ p = ConfigItem_lookup("DIGIDOC_OCSP_RESPONDER_CERTS");
+ RETURN_IF_NOT(p != NULL, ERR_CONF_LINE);
+ n = atoi(p);
+ for(i = 1; (i <= n) && !(*idx); i++) {
+ if(cn) {
+ snprintf(buf1, sizeof(buf1), "DIGIDOC_OCSP_RESPONDER_CERT_%d_CN", i);
+ p = ConfigItem_lookup(buf1);
+ if(p && !strcmp(p, cn)) { // found it
+ *idx = i;
+ break;
+ }
+ }
+ else if(hash) {
+ snprintf(buf1, sizeof(buf1), "DIGIDOC_OCSP_RESPONDER_CERT_%d_HASH", i);
+ p = ConfigItem_lookup(buf1);
+ if(p && !strcmp(p, hash)) { // found it
+ *idx = i;
+ break;
+ }
+ }
+ else if(ca) {
+ snprintf(buf1, sizeof(buf1), "DIGIDOC_OCSP_RESPONDER_CERT_%d_CA", i);
+ p = ConfigItem_lookup(buf1);
+ if(p && !strcmp(p, ca)) { // found it
+ *idx = i;
+ break;
+ }
+ }
+ }
+ return err;
+}
+
+//--------------------------------------------------
+// Finds CA certificate by CN
+// ppCA - address of found CA
+// szCN - CA certs common name
+// pHash - authority-key-identifier to search for CA
+// return error code or 0 for success
+//--------------------------------------------------
+DIGIDOC_DEPRECATED EXP_OPTION int findCAForCN(X509** ppCA, const char* szCN, DigiDocMemBuf *pHash)
+{
+ return findCAForCNAndSigTime(ppCA, szCN, pHash, 0);
+}
+
+//--------------------------------------------------
+// Read ca and ocsp responder certs from files and cache in memory
+//--------------------------------------------------
+int initCertificateItems()
+{
+ int err = ERR_OK, i, n, e2, j;
+ const char *p1, *p2, *p3;
+ char buf2[300], buf1[50];
+ X509 *x509 = NULL;
+
+ // read CA certs
+ p1 = ConfigItem_lookup("CA_CERTS");
+ RETURN_IF_NOT(p1 != NULL, ERR_CONF_LINE);
+ p2 = ConfigItem_lookup("CA_CERT_PATH");
+ RETURN_IF_NOT(p2 != NULL, ERR_CONF_LINE);
+ ddocDebug(3, "initCertificateItems", "Init ca certs: %s ca-path: %s", p1, p2);
+ n = atoi(p1);
+ for(i = 1; i <= n; i++) {
+ snprintf(buf1, sizeof(buf1), "CA_CERT_%d_CN", i);
+ p1 = ConfigItem_lookup(buf1);
+ snprintf(buf1, sizeof(buf1), "CA_CERT_%d", i);
+ p3 = ConfigItem_lookup(buf1);
+ if(p1 && p3) {
+#ifdef WIN32
+ snprintf(buf2, sizeof(buf2), "%s\\%s", p2, p3);
+#else
+ snprintf(buf2, sizeof(buf2), "%s/%s", p2, p3);
+#endif
+ x509 = 0;
+ e2 = ReadCertificateNoErr(&x509, buf2);
+ if(x509) {
+ ddocDebug(3, "initCertificateItems", "CA Cert item: %d CN: %s file: %s", i, p1, p3);
+ addCertificateItem(&g_configStore, p1, x509); // release ownership on x509!
+ } else {
+ ddocDebug(1, "initCertificateItems", "Error: %d reading item: %d CN: %s file: %s", e2, i, p1, p3);
+ }
+ }
+ }
+ // read ocsp responder certs
+ p1 = ConfigItem_lookup("DIGIDOC_OCSP_RESPONDER_CERTS");
+ RETURN_IF_NOT(p1 != NULL, ERR_CONF_LINE);
+ ddocDebug(3, "initCertificateItems", "Init ocsp certs: %s ca-path: %s", p1, p2);
+ n = atoi(p1);
+ for(i = 1; i <= n; i++) {
+ snprintf(buf1, sizeof(buf1), "DIGIDOC_OCSP_RESPONDER_CERT_%d_CN", i);
+ p1 = ConfigItem_lookup(buf1);
+ snprintf(buf1, sizeof(buf1), "DIGIDOC_OCSP_RESPONDER_CERT_%d", i);
+ p3 = ConfigItem_lookup(buf1);
+ if(p1 && p3) {
+#ifdef WIN32
+ snprintf(buf2, sizeof(buf2), "%s\\%s", p2, p3);
+#else
+ snprintf(buf2, sizeof(buf2), "%s/%s", p2, p3);
+#endif
+ x509 = 0;
+ e2 = ReadCertificateNoErr(&x509, buf2);
+ if(x509) {
+ ddocDebug(3, "initCertificateItems", "OCSP Cert item: %d CN: %s file: %s", i, p1, p3);
+ addCertificateItem(&g_configStore, buf1, x509); // release ownership on x509!
+ } else {
+ ddocDebug(1, "initCertificateItems", "Error: %d reading item: %d CN: %s file: %s", e2, i, p1, p3);
+ }
+ }
+ for(j = 1; j < 10; j++) {
+ snprintf(buf1, sizeof(buf1), "DIGIDOC_OCSP_RESPONDER_CERT_%d_%d", i, j);
+ p3 = ConfigItem_lookup(buf1);
+ if(p1 && p3) {
+#ifdef WIN32
+ snprintf(buf2, sizeof(buf2), "%s\\%s", p2, p3);
+#else
+ snprintf(buf2, sizeof(buf2), "%s/%s", p2, p3);
+#endif
+ x509 = 0;
+ e2 = ReadCertificateNoErr(&x509, buf2);
+ if(x509) {
+ ddocDebug(3, "initCertificateItems", "OCSP Cert item: %d CN: %s file: %s", i, p1, p3);
+ addCertificateItem(&g_configStore, buf1, x509); // release ownership on x509!
+ } else {
+ ddocDebug(1, "initCertificateItems", "Error: %d reading item: %d CN: %s file: %s", e2, i, p1, p3);
+ }
+ }
+ }
+ }
+
+ return err;
+}
+
+//--------------------------------------------------
+// Finds CA certificate by CN
+// ppCA - address of found CA
+// szCN - CA certs common name
+// pHash - authority-key-identifier to search for CA
+// tSigTime - signing time or 0
+// return error code or 0 for success
+//--------------------------------------------------
+EXP_OPTION int findCAForCNAndSigTime(X509** ppCA, const char* szCN, DigiDocMemBuf *pHash, time_t tSigTime)
+{
+ int err = ERR_OK, i, n;
+ char buf2[300], buf1[30], buf3[50];
+ const char *p1, *p2;
+ X509 *x509 = NULL;
+ DigiDocMemBuf mbuf2, mbuf3, mbuf1;
+ time_t tFrom = 0, tTo = 0;
+
+ mbuf1.pMem = 0;
+ mbuf1.nLen = 0;
+ mbuf2.pMem = 0;
+ mbuf2.nLen = 0;
+ mbuf3.pMem = 0;
+ mbuf3.nLen = 0;
+ ddocEncodeBase64(pHash, &mbuf3);
+ ddocBin2Hex(pHash, &mbuf2);
+ ddocDebug(3, "findCAForCN", "Find CN: %s subj-hash: %s subj-hash-hex: %s sig-time: %ld", szCN, (char*)mbuf3.pMem, (char*)mbuf2.pMem, (unsigned long)tSigTime);
+ ddocMemBuf_free(&mbuf3);
+ ddocMemBuf_free(&mbuf2);
+ // initialize
+ *ppCA = NULL;
+ p1 = ConfigItem_lookup("CA_CERTS");
+ RETURN_IF_NOT(p1 != NULL, ERR_CONF_LINE);
+ n = atoi(p1);
+ for(i = 1; (i <= n) && !(*ppCA); i++) {
+ snprintf(buf1, sizeof(buf1), "CA_CERT_%d_CN", i);
+ p1 = ConfigItem_lookup(buf1);
+ x509 = NULL;
+ ddocDebug(3, "findCAForCN", "CA: %s -> %s", buf1, p1);
+ if(p1 && !strcmp(p1, szCN)) { // found CN, try read cert
+ snprintf(buf1, sizeof(buf1), "CA_CERT_%d", i);
+ p1 = ConfigItem_lookup(buf1);
+ if(p1) {
+ p2 = ConfigItem_lookup("CA_CERT_PATH");
+ RETURN_IF_NOT(p2 != NULL, ERR_CONF_LINE);
+#ifdef WIN32
+ snprintf(buf2, sizeof(buf2), "%s\\%s", p2, p1);
+#else
+ snprintf(buf2, sizeof(buf2), "%s/%s", p2, p1);
+#endif
+ // check cache first
+ x509 = Cert_find(szCN);
+ if(!x509)
+ err = ReadCertificate(&x509, buf2);
+ ddocDebug(4, "findCAForCN", "Read cert: %s rc: %d\n", buf2, err);
+ if(err == ERR_FILE_READ) err = ERR_UNKNOWN_CA;
+ if(pHash && pHash->pMem && x509) {
+ memset(buf3, 0, sizeof(buf3));
+ ReadCertSerialNumber(buf3, sizeof(buf3), x509);
+ readSubjectKeyIdentifier(x509, &mbuf2);
+ ddocEncodeBase64(&mbuf2, &mbuf3);
+ ddocBin2Hex(&mbuf2, &mbuf1);
+ tFrom = getCertNotBeforeTimeT(x509);
+ tTo = getCertNotAfterTimeT(x509);
+ if(!ddocMemCompareMemBufs(pHash, &mbuf2) &&
+ (!tSigTime || (tSigTime >= tFrom && tSigTime <= tTo))) {
+ *ppCA = x509;
+ err = ERR_OK;
+ ddocDebug(4, "findCAForCN", "Found cert: %s with nr: %s from: %ld to: %ld", szCN, buf3, tFrom, tTo);
+ } else {
+ ddocDebug(4, "findCAForCN", "Release cert: %s with nr: %s", szCN, buf3);
+ X509_free(x509); // release wrong cert
+ *ppCA = NULL;
+ err = ERR_UNKNOWN_CA;
+ }
+ ddocDebug(3, "findCAForCN", "Compare CA: %s subj-hash: %s hex: %s err: %d", buf1, (char*)mbuf3.pMem, (char*)mbuf1.pMem, err);
+ ddocMemBuf_free(&mbuf2);
+ ddocMemBuf_free(&mbuf3);
+ ddocMemBuf_free(&mbuf1);
+ } else { // plain CN match is enough
+ if(x509) {
+ *ppCA = x509;
+ err = ERR_OK;
+ ddocDebug(4, "findCAForCN", "Found cert: %s with cn", szCN);
+ }
+ }
+
+ } else {
+ ddocDebug(3, "findCAForCN", "No cert file for: %s", buf1);
+ }
+ }
+ }
+ RETURN_IF_NOT(err == ERR_OK, err);
+ //*ppCA = x509;
+ if(*ppCA) {
+ ddocCertGetSubjectDN(*ppCA, &mbuf2);
+ ddocDebug(4, "findCAForCN", "Found cert: %s with cn %s", (char*)mbuf2.pMem, szCN);
+ ddocMemBuf_free(&mbuf2);
+ }
+ return err;
+}
+
+
+//--------------------------------------------------
+// Finds Responders certificate by CN
+// ppResp - address of found cert
+// szCN - Responder certs common name
+// hash - responder certs hash in base64
+// nIdx - index of the certificate for this respnder. Starts at 0
+// return error code or 0 for success
+//--------------------------------------------------
+EXP_OPTION int findResponderByCNAndHashAndIndex(X509** ppResp, const char* szCN,
+ const char* hash, int nIdx)
+{
+ int err = ERR_OK, i;
+ char buf[300];
+ const char *p1, *p2;
+
+ RETURN_IF_NULL_PARAM(ppResp);
+ // initialize
+ *ppResp = NULL;
+ err = findResponderIndex(&i, szCN, hash, NULL);
+ ddocDebug(3, "findResponderByCNAndHashAndIndex", "CN: %s hash: %s resp-index: %d, cert-index: %d",
+ (szCN ? szCN : "NULL"), (hash ? hash : "NULL"), i, nIdx);
+ RETURN_IF_NOT(err == ERR_OK, err);
+ // check cache first
+ *ppResp = Cert_find(szCN);
+ if(*ppResp) return ERR_OK;
+
+ // compose search key
+ if(!nIdx)
+ snprintf(buf, sizeof(buf), "DIGIDOC_OCSP_RESPONDER_CERT_%d", i);
+ else
+ snprintf(buf, sizeof(buf), "DIGIDOC_OCSP_RESPONDER_CERT_%d_%d", i, nIdx);
+ p1 = ConfigItem_lookup(buf);
+ ddocDebug(3, "findResponderByCNAndHashAndIndex", "Read cert key: %s file: %s", buf, (p1 ? p1 : "NULL"));
+ if(p1) {
+ if(checkFileExists(p1)) {
+ err = ReadCertificate(ppResp, p1);
+ } else {
+ p2 = ConfigItem_lookup("CA_CERT_PATH");
+ if(p2) {
+#ifdef WIN32
+ snprintf(buf, sizeof(buf), "%s\\%s", p2, p1);
+#else
+ snprintf(buf, sizeof(buf), "%s/%s", p2, p1);
+#endif
+ if(checkFileExists(buf))
+ err = ReadCertificate(ppResp, buf);
+ ddocDebug(3, "findResponderByCNAndHashAndIndex", "Read cert: %s rc: %d got: %s", buf, err, (*ppResp ? "OK" : "NULL"));
+ }
+ }
+ } // if p1
+ return err;
+}
+
+
+//--------------------------------------------------
+// Finds Responders certificate by CN
+// ppResp - address of found cert
+// szCN - Responder certs common name
+// hash - responder certs hash in base64 form
+// szCertSerial - specific serial number to search
+// return error code or 0 for success
+//--------------------------------------------------
+EXP_OPTION int findResponder(X509** ppResp, const char* szCN,
+ const char* szHash, char* szCertSerial)
+{
+ int err = ERR_OK, i, j;
+ char buf[300], szSerial[100];
+ const char *p1, *p2;
+ time_t t1, t2;
+ X509 *x509;
+
+ RETURN_IF_NULL_PARAM(ppResp);
+ // initialize
+ *ppResp = NULL;
+ err = findResponderIndex(&i, szCN, szHash, NULL);
+ ddocDebug(3, "findResponder", "CN: %s hash: %s index: %d, search notary: %s",
+ (szCN ? szCN : "NULL"), (szHash ? szHash : "NULL"), i,
+ (szCertSerial ? szCertSerial : "LATEST"));
+ RETURN_IF_NOT(err == ERR_OK, err);
+ j = 0;
+ t1 = t2 = 0;
+ do {
+ x509 = 0;
+ p1 = p2 = 0;
+ // compose search key
+ if(!j)
+ snprintf(buf, sizeof(buf), "DIGIDOC_OCSP_RESPONDER_CERT_%d", i);
+ else
+ snprintf(buf, sizeof(buf), "DIGIDOC_OCSP_RESPONDER_CERT_%d_%d", i, j);
+ p1 = ConfigItem_lookup(buf);
+ ddocDebug(3, "findResponder", "Read cert key: %s file: %s", buf, (p1 ? p1 : "NULL"));
+ if(p1) {
+ // check cache first
+ x509 = Cert_find(buf);
+ if(!x509) { // if not found in cache
+ if(checkFileExists(p1)) {
+
+ err = ReadCertificate(&x509, p1);
+ if(x509)
+ t2 = getCertNotAfterTimeT(x509);
+ ddocDebug(3, "findResponder", "Read cert: %s rc: %d not-after: %ld", p1, err, (unsigned long)t2);
+ } else {
+ p2 = ConfigItem_lookup("CA_CERT_PATH");
+ RETURN_IF_NOT(p2 != NULL, ERR_CONF_LINE);
+#ifdef WIN32
+ snprintf(buf, sizeof(buf), "%s\\%s", p2, p1);
+#else
+ snprintf(buf, sizeof(buf), "%s/%s", p2, p1);
+#endif
+ err = ReadCertificate(&x509, buf);
+ if(x509)
+ t2 = getCertNotAfterTimeT(x509);
+ ddocDebug(3, "findResponder", "Read cert: %s rc: %d not-after: %ld", buf, err, (unsigned long)t2);
+ } // else
+ } // !x509
+ if(!err && x509) { // if cert read successfully
+ if(szCertSerial) { // check for specific notary cert serial
+ szSerial[0] = 0;
+ ReadCertSerialNumber(szSerial, sizeof(szSerial), x509);
+ if(!strcmp(szSerial, szCertSerial)) {
+ *ppResp = x509;
+ ddocDebug(4, "findResponder", "assigning CA 1");
+ return ERR_OK;
+ }
+ }
+ if(!t1 || t2 > t1) { // first cert to check
+ t1 = t2;
+ ddocDebug(4, "findResponder", "assigning CA 2");
+ *ppResp = x509;
+ }
+ }
+ } // if p1
+ j++;
+ } while(x509 || j < 10); // until any potential cert found and I have tried to find one of the multiple certs
+ RETURN_IF_NOT(err == ERR_OK, ERR_CERT_READ);
+ ddocDebug(3, "findResponder", "CN: %s hash: %s index: %d, search notary: %s",
+ (szCN ? szCN : "NULL"), (szHash ? szHash : "NULL"), err, (*ppResp ? "OK" : "NULL"));
+ return err;
+}
+
+//--------------------------------------------------
+// Finds Responder certificates CA certs CN
+// caCN - buffer for responders CA CN
+// len - length of buffer for CA CN
+// szCN - responder certs common name
+// hash - responder certs hash in base64 form
+// return error code or 0 for success
+//--------------------------------------------------
+EXP_OPTION int findResponderCA(char* caCN, int len, const char* szCN, const char* hash)
+{
+ int err = ERR_OK, i=0;
+ char buf[50];
+ const char* p;
+
+ // initialize
+ RETURN_IF_NULL_PARAM(caCN);
+ caCN[0] = 0;
+ ddocDebug(3, "findResponderCA", "CA cn: %s, cn-l: %d", caCN, len);
+ err = findResponderIndex(&i, szCN, hash, NULL);
+ ddocDebug(3, "findResponderCA", "Resp idx: %d", i);
+ RETURN_IF_NOT(err == ERR_OK, err);
+ snprintf(buf, sizeof(buf), "DIGIDOC_OCSP_RESPONDER_CERT_%d_CA", i);
+ p = ConfigItem_lookup(buf);
+ ddocDebug(3, "findResponderCA", "Lookup: %s found: %s len: %d", buf, p, len);
+ RETURN_IF_NOT(p != NULL, ERR_OCSP_RESP_NOT_TRUSTED);
+ strncpy(caCN, p, len);
+ return ERR_OK;
+}
+
+//--------------------------------------------------
+// Finds CA certificate of the given certificate
+// ppCA - address of found CA
+// pCert - certificate whose CA we are looking for
+// return error code or 0 for success
+// deprecated use findCAForCertificateAndSigTime()
+//--------------------------------------------------
+DIGIDOC_DEPRECATED EXP_OPTION int findCAForCertificate(X509** ppCA, const X509* pCert)
+{
+ return findCAForCertificateAndSigTime(ppCA, pCert, 0);
+}
+
+//--------------------------------------------------
+// Finds CA certificate of the given certificate
+// ppCA - address of found CA
+// pCert - certificate whose CA we are looking for
+// tSigTime - signature timestamp
+// return error code or 0 for success
+//--------------------------------------------------
+EXP_OPTION int findCAForCertificateAndSigTime(X509** ppCA, const X509* pCert, time_t tSigTime)
+{
+ int err = ERR_OK;
+ DigiDocMemBuf mbuf1, mbuf2;
+
+ mbuf1.pMem = 0;
+ mbuf1.nLen = 0;
+ mbuf2.pMem = 0;
+ mbuf2.nLen = 0;
+ // read cert issuers CN
+ err = ddocCertGetIssuerCN((X509*)pCert, &mbuf1);
+ RETURN_IF_NOT(err == ERR_OK, ERR_PKCS_CERT_DECODE);
+ RETURN_IF_NOT(mbuf1.pMem, ERR_PKCS_CERT_DECODE); // PR. fix crash
+ err = readAuthorityKeyIdentifier((X509*)pCert, &mbuf2);
+ RETURN_IF_NOT(err == ERR_OK, err);
+ err = findCAForCNAndSigTime(ppCA, (const char*)mbuf1.pMem, &mbuf2, tSigTime);
+ ddocMemBuf_free(&mbuf1);
+ ddocMemBuf_free(&mbuf2);
+ RETURN_IF_NOT(err == ERR_OK, err);
+ return err;
+}
+
+//--------------------------------------------------
+// Finds CA chain
+// ppChain - address of cert pointer array
+// nMaxChain - index of last cert in returned array - 0 based
+// szCN - CN of the first CA cert (not the child cert!)
+// pCert - certificate to search ca-s for
+// return error code or 0 for success
+// deprecated use findCAChainForCNAndSigTime()
+//--------------------------------------------------
+DIGIDOC_DEPRECATED EXP_OPTION int findCAChainForCN(X509** ppChain, int* nMaxChain, const char* szCN, X509* pCert)
+{
+ return findCAChainForCNAndSigTime(ppChain, nMaxChain, szCN, pCert, 0);
+}
+
+//--------------------------------------------------
+// Finds CA chain
+// ppChain - address of cert pointer array
+// nMaxChain - index of last cert in returned array - 0 based
+// szCN - CN of the first CA cert (not the child cert!)
+// pCert - certificate to search ca-s for
+// tSigTime - signature timestamp
+// return error code or 0 for success
+//--------------------------------------------------
+EXP_OPTION int findCAChainForCNAndSigTime(X509** ppChain, int* nMaxChain, const char* szCN, X509* pCert, time_t tSigTime)
+{
+ int err = ERR_OK, i;
+ char oldcn[300], buf3[100];
+ X509 * caCerts[NUM_SEARCH_CAS];
+ DigiDocMemBuf mbuf1, mbuf2, mbuf3;
+
+ mbuf1.pMem = 0;
+ mbuf1.nLen = 0;
+ mbuf2.pMem = 0;
+ mbuf2.nLen = 0;
+ mbuf3.pMem = 0;
+ mbuf3.nLen = 0;
+ RETURN_IF_NULL_PARAM(ppChain);
+ RETURN_IF_NULL_PARAM(nMaxChain);
+ RETURN_IF_NULL_PARAM(szCN);
+ // initialize
+ for(i = 0; i < NUM_SEARCH_CAS; i++)
+ caCerts[i] = 0;
+ for(i = 0; i < NUM_SEARCH_CAS; i++)
+ ppChain[i] = NULL;
+ i = 0;
+ memset(oldcn, 0, sizeof(oldcn));
+ strncpy(oldcn, szCN, sizeof(oldcn));
+ *nMaxChain = -1;
+ if(pCert != NULL) {
+ err = readAuthorityKeyIdentifier(pCert, &mbuf2);
+ ddocEncodeBase64(&mbuf2, &mbuf3);
+ memset(buf3, 0, sizeof(buf3));
+ ReadCertSerialNumber(buf3, sizeof(buf3), pCert);
+ ddocDebug(3, "findCAChainForCN", "Subj cert nr: %s, auth-key: %s", buf3, (char*)mbuf3.pMem);
+ ddocMemBuf_free(&mbuf3);
+ }
+ do {
+ if(caCerts[i]) { // for first ca it is null
+ err = readAuthorityKeyIdentifier(caCerts[i], &mbuf2);
+ ddocEncodeBase64(&mbuf2, &mbuf3);
+ ddocDebug(3, "findCAChainForCN", "CA cert: %d, auth-key: %s", i, (char*)mbuf3.pMem);
+ ddocMemBuf_free(&mbuf3);
+ if(err)
+ return err;
+ }
+ err = findCAForCNAndSigTime(&caCerts[i], oldcn, &mbuf2, tSigTime);
+ ddocMemBuf_free(&mbuf2);
+ ddocDebug(3, "findCAChainForCN", "Read CA for CN: %s idx: %d rc: %d", oldcn, i, err);
+ SET_LAST_ERROR_IF_NOT(err == ERR_OK, err);
+ if (caCerts[i] && !err) {
+ err = ddocCertGetIssuerCN(caCerts[i], &mbuf1);
+ ddocDebug(3, "findCAChainForCN", "Issuer: %s old was: %s, rc: %d",
+ (const char*)mbuf1.pMem, oldcn, err);
+ SET_LAST_ERROR_IF_NOT(err == ERR_OK, err);
+ }
+ if(caCerts[i] && !err && mbuf1.pMem && !strcmp((const char*)mbuf1.pMem, oldcn) && i == 0) {
+ ppChain[0] = caCerts[0];
+ *nMaxChain = 0;
+ return err;
+ } else
+ if(!err && mbuf1.pMem && strcmp((const char*)mbuf1.pMem, oldcn)) {
+ i++;
+ if(!err)
+ strncpy(oldcn, (const char*)mbuf1.pMem, sizeof(oldcn) );
+ ddocMemBuf_free(&mbuf1);
+ } else {
+ ddocMemBuf_free(&mbuf1);
+ break;
+ }
+ } while (err == ERR_OK);
+ *nMaxChain = i;
+ ddocDebug(3, "findCAChainForCN", "Found: %d certs", (*nMaxChain) + 1);
+ // now reverse the chain such that the root CA is at the top - is it necessary??? // PR fix index
+ for(i = 0; i <= *nMaxChain; i++)
+ ppChain[i] = caCerts[(*nMaxChain) - i];
+ return err;
+}
+
+//------------------------------------------
+// Get a notary confirmation for signature
+// pSigDoc - signed document pointer
+// pSigInfo - signature to notarize
+// returns error code
+//------------------------------------------
+EXP_OPTION int notarizeSignature(SignedDoc* pSigDoc, SignatureInfo* pSigInfo)
+{
+ return notarizeSignatureWithIp(pSigDoc, pSigInfo, 0);
+}
+
+//------------------------------------------
+// Selects correct OCSP URL for this certificate
+// issuerDN - certificate issuer DN
+// ppOcspUrl - returned OCSP url or NULL if not found
+// returns error code or ERR_OK
+//------------------------------------------
+int ddocSelectOcspUrl(char* issuerDN, char** ppOcspUrl)
+{
+ int err = ERR_OK, i;
+ char buf1[100], *p;
+
+ RETURN_IF_NULL_PARAM(ppOcspUrl);
+ // get default OCSP URL
+ *ppOcspUrl = (char*)ConfigItem_lookup("DIGIDOC_OCSP_URL");
+ // if possible find OCSP URL by signers CA
+ ddocDebug(3, "ddocSelectOcspUrl", "signers CA: %s", (issuerDN ? issuerDN : "NULL"));
+ if(issuerDN) {
+ buf1[0] = 0;
+ findCN(issuerDN, buf1, sizeof(buf1));
+ ddocDebug(3, "ddocSelectOcspUrl", "signers CA CN: %s", buf1);
+ findResponderIndex(&i, NULL, NULL, buf1);
+ if(i > 0) {
+ snprintf(buf1, sizeof(buf1), "DIGIDOC_OCSP_RESPONDER_CERT_%d_URL", i);
+ p = (char*)ConfigItem_lookup(buf1);
+ if(p) {
+ *ppOcspUrl = p;
+ ddocDebug(3, "ddocSelectOcspUrl", "Selected OCSP URL: %s", p);
+ }
+ }
+ buf1[0] = 0;
+ }
+ if(!(*ppOcspUrl)) {
+ ddocDebug(1, "ddocSelectOcspUrl", "ERR112 ocsp url: %s", (*ppOcspUrl ? *ppOcspUrl : "NULL"));
+ SET_LAST_ERROR(ERR_UNKNOWN_CA);
+ err = ERR_UNKNOWN_CA;
+ } else {
+ ddocDebug(3, "ddocSelectOcspUrl", "Selected OCSP URL: %s", *ppOcspUrl);
+ }
+ return err;
+}
+
+int ddocFindCaChainForCert(X509* pCert,
+ X509** caCerts, int *nCerts,
+ char* szCA, int caLen)
+{
+ int err = ERR_OK, i;
+ DigiDocMemBuf mbuf1, mbuf2;
+
+ RETURN_IF_NULL_PARAM(caCerts);
+ RETURN_IF_NULL_PARAM(nCerts);
+ RETURN_IF_NULL_PARAM(szCA);
+ mbuf1.pMem = 0;
+ mbuf1.nLen = 0;
+ mbuf2.pMem = 0;
+ mbuf2.nLen = 0;
+ for(i = 0; i < NUM_SEARCH_CAS; i++)
+ caCerts[i] = 0;
+ szCA[0] = 0;
+ err = ddocCertGetIssuerDN(pCert, &mbuf1);
+ err = ddocCertGetSubjectDN(pCert, &mbuf2);
+ ddocDebug(3, "ddocFindCaChainForCert", "Find chain for: %s issuer: %s",
+ (char*)mbuf2.pMem, (char*)mbuf1.pMem);
+ if(!err) {
+ err = findCN((char*)mbuf1.pMem, szCA, caLen);
+ ddocDebug(3, "ddocFindCaChainForCert", "Find chain for CN: %s", szCA);
+ if(!err) {
+ err = findCAChainForCNAndSigTime(caCerts, nCerts, szCA, pCert, 0);
+ ddocDebug(3, "ddocFindCaChainForCert", "Chain length: %d, err: %d", *nCerts, err);
+ }
+ }
+ ddocMemBuf_free(&mbuf1);
+ ddocMemBuf_free(&mbuf2);
+ return err;
+}
+
+int ddocFindOcspCnCaAndCerts(OCSP_RESPONSE* pResp, int *nType,
+ X509** caCerts, int *nCerts,
+ char* szCN, int cnLen,
+ char* szCA, int caLen)
+{
+ int err = ERR_OK, i;
+ DigiDocMemBuf mbuf1;
+
+ RETURN_IF_NULL_PARAM(pResp);
+ RETURN_IF_NULL_PARAM(nType);
+ RETURN_IF_NULL_PARAM(caCerts);
+ RETURN_IF_NULL_PARAM(nCerts);
+ RETURN_IF_NULL_PARAM(szCN);
+ RETURN_IF_NULL_PARAM(szCA);
+ mbuf1.pMem = 0;
+ mbuf1.nLen = 0;
+ for(i = 0; i <= NUM_SEARCH_CAS; i++)
+ caCerts[i] = 0;
+ szCN[0] = szCA[0] = 0;
+ // find responder id type and value
+ ddocDebug(3, "ddocFindOcspCnCaAndCerts", "OCSP: %s", (pResp ? "OK" : "NO"));
+ err = ddocGetOcspRespIdTypeAndValue(pResp, nType, &mbuf1);
+ if((*nType) == RESPID_NAME_TYPE) {
+ err = findCN((char*)mbuf1.pMem, szCN, cnLen);
+ if (!err)
+ err = findResponderCA(szCA, caLen, szCN, NULL);
+ }
+ else if((*nType) == RESPID_KEY_TYPE) {
+ i = sizeof(szCN);
+ encode((const byte*)mbuf1.pMem, mbuf1.nLen, (byte*)szCN, &i);
+ if (!err)
+ err = findResponderCA(szCA, caLen, NULL, szCN);
+ }
+ else {
+ SET_LAST_ERROR(ERR_OCSP_WRONG_RESPID);
+ err = ERR_OCSP_WRONG_RESPID;
+ }
+ ddocDebug(3, "ddocFindOcspCnCaAndCerts", "Responder CN: %s CA: %s, RC: %d", szCN, szCA, err);
+ // find CA chain
+ if(err == ERR_OK)
+ err = findCAChainForCNAndSigTime(caCerts, nCerts, szCA, NULL, 0);
+ ddocDebug(3, "ddocFindOcspCnCaAndCerts", "Chain length: %d, err: %d", *nCerts, err);
+ // cleanup
+ ddocMemBuf_free(&mbuf1);
+ return err;
+}
+
+//------------------------------------------
+// Get a notary confirmation for signature
+// pSigDoc - signed document pointer
+// pSigInfo - signature to notarize
+// ip - callers ip address if known
+// returns error code
+//------------------------------------------
+EXP_OPTION int notarizeSignatureWithIp(SignedDoc* pSigDoc, SignatureInfo* pSigInfo, unsigned long ip)
+{
+ NotaryInfo* pNotInfo;
+ int err = ERR_OK, nCAs = NUM_SEARCH_CAS, i, j, err2 = 0, nType;
+ X509* caCerts[NUM_SEARCH_CAS+1];
+ X509* pNotCert, *pSigCert = 0, *pSigCa = 0;
+ //AM 24.09.08 szCA size from 30 to 100 for Portuguese ID card
+ char szCN[200], szCA[100];
+ char *pkcs12file, *pkcs12passwd, *ocspUrl;
+ char *proxyHost, *proxyPort, *proxyUser, *proxyPass;
+ OCSP_RESPONSE *pResp = 0;
+ CertValue *pCertValue = 0;
+
+ // PR. index fix
+ for(i = 0; i < NUM_SEARCH_CAS; i++)
+ caCerts[i] = 0;
+ if(ConfigItem_lookup_bool("SIGN_OCSP", 1)) {
+ pkcs12file = (char*)ConfigItem_lookup("DIGIDOC_PKCS_FILE");
+ RETURN_IF_NOT(pkcs12file, ERR_OCSP_PKCS12_NO_FILE);
+ pkcs12passwd = (char*)ConfigItem_lookup("DIGIDOC_PKCS_PASSWD");
+ //RETURN_IF_NOT(pkcs12passwd, ERR_OCSP_PKCS12_NO_PASSWD);
+ } else {
+ pkcs12file = pkcs12passwd = NULL;
+ }
+ if(ConfigItem_lookup_bool("USE_PROXY", 1)) {
+ proxyHost = (char*)ConfigItem_lookup("DIGIDOC_PROXY_HOST");
+ RETURN_IF_NOT(proxyHost, ERR_WRONG_URL_OR_PROXY);
+ proxyPort = (char*)ConfigItem_lookup("DIGIDOC_PROXY_PORT");
+ RETURN_IF_NOT(proxyPort, ERR_WRONG_URL_OR_PROXY);
+ proxyUser = (char*)ConfigItem_lookup("DIGIDOC_PROXY_USER");
+ proxyPass = (char*)ConfigItem_lookup("DIGIDOC_PROXY_PASS");
+ ddocDebug(4, "notarizeSignature", "proxy: %s port : %s", proxyHost, proxyPort);
+ } else {
+ proxyHost = proxyPort = proxyUser = proxyPass = NULL;
+ }
+ err = ddocSelectOcspUrl((char*)ddocSigInfo_GetSignersCert_IssuerName(pSigInfo), &ocspUrl);
+ RETURN_IF_NOT(err == ERR_OK, err);
+ // get signers ca certs
+ pSigCert = ddocSigInfo_GetSignersCert(pSigInfo);
+ err = ddocFindCaChainForCert(pSigCert, caCerts, &nCAs, szCA, sizeof(szCA));
+ RETURN_IF_NOT(nCAs >= 0, ERR_SIGNERS_CERT_NOT_TRUSTED);
+ pSigCa = caCerts[nCAs];
+ // get OCSP confirmation
+ ddocDebug(3, "notarizeSignatureWithIp", "Getting OCSP confirmation");
+ err = getConfirmationWithIpEx(pSigDoc, pSigInfo, (const X509 **)caCerts, NULL,
+ pkcs12file, pkcs12passwd, ocspUrl,
+ proxyHost, proxyPort, proxyUser, proxyPass, ip);
+ // release ca certs
+ nCAs=10;
+ for(i = 0; i < NUM_SEARCH_CAS; i++) {
+ if(caCerts[i] && caCerts[i] != pSigCa) {
+ X509_free(caCerts[i]);
+ caCerts[i] = 0;
+ }
+ }
+ // continue with the rest
+ RETURN_IF_NOT(err == ERR_OK, err);
+ pNotInfo = getNotaryWithSigId(pSigDoc, pSigInfo->szId);
+ RETURN_IF_NOT(pNotInfo != NULL, ERR_NOTARY_SIG_MATCH);
+ // get OCSP response
+ pResp = ddocNotInfo_GetOCSPResponse_Value(pNotInfo);
+ RETURN_IF_NOT(pResp != NULL, ERR_NOTARY_SIG_MATCH);
+ // find CN from responder-id, right CA and CA certs chain
+ err = ddocFindOcspCnCaAndCerts(pResp, &nType, (X509**)caCerts, &nCAs,
+ szCN, sizeof(szCN), szCA, sizeof(szCA));
+ // find usable responder cert by trying all of them
+ // until verification with one succedes
+ if(err == ERR_OK) {
+ j = 0;
+ do {
+ pNotCert = 0;
+ err2 = ERR_OK;
+ if(nType == RESPID_NAME_TYPE)
+ findResponderByCNAndHashAndIndex(&pNotCert, szCN, NULL, j);
+ else if(nType == RESPID_KEY_TYPE)
+ findResponderByCNAndHashAndIndex(&pNotCert, NULL, szCN, j);
+ ddocDebug(1, "notarizeSignatureWithIp", "Find notary: %s idx: %d cert: %s", szCN, j, (pNotCert ? "OK" : "NULL"));
+ if(pNotCert) {
+ err2 = finalizeAndVerifyNotary2(pSigDoc, pSigInfo,
+ pNotInfo, (const X509**)&caCerts, (const X509*)pNotCert, (const X509*)pSigCa);
+ ddocDebug(1, "notarizeSignatureWithIp", "Verifying notary: %d", err);
+ j++;
+ if(err2) {
+ // VS: release ownership before deletion
+ pCertValue = ddocSigInfo_GetOrCreateCertValueOfType(pSigInfo, CERTID_VALUE_RESPONDERS_CERT);
+ if(pCertValue && pCertValue->pCert == pNotCert) {
+ ddocDebug(1, "notarizeSignatureWithIp", "Release notary cert err2: %d", err2);
+ pCertValue->pCert = NULL;
+ }
+ X509_free(pNotCert);
+ }
+ }
+ } while(pNotCert && err2 != ERR_OK);
+ }
+ if(pSigCa)
+ X509_free(pSigCa);
+ if(err2)
+ err = err2;
+ else
+ clearErrors();
+ for(i = 0; i < NUM_SEARCH_CAS; i++)
+ if(caCerts[i])
+ X509_free(caCerts[i]);
+ if(pResp)
+ OCSP_RESPONSE_free(pResp);
+ // test if not cert is ok
+ pCertValue = ddocSigInfo_GetOrCreateCertValueOfType(pSigInfo, CERTID_VALUE_RESPONDERS_CERT);
+ ddocDebug(3, "notarizeSignatureWithIp", "End Notary: cert-val: %s cert: %s",
+ ((pCertValue && pCertValue->pCert) ? "OK" : "NULL"), (pNotCert ? "OK" : "NULL"));
+ // please note that we cannot free pNotCert here because we gave ownership to pNotInf!
+ return err;
+}
+
+//--------------------------------------------------
+// Signs the document and gets configrmation
+// pSigDoc - signed document pointer
+// ppSigInfo - address of new signature pointer
+// pin - smart card PIN
+// manifest - manifest / resolution (NULL)
+// city - signers city (NULL)
+// state - signers state (NULL)
+// zip - signers postal code (NULL)
+// country - signers country (NULL)
+//--------------------------------------------------
+EXP_OPTION int signDocument(SignedDoc* pSigDoc, SignatureInfo** ppSigInfo,
+ const char* pin, const char* manifest,
+ const char* city, const char* state,
+ const char* zip, const char* country)
+{
+ return signDocumentWithSlot(pSigDoc, ppSigInfo, pin, manifest,
+ city, state, zip, country,
+ ConfigItem_lookup_int("DIGIDOC_SIGNATURE_SLOT", 0), 1, 1);
+}
+
+//--------------------------------------------------
+// Signs the document and gets configrmation
+// pSigDoc - signed document pointer
+// ppSigInfo - address of new signature pointer
+// pin - smart card PIN
+// manifest - manifest / resolution (NULL)
+// city - signers city (NULL)
+// state - signers state (NULL)
+// zip - signers postal code (NULL)
+// country - signers country (NULL)
+//--------------------------------------------------
+EXP_OPTION int signDocumentWithSlot(SignedDoc* pSigDoc, SignatureInfo** ppSigInfo,
+ const char* pin, const char* manifest,
+ const char* city, const char* state,
+ const char* zip, const char* country,
+ int nSlot, int nOcsp, int nSigner)
+{
+ return signDocumentWithSlotAndSigner(pSigDoc, ppSigInfo, pin, manifest,
+ city, state, zip, country, nSlot, nOcsp, nSigner, NULL);
+}
+
+//--------------------------------------------------
+// Signs the document and gets configrmation
+// pSigDoc - signed document pointer
+// ppSigInfo - address of new signature pointer
+// pin - smart card PIN
+// manifest - manifest / resolution (NULL)
+// city - signers city (NULL)
+// state - signers state (NULL)
+// zip - signers postal code (NULL)
+// country - signers country (NULL)
+// nSigner - 1=PKCS11, 2=CNG (Microsoft CAPI)
+// szPkcs12FileName - PKCS#12 file name to be used for signing (required if nSigner=3)
+//--------------------------------------------------
+EXP_OPTION int signDocumentWithSlotAndSigner(SignedDoc* pSigDoc, SignatureInfo** ppSigInfo,
+ const char* pin, const char* manifest,
+ const char* city, const char* state,
+ const char* zip, const char* country,
+ int nSlot, int nOcsp, int nSigner,
+ const char* szPkcs12FileName)
+{
+ int err = ERR_OK;
+ SignatureInfo* pSigInfo = NULL;
+
+ RETURN_IF_NULL_PARAM(pSigDoc);
+ RETURN_IF_NULL_PARAM(ppSigInfo);
+ if(nSigner == 3)
+ RETURN_IF_NULL_PARAM(szPkcs12FileName)
+ if(!pSigDoc->szFormatVer ||
+ strcmp(pSigDoc->szFormatVer, DIGIDOC_XML_1_3_VER) ||
+ !pSigDoc->szFormat ||
+ strcmp(pSigDoc->szFormat, DIGIDOC_XML_1_1_NAME)) {
+ SET_LAST_ERROR(ERR_UNSUPPORTED_FORMAT);
+ return ERR_UNSUPPORTED_FORMAT;
+ }
+ clearErrors();
+
+ ddocDebug(1, "signDocument", "Creating new digital signature");
+ RETURN_IF_NOT(err == ERR_OK, err);
+
+ // add new signature with default id
+ err = SignatureInfo_new(&pSigInfo, pSigDoc, NULL);
+ RETURN_IF_NOT(err == ERR_OK, err);
+ *ppSigInfo = pSigInfo;
+ // automatically calculate doc-info elements for this signature
+ addAllDocInfos(pSigDoc, *ppSigInfo);
+ // add signature production place
+ if (city || state || zip || country)
+ err = setSignatureProductionPlace(*ppSigInfo, city, state, zip, country);
+ // add user roles
+ if (manifest)
+ err = addSignerRole(*ppSigInfo, 0, manifest, -1, 0);
+ ddocDebug(1, "signDocument", "Calc signature");
+ // now sign the doc
+ if(nSigner == 1 || !nSigner)
+ err = calculateSignatureWithEstID(pSigDoc, *ppSigInfo, nSlot, pin);
+#ifdef WIN32
+ if(nSigner == 2)
+ err = calculateSigInfoSignatureWithCSPEstID(pSigDoc, *ppSigInfo, 0, pin);
+#endif
+ if(nSigner == 3)
+ err = calculateSignatureWithPkcs12(pSigDoc, *ppSigInfo, szPkcs12FileName, pin);
+ if(err == ERR_PKCS_LOGIN) return err;
+ RETURN_IF_NOT(err == ERR_OK, ERR_PKCS_SIGN_DATA);
+ if(nOcsp)
+ err = notarizeSignature(pSigDoc, *ppSigInfo);
+ RETURN_IF_NOT(err == ERR_OK, err);
+ return ERR_OK;
+}
+
+//--------------------------------------------------
+// Verify this notary
+// pSigDoc - signed document pointer
+// pNotInfo - notary to verify
+// returns error code
+//--------------------------------------------------
+int verifyNotary(SignedDoc* pSigDoc, SignatureInfo* pSigInfo, NotaryInfo* pNotInfo)
+{
+ int err = ERR_OK, nCAs = NUM_SEARCH_CAS, i, err2 = 0;
+ X509 * caCerts[NUM_SEARCH_CAS];
+ X509* pNotCert = 0, *pCaCert = 0;
+ const DigiDocMemBuf *pMBuf = 0;
+ char buf1[300], buf2[300], szNotSerial[100];
+ int mustFreeNotaryCert = 0;
+
+ for (i = 0; i < NUM_SEARCH_CAS; i++)
+ caCerts[i] = 0;
+ // get responder certs serial nr
+ szNotSerial[0] = 0;
+ if(ddocSigInfo_GetOCSPRespondersCert(pSigInfo))
+ err = ReadCertSerialNumber(szNotSerial, sizeof(szNotSerial),
+ ddocSigInfo_GetOCSPRespondersCert(pSigInfo));
+ // find responder cert and it's CA cert
+ pMBuf = ddocNotInfo_GetResponderId(pNotInfo);
+ RETURN_IF_NULL(pMBuf);
+ memset(buf2, 0, sizeof(buf2));
+ // use responders cert from ddoc
+ //pNotCert = ddocSigInfo_GetOCSPRespondersCert(pSigInfo);
+
+ if(pNotInfo->nRespIdType == RESPID_NAME_TYPE) {
+ err = findCN((char*)pMBuf->pMem, buf1, sizeof(buf1));
+ ddocDebug(3, "verifyNotary", "Responder text: %s", buf1);
+ if (!err) {
+ err = findResponderCA(buf2, sizeof(buf2), buf1, NULL);
+ ddocDebug(3, "verifyNotary", "Responder CA: %s", buf2);
+ }
+ if(!err) {
+ err = findResponder(&pNotCert, buf1, NULL, (strlen(szNotSerial) ? szNotSerial : NULL));
+ ddocDebug(3, "verifyNotary", "Responder %s cert: %s, err: %d", buf1,
+ (pNotCert ? "OK" : "NULL"), err);
+ }
+ }
+ else if(pNotInfo->nRespIdType == RESPID_KEY_TYPE) {
+ i = sizeof(buf1);
+ encode((const byte*)pMBuf->pMem, pMBuf->nLen, (byte*)buf1, &i);
+ ddocDebug(3, "verifyNotary", "Responder bin: %s", buf1);
+ if (!err) {
+ err = findResponderCA(buf2, sizeof(buf2), NULL, buf1);
+ ddocDebug(3, "verifyNotary", "Responder CA: %s", buf2);
+ }
+ if(!err) {
+ err = findResponder(&pNotCert, NULL, buf1, (strlen(szNotSerial) ? szNotSerial : NULL));
+ ddocDebug(3, "verifyNotary", "Responder %s cert: %s, err: %d", buf1,
+ (pNotCert ? "OK" : "NULL"), err);
+ }
+ }
+ else {
+ SET_LAST_ERROR(ERR_OCSP_WRONG_RESPID);
+ err = ERR_OCSP_WRONG_RESPID;
+ }
+ if (!err) {
+ ddocDebug(3, "verifyNotary", "Find ca chain for: %s", buf2);
+ err = findCAChainForCNAndSigTime((X509**)caCerts, &nCAs, buf2, pNotCert, 0);
+ ddocDebug(3, "verifyNotary", "CA chain for: %s, ca-s: %d, rc: %d", buf2, nCAs+1, err);
+ }
+ // use specific error code for responders cert not found!
+ if(err) {
+ SET_LAST_ERROR(ERR_OCSP_RESP_NOT_TRUSTED);
+ err = ERR_OCSP_RESP_NOT_TRUSTED;
+ }
+ ddocDebug(3, "verifyNotary", "Chain length: %d, err: %d", nCAs+1, err);
+ if(pNotCert) { // #23784 - dont use responders cert in signature, use local copy
+ err = ddocSigInfo_SetOCSPRespondersCert(pSigInfo, pNotCert);
+ ddocDebug(3, "verifyNotary", "assigned notary cert from local store");
+ } else {
+ mustFreeNotaryCert = 1;
+
+ }
+ if (!err) {
+ ddocDebug(3, "verifyNotary", "Verifying Notary %s - cert: %s CA-s: %d", pNotInfo->szId, ((pNotCert) ? "OK" : "NULL"),nCAs+1);
+ err = findCAForCertificateAndSigTime(&pCaCert, ddocSigInfo_GetSignersCert(pSigInfo), 0);
+ err = verifyNotaryInfoCERT2(pSigDoc, pSigInfo, pNotInfo,
+ (const X509**)caCerts, ConfigItem_lookup("CA_CERT_PATH"),
+ pNotCert, pCaCert);
+ ddocDebug(3, "verifyNotary", "Verifying Notary %s - %s", pNotInfo->szId, ((!err) ? "OK" : "ERROR"));
+ }
+ if (mustFreeNotaryCert) {
+ ddocDebug(3, "verifyNotary", "freed notary cert, hopefully all is OK");
+ X509_free(pNotCert);
+ }
+ if (!err) {
+ err = isCertSignedByCERT(ddocSigInfo_GetOCSPRespondersCert(pSigInfo), caCerts[nCAs]);
+ if(err) {
+ err2 = isCertSignedByCERT(ddocSigInfo_GetOCSPRespondersCert(pSigInfo), caCerts[nCAs - 1]);
+ if(!err2) clearErrors(); else err = err2;
+ }
+ ddocDebug(3, "verifyNotary", "\tCertificate trusted - %s", ((!err) ? "OK" : "ERROR"));
+ }
+ // verify notary digest
+ if (!err) {
+ err = verifyNotaryDigest(pSigDoc, pNotInfo);
+ ddocDebug(3, "verifyNotary", "\tNotary digest - %s", ((!err) ? "OK" : "ERROR"));
+ }
+ for (i = 0; i < NUM_SEARCH_CAS; i++) {
+ if(caCerts[i]) {
+ X509_free(caCerts[i]);
+ caCerts[i] = 0;
+ }
+ }
+ if (err != ERR_OK) SET_LAST_ERROR(err);
+ return err;
+}
+
+
+//--------------------------------------------------
+// Verify this signature and it's notary
+// pSigDoc - signed document pointer
+// pSigInfo - signature to verify
+// szFileName - input digidoc filename
+// returns error code
+//--------------------------------------------------
+EXP_OPTION int verifySignatureAndNotary(SignedDoc* pSigDoc, SignatureInfo* pSigInfo, const char* szFileName)
+{
+ int err1 = ERR_OK, err2 = ERR_OK, k;
+ X509* pCA = 0;
+ NotaryInfo* pNotInfo;
+ time_t tProdAt = 0;
+
+ pNotInfo = getNotaryWithSigId(pSigDoc, pSigInfo->szId);
+ if(pNotInfo)
+ ddocNotInfo_GetProducedAt_timet(pNotInfo, &tProdAt);
+ err1 = findCAForCertificateAndSigTime(&pCA, ddocSigInfo_GetSignersCert(pSigInfo), tProdAt);
+ ddocDebug(3, "verifySignatureAndNotary", "Sig: %s find ca: %d, CA: %s sig-time: %ld", pSigInfo->szId, err1, (pCA ? "OK" : "NULL"), (unsigned long)tProdAt);
+ //RETURN_IF_NOT(err == ERR_OK, err);
+ //RETURN_IF_NOT(pCA, ERR_SIGNERS_CERT_NOT_TRUSTED);
+ if(!pCA) {
+ err1 = ERR_SIGNERS_CERT_NOT_TRUSTED;
+ SET_LAST_ERROR(err1);
+ }
+ if(pCA)
+ err2 = verifySignatureInfoCERT(pSigDoc, pSigInfo, pCA, szFileName, 1);
+ if(err2) {
+ SET_LAST_ERROR(err2);
+ err1 = err2;
+ }
+ if (pNotInfo) {
+ err2 = verifyNotary(pSigDoc, pSigInfo, pNotInfo);
+ if(err2) {
+ SET_LAST_ERROR(err2);
+ if(!err1) err1 = err2;
+ }
+ ddocDebug(3, "verifySignatureAndNotary", "verify notary: %d", err2);
+ } else {
+ ddocDebug(3, "verifySignatureAndNotary", "\tSignature has no OCSP confirmation!\n");
+ SET_LAST_ERROR(ERR_NO_OCSP);
+ err2 = ERR_NO_OCSP;
+ if(!err1) err1 = err2;
+ }
+ if((k = getCountOfSignerRoles(pSigInfo, 0)) > 1) {
+ ddocDebug(1, "verifySignatureInfo", "Number of roles: %d, Currently supports max 1 roles", k);
+ SET_LAST_ERROR(ERR_MAX_1_ROLES);
+ err2 = ERR_MAX_1_ROLES;
+ if(!err1) err1 = err2;
+ }
+ //} else
+ // SET_LAST_ERROR(err2);
+ if (pCA)
+ X509_free(pCA);
+ if(pSigInfo->nErr1) // restore possibly cleared parsing err
+ SET_LAST_ERROR(pSigInfo->nErr1);
+ ddocDebug(3, "verifySignatureAndNotary", "Sig: %s err: %d haserr: %d", pSigInfo->szId, err1, hasUnreadErrors());
+ return checkUnknownErr();
+}
+
+//--------------------------------------------------
+// Extract common name from cert DN or responder id
+// src - DN
+// dest - buffer for CN
+// destLen - size of output buffer in bytes
+//--------------------------------------------------
+int findCN(char* src, char* dest, int destLen)
+{
+ char* p1, *p2;
+ int n;
+
+ p1 = strstr(src, "CN=");
+ if(p1) {
+ p1 += 3; // start of CN field
+ // find start of next field
+ p2 = strchr(p1, '=');
+ if(!p2) // if not found then this was the last field
+ p2 = strchr(p1, 0);
+ // if we have found = of next field then move back until before field name
+ if(p2 && *p2 == '=')
+ while(p2 > p1 && isalpha(*(p2-1))) p2--;
+ // remove possible field separators
+ while(p2 > p1 &&
+ (*(p2-1) == ' ' || *(p2-1) == ',' || *(p2-1) == '/'))
+ p2--;
+ if(p2) {
+ n = (int)(p2-p1);
+ if(n >= destLen) n = destLen - 1;
+ strncpy(dest, p1, n);
+ dest[n] = 0;
+ return ERR_OK;
+ }
+ }
+ SET_LAST_ERROR_RETURN_CODE(ERR_CERT_INVALID);
+}
+
+//------------------------------------------
+// Verify certificate by OCSP
+// pCert - certificate to check
+// ppResp - address to return OCSP response. Use NULL if
+// you don't want OCSP response to be returned
+// returns error code
+//------------------------------------------
+EXP_OPTION int ddocVerifyCertByOCSP(X509* pCert, OCSP_RESPONSE **ppResp)
+{
+ return ddocVerifyCertByOCSPWithIp(pCert, ppResp, 0);
+}
+
+//------------------------------------------
+// Verify certificate by OCSP
+// pCert - certificate to check
+// ppResp - address to return OCSP response. Use NULL if
+// you don't want OCSP response to be returned
+// returns error code
+//------------------------------------------
+EXP_OPTION int ddocVerifyCertByOCSPWithIp(X509* pCert, OCSP_RESPONSE **ppResp, unsigned long ip)
+{
+ int err = ERR_OK, nCAs = NUM_SEARCH_CAS, i, j, err2 = ERR_OK, nType;
+ X509 * caCerts[NUM_SEARCH_CAS];
+ X509 *pNotCert = 0;
+ char *pkcs12file, *pkcs12passwd;
+ char *proxyHost, *proxyPort;
+ char szCN[100], szCA[100], *ocspUrl;
+ OCSP_RESPONSE *pResp = NULL;
+ DigiDocMemBuf mbuf1;
+
+ mbuf1.pMem = 0;
+ mbuf1.nLen = 0;
+ // check if OCSP must be signed
+ if(ConfigItem_lookup_bool("SIGN_OCSP", 1)) {
+ pkcs12file = (char*)ConfigItem_lookup("DIGIDOC_PKCS_FILE");
+ RETURN_IF_NOT(pkcs12file, ERR_OCSP_PKCS12_NO_FILE);
+ pkcs12passwd = (char*)ConfigItem_lookup("DIGIDOC_PKCS_PASSWD");
+ RETURN_IF_NOT(pkcs12passwd, ERR_OCSP_PKCS12_NO_PASSWD);
+ } else {
+ pkcs12file = pkcs12passwd = NULL;
+ }
+ // check proxy usage
+ if(ConfigItem_lookup_bool("USE_PROXY", 1)) {
+ proxyHost = (char*)ConfigItem_lookup("DIGIDOC_PROXY_HOST");
+ RETURN_IF_NOT(proxyHost, ERR_WRONG_URL_OR_PROXY);
+ proxyPort = (char*)ConfigItem_lookup("DIGIDOC_PROXY_PORT");
+ RETURN_IF_NOT(proxyPort, ERR_WRONG_URL_OR_PROXY);
+ ddocDebug(4, "ddocVerifyCertByOCSPWithIp", "proxy: %s port : %s", proxyHost, proxyPort);
+ } else {
+ proxyHost = proxyPort = NULL;
+ }
+ // send OCSP request and don't verify result immediately
+ err = ddocCertGetIssuerDN(pCert, &mbuf1);
+ RETURN_IF_NOT(err == ERR_OK, err);
+ err = ddocSelectOcspUrl((char*)mbuf1.pMem, &ocspUrl);
+ ddocMemBuf_free(&mbuf1);
+ RETURN_IF_NOT(err == ERR_OK, err);
+ // find cert oweners CA cert chain
+ err = ddocFindCaChainForCert(pCert, (X509**)caCerts, &nCAs, szCA, sizeof(szCA));
+ // if possible find OCSP URL by signers CA
+ ddocDebug(3, "ddocVerifyCertByOCSPWithIp", "OCSP URL: %s CA: %s chain: %d",
+ (ocspUrl ? ocspUrl : "NULL"), szCA, nCAs);
+ err = verifyCertificateByOCSPWithIp(pCert, (const X509 **)caCerts, NULL, ocspUrl,
+ proxyHost, proxyPort, pkcs12file, pkcs12passwd, &pResp, ip);
+ ddocDebug(3, "ddocVerifyCertByOCSPWithIp", "OCSP verification - RC: %d, resp: %s", err, (pResp ? "OK" : "NULL"));
+ // release cert CA chain, PR. index fix
+ for(i = 0; i < NUM_SEARCH_CAS; i++) {
+ if(caCerts[i]) {
+ X509_free(caCerts[i]);
+ caCerts[i] = 0;
+ }
+ }
+ // verify OCSP response
+ // find CN from responder-id, right CA and CA certs chain
+ if(!err)
+ err = ddocFindOcspCnCaAndCerts(pResp, &nType, (X509**)caCerts, &nCAs,
+ szCN, sizeof(szCN), szCA, sizeof(szCA));
+ // find usable responder cert by trying all of them
+ // until verification with one succedes
+ if(err == ERR_OK) {
+ j = 0;
+ do {
+ pNotCert = 0;
+ err2 = ERR_OK;
+ if(nType == RESPID_NAME_TYPE)
+ findResponderByCNAndHashAndIndex(&pNotCert, szCN, NULL, j);
+ else if(nType == RESPID_KEY_TYPE)
+ findResponderByCNAndHashAndIndex(&pNotCert, NULL, szCN, j);
+ ddocDebug(1, "ddocVerifyCertByOCSPWithIp", "Find notary: %s idx: %d cert: %s", szCN, j, (pNotCert ? "OK" : "NULL"));
+ if(pNotCert)
+ err2 = verifyOCSPResponse(pResp, (const X509**)&caCerts,
+ NULL, (const X509*)pNotCert);
+ ddocDebug(1, "ddocVerifyCertByOCSPWithIp", "Verifying notary: %d", err);
+ j++;
+ if(pNotCert)
+ X509_free(pNotCert);
+ } while(pNotCert && err2 != ERR_OK);
+ }
+ if(err2)
+ err = err2;
+ else
+ clearErrors();
+ for(i = 0; i < NUM_SEARCH_CAS; i++)
+ if(caCerts[i])
+ X509_free(caCerts[i]);
+ // return OCSP response if requested
+ if(pResp) {
+ if(ppResp)
+ *ppResp = pResp;
+ else
+ OCSP_RESPONSE_free(pResp);
+ }
+ return err;
+}
+
+//------------------------------------------
+// Reads an arbitrary file into memory buffer
+// szFileName - file name and path
+// pData - memory buffer object
+// returns error code
+//------------------------------------------
+EXP_OPTION int ddocReadFile(const char* szFileName, DigiDocMemBuf* pData)
+{
+ int err = ERR_OK;
+ long l1;
+ FILE *hFile;
+ char buf1[2050];
+#ifdef WIN32
+ wchar_t *convFileName = 0;
+ int i= 0;
+ err = utf82unicode((const char*)szFileName, (char**)&convFileName, &i);
+ ddocDebug(3, "ddocReadFile", "file: %s, conv-file: %s len: %d", szFileName, convFileName, i);
+#endif
+
+ RETURN_IF_NULL_PARAM(szFileName);
+ RETURN_IF_NULL_PARAM(pData);
+ pData->pMem = 0;
+ pData->nLen = 0;
+#ifdef WIN32
+ hFile = _wfopen(convFileName, L"rb");
+#else
+ hFile = fopen(szFileName, "rb");
+#endif
+ RETURN_IF_NOT(hFile, ERR_FILE_READ);
+ do {
+ l1 = fread(buf1, 1, 2048, hFile);
+ err = ddocMemAppendData(pData, buf1, (long)l1);
+ } while(l1 == 2048 && !err);
+ fclose(hFile);
+ return err;
+}
+
+//------------------------------------------
+// Writes an arbitrary file into memory buffer
+// szFileName - file name and path
+// pData - memory buffer object
+// returns error code
+//------------------------------------------
+EXP_OPTION int ddocWriteFile(const char* szFileName, DigiDocMemBuf* pData)
+{
+ int err = ERR_OK;
+ FILE *hFile;
+#ifdef WIN32
+ wchar_t *convFileName = 0;
+ int i= 0;
+ err = utf82unicode((const char*)szFileName, (char**)&convFileName, &i);
+ ddocDebug(3, "ddocReadFile", "file: %s, conv-file: %s len: %d", szFileName, convFileName, i);
+#endif
+
+ RETURN_IF_NULL_PARAM(szFileName);
+ RETURN_IF_NULL_PARAM(pData);
+#ifdef WIN32
+ hFile = _wfopen(convFileName, L"wb");
+#else
+ hFile = fopen(szFileName, "wb");
+#endif
+ RETURN_IF_NOT(hFile, ERR_FILE_WRITE);
+ if(hFile)
+ fwrite(pData->pMem, 1, pData->nLen, hFile);
+ fclose(hFile);
+ return err;
+}
+
diff --git a/libdigidoc/DigiDocConfig.h b/libdigidoc/DigiDocConfig.h
new file mode 100644
index 0000000..7e4d3e4
--- /dev/null
+++ b/libdigidoc/DigiDocConfig.h
@@ -0,0 +1,425 @@
+#ifndef __DIGI_DOC_CFG_H__
+#define __DIGI_DOC_CFG_H__
+//==================================================
+// FILE: DigiDocCfonfig.h
+// PROJECT: Digi Doc
+// DESCRIPTION: Digi Doc functions for configuration management
+// AUTHOR: Veiko Sinivee, S|E|B IT Partner Estonia
+//==================================================
+// Copyright (C) AS Sertifitseerimiskeskus
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+// GNU Lesser General Public Licence is available at
+// http://www.gnu.org/copyleft/lesser.html
+//==========< HISTORY >=============================
+// 08.01.2004 Veiko Sinivee
+// Creation
+// 20.03.2004 Added functions createOrReplacePrivateConfigItem()
+// writeConfigFile() and writePrivateConfigFile()
+// 20.03.2004 changed function notarizeSignature to check for PKCS12 arguments
+//==================================================
+
+#include <libdigidoc/DigiDocDefs.h>
+#include <libdigidoc/DigiDocLib.h>
+#include <time.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+#include <openssl/x509.h>
+
+
+// item type
+#define ITEM_TYPE_UNKNOWN 0
+#define ITEM_TYPE_GLOBAL 1
+#define ITEM_TYPE_PRIVATE 2
+
+// used to mark modified items to then store all together in private config file
+#define ITEM_STATUS_UNKNOWN 0
+#define ITEM_STATUS_OK 1
+#define ITEM_STATUS_MODIFIED 2
+
+ // holds one configuration item
+ typedef struct ConfigItem_st {
+ char* szKey; // items key
+ char* szValue; // items value
+ int nType; // items type (system wide or private)
+ int nStatus; // item status - clean/modified
+ } ConfigItem;
+
+ // holds one certificate item
+ typedef struct CertificateItem_st {
+ char* szKey; // items key
+ X509* pCert; // certificate
+ } CertificateItem;
+
+ // array of configration items
+ typedef struct ConfigurationStore_st {
+ int nItems;
+ ConfigItem** pItems;
+ int nCerts;
+ CertificateItem** pCerts;
+ } ConfigurationStore;
+
+ //--------------------------------------------------
+ // Returns true (not 0) if config store structure has been inited
+ //--------------------------------------------------
+ EXP_OPTION int isConfigInited();
+
+ //--------------------------------------------------
+ // Initializes configuration store
+ // szConfigFile - name of config file. Use NULL for default
+ //--------------------------------------------------
+ EXP_OPTION int initConfigStore(const char* szConfigFile);
+
+ //--------------------------------------------------
+ // Cleans memory of configuration store
+ // pConfStore - configuration collection (use NULL for default)
+ //--------------------------------------------------
+ EXP_OPTION void cleanupConfigStore(ConfigurationStore *pConfStore);
+
+ //--------------------------------------------------
+ // Adds a new configration item
+ // pConfStore - configuration collection (use NULL for default)
+ // key - items key
+ // value - items value
+ // type - item type
+ // status - item status
+ // returns ERR_OK on success
+ //--------------------------------------------------
+ EXP_OPTION int addConfigItem(ConfigurationStore *pConfStore, const char* key, const char* value, int type, int status);
+
+ //--------------------------------------------------
+ // Read ca and ocsp responder certs from files and cache in memory
+ //--------------------------------------------------
+ int initCertificateItems();
+
+ //--------------------------------------------------
+ // Deletes configration item
+ // key - items key
+ // returns ERR_OK on success
+ //--------------------------------------------------
+ EXP_OPTION int ConfigItem_delete(const char* key);
+
+ //--------------------------------------------------
+ // Adds a new private configration item or modifies
+ // pConfStore - configuration collection (use NULL for default)
+ // an existing one
+ // key - items key
+ // value - items value
+ // returns ERR_OK on success
+ //--------------------------------------------------
+ EXP_OPTION int createOrReplacePrivateConfigItem(ConfigurationStore *pConfStore, const char* key, const char* value);
+
+ //--------------------------------------------------
+ // Finds a new configration items value by key
+ // key - items key
+ // returns value of config item or NULL if not found
+ //--------------------------------------------------
+ EXP_OPTION const char* ConfigItem_lookup(const char* key);
+
+ //--------------------------------------------------
+ // Finds a new configration items value by key from the store
+ // key - items key
+ // pConfStore - store to search in
+ // returns value of config item or NULL if not found
+ //--------------------------------------------------
+ EXP_OPTION const char* ConfigItem_lookup_fromStore(ConfigurationStore *pConfStore, const char* key);
+
+ //--------------------------------------------------
+ // Finds a all configration items that start with this prefix
+ // pConfStore - collection of found items
+ // prefix - item keys prefix
+ // returns error code or ERR_OK
+ //--------------------------------------------------
+ int ConfigItem_findByPrefix(ConfigurationStore *pConfStore, const char* prefix);
+
+ //--------------------------------------------------
+ // Finds a numeric configration items value by key
+ // key - items key
+ // defValue - default value to be returned
+ // returns value of config item or defValue if not found
+ //--------------------------------------------------
+ EXP_OPTION int ConfigItem_lookup_int(const char* key, int defValue);
+
+ //--------------------------------------------------
+ // Finds a bolean configration items value by key
+ // key - items key
+ // defValue - default value to be returned
+ // returns value of config item or defValue if not found
+ //--------------------------------------------------
+ EXP_OPTION int ConfigItem_lookup_bool(const char* key, int defValue);
+
+ //--------------------------------------------------
+ // Finds a new configration items value by key
+ // key - items key
+ // returns value of config item or NULL if not found
+ //--------------------------------------------------
+ EXP_OPTION const char* ConfigItem_lookup_str(const char* key, const char* defValue);
+
+ //--------------------------------------------------
+ // Reads and parses configuration file
+ // fileName - configuration file name
+ // type - type of config file global/private
+ // return error code or 0 for success
+ //--------------------------------------------------
+ EXP_OPTION int readConfigFile(const char* fileName, int type);
+
+ //--------------------------------------------------
+ // Writes a configuration file
+ // fileName - configuration file name
+ // type - type of config file global/private
+ // return error code or 0 for success
+ //--------------------------------------------------
+ EXP_OPTION int writeConfigFile(const char* fileName, int type);
+
+ //--------------------------------------------------
+ // Saves all private config items in correct file
+ // return error code or 0 for success
+ //--------------------------------------------------
+ EXP_OPTION int writePrivateConfigFile();
+
+ //--------------------------------------------------
+ // Sets a new name for private config file. Can be
+ // used to override default of env(HOME)/.digidoc.conf
+ // Use NULL to restore default value
+ //--------------------------------------------------
+ EXP_OPTION void setPrivateConfigFile(const char* fileName);
+
+ //--------------------------------------------------
+ // Finds CA certificate of the given certificate
+ // ppCA - address of found CA
+ // pCert - certificate whose CA we are looking for
+ // return error code or 0 for success
+ // deprecated use findCAForCertificateAndSigTime()
+ //--------------------------------------------------
+ DIGIDOC_DEPRECATED EXP_OPTION int findCAForCertificate(X509** ppCA, const X509* pCert);
+
+ //--------------------------------------------------
+ // Finds CA certificate of the given certificate
+ // ppCA - address of found CA
+ // pCert - certificate whose CA we are looking for
+ // tSigTime - signature timestamp
+ // return error code or 0 for success
+ //--------------------------------------------------
+ EXP_OPTION int findCAForCertificateAndSigTime(X509** ppCA, const X509* pCert, time_t tSigTime);
+
+ //--------------------------------------------------
+ // Finds CA certificate by CN
+ // ppCA - address of found CA
+ // szCN - CA certs common name
+ // pHash - authority-key-identifier to search for CA
+ // return error code or 0 for success
+ // deprecated use findCAForCNAndSigTime()
+ //--------------------------------------------------
+ DIGIDOC_DEPRECATED EXP_OPTION int findCAForCN(X509** ppCA, const char* szCN, DigiDocMemBuf *pHash);
+
+ //--------------------------------------------------
+ // Finds CA certificate by CN
+ // ppCA - address of found CA
+ // szCN - CA certs common name
+ // pHash - authority-key-identifier to search for CA
+ // tSigTime - signing time or 0
+ // return error code or 0 for success
+ //--------------------------------------------------
+ EXP_OPTION int findCAForCNAndSigTime(X509** ppCA, const char* szCN, DigiDocMemBuf *pHash, time_t tSigTime);
+
+ //--------------------------------------------------
+ // Finds CA chain
+ // ppChain - address of cert pointer array
+ // nMaxChain - index of last cert in returned array - 0 based
+ // szCN - CN of the first CA cert (not the child cert!)
+ // pCert - certificate to search ca-s for
+ // return error code or 0 for success
+ // deprecated use findCAChainForCNAndSigTime()
+ //--------------------------------------------------
+ DIGIDOC_DEPRECATED EXP_OPTION int findCAChainForCN(X509** ppChain, int* nMaxChain, const char* szCN, X509* pCert);
+
+ //--------------------------------------------------
+ // Finds CA chain
+ // ppChain - address of cert pointer array
+ // nMaxChain - index of last cert in returned array - 0 based
+ // szCN - CN of the first CA cert (not the child cert!)
+ // pCert - certificate to search ca-s for
+ // tSigTime - signature timestamp
+ // return error code or 0 for success
+ //--------------------------------------------------
+ EXP_OPTION int findCAChainForCNAndSigTime(X509** ppChain, int* nMaxChain, const char* szCN, X509* pCert, time_t tSigTime);
+
+ //--------------------------------------------------
+ // Finds Responders certificate by CN
+ // ppResp - address of found cert
+ // szCN - Responder certs common name
+ // hash - responder certs hash in base64 form
+ // szCertSerial - specific serial number to search
+ // return error code or 0 for success
+ //--------------------------------------------------
+ EXP_OPTION int findResponder(X509** ppResp, const char* szCN,
+ const char* szHash, char* szCertSerial);
+
+ //--------------------------------------------------
+ // Finds Responders certificate by CN and index
+ // ppResp - address of found cert
+ // szCN - Responder certs common name
+ // hash - responder certs hash in base64
+ // nIdx - index of the certificate for this respnder. Starts at 0
+ // return error code or 0 for success
+ //--------------------------------------------------
+ EXP_OPTION int findResponderByCNAndHashAndIndex(X509** ppResp, const char* szCN,
+ const char* hash, int nIdx);
+
+ //--------------------------------------------------
+ // Finds Responder certificates CA certs CN
+ // caCN - buffer for responders CA CN
+ // len - length of buffer for CA CN
+ // szCN - responder certs common name
+ // hash - responder certs hash in base64 form
+ // return error code or 0 for success
+ //--------------------------------------------------
+ EXP_OPTION int findResponderCA(char* caCN, int len, const char* szCN, const char* hash);
+
+ //------------------------------------------
+ // Get a notary confirmation for signature
+ // pSigDoc - signed document pointer
+ // pSigInfo - signature to notarize
+ // returns error code
+ //------------------------------------------
+ EXP_OPTION int notarizeSignature(SignedDoc* pSigDoc, SignatureInfo* pSigInfo);
+
+ //------------------------------------------
+ // Get a notary confirmation for signature
+ // pSigDoc - signed document pointer
+ // pSigInfo - signature to notarize
+ // ip - callers ip address if known
+ // returns error code
+ //------------------------------------------
+ EXP_OPTION int notarizeSignatureWithIp(SignedDoc* pSigDoc, SignatureInfo* pSigInfo, unsigned long ip);
+
+ //--------------------------------------------------
+ // Signs the document and gets configrmation
+ // pSigDoc - signed document pointer
+ // ppSigInfo - address of new signature pointer
+ // pin - smart card PIN
+ // manifest - manifest / resolution (NULL)
+ // city - signers city (NULL)
+ // state - signers state (NULL)
+ // zip - signers postal code (NULL)
+ // country - signers country (NULL)
+ //--------------------------------------------------
+ EXP_OPTION int signDocument(SignedDoc* pSigDoc, SignatureInfo** ppSigInfo,
+ const char* pin, const char* manifest,
+ const char* city, const char* state,
+ const char* zip, const char* country);
+
+ //--------------------------------------------------
+ // Signs the document and gets configrmation
+ // pSigDoc - signed document pointer
+ // ppSigInfo - address of new signature pointer
+ // pin - smart card PIN
+ // manifest - manifest / resolution (NULL)
+ // city - signers city (NULL)
+ // state - signers state (NULL)
+ // zip - signers postal code (NULL)
+ // country - signers country (NULL)
+ // signs with PKCS11
+ //--------------------------------------------------
+ EXP_OPTION int signDocumentWithSlot(SignedDoc* pSigDoc, SignatureInfo** ppSigInfo,
+ const char* pin, const char* manifest,
+ const char* city, const char* state,
+ const char* zip, const char* country,
+ int nSlot, int nOcsp, int nSigner);
+
+ //--------------------------------------------------
+ // Signs the document and gets configrmation
+ // pSigDoc - signed document pointer
+ // ppSigInfo - address of new signature pointer
+ // pin - smart card PIN
+ // manifest - manifest / resolution (NULL)
+ // city - signers city (NULL)
+ // state - signers state (NULL)
+ // zip - signers postal code (NULL)
+ // country - signers country (NULL)
+ // nSigner - 1=PKCS11, 2=CNG (Microsoft CAPI), 3=PKCS#12
+ // szPkcs12FileName - PKCS#12 file name to be used for signing (required if nSigner=3)
+ //--------------------------------------------------
+ EXP_OPTION int signDocumentWithSlotAndSigner(SignedDoc* pSigDoc, SignatureInfo** ppSigInfo,
+ const char* pin, const char* manifest,
+ const char* city, const char* state,
+ const char* zip, const char* country,
+ int nSlot, int nOcsp, int nSigner,
+ const char* szPkcs12FileName);
+
+ //--------------------------------------------------
+ // Verify this notary
+ // pSigDoc - signed document pointer
+ // pNotInfo - notary to verify
+ // returns error code
+ //--------------------------------------------------
+ int verifyNotary(SignedDoc* pSigDoc, SignatureInfo* pSigInfo, NotaryInfo* pNotInfo);
+
+ //--------------------------------------------------
+ // Verify this signature and it's notary
+ // pSigDoc - signed document pointer
+ // pSigInfo - signature to verify
+ // szFileName - input digidoc filename
+ // returns error code
+ //--------------------------------------------------
+ EXP_OPTION int verifySignatureAndNotary(SignedDoc* pSigDoc, SignatureInfo* pSigInfo, const char* szFileName);
+
+ //--------------------------------------------------
+ // Extract common name from cert DN or responder id
+ // src - DN
+ // dest - buffer for CN
+ // destLen - size of output buffer in bytes
+ //--------------------------------------------------
+ int findCN(char* src, char* dest, int destLen);
+
+ //------------------------------------------
+ // Verify certificate by OCSP
+ // pCert - certificate to check
+ // ppResp - address to return OCSP response. Use NULL if
+ // you don't want OCSP response to be returned
+ // returns error code
+ //------------------------------------------
+ EXP_OPTION int ddocVerifyCertByOCSP(X509* pCert, OCSP_RESPONSE **ppResp);
+
+ //------------------------------------------
+ // Verify certificate by OCSP
+ // pCert - certificate to check
+ // ppResp - address to return OCSP response. Use NULL if
+ // you don't want OCSP response to be returned
+ // returns error code
+ //------------------------------------------
+ EXP_OPTION int ddocVerifyCertByOCSPWithIp(X509* pCert, OCSP_RESPONSE **ppResp, unsigned long ip);
+
+ //------------------------------------------
+ // Reads an arbitrary file into memory buffer
+ // szFileName - file name and path
+ // pData - memory buffer object
+ // returns error code
+ //------------------------------------------
+ EXP_OPTION int ddocReadFile(const char* szFileName, DigiDocMemBuf* pData);
+
+ //------------------------------------------
+ // Writes an arbitrary file into memory buffer
+ // szFileName - file name and path
+ // pData - memory buffer object
+ // returns error code
+ //------------------------------------------
+ EXP_OPTION int ddocWriteFile(const char* szFileName, DigiDocMemBuf* pData);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif // __DIGI_DOC_CFG_H__
diff --git a/libdigidoc/DigiDocConvert.c b/libdigidoc/DigiDocConvert.c
new file mode 100644
index 0000000..d81b070
--- /dev/null
+++ b/libdigidoc/DigiDocConvert.c
@@ -0,0 +1,1373 @@
+//==================================================
+// FILE: DigiDocEnc.c
+// PROJECT: Digi Doc Encryption
+// DESCRIPTION: DigiDoc character conversion routines
+// AUTHOR: Veiko Sinivee, S|E|B IT Partner Estonia
+//==================================================
+// Copyright (C) AS Sertifitseerimiskeskus
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+// GNU Lesser General Public Licence is available at
+// http://www.gnu.org/copyleft/lesser.html
+//==========< HISTORY >=============================
+// 22.09.2004 Veiko Sinivee
+// Creation
+//==================================================
+
+#include <libdigidoc/DigiDocDebug.h>
+#include <libdigidoc/DigiDocConvert.h>
+#include <libdigidoc/DigiDocError.h>
+#include <libdigidoc/DigiDocMem.h>
+#include <libdigidoc/DigiDocGen.h>
+
+#ifdef WIN32
+ #include <windows.h>
+#endif
+#include <libxml/globals.h>
+#include <libxml/xmlerror.h>
+#include <libxml/parser.h>
+#include <libxml/parserInternals.h> /* only for xmlNewInputFromFile() */
+#include <libxml/tree.h>
+#include <libxml/debugXML.h>
+#include <libxml/xmlmemory.h>
+#include <libxml/c14n.h>
+#include <ctype.h>
+#include <memory.h>
+
+
+
+//==========< general fucntions >============
+
+//--------------------------------------------------
+// Helper function that converts ISO Latin1 to UTF8
+// ascii - input data in ISO Latin1
+// utf8out - output buffer for UTF8 text
+// outlen - output buffer length
+// returns output buffer
+//--------------------------------------------------
+EXP_OPTION char* ascii2utf8(const char* ascii, char* utf8out, int* outlen)
+{
+ int inlen = strlen(ascii);
+ memset(utf8out, 0, *outlen);
+ isolat1ToUTF8((unsigned char*)utf8out, outlen, (const unsigned char*)ascii, &inlen);
+ return utf8out;
+}
+
+//--------------------------------------------------
+// Helper function that converts UTF8 to ISO Latin1
+// utf8in - input data in UTF8
+// asciiout - output buffer for ISO Latin1 text
+// outlen - output buffer length
+// returns output buffer
+//--------------------------------------------------
+EXP_OPTION char* utf82ascii(const char* utf8in, char* asciiout, int* outlen)
+{
+ int inlen = strlen(utf8in);
+ memset(asciiout, 0, *outlen);
+ UTF8Toisolat1((unsigned char*)asciiout, outlen, (const unsigned char*)utf8in, &inlen);
+ return asciiout;
+}
+
+int hex2char(char c)
+{
+ static char unidigits[] = "0123456789ABCDEF";
+ unsigned int i, k = 0;
+ for(i = 0; i < sizeof(unidigits); i++) {
+ if(unidigits[i] == c) {
+ k = i;
+ break;
+ }
+ }
+ return k;
+}
+
+
+struct u2w {
+ long uni;
+ unsigned char cp1252; // cp 1252 charset
+ unsigned char cp1257; // baltic charset
+ unsigned char utf8_1; // UTF8 1. byte
+ unsigned char utf8_2; // UTF8 2. byte
+};
+
+struct u2w uni2cp1252 [] = {
+ { 8364, 128, 0, 0, 0 }, // euro sign
+ { 8218, 130, 0, 0, 0 }, // SINGLE LOW-9 QUOTATION MARK
+ { 402, 131, 0, 0, 0 }, // LATIN SMALL LETTER F WITH HOOK
+ { 8222, 132, 0, 0, 0 }, // DOUBLE LOW-9 QUOTATION MARK
+ { 8230, 133, 0, 0, 0 }, // HORIZONTAL ELLIPSIS
+ { 8224, 134, 0, 0, 0 }, // DAGGER
+ { 8225, 135, 0, 0, 0 }, // DOUBLE DAGGER
+ { 710, 136, 0, 0, 0 }, // MODIFIER LETTER CIRCUMFLEX ACCENT
+ { 8240, 137, 0, 0, 0 }, // PER MILLE SIGN
+ { 352, 138, 208, 197, 160 }, // LATIN CAPITAL LETTER S WITH CARON
+ { 8249, 139, 0, 0, 0 }, // SINGLE LEFT-POINTING ANGLE QUOTATION MARK
+ { 338, 140, 0, 0, 0 }, // LATIN CAPITAL LIGATURE OE
+ { 381, 142, 222, 197, 189 }, // LATIN CAPITAL LETTER Z WITH CARON
+ { 8216, 145, 0, 0, 0 }, // LEFT SINGLE QUOTATION MARK
+ { 8217, 146, 0, 0, 0 }, // RIGHT SINGLE QUOTATION MARK
+ { 8220, 147, 0, 0, 0 }, // LEFT DOUBLE QUOTATION MARK
+ { 8221, 148, 0, 0, 0 }, // RIGHT DOUBLE QUOTATION MARK
+ { 8226, 149, 0, 0, 0 }, // BULLET
+ { 8211, 150, 0, 0, 0 }, // EN DASH
+ { 8212, 151, 0, 0, 0 }, // EM DASH
+ { 732, 152, 0, 0, 0 }, // SMALL TILDE
+ { 8482, 153, 0, 0, 0 }, // TRADE MARK SIGN
+ { 353, 154, 240, 197, 161 }, // LATIN SMALL LETTER S WITH CARON
+ { 8250, 155, 0, 0, 0 }, // SINGLE RIGHT-POINTING ANGLE QUOTATION MARK
+ { 339, 156, 0, 0, 0 }, // LATIN SMALL LIGATURE OE
+ { 382, 158, 254, 197, 190 }, // LATIN SMALL LETTER Z WITH CARON
+ { 376, 159, 0, 0, 0 }, // LATIN CAPITAL LETTER Y WITH DIAERESIS
+ { 196, 196, 196, 195, 132}, // Capital A with umlaut
+ { 214, 214, 214, 195, 150}, // Calital O with umlaut
+ { 220, 220, 220, 195, 156}, // Capital U with umlaut
+ { 213, 213, 213, 195, 149}, // Capital O with tilde
+ { 228, 228, 228, 195, 164}, // small a with umlaut
+ { 246, 246, 246, 195, 132}, // small o with umlaut
+ { 245, 245, 245, 195, 181}, // small o with tilde
+ { 252, 252, 252, 195, 188}, // small u with umlaut
+
+ { 0, 0, 0, 0, 0 } // table end marker
+};
+
+int isUmlaut(unsigned char c)
+{
+ int i;
+ for(i = 0; uni2cp1252[i].uni; i++) {
+ if(uni2cp1252[i].cp1252 == c) {
+ return 1;
+ }
+ }
+ return 0;
+}
+
+int hasUmlauts(const char* str)
+{
+ int i;
+ for(i = 0; str[i]; i++) {
+ if(isUmlaut((unsigned char)str[i]))
+ return 1;
+ }
+ return 0;
+}
+
+int uni2char(long c)
+{
+ int i, k = 0x20; // use space for all undisplayable unicode chars
+ for(i = 0; uni2cp1252[i].uni; i++) {
+ if(uni2cp1252[i].uni == c) {
+ if(uni2cp1252[i].cp1257)
+ k = uni2cp1252[i].cp1257;
+ else
+ k = uni2cp1252[i].cp1252;
+ break;
+ }
+ }
+ return k;
+}
+
+int uni2utf8(long c, int utfidx)
+{
+ int i, k = 0x20; // use space for all undisplayable unicode chars
+ for(i = 0; uni2cp1252[i].uni; i++) {
+ if(uni2cp1252[i].uni == c) {
+ if(uni2cp1252[i].utf8_1) {
+ if(utfidx)
+ k = uni2cp1252[i].utf8_2;
+ else
+ k = uni2cp1252[i].utf8_1;
+ }
+ else
+ k = uni2cp1252[i].cp1252;
+ break;
+ }
+ }
+ return k;
+}
+
+
+EXP_OPTION void unicode2ascii(const char* uni, char* dest)
+{
+ int len, i, j, k;
+ long c;
+
+ RETURN_VOID_IF_NULL(uni);
+ RETURN_VOID_IF_NULL(dest);
+
+ len = strlen(uni);
+ memset(dest, 0, len+1);
+ for(i = j = 0; i < len; i++) {
+ if(uni[i] == '\\' && uni[i+1] == 'x') {
+ if(uni[i+2] == '0' && uni[i+3] == '0') {
+ if(uni[i+4] >= 'A' && uni[i+4] <= 'Z') { // simple char in form \x00A
+ dest[j] = (unsigned char)uni[i+4];
+ i += 4;
+ j++;
+ continue;
+ } else {
+ i += 3;
+ continue;
+ }
+ }
+ if(uni[i+2] == '0' && uni[i+3] != '0') { // more complex char like \x0}1
+ c = 0;
+ // first pos
+ k = uni[i+2];
+ k = (((k >= '0') && (k <= '9')) ? k - '0' : k);
+ k *= 4096;
+ c += k;
+ // second pos
+ k = uni[i+3];
+ k = (((k >= '0') && (k <= '9')) ? k - '0' : k);
+ k *= 256;
+ c += k;
+ // third pos
+ k = uni[i+4];
+ k = (((k >= '0') && (k <= '9')) ? k - '0' : k);
+ c += k;
+ if(c >= 0 && c <= 9) c+= '0';
+ // get corresponding cp1252 char
+ if(c > 256) {
+#ifdef WIN32
+ dest[j] = (unsigned char)uni2char(c);
+ j++;
+#else
+ dest[j] = uni2utf8(c, 0);
+ j++;
+ dest[j] = uni2utf8(c, 1);
+ j++;
+#endif
+ } else {
+ dest[j] = (unsigned char)c;
+ j++;
+ }
+ i += 4;
+ continue;
+ }
+ if(uni[i+2] != '0' && uni[i+3] != '0') { // hex char code like \xC4
+ c = hex2char(uni[i+2]) * 16 + hex2char(uni[i+3]);
+ if(c > 256) {
+#ifdef WIN32
+ dest[j] = (unsigned char)uni2char(c);
+ j++;
+#else
+ dest[j] = uni2utf8(c, 0);
+ j++;
+ dest[j] = uni2utf8(c, 1);
+ j++;
+#endif
+ } else {
+ dest[j] = (unsigned char)c;
+ j++;
+ }
+ i += 3;
+ continue;
+ }
+ } else {
+ dest[j] = uni[i];
+ j++;
+ }
+ }
+}
+
+typedef struct xmlsym_st {
+ char sym;
+ char* escape;
+} xmlsym;
+
+int g_xmlsyms = 6, g_xmlsyms2 = 7;
+xmlsym g_xmlsym[] = {
+ { '\n', "&#xA;" },
+ { '\r', "&#xD;" },
+ { '<', "&lt;" },
+ { '>', "&gt;" },
+ { '"', "&quot;" },
+ { '&', "&amp;" }, // VS: test if really necessary!
+ { '&', "&#38;" }
+};
+
+int findEscape(const char* src, char* sym)
+{
+ int i;
+
+ *sym = 0;
+ for(i = 0; i < g_xmlsyms; i++) {
+ if(!strncmp(g_xmlsym[i].escape, src, strlen(g_xmlsym[i].escape))) {
+ *sym = g_xmlsym[i].sym;
+ return strlen(g_xmlsym[i].escape);
+ }
+ }
+ return 0;
+}
+
+char findSym(const char* sym, int len)
+{
+ int i;
+
+ for(i = 0; i < g_xmlsyms2; i++) {
+ if(!strncmp(g_xmlsym[i].escape, sym, len)) {
+ return g_xmlsym[i].sym;
+ }
+ }
+ return 0;
+}
+
+//--------------------------------------------------
+// Converts xml symbols to corresponding escapes
+// src - string with xml special sybols
+// returns string with esacpes
+//--------------------------------------------------
+char* escape2xmlsym(const char* src)
+{
+ char* dest = 0, c;
+ int i, j, l, k;
+
+ l = strlen(src);
+ dest = (char*)malloc(l+1);
+ SET_LAST_ERROR_RETURN_IF_NOT(dest, ERR_BAD_ALLOC, NULL);
+ memset(dest, 0, l+1);
+ for(i = j = 0; i < l; i++, j++) {
+ if(src[i] == '&') {
+ k = findEscape(src + i, &c);
+ if(k && c) {
+ dest[j] = c;
+ i += k - 1;
+ }
+ else
+ dest[j] = src[i];
+ }
+ else
+ dest[j] = src[i];
+ }
+ ddocDebug(4, "escape2xmlsym", "%s --> %s", src, dest);
+ return dest;
+}
+
+
+//--------------------------------------------------
+// Converts xml symbols to corresponding escapes
+// src - string with xml special sybols
+// returns string with esacpes
+//--------------------------------------------------
+char* unescapeXmlsym(const char* src)
+{
+ char* dest = 0, c;
+ int i, j, l, k;
+
+ l = strlen(src);
+ dest = (char*)malloc(l+1);
+ SET_LAST_ERROR_RETURN_IF_NOT(dest, ERR_BAD_ALLOC, NULL);
+ memset(dest, 0, l+1);
+ for(i = j = 0; i < l; i++, j++) {
+ if(src[i] == '&') {
+ if(src[i+1] == ';') k = 1;
+ if(src[i+2] == ';') k = 2;
+ if(src[i+3] == ';') k = 3;
+ if(src[i+4] == ';') k = 4;
+ c = findSym(src + i, k);
+ if(k && c) {
+ dest[j] = c;
+ i += k;
+ }
+ else
+ dest[j] = src[i];
+ }
+ else
+ dest[j] = src[i];
+ }
+ ddocDebug(4, "unescapeXmlsym", "%s --> %s", src, dest);
+ return dest;
+}
+
+char g_hexChars[] = "0123456789ABCDEF";
+
+//--------------------------------------------------
+// Decodes a single hex digit
+// h - hex digit
+// return binary value
+//--------------------------------------------------
+byte h2b(char h)
+{
+ int i;
+ for(i = 0; i < 16; i++) {
+ if(g_hexChars[i] == h || g_hexChars[i] == toupper(h))
+ return (byte)i;
+ }
+ // if not found then return an error
+ ddocDebug(1, "h2b", "Invalid hex byte: %c", h);
+ SET_LAST_ERROR(ERR_BAD_PARAM);
+ return 0; // MSTERN: incorrect, VS - yes return -1 if not found. This is an error code
+}
+
+//--------------------------------------------------
+// Converts a hex number (string) to binary value
+// hex - hex number
+// bin - buffer for binary value
+// len - buffer length
+//--------------------------------------------------
+EXP_OPTION void hex2bin(const char* hex, byte* bin, int* len)
+{
+ int i, l;
+ byte b;
+
+ RETURN_VOID_IF_NULL(hex);
+ RETURN_VOID_IF_NULL(bin);
+ RETURN_VOID_IF_NULL(len);
+ memset(bin, 0, *len);
+ l = strlen(hex);
+ for(i = 0; i < l; i += 2) {
+ b = (byte) ((h2b(hex[i]) << 4) | h2b(hex[i+1]));
+ bin[i/2] = b;
+ }
+ *len = i / 2;
+}
+
+//--------------------------------------------------
+// Converts a single byte to two hex characters
+// b - binary value
+// dest - destination buffer
+//--------------------------------------------------
+void b2h(byte b, char* dest)
+{
+ dest[0] = g_hexChars[(b & 0xF0) >> 4];
+ dest[1] = g_hexChars[b & 0x0F];
+}
+
+//--------------------------------------------------
+// Converts a binary value to hex string
+// bin - binary value
+// blen - binary value length
+// hex - buffer for hex string
+// len - buffer length
+//--------------------------------------------------
+EXP_OPTION void bin2hex(const byte* bin, int blen, char* hex, int* len)
+{
+ int i;
+ byte b;
+
+ RETURN_VOID_IF_NULL(hex);
+ RETURN_VOID_IF_NULL(bin);
+ RETURN_VOID_IF_NULL(len);
+ memset(hex, 0, *len);
+ for(i = 0; i < blen; i++) {
+ b = bin[i];
+ hex[i*2] = g_hexChars[(b & 0xF0) >> 4];
+ hex[i*2+1] = g_hexChars[b & 0x0F];
+ }
+ *len = i / 2;
+}
+
+//============================================================
+// Encodes input data in hex format.
+// pMBufSrc - input data
+// pMBufDest - destination buffer
+//============================================================
+EXP_OPTION int ddocBin2Hex(const DigiDocMemBuf* pMBufSrc, DigiDocMemBuf* pMBufDest)
+{
+ int err = ERR_OK, n;
+
+ RETURN_IF_NULL(pMBufSrc);
+ RETURN_IF_NULL(pMBufDest);
+ pMBufDest->pMem = 0;
+ pMBufDest->nLen = 0;
+ // alloc mem for result
+ if(pMBufSrc->pMem && pMBufSrc->nLen) {
+ err = ddocMemSetLength(pMBufDest, pMBufSrc->nLen * 2 + 10);
+ n = pMBufSrc->nLen * 2 + 10;
+ if(err) return err;
+ bin2hex((const byte*)pMBufSrc->pMem, pMBufSrc->nLen, (char*)pMBufDest->pMem, &n);
+ pMBufDest->nLen = n;
+ }
+ return err;
+}
+
+//--------------------------------------------------
+// Converts correct filename to incorrect encoding
+// used in formats 1.0, 1.1 and 1.2
+// src - input data
+// dest - buffer for converted data
+// len - length of destination buffer
+//--------------------------------------------------
+EXP_OPTION void convFNameToWin(const char* src, char* dest, int len)
+{
+ int i, j;
+ for(i = j = 0; src[i] && (j < len - 1); i++, j++) {
+ if(((unsigned char)src[i]) == 197 && ((unsigned char)src[i+1]) == 161) {
+ dest[j] = (unsigned char)195; dest[j+1] = (unsigned char)176; j++, i++; continue;
+ } else if(((unsigned char)src[i]) == 197 && ((unsigned char)src[i+1]) == 160) {
+ dest[j] = (unsigned char)195; dest[j+1] = (unsigned char)144; j++, i++; continue;
+ } else if(((unsigned char)src[i]) == 197 && ((unsigned char)src[i+1]) == 190) {
+ dest[j] = (unsigned char)195; dest[j+1] = (unsigned char)190; j++, i++; continue;
+ } else if(((unsigned char)src[i]) == 197 && ((unsigned char)src[i+1]) == 189) {
+ dest[j] = (unsigned char)195; dest[j+1] = (unsigned char)158; j++, i++; continue;
+ } else {
+ dest[j] = src[i];
+ }
+ }
+ dest[j] = 0;
+}
+
+//--------------------------------------------------
+// Converts bad UTF-8 filename used in formats 1.0,
+// 1.1 and 1.2 to correct encoding
+// src - input data
+// dest - buffer for converted data
+// len - length of destination buffer
+//--------------------------------------------------
+EXP_OPTION void convWinToFName(const char* src, char* dest, int len)
+{
+ int i, j;
+ for(i = j = 0; src[i] && (j < len - 1); i++, j++) {
+ if(((unsigned char)src[i]) == 195 && ((unsigned char)src[i+1]) == 176) {
+ dest[j] = (unsigned char)197; dest[j+1] = (unsigned char)161; j++, i++; continue;
+ } else if(((unsigned char)src[i]) == 195 && ((unsigned char)src[i+1]) == 144) {
+ dest[j] = (unsigned char)197; dest[j+1] = (unsigned char)160; j++, i++; continue;
+ } else if(((unsigned char)src[i]) == 195 && ((unsigned char)src[i+1]) == 190) {
+ dest[j] = (unsigned char)197; dest[j+1] = (unsigned char)190; j++, i++; continue;
+ } else if(((unsigned char)src[i]) == 195 && ((unsigned char)src[i+1]) == 158) {
+ dest[j] = (unsigned char)197; dest[j+1] = (unsigned char)189; j++, i++; continue;
+ } else {
+ dest[j] = src[i];
+ }
+ }
+ dest[j] = 0;
+}
+
+
+//==========< only win32 fucntions >============
+
+#ifdef WIN32
+
+//--------------------------------------------------
+// Converts input OEM charset data to 16 bit unicode.
+// oem - 8 bit oem charset input data
+// unicode - address of pointer for allocated unicode string. Caller must free() !
+// outlen - address of length variable for unicode string
+// returns error code or ERR_OK
+//--------------------------------------------------
+EXP_OPTION int oem2unicode(const char* oem, char** unicode, int* outlen)
+{
+ int len;
+
+ *unicode = 0;
+ // convert oem to unicode
+ if(!oem || !strlen(oem))
+ return ERR_OK;
+ ddocDebug(4, "oem2unicode", "Convert: \'%s\' len: %d", oem, strlen(oem));
+ len = MultiByteToWideChar(CP_ACP, 0, oem, -1, NULL, 0) * 2 + 10;
+ ddocDebug(5, "oem2unicode", "Alloc: %d", len);
+ *unicode = (char*)malloc(len);
+ RETURN_IF_BAD_ALLOC(*unicode);
+ memset(*unicode, 0, len);
+ *outlen = MultiByteToWideChar(CP_ACP, 0, oem, -1, (LPWSTR)(*unicode), len);
+ if(!(*outlen)) {
+ SET_LAST_ERROR(ERR_CHARSET_CONVERT);
+ return ERR_CHARSET_CONVERT;
+ }
+ else
+ return ERR_OK;
+}
+
+//--------------------------------------------------
+// Converts input 16 bit unicode data to UTF8.
+// unicode - 16 bit unicode input data
+// utf8 - address of pointer for allocated utf8 string. Caller must free() !
+// outlen - address of length variable for utf8 string
+// returns error code or ERR_OK
+//--------------------------------------------------
+EXP_OPTION int unicode2utf8(const char* unicode, char** utf8, int* outlen)
+{
+ int len;
+
+ *utf8 = 0;
+ // now convert unicode to UTF8
+ if(!unicode || !strlen(unicode))
+ return ERR_OK;
+ len = WideCharToMultiByte(CP_UTF8, 0, (LPWSTR)unicode, -1, NULL, 0, NULL, NULL) + 10;
+ ddocDebug(5, "unicode2utf8", "Alloc: %d", len);
+ *utf8 = (char*)malloc(len);
+ RETURN_IF_BAD_ALLOC(*utf8);
+ memset(*utf8, 0, len);
+ *outlen = WideCharToMultiByte(CP_UTF8, 0, (LPWSTR)unicode, -1, *utf8, len, NULL, NULL);
+ ddocDebug(5, "unicode2utf8", "Convert: \'%s\' len: %d", *utf8, strlen(*utf8));
+ if(!(*outlen)) {
+ SET_LAST_ERROR(ERR_CHARSET_CONVERT);
+ return ERR_CHARSET_CONVERT;
+ }
+ else
+ return ERR_OK;
+}
+
+//--------------------------------------------------
+// Converts input OEM charset data to UTF-8
+// oem - 8 bit oem charset input data
+// utf8 - address of buffer allocated utf8 string.
+// len - size of buffer
+// returns error code or ERR_OK
+//--------------------------------------------------
+EXP_OPTION int oem2utf8(const char* oem, char* utf8, int len)
+{
+ int err = ERR_OK, len1, len2;
+ char *pTmp1 = 0, *pTmp2 = 0;
+
+ ddocDebug(5, "oem2utf8", "oem2utf8");
+ // Kaido: 2.1.13 - initialize return value
+ *utf8 = 0;
+ // convert oem to unicode
+ if(!oem || !strlen(oem))
+ return ERR_OK;
+ err = oem2unicode(oem, &pTmp1, &len1);
+ if(err) return err;
+ // now convert unicode to UTF8
+ err = unicode2utf8(pTmp1, &pTmp2, &len2);
+ if(len2 < len)
+ memcpy(utf8, pTmp2, len2);
+ else
+ err = ERR_CHARSET_CONVERT;
+ if(pTmp1)
+ free(pTmp1);
+ if(pTmp2)
+ free(pTmp2);
+ return err;
+}
+
+//--------------------------------------------------
+// Converts input UTF-8 data to 16 bit unicode data.
+// utf8 - UTF-8 input data
+// unicode - address of pointer for allocated unicode string. Caller must free() !
+// outlen - address of length variable for unicode string
+// returns error code or ERR_OK
+//--------------------------------------------------
+EXP_OPTION int utf82unicode(const char* utf8, char** unicode, int* outlen)
+{
+ int len;
+
+ *unicode = 0;
+ // convert unicode to UTF-8
+ if(!utf8 || !strlen(utf8))
+ return ERR_OK;
+ ddocDebug(5, "utf82unicode", "Convert: \'%s\' len: %d", utf8, strlen(utf8));
+ len = MultiByteToWideChar(CP_UTF8, 0, utf8, -1, NULL, 0) * 2 + 10;
+ ddocDebug(5, "utf82unicode", "Alloc: %d", len);
+ *unicode = (char*)malloc(len);
+ RETURN_IF_BAD_ALLOC(*unicode);
+ memset(*unicode, 0, len);
+ *outlen = MultiByteToWideChar(CP_UTF8, 0, utf8, -1, (LPWSTR)(*unicode), len);
+ ddocDebug(5, "utf82unicode", "Converted: \'%s\' to \'%s\' len: %d", utf8, *unicode, *outlen);
+ if(!(*outlen)) {
+ SET_LAST_ERROR(ERR_CHARSET_CONVERT);
+ return ERR_CHARSET_CONVERT;
+ }
+ else
+ return ERR_OK;
+}
+
+//--------------------------------------------------
+// Converts input 16 bit unicode data to oem charset data.
+// unicode - 16 bit unicode input data
+// oem - address of pointer for allocated oem string. Caller must free() !
+// outlen - address of length variable for oem string
+// returns error code or ERR_OK
+//--------------------------------------------------
+EXP_OPTION int unicode2oem(const char* unicode, char** oem, int* outlen)
+{
+ int len;
+
+ *oem = 0;
+ if(!unicode || !strlen(unicode))
+ return ERR_OK;
+ // now convert unicode to OEM
+ len = WideCharToMultiByte(CP_ACP, 0, (LPWSTR)unicode, -1, NULL, 0, NULL, NULL) + 10;
+ ddocDebug(5, "unicode2oem", "Alloc: %d", len);
+ *oem = (char*)malloc(len);
+ RETURN_IF_BAD_ALLOC(*oem);
+ memset(*oem, 0, len);
+ *outlen = WideCharToMultiByte(CP_ACP, 0, (LPWSTR)unicode, -1, *oem, len, NULL, NULL);
+ ddocDebug(5, "unicode2oem", "Convert: \'%s\' len: %d", *oem, strlen(*oem));
+ if(!(*outlen)) {
+ SET_LAST_ERROR(ERR_CHARSET_CONVERT);
+ return ERR_CHARSET_CONVERT;
+ }
+ else
+ return ERR_OK;
+}
+
+
+//--------------------------------------------------
+// Converts input UTF-8 data to OEM charset data
+// utf8 - UTF-8 input data
+// oem - address of buffer for oem string.
+// len - size of buffer
+// returns error code or ERR_OK
+//--------------------------------------------------
+EXP_OPTION int utf82oem(const char* utf8, char* oem, int len)
+{
+ int err = ERR_OK, len1, len2;
+ char *pTmp1 = 0, *pTmp2 = 0;
+
+ // Kaido: 2.1.13 - initialize return value
+ *oem = 0;
+ // convert utf8 to unicode
+ if(!utf8 || !strlen(utf8))
+ return ERR_OK;
+ memset(oem, 0, len);
+ err = utf82unicode(utf8, &pTmp1, &len1);
+ if(err) return err;
+ // now convert unicode to OEM
+ err = unicode2oem(pTmp1, &pTmp2, &len2);
+ if(len2 < len)
+ memcpy(oem, pTmp2, len2);
+ else
+ err = ERR_CHARSET_CONVERT;
+ if(pTmp1)
+ free(pTmp1);
+ if(pTmp2)
+ free(pTmp2);
+ return err;
+}
+
+//--------------------------------------------------
+// Converts input UTF-8 data to OEM charset data
+// pSigDoc - signed doc object
+// pDf - data file obejct
+// outFileName - output buffer
+// len - length of output buffer
+// returns error code or ERR_OK
+//--------------------------------------------------
+EXP_OPTION int getDataFileFileName(SignedDoc* pSigDoc, DataFile* pDf, char* outFileName, int len)
+{
+ int err = ERR_OK;
+ RETURN_IF_NULL_PARAM(pSigDoc);
+ RETURN_IF_NULL_PARAM(pDf);
+ RETURN_IF_NULL_PARAM(outFileName);
+
+ // Kaido: 2.1.13 - initialize return value
+ *outFileName = 0;
+ if(!strcmp(pSigDoc->szFormatVer, DIGIDOC_XML_1_3_VER) ) {
+ //utf82oem(pDf->szFileName, buf1, 300);
+ //convFNameToWin(buf1, outFileName, len);
+ strncpy(outFileName, pDf->szFileName, len);
+ } else {
+ convWinToFName(pDf->szFileName, outFileName, len);
+ }
+ return err;
+}
+
+
+#endif
+
+
+//--------------------------------------------------
+// Converts input data to UTF-8
+// src - input data
+// returns converted string or NULL. Caller must free it.
+//--------------------------------------------------
+EXP_OPTION int ddocConvertInput(const char* src, char** dest)
+{
+ int l1, err = ERR_OK;
+
+ *dest = 0;
+ l1 = strlen(src) * 2 + 3;
+ *dest = (char*)malloc(l1);
+ if(*dest) {
+ memset(*dest, 0, l1);
+#ifdef WIN32
+ RETURN_IF_NULL(*dest);
+ err = oem2utf8(src, *dest, l1);
+#else
+ strncpy(*dest, src, l1);
+#endif
+ }
+ return err;
+}
+
+//--------------------------------------------------
+// Releases mem-block allocated by lib. In win32
+// this must be done since the mem was allocated by dll
+// and must also be released by dll that allocated it.
+// p - mem to be freed
+//--------------------------------------------------
+EXP_OPTION void freeLibMem(void* p)
+{
+ if(p)
+ free(p);
+}
+
+
+//--------------------------------------------------
+// Converts a filename according to platform rules
+// dest - destination buffer
+// destlen - destination buffer length
+// src - source filename
+// returns error code or ERR_OK
+//--------------------------------------------------
+int ddocConvertFileName(char* dest, int destlen, const char* src)
+{
+ int err = ERR_OK;
+
+ RETURN_IF_NULL_PARAM(dest);
+ RETURN_IF_NULL_PARAM(src);
+
+ *dest = 0; // initialize
+#ifdef WIN32
+ err = utf82oem(src, dest, destlen);
+#else
+ SET_LAST_ERROR_IF_NOT((int)strlen(src) < destlen, ERR_BUF_LEN);
+ strncpy(dest, src, destlen);
+#endif
+ return err;
+}
+
+//==========< Base64 functions >================
+
+
+//============================================================
+// Encode a byte array in Base64 format.
+// raw - input data
+// rawlen - length of input data
+// buf - destination buffer
+// buflen - destination buffer length (will be modified by catual number of bytes)
+//============================================================
+EXP_OPTION void encode(const byte* raw, int rawlen, byte* buf, int* buflen)
+{
+ EVP_ENCODE_CTX ectx;
+
+ RETURN_VOID_IF_NULL(raw);
+ RETURN_VOID_IF_NULL(buf);
+ RETURN_VOID_IF_NULL(buflen);
+
+ memset(buf, 0, *buflen);
+ EVP_EncodeInit(&ectx);
+ EVP_EncodeUpdate(&ectx, buf, buflen, (byte*)raw, rawlen);
+ EVP_EncodeFinal(&ectx, (unsigned char*)strchr((const char*)buf, 0), buflen);
+ *buflen = strlen((const char*)buf);
+ while(buf[*buflen-1] == '\n' || buf[*buflen-1] == '\r' || buf[*buflen-1] == '-') {
+ if(buf[*buflen-1] == '-')
+ ddocDebug(1, "encode", "Found - at the end of base64 code: %s", buf);
+
+ buf[*buflen-1] = 0;
+ *buflen = *buflen - 1;
+ }
+ *buflen = strlen((const char*)buf);
+}
+
+
+byte* breakToLinesOf64(byte* raw, int rawlen)
+{
+ int i, l1, j;
+ byte* p = raw;
+
+ // if it's not divide in lines
+ l1 = rawlen;
+ j = l1 + (l1/64) * 3;
+ p = (byte*)malloc(j);
+ if (!p) return NULL;
+ memset(p, 0, j);
+ for(i = j = 0; i < l1; i += 64) {
+ strncpy(strchr((const char*)p,0), (const char*)raw+i, ((i+64<l1) ? 64 : l1-i));
+ if(i + 64 < l1)
+ strncat((char*)p, "\n", j - strlen((char*)p));
+ }
+ l1 = strlen((const char*)p);
+ return p;
+}
+
+//============================================================
+// Decodes input data in Base64 format.
+// raw - input data
+// rawlen - length of input data
+// buf - destination buffer
+// buflen - destination buffer length (will be modified by catual number of bytes)
+//============================================================
+EXP_OPTION void decode(const byte* raw, int rawlen, byte* buf, int* buflen)
+{
+ EVP_ENCODE_CTX ectx;
+ int l1 = 0;
+ byte* p;
+
+ RETURN_VOID_IF_NULL(raw);
+ RETURN_VOID_IF_NULL(buf);
+ RETURN_VOID_IF_NULL(buflen);
+
+ memset(buf, 0, *buflen);
+ *buflen = 0;
+ EVP_DecodeInit(&ectx);
+ if((!strstr((const char*)raw, "\n") ||
+ !strstr((const char*)raw, "\r")) &&
+ strlen((const char*)raw) > 64) {
+ p = breakToLinesOf64((byte*)raw, rawlen);
+ l1 = strlen((const char*)p);
+ EVP_DecodeUpdate(&ectx, (unsigned char*)buf, &l1,
+ (unsigned char*)p,
+ strlen((const char*)p));
+ *buflen += l1;
+ free(p);
+ }
+ else
+ EVP_DecodeUpdate(&ectx, buf, buflen, (byte*)raw, rawlen);
+ EVP_DecodeFinal(&ectx, buf, &l1);
+ *buflen += l1;
+}
+
+
+//============================================================
+// Helper function to determine if this is a base64 char
+//============================================================
+int isb64char(int c)
+{
+ return ( (c >= 'A' && c <= 'Z') ||
+ (c >= 'a' && c <= 'z') ||
+ (c >= '0' && c <= '9') ||
+ (c == '+') ||
+ (c == '/') ||
+ (c == '=')
+ );
+}
+
+//============================================================
+// Decodes input data in Base64 format.
+// pMBufSrc - input data
+// pMBufDest - destination buffer
+//============================================================
+EXP_OPTION int ddocDecodeBase64(DigiDocMemBuf* pMBufSrc, DigiDocMemBuf* pMBufDest)
+{
+ int err = ERR_OK, n;
+ long lPos1 = 0, lPos2 = 0;
+ EVP_ENCODE_CTX ectx;
+ char buf1[70];
+ RETURN_IF_NULL(pMBufSrc);
+ RETURN_IF_NULL(pMBufDest);
+
+ pMBufDest->pMem = 0;
+ pMBufDest->nLen = 0;
+ // alloc mem for result - it will get smaller so original length must be enough
+ err = ddocMemSetLength(pMBufDest, pMBufSrc->nLen);
+ if(err) return err;
+ EVP_DecodeInit(&ectx);
+ // decode base64
+ while(lPos1 < pMBufSrc->nLen) {
+ // copy next input row
+ memset(buf1, 0, sizeof(buf1));
+ n = 0;
+ while(n < 64 && lPos1 < pMBufSrc->nLen) {
+ if(isb64char(((char*)pMBufSrc->pMem)[lPos1])) {
+ buf1[n] = ((char*)pMBufSrc->pMem)[lPos1];
+ n++;
+ }
+ lPos1++;
+ }
+ strncat(buf1, "\n", sizeof(buf1) - strlen(buf1));
+ // decode this chunk
+ n = pMBufDest->nLen - lPos2;
+ EVP_DecodeUpdate(&ectx, (unsigned char*)((char*)pMBufDest->pMem + lPos2), &n,
+ (unsigned char*)buf1, strlen((const char*)buf1));
+ lPos2 += n;
+ }
+ memset(buf1, 0, sizeof(buf1));
+ n = sizeof(buf1);
+ EVP_DecodeFinal(&ectx, (unsigned char*)buf1, &n);
+ lPos2 += n;
+ pMBufDest->nLen = lPos2;
+ return err;
+}
+
+
+//============================================================
+// Decodes input data in Base64 format.
+// data - input data
+// len - length of input data. Use -1 for zero terminated strings
+// pMBufDest - destination buffer
+//============================================================
+EXP_OPTION int ddocDecodeBase64Data(void* data, long len, DigiDocMemBuf* pMBufDest)
+{
+ DigiDocMemBuf mbuf1;
+
+ mbuf1.pMem = data;
+ if(len == -1)
+ mbuf1.nLen = strlen((const char*)data);
+ else
+ mbuf1.nLen = len;
+ return ddocDecodeBase64(&mbuf1, pMBufDest);
+}
+
+
+//============================================================
+// Encodes input data in Base64 format.
+// pMBufSrc - input data
+// pMBufDest - destination buffer
+//============================================================
+EXP_OPTION int ddocEncodeBase64(const DigiDocMemBuf* pMBufSrc, DigiDocMemBuf* pMBufDest)
+{
+ int err = ERR_OK, nLen;
+ EVP_ENCODE_CTX ectx;
+
+ RETURN_IF_NULL(pMBufSrc);
+ RETURN_IF_NULL(pMBufDest);
+
+ pMBufDest->pMem = 0;
+ pMBufDest->nLen = 0;
+ // alloc mem for result
+ err = ddocMemSetLength(pMBufDest, pMBufSrc->nLen * 2 + 10);
+ if(err) return err;
+ EVP_EncodeInit(&ectx);
+ // encode base64
+ nLen = pMBufDest->nLen;
+ EVP_EncodeUpdate(&ectx, (unsigned char*)pMBufDest->pMem, &nLen,
+ (byte*)pMBufSrc->pMem, pMBufSrc->nLen);
+ pMBufDest->nLen = nLen;
+ nLen = (pMBufSrc->nLen * 2 + 10) - pMBufDest->nLen;
+ EVP_EncodeFinal(&ectx, (unsigned char*)pMBufDest->pMem + pMBufDest->nLen, &nLen);
+ pMBufDest->nLen += nLen; //strlen((const char*)pMBufDest->pMem);
+ return err;
+}
+
+//==========< conversion fucntions >================
+
+//--------------------------------------------------
+// Decodes an ASN1 generalized time
+// tm - ASN1 generalized time
+// y - year
+// M - month
+// d - day of month
+// h - hour
+// m - minute
+// s - second
+// returns error code or ERR_OK
+//--------------------------------------------------
+int decodeGeneralizedTime(ASN1_GENERALIZEDTIME *tm,
+ int* y, int* M, int* d,
+ int* h, int* m, int* s)
+{
+ char *v = NULL;
+ int gmt=0;
+ int i, err = ERR_OK;
+
+ RETURN_IF_NULL_PARAM(tm);
+ RETURN_IF_NULL_PARAM(y);
+ RETURN_IF_NULL_PARAM(M);
+ RETURN_IF_NULL_PARAM(d);
+ RETURN_IF_NULL_PARAM(h);
+ RETURN_IF_NULL_PARAM(m);
+ RETURN_IF_NULL_PARAM(s);
+
+ i=tm->length;
+ v=(char *)tm->data;
+ if (i < 12)
+ err = ERR_TIMESTAMP_DECODE;
+ if (v[i-1] == 'Z') gmt=1;
+ for (i=0; i<12; i++)
+ if ((v[i] > '9') || (v[i] < '0'))
+ err = ERR_TIMESTAMP_DECODE;
+ *y= (v[0]-'0')*1000+(v[1]-'0')*100 + (v[2]-'0')*10+(v[3]-'0');
+ *M= (v[4]-'0')*10+(v[5]-'0');
+ if ((*M > 12) || (*M < 1))
+ err = ERR_TIMESTAMP_DECODE;
+ *d= (v[6]-'0')*10+(v[7]-'0');
+ *h= (v[8]-'0')*10+(v[9]-'0');
+ *m= (v[10]-'0')*10+(v[11]-'0');
+ if ( (v[12] >= '0') && (v[12] <= '9') &&
+ (v[13] >= '0') && (v[13] <= '9'))
+ *s= (v[12]-'0')*10+(v[13]-'0');
+ if (err != ERR_OK) SET_LAST_ERROR(err);
+ return err;
+}
+
+//--------------------------------------------------
+// Decodes an ASN1 UTC time
+// tm - ASN1 generalized time
+// y - year
+// M - month
+// d - day of month
+// h - hour
+// m - minute
+// s - second
+// returns error code or ERR_OK
+//--------------------------------------------------
+int decodeUTCTime(ASN1_UTCTIME *tm,
+ int* y, int* M, int* d,
+ int* h, int* m, int* s)
+{
+ char *v;
+ int gmt=0;
+ int i, err = 0;
+
+ RETURN_IF_NULL_PARAM(tm);
+ RETURN_IF_NULL_PARAM(y);
+ RETURN_IF_NULL_PARAM(M);
+ RETURN_IF_NULL_PARAM(d);
+ RETURN_IF_NULL_PARAM(h);
+ RETURN_IF_NULL_PARAM(m);
+ RETURN_IF_NULL_PARAM(s);
+
+ i=tm->length;
+ v=(char *)tm->data;
+
+ if (i < 10)
+ err = ERR_TIMESTAMP_DECODE;
+ if (v[i-1] == 'Z') gmt=1;
+ for (i=0; i<10; i++)
+ if ((v[i] > '9') || (v[i] < '0'))
+ err = ERR_TIMESTAMP_DECODE;
+ *y= (v[0]-'0')*10+(v[1]-'0');
+ if (*y < 50) *y+=100;
+ *M= (v[2]-'0')*10+(v[3]-'0');
+ if ((*M > 12) || (*M < 1))
+ err = ERR_TIMESTAMP_DECODE;
+ *d= (v[4]-'0')*10+(v[5]-'0');
+ *h= (v[6]-'0')*10+(v[7]-'0');
+ *m= (v[8]-'0')*10+(v[9]-'0');
+ if ( (v[10] >= '0') && (v[10] <= '9') &&
+ (v[11] >= '0') && (v[11] <= '9'))
+ *s= (v[10]-'0')*10+(v[11]-'0');
+
+ if (err != ERR_OK) SET_LAST_ERROR(err);
+ return err;
+}
+
+//==========================================================
+// converts ASN1 time to time_t
+//==========================================================
+int asn1time2time_t(ASN1_TIME* tm, time_t* pT)
+{
+ int err = ERR_OK;
+ struct tm tm1;
+ //int dmz=0;
+
+ RETURN_IF_NULL_PARAM(tm);
+ RETURN_IF_NULL_PARAM(pT);
+ _tzset();
+ memset(&tm1, 0, sizeof(tm1));
+ if(tm->type == V_ASN1_UTCTIME)
+ err = decodeUTCTime(tm, &tm1.tm_year, &tm1.tm_mon,
+ &tm1.tm_mday, &tm1.tm_hour, &tm1.tm_min, &tm1.tm_sec);
+ if(tm->type == V_ASN1_GENERALIZEDTIME)
+ err = decodeGeneralizedTime(tm, &tm1.tm_year, &tm1.tm_mon,
+ &tm1.tm_mday, &tm1.tm_hour, &tm1.tm_min, &tm1.tm_sec);
+ tm1.tm_year -= 1900;
+ tm1.tm_mon -= 1;
+ tm1.tm_isdst = _daylight;
+ (*pT) = mktime(&tm1);
+ /*
+ if(_daylight!=0) {
+ if(_timezone<0){
+ dmz = (_timezone / 3600) - _daylight;
+ }else{
+ dmz = (_timezone / 3600) + _daylight;
+ }
+ }else{
+ dmz=_timezone / 3600;
+ }
+ (*pT) = (*pT) - (dmz * 3600);
+ */
+ if (err != ERR_OK) SET_LAST_ERROR(err);
+ return err;
+}
+
+
+//==========================================================
+// converts ASN1 time to time_t
+//==========================================================
+int asn1time2time_t_local(ASN1_TIME* tm, time_t* pT)
+{
+ int err = ERR_OK;
+ struct tm tm1;
+ int dmz=0;
+
+ RETURN_IF_NULL_PARAM(tm);
+ RETURN_IF_NULL_PARAM(pT);
+ _tzset();
+ memset(&tm1, 0, sizeof(tm1));
+ if(tm->type == V_ASN1_UTCTIME)
+ err = decodeUTCTime(tm, &tm1.tm_year, &tm1.tm_mon,
+ &tm1.tm_mday, &tm1.tm_hour, &tm1.tm_min, &tm1.tm_sec);
+ if(tm->type == V_ASN1_GENERALIZEDTIME)
+ err = decodeGeneralizedTime(tm, &tm1.tm_year, &tm1.tm_mon,
+ &tm1.tm_mday, &tm1.tm_hour, &tm1.tm_min, &tm1.tm_sec);
+ if(tm1.tm_year > 1900)
+ tm1.tm_year -= 1900;
+ tm1.tm_mon -= 1;
+ tm1.tm_isdst = _daylight;
+ (*pT) = mktime(&tm1);
+ if(_daylight != 0) {
+ if(_timezone<0){
+ dmz = (_timezone / 3600) - _daylight;
+ }else{
+ dmz = (_timezone / 3600) + _daylight;
+ }
+ }else{
+ dmz=_timezone / 3600;
+ }
+ (*pT) = (*pT) - (dmz * 3600);
+ if (err != ERR_OK) SET_LAST_ERROR(err);
+ return err;
+}
+
+//==========================================================
+// converts ASN1 time to string
+//==========================================================
+int asn1time2strYear(const SignedDoc* pSigDoc, ASN1_TIME* tm, char* buf, int year, int len)
+{
+ int err = ERR_OK;
+ struct tm tm1, tm2;
+ time_t t2;
+ int dmz=0;
+
+ RETURN_IF_NULL_PARAM(tm);
+ RETURN_IF_NULL_PARAM(buf);
+ //RETURN_IF_NULL_PARAM(pSigDoc);
+ _tzset();
+ memset(&tm1, 0, sizeof(tm1));
+ if(tm->type == V_ASN1_UTCTIME)
+ err = decodeUTCTime(tm, &tm1.tm_year, &tm1.tm_mon,
+ &tm1.tm_mday, &tm1.tm_hour, &tm1.tm_min, &tm1.tm_sec);
+ if(tm->type == V_ASN1_GENERALIZEDTIME)
+ err = decodeGeneralizedTime(tm, &tm1.tm_year, &tm1.tm_mon,
+ &tm1.tm_mday, &tm1.tm_hour, &tm1.tm_min, &tm1.tm_sec);
+
+ // V 1.76 - in format 1.3 we use CCYY-MM-DDTHH:MM:SSZ
+ if(!pSigDoc || (pSigDoc &&
+ !strcmp(pSigDoc->szFormatVer, DIGIDOC_XML_1_3_VER) )) {
+ snprintf(buf, len, "%04d-%02d-%02dT%02d:%02d:%02dZ",
+ year + tm1.tm_year, tm1.tm_mon, tm1.tm_mday,
+ tm1.tm_hour, tm1.tm_min, tm1.tm_sec);
+ } else
+ // in version 1.0 we use format CCYY.MM.DDTHH:MM:SS-TZ
+ if(pSigDoc && !strcmp(pSigDoc->szFormat, SK_XML_1_NAME) && !strcmp(pSigDoc->szFormatVer, SK_XML_1_VER)) {
+ tm1.tm_year -= 1900 - year;
+ tm1.tm_mon -= 1;
+ tm1.tm_isdst = _daylight;
+ t2 = mktime(&tm1);
+ if (err == ERR_OK) {
+ if (_daylight!=0) {
+ if (_timezone<0) {
+ dmz = (_timezone / 3600) - _daylight;
+ } else {
+ dmz = (_timezone / 3600) + _daylight;
+ }
+ } else {
+ dmz=_timezone / 3600;
+ }
+ t2 -= (dmz * 3600);
+ ddocLocalTime(&t2, &tm2, 1);
+ snprintf(buf, len, "%04d.%02d.%02dT%02d:%02d:%02d%+03d:00",
+ tm2.tm_year + 1900, tm2.tm_mon + 1,
+ tm2.tm_mday, tm2.tm_hour, tm2.tm_min,
+ tm2.tm_sec, dmz * -1);
+ ddocDebug(5, "asn1time2strYear",
+ "ASN1 time: %s, tz: %d, string: %s\n", tm->data, dmz * -1, buf);
+ }
+ } else { // in version 1.1 we use format CCYY.MM.DDTHH:MM:SSZ and allways UTC time
+ snprintf(buf, len, "%04d.%02d.%02dT%02d:%02d:%02dZ",
+ year + tm1.tm_year, tm1.tm_mon, tm1.tm_mday,
+ tm1.tm_hour, tm1.tm_min, tm1.tm_sec);
+ }
+
+ if (err != ERR_OK) SET_LAST_ERROR(err);
+ return err;
+}
+
+//==========================================================
+// converts ASN1 time to string
+//==========================================================
+int asn1time2str(const SignedDoc* pSigDoc, ASN1_TIME* tm, char* buf, int len)
+{
+ return asn1time2strYear(pSigDoc, tm, buf, 0, len);
+}
+
+
+
+//==============================================================================
+// converts ASN1_GENERALIZEDTOME object to string
+//==============================================================================
+int str2asn1time(const SignedDoc* pSigDoc, const char* str, ASN1_GENERALIZEDTIME* asn1tm)
+{
+ char buf[50];
+ int rc, dmz = 0;
+ struct tm tm1, tm2;
+ time_t t2;
+
+
+ RETURN_IF_NULL_PARAM(str);
+ RETURN_IF_NULL_PARAM(asn1tm);
+ _tzset();
+ memset(&tm1, 0, sizeof(tm1));
+ // in version 1.0 we use format CCYY.MM.DDTHH:MM:SS-TZ
+ if(!strcmp(pSigDoc->szFormat, SK_XML_1_NAME) && !strcmp(pSigDoc->szFormatVer, SK_XML_1_VER)) {
+ sscanf(str, "%04d.%02d.%04dT%02d:%02d:%02d%3d:00",
+ &(tm1.tm_year), &(tm1.tm_mon), &(tm1.tm_mday),
+ &(tm1.tm_hour), &(tm1.tm_min), &(tm1.tm_sec), &dmz);
+ tm1.tm_year -= 1900;
+ tm1.tm_mon -= 1;
+ tm1.tm_isdst = _daylight;
+ t2 = mktime(&tm1);
+ t2 -= (dmz * 3600);
+ ddocLocalTime(&t2, &tm2, 1);
+ snprintf(buf, sizeof(buf), "%04d%02d%02d%02d%02d%02dZ",
+ tm2.tm_year + 1900, tm2.tm_mon + 1, tm2.tm_mday,
+ tm2.tm_hour, tm2.tm_min, tm2.tm_sec);
+ } else { // in version 1.1 we use format CCYY.MM.DDTHH:MM:SSZ and allways UTC time
+ sscanf(str, "%04d.%02d.%04dT%02d:%02d:%02dZ",
+ &(tm1.tm_year), &(tm1.tm_mon), &(tm1.tm_mday),
+ &(tm1.tm_hour), &(tm1.tm_min), &(tm1.tm_sec));
+ snprintf(buf, sizeof(buf), "%04d%02d%02d%02d%02d%02dZ",
+ tm1.tm_year, tm1.tm_mon, tm1.tm_mday,
+ tm1.tm_hour, tm1.tm_min, tm1.tm_sec);
+ }
+ rc = ASN1_GENERALIZEDTIME_set_string(asn1tm, buf);
+ //printf("String: %s, tz: %d, ASN1 time: %s\n", str, dmz, asn1tm->data);
+ return ERR_OK;
+}
+
+//===================================================================
+// converts time_t to timestamp string
+// t - time_t input value
+// szTimestamp - output buffer
+// len - length of buffer
+// returns error code or ERR_OK
+//===================================================================
+EXP_OPTION int time_t2str(time_t t, char* szTimestamp, int len)
+{
+ struct tm tm1;
+
+ RETURN_IF_NULL_PARAM(szTimestamp);
+ ddocLocalTime(&t, &tm1, 0);
+ snprintf(szTimestamp, len, "%04d-%02d-%02dT%02d:%02d:%02dZ",
+ tm1.tm_year + 1900, tm1.tm_mon + 1,
+ tm1.tm_mday, tm1.tm_hour, tm1.tm_min, tm1.tm_sec);
+ return ERR_OK;
+}
+
+//===================================================================
+// converts string to time_t
+// szTimestamp - input buffer
+// pT - address time_t output value
+// returns error code or ERR_OK
+//===================================================================
+EXP_OPTION int str2time_t(char* szTimestamp, time_t* pT)
+{
+ struct tm tm1;
+ time_t t1 = 0;
+ //int dmz = 0;
+
+ RETURN_IF_NULL_PARAM(szTimestamp);
+ RETURN_IF_NULL_PARAM(pT);
+ _tzset();
+ memset(&tm1, 0, sizeof(tm1));
+ sscanf(szTimestamp, "%04d.%02d.%04dT%02d:%02d:%02dZ",
+ &(tm1.tm_year), &(tm1.tm_mon), &(tm1.tm_mday),
+ &(tm1.tm_hour), &(tm1.tm_min), &(tm1.tm_sec) /*, &dmz*/);
+ tm1.tm_year -= 1900;
+ tm1.tm_mon -= 1;
+ tm1.tm_isdst = _daylight;
+ t1 = mktime(&tm1);
+ //t1 -= (dmz * 3600);
+ (*pT) = t1;
+ return ERR_OK;
+}
+
diff --git a/libdigidoc/DigiDocConvert.h b/libdigidoc/DigiDocConvert.h
new file mode 100644
index 0000000..d82886c
--- /dev/null
+++ b/libdigidoc/DigiDocConvert.h
@@ -0,0 +1,303 @@
+#ifndef __DIGIDOC_CONVERT_H__
+#define __DIGIDOC_CONVERT_H__
+//==================================================
+// FILE: DigiDocEnc.h
+// PROJECT: Digi Doc Encryption
+// DESCRIPTION: DigiDoc character conversion routines
+// AUTHOR: Veiko Sinivee, S|E|B IT Partner Estonia
+//==================================================
+// Copyright (C) AS Sertifitseerimiskeskus
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+// GNU Lesser General Public Licence is available at
+// http://www.gnu.org/copyleft/lesser.html
+//==========< HISTORY >=============================
+// 22.09.2004 Veiko Sinivee
+// Creation
+//==================================================
+
+#include <libdigidoc/DigiDocLib.h>
+#include <libdigidoc/DigiDocDefs.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+//==========< general functions >============
+
+//--------------------------------------------------
+// Decodes a single hex digit
+// h - hex digit
+// return binary value
+//--------------------------------------------------
+byte h2b(char h);
+
+//--------------------------------------------------
+// Converts a single byte to two hex characters
+// b - binary value
+// dest - destination buffer
+//--------------------------------------------------
+void b2h(byte b, char* dest);
+
+//--------------------------------------------------
+// Converts correct filename to incorrect encoding
+// used in formats 1.0, 1.1 and 1.2
+// src - input data
+// dest - buffer for converted data
+// len - length of destination buffer
+//--------------------------------------------------
+EXP_OPTION void convFNameToWin(const char* src, char* dest, int len);
+
+//--------------------------------------------------
+// Converts bad UTF-8 filename used in formats 1.0,
+// 1.1 and 1.2 to correct encoding
+// src - input data
+// dest - buffer for converted data
+// len - length of destination buffer
+//--------------------------------------------------
+EXP_OPTION void convWinToFName(const char* src, char* dest, int len);
+
+// Converts a hex number (string) to binary value
+EXP_OPTION void hex2bin(const char* hex, byte* bin, int* len);
+
+// Converts a binary value to hex string
+EXP_OPTION void bin2hex(const byte* bin, int blen, char* hex, int* len);
+
+//============================================================
+// Encodes input data in hex format.
+// pMBufSrc - input data
+// pMBufDest - destination buffer
+//============================================================
+EXP_OPTION int ddocBin2Hex(const DigiDocMemBuf* pMBufSrc, DigiDocMemBuf* pMBufDest);
+
+// Helper function that converts ISO Latin1 to UTF8
+EXP_OPTION char* ascii2utf8(const char* ascii, char* utf8out, int* outlen);
+
+// Helper function that converts UTF8 to ISO Latin1
+EXP_OPTION char* utf82ascii(const char* utf8in, char* asciiout, int* outlen);
+
+// converts string from unicode to ascii
+EXP_OPTION void unicode2ascii(const char* uni, char* dest);
+// converts unicode escapes string to UTF8
+EXP_OPTION void unicodeEscapes2utf8(const char* uni, char* dest);
+
+
+char* escape2xmlsym(const char* src);
+
+
+int hasUmlauts(const char* str);
+int str2asn1time(const SignedDoc* pSigDoc, const char* str, ASN1_GENERALIZEDTIME* asn1tm);
+
+//--------------------------------------------------
+// Converts xml symbols to corresponding escapes
+// src - string with xml special sybols
+// returns string with esacpes
+//--------------------------------------------------
+char* escape2xmlsym(const char* src);
+
+char* unescapeXmlsym(const char* src);
+
+//--------------------------------------------------
+// Converts input data to UTF-8
+// src - input data
+// returns converted string or NULL. Caller must free it.
+//--------------------------------------------------
+EXP_OPTION int ddocConvertInput(const char* src, char** dest);
+
+// Base64 encode some data
+EXP_OPTION void encode(const byte* raw, int rawlen, byte* buf, int* buflen);
+// Base64 decode some data
+EXP_OPTION void decode(const byte* raw, int rawlen, byte* buf, int* buflen);
+
+
+//============================================================
+// Decodes input data in Base64 format.
+// pMBufSrc - input data
+// pMBufDest - destination buffer
+//============================================================
+EXP_OPTION int ddocDecodeBase64(DigiDocMemBuf* pMBufSrc, DigiDocMemBuf* pMBufDest);
+
+//============================================================
+// Decodes input data in Base64 format.
+// data - input data
+// len - length of input data. Use -1 for zero terminated strings
+// pMBufDest - destination buffer
+//============================================================
+EXP_OPTION int ddocDecodeBase64Data(void* data, long lLen, DigiDocMemBuf* pMBufDest);
+
+//============================================================
+// Encodes input data in Base64 format.
+// pMBufSrc - input data
+// pMBufDest - destination buffer
+//============================================================
+EXP_OPTION int ddocEncodeBase64(const DigiDocMemBuf* pMBufSrc, DigiDocMemBuf* pMBufDest);
+
+//=======< time convesrion >=======================
+
+//--------------------------------------------------
+// Decodes an ASN1 generalized time
+// tm - ASN1 generalized time
+// y - year
+// M - month
+// d - day of month
+// h - hour
+// m - minute
+// s - second
+// returns error code or ERR_OK
+//--------------------------------------------------
+int decodeGeneralizedTime(ASN1_GENERALIZEDTIME *tm,
+ int* y, int* M, int* d,
+ int* h, int* m, int* s);
+
+//--------------------------------------------------
+// Decodes an ASN1 UTC time
+// tm - ASN1 generalized time
+// y - year
+// M - month
+// d - day of month
+// h - hour
+// m - minute
+// s - second
+// returns error code or ERR_OK
+//--------------------------------------------------
+int decodeUTCTime(ASN1_UTCTIME *tm,
+ int* y, int* M, int* d,
+ int* h, int* m, int* s);
+
+//==========================================================
+// converts ASN1 time to time_t
+//==========================================================
+int asn1time2time_t(ASN1_TIME* tm, time_t* pT);
+
+int asn1time2time_t_local(ASN1_TIME* tm, time_t* pT);
+
+//==========================================================
+// converts ASN1 time to string
+//==========================================================
+int asn1time2strYear(const SignedDoc* pSigDoc, ASN1_TIME* tm, char* buf, int year, int len);
+
+//==========================================================
+// converts ASN1 time to string
+//==========================================================
+int asn1time2str(const SignedDoc* pSigDoc, ASN1_TIME* tm, char* buf, int len);
+
+//===================================================================
+// converts time_t to timestamp string
+// t - time_t input value
+// szTimestamp - output buffer
+// len - length of buffer
+// returns error code or ERR_OK
+//===================================================================
+ EXP_OPTION int time_t2str(time_t t, char* szTimestamp, int len);
+
+//===================================================================
+// converts string to time_t
+// szTimestamp - input buffer
+// pT - address time_t output value
+// returns error code or ERR_OK
+//===================================================================
+EXP_OPTION int str2time_t(char* szTimestamp, time_t* pT);
+
+//--------------------------------------------------
+// Converts a filename according to platform rules
+// dest - destination buffer
+// destlen - destination buffer length
+// src - source filename
+// returns error code or ERR_OK
+//--------------------------------------------------
+EXP_OPTION int ddocConvertFileName(char* dest, int destlen, const char* src);
+
+//==========< only win32 fucntions >============
+
+#ifdef WIN32
+
+//--------------------------------------------------
+// Converts input OEM charset data to 16 bit unicode.
+// oem - 8 bit oem charset input data
+// unicode - address of pointer for allocated unicode string. Caller must free() !
+// outlen - address of length variable for unicode string
+// returns error code or ERR_OK
+//--------------------------------------------------
+EXP_OPTION int oem2unicode(const char* oem, char** unicode, int* outlen);
+
+//--------------------------------------------------
+// Converts input 16 bit unicode data to UTF8.
+// unicode - 16 bit unicode input data
+// utf8 - address of pointer for allocated utf8 string. Caller must free() !
+// outlen - address of length variable for utf8 string
+// returns error code or ERR_OK
+//--------------------------------------------------
+EXP_OPTION int unicode2utf8(const char* unicode, char** utf8, int* outlen);
+
+//--------------------------------------------------
+// Converts input OEM charset data to UTF-8
+// oem - 8 bit oem charset input data
+// utf8 - address of buffer allocated utf8 string.
+// len - size of buffer
+// returns error code or ERR_OK
+//--------------------------------------------------
+EXP_OPTION int oem2utf8(const char* oem, char* utf8, int len);
+
+//--------------------------------------------------
+// Converts input UTF-8 data to 16 bit unicode data.
+// utf8 - UTF-8 input data
+// unicode - address of pointer for allocated unicode string. Caller must free() !
+// outlen - address of length variable for unicode string
+// returns error code or ERR_OK
+//--------------------------------------------------
+EXP_OPTION int utf82unicode(const char* utf8, char** unicode, int* outlen);
+
+//--------------------------------------------------
+// Converts input 16 bit unicode data to oem charset data.
+// unicode - 16 bit unicode input data
+// oem - address of pointer for allocated oem string. Caller must free() !
+// outlen - address of length variable for oem string
+// returns error code or ERR_OK
+//--------------------------------------------------
+EXP_OPTION int unicode2oem(const char* unicode, char** oem, int* outlen);
+
+//--------------------------------------------------
+// Converts input UTF-8 data to OEM charset data
+// utf8 - UTF-8 input data
+// oem - address of buffer for oem string.
+// len - size of buffer
+// returns error code or ERR_OK
+//--------------------------------------------------
+EXP_OPTION int utf82oem(const char* utf8, char* oem, int len);
+
+//--------------------------------------------------
+// Converts input UTF-8 data to OEM charset data
+// pSigDoc - signed doc object
+// pDf - data file obejct
+// outFileName - output buffer
+// len - length of output buffer
+// returns error code or ERR_OK
+//--------------------------------------------------
+EXP_OPTION int getDataFileFileName(SignedDoc* pSigDoc, DataFile* pDf, char* outFileName, int len);
+
+#endif // WIN32
+
+//--------------------------------------------------
+// Releases mem-block allocated by lib. In win32
+// this must be done since the mem was allocated by dll
+// and must also be released by dll that allocated it.
+// p - mem to be freed
+//--------------------------------------------------
+EXP_OPTION void freeLibMem(void* p);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif // __DIGIDOC_CONVERT_H__
+
+
+
diff --git a/libdigidoc/DigiDocCsp.c b/libdigidoc/DigiDocCsp.c
new file mode 100644
index 0000000..ee0081b
--- /dev/null
+++ b/libdigidoc/DigiDocCsp.c
@@ -0,0 +1,2229 @@
+//==================================================
+// FILE: DigiDocCsp.c
+// PROJECT: Digi Doc
+// DESCRIPTION: Digi Doc functions for creating
+// and reading signed documents.
+// AUTHOR: Veiko Sinivee, S|E|B IT Partner Estonia
+//==================================================
+// Copyright (C) AS Sertifitseerimiskeskus
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+// GNU Lesser General Public Licence is available at
+// http://www.gnu.org/copyleft/lesser.html
+//==========< HISTORY >=============================
+// 20.10.2004 Changed createOCSPRequest, added SignedDoc parameeter
+// 10.02.2004 Changed decodeCertificateData
+// ReadCertSerialNumber
+// ReadCertificate
+// NotaryInfo_new
+// 01.02.2004 Aare Amenberg
+// from comments "Functions from EstIDLib.c"
+// functions from EstIdLib.c file
+// 20.11.2003 Aare Amenberg
+// removed tes2.resp file creating
+// 29.10.2003 Created by AA
+//
+//==================================================
+#ifdef WIN32
+
+#define WIN32_PKCS 1
+
+#include <windows.h>
+#include <wincrypt.h>
+#include <libdigidoc/DigiDocDefs.h>
+#include <libdigidoc/DigiDocLib.h>
+#include <libdigidoc/DigiDocCert.h>
+#include <libdigidoc/DigiDocMem.h>
+#include <libdigidoc/DigiDocConfig.h>
+#include <libdigidoc/DigiDocOCSP.h>
+#include <libdigidoc/DigiDocObj.h>
+#include <libdigidoc/DigiDocGen.h>
+#include <libdigidoc/DigiDocVerify.h>
+#include <libdigidoc/DigiDocConvert.h>
+#include <libdigidoc/DigiDocDebug.h>
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <memory.h>
+#include <string.h>
+#include <assert.h>
+#include <malloc.h>
+#include <direct.h>
+
+#include <fcntl.h>
+#include <time.h>
+
+
+#include <openssl/sha.h>
+#include <openssl/rsa.h>
+#include <openssl/evp.h>
+#include <openssl/objects.h>
+#include <openssl/x509.h>
+#include <openssl/x509v3.h>
+#include <openssl/err.h>
+#include <openssl/pem.h>
+#include <openssl/ssl.h>
+#include <openssl/ocsp.h>
+#include <openssl/pkcs12.h>
+
+#include <libxml/globals.h>
+#include <libxml/xmlerror.h>
+#include <libxml/parser.h>
+#include <libxml/parserInternals.h> /* only for xmlNewInputFromFile() */
+#include <libxml/tree.h>
+#include <libxml/debugXML.h>
+#include <libxml/xmlmemory.h>
+#include <libxml/c14n.h>
+
+#include "DigiCrypt.h"
+#include "DigiDocCert.h"
+
+#include "DigiDocCsp.h"
+
+CSProvider * cCSProvider;
+CSProvider * knownCSProviders[3];
+
+
+//AARE01102003
+typedef struct StoreHandle_st {
+ HCERTSTORE hHandle;
+ BOOL fRoot;
+} StoreHandle;
+
+
+BOOL Digi_OpenStore(StoreHandle *hStore);
+void Digi_CloseStore(StoreHandle *hStore);
+BOOL Digi_IsValidResponderCert(PCCERT_CONTEXT pCert);
+
+X509 * Digi_FindX509CopyFromStore(StoreHandle *hStore, X509 *pX509cert);
+X509 *Digi_FindResponderCert(StoreHandle *hStore, X509 *poSignerCert);
+char *Digi_GetName(X509_NAME *pName);
+BOOL Digi_CheckEnhancedKeyUsage(PCCERT_CONTEXT pCert, char *psValue);
+X509 *Digi_FindCertByResponse(StoreHandle *hStore, OCSP_RESPONSE *poResponse);
+PCCERT_CONTEXT Digi_FindCertBySubject(StoreHandle *hStore,char *psCN, BOOL bCheckValid, const char* szSerialNr, BOOL bCA);
+BOOL Digi_CompareCN(char *psSub1, char *psSub2);
+X509 **Digi_MakeCertList(X509 *poX509Main, StoreHandle *hStore);
+X509 **Digi_MakeCertListLow(X509 *poX509Main, StoreHandle *hStore);
+BOOL Digi_CheckResponderCertByResponse(X509 *poX509Responder, OCSP_RESPONSE *poResponse);
+
+void Digi_FreeCertList(X509 **caCerts);
+BOOL Digi_IsCert1SubjectDNEqualCert2IssuerDN(X509 *pCert1, X509 *pCert2);
+int ReadTestAare(char *pkcs12file);
+int Test_ReadCertData(X509 *poX509);
+int Test_ReadCertDataC(PCCERT_CONTEXT pCert);
+
+// Reads a certificate from pkcs12 container
+EXP_OPTION int Digi_readCertificateByPKCS12OnlyCertHandle(const char *pkcs12file, const char * passwd, X509 **x509);
+int Digi_getConfirmationWithCertSearch(SignedDoc* pSigDoc, SignatureInfo* pSigInfo, char* pkcs12File, char* password,
+ char* notaryURL, char* proxyHost, char* proxyPort);
+//int Digi_setNotaryCertificate(NotaryInfo* pNotary, X509* notCert);
+int Digi_verifyNotaryInfoWithCertSearch(const SignedDoc* pSigDoc, const NotaryInfo* pNotInfo);
+
+// verifies this one signature
+int Digi_verifySignatureInfo(const SignedDoc* pSigDoc, const SignatureInfo* pSigInfo,
+ const char* szDataFile);
+// verifies the whole document (returns on first err)
+int Digi_verifySigDoc(const SignedDoc* pSigDoc, const char* szDataFile);
+int Digi_verifySigDocWithCertSearch(const SignedDoc* pSigDoc, const char* szDataFile);
+int Digi_verifyNotaryInfoCERT(const SignedDoc* pSigDoc,
+ const NotaryInfo* pNotInfo,
+ const X509** caCerts,
+ const X509* notCert,
+ const X509* pSigCA);
+//int Digi_initializeNotaryInfoWithOCSP(SignedDoc* pSigDoc, NotaryInfo* pNotary,
+// OCSP_RESPONSE* resp, X509* notCert, int initDigest);
+
+
+// verifies signed doc
+int verifySigDoc_ByCertStore(const SignedDoc* pSigDoc, const char* szDataFile);
+// Verifies this signature
+int verifySignatureInfo_ByCertStore(const SignedDoc* pSigDoc,
+ const SignatureInfo* pSigInfo, const char* szDataFile);
+// Verfies NotaryInfo signature
+int verifyNotaryInfo_ByCertStore(const SignedDoc* pSigDoc, const NotaryInfo* pNotInfo);
+
+// resolves certificate chain from MS CertStore upto root cert
+int resolveCertChain_ByCertStore(CertItem* pListStart);
+
+int GetAllCertificatesFromStore(const CertSearchStore *sS, CertItem **certList, int *numberOfCerts);
+void prepareString(const char * strIN,char * strOUT);
+void reverseArray(unsigned char *array, unsigned long arrayLen);
+
+extern int setup_verifyCERT(X509_STORE **newX509_STORE, const char *CApath, const X509** certs);
+
+extern X509_ALGOR* setSignAlgorithm(const EVP_MD * type);
+
+extern EXP_OPTION int signOCSPRequestPKCS12(OCSP_REQUEST *req, const char* filename, const char* passwd);
+
+
+extern LPBYTE getDefaultKeyName(CSProvider * cProvider);
+//extern CERT_PUBLIC_KEY_INFO * getCardKeyInfo(const char * ppContainerName);
+extern int GetCertificateFromStore(const CertSearchStore *sS, X509 **x509);
+extern int GetSignedHashWithEstIdCSPkey(const char * dataToBeSigned,unsigned long dataLen,unsigned char *pbKeyBlob, unsigned long *pbKeyBlobLen,unsigned char *hash, unsigned long *hashLen, unsigned char * hashedSignature,unsigned long * sigLen);
+extern int GetSignedHashWithKeyAndCSP(char *psKeyName, char *psCSPName, const char * dataToBeSigned,unsigned long dataLen,unsigned char *pbKeyBlob, unsigned long *pbKeyBlobLen,unsigned char *hash, unsigned long *hashLen, unsigned char * hashedSignature,unsigned long * sigLen, const char*
+);
+extern X509 * findIssuerCertificatefromStore(X509 *x509);
+X509* Digi_FindDirectCA(X509 *poX509Main, StoreHandle *hStore);
+
+X509* Digi_FindCertBySubjectAndHash(StoreHandle *hStore, char *psCN, BOOL bCheckValid, const char* szSerialNr, BOOL bCA, DigiDocMemBuf *pHash);
+
+//==========< macros >====================
+
+#define SET_LAST_ERROR(code) (addError((code), __FILE__, __LINE__, ""))
+#define SET_LAST_ERROR_IF_NOT(expr, code) { if(!(expr)) addError((code), __FILE__, __LINE__, #expr); }
+#define SET_LAST_ERROR_RETURN(code, retVal) { SET_LAST_ERROR(code); return (retVal); }
+#define SET_LAST_ERROR_RETURN_IF_NOT(expr, code, retVal) { if(!(expr)) { addError((code), __FILE__, __LINE__, #expr); return (retVal); } }
+#define SET_LAST_ERROR_RETURN_VOID_IF_NOT(expr, code) { if(!(expr)) { addError((code), __FILE__, __LINE__, #expr); return; } }
+#define RETURN_IF_NOT(expr, code) SET_LAST_ERROR_RETURN_IF_NOT((expr), (code), (code));
+#define RETURN_IF_NULL(p) RETURN_IF_NOT((p), ERR_NULL_POINTER);
+#define RETURN_VOID_IF_NULL(p) SET_LAST_ERROR_RETURN_VOID_IF_NOT((p), ERR_NULL_POINTER);
+#define RETURN_OBJ_IF_NULL(p, obj) SET_LAST_ERROR_RETURN_IF_NOT((p), ERR_NULL_POINTER, (obj));
+#define SET_LAST_ERROR_RETURN_CODE(code) { SET_LAST_ERROR(code); return (code); }
+
+//========================================
+
+
+BOOL Digi_OpenStore(StoreHandle *hStore)
+{
+ BOOL fRes = FALSE;
+ if (hStore != NULL) {
+ memset(hStore,0,sizeof(StoreHandle));
+ hStore->hHandle = CertOpenStore(CERT_STORE_PROV_SYSTEM,0,(HCRYPTPROV)NULL,
+ CERT_SYSTEM_STORE_CURRENT_USER | CERT_STORE_READONLY_FLAG,L"CA");
+ if (hStore->hHandle != NULL)
+ fRes = TRUE;
+ }
+ return(fRes);
+}
+
+void Digi_CloseStore(StoreHandle *hStore)
+{
+if (hStore != NULL && hStore->hHandle)
+ CertCloseStore(hStore->hHandle,CERT_CLOSE_STORE_FORCE_FLAG);
+hStore->hHandle = NULL;
+hStore->fRoot = FALSE;
+}
+
+
+X509 * Digi_FindX509CopyFromStore(StoreHandle *hStore, X509 *pX509cert) {
+ X509 *pResultCert = NULL;
+ char* certBlob;
+ int certBlobLen;
+ PCCERT_CONTEXT pCertFindContext = NULL;
+ PCCERT_CONTEXT pCertContext = NULL;
+ char *psValue = "1.3.6.1.5.5.7.3.9";
+
+ if (hStore == NULL || pX509cert == NULL) return(pResultCert);
+
+ certBlobLen = i2d_X509(pX509cert, NULL) + 1000;
+ certBlob = malloc(certBlobLen);
+
+ encodeCert(pX509cert,certBlob,&certBlobLen);
+ if (!certBlob) return(pResultCert);
+
+ pCertFindContext = CertCreateCertificateContext(X509_ASN_ENCODING|PKCS_7_ASN_ENCODING,certBlob,certBlobLen);
+ if (!pCertFindContext) return(pResultCert);
+
+ pCertContext = CertFindCertificateInStore(hStore->hHandle, X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
+ 0, CERT_FIND_EXISTING, pCertFindContext, NULL);
+
+ if (pCertContext) { //cert found
+ if (Digi_CheckEnhancedKeyUsage(pCertContext,psValue) != TRUE) return(pResultCert);
+ ddocDecodeX509Data(&pResultCert,pCertContext->pbCertEncoded,pCertContext->cbCertEncoded);
+ } else {
+ char schultz[300];
+ snprintf(schultz, sizeof(schultz), "CertFindCertificateInStore open failed with 0x%0lx ", GetLastError());
+ return(pResultCert);
+ }
+
+ if (certBlob) free(certBlob);
+
+ return pResultCert;
+}
+
+
+
+X509 *Digi_FindResponderCert(StoreHandle *hStore, X509 *poSignerCert)
+{
+X509 *poResultCert = NULL;
+FILETIME oResultTime;
+X509 *poX509;
+BOOL fSet;
+PCCERT_CONTEXT pCert = NULL;
+X509_NAME *poX509SignerName = NULL;
+X509_NAME *poX509CurrentName = NULL;
+
+poX509SignerName = X509_get_issuer_name(poSignerCert);
+while (pCert = CertEnumCertificatesInStore(hStore->hHandle, pCert))
+ {
+ fSet = FALSE;
+ //get handle
+ //AA100204
+ ddocDecodeX509Data(&poX509, pCert->pbCertEncoded,pCert->cbCertEncoded);
+ if (poX509 != NULL)
+ {
+ //get current cert issuer
+ poX509CurrentName = X509_get_issuer_name(poX509);
+ //TEST
+ //psTemp = Digi_GetName(poX509CurrentName);
+ //Digi_CheckEnhancedKeyUsage(pCert,"1.3.6.1.5.5");
+ //Test_ReadCertData(poX509);
+ //END TEST
+ // if issuer match
+ if (poX509SignerName != NULL && poX509CurrentName != NULL && X509_NAME_cmp(poX509SignerName, poX509CurrentName) == 0)
+ {
+ // check date
+ // NULL, if current time
+ if (Digi_IsValidResponderCert(pCert) == TRUE)
+ {
+ if (poResultCert == NULL)
+ fSet = TRUE;
+ else
+ {
+ if (CompareFileTime(&pCert->pCertInfo->NotBefore, &oResultTime) > 0)
+ fSet = TRUE;
+ }
+ if (fSet == TRUE)
+ {
+ //delete previous if exists
+ if (poResultCert != NULL)
+ X509_free(poResultCert);
+ //set result value
+ poResultCert = poX509;
+ memmove(&oResultTime,&pCert->pCertInfo->NotBefore,sizeof(FILETIME));
+ }
+ }
+ }
+ }
+ if (poX509 != NULL && fSet == FALSE)
+ X509_free(poX509);
+ }
+
+
+return(poResultCert);
+}
+
+int Test_ReadCertDataC(PCCERT_CONTEXT pCert)
+{
+int iRes = 0;
+X509 *poX509 = NULL;
+if (pCert != NULL);
+ //AA100204
+ ddocDecodeX509Data(&poX509,pCert->pbCertEncoded,pCert->cbCertEncoded);
+if (poX509 != NULL)
+ iRes = Test_ReadCertData(poX509);
+return(iRes);
+}
+
+
+
+int Test_ReadCertData(X509 *poX509)
+{
+ int iRes;
+ DigiDocMemBuf mbuf1;
+ DigiDocMemBuf mbuf2;
+
+ mbuf1.pMem = 0;
+ mbuf1.nLen = 0;
+ mbuf2.pMem = 0;
+ mbuf2.nLen = 0;
+ // get issuer DN
+ iRes = ddocCertGetIssuerDN(poX509, &mbuf1);
+ iRes = ddocMemAppendData(&mbuf1, "\n", -1);
+ // get subject DN
+ iRes = ddocCertGetSubjectDN(poX509, &mbuf2);
+ iRes = ddocMemAppendData(&mbuf1, (const char*)mbuf2.pMem, mbuf2.nLen);
+ // display it
+ MessageBox(NULL,(const char*)mbuf1.pMem,"TEST",0);
+ ddocMemBuf_free(&mbuf1);
+ ddocMemBuf_free(&mbuf2);
+ return(0);
+}
+
+BOOL Digi_IsValidResponderCert(PCCERT_CONTEXT pCert)
+{
+BOOL fIsValid = FALSE;
+char *psValue = "1.3.6.1.5.5.7.3.9";
+if (pCert != NULL)
+ {
+ fIsValid = Digi_CheckEnhancedKeyUsage(pCert,psValue);
+ if (fIsValid == TRUE)
+ {
+ if (CertVerifyTimeValidity(NULL,pCert->pCertInfo) != 0)
+ fIsValid = FALSE;
+ }
+ }
+return(fIsValid);
+}
+
+
+BOOL Digi_CheckEnhancedKeyUsage(PCCERT_CONTEXT pCert, char *psValue)
+{
+BOOL fRes = FALSE;
+DWORD dwFlags = CERT_FIND_EXT_ONLY_ENHKEY_USAGE_FLAG;
+PCERT_ENHKEY_USAGE pUsage = NULL;
+//DWORD cUsageIdentifier - number of elements in rgpszUsageIdentifier
+//LPSTR *rgpszUsageIdentifier - array;
+DWORD cbUsage = 0;
+BOOL fCallRes;
+int iI;
+char *psValueCurrent;
+fCallRes = CertGetEnhancedKeyUsage(pCert,dwFlags,NULL, &cbUsage);
+if (fCallRes == TRUE)
+ {
+ pUsage = (PCERT_ENHKEY_USAGE)malloc(cbUsage);
+ fCallRes = CertGetEnhancedKeyUsage(pCert,dwFlags,pUsage, &cbUsage);
+ if (fCallRes == TRUE)
+ {
+ for (iI=0; iI < (int)pUsage->cUsageIdentifier;++iI)
+ {
+ psValueCurrent = pUsage->rgpszUsageIdentifier[iI];
+ if (psValueCurrent != NULL && psValue != NULL)
+ {
+ if (strstr(psValueCurrent,psValue) != NULL)
+ {
+ fRes = TRUE;
+ break;
+ }
+ }
+ }
+ }
+ }
+if (pUsage != NULL)
+ free(pUsage);
+return(fRes);
+}
+
+
+X509 *Digi_FindCertByResponse(StoreHandle *hStore, OCSP_RESPONSE *poResponse)
+{
+ X509 *poX509 = NULL;
+ PCCERT_CONTEXT pCert = NULL;
+ OCSP_RESPID *rid = NULL;
+ OCSP_BASICRESP *br = NULL;
+ OCSP_RESPDATA *rd = NULL;
+ int iLen;
+ char sCN[255];
+
+ if (poResponse != NULL) {
+ if ((br = OCSP_response_get1_basic(poResponse)) == NULL)
+ return(poX509);
+ rd = br->tbsResponseData;
+ rid = rd->responderId;
+ if (rid->type != V_OCSP_RESPID_NAME) {
+ if(br) OCSP_BASICRESP_free(br);
+ return(poX509);
+ }
+ iLen = X509_NAME_get_text_by_NID(rid->value.byName,NID_commonName,sCN,sizeof(sCN));
+ if (iLen > 0) //VS: 18.03.2006 - use only currently valid cert for new notary
+ pCert = Digi_FindCertBySubject(hStore, sCN, TRUE, 0, TRUE);
+ if(pCert != NULL)
+ //AA100204
+ ddocDecodeX509Data(&poX509,pCert->pbCertEncoded,pCert->cbCertEncoded);
+ }
+ if(br) OCSP_BASICRESP_free(br);
+ return(poX509);
+}
+
+
+
+//Added by AA 09/10/2003
+BOOL Digi_CheckResponderCertByResponse(X509 *poX509Responder, OCSP_RESPONSE *poResponse)
+{
+BOOL fRes = FALSE;
+OCSP_RESPID *rid = NULL;
+OCSP_BASICRESP *br = NULL;
+OCSP_RESPDATA *rd = NULL;
+int iLen;
+char sCNResp[255];
+char sCNCert[255];
+if (poResponse != NULL)
+ {
+ if ((br = OCSP_response_get1_basic(poResponse)) == NULL)
+ return(fRes);
+ rd = br->tbsResponseData;
+ rid = rd->responderId;
+ if (rid->type != V_OCSP_RESPID_NAME)
+ return(fRes);
+ iLen = X509_NAME_get_text_by_NID(rid->value.byName,NID_commonName,sCNResp,sizeof(sCNResp));
+ if (iLen > 0)
+ {
+ iLen = X509_NAME_get_text_by_NID(X509_get_subject_name(poX509Responder),NID_commonName, sCNCert,sizeof(sCNCert));
+ if (iLen > 0)
+ {
+ fRes = Digi_CompareCN(sCNResp,sCNCert);
+ }
+ }
+ }
+return(fRes);
+}
+
+//VS: 18.03.2006 - use only currently valid cert for new notary
+PCCERT_CONTEXT Digi_FindCertBySubject(StoreHandle *hStore, char *psCN, BOOL bCheckValid, const char* szSerialNr, BOOL bCA)
+{
+ PCCERT_CONTEXT pCert = NULL;
+ BOOL fFind = FALSE;
+ X509 *poX509;
+ char sSerial[255];
+ time_t tNow;
+ DigiDocMemBuf mbuf;
+
+ mbuf.pMem = 0;
+ mbuf.nLen = 0;
+
+ if (hStore == NULL || psCN == NULL)
+ return(pCert);
+ Digi_CloseStore(hStore);
+ hStore->hHandle = CertOpenStore(CERT_STORE_PROV_SYSTEM,0,(HCRYPTPROV)NULL,
+ CERT_SYSTEM_STORE_CURRENT_USER | CERT_STORE_READONLY_FLAG, (bCA ? L"CA" : L"My"));
+ if (hStore->hHandle == NULL)
+ return(pCert);
+ //get signer issuer
+ while (fFind == FALSE && (pCert = CertEnumCertificatesInStore(hStore->hHandle,pCert)))
+ {
+ //AA100204
+ ddocDecodeX509Data(&poX509, pCert->pbCertEncoded,pCert->cbCertEncoded);
+ if (poX509 != NULL)
+ {
+ //iLen = X509_NAME_get_text_by_NID(X509_get_subject_name(poX509),NID_commonName, sSubject,255);
+
+ ddocCertGetSubjectCN(poX509, &mbuf);
+
+ if(mbuf.nLen > 0) {
+ fFind = Digi_CompareCN((char*)mbuf.pMem, psCN);
+ if(fFind) {
+ if(szSerialNr) { //VS: 18.03.2006 - look for a cert with specific serial nr
+ ReadCertSerialNumber(sSerial, sizeof(sSerial)-1, poX509);
+ fFind = !strcmp(szSerialNr, sSerial);
+ } else if(bCheckValid) { //VS: 18.03.2006 - use only currently valid cert for new notary
+ time(&tNow);
+ fFind = !isCertValid(poX509, tNow);
+ }
+ }
+ }
+ X509_free(poX509);
+ }
+ }
+ if (fFind == FALSE)
+ pCert = NULL;
+ return(pCert);
+}
+
+X509* Digi_FindCertBySubjectAndHash(StoreHandle *hStore, char *psCN, BOOL bCheckValid, const char* szSerialNr, BOOL bCA, DigiDocMemBuf *pHash)
+{
+ PCCERT_CONTEXT pCert = NULL;
+ BOOL fFind = FALSE;
+ X509 *poX509 = NULL, *pSCert = NULL;
+ char sSerial[255];
+ time_t tNow;
+ DigiDocMemBuf mbuf1, mbuf2, mbuf3; //, mbuf4, mbuf5;
+
+ mbuf1.pMem = 0;
+ mbuf1.nLen = 0;
+ mbuf2.pMem = 0;
+ mbuf2.nLen = 0;
+ mbuf3.pMem = 0;
+ mbuf3.nLen = 0;
+ /*mbuf4.pMem = 0;
+ mbuf4.nLen = 0;
+ mbuf5.pMem = 0;
+ mbuf5.nLen = 0;*/
+ if (hStore == NULL || psCN == NULL)
+ return NULL;
+ Digi_CloseStore(hStore);
+ hStore->hHandle = CertOpenStore(CERT_STORE_PROV_SYSTEM,0,(HCRYPTPROV)NULL,
+ CERT_SYSTEM_STORE_CURRENT_USER | CERT_STORE_READONLY_FLAG, (bCA ? L"CA" : L"My"));
+ if (hStore->hHandle == NULL)
+ return NULL;
+ ddocEncodeBase64(pHash, &mbuf3);
+ ddocDebug(3, "Digi_FindCertBySubjectAndHash", "Find CN: %s serial: %s subj-hash: %s", psCN, szSerialNr, (char*)mbuf3.pMem);
+ ddocMemBuf_free(&mbuf3);
+ //get signer issuer
+ while (fFind == FALSE && (pCert = CertEnumCertificatesInStore(hStore->hHandle,pCert)))
+ {
+ //AA100204
+ ddocDecodeX509Data(&poX509, pCert->pbCertEncoded,pCert->cbCertEncoded);
+ if (poX509 != NULL)
+ {
+ //iLen = X509_NAME_get_text_by_NID(X509_get_subject_name(poX509),NID_commonName, sSubject,255);
+ ddocCertGetSubjectCN(poX509, &mbuf1);
+ if(mbuf1.nLen > 0) {
+ fFind = Digi_CompareCN((char*)mbuf1.pMem, psCN);
+ if(fFind) {
+ if(szSerialNr) { //VS: 18.03.2006 - look for a cert with specific serial nr
+ ReadCertSerialNumber(sSerial, sizeof(sSerial)-1, poX509);
+ fFind = !strcmp(szSerialNr, sSerial);
+ } else if(bCheckValid) { //VS: 18.03.2006 - use only currently valid cert for new notary
+ time(&tNow);
+ fFind = !isCertValid(poX509, tNow);
+ }
+ }
+ if(fFind && pHash && poX509) {
+ readSubjectKeyIdentifier(poX509, &mbuf2);
+ ddocEncodeBase64(&mbuf2, &mbuf3);
+ //readAuthorityKeyIdentifier(poX509, &mbuf4);
+ //ddocEncodeBase64(&mbuf4, &mbuf5);
+ if(!ddocMemCompareMemBufs(pHash, &mbuf2)) {
+ pSCert = poX509;
+ fFind = TRUE;
+ //break;
+ }
+ else
+ fFind = FALSE;
+ }
+ }
+ //ddocDebug(3, "Digi_FindCertBySubjectAndHash", "Compare CN: %s serial: %s subj-hash: %s auth-hash: %s rc: %d", (char*)mbuf1.pMem, sSerial, (char*)mbuf3.pMem, (char*)mbuf5.pMem, fFind);
+ ddocDebug(3, "Digi_FindCertBySubjectAndHash", "Compare CN: %s serial: %s subj-hash: %s rc: %d", (char*)mbuf1.pMem, sSerial, (char*)mbuf3.pMem, fFind);
+ if(!pSCert) {
+ X509_free(poX509);
+ poX509 = NULL;
+ }
+ ddocMemBuf_free(&mbuf1);
+ ddocMemBuf_free(&mbuf2);
+ ddocMemBuf_free(&mbuf3);
+ //ddocMemBuf_free(&mbuf4);
+ //ddocMemBuf_free(&mbuf5);
+ }
+ }
+ if(fFind == FALSE)
+ pCert = NULL;
+ ddocMemBuf_free(&mbuf1);
+ ddocMemBuf_free(&mbuf2);
+ ddocMemBuf_free(&mbuf3);
+ //ddocMemBuf_free(&mbuf4);
+ //ddocMemBuf_free(&mbuf5);
+ return pSCert;
+}
+
+//----------------------------------------------------
+// Returns a list of certificates based on the
+// search criteria
+// szCN - CN of certs to search for
+// tValid - check validity on the given date (if not 0)
+// szSerialNr - serach for certs with this serial nr
+// pMBuf - public key hash to search
+//----------------------------------------------------
+X509 **Digi_FindCACerts(StoreHandle *hStore, const char* szCN, time_t tValid,
+ const char* szSerialNr, DigiDocMemBuf* pMBuf)
+{
+ int iMaxCerts = 512;
+ int iRes = 0, l1, l2;
+ X509 **caCerts = NULL;
+ X509 *poX509;
+ PCCERT_CONTEXT pCert = NULL;
+ BOOL fAdd;
+ char buf1[255], buf2[100];
+ DigiDocMemBuf mbuf1;
+
+ mbuf1.pMem = 0;
+ mbuf1.nLen = 0;
+ //ddocDebug(3, "Digi_FindCACerts", "CN: %s tValid: %ld serial: %s,
+ // open CA store
+ if(!hStore) return NULL;
+ Digi_CloseStore(hStore);
+ hStore->hHandle = CertOpenStore(CERT_STORE_PROV_SYSTEM,0,(HCRYPTPROV)NULL,
+ CERT_SYSTEM_STORE_CURRENT_USER | CERT_STORE_READONLY_FLAG,L"CA");
+ if (hStore->hHandle == NULL) {
+ return NULL;
+ }
+
+ // alloc list and initalize all positions to NULL
+ caCerts = (X509**)malloc(sizeof(void*) * (iMaxCerts+1));
+ if(caCerts == NULL) {
+ return(caCerts);
+ }
+ memset(caCerts,0,sizeof(void*) * (iMaxCerts+1));
+
+
+ if(hStore->hHandle != NULL) {
+ while(pCert= CertEnumCertificatesInStore(hStore->hHandle, pCert)) {
+ fAdd = FALSE;
+ ddocDecodeX509Data(&poX509,pCert->pbCertEncoded,pCert->cbCertEncoded);
+ if(poX509 != NULL) {
+ // check CN
+ if(szCN) {
+ buf1[0] = 0;
+ X509_NAME_get_text_by_NID(X509_get_subject_name(poX509), NID_commonName, buf1, sizeof(buf1));
+ fAdd = Digi_CompareCN((char*)szCN, buf1);
+ }
+ // check serial nr
+ if(szSerialNr) {
+ buf1[0] = 0;
+ ReadCertSerialNumber(buf1, sizeof(buf1)-1, poX509);
+ fAdd = !strcmp(szSerialNr, (const char*)buf1);
+ }
+ // check pubkey hash
+ if(pMBuf) {
+ ddocCertGetPubkeyDigest(poX509, &mbuf1);
+ l1 = sizeof(buf1);
+ l2 = sizeof(buf2);
+ bin2hex((const byte*)mbuf1.pMem, mbuf1.nLen, buf1, &l1);
+ bin2hex((const byte*)pMBuf->pMem, pMBuf->nLen, buf2, &l2);
+ ddocDebug(3, "Digi_FindCACerts", "Compare cert-hash: %s with searched-hash %s", buf1, buf2);
+ fAdd = !ddocMemCompareMemBufs(&mbuf1, pMBuf);
+ ddocMemBuf_free(&mbuf1);
+ }
+ if(tValid)
+ fAdd = !isCertValid(poX509, tValid);
+ }
+ // if any of the conditiones matched then add cert to list
+ if (fAdd == TRUE) {
+ caCerts[iRes] = poX509;
+ ++iRes;
+ }
+ else
+ X509_free(poX509);
+ }
+ }
+ // if no certs found then free the array
+ caCerts[iRes] = NULL;
+ if(iRes == 0) {
+ free(caCerts);
+ caCerts = NULL;
+ }
+ return(caCerts);
+}
+
+
+X509 **Digi_MakeCertList(X509 *poX509Main, StoreHandle *hStore)
+{
+X509 **caCerts = NULL;
+memset(hStore,0,sizeof(StoreHandle));
+hStore->hHandle = CertOpenStore(CERT_STORE_PROV_SYSTEM,0,(HCRYPTPROV)NULL,
+ CERT_SYSTEM_STORE_CURRENT_USER | CERT_STORE_READONLY_FLAG,L"CA");
+if (hStore->hHandle != NULL)
+ {
+ caCerts = Digi_MakeCertListLow(poX509Main, hStore);
+ if (caCerts == NULL)
+ {
+ CertCloseStore(hStore->hHandle,CERT_CLOSE_STORE_FORCE_FLAG);
+ hStore->hHandle = CertOpenStore(CERT_STORE_PROV_SYSTEM,0,(HCRYPTPROV)NULL,
+ CERT_SYSTEM_STORE_CURRENT_USER | CERT_STORE_READONLY_FLAG,L"ROOT");
+ if (hStore->hHandle != NULL)
+ {
+ hStore->fRoot = TRUE;
+ caCerts = Digi_MakeCertListLow(poX509Main, hStore);
+ }
+ }
+ }
+return(caCerts);
+}
+
+
+X509 **Digi_MakeCertListLow(X509 *poX509Main, StoreHandle *hStore)
+{
+int iMaxCerts = 512;
+int iRes = 0;
+X509 **caCerts = NULL;
+X509 *poX509;
+PCCERT_CONTEXT pCert = NULL;
+BOOL fAdd;
+if (poX509Main == NULL)
+ return(caCerts);
+caCerts = (X509**)malloc(sizeof(void*) * (iMaxCerts+1));
+if (caCerts == NULL)
+ return(caCerts);
+memset(caCerts,0,sizeof(void*) * (iMaxCerts+1));
+
+if (hStore->hHandle != NULL)
+ {
+ while( pCert= CertEnumCertificatesInStore( hStore->hHandle,pCert))
+ {
+ fAdd = FALSE;
+ ddocDecodeX509Data(&poX509,pCert->pbCertEncoded,pCert->cbCertEncoded);
+ //TEST
+ //Test_ReadCertData(poX509);
+ //ENDTEST
+ if (poX509 != NULL)
+ fAdd = Digi_IsCert1SubjectDNEqualCert2IssuerDN(poX509,poX509Main);
+ if (fAdd == TRUE)
+ {
+ caCerts[iRes] = poX509;
+ ++iRes;
+ }
+ else
+ X509_free(poX509);
+ }
+ }
+//Added by AA 2004/03/15
+caCerts[iRes] = NULL;
+if (iRes == 0)
+ {
+ free(caCerts);
+ caCerts = NULL;
+ }
+return(caCerts);
+}
+
+
+X509* Digi_FindDirectCA(X509 *poX509Main, StoreHandle *hStore)
+{
+ X509 *poX509;
+ PCCERT_CONTEXT pCert = NULL;
+
+ if (poX509Main == NULL)
+ return NULL;
+
+ if (hStore->hHandle != NULL) {
+ while(pCert = CertEnumCertificatesInStore( hStore->hHandle, pCert)) {
+ ddocDecodeX509Data(&poX509,pCert->pbCertEncoded,pCert->cbCertEncoded);
+ if(poX509 != NULL) {
+ if(Digi_IsCert1SubjectDNEqualCert2IssuerDN(poX509, poX509Main)) {
+ return poX509;
+ }
+ }
+ else
+ X509_free(poX509);
+ }
+ }
+ return NULL;
+}
+
+void Digi_FreeCertList(X509 **caCerts)
+{
+int iMaxCerts = 512;
+int i;
+if (caCerts != NULL)
+ {
+ for(i = 0; i < iMaxCerts; i++)
+ {
+ if(caCerts[i] != NULL)
+ X509_free(caCerts[i]);
+ }
+ free(caCerts);
+ }
+}
+
+
+BOOL Digi_CompareCN(char *psSub1, char *psSub2)
+{
+ BOOL fRes = FALSE;
+ if (psSub1 != NULL && psSub2 != NULL )
+ {
+ if (strlen(psSub1) > 0 || strlen(psSub2) > 0)
+ {
+ if (strcmp(psSub1,psSub2) == 0)
+ fRes = TRUE;
+ }
+ }
+ return(fRes);
+}
+
+
+int countCerts(const X509** certs)
+{
+ int i = 0;
+ while(certs && certs[i])
+ i++;
+ return i;
+}
+
+BOOL Digi_IsCert1SubjectDNEqualCert2IssuerDN(X509 *pCert1, X509 *pCert2)
+{
+BOOL fEqual = FALSE;
+unsigned long ulHash1;
+unsigned long ulHash2;
+ulHash1 = X509_subject_name_hash(pCert1);
+ulHash2 = X509_issuer_name_hash(pCert2);
+if (ulHash1 == ulHash2)
+ fEqual = TRUE;
+return(fEqual);
+}
+
+
+//29/09/2003
+//31/05/2006 - (g_current_TSAProfile->g_bAddTimeStamp) enables timestamping
+int Digi_getConfirmationWithCertSearch(SignedDoc* pSigDoc, SignatureInfo* pSigInfo,
+ char* pkcs12File, char *password,
+ char* notaryURL, char* proxyHost, char* proxyPort)
+{
+ int err = ERR_OK, err2 = ERR_OK, i, l1;
+ StoreHandle hStore;
+ NotaryInfo* pNotInf = NULL;
+ X509 *pNotCert = NULL, *pNotCertFound = NULL, *pSigCa = 0;
+ X509 **caCerts = NULL;
+ X509 **respCerts = NULL;
+ const DigiDocMemBuf *pMBuf = 0;
+ char szCN[255], buf1[100];
+
+ // set default values from config file
+ if(ConfigItem_lookup_bool("SIGN_OCSP", 1)) {
+ if(!pkcs12File || !strlen(pkcs12File))
+ pkcs12File = (char*)ConfigItem_lookup("DIGIDOC_PKCS_FILE");
+ if(!password || !strlen(password))
+ password = (char*)ConfigItem_lookup("DIGIDOC_PKCS_PASSWD");
+ }
+ if(!notaryURL || !strlen(notaryURL))
+ notaryURL = (char*)ConfigItem_lookup("DIGIDOC_OCSP_URL");
+ if(ConfigItem_lookup_bool("USE_PROXY", 1)) {
+ proxyHost = (char*)ConfigItem_lookup("DIGIDOC_PROXY_HOST");
+ RETURN_IF_NOT(proxyHost, ERR_WRONG_URL_OR_PROXY);
+ proxyPort = (char*)ConfigItem_lookup("DIGIDOC_PROXY_PORT");
+ RETURN_IF_NOT(proxyPort, ERR_WRONG_URL_OR_PROXY);
+ }
+ if (Digi_OpenStore(&hStore) == FALSE)
+ SET_LAST_ERROR_RETURN_CODE(ERR_CERT_STORE_READ);
+ // we need to find some CA-s of signer before asking for
+ // confirmation in order to be able to construct certid
+ // we need this because of users direct CA
+ respCerts = Digi_MakeCertListLow(ddocSigInfo_GetSignersCert(pSigInfo), &hStore);
+ if(respCerts) {
+ for(i = 0; respCerts[i]; i++) // find lowest (middle) ca - direct ca of signers cert
+ pSigCa = respCerts[i];
+ }
+ // VS: ver 1.5.33 - make this decision lower if confirmation can still be retrieved
+ //if(!respCerts) SET_LAST_ERROR_RETURN_CODE(ERR_SIGNERS_CERT_NOT_TRUSTED);
+ err = getConfirmation(pSigDoc, pSigInfo, respCerts, NULL,
+ pkcs12File, password,
+ notaryURL, proxyHost, proxyPort);
+ //Digi_FreeCertList(respCerts);
+ if(respCerts) {
+ for(i = 0; respCerts[i]; i++) {
+ if(respCerts[i] && respCerts[i] != pSigCa) {
+ X509_free(respCerts[i]);
+ respCerts[i] = 0;
+ }
+ }
+ }
+ if(err) return err;
+ pNotInf = pSigInfo->pNotary;
+ pMBuf = ddocNotInfo_GetResponderId(pNotInf);
+ RETURN_IF_NOT(pMBuf != NULL, ERR_NOTARY_SIG_MATCH);
+ if(pNotInf->nRespIdType == RESPID_NAME_TYPE) {
+ szCN[0] = 0;
+ if(pMBuf && pMBuf->pMem)
+ findCN((char*)pMBuf->pMem, szCN, sizeof(szCN));
+ pMBuf = NULL; // don't look for pubkey hash
+ ddocDebug(3, "Digi_getConfirmationWithCertSearch", "Find OCSP resp CA-s by key %s", szCN);
+ } else if(pNotInf->nRespIdType == RESPID_KEY_TYPE) {
+ // look for pubkey hash in Digi_FindCACerts
+ pMBuf = &(pNotInf->mbufRespId);
+ szCN[0] = 0;
+ l1 = sizeof(buf1);
+ bin2hex((const byte*)pNotInf->mbufRespId.pMem, pNotInf->mbufRespId.nLen, buf1, &l1);
+ ddocDebug(3, "Digi_getConfirmationWithCertSearch", "Find OCSP resp CA-s by hash %s", buf1);
+ }
+
+
+ RETURN_IF_NOT(pNotInf != NULL, ERR_NOTARY_SIG_MATCH);
+ // find a list of potential responder certificates
+ // search only by responder id = CN. Should I check also validity on current time ?
+ respCerts = Digi_FindCACerts(&hStore, (szCN[0] ? szCN : NULL), 0, 0, (DigiDocMemBuf*)pMBuf);
+ clearErrors();
+
+ if(!err && respCerts) {
+ i = 0;
+ do {
+ pNotCert = respCerts[i];
+ // get the next potential notary cert
+ if(pNotCert) {
+ // find CA certs for it
+ Digi_CloseStore(&hStore);
+ caCerts = Digi_MakeCertList(pNotCert, &hStore);
+
+ if (caCerts != NULL) {
+ err2 = finalizeAndVerifyNotary2(pSigDoc, pSigInfo, pNotInf, (const X509**)caCerts, (const X509*)pNotCert, pSigCa);
+ // if this didn't verify then free the cert and mark the slot as freed
+ if(err2) {
+ // remove certid and certvalue created for verification
+ removeNotaryInfoCert(pSigInfo);
+ // mark slot as freed (was done above)
+ respCerts[i] = 0;
+ }
+ // found one cert, save it for later
+ if(!err2) {
+ // if one cert was already found
+ // then pick the freshes one - one were not-after-date is latest
+ if(pNotCertFound) {
+ if(getCertNotAfterTimeT(pNotCert) > getCertNotAfterTimeT(pNotCertFound)) {
+ // release older cert
+ X509_free(pNotCertFound);
+ pNotCertFound = pNotCert;
+ }
+ }
+ pNotCertFound = pNotCert;
+ }
+ // else don't free, give ownership to new Notary!
+ // mark the slot as freed
+ respCerts[i] = 0;
+ }
+ else {
+ err = ERR_CERT_STORE_READ;
+ //fprintf(hFile, "No CA-s found, err: %d\n", err);
+ }
+ // free CA certs
+ Digi_FreeCertList(caCerts);
+ }
+ i++;
+ } while(pNotCert);
+ // free the remaining responder certs
+ Digi_FreeCertList(respCerts);
+ }
+
+ // else clear verifying errors
+ clearErrors();
+ // final check with the selected responders certificate
+ if(pNotCertFound) {
+ Digi_CloseStore(&hStore);
+ caCerts = Digi_MakeCertList(pNotCertFound, &hStore);
+ err = finalizeAndVerifyNotary2(pSigDoc, pSigInfo, pNotInf, (const X509**)caCerts, (const X509*)pNotCertFound, pSigCa);
+ Digi_FreeCertList(caCerts);
+ }
+ else
+ err = ERR_OCSP_CERT_NOTFOUND;
+ //fprintf(hFile, "OCSP finalize RC: %d\n", err);
+ // reset original signature content
+ if(pSigInfo->mbufOrigContent.pMem)
+ ddocMemBuf_free(&(pSigInfo->mbufOrigContent));
+ Digi_CloseStore(&hStore);
+ if(err != ERR_OK)
+ SET_LAST_ERROR(err);
+ return(err);
+}
+
+//--------------------------------------------------
+// Verfies NotaryInfo signature
+// pSigDoc - signed doc object
+// pNotInfo - NotaryInfo object
+// caFiles - array of CA file names terminated with NULL
+// CApath - path to (directory) all certs
+// notCertFile - Notary (e.g. OCSP responder) cert file
+//--------------------------------------------------
+int Digi_verifyNotaryInfoWithCertSearch(const SignedDoc* pSigDoc, const NotaryInfo* pNotInfo)
+{
+ X509** caCerts = NULL;
+ X509* notCert = NULL;
+ X509* cert = NULL, *pSigCA = NULL, *pSigCert = NULL;
+ StoreHandle hStore;
+ SignatureInfo *pSigInfo = NULL;
+ int err = ERR_OK;
+
+ if(pNotInfo)
+ pSigInfo = ddocGetSignatureForNotary(pSigDoc, pNotInfo);
+ if(pSigInfo != NULL) {
+ cert = ddocSigInfo_GetOCSPRespondersCert(pSigInfo);
+ }
+ caCerts = Digi_MakeCertList(cert,&hStore);
+ if(caCerts == NULL)
+ SET_LAST_ERROR_RETURN_CODE(ERR_CERT_STORE_READ);
+ //siin leitakse responderi cert vastavalt kirjeldusele
+ //notCert = Digi_FindResponderCert(&hStore,cert);
+ //08.03.2005 leitakse responderi koopia win certstoorest
+ if(!err) {
+ notCert = Digi_FindX509CopyFromStore(&hStore,cert);
+ pSigCert = ddocSigInfo_GetSignersCert(pSigInfo);
+ pSigCA = Digi_FindDirectCA(pSigCert, &hStore);
+ if((!notCert || !pSigCA) && hStore.fRoot == 1) { // try also CA store
+ Digi_CloseStore(&hStore);
+ memset(&hStore,0,sizeof(StoreHandle));
+ hStore.hHandle = CertOpenStore(CERT_STORE_PROV_SYSTEM,0,(HCRYPTPROV)NULL,
+ CERT_SYSTEM_STORE_CURRENT_USER | CERT_STORE_READONLY_FLAG,L"CA");
+ if(!notCert)
+ notCert = Digi_FindX509CopyFromStore(&hStore,cert);
+ if(!pSigCA)
+ pSigCA = Digi_FindDirectCA(pSigCert, &hStore);
+ }
+ if (notCert)
+ err = Digi_verifyNotaryInfoCERT(pSigDoc, pNotInfo, (const X509**)caCerts, notCert, pSigCA);
+ else
+ err = ERR_OCSP_CERT_NOTFOUND;
+ }
+ Digi_CloseStore(&hStore);
+ Digi_FreeCertList(caCerts);
+ //AM 23.05.08 where notCert is freed?
+ if(notCert)
+ X509_free(notCert);
+ if(pSigCA)
+ X509_free(pSigCA);
+ if (err != ERR_OK) SET_LAST_ERROR(err);
+ return err;
+}
+
+//============================================================
+// Verifies the whole document, but returns on first error
+// Use the functions defined earlier to verify all contents
+// step by step.
+// pSigDoc - signed doc data
+//
+//============================================================
+int Digi_verifySigDocWithCertSearch(const SignedDoc* pSigDoc, const char* szDataFile)
+
+{
+ SignatureInfo* pSigInfo;
+ NotaryInfo* pNotInfo;
+ int i, d, err = ERR_OK;
+
+ RETURN_IF_NULL(pSigDoc);
+ //assert(pSigDoc);
+ d = getCountOfSignatures(pSigDoc);
+ for(i = 0; i < d; i++) {
+ pSigInfo = getSignature(pSigDoc, i);
+ err = Digi_verifySignatureInfo(pSigDoc, pSigInfo, szDataFile);
+ RETURN_IF_NOT(err == ERR_OK, err);
+ pNotInfo = pSigInfo->pNotary;
+ err = Digi_verifyNotaryInfoWithCertSearch(pSigDoc, pNotInfo);
+ RETURN_IF_NOT(err == ERR_OK, err);
+ }
+ return err;
+}
+
+
+//--------------------------------------------------
+// Reads a certificate from pkcs12 conteiner
+//--------------------------------------------------
+// AA 18/09/2003
+EXP_OPTION int Digi_readCertificateByPKCS12OnlyCertHandle(const char *pkcs12file, const char * passwd, X509 **x509)
+{
+ int err = ERR_OK;
+ EVP_PKEY *pkey;
+ // VS: 26.01.2010 - initialize
+ (*x509) = 0;
+ //AM 16.09.08 DigiDocClient calling it with empty strings even ocsp request signing is off
+ if(!strcmp(pkcs12file, ""))
+ return ERR_OK;
+ err = ReadCertificateByPKCS12(x509,pkcs12file,passwd,&pkey);
+ //AM 22.05.08 pKey should be freed
+ if(err == 0 && pkey)
+ EVP_PKEY_free(pkey);
+ RETURN_IF_NOT(err == ERR_OK, err);
+ return ERR_OK;
+}
+
+//============================================================
+// Verifies this signature
+// pSigDoc - signed doc data
+// pSigInfo - signature info object
+// signerCA - direct signer CA certs filename
+// szDateFile - name of the digidoc file
+// bUseCA - use CA certs or not 1/0
+// from original file and use it for hash function.
+// This is usefull if the file has been generated by
+// another library and possibly formats these elements
+// differently.
+//============================================================
+int Digi_verifySignatureInfo(const SignedDoc* pSigDoc, const SignatureInfo* pSigInfo, const char* szDataFile)
+{
+ char buf2[100], *p1 = 0;
+ X509* pCaCert = 0;
+ int err = ERR_OK, k = 0;
+ StoreHandle hStore;
+ DigiDocMemBuf mbuf1;
+
+ mbuf1.pMem = 0;
+ mbuf1.nLen = 0;
+ buf2[0] = 0;
+ if(!Digi_OpenStore(&hStore))
+ return ERR_CERT_STORE_READ;
+ //p1 = ddocSigInfo_GetSignersCert_IssuerName(pSigInfo);
+ p1 = (char*)ddocSigInfo_GetSignersCert_IssuerNameAndHash(pSigInfo, &mbuf1);
+ //strncpy(buf1, ddocSigInfo_GetSignersCert_IssuerName(pSigInfo), sizeof(buf1));
+ if(p1)
+ findCN((char*)p1, buf2, sizeof(buf2));
+ pCaCert = Digi_FindCertBySubjectAndHash(&hStore, buf2, FALSE, 0, TRUE, &mbuf1);
+ if(!pCaCert) {
+ ddocDebug(1, "Digi_verifySignatureInfo", "ERR112 cert: %s", buf2);
+ //AM 02.03.09 teadmata olek kui leia CA serti
+ return ERR_UNKNOWN_CA;
+ }
+ err = verifySignatureInfoCERT(pSigDoc, pSigInfo, pCaCert,
+ szDataFile, (pCaCert != NULL));
+ if(pCaCert)
+ X509_free(pCaCert);
+ Digi_CloseStore(&hStore);
+ ddocMemBuf_free(&mbuf1);
+ if((k = getCountOfSignerRoles(pSigInfo, 0)) > 1) {
+ ddocDebug(1, "Digi_verifySignatureInfo", "Number of roles: %d, Currently supports max 1 roles", k);
+ SET_LAST_ERROR(ERR_MAX_1_ROLES);
+ err = ERR_MAX_1_ROLES;
+ }
+ return err;
+}
+
+
+//============================================================
+// Verifies the whole document, but returns on first error
+// Use the functions defined earlier to verify all contents
+// step by step.
+// pSigDoc - signed doc data
+//
+//============================================================
+
+int Digi_verifySigDoc(const SignedDoc* pSigDoc, const char* szDataFile)
+
+{
+ SignatureInfo* pSigInfo;
+ NotaryInfo* pNotInfo;
+ int i, d, err = ERR_OK;
+
+ RETURN_IF_NULL_PARAM(pSigDoc);
+ //assert(pSigDoc);
+ d = getCountOfSignatures(pSigDoc);
+ for(i = 0; i < d; i++) {
+ pSigInfo = getSignature(pSigDoc, i);
+ err = Digi_verifySignatureInfo(pSigDoc, pSigInfo, szDataFile);
+ RETURN_IF_NOT(err == ERR_OK, err);
+ }
+ d = getCountOfNotaryInfos(pSigDoc);
+ for(i = 0;i < d; i++) {
+ pNotInfo = getNotaryInfo(pSigDoc, i);
+ err = Digi_verifyNotaryInfoWithCertSearch(pSigDoc, pNotInfo);
+ RETURN_IF_NOT(err == ERR_OK, err);
+ }
+ return ERR_OK;
+}
+
+
+//--------------------------------------------------
+// Verfies NotaryInfo signature
+// pSigDoc - signed doc object
+// pNotInfo - NotaryInfo object
+// caCerts - CA certificate pointer array terminated with NULL
+// CApath - path to (directory) all certs
+// notCertFile - Notary (e.g. OCSP responder) cert file
+//--------------------------------------------------
+int Digi_verifyNotaryInfoCERT(const SignedDoc* pSigDoc,
+ const NotaryInfo* pNotInfo,
+ const X509** caCerts,
+ const X509* notCert,
+ const X509* pSigCA)
+{
+ SignatureInfo* pSigInfo = NULL;
+ pSigInfo = ddocGetSignatureForNotary(pSigDoc, pNotInfo);
+ RETURN_IF_NOT(pSigInfo != NULL, ERR_NOTARY_NO_SIGNATURE);
+ return verifyNotaryInfoCERT2(pSigDoc, pSigInfo, pNotInfo, caCerts, 0, notCert, pSigCA);
+}
+
+
+//====================================================================
+// Finds issuer certificate of given certificate
+// returns NULL if not found or any error occures
+// The stores "My","CA" and "Root" will be scanned.
+//====================================================================
+EXP_OPTION X509 * findIssuerCertificatefromMsStore(X509 *x509){
+ return findIssuerCertificatefromStore(x509);
+
+}
+
+//Functions from EstIDLib.c
+
+
+//============================================================
+// Calculates and stores a signature for this SignatureInfo object
+// Uses EstEID card as CSP to sign the info
+// pSigInfo - signature info object
+//============================================================
+EXP_OPTION int calculateSigInfoSignatureWithCSPEstID(SignedDoc* pSigDoc, SignatureInfo* pSigInfo, int iByKeyContainer, const char* szPin)
+{
+ int err = ERR_OK, l1;
+ PCCERT_CONTEXT pCert;
+ char buf1[300];
+ unsigned long sigLen;
+ int digLen, len=0;
+ char sigDig[300],signature[2084], *p1;
+ char *psKeyName = NULL;
+ char *psCSPName = NULL;
+ //long tmpSerial;
+ //HCRYPTPROV hProvider;
+ DWORD dwRes;
+ X509 *pX509;
+ DigiDocMemBuf *pMBuf1;
+
+ ddocDebug(3, "calculateSigInfoSignatureWithCSPEstID", "Sign id: %s", pSigInfo->szId);
+ pCert = DigiCrypt_FindContext((BOOL) iByKeyContainer, &dwRes);
+ if(pCert == NULL) {
+ if (dwRes == dDigiCrypt_Error_NotFoundCSP)
+ err = ERR_CSP_NO_CARD_DATA;
+ if(dwRes == dDigiCrypt_Error_UserCancel)
+ err = ERR_CSP_USER_CANCEL;
+ if (dwRes == dDigiCrypt_Error_NoDefaultKey)
+ err = ERR_CSP_NODEFKEY_CONTAINER;
+ if (dwRes == dDIgiCrypt_Error_NotFoundCert)
+ err = ERR_CSP_CERT_FOUND;
+
+ SET_LAST_ERROR_RETURN_CODE(err);
+ }
+ psKeyName = DigiCrypt_FindContext_GetKeyName();
+ psCSPName = DigiCrypt_FindContext_GetCSPName();
+ //AA100204
+ ddocDecodeX509Data(&pX509,pCert->pbCertEncoded,pCert->cbCertEncoded);
+ err = setSignatureCert(pSigInfo, pX509);
+ RETURN_IF_NOT(err == ERR_OK, err);
+ //AA-Viimase minuti jama
+ createTimestamp(pSigDoc, sigDig, sizeof(sigDig));
+ setString(&(pSigInfo->szTimeStamp), sigDig, -1);
+ // Signed properties digest
+ // now calculate signed properties digest
+ err = calculateSignedPropertiesDigest(pSigDoc, pSigInfo);
+ // TODO: replace later
+ pMBuf1 = ddocDigestValue_GetDigestValue(pSigInfo->pSigPropDigest);
+ ddocSigInfo_SetSigPropRealDigest(pSigInfo, (const char*)pMBuf1->pMem, pMBuf1->nLen);
+ // signature type & val
+ ddocSignatureValue_new(&(pSigInfo->pSigValue), 0, SIGN_RSA_NAME, 0, 0);
+ // calc signed-info digest
+ l1 = sizeof(buf1);
+ err = calculateSignedInfoDigest(pSigDoc, pSigInfo, (byte*)buf1, &l1);
+ err = ddocSigInfo_SetSigInfoRealDigest(pSigInfo, buf1, l1);
+ sigLen = sizeof(signature);
+ memset(signature, 0, sizeof(signature));
+ p1 = createXMLSignedInfo(pSigDoc, pSigInfo);
+ len = strlen(p1);
+
+ // sign the <SignedInfo> hash with CSP
+ digLen = sizeof(sigDig);
+ err = GetSignedHashWithKeyAndCSP(psKeyName,psCSPName, p1, len, NULL, NULL, sigDig, &digLen,&signature[0],&sigLen,szPin);
+ if(p1)
+ free(p1);
+ RETURN_IF_NOT(err == ERR_OK, err);
+ // set signature value
+ ddocSigInfo_SetSignatureValue(pSigInfo, signature, (int)sigLen);
+ ddocDebug(3, "calculateSigInfoSignatureWithCSPEstID", "End signing Sign id: %s, rc: %d", pSigInfo->szId, err);
+ return ERR_OK;
+}
+
+
+
+X509* findCertificate(const CertSearch * cS){
+ //debugPrint("findCertificate");
+ X509* poCert = NULL;
+ if(cS==NULL){
+ return NULL;
+ }else if(cS->searchType==CERT_SEARCH_BY_X509){
+ ReadCertificate(&poCert,cS->x509FileName);
+ return(poCert);
+ }else if(cS->searchType==CERT_SEARCH_BY_PKCS12){
+ X509 * x509=NULL;
+ EVP_PKEY * pKey=NULL;
+ int err=0;
+ err=ReadCertificateByPKCS12(&x509,cS->pkcs12FileName,cS->pswd,&pKey);
+ EVP_PKEY_free(pKey);
+ if(err==ERR_OK){
+ return x509;
+ }else{
+ SET_LAST_ERROR(err);
+ return NULL;
+ }
+ }else if(cS->searchType==CERT_SEARCH_BY_STORE){
+ #ifdef WIN32_CSP
+ X509 * x509=NULL;
+ int err=0;
+ RETURN_OBJ_IF_NULL(cS->certSearchStore, NULL);
+ err=GetCertificateFromStore(cS->certSearchStore,&x509);
+ //debugPrint("return from findCertificate (MS Store)");
+ if(err==ERR_OK){
+ return x509;
+ }else{
+ SET_LAST_ERROR(err);
+ return NULL;
+ }
+ #else
+ return NULL;
+ #endif
+ }else{
+ return NULL;
+ }
+}
+
+EXP_OPTION int findAllCertificates(const CertSearchStore *sS, X509 ***certsArray, int *numberOfCerts){
+ #ifdef WIN32_CSP
+ int rc=0,i;
+ X509 **array;
+ CertItem *certItem, *certItem2;
+ rc=GetAllCertificatesFromStore(sS,&certItem,numberOfCerts);
+ if(rc==ERR_OK){
+ array=malloc(sizeof(X509*)*(*numberOfCerts));
+ RETURN_IF_BAD_ALLOC(array);
+ for(i=0;i< *numberOfCerts ;i++){
+ array[i]=certItem->pCert;
+ certItem2=certItem;
+ certItem=certItem->nextItem;
+ free(certItem2);
+ }
+ *certsArray=array;
+ }
+ if (rc != ERR_OK) SET_LAST_ERROR(rc);
+ return rc;
+ #else
+ SET_LAST_ERROR_RETURN_CODE(ERR_UNSUPPORTED_CERT_SEARCH);
+ #endif // WIN32_CSP
+}
+
+/***********************************************************************/
+//=========================================================================
+// Returns pointer to current CSP. If current CSP was not initialized (i.e
+// NULL ) and input parameter is TRUE then active CSP is asked from
+// function getActiveProvider() and if CSP is "EST ID CSP" then
+// signature flag in CSP structure will turned to true
+//=========================================================================
+EXP_OPTION CSProvider * getCurrentCSProvider(BOOL tryToFindIfMissing){
+ if(tryToFindIfMissing==FALSE){
+ return cCSProvider;
+ }
+ // so tryToFindIfMissing was true, we need to find out if not found yet
+ if(cCSProvider==NULL ){
+ //cCSProvider=getActiveProvider();
+ if(cCSProvider!=NULL){
+ if(strcmp(cCSProvider->CSPName,EST_EID_CSP)==0)
+ cCSProvider->at_sig=TRUE;
+ else
+ cCSProvider->at_sig=FALSE;
+ }
+ }
+ return cCSProvider;
+
+}
+EXP_OPTION void setCurrentCSProvider(CSProvider * newProvider){
+ cCSProvider=newProvider;
+}
+
+
+
+//=====================================================
+EXP_OPTION CertSearchStore* CertSearchStore_new()
+{
+ CertSearchStore* certSearch;
+ certSearch=(CertSearchStore*)malloc(sizeof(CertSearchStore));
+ memset(certSearch, 0, sizeof(CertSearchStore));
+ return certSearch;
+}
+
+EXP_OPTION void CertSearchStore_free(CertSearchStore* certSearchStore){
+ int i=0;
+ RETURN_VOID_IF_NULL(certSearchStore);
+ if (certSearchStore->subDNCriterias) {
+ for(; i < certSearchStore->numberOfSubDNCriterias ; i++ ){
+ if(certSearchStore->subDNCriterias[i] != NULL){
+ free(certSearchStore->subDNCriterias[i]);
+ }
+ }
+ free(certSearchStore->subDNCriterias);
+ }
+ certSearchStore->numberOfSubDNCriterias=0;
+ if (certSearchStore->issDNCriterias) {
+ for(; i < certSearchStore->numberOfIssDNCriterias ; i++ ){
+ if(certSearchStore->issDNCriterias[i] != NULL){
+ free(certSearchStore->issDNCriterias[i]);
+ }
+ }
+ free(certSearchStore->issDNCriterias);
+ }
+ certSearchStore->numberOfIssDNCriterias=0;
+ if(certSearchStore->storeName != NULL){
+ free(certSearchStore->storeName);
+ }
+ if(certSearchStore->publicKeyInfo){
+ free(certSearchStore->publicKeyInfo);
+ }
+ free(certSearchStore);
+ certSearchStore=NULL;
+}
+
+
+EXP_OPTION CertSearch* CertSearch_new(){
+ CertSearch* certSearch;
+ certSearch=(CertSearch*)malloc(sizeof(CertSearch));
+ memset(certSearch, 0, sizeof(CertSearch));
+ return certSearch;
+}
+
+EXP_OPTION void CertSearch_free(CertSearch* certSearch){
+ if(certSearch->certSearchStore != NULL){
+ CertSearchStore_free(certSearch->certSearchStore);
+ }
+ if(certSearch->pkcs12FileName != NULL){
+ free(certSearch->pkcs12FileName);
+ }
+ if(certSearch->pswd != NULL){
+ free(certSearch->pswd);
+ }
+ if(certSearch->x509FileName != NULL){
+ free(certSearch->x509FileName);
+ }
+ if(certSearch->keyFileName != NULL){
+ free(certSearch->keyFileName);
+ }
+ free(certSearch);
+ certSearch=NULL;
+
+}
+
+EXP_OPTION void CertSearch_setX509FileName(CertSearch* certSearch, const char* str)
+{
+ if(certSearch && str) {
+ setString((char**)&certSearch->x509FileName, str, -1);
+ }
+}
+
+EXP_OPTION void CertSearch_setKeyFileName(CertSearch* certSearch, const char* str)
+{
+ if(certSearch && str) {
+ setString((char**)&certSearch->keyFileName, str, -1);
+ }
+}
+
+EXP_OPTION void CertSearch_setPkcs12FileName(CertSearch* certSearch, const char* str)
+{
+ if(certSearch && str) {
+ setString((char**)&certSearch->pkcs12FileName, str, -1);
+ }
+}
+
+EXP_OPTION void CertSearch_setPasswd(CertSearch* certSearch, const char* str)
+{
+ if(certSearch && str) {
+ setString((char**)&certSearch->pswd, str, -1);
+ }
+}
+
+
+
+// Frees cert handles and items in this list.
+// WARNING! when caller does not own the first cert in chain,
+// then pass pListStart->nextItem instead of pListStart itself.
+EXP_OPTION void CertList_free(CertItem* pListStart) {
+ if (pListStart) {
+ CertItem* pItem = pListStart;
+ CertItem* pTmp;
+ while (pItem) {
+ pTmp = pItem->nextItem;
+ X509_free((X509*)pItem->pCert);
+ free(pItem);
+ pItem = pTmp;
+ }
+ }
+}
+
+//=====================================================================
+// reads certificate from system store
+// IN CertSearchStore *sS - search criterias
+// OUT x509 certificate
+//=====================================================================
+int GetAllCertificatesFromStore(const CertSearchStore *sS, CertItem ** certList, int *numberOfCerts)
+{
+ int retCode=ERR_OK;
+/*
+ int retCode1=ERR_UNSUPPORTED_CERT_SEARCH; // Unknown search type
+ int retCode2=ERR_CSP_OPEN_STORE; // Can not open system store
+ int retCode3=ERR_CSP_CERT_FOUND; // Certificate not found from store, probably cetificate not registered
+ int retCode4=ERR_INCORRECT_CERT_SEARCH; // search type Sub DN but mismatch of parameters
+ int retCode5=ERR_PKCS_CERT_DECODE;
+*/
+
+ int i=0,certCounter=0;
+ int initSize=10;
+ X509 *x509;
+ CertItem *certFirst,*certCurrent,*certIt;
+ BOOL certFound=FALSE;
+ BOOL useSerial=FALSE;
+ BOOL useSubDN=FALSE;
+ BOOL useIssDN=FALSE;
+ HCERTSTORE hCertStore = NULL;
+ PCCERT_CONTEXT pCert=NULL;
+ char defaultName[]="My";
+ char* storeName;
+ char buf[4000];
+ char buf1[4000];
+ long tmpSerial;
+ int err;
+ DigiDocMemBuf mbuf1;
+ mbuf1.pMem = 0;
+ mbuf1.nLen = 0;
+
+ RETURN_IF_NOT(numberOfCerts !=NULL, ERR_NULL_SER_NUM_POINTER);
+
+ if((sS->searchType&(CERT_STORE_SEARCH_BY_SERIAL|CERT_STORE_SEARCH_BY_SUBJECT_DN|CERT_STORE_SEARCH_BY_ISSUER_DN)) == 0)
+ SET_LAST_ERROR_RETURN_CODE(ERR_UNSUPPORTED_CERT_SEARCH);
+
+ if((sS->searchType&CERT_STORE_SEARCH_BY_SERIAL) != 0){
+ useSerial=TRUE;
+ }
+ if((sS->searchType&CERT_STORE_SEARCH_BY_SUBJECT_DN) != 0){
+ useSubDN=TRUE;
+ if(sS->numberOfSubDNCriterias<1)
+ SET_LAST_ERROR_RETURN_CODE(ERR_INCORRECT_CERT_SEARCH);
+ if (sS->subDNCriterias == NULL)
+ SET_LAST_ERROR_RETURN_CODE(ERR_INCORRECT_CERT_SEARCH);
+ for(i=0;i<sS->numberOfSubDNCriterias;i++){
+ if(sS->subDNCriterias[i]==NULL)
+ SET_LAST_ERROR_RETURN_CODE(ERR_INCORRECT_CERT_SEARCH);
+ }
+ }
+ if((sS->searchType&CERT_STORE_SEARCH_BY_ISSUER_DN) != 0){
+ useIssDN=TRUE;
+ if(sS->numberOfIssDNCriterias<1)
+ SET_LAST_ERROR_RETURN_CODE(ERR_INCORRECT_CERT_SEARCH);
+
+ if (sS->issDNCriterias == NULL)
+ SET_LAST_ERROR_RETURN_CODE(ERR_INCORRECT_CERT_SEARCH);
+ for(i=0;i<sS->numberOfIssDNCriterias;i++){
+ if(sS->issDNCriterias[i]==NULL)
+ SET_LAST_ERROR_RETURN_CODE(ERR_INCORRECT_CERT_SEARCH);
+ }
+ }
+ if(sS->storeName!=NULL){
+ storeName=sS->storeName;
+ }else{
+ storeName=defaultName;
+ }
+ certFirst = malloc(sizeof(CertItem));
+ RETURN_IF_BAD_ALLOC(certFirst);
+ // memset(certFirst,0,sizeof(certFirst)); <-- Andrus: fills with zeros only first 32 bits
+ memset(certFirst,0,sizeof(CertItem));
+ *certList=certFirst;
+ certCurrent=certFirst;
+ /////******************** start task ***********************************
+ while(TRUE){
+ hCertStore=CertOpenSystemStore(0,storeName);
+ if(!hCertStore){
+ retCode=ERR_CSP_OPEN_STORE;
+ SET_LAST_ERROR(retCode);
+ break;
+ }
+
+ while(TRUE){
+ pCert = CertEnumCertificatesInStore( hCertStore,pCert);
+ if(!pCert)
+ break;
+ //AA100204
+ ddocDecodeX509Data(&x509,pCert->pbCertEncoded,pCert->cbCertEncoded);
+ RETURN_IF_NOT(x509 != NULL, ERR_PKCS_CERT_DECODE);
+
+ // if serial is a criteria check it
+ if(useSerial){
+ //AA-viimase minuti jama
+ //ReadCertSerialNumber(&tmpSerial,x509);
+ ReadCertSerialNumber(buf,sizeof(buf),x509);
+ tmpSerial = atol(buf);
+ if(tmpSerial == sS->certSerial){
+ certFound=TRUE;
+ }else{
+ certFound=FALSE;
+ X509_free(x509);
+ continue;
+ }
+ }//if(useSerial){
+
+ // if issuer name is a criteria check it
+ if(useIssDN){
+ int len=0;
+ X509_NAME * x509name;
+ x509name = X509_get_issuer_name(x509);
+ len=sizeof(buf);
+ memset(buf,0,len);
+ memset(buf1,0,sizeof(buf1));
+
+ //AM 26.09.08
+ //X509_NAME_oneline(x509name,buf,len);
+ err = ddocCertGetIssuerDN(x509, &mbuf1);
+ RETURN_IF_NOT(err == ERR_OK, err);
+ len=strlen((char*)mbuf1.pMem);
+ prepareString((char*)mbuf1.pMem,buf1);
+ for(i=0;i<sS->numberOfIssDNCriterias;i++){
+ memset(buf,0,sizeof(buf));
+ prepareString(sS->issDNCriterias[i],buf);
+ if(strstr(buf1,buf)){
+ certFound=TRUE;
+ }else{
+ certFound=FALSE;
+ //X509_free(x509); <-- Andrus: free operation performed in the end of useIssDN block
+ break;
+ }
+ }
+ if(!certFound){
+ X509_free(x509);
+ continue;
+ }
+ }//if(useIssDN){
+
+ // if subject name is a criteria check it
+ if(useSubDN){
+ int len=0;
+ X509_NAME * x509name;
+ x509name = X509_get_subject_name(x509);
+ len=sizeof(buf);
+ memset(buf,0,len);
+ memset(buf1,0,sizeof(buf1));
+
+ //AM 26.09.08
+ //X509_NAME_oneline(x509name,buf,len);
+ err = ddocCertGetSubjectDN(x509, &mbuf1);
+ RETURN_IF_NOT(err == ERR_OK, err);
+ len=strlen((char*)mbuf1.pMem);
+ prepareString((char*)mbuf1.pMem,buf1);
+ for(i=0;i<sS->numberOfSubDNCriterias;i++){
+ memset(buf,0,sizeof(buf));
+ prepareString(sS->subDNCriterias[i],buf);
+ if(strstr(buf1,buf)){
+ certFound=TRUE;
+ }else{
+ certFound=FALSE;
+ break;
+ }
+ }
+ // did we find ?
+ if(!certFound){
+ X509_free(x509);
+ continue;
+ }
+ }//if(useSubDN){
+ ddocMemBuf_free(&mbuf1);
+ // did we find ?
+ if(certFound){
+ certCounter++;
+ if(certCounter==1){
+ certFirst->pCert=x509;
+ continue;
+ }
+ certIt = malloc(sizeof(CertItem));
+ RETURN_IF_BAD_ALLOC(certIt);
+ // memset(certIt,0,sizeof(certIt)); <-- Andrus: fills with zeros only first 32 bits
+ memset(certIt,0,sizeof(CertItem));
+ certIt->pCert=x509;
+ certCurrent->nextItem=certIt;
+ certCurrent=certIt;
+ }else{
+ X509_free(x509);
+ continue;
+ }
+ }//while(pCertt=CertEnumCertificatesInStore(hCertStore,pCert))
+ *numberOfCerts=certCounter;
+ if( certCounter<1 ){
+ retCode = ERR_CSP_CERT_FOUND;
+ SET_LAST_ERROR(retCode);
+ break;
+ }
+ break;
+ }//while(TRUE){
+ /////******************** close and free objects ***********************************
+ if(pCert) {CertFreeCertificateContext(pCert); }
+ if(hCertStore) {CertCloseStore(hCertStore,CERT_CLOSE_STORE_FORCE_FLAG);hCertStore=0;}
+ return retCode;
+ /////*******************************************************************************
+}
+//==========================================================
+// removes all spaces and tabs and makes all characters uppercase
+//==========================================================
+void prepareString(const char * strIN,char * strOUT){
+ int len=0;
+ int i=0;
+ int tempLen=0;
+ len=strlen(strIN);
+
+ if(len==0){
+ return;
+ }
+ for (;i<len ; i++) {
+ if((strIN[i] == ' ') || (strIN[i] == '\t')){
+ continue;
+ }else if( strIN[i]>0x60 && strIN[i]<0x7B ){
+ strOUT[tempLen++] = (strIN[i]-0x20);
+ }else {
+ strOUT[tempLen++] = strIN[i];
+ }
+ }
+}
+
+//=====================================================================
+// reads certificate from system store
+// IN CertSearchStore *sS - search criterias
+// OUT x509 certificate
+//=====================================================================
+int GetCertificateFromStore(const CertSearchStore *sS, X509 **cert){
+ int retCode=ERR_OK;
+ int retCode1=ERR_UNSUPPORTED_CERT_SEARCH; // Unknown search type
+ int retCode2=ERR_CSP_OPEN_STORE; // Can not open system store
+ int retCode3=ERR_CSP_CERT_FOUND; // Certificate not found from store, probably cetificate not registered
+ int retCode4=ERR_INCORRECT_CERT_SEARCH; // search type Sub DN but mismatch of parameters
+ int retCode5=ERR_PKCS_CERT_DECODE;
+
+ int i=0;
+ X509 *x509;
+ BOOL certFound=FALSE;
+ BOOL useKeyInfo=FALSE;
+ BOOL useSerial=FALSE;
+ BOOL useSubDN=FALSE;
+ BOOL useIssDN=FALSE;
+ HCERTSTORE hCertStore = NULL;
+ CERT_PUBLIC_KEY_INFO* pKeyInfo;
+ PCCERT_CONTEXT pCert=NULL;
+ char defaultName[]="My";
+ char* storeName;
+ char buf[3000];
+ char buf1[3000];
+ long tmpSerial;
+ int err=0;
+ DigiDocMemBuf mbuf1;
+ mbuf1.pMem = 0;
+ mbuf1.nLen = 0;
+ //---------------------------------
+ // TODO: it's just a test - remove it
+ //---------------------------------
+ /*
+ char* pSelArr[] = {"Good reader", "Better reader", "The best reader", NULL};
+ int iRes = runDigiDocDialogUnit(pSelArr, "Please select smartcard reader:");
+ if (iRes != -1) {
+ // handle picked element
+ char resultAsText[128];
+ //sprintf(resultAsText, "Selected item with index=%d", iRes);
+ MessageBox(NULL, resultAsText, "DigiDoc", MB_OK|MB_ICONEXCLAMATION);
+ } else {
+ // if possible, handle Cancel operation
+ }
+ */
+ //---------------------------------
+ // End of TODO
+ //---------------------------------
+ if((sS->searchType&(CERT_STORE_SEARCH_BY_SERIAL|CERT_STORE_SEARCH_BY_SUBJECT_DN|CERT_STORE_SEARCH_BY_ISSUER_DN|CERT_STORE_SEARCH_BY_KEY_INFO)) == 0)
+ SET_LAST_ERROR_RETURN_CODE(ERR_UNSUPPORTED_CERT_SEARCH);
+ if((sS->searchType&CERT_STORE_SEARCH_BY_KEY_INFO) != 0){
+ useKeyInfo=TRUE;
+ pKeyInfo=sS->publicKeyInfo;
+ if(pKeyInfo==NULL){
+ SET_LAST_ERROR_RETURN_CODE(ERR_INCORRECT_CERT_SEARCH);
+ }
+ }
+ if((sS->searchType&CERT_STORE_SEARCH_BY_SERIAL) != 0){
+ useSerial=TRUE;
+ }
+ if((sS->searchType&CERT_STORE_SEARCH_BY_SUBJECT_DN) != 0){
+ useSubDN=TRUE;
+ if(sS->numberOfSubDNCriterias<1)
+ SET_LAST_ERROR_RETURN_CODE(ERR_INCORRECT_CERT_SEARCH);
+ if (sS->subDNCriterias == NULL)
+ SET_LAST_ERROR_RETURN_CODE(ERR_INCORRECT_CERT_SEARCH);
+ for(i=0;i<sS->numberOfSubDNCriterias;i++){
+ if(sS->subDNCriterias[i]==NULL)
+ SET_LAST_ERROR_RETURN_CODE(ERR_INCORRECT_CERT_SEARCH);
+ }
+ }
+ if((sS->searchType&CERT_STORE_SEARCH_BY_ISSUER_DN) != 0){
+ useIssDN=TRUE;
+ if(sS->numberOfIssDNCriterias<1)
+ SET_LAST_ERROR_RETURN_CODE(ERR_INCORRECT_CERT_SEARCH);
+ if (sS->issDNCriterias == NULL)
+ SET_LAST_ERROR_RETURN_CODE(ERR_INCORRECT_CERT_SEARCH);
+ for(i=0;i<sS->numberOfIssDNCriterias;i++){
+ if(sS->issDNCriterias[i]==NULL)
+ SET_LAST_ERROR_RETURN_CODE(ERR_INCORRECT_CERT_SEARCH);
+ }
+ }
+ if(sS->storeName!=NULL){
+ storeName=sS->storeName;
+ }else{
+ storeName=&defaultName[0];
+ }
+ /////******************** start task ***********************************
+ while(TRUE){
+ hCertStore=CertOpenSystemStore(0,storeName);
+ if(!hCertStore){
+ retCode = ERR_CSP_OPEN_STORE;
+ SET_LAST_ERROR(retCode);
+ break;
+ }
+ if(useKeyInfo){
+ pCert=CertFindCertificateInStore(hCertStore,X509_ASN_ENCODING|PKCS_7_ASN_ENCODING,0,CERT_FIND_PUBLIC_KEY,pKeyInfo,NULL );
+ if(pCert){
+ //AA100204
+ ddocDecodeX509Data(&x509,pCert->pbCertEncoded,pCert->cbCertEncoded);
+ certFound=TRUE;
+ //memcpy(cert,x509,sizeof(x509));
+ //X509_free(x509);
+ *cert=x509;
+ break;
+ }
+ }//if(useSerial){
+ while( pCert= CertEnumCertificatesInStore( hCertStore,pCert)){
+ //AA100204
+ ddocDecodeX509Data(&x509,pCert->pbCertEncoded,pCert->cbCertEncoded);
+ RETURN_IF_NOT(x509 != NULL, ERR_PKCS_CERT_DECODE);
+ if(useSerial){
+ //AA-Viimase minuti jama
+ //ReadCertSerialNumber(&tmpSerial,x509);
+ ReadCertSerialNumber(buf,sizeof(buf),x509);
+ tmpSerial = atol(buf);
+ if(tmpSerial == sS->certSerial){
+ certFound=TRUE;
+ }else{
+ certFound=FALSE;
+ X509_free(x509);
+ continue;
+ }
+ }//if(useSerial){
+ if(useIssDN){
+ int len=0;
+ X509_NAME * x509name;
+ x509name = X509_get_issuer_name(x509);
+ len=sizeof(buf);
+ memset(buf,0,len);
+ memset(buf1,0,sizeof(buf1));
+
+ //AM 26.09.08
+ //X509_NAME_oneline(x509name,buf,len);
+ err = ddocCertGetIssuerDN(x509, &mbuf1);
+ RETURN_IF_NOT(err == ERR_OK, err);
+ len=strlen((char*)mbuf1.pMem);
+ prepareString((char*)mbuf1.pMem,buf1);
+
+ for(i=0;i<sS->numberOfIssDNCriterias;i++){
+ memset(buf,0,sizeof(buf));
+ prepareString(sS->issDNCriterias[i],buf);
+ if(strstr(buf1,buf)){
+ certFound=TRUE;
+ }else{
+ certFound=FALSE;
+ X509_free(x509);
+ break;
+ }
+ }
+ if(!certFound){
+ X509_free(x509);
+ continue;
+ }
+ }//if(useIssDN){
+
+ if(useSubDN){
+ int len=0;
+ X509_NAME * x509name;
+ x509name = X509_get_subject_name(x509);
+ len=sizeof(buf);
+ memset(buf,0,len);
+ memset(buf1,0,sizeof(buf1));
+
+ //AM 26.09.08
+ //X509_NAME_oneline(x509name,buf,len);
+ err = ddocCertGetSubjectDN(x509, &mbuf1);
+ RETURN_IF_NOT(err == ERR_OK, err);
+ len=strlen((char*)mbuf1.pMem);
+ prepareString((char*)mbuf1.pMem,buf1);
+
+ for(i=0;i<sS->numberOfSubDNCriterias;i++){
+ memset(buf,0,sizeof(buf));
+ prepareString(sS->subDNCriterias[i],buf);
+ if(strstr(buf1,buf)){
+ certFound=TRUE;
+ }else{
+ certFound=FALSE;
+ break;
+ }
+ }
+ // did we find ?
+ if(!certFound){
+ X509_free(x509);
+ continue;
+ }
+ }//if(useSubDN){
+ ddocMemBuf_free(&mbuf1);
+ // did we find ?
+ if(certFound){
+ break;
+ }else{
+ X509_free(x509);
+ continue;
+ }
+ }//while(pCertt=CertEnumCertificatesInStore(hCertStore,pCert))
+ if( certFound ){
+ //memcpy(cert,x509,sizeof(x509));
+ //X509_free(x509);
+ *cert=x509;
+ }else{
+ retCode=ERR_CSP_CERT_FOUND;
+ SET_LAST_ERROR(retCode);
+ break;
+ }
+ break;
+ }//while(TRUE){
+
+ /////******************** close and free objects ***********************************
+ if(pCert) {CertFreeCertificateContext(pCert); }
+ if(hCertStore) {CertCloseStore(hCertStore,CERT_CLOSE_STORE_FORCE_FLAG);hCertStore=0;}
+ return retCode;
+ /////*******************************************************************************
+}
+//=======================================================
+//Asks and returns key name or NULL if can not be found.
+//Key name must be freed. Name will be like "AUT_VIISAKAS,VILLU,19901012020"
+//IN cProvider - crypto provider name, "EstEID Card CSP" in
+// EstID's case.
+//=======================================================
+LPBYTE getDefaultKeyName(CSProvider * cCSP){
+ BOOL fRes;
+ HCRYPTPROV hProv = 0;
+ LPBYTE pbContName = NULL;//string, key name to be stored
+ DWORD dwContName;
+ if(cCSP==NULL){
+ cCSP=getCurrentCSProvider(TRUE);
+ }
+ if(cCSP==NULL){
+ return NULL;
+ }
+ if(cCSP->rsa_full){
+ fRes = CryptAcquireContext(&hProv,NULL,cCSP->CSPName, PROV_RSA_FULL, 0);
+ }else{
+ fRes = CryptAcquireContext(&hProv,NULL,cCSP->CSPName, PROV_RSA_SIG, 0);
+ }
+ if (RCRYPT_FAILED(fRes)){ return NULL; }
+ // asks keypair name, in auth case it is AUT_<name, given name, code>
+ // first size and the the keyname itself
+ fRes = CryptGetProvParam(hProv,PP_CONTAINER,NULL,&dwContName,0);
+ if (RCRYPT_FAILED(fRes)){ return NULL; }
+ //pbContName =(LPBYTE) LocalAlloc(0,dwContName);
+ pbContName =(LPBYTE) malloc(dwContName);
+ if(pbContName != NULL ){
+ fRes = CryptGetProvParam(hProv,PP_CONTAINER,pbContName,&dwContName,0);
+ }
+ //in pbContName-s there is now ASCII string
+ fRes = CryptReleaseContext(hProv,0);
+ if (RCRYPT_FAILED(fRes)){ return NULL; }
+ hProv =0;
+ return pbContName;
+
+}
+
+//========================================================================
+// Returns issuer certificate context
+//========================================================================
+const CERT_CONTEXT * findCertFromStore(const CERT_CONTEXT *cert, const char *storeName)
+{
+ HCERTSTORE hCertStore = NULL;
+ const CERT_CONTEXT *issuer = NULL;
+ DWORD flag=CERT_STORE_SIGNATURE_FLAG;
+ hCertStore=CertOpenSystemStore(0,storeName);
+ if(!hCertStore){
+ return NULL;
+ }
+ issuer = CertGetIssuerCertificateFromStore(hCertStore,cert,NULL,&flag);
+ CertCloseStore(hCertStore,0);
+ return issuer;
+}
+
+//=========================================================================
+X509 * findIssuerCertificatefromStore(X509 *x509)
+{
+ const CERT_CONTEXT *cert = NULL;
+ const CERT_CONTEXT *issuer = NULL;
+ char * storeNames[] = {"CA","Root","My"};
+
+ unsigned char certBlob[5000];
+ int i, certBlobLen = sizeof(certBlob);
+ X509 *x509issuer = NULL;
+
+ RETURN_OBJ_IF_NULL(x509, NULL);
+ //encode(
+ memset(certBlob,0,sizeof(certBlob));
+ encodeCert(x509,(char *)certBlob,&certBlobLen);
+ cert = CertCreateCertificateContext(X509_ASN_ENCODING|PKCS_7_ASN_ENCODING,certBlob,certBlobLen);
+ if(cert == NULL){
+ return NULL;
+ }
+ for( i=0;i<3;i++){
+ issuer=findCertFromStore(cert,storeNames[i]);
+ if(issuer){
+ break;
+ }
+ }
+ if(issuer){
+ //AA100204
+ ddocDecodeX509Data(&x509issuer,issuer->pbCertEncoded,issuer->cbCertEncoded);
+ CertFreeCertificateContext(issuer);
+ }
+ CertFreeCertificateContext(cert);
+
+ return x509issuer;
+
+}
+
+
+//=====================================================================
+// hashes and signes data with EstId card, returns also public_key_blob
+// which can be used in order to verify signature
+// IN dataToBeSigned - source data buffer
+// IN dataLen - how many bytes will be read from source buffer
+// OUT pbKeyBlob - public key buffer( corresponding private key was used to sign.
+// OUT pbKeyBlobLen - public key length in buffer
+// OUT hash - output data buffer for hash
+// OUT hashLen - data length in output buffer
+// OUT hashedSignature - output data buffer for hashed and signed data
+// OUT sigLen - data length in output buffer
+// IN szPin - PIN2 [optional]
+//=====================================================================
+int GetSignedHashWithKeyAndCSP( char *psKeyName, char *psCSPName,
+ const char * dataToBeSigned,unsigned long dataLen,
+ unsigned char *pbKeyBlob, unsigned long *pbKeyBlobLen,
+ unsigned char *hash, unsigned long *hashLen,
+ unsigned char * hashedSignature,unsigned long * sigLen,
+ const char* szPin)
+{
+ int retCode=ERR_OK, l1;
+ HCRYPTPROV hProv = 0;
+ HCRYPTHASH sha1 = 0;
+ HCRYPTKEY hKey = 0;
+ PCCERT_CONTEXT pCert=NULL;
+ BOOL fRes;
+ DWORD dwRes;
+ char *p1 = 0;
+
+ ddocDebug(3, "GetSignedHashWithKeyAndCSP", "key: %s csp: %s, pin-len: %d", psKeyName, psCSPName, (szPin ? strlen(szPin) : 0));
+ // debug
+ ddocDebug(3, "GetSignedHashWithKeyAndCSP", "data to sign: \'%s\' len: %d tlen: %d", dataToBeSigned, dataLen, strlen(dataToBeSigned));
+ //////******************** start task *************************************
+ while(TRUE){
+ //
+ //sprintf(sTemp,"CSP=%s \nCON=%s\n%d",psCSPName,psKeyName,DigiCrypt_FindContext_GetCSPType(psCSPName));
+ //MessageBox(NULL,sTemp,"TEST",MB_OK);
+ //
+ fRes=CryptAcquireContext(&hProv,psKeyName,psCSPName,DigiCrypt_FindContext_GetCSPType(psCSPName),0);//CRYPT_VERIFYCONTEXT);
+ ddocDebug(1, "GetSignedHashWithKeyAndCSP", "CryptAcquireContext: \'%s\' rc: %d", psKeyName, fRes);
+
+ if(fRes==FALSE){
+ dwRes = GetLastError();
+ ddocDebug(1, "GetSignedHashWithKeyAndCSP", "error in CryptAcquireContext: %ld hex: %x", dwRes, dwRes);
+ retCode=ERR_CSP_NO_CARD_DATA;
+ break;
+
+ }
+ fRes=CryptCreateHash(hProv,CALG_SHA1,0,0,&sha1);
+ if(fRes==FALSE){
+ ddocDebug(1, "GetSignedHashWithKeyAndCSP", "CryptCreateHash RC (bool): %d", (int)fRes);
+ retCode=ERR_CSP_NO_HASH_START;
+ SET_LAST_ERROR(retCode);
+ break;
+ }
+ // start hash
+ fRes=CryptHashData(sha1,dataToBeSigned,dataLen,0);
+
+ if(fRes==FALSE){
+ retCode=ERR_CSP_NO_HASH;
+ SET_LAST_ERROR(retCode);
+ break;
+ }
+ if(hash!=NULL){
+ ddocDebug(3, "GetSignedHashWithKeyAndCSP", "caling CryptGetHashParam hash: %s len: %ld", hash, *hashLen);
+ fRes=CryptGetHashParam(sha1,HP_HASHVAL, hash,hashLen ,0);
+ if(fRes==FALSE){
+ ddocDebug(1, "GetSignedHashWithKeyAndCSP", "CryptGetHashParam RC (bool): %d", (int)fRes);
+ retCode=ERR_CSP_NO_HASH_RESULT;
+ SET_LAST_ERROR(retCode);
+ break;
+ }
+ // debug
+ l1 = *hashLen * 2 + 10;
+ p1 = (char*)malloc(l1);
+ if(p1) {
+ memset(p1, 0, l1);
+ encode((const byte*)hash, *hashLen, (byte*)p1, &l1);
+ ddocDebug(3, "GetSignedHashWithKeyAndCSP", "hash: %s len: %d", p1, l1);
+ free(p1);
+ p1 = 0;
+ }
+ }
+
+ if(hashedSignature != NULL) {
+ //use by standard way is not allways possible -- AT_SIGNATURE -- main thing is that cert is ok nor the keyspec
+ //instead of that we should use CryptAcquireCertificatePrivateKey function. But then we must change basic context of this function.
+ //workaround -- we try with both keyspecs
+ // set PIN2 for signing if possible
+ if(szPin && strlen(szPin)) {
+ ddocDebug(3, "GetSignedHashWithKeyAndCSP", "Setting PIN len: %d", strlen(szPin));
+ fRes = CryptSetProvParam(hProv, PP_SIGNATURE_PIN, (const BYTE*)szPin, 0 );
+ ddocDebug(3, "GetSignedHashWithKeyAndCSP", "PIN setting: %d", fRes);
+ }
+ fRes=CryptSignHash(sha1,AT_SIGNATURE ,NULL,0, hashedSignature,sigLen);
+ if(fRes==FALSE)
+ {
+ dwRes = GetLastError();
+ //try again with keyspec AT_KEYEXCHANGE
+ if(dwRes==0x8009000d) // wrong keyspec
+ {
+ fRes=CryptSignHash(sha1,AT_KEYEXCHANGE ,NULL,0, NULL,sigLen); //*sigLen should be 128... this can be avoided whi
+ fRes=CryptSignHash(sha1,AT_KEYEXCHANGE ,NULL,0, hashedSignature,sigLen);
+ if(fRes==FALSE)
+ {
+ dwRes = GetLastError();
+ ddocDebug(1, "GetSignedHashWithKeyAndCSP", "error in CryptSignHash: %ld", dwRes);
+ retCode=ERR_CSP_SIGN;
+ SET_LAST_ERROR(retCode);
+ break;
+ }
+ } else if(dwRes == 0x8010006e) {
+ ddocDebug(2, "GetSignedHashWithKeyAndCSP", "user cancelled signing");
+ retCode=ERR_CSP_USER_CANCEL;
+ SET_LAST_ERROR(ERR_CSP_USER_CANCEL);
+ break;
+ }
+ else
+ {
+ ddocDebug(1, "GetSignedHashWithKeyAndCSP", "error in signing: %uld hex: %x", dwRes, dwRes);
+ retCode=ERR_CSP_SIGN;
+ SET_LAST_ERROR(retCode);
+ break;
+ }
+ }
+ } else
+ ddocDebug(1, "GetSignedHashWithKeyAndCSP", "hashed signature is NULL");
+
+ // we must switsh end and begining
+ // because windows uses little-endian but verification
+ // assumes big-endian
+ reverseArray(hashedSignature, *sigLen);
+
+ if(pbKeyBlob!=NULL){
+ fRes=CryptGetUserKey(hProv,AT_KEYEXCHANGE,&hKey);
+ if(fRes==FALSE){
+ ddocDebug(1, "GetSignedHashWithKeyAndCSP", "error in CryptGetUserKey");
+ retCode=ERR_CSP_OPEN_KEY;
+ SET_LAST_ERROR(retCode);
+ break;
+ }
+ fRes=CryptExportKey(hKey,0,PUBLICKEYBLOB,0,pbKeyBlob,pbKeyBlobLen);
+ if(fRes==FALSE){
+ ddocDebug(1, "GetSignedHashWithKeyAndCSP", "error in CryptExportKey");
+ retCode=ERR_CSP_READ_KEY;
+ SET_LAST_ERROR(retCode);
+ break;
+ }
+ }
+
+ break;
+ }//while(TRUE)
+ ///********************** free objects ************************************
+ if(hKey){
+ CryptDestroyKey(hKey);hKey=0;
+ }
+ if(sha1){
+ CryptDestroyHash(sha1);sha1= 0;
+ }
+ if(hProv){
+ CryptReleaseContext(hProv,0);
+ }
+ ddocDebug(3, "GetSignedHashWithKeyAndCSP", "end of signing RC: %d", retCode);
+ return retCode;
+ /////*******************************************************************************
+}
+
+//===============================================================
+// This function is used to change order in a massive. Last byte
+// becomes first and so on.
+// IN/OUT array - massive to be changed
+// IN arrayLen - array's length
+//===============================================================
+void reverseArray(unsigned char *array, unsigned long arrayLen)
+{
+ int ri, rj;
+ unsigned char t;
+
+ for (ri = 0, rj = arrayLen - 1; ri < rj; ++ri, --rj) {
+ t = array[ri];
+ array[ri] = array[rj];
+ array[rj] = t;
+ }
+}
+
+
+
+#endif
diff --git a/libdigidoc/DigiDocCsp.h b/libdigidoc/DigiDocCsp.h
new file mode 100644
index 0000000..c285c29
--- /dev/null
+++ b/libdigidoc/DigiDocCsp.h
@@ -0,0 +1,132 @@
+#ifndef __DIGIDOCCSP_H__
+#define __DIGIDOCCSP_H__
+
+//==================================================
+// FILE: DigDocCsp.h
+// PROJECT: Digi Doc
+// DESCRIPTION: CSP Functions
+// AUTHOR: Veiko Sinivee, S|E|B IT Partner Estonia
+//==================================================
+// Copyright (C) AS Sertifitseerimiskeskus
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+// GNU Lesser General Public Licence is available at
+// http://www.gnu.org/copyleft/lesser.html
+//==========< HISTORY >=============================
+// 1.0 09.05.2002 Veiko Sinivee
+//==================================================
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define EST_EID_CSP "EstEID Card CSP"
+
+typedef struct CSProvider_st {
+ char* CSPName;
+ int rsa_full; // if FALSE RSA_SIG will be used
+ int at_sig; //// if FALSE AT_KEYEXCHANGE will be used
+} CSProvider;
+
+// general structure for a list of certificates
+typedef struct CertItem_st {
+ X509* pCert;
+ struct CertItem_st* nextItem;
+} CertItem;
+
+
+typedef struct CertSearchStore_st {
+ int searchType;
+ char* storeName; // default is "My"
+ long certSerial;
+ int numberOfSubDNCriterias;
+ char** subDNCriterias;
+ int numberOfIssDNCriterias;
+ char** issDNCriterias;
+ void* publicKeyInfo;
+} CertSearchStore;
+
+typedef struct CertSearch_st {
+ int searchType;
+ char* x509FileName;
+ char* keyFileName;
+ char* pkcs12FileName;
+ char * pswd;
+ CertSearchStore* certSearchStore;
+} CertSearch;
+
+
+//=====================================================================
+// Hashes and signes data with EstId card, returns also cert
+// which can be used in order to verify signature
+// IN dataToBeSigned - source data buffer
+// IN dataLen - how many bytes will be read from source buffer
+// OUT cert - cert buffer( corresponding private key was used to sign.), migth be NULL if this parameter is not needed.
+// OUT certLen - cert length in buffer, migth be NULL if cert parameter is not needed.
+// OUT keyBlob - public key's buffer, migth be NULL if this parameter is not needed.
+// OUT keyBlobLen - public key's length in buffer, migth be NULL if keyBlob parameter is not needed.
+// OUT hash - hash buffer, migth be NULL if this parameter is not needed.
+// OUT hashLen - hash length in buffer, migth be NULL if hash parameter is not needed.
+// OUT sign - output data buffer for hashed and signed data
+// OUT sigLen - data length in output buffer
+//=====================================================================
+int GetSignParametersWithEstIdCSP(byte * dataToBeSigned,unsigned long dataLen,
+ X509 **x509, int *needCert,
+ byte *keyBlob, unsigned long *keyBlobLen,
+ byte *hash, unsigned long *hashLen,
+ byte *sign,unsigned long *sigLen);
+
+
+
+//EXP_OPTION int calculateSigInfoSignatureWithEstID(SignedDoc* pSigDoc, SignatureInfo* pSigInfo,
+// int slot, const char* passwd);
+
+
+//Added parameter iByKeyContainer by A.Amenberg 06062003
+EXP_OPTION int calculateSigInfoSignatureWithCSPEstID(SignedDoc* pSigDoc, SignatureInfo* pSigInfo, int iByKeyContainer, const char* szPin);
+
+EXP_OPTION X509 * findIssuerCertificatefromMsStore(X509 *x509);
+
+
+EXP_OPTION CertSearchStore* CertSearchStore_new();
+EXP_OPTION void CertSearchStore_free(CertSearchStore* certSearchStore);
+
+EXP_OPTION CertSearch* CertSearch_new();
+EXP_OPTION void CertSearch_free(CertSearch* certSearch);
+EXP_OPTION void CertList_free(CertItem* pListStart);
+EXP_OPTION void CertSearch_setX509FileName(CertSearch* certSearch, const char* str);
+EXP_OPTION void CertSearch_setKeyFileName(CertSearch* certSearch, const char* str);
+EXP_OPTION void CertSearch_setPkcs12FileName(CertSearch* certSearch, const char* str);
+EXP_OPTION void CertSearch_setPasswd(CertSearch* certSearch, const char* str);
+
+
+//
+EXP_OPTION CSProvider * getCurrentCSProvider(BOOL tryToFindIfMissing);
+EXP_OPTION X509* findCertificate(const CertSearch * cS);
+EXP_OPTION int findAllCertificates(const CertSearchStore *sS, X509 ***certsArray, int *numberOfCerts);
+
+EXP_OPTION int Digi_readCertificateByPKCS12OnlyCertHandle(const char *pkcs12file, const char * passwd, X509 **x509);
+EXP_OPTION int Digi_getConfirmationWithCertSearch(SignedDoc* pSigDoc, SignatureInfo* pSigInfo, char* pkcs12File, char* password,
+ char* notaryURL, char* proxyHost, char* proxyPort);
+EXP_OPTION int Digi_setNotaryCertificate(NotaryInfo* pNotary, X509* notCert);
+EXP_OPTION int Digi_verifyNotaryInfoWithCertSearch(const SignedDoc* pSigDoc, const NotaryInfo* pNotInfo);
+
+// verifies this one signature
+EXP_OPTION int Digi_verifySignatureInfo(const SignedDoc* pSigDoc, const SignatureInfo* pSigInfo,
+ const char* szDataFile);
+// verifies the whole document (returns on first err)
+EXP_OPTION int Digi_verifySigDoc(const SignedDoc* pSigDoc, const char* szDataFile);
+EXP_OPTION int Digi_verifySigDocWithCertSearch(const SignedDoc* pSigDoc, const char* szDataFile);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif \ No newline at end of file
diff --git a/libdigidoc/DigiDocDebug.c b/libdigidoc/DigiDocDebug.c
new file mode 100644
index 0000000..0c7e3b8
--- /dev/null
+++ b/libdigidoc/DigiDocDebug.c
@@ -0,0 +1,170 @@
+//==================================================
+// FILE: DigiDocDebug.h
+// PROJECT: Digi Doc
+// DESCRIPTION: Digi Doc functions for debug output
+// AUTHOR: Veiko Sinivee, S|E|B IT Partner Estonia
+//==================================================
+// Copyright (C) AS Sertifitseerimiskeskus
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+// GNU Lesser General Public Licence is available at
+// http://www.gnu.org/copyleft/lesser.html
+//==========< HISTORY >=============================
+// 10.08.2004 Veiko Sinivee
+// Creation
+//==================================================
+
+#include <libdigidoc/DigiDocDebug.h>
+#include <libdigidoc/DigiDocConfig.h>
+#include <libdigidoc/DigiDocLib.h>
+
+#if defined(GNUCPP) || !defined(WIN32)
+ #include <unistd.h>
+ #define _mkdir mkdir
+ #define _rmdir rmdir
+ #define _unlink unlink
+ #define _tzset tzset
+ #define _getcwd getcwd
+#endif
+
+
+//-----------------------------------------
+// Formats debug output
+// level - debug level to output this message on
+// func - name of the function
+// format - message format and arguments
+//-----------------------------------------
+EXP_OPTION void ddocDebug(int level, const char* func, const char* format, ...)
+{
+ time_t tNow;
+ struct tm tm1;
+ int nLevel = ConfigItem_lookup_int("DEBUG_LEVEL", 1);
+ const char * szDebugFile = ConfigItem_lookup("DEBUG_FILE");
+ va_list args;
+ FILE* hFile = 0;
+
+ if(level <= nLevel) {
+ time(&tNow);
+ ddocLocalTime(&tNow, &tm1, 1);
+ va_start(args, format);
+ if(szDebugFile && ((hFile = fopen(szDebugFile, "ab")) != NULL)) {
+ fprintf(hFile, "%s\t[%04d-%02d-%02d %02d:%02d:%02d] ",
+ func, tm1.tm_year + 1900, tm1.tm_mon + 1, tm1.tm_mday,
+ tm1.tm_hour, tm1.tm_min, tm1.tm_sec);
+ vfprintf(hFile, format, args);
+ fprintf(hFile, "\n");
+ fclose(hFile);
+ } else {
+ fprintf(stderr, "%s\t[%04d-%02d-%02d %02d:%02d:%02d] ",
+ func, tm1.tm_year + 1900, tm1.tm_mon + 1, tm1.tm_mday,
+ tm1.tm_hour, tm1.tm_min, tm1.tm_sec);
+ vfprintf(stderr, format, args);
+ fprintf(stderr, "\n");
+ }
+ }
+}
+
+//-----------------------------------------
+// Writes debug data in a file
+// level - debug level to write on
+// szFileName - target file name
+// pMemBuf - buffer for log data
+//-----------------------------------------
+EXP_OPTION int ddocDebugWriteFile(int level, const char* szFileName, DigiDocMemBuf *pMemBuf)
+{
+ int err = ERR_OK;
+ FILE* hFile;
+ int nLevel = ConfigItem_lookup_int("DEBUG_LEVEL", 1);
+
+ RETURN_IF_NULL_PARAM(szFileName);
+ RETURN_IF_NULL_PARAM(pMemBuf);
+ if(level <= nLevel) {
+ if((hFile = fopen(szFileName, "ab")) != NULL) {
+ fwrite(pMemBuf->pMem, 1, pMemBuf->nLen, hFile);
+ fclose(hFile);
+ }
+ }
+ return err;
+}
+
+//-----------------------------------------
+// Formats debug output
+// level - debug level to output this message on
+// func - name of the function
+// msg - message format and arguments
+// args - va_list struct
+//-----------------------------------------
+EXP_OPTION void ddocDebugVaArgs(int level, const char* func, const char* msg, va_list args)
+{
+ time_t tNow;
+ struct tm tm1;
+ int nLevel = ConfigItem_lookup_int("DEBUG_LEVEL", 1);
+ const char * szDebugFile = ConfigItem_lookup("DEBUG_FILE");
+ FILE* hFile = 0;
+
+ if(level <= nLevel) {
+ time(&tNow);
+ ddocLocalTime(&tNow, &tm1, 1);
+ if(szDebugFile && ((hFile = fopen(szDebugFile, "ab")) != NULL)) {
+ fprintf(hFile, "%s\t[%04d-%02d-%02d %02d:%02d:%02d] ",
+ func, tm1.tm_year + 1900, tm1.tm_mon + 1, tm1.tm_mday,
+ tm1.tm_hour, tm1.tm_min, tm1.tm_sec);
+ vfprintf(hFile, msg, args);
+ fprintf(hFile, "\n");
+ fclose(hFile);
+ } else {
+ fprintf(stderr, "%s\t[%04d-%02d-%02d %02d:%02d:%02d] ",
+ func, tm1.tm_year + 1900, tm1.tm_mon + 1, tm1.tm_mday,
+ tm1.tm_hour, tm1.tm_min, tm1.tm_sec);
+ vfprintf(stderr, msg, args);
+ fprintf(stderr, "\n");
+ }
+ }
+}
+
+//-----------------------------------------
+// Deletes the log file if it exists.
+//-----------------------------------------
+EXP_OPTION void ddocDebugTruncateLog()
+{
+ char * szDebugFile = (char*)ConfigItem_lookup("DEBUG_FILE");
+ if(szDebugFile && checkFileExists(szDebugFile)) {
+ _unlink(szDebugFile);
+ }
+}
+
+//-----------------------------------------
+// Reads the contents of the log file
+// pMemBuf - buffer for log data
+//-----------------------------------------
+EXP_OPTION int ddocDebugReadLog(DigiDocMemBuf *pMemBuf)
+{
+ char * szDebugFile = (char*)ConfigItem_lookup("DEBUG_FILE");
+ FILE *hFile;
+ int err = ERR_OK, l2, l1;
+ char buf1[1025];
+
+ RETURN_IF_NULL_PARAM(pMemBuf);
+ pMemBuf->pMem = 0;
+ pMemBuf->nLen = 0;
+ if(szDebugFile) {
+ if((hFile = fopen(szDebugFile, "rt")) != NULL) {
+ l1 = sizeof(buf1);
+ do {
+ l2 = fread(buf1, 1, l1, hFile);
+ err = ddocMemAppendData(pMemBuf, buf1, l2);
+ } while(l2 > 0);
+ fclose(hFile);
+ }
+ }
+ else
+ err = ERR_FILE_READ;
+ return err;
+}
+
diff --git a/libdigidoc/DigiDocDebug.h b/libdigidoc/DigiDocDebug.h
new file mode 100644
index 0000000..366bce7
--- /dev/null
+++ b/libdigidoc/DigiDocDebug.h
@@ -0,0 +1,75 @@
+#ifndef __DIGIDOC_DEBUG_H__
+#define __DIGIDOC_DEBUG_H__
+//==================================================
+// FILE: DigiDocDebug.h
+// PROJECT: Digi Doc
+// DESCRIPTION: Digi Doc functions for debug output
+// AUTHOR: Veiko Sinivee, S|E|B IT Partner Estonia
+//==================================================
+// Copyright (C) AS Sertifitseerimiskeskus
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+// GNU Lesser General Public Licence is available at
+// http://www.gnu.org/copyleft/lesser.html
+//==========< HISTORY >=============================
+// 10.08.2004 Veiko Sinivee
+// Creation
+//==================================================
+
+#include <libdigidoc/DigiDocMem.h>
+#include <libdigidoc/DigiDocDefs.h>
+#include <stdarg.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+//-----------------------------------------
+// Formats debug output
+// level - debug level to output this message on
+// func - name of the function
+// format - message format and arguments
+//-----------------------------------------
+EXP_OPTION void ddocDebug(int level, const char* func, const char* format, ...);
+
+//-----------------------------------------
+// Formats debug output
+// level - debug level to output this message on
+// func - name of the function
+// msg - message format and arguments
+// args - va_list struct
+//-----------------------------------------
+EXP_OPTION void ddocDebugVaArgs(int level, const char* func, const char* msg, va_list args);
+
+//-----------------------------------------
+// Deletes the log file if it exists.
+//-----------------------------------------
+EXP_OPTION void ddocDebugTruncateLog();
+
+//-----------------------------------------
+// Reads the contents of the log file
+// pMemBuf - buffer for log data
+//-----------------------------------------
+EXP_OPTION int ddocDebugReadLog(DigiDocMemBuf *pMemBuf);
+
+//-----------------------------------------
+// Writes debug data in a file
+// level - debug level to write on
+// szFileName - target file name
+// pMemBuf - buffer for log data
+//-----------------------------------------
+EXP_OPTION int ddocDebugWriteFile(int level, const char* szFileName, DigiDocMemBuf *pMemBuf);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // __DIGIDOC_DEBUG_H__
+
diff --git a/libdigidoc/DigiDocDefs.h b/libdigidoc/DigiDocDefs.h
new file mode 100644
index 0000000..713369c
--- /dev/null
+++ b/libdigidoc/DigiDocDefs.h
@@ -0,0 +1,180 @@
+#ifndef __DIGIDOC_DEFS_H__
+#define __DIGIDOC_DEFS_H__
+//==================================================
+// FILE: DigiDocDefs.h
+// PROJECT: Digi Doc
+// DESCRIPTION: Digi Doc global definitions.
+// AUTHOR: Veiko Sinivee, S|E|B IT Partner Estonia
+//==================================================
+// Copyright (C) AS Sertifitseerimiskeskus
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.ode
+// GNU Lesser General Public Licence is available at
+// http://www.gnu.org/copyleft/lesser.html
+//==========< HISTORY >=============================
+// 15.06.2005 Veiko Sinivee
+//==================================================
+
+
+#ifdef WIN32
+ #ifndef WIN32_LEAN_AND_MEAN
+ #define WIN32_LEAN_AND_MEAN
+ #endif
+ #include <windows.h>
+ #define WIN32_CSP
+ #ifdef _MSC_VER
+ #pragma warning( disable: 4100 4706 4204 4221 )
+ #endif
+ #ifdef digidoc_EXPORTS
+ #define EXP_OPTION __declspec(dllexport)
+ #else
+ #define EXP_OPTION __declspec(dllimport)
+ #endif
+ #define DIGIDOC_DEPRECATED __declspec(deprecated)
+#else
+ #if __GNUC__ >= 4
+ #define EXP_OPTION __attribute__ ((visibility("default")))
+ #define DIGIDOC_DEPRECATED __attribute__ ((__deprecated__))
+ #else
+ #define EXP_OPTION
+ #define DIGIDOC_DEPRECATED
+ #endif
+#endif
+
+#ifdef WIN32
+ //for _msize function
+ #define FILESEPARATOR "\\"
+ #include <malloc.h>
+ #include <direct.h>
+ #define snprintf _snprintf
+#else
+ #define FILESEPARATOR "/"
+ #define DIGI_DOC_LIB
+ #include <unistd.h>
+ #define _mkdir mkdir
+ #define _rmdir rmdir
+ #define _unlink unlink
+ #define _tzset tzset
+ #define _getcwd getcwd
+ #if defined(__FreeBSD__)
+ #define _timezone tzone
+ extern long int tzone; /* default for Estonia, but see initDigiDocLib() */
+ #define _daylight daylight
+ extern int daylight; /* default, but see initDigiDocLib() */
+ #else
+ #define _timezone timezone
+ #define _daylight daylight
+ #endif
+#endif
+
+#define WITH_BASE64_HASHING_HACK 1
+// VS: disabled ecdsa support for FC13 building
+//#define WITH_ECDSA 1
+
+//#define WITH_DEPRECATED_FUNCTIONS
+
+
+// old timestamp struct
+#define WITH_TIMETSTAMP_STRUCT
+
+#ifndef byte
+typedef unsigned char byte;
+#endif
+
+#define WITH_SHA256
+//==========< Digest types >=======================
+#ifdef WITH_SHA256
+#define SIGNATURE_LEN 144
+#else
+#define SIGNATURE_LEN 128
+#endif
+#define DIGEST_LEN 20
+#define DIGEST_SHA1 0
+#define DIGEST_SHA256 1
+#define DIGEST_LEN256 32
+#define CERT_DATA_LEN 4096
+#define X509_NAME_LEN 256
+#define SIGNATURE_RSA 0
+#define CONTENT_EMBEDDED "EMBEDDED"
+#define CONTENT_EMBEDDED_BASE64 "EMBEDDED_BASE64"
+#define X509_NAME_BUF_LEN 500
+
+//==========< Format types >=======================
+
+#define SK_PKCS7_1 "SK-PKCS#7-1.0"
+#define SK_XML_1_NAME "SK-XML"
+#define DIGIDOC_XML_1_1_NAME "DIGIDOC-XML"
+#define SK_XML_1_VER "1.0"
+#define DIGIDOC_XML_1_1_VER "1.1"
+#define DIGIDOC_XML_1_2_VER "1.2"
+#define DIGIDOC_XML_1_3_VER "1.3"
+#define SK_NOT_VERSION "OCSP-1.0"
+
+#define DIGEST_SHA1_NAME "sha1"
+#define DIGEST_SHA1_WRONG "sha1wrong"
+#define DIGEST_SHA256_NAME "sha256"
+#define SIGN_RSA_NAME "RSA"
+#ifdef WITH_ECDSA
+ #define SIGN_ECDSA_NAME "ECDSA"
+#endif
+#define OCSP_NONCE_NAME "OCSP Nonce"
+#define RESPID_NAME_VALUE "NAME"
+#define RESPID_KEY_VALUE "KEY HASH"
+#define OCSP_SIG_TYPE "sha1WithRSAEncryption"
+#define RESPID_NAME_TYPE 1
+#define RESPID_KEY_TYPE 2
+
+#define DIGEST_METHOD_SHA1 "http://www.w3.org/2000/09/xmldsig#sha1"
+#define DIGEST_METHOD_SHA256 "http://www.w3.org/2001/04/xmlenc#sha256"
+#define NAMESPACE_XML_DSIG "http://www.w3.org/2000/09/xmldsig#"
+#define NAMESPACE_XADES_111 "http://uri.etsi.org/01903/v1.1.1#"
+#define NAMESPACE_XADES_132 "http://uri.etsi.org/01903/v1.3.2#"
+#define NAMESPACE_XADES "http://uri.etsi.org/01903#"
+
+
+//==========< Format types >=======================
+
+#define CHARSET_ISO_8859_1 "ISO-8859-1"
+#define CHARSET_UTF_8 "UTF-8"
+
+
+//==========< language codes >=======================
+#define DDOC_LANG_ENGLISH 0
+#define DDOC_LANG_ESTONIAN 1
+#define DDOC_NUM_LANGUAGES 2
+#define SUPPORTED_VERSION_COUNT 4
+
+//==========< file formats >=======================
+
+#define FILE_FORMAT_ASN1 0
+#define FILE_FORMAT_PEM 1
+//#define FILE_FORMAT_
+
+//============< OCSP paramaters >==================
+
+#define OCSP_REQUEST_SIGN_NO 1
+#define OCSP_REQUEST_SIGN_CSP 2
+#define OCSP_REQUEST_SIGN_X509 3
+#define OCSP_REQUEST_SIGN_PKCS11_WIN 4
+#define OCSP_REQUEST_SIGN_PKCS12 5
+
+//================== Cert search constants =========
+#define CERT_SEARCH_BY_STORE 1
+#define CERT_SEARCH_BY_X509 2
+#define CERT_SEARCH_BY_PKCS12 3
+
+// thes can be XOR'ed, then all criterias are used
+#define CERT_STORE_SEARCH_BY_SERIAL 0x01
+#define CERT_STORE_SEARCH_BY_SUBJECT_DN 0x02
+#define CERT_STORE_SEARCH_BY_ISSUER_DN 0x04
+#define CERT_STORE_SEARCH_BY_KEY_INFO 0x08
+
+#define FILE_BUFSIZE 1024*16
+
+#endif // __DIGIDOC_DEFS_H__
diff --git a/libdigidoc/DigiDocDfExtract.c b/libdigidoc/DigiDocDfExtract.c
new file mode 100644
index 0000000..28345e9
--- /dev/null
+++ b/libdigidoc/DigiDocDfExtract.c
@@ -0,0 +1,405 @@
+//==================================================
+// FILE: DigiDocDfExtract.c
+// PROJECT: Digi Doc
+// DESCRIPTION: Digi Doc functions for extracting <DataFile> contents
+// AUTHOR: Veiko Sinivee, S|E|B IT Partner Estonia
+//==================================================
+// Copyright (C) AS Sertifitseerimiskeskus
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+// GNU Lesser General Public Licence is available at
+// http://www.gnu.org/copyleft/lesser.html
+//==========< HISTORY >=============================
+// 03.03.2008 Veiko Sinivee
+// Creation
+//==================================================
+
+#include <libdigidoc/DigiDocDefs.h>
+#include <libdigidoc/DigiDocError.h>
+#include <libdigidoc/DigiDocDebug.h>
+#include <libdigidoc/DigiDocConvert.h>
+#include <libdigidoc/DigiDocMem.h>
+#include <libdigidoc/DigiDocLib.h>
+#include <libdigidoc/DigiDocObj.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <memory.h>
+#include <string.h>
+#include <ctype.h>
+
+#ifdef WIN32
+ #define snprintf _snprintf
+ #include <wchar.h>
+#endif
+
+#define ST_START 0
+#define ST_XML 1
+#define ST_TAG_NM 2
+#define ST_TAG_WS 3
+#define ST_ATTR_NM 4
+#define ST_ATTR_WS 5
+#define ST_ATTR_CON 6
+#define ST_CON 7
+#define ST_DF_START 8
+#define ST_DF_CON 9
+#define ST_DF_TAG 10
+#define ST_DF_END 11
+#define ST_DF_END_END 12
+
+
+//--------------------------------------------------
+// Reads in signed XML document and extracts the desired data file
+// pSigDoc - signed document object if exists. Can be NULL
+// szFileName - digidoc filename
+// szDataFileName - name of the file where to store embedded data.
+// szDocId - DataFile Id atribute value
+// szCharset - convert DataFile content to charset
+//--------------------------------------------------
+EXP_OPTION int ddocExtractDataFile(SignedDoc* pSigDoc, const char* szFileName,
+ const char* szDataFileName, const char* szDocId,
+ const char* szCharset)
+{
+ FILE *fIn = 0, *fOut = 0;
+ int err = ERR_OK, i, nRead, lt, la, lc, j, ld, lb, l, eState = 0, fs = 0;
+ long len, lExtr = 0, lSize = 0;
+ char chars[1050], tag[100], attr[100], con[1030], dec[70], b64line[70];
+ unsigned char b64 = 0, nNc = 0, bFound = 0;
+ void *pBuf;
+ EVP_ENCODE_CTX ectx;
+#ifdef WIN32
+ wchar_t *convFileName = 0, *convDataFileName = 0; i= 0;
+ err = utf82unicode((const char*)szFileName, (char**)&convFileName, &i);
+ ddocDebug(3, "ddocExtractDataFile", "file: %s, conv-file: %s len: %d", szFileName, convFileName, i);
+ i= 0;
+ err = utf82unicode((const char*)szDataFileName, (char**)&convDataFileName, &i);
+ ddocDebug(3, "ddocExtractDataFile", "dfile: %s, conv-dfile: %s len: %d", szDataFileName, convDataFileName, i);
+#endif
+
+ RETURN_IF_NULL_PARAM(szFileName);
+ RETURN_IF_NULL_PARAM(szDataFileName);
+ RETURN_IF_NULL_PARAM(szDocId);
+ RETURN_IF_NULL_PARAM(szCharset);
+ clearErrors();
+ ddocDebug(3, "ddocExtractDataFile", "SigDoc: %s, docid: %s, digidoc: %s, file: %s, charset: %s", (pSigDoc ? "OK" : "NULL"), szDocId, szFileName, szDataFileName, szCharset);
+ if(szCharset && !strcmp(szCharset, "NO-CHANGE"))
+ nNc = 1;
+ // try reading from memory if already cached?
+ nRead = ddocGetDataFileCachedData(pSigDoc, szDocId, &pBuf, &len);
+ if(pBuf) { // gotcha
+ ddocDebug(3, "ddocSaxExtractDataFile", "Using cached data: %d bytes", len);
+#ifdef WIN32
+ if((fOut = _wfopen(convDataFileName, L"wb")) != NULL) {
+#else
+ if((fOut = fopen(szDataFileName, "wb")) != NULL) {
+#endif
+ fwrite(pBuf, 1, len, fOut);
+ fclose(fOut);
+ } else {
+ free(pBuf);
+ ddocDebug(1, "ddocSaxExtractDataFile", "Error writing file: %s", szDataFileName);
+ SET_LAST_ERROR_RETURN_CODE(ERR_FILE_WRITE);
+ }
+ free(pBuf);
+ return nRead;
+ }
+ // open ddoc file
+#ifdef WIN32
+ if((fIn = _wfopen(convFileName, L"rb")) != NULL) {
+#else
+ if((fIn = fopen(szFileName, "rb")) != NULL) {
+#endif
+ ddocDebug(3, "ddocExtractDataFile", "Opened ddoc-file: %s", szFileName);
+ do {
+ nRead = fread(chars, 1, 1024, fIn);
+ chars[nRead] = 0;
+ ddocDebug(6, "ddocExtractDataFile", "Parsing %d bytes: \n%s\n", nRead, chars);
+ // handle read data
+ for(i = 0; i < nRead; i++) {
+ switch(eState) {
+ case ST_START: // search '<?xml'
+ if(chars[i] == '<' &&
+ !strncmp(chars+i, "<?xml", 5)) {
+ eState = ST_XML;
+ i += 4;
+ }
+ break;
+ case ST_XML: // search '<'
+ if(chars[i] == '<') {
+ eState = ST_TAG_NM;
+ lt = 0;
+ tag[lt] = 0;
+ }
+ break;
+ case ST_TAG_NM: // read tag name
+ if(isalnum(chars[i]) || chars[i] == ':' || chars[i] == '/') {
+ if(lt < sizeof(tag)-1) {
+ tag[lt] = chars[i];
+ tag[++lt] = 0;
+ } else {
+ ddocDebug(1, "ddocSaxExtractDataFile", "Invalid xml tag-len > %d", sizeof(tag));
+ SET_LAST_ERROR_RETURN_CODE(ERR_FILE_READ);
+ }
+ } else if(chars[i] == '>') { // tag ended - content
+ eState = ST_CON;
+ } else { // expecting atributes
+ eState = ST_TAG_WS;
+ }
+ break;
+ case ST_TAG_WS:
+ if(chars[i] == '>') {
+ if(bFound) {
+ eState = ST_DF_CON;
+ if(b64)
+ EVP_DecodeInit(&ectx);
+ } else
+ eState = ST_CON; // tag endded - content
+ lc = 0;
+ con[lc] = 0;
+ } else if(isalnum(chars[i])) {
+ eState = ST_ATTR_NM; // attr name started
+ la = 0;
+ attr[la] = chars[i];
+ attr[++la] = 0;
+ }
+ break;
+ case ST_ATTR_NM:
+ if(isalnum(chars[i])) {
+ if(la < (int)sizeof(attr)-1) {
+ attr[la] = chars[i];
+ attr[++la] = 0;
+ }
+ else
+ ddocDebug(1, "ddocExtractDataFile", "Truncating attr name: %s", attr);
+ break;
+ //19.11.08 added support for '
+ } else if(chars[i] == '\"'/*|| chars[i] == '\''*/) {
+ eState = ST_ATTR_CON;
+ lc = 0;
+ con[lc] = 0;
+ fs = 2;
+ } else if(chars[i] == '\'' && fs==0) {
+ eState = ST_ATTR_CON;
+ lc = 0;
+ con[lc] = 0;
+ fs = 1;
+ } else {
+ eState = ST_ATTR_WS;
+ }
+ break;
+ case ST_ATTR_WS:
+ //19.11.08 added support for '
+ if(chars[i] == '\"'/*|| chars[i] == '\''*/) {
+ eState = ST_ATTR_CON;
+ lc = 0;
+ con[lc] = 0;
+ } else if(chars[i] == '\'' && fs==1) {
+ eState = ST_ATTR_CON;
+ lc = 0;
+ con[lc] = 0;
+ } else {
+ eState = ST_TAG_WS;
+ }
+ break;
+ case ST_ATTR_CON:
+ //19.11.08 added support for '
+ if(chars[i] != '\"' /*&& chars[i] != '\''*/) {
+ if(lc < (int)sizeof(con)-1) {
+ con[lc] = chars[i];
+ con[++lc] = 0;
+ } else
+ ddocDebug(1, "ddocExtractDataFile", "Truncating attr content: %s", attr);
+ } else if(chars[i] == '\'' && fs==1) {
+ if(lc < (int)sizeof(con)-1) {
+ con[lc] = chars[i];
+ con[++lc] = 0;
+ } else
+ ddocDebug(1, "ddocExtractDataFile", "Truncating attr content: %s", attr);
+ } else {
+ eState = ST_TAG_WS;
+ // attribute value complete
+ if(!strcmp(tag, "DataFile")) {
+ // ddocDebug(3, "ddocSaxExtractDataFile", "DataFile start, attr: %s", attr);
+ if(!strcmp(attr, "ContentType")) {
+ b64 = (!strcmp(con, "EMBEDDED_BASE64")) ? 1 : 0;
+ lb = 0;
+ b64line[0] = 0;
+ }
+ if(!strcmp(attr, "Size") && bFound) {
+ lSize = atol(con);
+ }
+ if(!strcmp(attr, "Id")) {
+ ddocDebug(3, "ddocSaxExtractDataFile", "Found Id: %s searching id: %s", con, szDocId);
+ if(!strcmp(con, szDocId)) {
+ bFound = 1;
+#ifdef WIN32
+ fOut = _wfopen(convDataFileName, L"wb");
+ ddocDebug(3, "ddocSaxExtractDataFile", "Opening file: %s handle: %s", convDataFileName, (fOut ? "OK" : "NULL"));
+#else
+ fOut = fopen(szDataFileName, "wb");
+ ddocDebug(3, "ddocSaxExtractDataFile", "Opening file: %s handle: %s", szDataFileName, (fOut ? "OK" : "NULL"));
+#endif
+ if(!fOut) {
+ SET_LAST_ERROR(ERR_FILE_WRITE);
+ err = ERR_FILE_WRITE;
+ return err;
+ }
+ }
+ }
+ }
+ }
+ break;
+ case ST_CON:
+ if(chars[i] == '<') {
+ eState = ST_TAG_NM;
+ lt = 0;
+ tag[lt] = 0;
+ } else {
+ //con[lc] = chars[i];
+ //con[++lc] = 0;
+ }
+ break;
+ case ST_DF_START: // find tag end
+ if(chars[i] == '>') {
+ eState = ST_DF_CON;
+ lc = 0;
+ con[lc] = 0;
+ if(b64)
+ EVP_DecodeInit(&ectx);
+ }
+ break;
+ case ST_DF_CON:
+ if(chars[i] == '<') {
+ eState = ST_DF_TAG;
+ lt = 0;
+ tag[lt] = 0;
+ } else {
+ if(lc < (int)sizeof(con) - 1) {
+ if(b64 && !nNc) {
+ for(l = 0; l < lc; ) {
+ while(lb < 64 && l < lc && l < sizeof(con)) {
+ if(con[l] != '\n' && con[l] != '\r')
+ b64line[lb++] = con[l];
+ l++;
+ }
+ if(lb == 64) {
+ b64line[lb++] = '\n';
+ b64line[lb] = 0;
+ ld = sizeof(dec);
+ dec[0] = 0;
+ EVP_DecodeUpdate(&ectx, (unsigned char*)dec, &ld, (unsigned char*)b64line, lb);
+ lExtr += ld;
+ if(ld > 0)
+ fwrite(dec, 1, ld, fOut);
+ lb = 0;
+ }
+ }
+ } else if(nNc || !b64) {
+ lExtr += lc;
+ fwrite(con, 1, lc, fOut);
+ }
+ lc = 0;
+ }
+ if(lc < sizeof(con)-1) {
+ con[lc] = chars[i];
+ con[++lc] = 0;
+ }
+ }
+ break;
+ case ST_DF_TAG:
+ if(/*isalnum(chars[i]) || chars[i] == ':' || chars[i] == '/' ||*/ chars[i] != '>') {
+ if(lt < sizeof(tag)-1) {
+ tag[lt] = chars[i];
+ tag[++lt] = 0;
+ } else {
+ ddocDebug(1, "ddocSaxExtractDataFile", "Invalid xml tag-len > %d", sizeof(tag));
+ SET_LAST_ERROR_RETURN_CODE(ERR_FILE_READ);
+ }
+ } else { // DF intenal tag name ready
+ if(!strcmp(tag, "/DataFile")) { // end of DF
+ eState = ST_DF_END;
+ } else { // wrong tag - this is content
+ if(lc < sizeof(con)-1) {
+ con[lc] = '<';
+ for(j = 0; j < lt; j++)
+ con[++lc] = tag[j];
+ con[++lc] = '>';
+ con[++lc] = 0;
+ }
+ eState = ST_DF_CON;
+ }
+ }
+ if(eState != ST_DF_END)
+ break;
+ case ST_DF_END:
+ if(b64 && !nNc) {
+ if(lc > 0) {
+ for(l = 0; l < lc; ) {
+ while(lb < 64 && l < lc) {
+ if(con[l] != '\n' && con[l] != '\r')
+ b64line[lb++] = con[l];
+ l++;
+ }
+ b64line[lb++] = '\n';
+ b64line[lb] = 0;
+ ld = sizeof(dec);
+ dec[0] = 0;
+ EVP_DecodeUpdate(&ectx, (unsigned char*)dec, &ld, (unsigned char*)b64line, lb);
+ lExtr += ld;
+ if(ld > 0)
+ fwrite(dec, 1, ld, fOut);
+ lb = 0;
+ }
+ }
+ ld = 0;
+ dec[ld] = 0;
+ EVP_DecodeFinal(&ectx, (unsigned char*)dec, &ld);
+ lExtr += ld;
+ if(ld)
+ fwrite(dec, 1, ld, fOut);
+ } else if(nNc || !b64) {
+ if(lc) {
+ lExtr += lc;
+ fwrite(con, 1, lc, fOut);
+ lc = 0;
+
+ }
+ }
+ i = sizeof(chars);
+ //AM 24.09.08 RIK
+ eState = ST_DF_END_END;
+ break;
+ }
+ }
+ //AM 24.09.08 RIK ST_DF_END to ST_DF_END_END_END
+ } while(nRead > 0 && !err && eState < ST_DF_END_END);
+ } else {
+ ddocDebug(1, "ddocExtractDataFile", "Error reading file: %s", szFileName);
+ SET_LAST_ERROR(ERR_FILE_READ);
+ }
+ if(fIn)
+ fclose(fIn);
+ if(fOut)
+ fclose(fOut);
+ if(!nNc && lSize != lExtr) {
+ ddocDebug(1, "ddocExtractDataFile", "Warning! Extracted: %ld bytes but expected: %ld bytes", lExtr, lSize);
+ //SET_LAST_ERROR(ERR_FILE_READ);
+ //err = ERR_FILE_READ;
+ }
+ if(!bFound) {
+ ddocDebug(1, "ddocExtractDataFile", "DF: %s not found", szDocId);
+ SET_LAST_ERROR(ERR_FILE_WRITE);
+ err = ERR_FILE_WRITE;
+ }
+ ddocDebug(3, "ddocExtractDataFile", "Extracted DF: %s to %s size: %ld expected: %ld", szDocId, szDataFileName, lExtr, lSize);
+#ifdef WIN32
+ free(convFileName);
+ free(convDataFileName);
+#endif
+ return err;
+}
diff --git a/libdigidoc/DigiDocDfExtract.h b/libdigidoc/DigiDocDfExtract.h
new file mode 100644
index 0000000..0bfab68
--- /dev/null
+++ b/libdigidoc/DigiDocDfExtract.h
@@ -0,0 +1,48 @@
+#ifndef __DIGIDOC_DF_EXTRACT_H__
+#define __DIGIDOC_DF_EXTRACT_H__
+//==================================================
+// FILE: DigiDocDfExtract.h
+// PROJECT: Digi Doc
+// DESCRIPTION: Digi Doc functions for extracting <DataFile> contents
+// AUTHOR: Veiko Sinivee, S|E|B IT Partner Estonia
+//==================================================
+// Copyright (C) AS Sertifitseerimiskeskus
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+// GNU Lesser General Public Licence is available at
+// http://www.gnu.org/copyleft/lesser.html
+//==========< HISTORY >=============================
+// 03.03.2008 Veiko Sinivee
+// Creation
+//==================================================
+
+#include <libdigidoc/DigiDocDefs.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+//--------------------------------------------------
+// Reads in signed XML document and extracts the desired data file
+// pSigDoc - signed document object if exists. Can be NULL
+// szFileName - digidoc filename
+// szDataFileName - name of the file where to store embedded data.
+// szDocId - DataFile Id atribute value
+// szCharset - convert DataFile content to charset
+//--------------------------------------------------
+EXP_OPTION int ddocExtractDataFile(SignedDoc* pSigDoc, const char* szFileName,
+ const char* szDataFileName, const char* szDocId,
+ const char* szCharset);
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif
diff --git a/libdigidoc/DigiDocEnc.c b/libdigidoc/DigiDocEnc.c
new file mode 100644
index 0000000..60752aa
--- /dev/null
+++ b/libdigidoc/DigiDocEnc.c
@@ -0,0 +1,2743 @@
+//==================================================
+// FILE: DigiDocEnc.c
+// PROJECT: Digi Doc Encryption
+// DESCRIPTION: DigiDocEnc structure admin functions
+// AUTHOR: Veiko Sinivee, S|E|B IT Partner Estonia
+//==================================================
+// Copyright (C) AS Sertifitseerimiskeskus
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+// GNU Lesser General Public Licence is available at
+// http://www.gnu.org/copyleft/lesser.html
+//==========< HISTORY >=============================
+// 15.09.2004 Veiko Sinivee
+// Creation
+//==================================================
+
+// config data comes from there
+#ifndef WIN32
+ #if HAVE_CONFIG_H
+ #include <config.h>
+ #endif
+#endif // no win32
+
+#include <libdigidoc/DigiDocDefs.h>
+#include <libdigidoc/DigiDocEnc.h>
+#include <libdigidoc/DigiDocEncGen.h>
+#include <libdigidoc/DigiDocError.h>
+#include <libdigidoc/DigiDocDebug.h>
+#include <libdigidoc/DigiDocPKCS11.h>
+#include <libdigidoc/DigiDocConvert.h>
+#include <libdigidoc/DigiDocCert.h>
+#include <libdigidoc/DigiDocMem.h>
+
+#include <openssl/sha.h>
+#include <openssl/rsa.h>
+#include <openssl/evp.h>
+#include <openssl/rand.h>
+#include <zlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#ifdef WIN32
+#define snprintf _snprintf
+#endif
+
+
+//======================< DEncEncryptedData >==============================
+
+
+//--------------------------------------------------
+// Validates the <EncryptionMethod> parameter. We
+// currently support only AES-128-CBC.
+// szEncMethod - value to be checked
+// returns error code or ERR_OK
+//--------------------------------------------------
+int dencEncDataValidateEncMethod(const char* szEncMethod)
+{
+ if(szEncMethod && strcmp(szEncMethod, DENC_ENC_METHOD_AES128))
+ SET_LAST_ERROR_RETURN(ERR_DENC_ENC_METHOD, ERR_DENC_ENC_METHOD)
+ else
+ return ERR_OK;
+}
+
+//--------------------------------------------------
+// Validates the XML namespace parameter. We
+// currently support only
+// szEncMethod - value to be checked
+// returns error code or ERR_OK
+//--------------------------------------------------
+int dencValidateEncXmlNs(const char* szXmlNs)
+{
+ if(szXmlNs && strcmp(szXmlNs, DENC_XMLNS_XMLENC))
+ SET_LAST_ERROR_RETURN(ERR_DENC_ENC_XMLNS, ERR_DENC_ENC_XMLNS)
+ else
+ return ERR_OK;
+}
+
+//--------------------------------------------------
+// "Constructor" of DEncEncryptedData object
+// pEncData - address of buffer for newly allocated object [REQUIRED]
+// szXmlNs - XML namespace uri
+// szEncMethod - encyrption method algorithm uri
+// szId - elements Id attribute [OPTIONAL]
+// szType - elements type atribute [OPTIONAL]
+// szMimeType - elements mime-type attribute [OPTIONAL]
+// returns error code or ERR_OK
+//--------------------------------------------------
+EXP_OPTION int dencEncryptedData_new(DEncEncryptedData** pEncData,
+ const char* szXmlNs, const char* szEncMethod,
+ const char* szId, const char* szType,
+ const char* szMimeType)
+{
+ int err = ERR_OK;
+
+ // check input parameters
+ ddocDebug(3, "dencEncryptedData_new", "EncMethod: %s, Id: %s, type: %s, mime: %s",
+ szEncMethod, szId, szType, szMimeType);
+ RETURN_IF_NULL_PARAM(pEncData);
+ err = dencEncDataValidateEncMethod(szEncMethod);
+ if(err) return err;
+ err = dencValidateEncXmlNs(szXmlNs);
+ if(err) return err;
+ *pEncData = (DEncEncryptedData*)malloc(sizeof(DEncEncryptedData));
+ // allocate new object
+ RETURN_IF_BAD_ALLOC(*pEncData);
+ memset(*pEncData, 0, sizeof(DEncEncryptedData));
+ // set required fields
+ if(szXmlNs) {
+ err = ddocMemAssignString((char**)&((*pEncData)->szXmlNs), szXmlNs);
+ if(err) return err;
+ }
+ if(szEncMethod) {
+ err = ddocMemAssignString((char**)&((*pEncData)->szEncryptionMethod), szEncMethod);
+ if(err) return err;
+ }
+ // set optional fields
+ if(szId) {
+ err = ddocMemAssignString((char**)&((*pEncData)->szId), szId);
+ if(err) return err;
+ }
+ if(szType) {
+ err = ddocMemAssignString((char**)&((*pEncData)->szType), szType);
+ if(err) return err;
+ }
+ if(szMimeType) {
+ err = ddocMemAssignString((char**)&((*pEncData)->szMimeType), szMimeType);
+ if(err) return err;
+ }
+ // set meta info carrying lib & document format versions
+ dencMetaInfo_SetLibVersion(*pEncData);
+ dencMetaInfo_SetFormatVersion(*pEncData);
+ return err;
+}
+
+//--------------------------------------------------
+// "Destructor" of DEncEncryptedData object
+// pEncData - address of object to be deleted [REQUIRED]
+// returns error code or ERR_OK
+//--------------------------------------------------
+EXP_OPTION int dencEncryptedData_free(DEncEncryptedData* pEncData)
+{
+ int i, err = ERR_OK;
+ RETURN_IF_NULL_PARAM(pEncData)
+ // cleanup this object
+ if(pEncData->szId)
+ free(pEncData->szId);
+ if(pEncData->szType)
+ free(pEncData->szType);
+ if(pEncData->szMimeType)
+ free(pEncData->szMimeType);
+ if(pEncData->szEncryptionMethod)
+ free(pEncData->szEncryptionMethod);
+ if(pEncData->szXmlNs)
+ free(pEncData->szXmlNs);
+ // cleanup child objects
+ ddocMemBuf_free(&(pEncData->mbufEncryptedData));
+ if(pEncData->encProperties.szId)
+ free(pEncData->encProperties.szId);
+ for(i = 0; i < pEncData->encProperties.nEncryptionProperties; i++) {
+ if(pEncData->encProperties.arrEncryptionProperties[i]) {
+ err = dencEncryptionProperty_free(pEncData->encProperties.arrEncryptionProperties[i]);
+ if(err) return err;
+ }
+ }
+ if(pEncData->encProperties.arrEncryptionProperties)
+ free(pEncData->encProperties.arrEncryptionProperties);
+ ddocMemBuf_free(&(pEncData->mbufTransportKey));
+ for(i = 0; i < pEncData->nEncryptedKeys; i++) {
+ if(pEncData->arrEncryptedKeys[i]) {
+ err = dencEncryptedKey_free(pEncData->arrEncryptedKeys[i]);
+ if(err) return err;
+ }
+ }
+ free(pEncData->arrEncryptedKeys);
+ free(pEncData);
+ return err;
+}
+
+
+//======================< DEncEncryptedData - accessors >===================
+
+
+//--------------------------------------------------
+// Accessor for Id atribute of DEncEncryptedData object.
+// pEncData - pointer to DEncEncryptedData object [REQUIRED]
+// returns value of atribute or NULL.
+//--------------------------------------------------
+EXP_OPTION const char* dencEncryptedData_GetId(DEncEncryptedData* pEncData)
+{
+ RETURN_OBJ_IF_NULL(pEncData, NULL)
+ return pEncData->szId;
+}
+
+//--------------------------------------------------
+// Accessor for Type atribute of DEncEncryptedData object.
+// pEncData - pointer to DEncEncryptedData object [REQUIRED]
+// returns value of atribute or NULL.
+//--------------------------------------------------
+EXP_OPTION const char* dencEncryptedData_GetType(DEncEncryptedData* pEncData)
+{
+ RETURN_OBJ_IF_NULL(pEncData, NULL)
+ return pEncData->szType;
+}
+
+//--------------------------------------------------
+// Accessor for MimeType atribute of DEncEncryptedData object.
+// pEncData - pointer to DEncEncryptedData object [REQUIRED]
+// returns value of atribute or NULL.
+//--------------------------------------------------
+EXP_OPTION const char* dencEncryptedData_GetMimeType(DEncEncryptedData* pEncData)
+{
+ RETURN_OBJ_IF_NULL(pEncData, NULL)
+ return pEncData->szMimeType;
+}
+
+//--------------------------------------------------
+// Accessor for xmlns atribute of DEncEncryptedData object.
+// pEncData - pointer to DEncEncryptedData object [REQUIRED]
+// returns value of atribute or NULL.
+//--------------------------------------------------
+EXP_OPTION const char* dencEncryptedData_GetXmlNs(DEncEncryptedData* pEncData)
+{
+ RETURN_OBJ_IF_NULL(pEncData, NULL)
+ return pEncData->szXmlNs;
+}
+
+//--------------------------------------------------
+// Accessor for EncryptionMethod subelement of DEncEncryptedData object.
+// pEncData - pointer to DEncEncryptedData object [REQUIRED]
+// returns value of atribute or NULL.
+//--------------------------------------------------
+EXP_OPTION const char* dencEncryptedData_GetEncryptionMethod(DEncEncryptedData* pEncData)
+{
+ RETURN_OBJ_IF_NULL(pEncData, NULL)
+ return pEncData->szEncryptionMethod;
+}
+
+//--------------------------------------------------
+// Accessor for Id atribute of EncryptionProperties subelement of DEncEncryptedData object.
+// pEncData - pointer to DEncEncryptedData object [REQUIRED]
+// returns value of atribute or NULL.
+//--------------------------------------------------
+EXP_OPTION const char* dencEncryptedData_GetEncryptionPropertiesId(DEncEncryptedData* pEncData)
+{
+ RETURN_OBJ_IF_NULL(pEncData, NULL)
+ return pEncData->encProperties.szId;
+}
+
+//--------------------------------------------------
+// Accessor for count of EncryptionProperties subelement of DEncEncryptedData object.
+// pEncData - pointer to DEncEncryptedData object [REQUIRED]
+// returns count or -1 for error. Then use error API to check errors
+//--------------------------------------------------
+EXP_OPTION int dencEncryptedData_GetEncryptionPropertiesCount(DEncEncryptedData* pEncData)
+{
+ SET_LAST_ERROR_RETURN_IF_NOT(pEncData, ERR_NULL_POINTER, -1)
+ return pEncData->encProperties.nEncryptionProperties;
+}
+
+//--------------------------------------------------
+// Accessor for EncryptionProperties subelement of DEncEncryptedData object.
+// pEncData - pointer to DEncEncryptedData object [REQUIRED]
+// nIdx - index of EncryptionProperty object [REQUIRED]
+// returns EncryptionProperty pointer or NULL for error
+//--------------------------------------------------
+EXP_OPTION DEncEncryptionProperty* dencEncryptedData_GetEncryptionProperty(DEncEncryptedData* pEncData, int nIdx)
+{
+ RETURN_OBJ_IF_NULL(pEncData, NULL)
+ SET_LAST_ERROR_RETURN_IF_NOT(nIdx >= 0 && nIdx < pEncData->encProperties.nEncryptionProperties, ERR_DENC_BAD_PROP_IDX, NULL);
+ RETURN_OBJ_IF_NULL(pEncData->encProperties.arrEncryptionProperties[nIdx], 0);
+ return pEncData->encProperties.arrEncryptionProperties[nIdx];
+}
+
+//--------------------------------------------------
+// Finds EncryptionProperty by Name atribute
+// pEncData - pointer to DEncEncryptedData object [REQUIRED]
+// name - name of searched property
+// returns EncryptionProperty pointer or NULL for error
+//--------------------------------------------------
+EXP_OPTION DEncEncryptionProperty* dencEncryptedData_FindEncryptionPropertyByName(DEncEncryptedData* pEncData, const char* name)
+{
+ DEncEncryptionProperty* pEncProp = 0;
+ int i;
+
+ RETURN_OBJ_IF_NULL(pEncData, NULL)
+ RETURN_OBJ_IF_NULL(name, NULL)
+ for(i = 0; i < pEncData->encProperties.nEncryptionProperties; i++) {
+ if(pEncData->encProperties.arrEncryptionProperties[i] &&
+ pEncData->encProperties.arrEncryptionProperties[i]->szName &&
+ !strcmp(pEncData->encProperties.arrEncryptionProperties[i]->szName, name)) {
+ pEncProp = pEncData->encProperties.arrEncryptionProperties[i];
+ break;
+ }
+ }
+ return pEncProp;
+}
+
+//--------------------------------------------------
+// Retrieves the last EncryptionProperty subelement of DEncEncryptedData object.
+// pEncData - pointer to DEncEncryptedData object [REQUIRED]
+// returns EncryptionProperty pointer or NULL for error
+//--------------------------------------------------
+EXP_OPTION DEncEncryptionProperty* dencEncryptedData_GetLastEncryptionProperty(DEncEncryptedData* pEncData)
+{
+ int nIdx;
+ RETURN_OBJ_IF_NULL(pEncData, NULL)
+ nIdx = pEncData->encProperties.nEncryptionProperties -1;
+ SET_LAST_ERROR_RETURN_IF_NOT(nIdx >= 0 && nIdx < pEncData->encProperties.nEncryptionProperties, ERR_DENC_BAD_PROP_IDX, NULL);
+ RETURN_OBJ_IF_NULL(pEncData->encProperties.arrEncryptionProperties[nIdx], 0);
+ return pEncData->encProperties.arrEncryptionProperties[nIdx];
+}
+
+//--------------------------------------------------
+// Accessor for count of EncryptedKey subelement of DEncEncryptedData object.
+// pEncData - pointer to DEncEncryptedData object [REQUIRED]
+// returns count or -1 for error. Then use error API to check errors
+//--------------------------------------------------
+EXP_OPTION int dencEncryptedData_GetEncryptedKeyCount(DEncEncryptedData* pEncData)
+{
+ SET_LAST_ERROR_RETURN_IF_NOT(pEncData, ERR_NULL_POINTER, -1)
+ return pEncData->nEncryptedKeys;
+}
+
+//--------------------------------------------------
+// Accessor for EncryptedKey subelement of DEncEncryptedData object.
+// pEncData - pointer to DEncEncryptedData object [REQUIRED]
+// nIdx - index of EncryptedKey object [REQUIRED]
+// returns EncryptedKey pointer or NULL for error
+//--------------------------------------------------
+EXP_OPTION DEncEncryptedKey* dencEncryptedData_GetEncryptedKey(DEncEncryptedData* pEncData, int nIdx)
+{
+ RETURN_OBJ_IF_NULL(pEncData, NULL)
+ SET_LAST_ERROR_RETURN_IF_NOT(nIdx >= 0 && nIdx < pEncData->nEncryptedKeys, ERR_DENC_BAD_KEY_IDX, NULL);
+ RETURN_OBJ_IF_NULL(pEncData->arrEncryptedKeys[nIdx], 0);
+ return pEncData->arrEncryptedKeys[nIdx];
+}
+
+
+//--------------------------------------------------
+// Searches an EncryptedKey by recipients name
+// pEncData - pointer to DEncEncryptedData object [REQUIRED]
+// recipient - recipient name used to search the key [REQUIRED]
+// returns EncryptedKey pointer or NULL for error
+//--------------------------------------------------
+EXP_OPTION DEncEncryptedKey* dencEncryptedData_FindEncryptedKeyByRecipient(DEncEncryptedData* pEncData, const char* recipient)
+{
+ int i;
+ DEncEncryptedKey *pKey;
+
+ RETURN_OBJ_IF_NULL(pEncData, NULL)
+ RETURN_OBJ_IF_NULL(recipient, NULL)
+ for(i = 0; i < pEncData->nEncryptedKeys; i++) {
+ pKey = pEncData->arrEncryptedKeys[i];
+ if(pKey && pKey->szRecipient && !strcmp(pKey->szRecipient, recipient))
+ return pKey;
+ }
+ return NULL;
+}
+
+//--------------------------------------------------
+// Searches an EncryptedKey by certs CN field
+// pEncData - pointer to DEncEncryptedData object [REQUIRED]
+// cn - cert CN used to search the key [REQUIRED]
+// returns EncryptedKey pointer or NULL for error
+//--------------------------------------------------
+EXP_OPTION DEncEncryptedKey* dencEncryptedData_FindEncryptedKeyByCN(DEncEncryptedData* pEncData, const char* cn)
+{
+ int i, err = ERR_OK;
+ DEncEncryptedKey *pKey;
+ DigiDocMemBuf mbuf;
+
+ mbuf.pMem = 0;
+ mbuf.nLen = 0;
+ RETURN_OBJ_IF_NULL(pEncData, NULL)
+ RETURN_OBJ_IF_NULL(cn, NULL)
+ for(i = 0; i < pEncData->nEncryptedKeys; i++) {
+ pKey = pEncData->arrEncryptedKeys[i];
+ if(pKey && pKey->pCert) {
+ err = ddocCertGetSubjectCN(pKey->pCert, &mbuf);
+ if(!strcmp((const char*)mbuf.pMem, cn)) {
+ ddocMemBuf_free(&mbuf);
+ return pKey;
+ }
+ }
+ }
+ ddocMemBuf_free(&mbuf);
+ return NULL;
+}
+
+
+//--------------------------------------------------
+// Accessor for EncryptedKey subelement of DEncEncryptedData object.
+// pEncData - pointer to DEncEncryptedData object [REQUIRED]
+// returns EncryptedKey pointer or NULL for error
+//--------------------------------------------------
+EXP_OPTION DEncEncryptedKey* dencEncryptedData_GetLastEncryptedKey(DEncEncryptedData* pEncData)
+{
+ int nIdx;
+ RETURN_OBJ_IF_NULL(pEncData, NULL)
+ nIdx = pEncData->nEncryptedKeys-1;
+ SET_LAST_ERROR_RETURN_IF_NOT(nIdx >= 0 && nIdx < pEncData->nEncryptedKeys, ERR_DENC_BAD_KEY_IDX, NULL);
+ RETURN_OBJ_IF_NULL(pEncData->arrEncryptedKeys[nIdx], 0);
+ return pEncData->arrEncryptedKeys[nIdx];
+}
+
+//--------------------------------------------------
+// Accessor for encrypted data.
+// pEncData - pointer to DEncEncryptedData object [REQUIRED]
+// ppBuf - address for encrypted data pointer [REQUIRED]
+// returns error code or ERR_OK
+//--------------------------------------------------
+EXP_OPTION int dencEncryptedData_GetEncryptedData(DEncEncryptedData* pEncData, DigiDocMemBuf** ppBuf)
+{
+ RETURN_IF_NULL_PARAM(pEncData)
+ RETURN_IF_NULL_PARAM(ppBuf)
+ *ppBuf = &(pEncData->mbufEncryptedData);
+ return ERR_OK;
+}
+
+//--------------------------------------------------
+// Accessor for encrypted data status flag.
+// pEncData - pointer to DEncEncryptedData object [REQUIRED]
+// returns status or -1 for error. Then use error API to check errors
+//--------------------------------------------------
+EXP_OPTION int dencEncryptedData_GetEncryptedDataStatus(DEncEncryptedData* pEncData)
+{
+ SET_LAST_ERROR_RETURN_IF_NOT(pEncData, ERR_NULL_POINTER, -1)
+ return pEncData->nDataStatus;
+}
+
+
+//======================< DEncEncryptedData - mutators >===================
+
+//--------------------------------------------------
+// Mutatoror for Id atribute of DEncEncryptedData object.
+// pEncData - pointer to DEncEncryptedData object [REQUIRED]
+// value - new value for atribute [REQUIRED]
+// returns error code or ERR_OK
+//--------------------------------------------------
+EXP_OPTION int dencEncryptedData_SetId(DEncEncryptedData* pEncData, const char* value)
+{
+ int err = ERR_OK;
+ RETURN_IF_NULL_PARAM(pEncData)
+ RETURN_IF_NULL_PARAM(value)
+ err = ddocMemAssignString((char**)&(pEncData->szId), value);
+ return err;
+}
+
+//--------------------------------------------------
+// Mutatoror for Type atribute of DEncEncryptedData object.
+// pEncData - pointer to DEncEncryptedData object [REQUIRED]
+// value - new value for atribute [REQUIRED]
+// returns error code or ERR_OK
+//--------------------------------------------------
+EXP_OPTION int dencEncryptedData_SetType(DEncEncryptedData* pEncData, const char* value)
+{
+ int err = ERR_OK;
+ RETURN_IF_NULL_PARAM(pEncData)
+ RETURN_IF_NULL_PARAM(value)
+ err = ddocMemAssignString((char**)&(pEncData->szType), value);
+ return err;
+}
+
+//--------------------------------------------------
+// Mutatoror for MimeType atribute of DEncEncryptedData object.
+// pEncData - pointer to DEncEncryptedData object [REQUIRED]
+// value - new value for atribute [REQUIRED]
+// returns error code or ERR_OK
+//--------------------------------------------------
+EXP_OPTION int dencEncryptedData_SetMimeType(DEncEncryptedData* pEncData, const char* value)
+{
+ int err = ERR_OK;
+ RETURN_IF_NULL_PARAM(pEncData)
+ RETURN_IF_NULL_PARAM(value)
+ err = ddocMemAssignString((char**)&(pEncData->szMimeType), value);
+ return err;
+}
+
+//--------------------------------------------------
+// Mutatoror for xmlns atribute of DEncEncryptedData object.
+// pEncData - pointer to DEncEncryptedData object [REQUIRED]
+// value - new value for atribute [REQUIRED]
+// returns error code or ERR_OK
+//--------------------------------------------------
+EXP_OPTION int dencEncryptedData_SetXmlNs(DEncEncryptedData* pEncData, const char* value)
+{
+ int err = ERR_OK;
+ RETURN_IF_NULL_PARAM(pEncData)
+ RETURN_IF_NULL_PARAM(value)
+ err = dencValidateEncXmlNs(value);
+ if(err) return err;
+ err = ddocMemAssignString((char**)&(pEncData->szXmlNs), value);
+ return err;
+}
+
+
+//--------------------------------------------------
+// Mutatoror for EncryptionMethod subelement of DEncEncryptedData object.
+// pEncData - pointer to DEncEncryptedData object [REQUIRED]
+// value - new value for atribute [REQUIRED]
+// returns error code or ERR_OK
+//--------------------------------------------------
+EXP_OPTION int dencEncryptedData_SetEncryptionMethod(DEncEncryptedData* pEncData, const char* value)
+{
+ int err = ERR_OK;
+ RETURN_IF_NULL_PARAM(pEncData)
+ RETURN_IF_NULL_PARAM(value)
+ // replace the buggy URI with correct one to enable
+ // decrypting files with buggy URI but write only
+ // correct URI in new files
+ if(!strcmp(value, DENC_ENC_METHOD_RSA1_5_BUGGY))
+ value = DENC_ENC_METHOD_RSA1_5;
+ err = dencEncDataValidateEncMethod(value);
+ if(err) return err;
+ err = ddocMemAssignString((char**)&(pEncData->szEncryptionMethod), value);
+ return err;
+}
+
+//--------------------------------------------------
+// Adds unencrypted data to encrypted data element
+// waiting to be encrypted in next steps
+// pEncData - pointer to DEncEncryptedData object [REQUIRED]
+// data - new unencrypted data [REQUIRED]
+// len - length of data. Use -1 for null terminated strings [REQUIRED]
+// returns error code or ERR_OK
+//--------------------------------------------------
+EXP_OPTION int dencEncryptedData_AppendData(DEncEncryptedData* pEncData, const char* data, int len)
+{
+ ddocDebug(3, "dencEncryptedData_AppendData", "data: %s, len: %d", (data ? "OK" : "NULL"), len);
+ RETURN_IF_NULL_PARAM(pEncData)
+ RETURN_IF_NULL_PARAM(data)
+ SET_LAST_ERROR_RETURN_IF_NOT(pEncData->nDataStatus == DENC_DATA_STATUS_UNINITIALIZED ||
+ pEncData->nDataStatus == DENC_DATA_STATUS_UNENCRYPTED_AND_NOT_COMPRESSED,
+ ERR_DENC_DATA_STATUS, ERR_DENC_DATA_STATUS)
+ if(pEncData->nDataStatus == DENC_DATA_STATUS_UNINITIALIZED)
+ pEncData->nDataStatus = DENC_DATA_STATUS_UNENCRYPTED_AND_NOT_COMPRESSED;
+ return ddocMemAppendData(&(pEncData->mbufEncryptedData), data, len);
+}
+
+//--------------------------------------------------
+// Mutatoror for Id atribute of EncryptionProperties subelement of DEncEncryptedData object.
+// pEncData - pointer to DEncEncryptedData object [REQUIRED]
+// value - new value for atribute [REQUIRED]
+// returns error code or ERR_OK
+//--------------------------------------------------
+EXP_OPTION int dencEncryptedData_SetEncryptionPropertiesId(DEncEncryptedData* pEncData, const char* value)
+{
+ int err = ERR_OK;
+ RETURN_IF_NULL_PARAM(pEncData)
+ RETURN_IF_NULL_PARAM(value)
+ err = ddocMemAssignString((char**)&(pEncData->encProperties.szId), value);
+ return err;
+}
+
+//--------------------------------------------------
+// Deletes EncryptionProperties subelement of DEncEncryptedData object.
+// pEncData - pointer to DEncEncryptedData object [REQUIRED]
+// nIdx - index of EncryptionProperty object to be removed [REQUIRED]
+// returns error code or ERR_OK
+//--------------------------------------------------
+EXP_OPTION int dencEncryptedData_DeleteEncryptionProperty(DEncEncryptedData* pEncData, int nIdx)
+{
+ int err = ERR_OK, i;
+
+ RETURN_IF_NULL_PARAM(pEncData)
+ SET_LAST_ERROR_RETURN_IF_NOT(nIdx >= 0 && nIdx < pEncData->encProperties.nEncryptionProperties, ERR_DENC_BAD_PROP_IDX, ERR_DENC_BAD_PROP_IDX);
+ RETURN_IF_NULL_PARAM(pEncData->encProperties.arrEncryptionProperties[nIdx]);
+ // delete the given object
+ err = dencEncryptionProperty_free(pEncData->encProperties.arrEncryptionProperties[nIdx]);
+ if(err) return err;
+ pEncData->encProperties.arrEncryptionProperties[nIdx] = 0;
+ // move other objects 1 step close to array start
+ for(i = nIdx; i < pEncData->encProperties.nEncryptionProperties-1; i++)
+ pEncData->encProperties.arrEncryptionProperties[i] =
+ pEncData->encProperties.arrEncryptionProperties[i+1];
+ pEncData->encProperties.arrEncryptionProperties[pEncData->encProperties.nEncryptionProperties - 1] = 0;
+ pEncData->encProperties.nEncryptionProperties--;
+ return err;
+}
+
+//--------------------------------------------------
+// Deletes EncryptedKey subelement of DEncEncryptedData object.
+// pEncData - pointer to DEncEncryptedData object [REQUIRED]
+// nIdx - index of EncryptedKey object to be removed [REQUIRED]
+// returns error code or ERR_OK
+//--------------------------------------------------
+EXP_OPTION int dencEncryptedData_DeleteEncryptedKey(DEncEncryptedData* pEncData, int nIdx)
+{
+ int err = ERR_OK, i;
+
+ RETURN_IF_NULL_PARAM(pEncData)
+ SET_LAST_ERROR_RETURN_IF_NOT(nIdx >= 0 && nIdx < pEncData->nEncryptedKeys, ERR_DENC_BAD_KEY_IDX, ERR_DENC_BAD_KEY_IDX);
+ RETURN_IF_NULL_PARAM(pEncData->arrEncryptedKeys[nIdx]);
+ // delete the given object
+ err = dencEncryptedKey_free(pEncData->arrEncryptedKeys[nIdx]);
+ if(err) return err;
+ pEncData->arrEncryptedKeys[nIdx] = 0;
+ // move other objects 1 step closer to array start
+ for(i = nIdx; i < pEncData->nEncryptedKeys-1; i++)
+ pEncData->arrEncryptedKeys[i] =
+ pEncData->arrEncryptedKeys[i+1];
+ pEncData->arrEncryptedKeys[pEncData->nEncryptedKeys - 1] = 0;
+ pEncData->nEncryptedKeys--;
+ return err;
+}
+
+
+//--------------------------------------------------
+// Mutatoror for Id atribute of DEncEncryptedData object.
+// Sets the default value - "ED0"
+// pEncData - pointer to DEncEncryptedData object [REQUIRED]
+// returns error code or ERR_OK
+//--------------------------------------------------
+EXP_OPTION int dencEncryptedData_SetId_default(DEncEncryptedData* pEncData)
+{
+ int err = ERR_OK;
+ RETURN_IF_NULL_PARAM(pEncData)
+ err = ddocMemAssignString((char**)&(pEncData->szId), "ED0");
+ return err;
+}
+
+//--------------------------------------------------
+// Mutatoror for Type atribute of DEncEncryptedData object.
+// Sets the default value - "http://www.sk.ee/DigiDoc/v1.3.0/digidoc.xsd"
+// pEncData - pointer to DEncEncryptedData object [REQUIRED]
+// returns error code or ERR_OK
+//--------------------------------------------------
+EXP_OPTION int dencEncryptedData_SetType_default(DEncEncryptedData* pEncData)
+{
+ int err = ERR_OK;
+ RETURN_IF_NULL_PARAM(pEncData)
+ err = ddocMemAssignString((char**)&(pEncData->szType), DENC_ENCDATA_TYPE_DDOC);
+ return err;
+}
+
+//======================< DEncEncryptionProperty >===================
+
+//--------------------------------------------------
+// "Constructor" for EncryptionProperty
+// pEncData - pointer to DEncEncryptedData object [REQUIRED]
+// pEncProperty - address of buffer for new property object [REQUIRED]
+// szId - Id atribute of EncryptionProperty [OPTIONAL]
+// szTarget - Target atribute of EncryptionProperty [OPTIONAL]
+// szName - name atribute of EncryptionProperty [OPTIONAL]
+// szContent - content of EncryptionProperty [OPTIONAL]
+// returns error code or ERR_OK
+//--------------------------------------------------
+EXP_OPTION int dencEncryptionProperty_new(DEncEncryptedData* pEncData,
+ DEncEncryptionProperty** ppEncProperty,
+ const char* szId, const char* szTarget,
+ const char* szName, const char* szContent)
+{
+ int err = ERR_OK, nProps;
+ DEncEncryptionProperty **pProps, *pProp;
+
+ // check parameters
+ RETURN_IF_NULL_PARAM(pEncData)
+ RETURN_IF_NULL_PARAM(ppEncProperty)
+ *ppEncProperty = 0; // mark as not yet allocated
+ // allocate memory for pointer array
+ nProps = pEncData->encProperties.nEncryptionProperties + 1;
+ pProps = (DEncEncryptionProperty **)realloc(pEncData->encProperties.arrEncryptionProperties,
+ sizeof(DEncEncryptionProperty *) * nProps);
+ if(!pProps)
+ SET_LAST_ERROR_RETURN(ERR_BAD_ALLOC, ERR_BAD_ALLOC)
+ pEncData->encProperties.arrEncryptionProperties = pProps;
+ pProps[pEncData->encProperties.nEncryptionProperties] = 0;
+ // allocate memory for new property
+ pProp = (DEncEncryptionProperty*)malloc(sizeof(DEncEncryptionProperty));
+ if(!pProp)
+ SET_LAST_ERROR_RETURN(ERR_BAD_ALLOC, ERR_BAD_ALLOC)
+ memset(pProp, 0, sizeof(DEncEncryptionProperty));
+ pProps[pEncData->encProperties.nEncryptionProperties] = pProp;
+ *ppEncProperty = pProp;
+ pEncData->encProperties.nEncryptionProperties = nProps;
+ // set data
+ if(szId) {
+ err = ddocMemAssignString((char**)&(pProp->szId), szId);
+ if(err) return err;
+ }
+ if(szTarget) {
+ err = ddocMemAssignString((char**)&(pProp->szTarget), szTarget);
+ if(err) return err;
+ }
+ if(szName) {
+ err = ddocMemAssignString((char**)&(pProp->szName), szName);
+ if(err) return err;
+ }
+ if(szContent) {
+ err = ddocMemAssignString((char**)&(pProp->szContent), szContent);
+ if(err) return err;
+ }
+ return err;
+}
+
+//--------------------------------------------------
+// "Destructor" for EncryptionProperty
+// pEncProperty - address of buffer for new property object [REQUIRED]
+// returns error code or ERR_OK
+//--------------------------------------------------
+EXP_OPTION int dencEncryptionProperty_free(DEncEncryptionProperty* pEncProperty)
+{
+ RETURN_IF_NULL_PARAM(pEncProperty)
+ if(pEncProperty->szId)
+ free(pEncProperty->szId);
+ if(pEncProperty->szTarget)
+ free(pEncProperty->szTarget);
+ if(pEncProperty->szName)
+ free(pEncProperty->szName);
+ if(pEncProperty->szContent)
+ free(pEncProperty->szContent);
+ free(pEncProperty);
+ return ERR_OK;
+}
+
+//======================< DEncEncryptionProperty - accessors >===================
+
+//--------------------------------------------------
+// Accessor for Id atribute of EncryptionProperty object.
+// pEncProp - pointer to DEncEncryptionProperty object [REQUIRED]
+// returns value of atribute or NULL.
+//--------------------------------------------------
+EXP_OPTION const char* dencEncryptionProperty_GetId(DEncEncryptionProperty* pEncProp)
+{
+ RETURN_OBJ_IF_NULL(pEncProp, NULL)
+ return pEncProp->szId;
+}
+
+//--------------------------------------------------
+// Accessor for Target atribute of EncryptionProperty object.
+// pEncProp - pointer to DEncEncryptionProperty object [REQUIRED]
+// returns value of atribute or NULL.
+//--------------------------------------------------
+EXP_OPTION const char* dencEncryptionProperty_GetTarget(DEncEncryptionProperty* pEncProp)
+{
+ RETURN_OBJ_IF_NULL(pEncProp, NULL)
+ return pEncProp->szTarget;
+}
+
+//--------------------------------------------------
+// Accessor for Name atribute of EncryptionProperty object.
+// pEncProp - pointer to DEncEncryptionProperty object [REQUIRED]
+// returns value of atribute or NULL.
+//--------------------------------------------------
+EXP_OPTION const char* dencEncryptionProperty_GetName(DEncEncryptionProperty* pEncProp)
+{
+ RETURN_OBJ_IF_NULL(pEncProp, NULL)
+ return pEncProp->szName;
+}
+
+//--------------------------------------------------
+// Accessor for content of EncryptionProperty object.
+// pEncProp - pointer to DEncEncryptionProperty object [REQUIRED]
+// returns value of atribute or NULL.
+//--------------------------------------------------
+EXP_OPTION const char* dencEncryptionProperty_GetContent(DEncEncryptionProperty* pEncProp)
+{
+ RETURN_OBJ_IF_NULL(pEncProp, NULL)
+ return pEncProp->szContent;
+}
+
+//======================< DEncEncryptionProperty - mutators >===================
+
+//--------------------------------------------------
+// Mutatoror for Id atribute of DEncEncryptionProperty object.
+// pEncProp - pointer to DEncEncryptionProperty object [REQUIRED]
+// value - new value for atribute [REQUIRED]
+// returns error code or ERR_OK
+//--------------------------------------------------
+EXP_OPTION int dencEncryptionProperty_SetId(DEncEncryptionProperty* pEncProp, const char* value)
+{
+ int err = ERR_OK;
+ RETURN_IF_NULL_PARAM(pEncProp)
+ RETURN_IF_NULL_PARAM(value)
+ err = ddocMemAssignString((char**)&(pEncProp->szId), value);
+ return err;
+}
+
+//--------------------------------------------------
+// Mutatoror for Target atribute of DEncEncryptionProperty object.
+// pEncProp - pointer to DEncEncryptionProperty object [REQUIRED]
+// value - new value for atribute [REQUIRED]
+// returns error code or ERR_OK
+//--------------------------------------------------
+EXP_OPTION int dencEncryptionProperty_SetTarget(DEncEncryptionProperty* pEncProp, const char* value)
+{
+ int err = ERR_OK;
+ RETURN_IF_NULL_PARAM(pEncProp)
+ RETURN_IF_NULL_PARAM(value)
+ err = ddocMemAssignString((char**)&(pEncProp->szTarget), value);
+ return err;
+}
+
+//--------------------------------------------------
+// Mutatoror for Name atribute of DEncEncryptionProperty object.
+// pEncProp - pointer to DEncEncryptionProperty object [REQUIRED]
+// value - new value for atribute [REQUIRED]
+// returns error code or ERR_OK
+//--------------------------------------------------
+EXP_OPTION int dencEncryptionProperty_SetName(DEncEncryptionProperty* pEncProp, const char* value)
+{
+ int err = ERR_OK;
+ RETURN_IF_NULL_PARAM(pEncProp)
+ RETURN_IF_NULL_PARAM(value)
+ err = ddocMemAssignString((char**)&(pEncProp->szName), value);
+ return err;
+}
+
+//--------------------------------------------------
+// Mutatoror for content of DEncEncryptionProperty object.
+// pEncProp - pointer to DEncEncryptionProperty object [REQUIRED]
+// value - new value for atribute [REQUIRED]
+// returns error code or ERR_OK
+//--------------------------------------------------
+EXP_OPTION int dencEncryptionProperty_SetContent(DEncEncryptionProperty* pEncProp, const char* value)
+{
+ int err = ERR_OK;
+ RETURN_IF_NULL_PARAM(pEncProp)
+ RETURN_IF_NULL_PARAM(value)
+ err = ddocMemAssignString((char**)&(pEncProp->szContent), value);
+ return err;
+}
+
+
+//======================< DEncEncryptedKey >===================
+
+//--------------------------------------------------
+// Initializes transport key and init vector.
+// pEncData - pointer to DEncEncryptedData object [REQUIRED]
+// returns error code or ERR_OK
+//--------------------------------------------------
+int dencEncryptedData_initTransportKey(DEncEncryptedData* pEncData)
+{
+ int err = ERR_OK, l1;
+ char salt[8], indata[128], key[16];
+
+ RETURN_IF_NULL_PARAM(pEncData)
+ // init random generator
+#ifdef WIN32
+ RAND_screen();
+ RAND_bytes((unsigned char*)salt, sizeof(salt));
+ RAND_bytes((unsigned char*)indata, sizeof(indata));
+ RAND_bytes((unsigned char*)pEncData->initVector, sizeof(pEncData->initVector));
+#else
+ if((l1 = RAND_load_file("/dev/urandom", 1024)) > 0) {
+ ddocDebug(4, "dencEncryptedData_initTransportKey", "rand load: %d", l1);
+ RAND_bytes((unsigned char*)salt, sizeof(salt));
+ RAND_bytes((unsigned char*)indata, sizeof(indata));
+ RAND_bytes((unsigned char*)pEncData->initVector, sizeof(pEncData->initVector));
+ }
+#endif
+ // intialize IV
+ memset(key, 0, sizeof(key));
+ l1 = EVP_BytesToKey(EVP_aes_128_cbc(), EVP_md5(), (const unsigned char*)salt, (const unsigned char*)indata, sizeof(indata), 1, (unsigned char*)key, NULL);
+ ddocDebug(3, "dencEncryptedData_initTransportKey", "BytesToKey: %d", l1);
+ err = ddocMemAssignData(&(pEncData->mbufTransportKey), key, sizeof(key));
+ if(err) return err;
+ ddocDebug(3, "dencEncryptedData_initTransportKey", "RC: %d key: %d",
+ l1, pEncData->mbufTransportKey.nLen);
+ pEncData->nKeyStatus = DENC_KEY_STATUS_INITIALIZED;
+ return err;
+}
+
+//--------------------------------------------------
+// Validates the <EncryptionMethod> parameter. We
+// currently support only RSA-1.5
+// szEncMethod - value to be checked
+// returns error code or ERR_OK
+//--------------------------------------------------
+int dencEncKeyValidateEncMethod(const char* szEncMethod)
+{
+ if(szEncMethod && strcmp(szEncMethod, DENC_ENC_METHOD_RSA1_5))
+ SET_LAST_ERROR_RETURN(ERR_DENC_ENC_METHOD, ERR_DENC_ENC_METHOD)
+ else
+ return ERR_OK;
+}
+
+
+//--------------------------------------------------
+// Encrypts data with RSA public key (receivers key?)
+// pCert - receivers certificate
+// data - input data
+// dLen - input data length
+// result - encrypted data
+// resLen - output buffer length / used bytes
+//--------------------------------------------------
+int dencEncryptWithCert(X509* pCert, const char* data, int dLen, char* result, int* resLen)
+{
+ int err = ERR_OK;
+ EVP_PKEY* pkey;
+
+ // check parameters
+ RETURN_IF_NULL_PARAM(pCert)
+ RETURN_IF_NULL_PARAM(data)
+ RETURN_IF_NULL_PARAM(result)
+ RETURN_IF_NULL_PARAM(resLen)
+ // get certificates public key
+ err = GetPublicKey(&pkey, pCert);
+ if(err) return err;
+ // encrypt data
+ memset((char*)result, 0, *resLen);
+ *resLen = RSA_public_encrypt(dLen, (const unsigned char*)data, (unsigned char*)result, pkey->pkey.rsa, RSA_PKCS1_PADDING);
+ // cleanup
+ EVP_PKEY_free(pkey); // should I ???
+
+ return err;
+}
+
+
+//--------------------------------------------------
+// "Constructor" for EncryptedKey
+// Encrypts the transport key for a receiver
+// and stores encrypted key in memory
+// Call this function repeatedly for all receivers,
+// pEncData - pointer to DEncEncryptedData object [REQUIRED]
+// pEncKey - address of buffer for new encrypted key object [REQUIRED]
+// pCert - recevers certificate [REQUIRED]
+// szEncMethod - encryption method [REQUIRED]
+// szId - Id atribute of EncryptedKey [OPTIONAL]
+// szRecipient - Recipient atribute of EncryptedKey [OPTIONAL]
+// szKeyName - KeyName subelement of EncryptedKey [OPTIONAL]
+// szCarriedKeyName - CarriedKeyName subelement of EncryptedKey [OPTIONAL]
+// returns error code or ERR_OK
+//--------------------------------------------------
+EXP_OPTION int dencEncryptedKey_new(DEncEncryptedData* pEncData,
+ DEncEncryptedKey** pEncKey, X509* pCert,
+ const char* szEncMethod, const char* szId,
+ const char* szRecipient, const char* szKeyName,
+ const char* szCarriedKeyName)
+{
+ int err = ERR_OK, nKeys, l1;
+ DEncEncryptedKey **pKeys, *pKey;
+ //AM 14.10.08 from 130 to 300
+ char tkey[300];
+
+ ddocDebug(3, "dencEncryptedKey_new", "cert: %s, method: %s, id: %s, recipient: %s, keyname: %s carriedkeyname: %s",
+ (pCert ? "OK" : "NULL"), szEncMethod, szId, szRecipient, szKeyName, szCarriedKeyName);
+ // check parameters
+ RETURN_IF_NULL_PARAM(pEncData)
+ RETURN_IF_NULL_PARAM(pEncKey)
+ err = dencEncKeyValidateEncMethod(szEncMethod);
+ if(err) return err;
+ *pEncKey = 0;
+ // increase the buffer for EncryptedKey pointers
+ nKeys = pEncData->nEncryptedKeys + 1;
+ pKeys = (DEncEncryptedKey **)realloc(pEncData->arrEncryptedKeys, sizeof(DEncEncryptedKey *) * nKeys);
+ if(!pKeys)
+ SET_LAST_ERROR_RETURN(ERR_BAD_ALLOC, ERR_BAD_ALLOC)
+ pEncData->arrEncryptedKeys = pKeys;
+ pEncData->arrEncryptedKeys[pEncData->nEncryptedKeys] = 0;
+ pKey = (DEncEncryptedKey*)malloc(sizeof(DEncEncryptedKey));
+ if(!pKey)
+ SET_LAST_ERROR_RETURN(ERR_BAD_ALLOC, ERR_BAD_ALLOC)
+ pEncData->arrEncryptedKeys[pEncData->nEncryptedKeys] = pKey;
+ pEncData->nEncryptedKeys = nKeys;
+ *pEncKey = pKey;
+ memset(pKey, 0, sizeof(DEncEncryptedKey));
+ // set required parameters
+ if(szEncMethod) {
+ err = ddocMemAssignString((char**)&(pKey->szEncryptionMethod), szEncMethod);
+ if(err) return err;
+ }
+ if(pCert) {
+ if(!ddocCertCheckKeyUsage(pCert, KUIDX_KEY_ENCIPHERMENT)) {
+ ddocDebug(1, "dencEncryptedKey_new", "ENC: cert has no key-encipherment key usage");
+ SET_LAST_ERROR(ERR_CERT_INVALID);
+ return ERR_CERT_INVALID;
+ } else
+ ddocDebug(3, "dencEncryptedKey_new", "ENC: cert has key-encipherment key usage");
+ pKey->pCert = pCert;
+ }
+ // set optional parameters
+ if(szId) {
+ err = ddocMemAssignString((char**)&(pKey->szId), szId);
+ if(err) return err;
+ }
+ if(szRecipient) {
+ err = ddocMemAssignString((char**)&(pKey->szRecipient), szRecipient);
+ if(err) return err;
+ }
+ if(szKeyName) {
+ err = ddocMemAssignString((char**)&(pKey->szKeyName), szKeyName);
+ if(err) return err;
+ }
+ if(szCarriedKeyName) {
+ err = ddocMemAssignString((char**)&(pKey->szCarriedKeyName), szCarriedKeyName);
+ if(err) return err;
+ }
+ if(pCert) {
+ // encrypt the key
+ if(pEncData->nKeyStatus == DENC_KEY_STATUS_UNINITIALIZED) {
+ err = dencEncryptedData_initTransportKey(pEncData);
+ if(err) return err;
+ }
+ l1 = sizeof(tkey);
+ err = dencEncryptWithCert(pCert, (const char*)pEncData->mbufTransportKey.pMem,
+ pEncData->mbufTransportKey.nLen, tkey, &l1);
+ if(err) return err;
+ //if(pKey)dencEncryptedKey_/free(&pKey);
+ //pKey = (DEncEncryptedKey*)malloc(sizeof(DEncEncryptedKey));
+ //memset(pKey, 0, sizeof(DEncEncryptedKey));
+ err = ddocMemAssignData(&(pKey->mbufTransportKey), tkey, l1);
+ }
+ return err;
+}
+
+//--------------------------------------------------
+// "Destructor" for EncryptedKey
+// pEncKey - address of buffer for new encrypted key object [REQUIRED]
+// returns error code or ERR_OK
+//--------------------------------------------------
+EXP_OPTION int dencEncryptedKey_free(DEncEncryptedKey* pEncKey)
+{
+ RETURN_IF_NULL_PARAM(pEncKey)
+ if(pEncKey->szId)
+ free(pEncKey->szId);
+ if(pEncKey->szRecipient)
+ free(pEncKey->szRecipient);
+ if(pEncKey->szEncryptionMethod)
+ free(pEncKey->szEncryptionMethod);
+ if(pEncKey->szKeyName)
+ free(pEncKey->szKeyName);
+ if(pEncKey->szCarriedKeyName)
+ free(pEncKey->szCarriedKeyName);
+ if(pEncKey->pCert)
+ X509_free(pEncKey->pCert);
+ ddocMemBuf_free(&(pEncKey->mbufTransportKey));
+ free(pEncKey);
+ return ERR_OK;
+}
+
+//======================< DEncEncryptedKey - acessors >===================
+
+
+//--------------------------------------------------
+// Accessor for Id atribute of DEncEncryptedKey object.
+// pEncKey - pointer to DEncEncryptedKey object [REQUIRED]
+// returns value of atribute or NULL.
+//--------------------------------------------------
+EXP_OPTION const char* dencEncryptedKey_GetId(DEncEncryptedKey* pEncKey)
+{
+ RETURN_OBJ_IF_NULL(pEncKey, NULL)
+ return pEncKey->szId;
+}
+
+//--------------------------------------------------
+// Accessor for Recipient atribute of DEncEncryptedKey object.
+// pEncKey - pointer to DEncEncryptedKey object [REQUIRED]
+// returns value of atribute or NULL.
+//--------------------------------------------------
+EXP_OPTION const char* dencEncryptedKey_GetRecipient(DEncEncryptedKey* pEncKey)
+{
+ RETURN_OBJ_IF_NULL(pEncKey, NULL)
+ return pEncKey->szRecipient;
+}
+
+//--------------------------------------------------
+// Accessor for EncryptionMethod subelement of DEncEncryptedKey object.
+// pEncKey - pointer to DEncEncryptedKey object [REQUIRED]
+// returns value of atribute or NULL.
+//--------------------------------------------------
+EXP_OPTION const char* dencEncryptedKey_GetEncryptionMethod(DEncEncryptedKey* pEncKey)
+{
+ RETURN_OBJ_IF_NULL(pEncKey, NULL)
+ return pEncKey->szEncryptionMethod;
+}
+
+//--------------------------------------------------
+// Accessor for KeyName subelement of DEncEncryptedKey object.
+// pEncKey - pointer to DEncEncryptedKey object [REQUIRED]
+// returns value of atribute or NULL.
+//--------------------------------------------------
+EXP_OPTION const char* dencEncryptedKey_GetKeyName(DEncEncryptedKey* pEncKey)
+{
+ RETURN_OBJ_IF_NULL(pEncKey, NULL)
+ return pEncKey->szKeyName;
+}
+
+//--------------------------------------------------
+// Accessor for CarriedKeyName subelement of DEncEncryptedKey object.
+// pEncKey - pointer to DEncEncryptedKey object [REQUIRED]
+// returns value of atribute or NULL.
+//--------------------------------------------------
+EXP_OPTION const char* dencEncryptedKey_GetCarriedKeyName(DEncEncryptedKey* pEncKey)
+{
+ RETURN_OBJ_IF_NULL(pEncKey, NULL)
+ return pEncKey->szCarriedKeyName;
+}
+
+//--------------------------------------------------
+// Accessor for certificate of DEncEncryptedKey object.
+// pEncKey - pointer to DEncEncryptedKey object [REQUIRED]
+// returns value of atribute or NULL.
+//--------------------------------------------------
+EXP_OPTION X509* dencEncryptedKey_GetCertificate(DEncEncryptedKey* pEncKey)
+{
+ RETURN_OBJ_IF_NULL(pEncKey, NULL)
+ return pEncKey->pCert;
+}
+
+//======================< DEncEncryptedKey - mutators >===================
+
+//--------------------------------------------------
+// Mutatoror for Id atribute of DEncEncryptedKey object.
+// pEncKey - pointer to DEncEncryptedKey object [REQUIRED]
+// value - new value for atribute [REQUIRED]
+// returns error code or ERR_OK
+//--------------------------------------------------
+EXP_OPTION int dencEncryptedKey_SetId(DEncEncryptedKey* pEncKey, const char* value)
+{
+ int err = ERR_OK;
+ RETURN_IF_NULL_PARAM(pEncKey)
+ RETURN_IF_NULL_PARAM(value)
+ err = ddocMemAssignString((char**)&(pEncKey->szId), value);
+ return err;
+}
+
+//--------------------------------------------------
+// Mutatoror for Recipient atribute of DEncEncryptedKey object.
+// pEncKey - pointer to DEncEncryptedKey object [REQUIRED]
+// value - new value for atribute [REQUIRED]
+// returns error code or ERR_OK
+//--------------------------------------------------
+EXP_OPTION int dencEncryptedKey_SetRecipient(DEncEncryptedKey* pEncKey, const char* value)
+{
+ int err = ERR_OK;
+ RETURN_IF_NULL_PARAM(pEncKey)
+ RETURN_IF_NULL_PARAM(value)
+ err = ddocMemAssignString((char**)&(pEncKey->szRecipient), value);
+ return err;
+}
+
+//--------------------------------------------------
+// Mutatoror for EncryptionMethod subelement of DEncEncryptedKey object.
+// pEncKey - pointer to DEncEncryptedKey object [REQUIRED]
+// value - new value for atribute [REQUIRED]
+// returns error code or ERR_OK
+//--------------------------------------------------
+EXP_OPTION int dencEncryptedKey_SetEncryptionMethod(DEncEncryptedKey* pEncKey, const char* value)
+{
+ int err = ERR_OK;
+ RETURN_IF_NULL_PARAM(pEncKey)
+ RETURN_IF_NULL_PARAM(value)
+ err = dencEncKeyValidateEncMethod(value);
+ if(err) return err;
+ err = ddocMemAssignString((char**)&(pEncKey->szEncryptionMethod), value);
+ return err;
+}
+
+//--------------------------------------------------
+// Mutatoror for KeyName subelement of DEncEncryptedKey object.
+// pEncKey - pointer to DEncEncryptedKey object [REQUIRED]
+// value - new value for atribute [REQUIRED]
+// returns error code or ERR_OK
+//--------------------------------------------------
+EXP_OPTION int dencEncryptedKey_SetKeyName(DEncEncryptedKey* pEncKey, const char* value)
+{
+ int err = ERR_OK;
+ RETURN_IF_NULL_PARAM(pEncKey)
+ RETURN_IF_NULL_PARAM(value)
+ err = ddocMemAssignString((char**)&(pEncKey->szKeyName), value);
+ return err;
+}
+
+//--------------------------------------------------
+// Mutatoror for CarriedKeyName subelement of DEncEncryptedKey object.
+// pEncKey - pointer to DEncEncryptedKey object [REQUIRED]
+// value - new value for atribute [REQUIRED]
+// returns error code or ERR_OK
+//--------------------------------------------------
+EXP_OPTION int dencEncryptedKey_SetCarriedKeyName(DEncEncryptedKey* pEncKey, const char* value)
+{
+ int err = ERR_OK;
+ RETURN_IF_NULL_PARAM(pEncKey)
+ RETURN_IF_NULL_PARAM(value)
+ err = ddocMemAssignString((char**)&(pEncKey->szCarriedKeyName), value);
+ return err;
+}
+
+//--------------------------------------------------
+// Mutatoror for certificate of DEncEncryptedKey object.
+// pEncKey - pointer to DEncEncryptedKey object [REQUIRED]
+// value - new value for atribute [REQUIRED]
+// returns error code or ERR_OK
+//--------------------------------------------------
+EXP_OPTION int dencEncryptedKey_SetCertificate(DEncEncryptedKey* pEncKey, X509* value)
+{
+ RETURN_IF_NULL_PARAM(pEncKey)
+ RETURN_IF_NULL_PARAM(value)
+ pEncKey->pCert = value;
+ return ERR_OK;
+}
+
+//==========< general crypto fucntions >============
+
+//--------------------------------------------------
+// Locates the correct EncryptedKey object by reading
+// users certificate from smartcard and searching the
+// right EncryptedKey object
+// pEncData - pointer to DEncEncryptedData object [REQUIRED]
+// ppEncKey - address of a buffer for EncryptedKey pointer [REQUIRED]
+// returns error code or ERR_OK
+//--------------------------------------------------
+EXP_OPTION int dencEncryptedData_findEncryptedKeyByPKCS11(DEncEncryptedData* pEncData, DEncEncryptedKey** ppEncKey)
+{
+ return dencEncryptedData_findEncryptedKeyByPKCS11UsingSlot(pEncData, ppEncKey, 0);
+}
+
+//--------------------------------------------------
+// Locates the correct EncryptedKey object by reading
+// users certificate from smartcard and searching the
+// right EncryptedKey object
+// pEncData - pointer to DEncEncryptedData object [REQUIRED]
+// ppEncKey - address of a buffer for EncryptedKey pointer [REQUIRED]
+// nSlot - slot nr
+// returns error code or ERR_OK
+//--------------------------------------------------
+EXP_OPTION int dencEncryptedData_findEncryptedKeyByPKCS11UsingSlot(DEncEncryptedData* pEncData, DEncEncryptedKey** ppEncKey, int nSlot)
+{
+ int err = ERR_OK, i, n;
+ X509 *pCert = 0;
+ DEncEncryptedKey *pEncKey = 0;
+ char buf1[100], buf2[100];
+
+ RETURN_IF_NULL_PARAM(pEncData)
+ RETURN_IF_NULL_PARAM(ppEncKey)
+ *ppEncKey = 0; // mark as not found yet
+ err = findUsersCertificate(nSlot, &pCert);
+ if(err) return err;
+ memset(buf1, 0, sizeof(buf1));
+ err = ReadCertSerialNumber(buf1, sizeof(buf1), pCert);
+ if(err) return err;
+ ddocDebug(3, "dencEncryptedData_findEncryptedKeyByPKCS11UsingSlot", "Users cert: %s", buf1);
+ n = dencEncryptedData_GetEncryptedKeyCount(pEncData);
+ for(i = 0; i < n; i++) {
+ pEncKey = dencEncryptedData_GetEncryptedKey(pEncData, i);
+ memset(buf2, 0, sizeof(buf2));
+ err = ReadCertSerialNumber(buf2, sizeof(buf2), pEncKey->pCert);
+ ddocDebug(3, "dencEncryptedData_findEncryptedKeyByPKCS11UsingSlot", "Key: %d cert: %s", i, buf2);
+ if(!err && !strcmp(buf1, buf2)) {
+ *ppEncKey = pEncKey;
+ ddocDebug(3, "dencEncryptedData_findEncryptedKeyByPKCS11UsingSlot", "Using key: %d cert: %s", i, buf2);
+ break;
+ }
+ }
+ if(pCert)
+ X509_free(pCert);
+ if(!*ppEncKey) {
+ ddocDebug(3, "dencEncryptedData_findEncryptedKeyByPKCS11UsingSlot", "No matching key found!");
+ SET_LAST_ERROR_RETURN(ERR_DENC_NO_KEY_FOUND, ERR_DENC_NO_KEY_FOUND)
+ }
+ return err;
+}
+
+//--------------------------------------------------
+// Locates the correct EncryptedKey object by reading
+// users certificate and private key from pkcs12 file and searching the
+// right EncryptedKey object
+// pEncData - pointer to DEncEncryptedData object [REQUIRED]
+// ppEncKey - address of a buffer for EncryptedKey pointer [REQUIRED]
+// ppKey - address of private key pointer. Caller must free [REQUIRED]
+// szPkcs12File - pkcs12 file name [REQUIRED]
+// szPasswd - pkcs12 file password [REQUIRED]. Might be empty?
+// returns error code or ERR_OK
+//--------------------------------------------------
+EXP_OPTION int dencEncryptedData_findEncryptedKeyByPKCS12(DEncEncryptedData* pEncData, DEncEncryptedKey** ppEncKey,
+ EVP_PKEY** ppKey, const char* szPkcs12File, const char* szPasswd)
+{
+ int err = ERR_OK, i, n;
+ X509 *pCert = 0;
+ DEncEncryptedKey *pEncKey = 0;
+ char buf1[100], buf2[100];
+
+ RETURN_IF_NULL_PARAM(pEncData)
+ RETURN_IF_NULL_PARAM(ppEncKey)
+ RETURN_IF_NULL_PARAM(ppKey)
+ *ppEncKey = 0; // mark as not found yet
+ *ppKey = 0;
+ err = ReadCertificateByPKCS12(&pCert, szPkcs12File, szPasswd, ppKey);
+ if(err) return err;
+ memset(buf1, 0, sizeof(buf1));
+ err = ReadCertSerialNumber(buf1, sizeof(buf1), pCert);
+ if(err) return err;
+ n = dencEncryptedData_GetEncryptedKeyCount(pEncData);
+ for(i = 0; i < n; i++) {
+ pEncKey = dencEncryptedData_GetEncryptedKey(pEncData, i);
+ memset(buf2, 0, sizeof(buf2));
+ err = ReadCertSerialNumber(buf2, sizeof(buf2), pEncKey->pCert);
+ if(!err && !strcmp(buf1, buf2)) {
+ *ppEncKey = pEncKey;
+ break;
+ }
+ }
+ if(pCert)
+ X509_free(pCert);
+ if(!*ppEncKey)
+ SET_LAST_ERROR_RETURN(ERR_DENC_NO_KEY_FOUND, ERR_DENC_NO_KEY_FOUND)
+ return err;
+}
+
+
+
+//--------------------------------------------------
+// AES encrypt/decrypt operations
+// pInData - input data
+// pOutData - output buffer
+// pKey - AES key
+// operation - ENCRYPT/DECRYPT
+// iv - init vector for the cipher
+//--------------------------------------------------
+int encryptDecrypt(DigiDocMemBuf *pInData, DigiDocMemBuf *pOutData,
+ DigiDocMemBuf *pKey, int operation, const char* iv)
+{
+ EVP_CIPHER_CTX ectx;
+ int err = ERR_OK, len, i, nInLen, nOutLen;
+ char padBuf[16], *pInMem;
+ int lOrigLen, lEncLen;
+
+ ddocDebug(3, "encryptDecrypt", "Input: %d, output: %d, key: %d, operation: %s",
+ (pInData ? pInData->nLen : 0), (pOutData ? pOutData->nLen : 0),
+ (pKey ? pKey->nLen : 0), (operation ? "ENCRYPT" : "DECRYPT"));
+ RETURN_IF_NULL_PARAM(pInData)
+ RETURN_IF_NULL_PARAM(pOutData)
+ RETURN_IF_NULL_PARAM(pKey)
+ nInLen = pInData->nLen;
+ pInMem = (char*)pInData->pMem;
+ // use the first 16 bytes as IV
+ // and remove this data from data to be decrypted
+ if(operation == DECRYPT) {
+ memcpy((char*)iv, (const char*)pInData->pMem, 16);
+ for(i = 0; i < 16; i++)
+ ddocDebug(3, "encryptDecrypt", "IV pos: %d = %d", i, iv[i]);
+ nInLen -= 16;
+ pInMem += 16;
+ ddocDebug(3, "encryptDecrypt", "DECRYPT using iv input left: %d", nInLen);
+ }
+ lOrigLen = lEncLen = 0;
+ len = nInLen % 16;
+ if(operation == ENCRYPT) {
+ len = 16 - (nInLen % 16);
+ ddocDebug(3, "encryptDecrypt", "Input len: %d adding padding: %d\n", nInLen, len);
+ memset(padBuf, 0, sizeof(padBuf));
+ for(i = 0; i < len; i++)
+ padBuf[i] = 0;
+ padBuf[len-1] = (unsigned char)len; // number of padded chars
+ }
+ if(pOutData->pMem)
+ free(pOutData->pMem);
+ pOutData->nLen = nInLen * 2 + len * 2;
+ if(operation == ENCRYPT)
+ pOutData->nLen += 16;
+ nOutLen = pOutData->nLen;
+ pOutData->pMem = (char*)malloc(pOutData->nLen);
+ memset(pOutData->pMem, 0, pOutData->nLen);
+ if(!pOutData->pMem)
+ SET_LAST_ERROR_RETURN(ERR_BAD_ALLOC, ERR_BAD_ALLOC)
+ ddocDebug(3, "encryptDecrypt", "Allocated: %d", pOutData->nLen);
+ // copy init vector to begin of output data
+ if(operation == ENCRYPT)
+ memcpy(pOutData->pMem, iv, 16);
+ EVP_CIPHER_CTX_init(&ectx);
+ EVP_CipherInit_ex(&ectx, EVP_aes_128_cbc(), NULL, (const unsigned char*)pKey->pMem, (const unsigned char*)iv, operation);
+ //EVP_CIPHER_CTX_set_padding(&ectx, 1);
+ //checkErrors();
+ lOrigLen += nInLen;
+ i = nOutLen;
+ // set initial position for encryted data
+ if(operation == ENCRYPT)
+ pOutData->nLen = 16;
+ else
+ pOutData->nLen = 0;
+ EVP_CipherUpdate(&ectx, (unsigned char*)pOutData->pMem + pOutData->nLen, &i, (const unsigned char*)pInMem, nInLen);
+ lEncLen += i;
+ pOutData->nLen += i;
+ ddocDebug(3, "encryptDecrypt", "Initial update: %d into: %d -> %d", nInLen, nOutLen, i);
+
+ //TODO: in 1.1 don't check len
+ if(len && operation == ENCRYPT) {
+ EVP_CipherUpdate(&ectx, (unsigned char*)pOutData->pMem + pOutData->nLen, &i, (const unsigned char*)padBuf, len);
+ ddocDebug(3, "encryptDecrypt", "Padding update: %d -> %d", len, i);
+ pOutData->nLen += i;
+ lOrigLen += len;
+ nOutLen -= i;
+ lEncLen += i;
+ }
+ i = nOutLen;
+ EVP_CipherFinal_ex(&ectx, (unsigned char*)pOutData->pMem + pOutData->nLen, &i);
+ ddocDebug(3, "encryptDecrypt", "Final update: %d into: %d", i, nOutLen);
+ pOutData->nLen += i;
+ lEncLen += i;
+ ddocDebug(3, "encryptDecrypt", "Total input: %d encrypted: %d", lOrigLen, lEncLen);
+ EVP_CIPHER_CTX_cleanup(&ectx);
+ if(operation == DECRYPT) {
+ // check ANSI X.923 padding
+ len = (int)(unsigned char)((char*)pOutData->pMem)[pOutData->nLen-1];
+ if(len > 0 && len <= 16) {
+ ddocDebug(3, "encryptDecrypt", "X.923 check padding: %d", len);
+ // check if all previous are 0-s
+ for(i = pOutData->nLen - len; i < pOutData->nLen - 1; i++) {
+ ddocDebug(3, "encryptDecrypt", "Byte at: %d = %d", i, ((char*)pOutData->pMem)[i]);
+ if(((char*)pOutData->pMem)[i])
+ len = 0; // set not matched flag
+ }
+ if(len >= 1) {
+ ddocDebug(3, "encryptDecrypt", "X.923 decrypted len: %d reduce by: %d", pOutData->nLen, len);
+ pOutData->nLen -= len;
+ }
+ else
+ ddocDebug(3, "encryptDecrypt", "X.923 decrypted len remains: %d", pOutData->nLen);
+ }
+ else
+ ddocDebug(3, "encryptDecrypt", "Impossible padding: %d", len);
+ }
+ return err;
+}
+
+//--------------------------------------------------
+// Encrypts data with the generated key
+// pEncData - pointer to DEncEncryptedData object [REQUIRED]
+// nCompressOption - flag: DENC_COMPRESS_ALLWAYS,
+// DENC_COMPRESS_NEVER or DENC_COMPRESS_BEST_EFFORT
+// returns error code or ERR_OK
+//--------------------------------------------------
+EXP_OPTION int dencEncryptedData_encryptData(DEncEncryptedData* pEncData, int nCompressOption)
+{
+ int err = ERR_OK;
+ DigiDocMemBuf outData;
+
+ RETURN_IF_NULL_PARAM(pEncData)
+ // check compression
+ if(nCompressOption == DENC_COMPRESS_ALLWAYS ||
+ nCompressOption == DENC_COMPRESS_BEST_EFFORT) {
+ err = dencEncryptedData_compressData(pEncData, nCompressOption);
+ if(err) return err;
+ }
+ // check data status
+ if(pEncData->nDataStatus != DENC_DATA_STATUS_UNENCRYPTED_AND_NOT_COMPRESSED &&
+ pEncData->nDataStatus != DENC_DATA_STATUS_UNENCRYPTED_AND_COMPRESSED)
+ SET_LAST_ERROR_RETURN(ERR_DENC_DATA_STATUS, ERR_DENC_DATA_STATUS)
+ // init transport key if necessary
+ if(pEncData->nKeyStatus == DENC_KEY_STATUS_UNINITIALIZED) {
+ err = dencEncryptedData_initTransportKey(pEncData);
+ if(err) return err;
+ }
+ outData.pMem = 0;
+ outData.nLen = 0;
+ err = encryptDecrypt(&(pEncData->mbufEncryptedData), &outData,
+ &(pEncData->mbufTransportKey), ENCRYPT,
+ pEncData->initVector);
+ if(!err) {
+ free(pEncData->mbufEncryptedData.pMem);
+ pEncData->mbufEncryptedData.pMem = outData.pMem;
+ pEncData->mbufEncryptedData.nLen = outData.nLen;
+ // check if we have original length in <EncryptionProperties>
+ if(pEncData->nDataStatus == DENC_DATA_STATUS_UNENCRYPTED_AND_NOT_COMPRESSED)
+ pEncData->nDataStatus = DENC_DATA_STATUS_ENCRYPTED_AND_NOT_COMPRESSED;
+ else
+ pEncData->nDataStatus = DENC_DATA_STATUS_ENCRYPTED_AND_COMPRESSED;
+ }
+ return err;
+}
+
+//--------------------------------------------------
+// Decrypts data with the generated key
+// pEncData - pointer to DEncEncryptedData object [REQUIRED]
+// returns error code or ERR_OK
+//--------------------------------------------------
+EXP_OPTION int dencEncryptedData_decryptData(DEncEncryptedData* pEncData)
+{
+ int err = ERR_OK;
+ DigiDocMemBuf outData;
+
+ RETURN_IF_NULL_PARAM(pEncData)
+ // check data status
+ if(pEncData->nDataStatus != DENC_DATA_STATUS_ENCRYPTED_AND_NOT_COMPRESSED &&
+ pEncData->nDataStatus != DENC_DATA_STATUS_ENCRYPTED_AND_COMPRESSED)
+ SET_LAST_ERROR_RETURN(ERR_DENC_DATA_STATUS, ERR_DENC_DATA_STATUS)
+ // check transport key
+ if(pEncData->nKeyStatus == DENC_KEY_STATUS_UNINITIALIZED)
+ SET_LAST_ERROR_RETURN(ERR_DENC_KEY_STATUS, ERR_DENC_KEY_STATUS)
+ outData.pMem = 0;
+ outData.nLen = 0;
+ err = encryptDecrypt(&(pEncData->mbufEncryptedData), &outData,
+ &(pEncData->mbufTransportKey), DECRYPT,
+ pEncData->initVector);
+ if(!err) {
+ free(pEncData->mbufEncryptedData.pMem);
+ pEncData->mbufEncryptedData.pMem = outData.pMem;
+ pEncData->mbufEncryptedData.nLen = outData.nLen;
+ if(pEncData->nDataStatus == DENC_DATA_STATUS_ENCRYPTED_AND_NOT_COMPRESSED)
+ pEncData->nDataStatus = DENC_DATA_STATUS_UNENCRYPTED_AND_NOT_COMPRESSED;
+ else
+ pEncData->nDataStatus = DENC_DATA_STATUS_UNENCRYPTED_AND_COMPRESSED;
+ }
+ // decompress if necessary
+ if(!err && pEncData->nDataStatus == DENC_DATA_STATUS_UNENCRYPTED_AND_COMPRESSED)
+ err = dencEncryptedData_decompressData(pEncData);
+ return err;
+}
+
+
+//--------------------------------------------------
+// Decrypts data transport key with ID card and
+// then decrypts the data with the transport key.
+// pEncData - pointer to DEncEncryptedData object [REQUIRED]
+// pEncKey - transport key to decrypt [REQUIRED]
+// pin - pin code for smart card [REQUIRED]
+// returns error code or ERR_OK
+//--------------------------------------------------
+EXP_OPTION int dencEncryptedData_decrypt(DEncEncryptedData* pEncData,
+ DEncEncryptedKey* pEncKey,
+ const char* pin)
+{
+ int nSlot = nSlot = ConfigItem_lookup_int("DIGIDOC_AUTH_KEY_SLOT", 0);
+ return dencEncryptedData_decryptUsingSlot(pEncData, pEncKey, pin, nSlot);
+}
+
+//--------------------------------------------------
+// Decrypts data transport key with ID card and
+// then decrypts the data with the transport key.
+// pEncData - pointer to DEncEncryptedData object [REQUIRED]
+// pEncKey - transport key to decrypt [REQUIRED]
+// pin - pin code for smart card [REQUIRED]
+// nSlot - slot nr
+// returns error code or ERR_OK
+//--------------------------------------------------
+EXP_OPTION int dencEncryptedData_decryptUsingSlot(DEncEncryptedData* pEncData,
+ DEncEncryptedKey* pEncKey,
+ const char* pin, int nSlot)
+{
+ int err = ERR_OK, len;
+ DEncEncryptionProperty* pEncProp;
+ long l;
+
+ RETURN_IF_NULL_PARAM(pEncData)
+ RETURN_IF_NULL_PARAM(pEncKey)
+ RETURN_IF_NULL_PARAM(pin)
+ // check data status
+ if(pEncData->nDataStatus != DENC_DATA_STATUS_ENCRYPTED_AND_NOT_COMPRESSED &&
+ pEncData->nDataStatus != DENC_DATA_STATUS_ENCRYPTED_AND_COMPRESSED)
+ SET_LAST_ERROR_RETURN(ERR_DENC_DATA_STATUS, ERR_DENC_DATA_STATUS)
+ pEncData->nKeyStatus = DENC_KEY_STATUS_UNINITIALIZED;
+ // it will shrink during decrypt so this is enough
+ pEncData->mbufTransportKey.nLen = pEncKey->mbufTransportKey.nLen;
+ pEncData->mbufTransportKey.pMem = (char*)malloc(pEncData->mbufTransportKey.nLen);
+ if(!pEncData->mbufTransportKey.pMem)
+ SET_LAST_ERROR_RETURN(ERR_BAD_ALLOC, ERR_BAD_ALLOC)
+ ddocDebug(3, "dencEncryptedData_decrypt", "Decrypt enckey: %d into: %d",
+ pEncKey->mbufTransportKey.nLen, pEncData->mbufTransportKey.nLen);
+ len = pEncData->mbufTransportKey.nLen;
+ err = decryptWithEstID(nSlot, pin,
+ (const char*)pEncKey->mbufTransportKey.pMem, pEncKey->mbufTransportKey.nLen,
+ (char*)pEncData->mbufTransportKey.pMem, &len);
+ pEncData->mbufTransportKey.nLen = len;
+ if(err) return err;
+ pEncData->nKeyStatus = DENC_KEY_STATUS_INITIALIZED;
+ err = dencEncryptedData_decryptData(pEncData);
+ /*pEncProp = dencEncryptedData_FindEncryptionPropertyByName(pEncData, ENCPROP_ORIG_SIZE);
+ if(pEncProp && pEncProp->szContent) {
+ l = atol(pEncProp->szContent);
+ if(l > 0 && l < pEncData->mbufEncryptedData.nLen) {
+ ddocDebug(4, "dencEncryptedData_decrypt", "Truncating decrypted data: %d to: %d",
+ pEncData->mbufEncryptedData.nLen, l);
+ pEncData->mbufEncryptedData.nLen = l;
+ }
+ }*/
+ return err;
+}
+
+//--------------------------------------------------
+// Decrypts data transport key with ID card and
+// then decrypts the data with the transport key.
+// pEncData - pointer to DEncEncryptedData object [REQUIRED]
+// pEncKey - transport key to decrypt [REQUIRED]
+// pKey - private key for decrypting [REQUIRED]
+// returns error code or ERR_OK
+//--------------------------------------------------
+EXP_OPTION int dencEncryptedData_decryptWithKey(DEncEncryptedData* pEncData,
+ DEncEncryptedKey* pEncKey,
+ EVP_PKEY* pKey)
+{
+ int err = ERR_OK, len;
+ DEncEncryptionProperty* pEncProp;
+ long l;
+
+ RETURN_IF_NULL_PARAM(pEncData)
+ RETURN_IF_NULL_PARAM(pEncKey)
+ RETURN_IF_NULL_PARAM(pKey)
+ // check data status
+ if(pEncData->nDataStatus != DENC_DATA_STATUS_ENCRYPTED_AND_NOT_COMPRESSED &&
+ pEncData->nDataStatus != DENC_DATA_STATUS_ENCRYPTED_AND_COMPRESSED)
+ SET_LAST_ERROR_RETURN(ERR_DENC_DATA_STATUS, ERR_DENC_DATA_STATUS)
+ pEncData->nKeyStatus = DENC_KEY_STATUS_UNINITIALIZED;
+ // it will shrink during decrypt so this is enough
+ pEncData->mbufTransportKey.nLen = pEncKey->mbufTransportKey.nLen;
+ pEncData->mbufTransportKey.pMem = (char*)malloc(pEncData->mbufTransportKey.nLen);
+ if(!pEncData->mbufTransportKey.pMem)
+ SET_LAST_ERROR_RETURN(ERR_BAD_ALLOC, ERR_BAD_ALLOC)
+ ddocDebug(3, "dencEncryptedData_decryptWithKey", "Decrypt enckey: %d into: %d",
+ pEncKey->mbufTransportKey.nLen, pEncData->mbufTransportKey.nLen);
+#if OPENSSL_VERSION_NUMBER > 0x10000000
+ len = EVP_PKEY_decrypt_old((unsigned char *)pEncData->mbufTransportKey.pMem,
+ (const unsigned char*)pEncKey->mbufTransportKey.pMem,
+ pEncKey->mbufTransportKey.nLen, pKey);
+#else
+ len = EVP_PKEY_decrypt((unsigned char *)pEncData->mbufTransportKey.pMem,
+ (const unsigned char*)pEncKey->mbufTransportKey.pMem,
+ pEncKey->mbufTransportKey.nLen, pKey);
+#endif
+ ddocDebug(3, "dencEncryptedData_decryptWithKey", "Decrypt rv: %d len: %l", err, len);
+ pEncData->mbufTransportKey.nLen = len;
+ if(len != 16) return ERR_DENC_DECRYPT;
+ else err = ERR_OK;
+ pEncData->nKeyStatus = DENC_KEY_STATUS_INITIALIZED;
+ err = dencEncryptedData_decryptData(pEncData);
+ pEncProp = dencEncryptedData_FindEncryptionPropertyByName(pEncData, ENCPROP_ORIG_SIZE);
+ if(pEncProp && pEncProp->szContent) {
+ l = atol(pEncProp->szContent);
+ if(l > 0 && l < pEncData->mbufEncryptedData.nLen) {
+ ddocDebug(4, "dencEncryptedData_decrypt", "Truncating decrypted data: %d to: %d",
+ pEncData->mbufEncryptedData.nLen, l);
+ pEncData->mbufEncryptedData.nLen = l;
+ }
+ }
+ return err;
+}
+
+
+//--------------------------------------------------
+// Decrypts data transport key with ID card and
+// then decrypts the data with the transport key.
+// pEncData - pointer to DEncEncryptedData object [REQUIRED]
+// tKey - decrypted transport key [REQUIRED]
+// keyLen - length of trasnport key [REQUIRED]
+// returns error code or ERR_OK
+//--------------------------------------------------
+EXP_OPTION int dencEncryptedData_decrypt_withKey(DEncEncryptedData* pEncData,
+ const char* tKey, int keyLen)
+{
+ int err = ERR_OK;
+ DEncEncryptionProperty* pEncProp;
+ long l;
+
+ RETURN_IF_NULL_PARAM(pEncData)
+ RETURN_IF_NULL_PARAM(tKey)
+ // check data status
+ if(pEncData->nDataStatus != DENC_DATA_STATUS_ENCRYPTED_AND_NOT_COMPRESSED &&
+ pEncData->nDataStatus != DENC_DATA_STATUS_ENCRYPTED_AND_COMPRESSED)
+ SET_LAST_ERROR_RETURN(ERR_DENC_DATA_STATUS, ERR_DENC_DATA_STATUS)
+ pEncData->mbufTransportKey.nLen = keyLen;
+ pEncData->mbufTransportKey.pMem = (char*)malloc(pEncData->mbufTransportKey.nLen);
+ if(!pEncData->mbufTransportKey.pMem)
+ SET_LAST_ERROR_RETURN(ERR_BAD_ALLOC, ERR_BAD_ALLOC)
+ memcpy(pEncData->mbufTransportKey.pMem, tKey, keyLen);
+ ddocDebug(4, "dencEncryptedData_decrypt_withKey", "Decrypt enckey: %d into: %d",
+ keyLen, pEncData->mbufTransportKey.nLen);
+ pEncData->nKeyStatus = DENC_KEY_STATUS_INITIALIZED;
+ err = dencEncryptedData_decryptData(pEncData);
+ pEncProp = dencEncryptedData_FindEncryptionPropertyByName(pEncData, ENCPROP_ORIG_SIZE);
+ if(pEncProp && pEncProp->szContent) {
+ l = atol(pEncProp->szContent);
+ if(l > 0 && l < pEncData->mbufEncryptedData.nLen) {
+ ddocDebug(4, "dencEncryptedData_decrypt_withKey", "Truncating decrypted data: %d to: %d",
+ pEncData->mbufEncryptedData.nLen, l);
+ pEncData->mbufEncryptedData.nLen = l;
+ }
+ }
+ return err;
+}
+
+
+//--------------------------------------------------
+// Compresses data with ZLIB. Cannot compress encrypted data!!!
+// pEncData - pointer to DEncEncryptedData object [REQUIRED]
+// nCompressOption - flag: DENC_COMPRESS_ALLWAYS,
+// DENC_COMPRESS_NEVER or DENC_COMPRESS_BEST_EFFORT
+// returns error code or ERR_OK
+//--------------------------------------------------
+EXP_OPTION int dencEncryptedData_compressData(DEncEncryptedData* pEncData, int nCompressOption)
+{
+ int err = ERR_OK;
+ DigiDocMemBuf outData;
+ char buf[20];
+ DEncEncryptionProperty* pEncProperty;
+
+ RETURN_IF_NULL_PARAM(pEncData)
+ // check compress option
+ RETURN_IF_NOT(nCompressOption == DENC_COMPRESS_ALLWAYS ||
+ nCompressOption == DENC_COMPRESS_BEST_EFFORT, ERR_COMPRESS)
+ // check data status - cannot compress encrypted data!!!
+ if(pEncData->nDataStatus != DENC_DATA_STATUS_UNENCRYPTED_AND_NOT_COMPRESSED)
+ SET_LAST_ERROR_RETURN(ERR_DENC_DATA_STATUS, ERR_DENC_DATA_STATUS)
+ //AM 30.04.08 2048 instead of 1024
+ outData.nLen = pEncData->mbufEncryptedData.nLen + 2048; // it should get smaller
+ outData.pMem = malloc(outData.nLen);
+ if(!outData.pMem)
+ SET_LAST_ERROR_RETURN(ERR_BAD_ALLOC, ERR_BAD_ALLOC)
+ err = compress OF(( (Bytef *)outData.pMem, (uLongf *)&outData.nLen,
+ (const Bytef *)pEncData->mbufEncryptedData.pMem, (uLong)pEncData->mbufEncryptedData.nLen));
+ ddocDebug(3, "dencEncryptedData_compressData", "Orig len: %d, compressed: %d, RC: %d",
+ pEncData->mbufEncryptedData.nLen, outData.nLen, err);
+ if(err != Z_OK) {
+ free(outData.pMem);
+ SET_LAST_ERROR_RETURN(ERR_COMPRESS, ERR_COMPRESS)
+ }
+ if(!err &&
+ ((nCompressOption == DENC_COMPRESS_ALLWAYS) ||
+ (nCompressOption == DENC_COMPRESS_BEST_EFFORT &&
+ outData.nLen < pEncData->mbufEncryptedData.nLen))) {
+ snprintf(buf, sizeof(buf), "%d", (int)(pEncData->mbufEncryptedData.nLen));
+ err = dencEncryptionProperty_new(pEncData, &pEncProperty,
+ NULL, NULL, ENCPROP_ORIG_SIZE, buf);
+ free(pEncData->mbufEncryptedData.pMem);
+ pEncData->mbufEncryptedData.pMem = outData.pMem;
+ pEncData->mbufEncryptedData.nLen = outData.nLen;
+ pEncData->nDataStatus = DENC_DATA_STATUS_UNENCRYPTED_AND_COMPRESSED;
+ // store original mime type
+ if(pEncData->szMimeType) {
+ pEncProperty = 0;
+ err = dencEncryptionProperty_new(pEncData, &pEncProperty,
+ NULL, NULL, ENCPROP_ORIG_MIME, pEncData->szMimeType);
+ free(pEncData->szMimeType);
+ }
+ pEncData->szMimeType = (char*)strdup(DENC_ENCDATA_MIME_ZLIB);
+ } else
+ free(outData.pMem);
+ return err;
+}
+
+//--------------------------------------------------
+// Decompresses data with ZLIB.
+// pEncData - pointer to DEncEncryptedData object [REQUIRED]
+// nCompressOption - flag: DENC_COMPRESS_ALLWAYS,
+// DENC_COMPRESS_NEVER or DENC_COMPRESS_BEST_EFFORT
+// returns error code or ERR_OK
+//--------------------------------------------------
+EXP_OPTION int dencEncryptedData_decompressData(DEncEncryptedData* pEncData)
+{
+ int err = ERR_OK;
+ long origLen;
+ DigiDocMemBuf outData;
+ DEncEncryptionProperty* pEncProp;
+
+ RETURN_IF_NULL_PARAM(pEncData)
+ // check data status - cannot decompress encrypted data!!!
+ if(pEncData->nDataStatus != DENC_DATA_STATUS_UNENCRYPTED_AND_COMPRESSED)
+ SET_LAST_ERROR_RETURN(ERR_DENC_DATA_STATUS, ERR_DENC_DATA_STATUS)
+ // find original data size
+ pEncProp = dencEncryptedData_FindEncryptionPropertyByName(pEncData, ENCPROP_ORIG_SIZE);
+ if(pEncProp && pEncProp->szContent) {
+ origLen = atol(pEncProp->szContent);
+ outData.nLen = (int)origLen;
+ } else
+ SET_LAST_ERROR_RETURN(ERR_DECOMPRESS, ERR_DECOMPRESS)
+ outData.pMem = malloc(outData.nLen);
+ if(!outData.pMem)
+ SET_LAST_ERROR_RETURN(ERR_BAD_ALLOC, ERR_BAD_ALLOC)
+ err = uncompress OF(( (Bytef *)outData.pMem, (uLongf *)&outData.nLen,
+ (const Bytef *)pEncData->mbufEncryptedData.pMem, (uLong)pEncData->mbufEncryptedData.nLen));
+ ddocDebug(3, "dencEncryptedData_decompressData", "Compressed len: %d, orig-len: %ld, uncompressed: %d, RC: %d",
+ pEncData->mbufEncryptedData.nLen, origLen, outData.nLen, err);
+ if(err != Z_OK) {
+ free(outData.pMem);
+ SET_LAST_ERROR_RETURN(ERR_DECOMPRESS, ERR_DECOMPRESS)
+ }
+ if(!err) {
+ free(pEncData->mbufEncryptedData.pMem);
+ pEncData->mbufEncryptedData.pMem = outData.pMem;
+ pEncData->mbufEncryptedData.nLen = outData.nLen;
+ pEncData->nDataStatus = DENC_DATA_STATUS_UNENCRYPTED_AND_NOT_COMPRESSED;
+ if(pEncData->szMimeType)
+ free(pEncData->szMimeType);
+ // restor original mime type ?
+ pEncData->szMimeType = 0;
+ // find original mime type
+ pEncProp = dencEncryptedData_FindEncryptionPropertyByName(pEncData, ENCPROP_ORIG_MIME);
+ if(pEncProp && pEncProp->szContent)
+ pEncData->szMimeType = (char*)strdup(pEncProp->szContent);
+ } else
+ free(outData.pMem);
+ return err;
+}
+
+//--------------------------------------------------
+// Encrypts a file and writes it to output file
+// The caller must have initialized the transport keys
+// but not the data.
+// pEncData - pointer to DEncEncryptedData object [REQUIRED]
+// szInputFileName - input data name [REQUIRED]
+// szOutputFileName - output file name [REQUIRED]
+// szMimeType - input data mime type [OPTIONAL]
+// returns error code or ERR_OK
+//--------------------------------------------------
+EXP_OPTION int dencEncryptFile(DEncEncryptedData* pEncData,
+ const char* szInputFileName, const char* szOutputFileName,
+ const char* szMimeType)
+{
+ int err = ERR_OK, l1, l2, l3, i, nBlock;
+ long lOrigLen, lEncSize, lWritten;
+ EVP_CIPHER_CTX ectx;
+ EVP_ENCODE_CTX bctx;
+ char convInFileName[250], convOutFileName[250];
+ char buf1[4096], buf2[5120], buf3[6144], buf4[70], *p2;
+ DigiDocMemBuf mbuf;
+ FILE *hInFile, *hOutFile;
+ DEncEncryptionProperty* pEncProperty;
+
+ RETURN_IF_NULL_PARAM(pEncData)
+ RETURN_IF_NULL_PARAM(szInputFileName)
+ RETURN_IF_NULL_PARAM(szOutputFileName)
+ ddocDebug(3, "dencEncryptFile", "In-file: %s, out-file: %s, key: %d",
+ szInputFileName, szOutputFileName, pEncData->mbufTransportKey.nLen);
+ // check data status - must be uninitialized since we will read it from file
+ if(pEncData->nDataStatus != DENC_DATA_STATUS_UNINITIALIZED)
+ SET_LAST_ERROR_RETURN(ERR_DENC_DATA_STATUS, ERR_DENC_DATA_STATUS)
+ // check key status - must have been initialized already!
+ if(pEncData->nKeyStatus == DENC_KEY_STATUS_UNINITIALIZED)
+ SET_LAST_ERROR_RETURN(ERR_DENC_KEY_STATUS, ERR_DENC_KEY_STATUS)
+ // convert filenames
+ ddocConvertFileName( convInFileName, sizeof(convInFileName), szInputFileName );
+ ddocConvertFileName( convOutFileName, sizeof(convOutFileName), szOutputFileName );
+ if(strstr(szInputFileName, ".bdoc") || strstr(szInputFileName, ".asice"))
+ err = dencEncryptedData_SetMimeType(pEncData, "application/vnd.etsi.asic-e+zip");
+ // TODO: compress the data
+
+ // read and encrypt data
+ memset(buf4, 0, sizeof(buf4));
+ nBlock = 0;
+ if((hInFile = fopen(convInFileName, "rb")) != NULL) {
+ if((hOutFile = fopen(convOutFileName, "wb")) != NULL) {
+ // write header
+ mbuf.pMem = 0;
+ mbuf.nLen = 0;
+ err = dencGenEncryptedData_header_toXML(pEncData, &mbuf);
+ fwrite(mbuf.pMem, 1, mbuf.nLen, hOutFile);
+ ddocMemBuf_free(&mbuf);
+ // init encryption
+ EVP_CIPHER_CTX_init(&ectx);
+ // init encoding
+ EVP_EncodeInit(&bctx);
+ EVP_CipherInit_ex(&ectx, EVP_aes_128_cbc(), NULL,
+ (const unsigned char*)pEncData->mbufTransportKey.pMem,
+ (const unsigned char*)pEncData->initVector, ENCRYPT);
+ //EVP_CIPHER_CTX_set_padding(&ectx, 1);
+ lOrigLen = 0;
+ lEncSize = 0;
+ lWritten = 0;
+ // read file & encrypt & write to output
+ do {
+ memset(buf1, 0, sizeof(buf1));
+ l1 = fread(buf1, 1, sizeof(buf1), hInFile);
+ if(l1 > 0) {
+ lOrigLen += l1;
+ // padding for final block
+ if(l1 != sizeof(buf1)) {
+ l2 = 16 - (l1 % 16);
+ ddocDebug(3, "dencEncryptFile", "Original %d padding: %d, new block: %d", l1, l2, l1+l2);
+ for(i = 0; i < l2; i++)
+ buf1[l1 + i] = 0;
+ buf1[l1 + l2 - 1] = (unsigned char)l2;
+ l1 += l2;
+ }
+ memset(buf2, 0, sizeof(buf2));
+ l2 = sizeof(buf2);
+ p2 = buf2;
+ // first block of encrypted data will contain
+ // not encrypted IV vector in the first 16 bytes
+ if(nBlock == 0) {
+ memcpy(buf2, pEncData->initVector, 16);
+ p2 += 16;
+ l2 -= 16;
+ }
+ EVP_CipherUpdate(&ectx, (unsigned char*)p2, &l2, (const unsigned char*)buf1, l1);
+ ddocDebug(3, "dencEncryptFile", "Input: %d, block: %d, buf: %d encrypted: %d", l1, nBlock, sizeof(buf2), l2);
+ lEncSize += l2;
+ // if it's the final block
+ if(l1 != sizeof(buf1)) {
+ l3 = sizeof(buf2) - l2;
+ p2 = buf2 + l2;
+ if(nBlock == 0) {
+ p2 += 16;
+ l3 -= 16;
+ }
+ EVP_CipherFinal_ex(&ectx, (unsigned char*)p2, &l3);
+ ddocDebug(3, "dencEncryptFile", "Buf: %d Final encrypted: %d", sizeof(buf2) - l2, l3);
+ l2 += l3;
+ lEncSize += l3;
+ }
+ // base64 encode
+ l3 = sizeof(buf3);
+ memset(buf3, 0, l3);
+ // encode also the IV vector at the beginning of first block
+ if(nBlock == 0)
+ l2 += 16;
+ EVP_EncodeUpdate(&bctx, (unsigned char*)buf3, &l3, (byte*)buf2, l2);
+ lWritten += l3;
+ fwrite(buf3, 1, l3, hOutFile);
+ ddocDebug(3, "dencEncryptFile", "In: %d, encrypted: %d, base64: %d", l1, l2, l3);
+ }
+ nBlock++;
+ } while(!err && l1 > 0);
+ EVP_CIPHER_CTX_cleanup(&ectx);
+ // write the last portion of line data
+ l3 = sizeof(buf3);
+ memset(buf3, 0, l3);
+ EVP_EncodeFinal(&bctx, (unsigned char*)buf3, &l3);
+ lWritten += l3;
+ fwrite(buf3, 1, l3, hOutFile);
+ ddocDebug(4, "dencEncryptFile", "Total input: %d, blocks: %d, encrypted: %d written: %d", lOrigLen, nBlock, lEncSize, lWritten);
+ // setup encryption properties
+ snprintf(buf1, sizeof(buf1), "%ld", lOrigLen);
+ pEncProperty = 0;
+ err = dencEncryptionProperty_new(pEncData, &pEncProperty,
+ NULL, NULL, ENCPROP_ORIG_SIZE, buf1);
+ pEncProperty = 0;
+ err = dencEncryptionProperty_new(pEncData, &pEncProperty,
+ NULL, NULL, ENCPROP_FILENAME, szInputFileName);
+ // write trailer
+ mbuf.pMem = 0;
+ mbuf.nLen = 0;
+ err = dencGenEncryptedData_trailer_toXML(pEncData, &mbuf);
+ fwrite(mbuf.pMem, 1, mbuf.nLen, hOutFile);
+ ddocMemBuf_free(&mbuf);
+ fclose(hOutFile);
+ } else {
+ SET_LAST_ERROR_RETURN_CODE(ERR_FILE_WRITE);
+ ddocDebug(1, "dencEncryptFile", "Error writing encrypted document: %s", convOutFileName);
+ }
+ fclose(hInFile);
+ } else {
+ SET_LAST_ERROR_RETURN_CODE(ERR_FILE_READ);
+ ddocDebug(1, "dencEncryptFile", "Error reading input from file: %s", convInFileName);
+ }
+
+ return err;
+}
+
+
+//====================< RecipientInfo functions >==========================
+
+//--------------------------------------------------
+// "Constructor" of DEncRecvInfo object
+// ppRecvInfo - address of buffer for newly allocated object [REQUIRED]
+// szId - recipients id [REQUIRED]
+// szRecipient - recipient atribute [OPTIONAL]
+// szKeyName - KeyName element [OPTIONAL]
+// szCarriedKeyName - CarriedKeyName element [OPTIONAL]
+// pCert - certificate [REQUIRED]
+// returns error code or ERR_OK
+//--------------------------------------------------
+EXP_OPTION int dencRecvInfo_new(DEncRecvInfo** ppRecvInfo,
+ const char* szId, const char* szRecipient,
+ const char* szKeyName, const char* szCarriedKeyName,
+ const X509* pCert)
+{
+ int err = ERR_OK;
+
+ // check input parameters
+ ddocDebug(3, "dencRecvInfo_new", "RecvInfo id: %s, recipient: %s, keyname: %s, ckeyname: %s cert: %s",
+ szId, szRecipient, szKeyName, szCarriedKeyName, (pCert ? "OK" : "NULL"));
+ RETURN_IF_NULL_PARAM(ppRecvInfo);
+ RETURN_IF_NULL_PARAM(szId);
+ RETURN_IF_NULL_PARAM(pCert);
+
+ *ppRecvInfo = (DEncRecvInfo*)malloc(sizeof(DEncRecvInfo));
+ // allocate new object
+ RETURN_IF_BAD_ALLOC(*ppRecvInfo);
+ memset(*ppRecvInfo, 0, sizeof(DEncRecvInfo));
+ // set required fields
+ if(szId) {
+ err = ddocMemAssignString((char**)&((*ppRecvInfo)->szId), szId);
+ if(err) return err;
+ }
+ (*ppRecvInfo)->pCert = (X509*)pCert;
+ // set optional fields
+ if(szRecipient) {
+ err = ddocMemAssignString((char**)&((*ppRecvInfo)->szRecipient), szRecipient);
+ if(err) return err;
+ }
+ if(szKeyName) {
+ err = ddocMemAssignString((char**)&((*ppRecvInfo)->szKeyName), szKeyName);
+ if(err) return err;
+ }
+ if(szCarriedKeyName) {
+ err = ddocMemAssignString((char**)&((*ppRecvInfo)->szCarriedKeyName), szCarriedKeyName);
+ if(err) return err;
+ }
+ return err;
+}
+
+//--------------------------------------------------
+// "Destructor" of DEncRecvInfo object
+// pRecvInfo - address of buffer for newly allocated object [REQUIRED]
+// returns error code or ERR_OK
+//--------------------------------------------------
+EXP_OPTION int dencRecvInfo_free(DEncRecvInfo* pRecvInfo)
+{
+ int err = ERR_OK;
+
+ RETURN_IF_NULL_PARAM(pRecvInfo);
+ if(pRecvInfo->szId)
+ free(pRecvInfo->szId);
+ if(pRecvInfo->szRecipient)
+ free(pRecvInfo->szRecipient);
+ if(pRecvInfo->szKeyName)
+ free(pRecvInfo->szKeyName);
+ if(pRecvInfo->szCarriedKeyName)
+ free(pRecvInfo->szCarriedKeyName);
+ if(pRecvInfo->pCert)
+ X509_free(pRecvInfo->pCert);
+ return err;
+}
+
+//--------------------------------------------------
+// Replaces newlines with blanks
+// data - data with newlines
+// returns data without newlines
+//--------------------------------------------------
+char* removeNewlines(char* data)
+{
+ int i, n, j;
+ n = strlen(data);
+ for(i = j = 0; i < n; i++) {
+ if(data[i] != '\n' && data[i] != '\r') {
+ data[j] = data[i];
+ j++;
+ }
+ }
+ if(j < i)
+ data[j] = 0;
+ return data;
+}
+
+//--------------------------------------------------
+// Stores DEncRecvInfo object to configuration store
+// pRecvInfo - address of RecvInfo object [REQUIRED]
+// returns error code or ERR_OK
+//--------------------------------------------------
+EXP_OPTION int dencRecvInfo_store(DEncRecvInfo* pRecvInfo)
+{
+ int err = ERR_OK;
+ char key[100], *p;
+
+ RETURN_IF_NULL_PARAM(pRecvInfo);
+ RETURN_IF_NULL_PARAM(pRecvInfo->szId);
+ RETURN_IF_NULL_PARAM(pRecvInfo->pCert);
+ if(!err) {
+ snprintf(key, sizeof(key), "RECV_%s_RECIPIENT", pRecvInfo->szId);
+ if(pRecvInfo->szRecipient)
+ err = createOrReplacePrivateConfigItem(NULL, key, removeNewlines(pRecvInfo->szRecipient));
+ else
+ err = ConfigItem_delete(key);
+ }
+ if(!err) {
+ snprintf(key, sizeof(key), "RECV_%s_KEY_NAME", pRecvInfo->szId);
+ if(pRecvInfo->szKeyName)
+ err = createOrReplacePrivateConfigItem(NULL, key, removeNewlines(pRecvInfo->szKeyName));
+ else
+ err = ConfigItem_delete(key);
+ }
+ if(!err) {
+ snprintf(key, sizeof(key), "RECV_%s_CARRIED_KEY_NAME", pRecvInfo->szId);
+ if(pRecvInfo->szCarriedKeyName)
+ err = createOrReplacePrivateConfigItem(NULL, key, removeNewlines(pRecvInfo->szCarriedKeyName));
+ else
+ err = ConfigItem_delete(key);
+ }
+ if(!err && pRecvInfo->pCert) {
+ snprintf(key, sizeof(key), "RECV_%s_CERT", pRecvInfo->szId);
+ err = getCertPEM(pRecvInfo->pCert, 0, &p);
+ if(!err && p) {
+ err = createOrReplacePrivateConfigItem(NULL, key, removeNewlines(p));
+ free(p);
+ }
+ }
+ return err;
+}
+
+//--------------------------------------------------
+// Deletes DEncRecvInfo object from configuration store
+// pRecvInfo - address of RecvInfo [REQUIRED]
+// returns error code or ERR_OK
+//--------------------------------------------------
+EXP_OPTION int dencRecvInfo_delete(DEncRecvInfo* pRecvInfo)
+{
+ int err = ERR_OK;
+ char key[100];
+
+ RETURN_IF_NULL_PARAM(pRecvInfo);
+ RETURN_IF_NULL_PARAM(pRecvInfo->szId);
+ snprintf(key, sizeof(key), "RECV_%s_RECIPIENT", pRecvInfo->szId);
+ err = ConfigItem_delete(key);
+ snprintf(key, sizeof(key), "RECV_%s_KEY_NAME", pRecvInfo->szId);
+ err = ConfigItem_delete(key);
+ snprintf(key, sizeof(key), "RECV_%s_CARRIED_KEY_NAME", pRecvInfo->szId);
+ err = ConfigItem_delete(key);
+ snprintf(key, sizeof(key), "RECV_%s_CERT", pRecvInfo->szId);
+ err = ConfigItem_delete(key);
+ return err;
+}
+
+
+//--------------------------------------------------
+// Finds the DEncRecvInfo object with the given id
+// pConfStore - store to search in [OPTIONAL]. Use NULL for default
+// ppRecvInfo - address of buffer for newly allocated object [REQUIRED]
+// szId - id of the object [REQUIRED]
+// returns error code or ERR_OK
+//--------------------------------------------------
+EXP_OPTION int dencRecvInfo_findById(ConfigurationStore *pConfStore,
+ DEncRecvInfo** ppRecvInfo, const char* szId)
+{
+ int err = ERR_OK;
+ char key[100], *p;
+ X509* pCert = NULL;
+
+ RETURN_IF_NULL_PARAM(ppRecvInfo);
+ *ppRecvInfo = 0; // mark as not found
+ // check for existence first
+ snprintf(key, sizeof(key), "RECV_%s_CERT", szId);
+ if(pConfStore)
+ p = (char*)ConfigItem_lookup_fromStore(pConfStore, key);
+ else
+ p = (char*)ConfigItem_lookup(key);
+ if(!p) return err;
+ err = ddocDecodeX509PEMData(&pCert, (const char*)p, strlen((const char*)p));
+ if(!pCert) return err;
+ err = dencRecvInfo_new(ppRecvInfo, szId, NULL, NULL, NULL, pCert);
+ // now set the optional items if possible
+ snprintf(key, sizeof(key), "RECV_%s_RECIPIENT", szId);
+ if(pConfStore)
+ p = (char*)ConfigItem_lookup_fromStore(pConfStore, key);
+ else
+ p = (char*)ConfigItem_lookup(key);
+ if(p)
+ (*ppRecvInfo)->szRecipient = (char*)strdup(p);
+ snprintf(key, sizeof(key), "RECV_%s_KEY_NAME", szId);
+ if(pConfStore)
+ p = (char*)ConfigItem_lookup_fromStore(pConfStore, key);
+ else
+ p = (char*)ConfigItem_lookup(key);
+ if(p)
+ (*ppRecvInfo)->szKeyName = (char*)strdup(p);
+ snprintf(key, sizeof(key), "RECV_%s_CARRIED_KEY_NAME", szId);
+ if(pConfStore)
+ p = (char*)ConfigItem_lookup_fromStore(pConfStore, key);
+ else
+ p = (char*)ConfigItem_lookup(key);
+ if(p)
+ (*ppRecvInfo)->szCarriedKeyName = (char*)strdup(p);
+ return err;
+}
+
+//--------------------------------------------------
+// Returns all DEncRecvInfo objects
+// pRecvInfoList - address of the list receiving the items [REQUIRED]
+// returns error code or ERR_OK
+//--------------------------------------------------
+EXP_OPTION int dencRecvInfo_findAll(DEncRecvInfoList* pRecvInfoList)
+{
+ int err = ERR_OK, i, j, k;
+ char id[50];
+ ConfigurationStore confStore;
+ DEncRecvInfo* pRecvInfo;
+
+ RETURN_IF_NULL_PARAM(pRecvInfoList);
+ pRecvInfoList->nItems = 0;
+ pRecvInfoList->pItems = NULL;
+ confStore.nItems = 0;
+ confStore.pItems = NULL;
+ // search the id's
+ err = ConfigItem_findByPrefix(&confStore, "RECV");
+ ddocDebug(4, "dencRecvInfo_findAll", "RECV items: %d", confStore.nItems);
+ for(i = 0; confStore.pItems && i < confStore.nItems; i++) {
+ j = (confStore.pItems[i] && confStore.pItems[i]->szKey) ?
+ strlen(confStore.pItems[i]->szKey) : 0;
+ if(j && !strcmp(confStore.pItems[i]->szKey + j - 4, "CERT")) {
+ j -= 6;
+ for(k = j; k > 0 && confStore.pItems[i]->szKey[k] != '_'; k--);
+ memset(id, 0, sizeof(id));
+ strncpy(id, confStore.pItems[i]->szKey + k + 1, j - k);
+ ddocDebug(4, "dencRecvInfo_findAll", "Read obj with id: %s", id);
+ err = dencRecvInfo_findById(&confStore, &pRecvInfo, id);
+ if(!err && pRecvInfo)
+ err = dencRecvInfoList_add(pRecvInfoList, pRecvInfo);
+ }
+ }
+
+ // cleanup
+ cleanupConfigStore(&confStore);
+ return err;
+}
+
+//====================< RecipientInfoList functions >==========================
+
+//--------------------------------------------------
+// Adds a DEncRecvInfo object to the list
+// pRecvInfoList - address of the list receiving the item [REQUIRED]
+// pRecvInfo - new object to be added
+// returns error code or ERR_OK
+//--------------------------------------------------
+EXP_OPTION int dencRecvInfoList_add(DEncRecvInfoList* pRecvInfoList, DEncRecvInfo *pRecvInfo)
+{
+ int err = ERR_OK;
+ DEncRecvInfo** pItems;
+
+ RETURN_IF_NULL_PARAM(pRecvInfoList);
+ RETURN_IF_NULL_PARAM(pRecvInfo);
+ pItems = (DEncRecvInfo**)realloc(pRecvInfoList->pItems,
+ (pRecvInfoList->nItems + 1) * sizeof(DEncRecvInfo *));
+ RETURN_IF_BAD_ALLOC(pItems);
+ pRecvInfoList->pItems = pItems;
+ pRecvInfoList->pItems[pRecvInfoList->nItems] = pRecvInfo;
+ pRecvInfoList->nItems++;
+ return err;
+}
+
+//--------------------------------------------------
+// Frees the contents of a DEncRecvInfoList object
+// pRecvInfoList - address of the list [REQUIRED]
+// returns error code or ERR_OK
+//--------------------------------------------------
+EXP_OPTION int dencRecvInfoList_free(DEncRecvInfoList* pRecvInfoList)
+{
+ int err = ERR_OK, i;
+
+ RETURN_IF_NULL_PARAM(pRecvInfoList);
+ for(i = 0; i < pRecvInfoList->nItems; i++) {
+ if(pRecvInfoList->pItems[i])
+ dencRecvInfo_free(pRecvInfoList->pItems[i]);
+ }
+ free(pRecvInfoList->pItems);
+ pRecvInfoList->pItems = 0;
+ pRecvInfoList->nItems = 0;
+ return err;
+}
+
+//--------------------------------------------------
+// Removes the given DEncRecvInfo object from the list
+// pRecvInfoList - address of the list [REQUIRED]
+// szId - id of the obect to be removed [REQUIRED]
+// returns error code or ERR_OK
+//--------------------------------------------------
+EXP_OPTION int dencRecvInfoList_delete(DEncRecvInfoList* pRecvInfoList, const char* szId)
+{
+ int err = ERR_OK, i, j;
+
+ ddocDebug(4, "dencRecvInfoList_delete", "Deleting id: %s orig-len: %d", szId, pRecvInfoList->nItems);
+ RETURN_IF_NULL_PARAM(pRecvInfoList);
+ RETURN_IF_NULL_PARAM(szId);
+ for(i = j = 0; i < pRecvInfoList->nItems; i++) {
+ if(pRecvInfoList->pItems[j] &&
+ pRecvInfoList->pItems[j]->szId &&
+ !strcmp(pRecvInfoList->pItems[j]->szId, szId)) {
+ free(pRecvInfoList->pItems[j]);
+ ddocDebug(4, "dencRecvInfoList_delete", "Dleting item on pos: %d", j);
+ } else {
+ pRecvInfoList->pItems[j] = pRecvInfoList->pItems[i];
+ j++;
+ }
+ }
+ pRecvInfoList->nItems = j;
+ ddocDebug(4, "dencRecvInfoList_delete", "remaining-len: %d", pRecvInfoList->nItems);
+ return err;
+}
+
+//====================< original content functions >===================
+
+//--------------------------------------------------
+// Returns the count of "orig_file" properties
+// pEncData - EncryptedData object [REQUIRED]
+// returns count or -1 for error.
+//--------------------------------------------------
+EXP_OPTION int dencOrigContent_count(DEncEncryptedData* pEncData)
+{
+ int nCount = 0, i, n;
+ DEncEncryptionProperty* pEncProp = 0;
+ char* pName;
+
+ SET_LAST_ERROR_RETURN_IF_NOT(pEncData, ERR_NULL_POINTER, -1)
+ n = dencEncryptedData_GetEncryptionPropertiesCount(pEncData);
+ for(i = 0; i < n; i++) {
+ pEncProp = (DEncEncryptionProperty*)dencEncryptedData_GetEncryptionProperty(pEncData, i);
+ if(pEncProp) {
+ pName = (char*)dencEncryptionProperty_GetName(pEncProp);
+ if(pName && !strcmp(pName, ENCPROP_ORIG_CONTENT))
+ nCount++;
+ }
+ }
+ return nCount;
+}
+
+//--------------------------------------------------
+// Creates a new property of type "orig_file"
+// pEncData - EncryptedData object [REQUIRED]
+// szOrigContentId - Id atribute for new Property object [OPTIONAL]
+// szName - original file name [REQUIRED]
+// szSize - size as string or irginal file [REQUIRED]
+// szMime - mime type or original file [REQUIRED]
+// szDfId - Id atribute of original file [REQUIRED]
+// returns error code or ERR_OK
+//--------------------------------------------------
+EXP_OPTION int dencOrigContent_add(DEncEncryptedData* pEncData, const char* szOrigContentId,
+ const char* szName, const char* szSize, const char* szMime, const char* szDfId)
+{
+ int err = ERR_OK, l1 = 0;
+ char* p1 = 0;
+ DEncEncryptionProperty* pEncProp = 0;
+
+ RETURN_IF_NULL_PARAM(pEncData);
+ RETURN_IF_NULL_PARAM(szName);
+ RETURN_IF_NULL_PARAM(szSize);
+ RETURN_IF_NULL_PARAM(szMime);
+ RETURN_IF_NULL_PARAM(szDfId);
+ l1 = strlen(szName) + strlen(szSize) + strlen(szMime) + strlen(szDfId) + 10;
+ p1 = (char*)malloc(l1);
+ RETURN_IF_BAD_ALLOC(p1);
+ memset(p1, 0, l1);
+ snprintf(p1, l1, "%s|%s|%s|%s", szName, szSize, szMime, szDfId);
+ err = dencEncryptionProperty_new(pEncData, &pEncProp, szOrigContentId,
+ NULL, ENCPROP_ORIG_CONTENT, p1);
+ if(p1)
+ free(p1);
+ return err;
+}
+
+
+//--------------------------------------------------
+// Returns the info from "orig_file" properties
+// pEncData - EncryptedData object [REQUIRED]
+// szOrigContentId - Id atribute for new Property object [OPTIONAL]
+// szName - buffer for original file name [REQUIRED]
+// nNameLen - buffer length of szName [REQUIRED]
+// szSize - buffer for size as string or irginal file [REQUIRED]
+// nSizeLen - buffer length of szSize [REQUIRED]
+// szMime - buffer for mime type or original file [REQUIRED]
+// nMimeLen - buffer length of szMime [REQUIRED]
+// szDfId - buffer for Id atribute of original file [REQUIRED]
+// nDfIdLen - buffer length of szDfId [REQUIRED]
+// returns error code or ERR_OK
+//--------------------------------------------------
+EXP_OPTION int dencOrigContent_findByIndex(DEncEncryptedData* pEncData, int origContIdx,
+ char* szName, int nNameLen, char* szSize, int nSizeLen,
+ char* szMime, int nMimeLen, char* szDfId, int nDfIdLen)
+{
+ int nCount = -1, i, n, j, k, l, m;
+ DEncEncryptionProperty* pEncProp = 0;
+ char *p1;
+
+ RETURN_IF_NULL_PARAM(pEncData);
+ RETURN_IF_NULL_PARAM(szName);
+ RETURN_IF_NULL_PARAM(szSize);
+ RETURN_IF_NULL_PARAM(szMime);
+ RETURN_IF_NULL_PARAM(szDfId);
+ memset(szName, 0, nNameLen);
+ memset(szSize, 0, nSizeLen);
+ memset(szMime, 0, nMimeLen);
+ memset(szDfId, 0, nDfIdLen);
+ n = dencEncryptedData_GetEncryptionPropertiesCount(pEncData);
+ for(i = 0; i < n; i++) {
+ pEncProp = (DEncEncryptionProperty*)dencEncryptedData_GetEncryptionProperty(pEncData, i);
+ if(pEncProp) {
+ p1 = (char*)dencEncryptionProperty_GetName(pEncProp);
+ if(p1 && !strcmp(p1, ENCPROP_ORIG_CONTENT))
+ nCount++;
+ ddocDebug(4, "dencOrigContent_findByIndex", "Prop: %d, name: %s count: %d", i, p1, nCount);
+ if(nCount == origContIdx && p1 && !strcmp(p1, ENCPROP_ORIG_CONTENT)) {
+ p1 = (char*)dencEncryptionProperty_GetContent(pEncProp);
+ ddocDebug(4, "dencOrigContent_findByIndex", "Prop: %d, count: %d, content: %s", i, nCount, p1);
+ if(p1) {
+ k = strlen(p1);
+ for(j = l = m = 0; j < k; j++) {
+ if(p1[j] == '|') {
+ l = 0;
+ m++;
+ } else {
+ switch(m) {
+ case 0: if(l < nNameLen) szName[l] = p1[j]; l++; break;
+ case 1: if(l < nSizeLen) szSize[l] = p1[j]; l++; break;
+ case 2: if(l < nMimeLen) szMime[l] = p1[j]; l++; break;
+ case 3: if(l < nDfIdLen) szDfId[l] = p1[j]; l++; break;
+ }
+ }
+ }
+ ddocDebug(4, "dencOrigContent_findByIndex", "Prop: %d, name: %s size: %s, mime: %s, id: %s", i, szName, szSize, szMime, szDfId);
+ }
+ }
+ }
+ }
+ if(!szName[0] && !szSize[0]) { // if not property name="orig_files" was not found then use Filename and OriginalSize
+ for(i = 0; i < n; i++) {
+ pEncProp = (DEncEncryptionProperty*)dencEncryptedData_GetEncryptionProperty(pEncData, i);
+ if(pEncProp) {
+ p1 = (char*)dencEncryptionProperty_GetName(pEncProp);
+ if(p1 && !strcmp(p1, ENCPROP_FILENAME)) {
+ p1 = (char*)dencEncryptionProperty_GetContent(pEncProp);
+ if(p1)
+ strncpy(szName, p1, nNameLen);
+ }
+ if(p1 && !strcmp(p1, ENCPROP_ORIG_SIZE)) {
+ p1 = (char*)dencEncryptionProperty_GetContent(pEncProp);
+ if(p1)
+ strncpy(szSize, p1, nSizeLen);
+ }
+ }
+ }
+ }
+ return ERR_OK;
+}
+
+//--------------------------------------------------
+// Checks if there is a digidoc document in this
+// encrypted document.
+// pEncData - EncryptedData object [REQUIRED]
+// returns 1 if digidoc document is inside
+//--------------------------------------------------
+EXP_OPTION int dencOrigContent_isDigiDocInside(DEncEncryptedData* pEncData)
+{
+ int i, n;
+ DEncEncryptionProperty* pEncProp = 0;
+ char *p1, *p2;
+
+ RETURN_IF_NULL_PARAM(pEncData);
+ if(pEncData->szMimeType && !strcmp(pEncData->szMimeType, DENC_ENCDATA_TYPE_DDOC)) {
+ ddocDebug(3, "dencOrigContent_isDigiDocInside", "mime: %s", pEncData->szMimeType);
+ return 1;
+ }
+ n = dencEncryptedData_GetEncryptionPropertiesCount(pEncData);
+ ddocDebug(3, "dencOrigContent_isDigiDocInside", "Props: %d", n);
+ for(i = 0; i < n; i++) {
+ pEncProp = (DEncEncryptionProperty*)dencEncryptedData_GetEncryptionProperty(pEncData, i);
+ if(pEncProp) {
+ p1 = (char*)dencEncryptionProperty_GetName(pEncProp);
+ ddocDebug(3, "dencOrigContent_isDigiDocInside", "Prop: %d name: %s", i, p1);
+ if(p1 && !strcmp(p1, ENCPROP_ORIG_MIME)) {
+ p2 = (char*)dencEncryptionProperty_GetContent(pEncProp);
+ ddocDebug(3, "dencOrigContent_isDigiDocInside", "Prop: %d mime: %s", i, p2);
+ if(p2 && !strcmp(p2, DENC_ENCDATA_TYPE_DDOC)) {
+ ddocDebug(3, "dencOrigContent_isDigiDocInside", "Name: %s mime: %s", p1, p2);
+ return 1;
+ }
+ }
+ }
+ }
+ return 0;
+}
+
+//--------------------------------------------------
+// Registers digidoc document as encrypted datatype
+// and stores it's data file info.
+// pEncData - EncryptedData object [REQUIRED]
+// pSigDoc - SignedDoc object [REQUIRED]
+// returns 1 if digidoc document is inside
+//--------------------------------------------------
+EXP_OPTION int dencOrigContent_registerDigiDoc(DEncEncryptedData* pEncData, SignedDoc* pSigDoc)
+{
+ int err = ERR_OK, i, n;
+ DEncEncryptionProperty* pEncProp = 0;
+ DataFile* pDf;
+ char buf[500], *sVer;
+
+ RETURN_IF_NULL_PARAM(pEncData);
+ RETURN_IF_NULL_PARAM(pSigDoc);
+ // set the mime type
+ sVer = (char*)ConfigItem_lookup_str("DENC_VERSION", DENC_VERSION_1_0);
+ err = dencEncryptedData_SetMimeType(pEncData, DENC_ENCDATA_TYPE_DDOC);
+ n = getCountOfDataFiles(pSigDoc);
+ for(i = 0; i < n; i++) {
+ pDf = getDataFile(pSigDoc, i);
+ if(pDf) {
+ pEncProp = 0;
+ snprintf(buf, sizeof(buf), "%s|%ld|%s|%s", getSimpleFileName(pDf->szFileName), pDf->nSize, pDf->szMimeType, pDf->szId);
+ err = dencEncryptionProperty_new(pEncData, &pEncProp,
+ NULL, NULL, ENCPROP_ORIG_CONTENT, buf);
+ }
+ }
+ return err;
+}
+
+//====================< other meta-info functions >===================
+
+//--------------------------------------------------
+// Sets the library name and version property
+// pEncData - EncryptedData object [REQUIRED]
+// returns count or -1 for error.
+//--------------------------------------------------
+EXP_OPTION int dencMetaInfo_SetLibVersion(DEncEncryptedData* pEncData)
+{
+ int err = ERR_OK;
+ DEncEncryptionProperty* pEncProp = 0;
+ char buf[500];
+
+ RETURN_IF_NULL_PARAM(pEncData);
+ // set the library name and version
+ snprintf(buf, sizeof(buf), "%s|%s", getLibName(), getLibVersion());
+ pEncProp = dencEncryptedData_FindEncryptionPropertyByName(pEncData, ENCPROP_LIB_VERSION);
+ if(pEncProp) { // property exists, set the content
+ err = dencEncryptionProperty_SetContent(pEncProp, (const char*)buf);
+ } else { // create a new property
+ err = dencEncryptionProperty_new(pEncData, &pEncProp, NULL, NULL,
+ ENCPROP_LIB_VERSION, buf);
+ }
+ return err;
+}
+
+//--------------------------------------------------
+// Sets the format name and version property
+// pEncData - EncryptedData object [REQUIRED]
+// returns count or -1 for error.
+//--------------------------------------------------
+EXP_OPTION int dencMetaInfo_SetFormatVersion(DEncEncryptedData* pEncData)
+{
+ int err = ERR_OK;
+ DEncEncryptionProperty* pEncProp = 0;
+ char buf[500];
+
+ RETURN_IF_NULL_PARAM(pEncData);
+ // set the library name and version
+ snprintf(buf, sizeof(buf), "%s|%s", DENC_FORMAT_ENCDOC_XML, ConfigItem_lookup_str("DENC_VERSION", DENC_VERSION_1_0));
+ pEncProp = dencEncryptedData_FindEncryptionPropertyByName(pEncData, ENCPROP_DOC_FORMAT);
+ if(pEncProp) { // property exists, set the content
+ err = dencEncryptionProperty_SetContent(pEncProp, (const char*)buf);
+ } else { // create a new property
+ err = dencEncryptionProperty_new(pEncData, &pEncProp, NULL, NULL,
+ ENCPROP_DOC_FORMAT, buf);
+ }
+ return err;
+}
+
+
+
+//--------------------------------------------------
+// Returns the library name and version meta-info of this document
+// pEncData - EncryptedData object [REQUIRED]
+// szLibrary - buffer for library name
+// nLibLen - length of library name buffer
+// szVersion - buffer for version info
+// nVerLen - length of version info buffer
+// returns count or -1 for error.
+//--------------------------------------------------
+EXP_OPTION int dencMetaInfo_GetLibVersion(DEncEncryptedData* pEncData, char* szLibrary, int nLibLen, char* szVersion, int nVerLen)
+{
+ int err = ERR_OK, i, j, n;
+ DEncEncryptionProperty* pEncProp = 0;
+ char *p1;
+
+ RETURN_IF_NULL_PARAM(pEncData);
+ RETURN_IF_NULL_PARAM(szLibrary);
+ RETURN_IF_NULL_PARAM(szVersion);
+ // mark as not found
+ memset(szLibrary, 0, nLibLen);
+ memset(szVersion, 0, nVerLen);
+ pEncProp = dencEncryptedData_FindEncryptionPropertyByName(pEncData, ENCPROP_LIB_VERSION);
+ if(pEncProp) { // property exists, set the content
+ p1 = (char*)dencEncryptionProperty_GetContent(pEncProp);
+ if(p1) {
+ for(i = j = n = 0; p1[i]; i++) {
+ if(p1[i] == '|' && j < nLibLen - 1) {
+ szLibrary[j] = 0;
+ j = 0;
+ n++;
+ continue;
+ } else {
+ if(!n) {
+ if(j < nLibLen - 1)
+ szLibrary[j++] = p1[i];
+ } else {
+ if(j < nVerLen - 1)
+ szVersion[j++] = p1[i];
+ }
+ }
+ }
+ }
+ } return err;
+}
+
+
+//--------------------------------------------------
+// Returns the format name and version meta-info of this document
+// pEncData - EncryptedData object [REQUIRED]
+// returns count or -1 for error.
+//--------------------------------------------------
+EXP_OPTION int dencMetaInfo_GetFormatVersion(DEncEncryptedData* pEncData, char* szFormat, int nFormat, char* szVersion, int nVersion)
+{
+ int err = ERR_OK, i, j, n;
+ DEncEncryptionProperty* pEncProp = 0;
+ char *p1;
+
+ RETURN_IF_NULL_PARAM(pEncData);
+ RETURN_IF_NULL_PARAM(szFormat);
+ RETURN_IF_NULL_PARAM(szVersion);
+ // mark as not found
+ memset(szFormat, 0, nFormat);
+ memset(szVersion, 0, nVersion);
+ pEncProp = dencEncryptedData_FindEncryptionPropertyByName(pEncData, ENCPROP_DOC_FORMAT);
+ if(pEncProp) { // property exists, set the content
+ p1 = (char*)dencEncryptionProperty_GetContent(pEncProp);
+ if(p1) {
+ for(i = j = n = 0; p1[i]; i++) {
+ if(p1[i] == '|' && j < nFormat - 1) {
+ szFormat[j] = 0;
+ j = 0;
+ n++;
+ continue;
+ } else {
+ if(!n) {
+ if(j < nFormat - 1)
+ szFormat[j++] = p1[i];
+ } else {
+ if(j < nVersion - 1)
+ szVersion[j++] = p1[i];
+ }
+ }
+ }
+ }
+ } return err;
+}
+
+//--------------------------------------------------
+// Deletes the meta-info properties
+// pEncData - EncryptedData object [REQUIRED]
+// returns error code or ERR_OK
+//--------------------------------------------------
+EXP_OPTION int dencMetaInfo_deleteVersionInfo(DEncEncryptedData* pEncData)
+{
+ int err = ERR_OK, i, j;
+
+ RETURN_IF_NULL_PARAM(pEncData);
+ // delete doc-format property
+ j = -1;
+ for(i = 0; i < pEncData->encProperties.nEncryptionProperties; i++) {
+ if(pEncData->encProperties.arrEncryptionProperties[i] &&
+ pEncData->encProperties.arrEncryptionProperties[i]->szName &&
+ !strcmp(pEncData->encProperties.arrEncryptionProperties[i]->szName, ENCPROP_DOC_FORMAT)) {
+ j = i;
+ break;
+ }
+ }
+ if(j >= 0)
+ err = dencEncryptedData_DeleteEncryptionProperty(pEncData, j);
+ // delete lib-version property
+ j = -1;
+ for(i = 0; i < pEncData->encProperties.nEncryptionProperties; i++) {
+ if(pEncData->encProperties.arrEncryptionProperties[i] &&
+ pEncData->encProperties.arrEncryptionProperties[i]->szName &&
+ !strcmp(pEncData->encProperties.arrEncryptionProperties[i]->szName, ENCPROP_LIB_VERSION)) {
+ j = i;
+ break;
+ }
+ }
+ if(j >= 0)
+ err = dencEncryptedData_DeleteEncryptionProperty(pEncData, j);
+ return err;
+}
+
+
+//--------------------------------------------------
+// Validates cdoc structure
+// pEncData - EncryptedData object [REQUIRED]
+// returns error code or ERR_OK
+//--------------------------------------------------
+EXP_OPTION int dencValidate(DEncEncryptedData* pEncData)
+{
+ int err = ERR_OK, i;
+ char* p1 = 0;
+ char errbuf[300];
+ X509* pCert = 0;
+
+ if(!pEncData) {
+ printf("\nERROR: 164 Invalid format. No <EncryptedData> found!");
+ SET_LAST_ERROR_RETURN_CODE(ERR_VALIDATE);
+ }
+ // xmlns
+ p1 = (char*)dencEncryptedData_GetXmlNs(pEncData);
+ if(!p1 || strcmp(p1, DENC_XMLNS_XMLENC)) {
+ printf("\nERROR: 164 Invalid xmlns attribute: %s. xmlns attribute is required atribute and only valid value is: %s\n", (p1 ? p1 : ""), DENC_XMLNS_XMLENC);
+ err = ERR_VALIDATE;
+ }
+ // <EncryptionMethod>
+ p1 = (char*)dencEncryptedData_GetEncryptionMethod(pEncData);
+ if(!p1 || strcmp(p1, DENC_ENC_METHOD_AES128)) {
+ printf("\nERROR: 164 Invalid EncryptedData encryption method: %s. Encryption method is required atribute and only valid value is: %s\n", (p1 ? p1 : ""), DENC_ENC_METHOD_AES128);
+ err = ERR_VALIDATE;
+ }
+ // encrypted data itself
+ if(!pEncData->mbufEncryptedData.pMem || !pEncData->mbufEncryptedData.nLen) {
+ printf("\nERROR: 164 empty cdoc! This <EncryptedData> element has no encrypted data!\n");
+ err = ERR_VALIDATE;
+ }
+ // encryption properties
+ for(i = 0; i < dencEncryptedData_GetEncryptionPropertiesCount(pEncData); i++) {
+ DEncEncryptionProperty* pEncProp = dencEncryptedData_GetEncryptionProperty(pEncData, i);
+ if(pEncProp) {
+ p1 = (char*)dencEncryptionProperty_GetName(pEncProp);
+ if(!p1 || !strlen(p1)) {
+ printf("\nERROR: 164 Invalid encryption property: %d. Encryption property name attribute is required and may not be empty!\n", i);
+ err = ERR_VALIDATE;
+ }
+ p1 = (char*)dencEncryptionProperty_GetContent(pEncProp);
+ if(!p1 || !strlen(p1)) {
+ printf("\nERROR: 164 Invalid encryption property: %d. Encryption property content may not be empty!\n", i);
+ err = ERR_VALIDATE;
+ }
+ }
+ }
+ if(!dencEncryptedData_GetEncryptedKeyCount(pEncData)) {
+ printf("\nERROR: 164 Invalid cdoc. This cdoc has no EncryptedKey elements!\n");
+ err = ERR_VALIDATE;
+ }
+ // encrypted keys
+ for(i = 0; i < dencEncryptedData_GetEncryptedKeyCount(pEncData); i++) {
+ DEncEncryptedKey* pEncKey = dencEncryptedData_GetEncryptedKey(pEncData, i);
+ // encryption method
+ p1 = (char*)dencEncryptedKey_GetEncryptionMethod(pEncKey);
+ if(!p1 || strcmp(p1, DENC_ENC_METHOD_RSA1_5)) {
+ printf("\nERROR: 164 Invalid EncryptedKey encryption method: %s. Encryption method is required atribute and only valid value is: %s\n", (p1 ? p1 : ""), DENC_ENC_METHOD_RSA1_5);
+ err = ERR_VALIDATE;
+ }
+ // recipients cert
+ pCert = dencEncryptedKey_GetCertificate(pEncKey);
+ if(!pCert) {
+ printf("\nERROR: 164 Invalid encrypted key: %d. Recipients certificate is required!\n", i);
+ err = ERR_VALIDATE;
+ } else {
+ if(!ddocCertCheckKeyUsage(pCert, KUIDX_DATA_ENCIPHERMENT)) {
+ printf("\nERROR: 164 RecipientsCertificate is not suitable for encryption - keyEncipherment flag not set!\n");
+ err = ERR_VALIDATE;
+ }
+ }
+ }
+
+ // xmlns
+ if(err)
+ SET_LAST_ERROR(err);
+ return err;
+}
+
diff --git a/libdigidoc/DigiDocEnc.h b/libdigidoc/DigiDocEnc.h
new file mode 100644
index 0000000..2f7ab9b
--- /dev/null
+++ b/libdigidoc/DigiDocEnc.h
@@ -0,0 +1,917 @@
+#ifndef __DIGIDOC_ENC_H__
+#define __DIGIDOC_ENC_H__
+//==================================================
+// FILE: DigiDocEnc.h
+// PROJECT: Digi Doc Encryption
+// DESCRIPTION: DigiDocEnc structures
+// AUTHOR: Veiko Sinivee, S|E|B IT Partner Estonia
+//==================================================
+// Copyright (C) AS Sertifitseerimiskeskus
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+// GNU Lesser General Public Licence is available at
+// http://www.gnu.org/copyleft/lesser.html
+//==========< HISTORY >=============================
+// 15.09.2004 Veiko Sinivee
+// Creation
+//==================================================
+
+#include <openssl/x509.h>
+#include <libdigidoc/DigiDocMem.h>
+#include <libdigidoc/DigiDocConfig.h>
+#include <libdigidoc/DigiDocDefs.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+typedef struct DEncEncryptionProperty_st {
+ char* szId; // Id atribute value if present
+ char* szTarget; // Target atribute value if present
+ char* szName; // "name" atribute value if present - used in our implementation
+ char* szContent; // element content if used
+ // TODO - other atributes ?
+} DEncEncryptionProperty;
+
+typedef struct DEncEncryptionProperties_st {
+ char* szId; // Id atribute value if present
+ DEncEncryptionProperty** arrEncryptionProperties; // array of EncryptionProperty pointers
+ int nEncryptionProperties; // number of EncryptionProperty objects
+} DEncEncryptionProperties;
+
+
+typedef struct DEncEncrytedKey_st {
+ char* szId; // Id atribute value if present
+ char* szRecipient; // Recipient atribute value if present
+ char* szEncryptionMethod; // EncryptionMethod element value
+ char* szKeyName; // KeyName element value if used
+ char* szCarriedKeyName; // CarriedKeyName element value if used
+ X509* pCert; // receivers certificate - required in our implementation!
+ DigiDocMemBuf mbufTransportKey; // encrypted transport key
+} DEncEncryptedKey;
+
+typedef struct DEncEncrytedData_st {
+ char* szId; // Id atribute value if present
+ char* szType; // Type atribute value if present
+ char* szMimeType; // MimeType atribute value if present
+ char* szEncryptionMethod; // EncryptionMethod element value
+ char* szXmlNs; // XML namespace
+ DEncEncryptedKey ** arrEncryptedKeys;
+ int nEncryptedKeys;
+ DigiDocMemBuf mbufEncryptedData;
+ DEncEncryptionProperties encProperties;
+
+ // private transient fields
+ DigiDocMemBuf mbufTransportKey; // unencrypted transport key
+ char initVector[16];
+ // flags
+ int nDataStatus;
+ int nKeyStatus;
+} DEncEncryptedData;
+
+typedef struct DEncRecvInfo_st {
+ char* szId; // Id of recipient
+ char* szRecipient; // Recipient atribute value if present
+ char* szKeyName; // KeyName element value if used
+ char* szCarriedKeyName; // CarriedKeyName element value if used
+ X509* pCert; // receivers certificate - required in our implementation!
+} DEncRecvInfo;
+
+typedef struct DEncRecvInfoList_st {
+ int nItems;
+ DEncRecvInfo** pItems;
+} DEncRecvInfoList;
+
+
+
+#define DENC_DATA_STATUS_UNINITIALIZED 0
+#define DENC_DATA_STATUS_UNENCRYPTED_AND_NOT_COMPRESSED 1
+#define DENC_DATA_STATUS_UNENCRYPTED_AND_COMPRESSED 2
+#define DENC_DATA_STATUS_ENCRYPTED_AND_NOT_COMPRESSED 3
+#define DENC_DATA_STATUS_ENCRYPTED_AND_COMPRESSED 4
+
+#define DENC_KEY_STATUS_UNINITIALIZED 0
+#define DENC_KEY_STATUS_INITIALIZED 1
+#define DENC_KEY_STATUS_DISCARDED 2
+
+#define ENCPROP_FILENAME "Filename"
+#define ENCPROP_ORIG_SIZE "OriginalSize"
+#define ENCPROP_ORIG_MIME "OriginalMimeType"
+#define ENCPROP_ORIG_CONTENT "orig_file"
+#define ENCPROP_LIB_VERSION "LibraryVersion"
+#define ENCPROP_DOC_FORMAT "DocumentFormat"
+
+#define DENC_FORMAT_ENCDOC_XML "ENCDOC-XML"
+#define DENC_VERSION_1_0 "1.0"
+#define DENC_VERSION_1_1 "1.1"
+
+#define DENC_COMPRESS_ALLWAYS 0
+#define DENC_COMPRESS_NEVER 1
+#define DENC_COMPRESS_BEST_EFFORT 2
+
+#define DENC_ENCRYPTED_KEY_LEN 128
+#define DENC_DECRYPTED_KEY_LEN 16
+
+#define ENCRYPT 1
+#define DECRYPT 0
+
+#define DENC_ENCDATA_TYPE_DDOC "http://www.sk.ee/DigiDoc/v1.3.0/digidoc.xsd"
+
+#define DENC_ENCDATA_MIME_XML "text/xml"
+#define DENC_ENCDATA_MIME_ZLIB "http://www.isi.edu/in-noes/iana/assignments/media-types/application/zip"
+
+#define DENC_ENC_METHOD_AES128 "http://www.w3.org/2001/04/xmlenc#aes128-cbc"
+#define DENC_ENC_METHOD_RSA1_5 "http://www.w3.org/2001/04/xmlenc#rsa-1_5"
+#define DENC_ENC_METHOD_RSA1_5_BUGGY "http://www.w3.org/2001/04/xmlenc#rsa-1-5"
+#define DENC_XMLNS_XMLENC "http://www.w3.org/2001/04/xmlenc#"
+#define DENC_XMLNS_XMLENC_ELEMENT "http://www.w3.org/2001/04/xmlenc#Element"
+#define DENC_XMLNS_XMLENC_CONTENT "http://www.w3.org/2001/04/xmlenc#Content"
+#define DENC_XMLNS_XMLENC_ENCPROP "http://www.w3.org/2001/04/xmlenc#EncryptionProperties"
+#define DENC_XMLNS_XMLDSIG "http://www.w3.org/2000/09/xmldsig#"
+
+
+//======================< DEncEncryptedData >==============================
+
+ //--------------------------------------------------
+ // "Constructor" of DEncEncryptedData object
+ // pEncData - address of buffer for newly allocated object [REQUIRED]
+ // szXmlNs - XML namespace uri [REQUIRED]
+ // szEncMethod - encyrption method algorithm uri [REQUIRED]
+ // szId - elements Id attribute [OPTIONAL]
+ // szType - elements type atribute [OPTIONAL]
+ // szMimeType - elements mime-type attribute [OPTIONAL]
+ // returns error code or ERR_OK
+ //--------------------------------------------------
+ EXP_OPTION int dencEncryptedData_new(DEncEncryptedData** ppEncData,
+ const char* szXmlNs, const char* szEncMethod,
+ const char* szId, const char* szType,
+ const char* szMimeType);
+
+ //--------------------------------------------------
+ // "Destructor" of DEncEncryptedData object
+ // pEncData - address of object to be deleted [REQUIRED]
+ // returns error code or ERR_OK
+ //--------------------------------------------------
+ EXP_OPTION int dencEncryptedData_free(DEncEncryptedData* pEncData);
+
+ //--------------------------------------------------
+ // Checks if this cdoc has embedded ddoc
+ // pEncData - address of object to be deleted [REQUIRED]
+ // returns 1 if true
+ //--------------------------------------------------
+ EXP_OPTION int dencEncryptedData_IsDdoc(DEncEncryptedData* pEncData);
+
+
+//======================< DEncEncryptedData - accessors >===================
+
+ //--------------------------------------------------
+ // Accessor for Id atribute of DEncEncryptedData object.
+ // pEncData - pointer to DEncEncryptedData object [REQUIRED]
+ // returns value of atribute or NULL.
+ //--------------------------------------------------
+ EXP_OPTION const char* dencEncryptedData_GetId(DEncEncryptedData* pEncData);
+
+ //--------------------------------------------------
+ // Accessor for Type atribute of DEncEncryptedData object.
+ // pEncData - pointer to DEncEncryptedData object [REQUIRED]
+ // returns value of atribute or NULL.
+ //--------------------------------------------------
+ EXP_OPTION const char* dencEncryptedData_GetType(DEncEncryptedData* pEncData);
+
+ //--------------------------------------------------
+ // Accessor for MimeType atribute of DEncEncryptedData object.
+ // pEncData - pointer to DEncEncryptedData object [REQUIRED]
+ // returns value of atribute or NULL.
+ //--------------------------------------------------
+ EXP_OPTION const char* dencEncryptedData_GetMimeType(DEncEncryptedData* pEncData);
+
+ //--------------------------------------------------
+ // Accessor for xmlns atribute of DEncEncryptedData object.
+ // pEncData - pointer to DEncEncryptedData object [REQUIRED]
+ // returns value of atribute or NULL.
+ //--------------------------------------------------
+ EXP_OPTION const char* dencEncryptedData_GetXmlNs(DEncEncryptedData* pEncData);
+
+ //--------------------------------------------------
+ // Accessor for EncryptionMethod subelement of DEncEncryptedData object.
+ // pEncData - pointer to DEncEncryptedData object [REQUIRED]
+ // returns value of atribute or NULL.
+ //--------------------------------------------------
+ EXP_OPTION const char* dencEncryptedData_GetEncryptionMethod(DEncEncryptedData* pEncData);
+
+ //--------------------------------------------------
+ // Accessor for Id atribute of EncryptionProperties subelement of DEncEncryptedData object.
+ // pEncData - pointer to DEncEncryptedData object [REQUIRED]
+ // returns value of atribute or NULL.
+ //--------------------------------------------------
+ EXP_OPTION const char* dencEncryptedData_GetEncryptionPropertiesId(DEncEncryptedData* pEncData);
+
+ //--------------------------------------------------
+ // Accessor for count of EncryptionProperties subelement of DEncEncryptedData object.
+ // pEncData - pointer to DEncEncryptedData object [REQUIRED]
+ // returns count or -1 for error. Then use error API to check errors
+ //--------------------------------------------------
+ EXP_OPTION int dencEncryptedData_GetEncryptionPropertiesCount(DEncEncryptedData* pEncData);
+
+ //--------------------------------------------------
+ // Accessor for EncryptionProperties subelement of DEncEncryptedData object.
+ // pEncData - pointer to DEncEncryptedData object [REQUIRED]
+ // nIdx - index of EncryptionProperty object [REQUIRED]
+ // returns EncryptionProperty pointer or NULL for error
+ //--------------------------------------------------
+ EXP_OPTION DEncEncryptionProperty* dencEncryptedData_GetEncryptionProperty(DEncEncryptedData* pEncData, int nIdx);
+
+ //--------------------------------------------------
+ // Retrieves the last EncryptionProperty subelement of DEncEncryptedData object.
+ // pEncData - pointer to DEncEncryptedData object [REQUIRED]
+ // returns EncryptionProperty pointer or NULL for error
+ //--------------------------------------------------
+ EXP_OPTION DEncEncryptionProperty* dencEncryptedData_GetLastEncryptionProperty(DEncEncryptedData* pEncData);
+
+ //--------------------------------------------------
+ // Finds EncryptionProperty by Name atribute
+ // pEncData - pointer to DEncEncryptedData object [REQUIRED]
+ // name - name of searched property
+ // returns EncryptionProperty pointer or NULL for error
+ //--------------------------------------------------
+ EXP_OPTION DEncEncryptionProperty* dencEncryptedData_FindEncryptionPropertyByName(DEncEncryptedData* pEncData, const char* name);
+
+ //--------------------------------------------------
+ // Accessor for count of EncryptedKey subelement of DEncEncryptedData object.
+ // pEncData - pointer to DEncEncryptedData object [REQUIRED]
+ // returns count or -1 for error. Then use error API to check errors
+ //--------------------------------------------------
+ EXP_OPTION int dencEncryptedData_GetEncryptedKeyCount(DEncEncryptedData* pEncData);
+
+ //--------------------------------------------------
+ // Accessor for EncryptedKey subelement of DEncEncryptedData object.
+ // pEncData - pointer to DEncEncryptedData object [REQUIRED]
+ // nIdx - index of EncryptedKey object [REQUIRED]
+ // returns EncryptedKey pointer or NULL for error
+ //--------------------------------------------------
+ EXP_OPTION DEncEncryptedKey* dencEncryptedData_GetEncryptedKey(DEncEncryptedData* pEncData, int nIdx);
+
+ //--------------------------------------------------
+ // Searches an EncryptedKey by recipients name
+ // pEncData - pointer to DEncEncryptedData object [REQUIRED]
+ // recipient - recipient name used to search the key [REQUIRED]
+ // returns EncryptedKey pointer or NULL for error
+ //--------------------------------------------------
+ EXP_OPTION DEncEncryptedKey* dencEncryptedData_FindEncryptedKeyByRecipient(DEncEncryptedData* pEncData, const char* recipient);
+
+ //--------------------------------------------------
+ // Searches an EncryptedKey by certs CN field
+ // pEncData - pointer to DEncEncryptedData object [REQUIRED]
+ // cn - cert CN used to search the key [REQUIRED]
+ // returns EncryptedKey pointer or NULL for error
+ //--------------------------------------------------
+ EXP_OPTION DEncEncryptedKey* dencEncryptedData_FindEncryptedKeyByCN(DEncEncryptedData* pEncData, const char* cn);
+
+ //--------------------------------------------------
+ // Accessor for EncryptedKey subelement of DEncEncryptedData object.
+ // pEncData - pointer to DEncEncryptedData object [REQUIRED]
+ // returns EncryptedKey pointer or NULL for error
+ //--------------------------------------------------
+ EXP_OPTION DEncEncryptedKey* dencEncryptedData_GetLastEncryptedKey(DEncEncryptedData* pEncData);
+
+ //--------------------------------------------------
+ // Accessor for encrypted data.
+ // pEncData - pointer to DEncEncryptedData object [REQUIRED]
+ // ppBuf - address for encrypted data pointer [REQUIRED]
+ // returns error code or ERR_OK
+ //--------------------------------------------------
+ EXP_OPTION int dencEncryptedData_GetEncryptedData(DEncEncryptedData* pEncData, DigiDocMemBuf** ppBuf);
+
+ //--------------------------------------------------
+ // Accessor for encrypted data status flag.
+ // pEncData - pointer to DEncEncryptedData object [REQUIRED]
+ // returns status or -1 for error. Then use error API to check errors
+ //--------------------------------------------------
+ EXP_OPTION int dencEncryptedData_GetEncryptedDataStatus(DEncEncryptedData* pEncData);
+
+
+//======================< DEncEncryptedData - mutators >===================
+
+ //--------------------------------------------------
+ // Mutatoror for Id atribute of DEncEncryptedData object.
+ // pEncData - pointer to DEncEncryptedData object [REQUIRED]
+ // value - new value for atribute [REQUIRED]
+ // returns error code or ERR_OK
+ //--------------------------------------------------
+ EXP_OPTION int dencEncryptedData_SetId(DEncEncryptedData* pEncData, const char* value);
+
+ //--------------------------------------------------
+ // Mutatoror for Type atribute of DEncEncryptedData object.
+ // pEncData - pointer to DEncEncryptedData object [REQUIRED]
+ // value - new value for atribute [REQUIRED]
+ // returns error code or ERR_OK
+ //--------------------------------------------------
+ EXP_OPTION int dencEncryptedData_SetType(DEncEncryptedData* pEncData, const char* value);
+
+ //--------------------------------------------------
+ // Mutatoror for MimeType atribute of DEncEncryptedData object.
+ // pEncData - pointer to DEncEncryptedData object [REQUIRED]
+ // value - new value for atribute [REQUIRED]
+ // returns error code or ERR_OK
+ //--------------------------------------------------
+ EXP_OPTION int dencEncryptedData_SetMimeType(DEncEncryptedData* pEncData, const char* value);
+
+ //--------------------------------------------------
+ // Mutatoror for xmlns atribute of DEncEncryptedData object.
+ // pEncData - pointer to DEncEncryptedData object [REQUIRED]
+ // value - new value for atribute [REQUIRED]
+ // returns error code or ERR_OK
+ //--------------------------------------------------
+ EXP_OPTION int dencEncryptedData_SetXmlNs(DEncEncryptedData* pEncData, const char* value);
+
+ //--------------------------------------------------
+ // Mutatoror for EncryptionMethod subelement of DEncEncryptedData object.
+ // pEncData - pointer to DEncEncryptedData object [REQUIRED]
+ // value - new value for atribute [REQUIRED]
+ // returns error code or ERR_OK
+ //--------------------------------------------------
+ EXP_OPTION int dencEncryptedData_SetEncryptionMethod(DEncEncryptedData* pEncData, const char* value);
+
+ //--------------------------------------------------
+ // Adds unencrypted data to encrypted data element
+ // waiting to be encrypted in next steps
+ // pEncData - pointer to DEncEncryptedData object [REQUIRED]
+ // data - new unencrypted data [REQUIRED]
+ // len - length of data. Use -1 for null terminated strings [REQUIRED]
+ // returns error code or ERR_OK
+ //--------------------------------------------------
+ EXP_OPTION int dencEncryptedData_AppendData(DEncEncryptedData* pEncData, const char* data, int len);
+
+ //--------------------------------------------------
+ // Mutatoror for Id atribute of EncryptionProperties subelement of DEncEncryptedData object.
+ // pEncData - pointer to DEncEncryptedData object [REQUIRED]
+ // value - new value for atribute [REQUIRED]
+ // returns error code or ERR_OK
+ //--------------------------------------------------
+ EXP_OPTION int dencEncryptedData_SetEncryptionPropertiesId(DEncEncryptedData* pEncData, const char* value);
+
+ //--------------------------------------------------
+ // Deletes EncryptionProperties subelement of DEncEncryptedData object.
+ // pEncData - pointer to DEncEncryptedData object [REQUIRED]
+ // nIdx - index of EncryptionProperty object to be removed [REQUIRED]
+ // returns error code or ERR_OK
+ //--------------------------------------------------
+ EXP_OPTION int dencEncryptedData_DeleteEncryptionProperty(DEncEncryptedData* pEncData, int nIdx);
+
+ //--------------------------------------------------
+ // Deletes EncryptedKey subelement of DEncEncryptedData object.
+ // pEncData - pointer to DEncEncryptedData object [REQUIRED]
+ // nIdx - index of EncryptedKey object to be removed [REQUIRED]
+ // returns error code or ERR_OK
+ //--------------------------------------------------
+ EXP_OPTION int dencEncryptedData_DeleteEncryptedKey(DEncEncryptedData* pEncData, int nIdx);
+
+
+//======================< DEncEncryptionProperty >===================
+
+ //--------------------------------------------------
+ // "Constructor" for EncryptionProperty
+ // pEncData - pointer to DEncEncryptedData object [REQUIRED]
+ // pEncProperty - address of buffer for new property object [REQUIRED]
+ // szId - Id atribute of EncryptionProperty [OPTIONAL]
+ // szTarget - Target atribute of EncryptionProperty [OPTIONAL]
+ // szName - name atribute of EncryptionProperty [OPTIONAL]
+ // szContent - content of EncryptionProperty [OPTIONAL]
+ // returns error code or ERR_OK
+ //--------------------------------------------------
+ EXP_OPTION int dencEncryptionProperty_new(DEncEncryptedData* pEncData,
+ DEncEncryptionProperty** pEncProperty,
+ const char* szId, const char* szTarget,
+ const char* szName, const char* szContent);
+
+ //--------------------------------------------------
+ // "Destructor" for EncryptionProperty
+ // pEncProperty - address of buffer for new property object [REQUIRED]
+ // returns error code or ERR_OK
+ //--------------------------------------------------
+ EXP_OPTION int dencEncryptionProperty_free(DEncEncryptionProperty* pEncProperty);
+
+//======================< DEncEncryptionProperty - accessors >===================
+
+ //--------------------------------------------------
+ // Accessor for Id atribute of EncryptionProperty object.
+ // pEncProp - pointer to DEncEncryptionProperty object [REQUIRED]
+ // returns value of atribute or NULL.
+ //--------------------------------------------------
+ EXP_OPTION const char* dencEncryptionProperty_GetId(DEncEncryptionProperty* pEncProp);
+
+ //--------------------------------------------------
+ // Accessor for Target atribute of EncryptionProperty object.
+ // pEncProp - pointer to DEncEncryptionProperty object [REQUIRED]
+ // returns value of atribute or NULL.
+ //--------------------------------------------------
+ EXP_OPTION const char* dencEncryptionProperty_GetTarget(DEncEncryptionProperty* pEncProp);
+
+ //--------------------------------------------------
+ // Accessor for Name atribute of EncryptionProperty object.
+ // pEncProp - pointer to DEncEncryptionProperty object [REQUIRED]
+ // returns value of atribute or NULL.
+ //--------------------------------------------------
+ EXP_OPTION const char* dencEncryptionProperty_GetName(DEncEncryptionProperty* pEncProp);
+
+ //--------------------------------------------------
+ // Accessor for content of EncryptionProperty object.
+ // pEncProp - pointer to DEncEncryptionProperty object [REQUIRED]
+ // returns value of atribute or NULL.
+ //--------------------------------------------------
+ EXP_OPTION const char* dencEncryptionProperty_GetContent(DEncEncryptionProperty* pEncProp);
+
+//======================< DEncEncryptionProperty - mutators >===================
+
+ //--------------------------------------------------
+ // Mutatoror for Id atribute of DEncEncryptionProperty object.
+ // pEncProp - pointer to DEncEncryptionProperty object [REQUIRED]
+ // value - new value for atribute [REQUIRED]
+ // returns error code or ERR_OK
+ //--------------------------------------------------
+ EXP_OPTION int dencEncryptionProperty_SetId(DEncEncryptionProperty* pEncProp, const char* value);
+
+ //--------------------------------------------------
+ // Mutatoror for Target atribute of DEncEncryptionProperty object.
+ // pEncProp - pointer to DEncEncryptionProperty object [REQUIRED]
+ // value - new value for atribute [REQUIRED]
+ // returns error code or ERR_OK
+ //--------------------------------------------------
+ EXP_OPTION int dencEncryptionProperty_SetTarget(DEncEncryptionProperty* pEncProp, const char* value);
+
+ //--------------------------------------------------
+ // Mutatoror for Name atribute of DEncEncryptionProperty object.
+ // pEncProp - pointer to DEncEncryptionProperty object [REQUIRED]
+ // value - new value for atribute [REQUIRED]
+ // returns error code or ERR_OK
+ //--------------------------------------------------
+ EXP_OPTION int dencEncryptionProperty_SetName(DEncEncryptionProperty* pEncProp, const char* value);
+
+ //--------------------------------------------------
+ // Mutatoror for content of DEncEncryptionProperty object.
+ // pEncProp - pointer to DEncEncryptionProperty object [REQUIRED]
+ // value - new value for atribute [REQUIRED]
+ // returns error code or ERR_OK
+ //--------------------------------------------------
+ EXP_OPTION int dencEncryptionProperty_SetContent(DEncEncryptionProperty* pEncProp, const char* value);
+
+
+//======================< DEncEncryptedKey >===================
+
+ //--------------------------------------------------
+ // "Constructor" for EncryptedKey
+ // Encrypts the transport key for a receiver
+ // and stores encrypted key in memory
+ // Call this function repeatedly for all receivers,
+ // pEncData - pointer to DEncEncryptedData object [REQUIRED]
+ // pEncKey - address of buffer for new encrypted key object [REQUIRED]
+ // pCert - recevers certificate [REQUIRED]
+ // szEncMethod - encryption method [REQUIRED]
+ // szId - Id atribute of EncryptedKey [OPTIONAL]
+ // szRecipient - Recipient atribute of EncryptedKey [OPTIONAL]
+ // szKeyName - KeyName subelement of EncryptedKey [OPTIONAL]
+ // szCarriedKeyName - CarriedKeyName subelement of EncryptedKey [OPTIONAL]
+ // returns error code or ERR_OK
+ //--------------------------------------------------
+ EXP_OPTION int dencEncryptedKey_new(DEncEncryptedData* pEncData,
+ DEncEncryptedKey** pEncKey, X509* pCert,
+ const char* szEncMethod, const char* szId,
+ const char* szRecipient, const char* szKeyName,
+ const char* szCarriedKeyName);
+
+ //--------------------------------------------------
+ // "Destructor" for EncryptedKey
+ // pEncKey - address of buffer for new encrypted key object [REQUIRED]
+ // returns error code or ERR_OK
+ //--------------------------------------------------
+ EXP_OPTION int dencEncryptedKey_free(DEncEncryptedKey* pEncKey);
+
+//======================< DEncEncryptedKey - acessors >===================
+
+ //--------------------------------------------------
+ // Accessor for Id atribute of DEncEncryptedKey object.
+ // pEncKey - pointer to DEncEncryptedKey object [REQUIRED]
+ // returns value of atribute or NULL.
+ //--------------------------------------------------
+ EXP_OPTION const char* dencEncryptedKey_GetId(DEncEncryptedKey* pEncKey);
+
+ //--------------------------------------------------
+ // Accessor for Recipient atribute of DEncEncryptedKey object.
+ // pEncKey - pointer to DEncEncryptedKey object [REQUIRED]
+ // returns value of atribute or NULL.
+ //--------------------------------------------------
+ EXP_OPTION const char* dencEncryptedKey_GetRecipient(DEncEncryptedKey* pEncKey);
+
+ //--------------------------------------------------
+ // Accessor for EncryptionMethod subelement of DEncEncryptedKey object.
+ // pEncKey - pointer to DEncEncryptedKey object [REQUIRED]
+ // returns value of atribute or NULL.
+ //--------------------------------------------------
+ EXP_OPTION const char* dencEncryptedKey_GetEncryptionMethod(DEncEncryptedKey* pEncKey);
+
+ //--------------------------------------------------
+ // Accessor for KeyName subelement of DEncEncryptedKey object.
+ // pEncKey - pointer to DEncEncryptedKey object [REQUIRED]
+ // returns value of atribute or NULL.
+ //--------------------------------------------------
+ EXP_OPTION const char* dencEncryptedKey_GetKeyName(DEncEncryptedKey* pEncKey);
+
+ //--------------------------------------------------
+ // Accessor for CarriedKeyName subelement of DEncEncryptedKey object.
+ // pEncKey - pointer to DEncEncryptedKey object [REQUIRED]
+ // returns value of atribute or NULL.
+ //--------------------------------------------------
+ EXP_OPTION const char* dencEncryptedKey_GetCarriedKeyName(DEncEncryptedKey* pEncKey);
+
+ //--------------------------------------------------
+ // Accessor for certificate of DEncEncryptedKey object.
+ // pEncKey - pointer to DEncEncryptedKey object [REQUIRED]
+ // returns value of atribute or NULL.
+ //--------------------------------------------------
+ EXP_OPTION X509* dencEncryptedKey_GetCertificate(DEncEncryptedKey* pEncKey);
+
+//======================< DEncEncryptedKey - mutators >===================
+
+ //--------------------------------------------------
+ // Mutatoror for Id atribute of DEncEncryptedKey object.
+ // pEncKey - pointer to DEncEncryptedKey object [REQUIRED]
+ // value - new value for atribute [REQUIRED]
+ // returns error code or ERR_OK
+ //--------------------------------------------------
+ EXP_OPTION int dencEncryptedKey_SetId(DEncEncryptedKey* pEncKey, const char* value);
+
+ //--------------------------------------------------
+ // Mutatoror for Recipient atribute of DEncEncryptedKey object.
+ // pEncKey - pointer to DEncEncryptedKey object [REQUIRED]
+ // value - new value for atribute [REQUIRED]
+ // returns error code or ERR_OK
+ //--------------------------------------------------
+ EXP_OPTION int dencEncryptedKey_SetRecipient(DEncEncryptedKey* pEncKey, const char* value);
+
+ //--------------------------------------------------
+ // Mutatoror for EncryptionMethod subelement of DEncEncryptedKey object.
+ // pEncKey - pointer to DEncEncryptedKey object [REQUIRED]
+ // value - new value for atribute [REQUIRED]
+ // returns error code or ERR_OK
+ //--------------------------------------------------
+ EXP_OPTION int dencEncryptedKey_SetEncryptionMethod(DEncEncryptedKey* pEncKey, const char* value);
+
+ //--------------------------------------------------
+ // Mutatoror for KeyName subelement of DEncEncryptedKey object.
+ // pEncKey - pointer to DEncEncryptedKey object [REQUIRED]
+ // value - new value for atribute [REQUIRED]
+ // returns error code or ERR_OK
+ //--------------------------------------------------
+ EXP_OPTION int dencEncryptedKey_SetKeyName(DEncEncryptedKey* pEncKey, const char* value);
+
+ //--------------------------------------------------
+ // Mutatoror for CarriedKeyName subelement of DEncEncryptedKey object.
+ // pEncKey - pointer to DEncEncryptedKey object [REQUIRED]
+ // value - new value for atribute [REQUIRED]
+ // returns error code or ERR_OK
+ //--------------------------------------------------
+ EXP_OPTION int dencEncryptedKey_SetCarriedKeyName(DEncEncryptedKey* pEncKey, const char* value);
+
+ //--------------------------------------------------
+ // Mutatoror for certificate of DEncEncryptedKey object.
+ // pEncKey - pointer to DEncEncryptedKey object [REQUIRED]
+ // value - new value for atribute [REQUIRED]
+ // returns error code or ERR_OK
+ //--------------------------------------------------
+ EXP_OPTION int dencEncryptedKey_SetCertificate(DEncEncryptedKey* pEncKey, X509* value);
+
+//==========< general crypto functions >============
+
+ //--------------------------------------------------
+ // Locates the correct EncryptedKey object by reading
+ // users certificate from smartcard and searching the
+ // right EncryptedKey object
+ // pEncData - pointer to DEncEncryptedData object [REQUIRED]
+ // ppEncKey - address of a buffer for EncryptedKey pointer [REQUIRED]
+ // returns error code or ERR_OK
+ //--------------------------------------------------
+ EXP_OPTION int dencEncryptedData_findEncryptedKeyByPKCS11(DEncEncryptedData* pEncData, DEncEncryptedKey** ppEncKey);
+
+ //--------------------------------------------------
+ // Locates the correct EncryptedKey object by reading
+ // users certificate from smartcard and searching the
+ // right EncryptedKey object
+ // pEncData - pointer to DEncEncryptedData object [REQUIRED]
+ // ppEncKey - address of a buffer for EncryptedKey pointer [REQUIRED]
+ // nSlot - slot nr
+ // returns error code or ERR_OK
+ //--------------------------------------------------
+ EXP_OPTION int dencEncryptedData_findEncryptedKeyByPKCS11UsingSlot(DEncEncryptedData* pEncData, DEncEncryptedKey** ppEncKey, int nSlot);
+
+ //--------------------------------------------------
+ // Locates the correct EncryptedKey object by reading
+ // users certificate and private key from pkcs12 file and searching the
+ // right EncryptedKey object
+ // pEncData - pointer to DEncEncryptedData object [REQUIRED]
+ // ppEncKey - address of a buffer for EncryptedKey pointer [REQUIRED]
+ // ppKey - address of private key pointer. Caller must free [REQUIRED]
+ // szPkcs12File - pkcs12 file name [REQUIRED]
+ // szPasswd - pkcs12 file password [REQUIRED]. Might be empty?
+ // returns error code or ERR_OK
+ //--------------------------------------------------
+ EXP_OPTION int dencEncryptedData_findEncryptedKeyByPKCS12(DEncEncryptedData* pEncData, DEncEncryptedKey** ppEncKey,
+ EVP_PKEY** ppKey, const char* szPkcs12File, const char* szPasswd);
+
+ //--------------------------------------------------
+ // Encrypts data with the generated key
+ // pEncData - pointer to DEncEncryptedData object [REQUIRED]
+ // nCompressOption - flag: DENC_COMPRESS_ALLWAYS,
+ // DENC_COMPRESS_NEVER or DENC_COMPRESS_BEST_EFFORT
+ // returns error code or ERR_OK
+ //--------------------------------------------------
+ EXP_OPTION int dencEncryptedData_encryptData(DEncEncryptedData* pEncData, int nCompressOption);
+
+ //--------------------------------------------------
+ // Decrypts data transport key with ID card and
+ // then decrypts the data with the transport key.
+ // pEncData - pointer to DEncEncryptedData object [REQUIRED]
+ // tKey - decrypted transport key [REQUIRED]
+ // keyLen - length of trasnport key [REQUIRED]
+ // returns error code or ERR_OK
+ //--------------------------------------------------
+ EXP_OPTION int dencEncryptedData_decrypt_withKey(DEncEncryptedData* pEncData,
+ const char* tKey, int keyLen);
+
+ //--------------------------------------------------
+ // Decrypts data with the generated key
+ // pEncData - pointer to DEncEncryptedData object [REQUIRED]
+ // returns error code or ERR_OK
+ //--------------------------------------------------
+ EXP_OPTION int dencEncryptedData_decryptData(DEncEncryptedData* pEncData);
+
+ //--------------------------------------------------
+ // Decrypts data transport key with ID card and
+ // then decrypts the data with the transport key.
+ // pEncData - pointer to DEncEncryptedData object [REQUIRED]
+ // pEncKey - transport key to decrypt [REQUIRED]
+ // pin - pin code for smart card [REQUIRED]
+ // returns error code or ERR_OK
+ //--------------------------------------------------
+ EXP_OPTION int dencEncryptedData_decrypt(DEncEncryptedData* pEncData,
+ DEncEncryptedKey* pEncKey,
+ const char* pin);
+ //--------------------------------------------------
+ // Decrypts data transport key with ID card and
+ // then decrypts the data with the transport key.
+ // pEncData - pointer to DEncEncryptedData object [REQUIRED]
+ // pEncKey - transport key to decrypt [REQUIRED]
+ // pin - pin code for smart card [REQUIRED]
+ // nSlot - slot nr
+ // returns error code or ERR_OK
+ //--------------------------------------------------
+ EXP_OPTION int dencEncryptedData_decryptUsingSlot(DEncEncryptedData* pEncData,
+ DEncEncryptedKey* pEncKey,
+ const char* pin, int nSlot);
+
+ //--------------------------------------------------
+ // Decrypts data transport key with ID card and
+ // then decrypts the data with the transport key.
+ // pEncData - pointer to DEncEncryptedData object [REQUIRED]
+ // pEncKey - transport key to decrypt [REQUIRED]
+ // pKey - private key for decrypting [REQUIRED]
+ // returns error code or ERR_OK
+ //--------------------------------------------------
+ EXP_OPTION int dencEncryptedData_decryptWithKey(DEncEncryptedData* pEncData,
+ DEncEncryptedKey* pEncKey,
+ EVP_PKEY* pKey);
+
+ //--------------------------------------------------
+ // Compresses data with ZLIB. Cannot compress encrypted data!!!
+ // pEncData - pointer to DEncEncryptedData object [REQUIRED]
+ // nCompressOption - flag: DENC_COMPRESS_ALLWAYS,
+ // DENC_COMPRESS_NEVER or DENC_COMPRESS_BEST_EFFORT
+ // returns error code or ERR_OK
+ //--------------------------------------------------
+ EXP_OPTION int dencEncryptedData_compressData(DEncEncryptedData* pEncData, int nCompressOption);
+
+ //--------------------------------------------------
+ // Decompresses data with ZLIB.
+ // pEncData - pointer to DEncEncryptedData object [REQUIRED]
+ // nCompressOption - flag: DENC_COMPRESS_ALLWAYS,
+ // DENC_COMPRESS_NEVER or DENC_COMPRESS_BEST_EFFORT
+ // returns error code or ERR_OK
+ //--------------------------------------------------
+ EXP_OPTION int dencEncryptedData_decompressData(DEncEncryptedData* pEncData);
+
+
+//====================< RecipientInfo functions >==========================
+
+ //--------------------------------------------------
+ // "Constructor" of DEncRecvInfo object
+ // ppRecvInfo - address of buffer for newly allocated object [REQUIRED]
+ // szId - recipients id [REQUIRED]
+ // szRecipient - recipient atribute [OPTIONAL]
+ // szKeyName - KeyName element [OPTIONAL]
+ // szCarriedKeyName - CarriedKeyName element [OPTIONAL]
+ // pCert - certificate [REQUIRED]
+ // returns error code or ERR_OK
+ //--------------------------------------------------
+ EXP_OPTION int dencRecvInfo_new(DEncRecvInfo** ppRecvInfo,
+ const char* szId, const char* szRecipient,
+ const char* szKeyName, const char* szCarriedKeyName,
+ const X509* pCert);
+
+ //--------------------------------------------------
+ // "Destructor" of DEncRecvInfo object
+ // pRecvInfo - address of buffer for newly allocated object [REQUIRED]
+ // returns error code or ERR_OK
+ //--------------------------------------------------
+ EXP_OPTION int dencRecvInfo_free(DEncRecvInfo* pRecvInfo);
+
+ //--------------------------------------------------
+ // Stores DEncRecvInfo object to configuration store
+ // pRecvInfo - address of buffer for newly allocated object [REQUIRED]
+ // returns error code or ERR_OK
+ //--------------------------------------------------
+ EXP_OPTION int dencRecvInfo_store(DEncRecvInfo* pRecvInfo);
+
+ //--------------------------------------------------
+ // Stores DEncRecvInfo object to configuration store
+ // pConfStore - store to search in [OPTIONAL]. Use NULL for default
+ // pRecvInfo - address of buffer for newly allocated object [REQUIRED]
+ // szId - id of the object [REQUIRED]
+ // returns error code or ERR_OK
+ //--------------------------------------------------
+ EXP_OPTION int dencRecvInfo_findById(ConfigurationStore *pConfStore,
+ DEncRecvInfo** ppRecvInfo, const char* szId);
+
+ //--------------------------------------------------
+ // Deletes DEncRecvInfo object from configuration store
+ // pRecvInfo - address of RecvInfo [REQUIRED]
+ // returns error code or ERR_OK
+ //--------------------------------------------------
+ EXP_OPTION int dencRecvInfo_delete(DEncRecvInfo* pRecvInfo);
+
+ //--------------------------------------------------
+ // Returns all DEncRecvInfo objects
+ // pRecvInfoList - address of the list receiving the items [REQUIRED]
+ // returns error code or ERR_OK
+ //--------------------------------------------------
+ EXP_OPTION int dencRecvInfo_findAll(DEncRecvInfoList* pRecvInfoList);
+
+
+//====================< RecipientInfoList functions >==========================
+
+ //--------------------------------------------------
+ // Adds a DEncRecvInfo object to the list
+ // pRecvInfoList - address of the list receiving the item [REQUIRED]
+ // pRecvInfo - new object to be added
+ // returns error code or ERR_OK
+ //--------------------------------------------------
+ EXP_OPTION int dencRecvInfoList_add(DEncRecvInfoList* pRecvInfoList, DEncRecvInfo *pRecvInfo);
+
+ //--------------------------------------------------
+ // Frees the contents of a DEncRecvInfoList object
+ // pRecvInfoList - address of the list [REQUIRED]
+ // returns error code or ERR_OK
+ //--------------------------------------------------
+ EXP_OPTION int dencRecvInfoList_free(DEncRecvInfoList* pRecvInfoList);
+
+ //--------------------------------------------------
+ // Removes the given DEncRecvInfo object from the list
+ // pRecvInfoList - address of the list [REQUIRED]
+ // szId - id of the obect to be removed [REQUIRED]
+ // returns error code or ERR_OK
+ //--------------------------------------------------
+ EXP_OPTION int dencRecvInfoList_delete(DEncRecvInfoList* pRecvInfoList, const char* szId);
+
+//====================< big file functions >==========================
+
+ //--------------------------------------------------
+ // Encrypts a file and writes it to output file
+ // The caller must have initialized the transport keys
+ // but not the data.
+ // pEncData - pointer to DEncEncryptedData object [REQUIRED]
+ // szInputFileName - input data name [REQUIRED]
+ // szOutputFileName - output file name [REQUIRED]
+ // szMimeType - input data mime type [OPTIONAL]
+ // returns error code or ERR_OK
+ //--------------------------------------------------
+ EXP_OPTION int dencEncryptFile(DEncEncryptedData* pEncData,
+ const char* szInputFileName, const char* szOutputFileName,
+ const char* szMimeType);
+
+//====================< original content functions >===================
+
+ //--------------------------------------------------
+ // Returns the count of "orig_file" properties
+ // pEncData - EncryptedData object [REQUIRED]
+ // returns count or -1 for error.
+ //--------------------------------------------------
+ EXP_OPTION int dencOrigContent_count(DEncEncryptedData* pEncData);
+
+ //--------------------------------------------------
+ // Creates a new property of type "orig_file"
+ // pEncData - EncryptedData object [REQUIRED]
+ // szOrigContentId - Id atribute for new Property object [OPTIONAL]
+ // szName - original file name [REQUIRED]
+ // szSize - size as string or irginal file [REQUIRED]
+ // szMime - mime type or original file [REQUIRED]
+ // szDfId - Id atribute of original file [REQUIRED]
+ // returns error code or ERR_OK
+ //--------------------------------------------------
+ EXP_OPTION int dencOrigContent_add(DEncEncryptedData* pEncData, const char* szOrigContentId,
+ const char* szName, const char* szSize, const char* szMime, const char* szDfId);
+
+ //--------------------------------------------------
+ // Returns the info from "orig_file" properties
+ // pEncData - EncryptedData object [REQUIRED]
+ // szOrigContentId - Id atribute for new Property object [OPTIONAL]
+ // szName - buffer for original file name [REQUIRED]
+ // nNameLen - buffer length of szName [REQUIRED]
+ // szSize - buffer for size as string or irginal file [REQUIRED]
+ // nSizeLen - buffer length of szSize [REQUIRED]
+ // szMime - buffer for mime type or original file [REQUIRED]
+ // nMimeLen - buffer length of szMime [REQUIRED]
+ // szDfId - buffer for Id atribute of original file [REQUIRED]
+ // nDfIdLen - buffer length of szDfId [REQUIRED]
+ // returns error code or ERR_OK
+ //--------------------------------------------------
+ EXP_OPTION int dencOrigContent_findByIndex(DEncEncryptedData* pEncData, int origContIdx,
+ char* szName, int nNameLen, char* szSize, int nSizeLen,
+ char* szMime, int nMimeLen, char* szDfId, int nDfIdLen);
+
+ //--------------------------------------------------
+ // Checks if there is a digidoc document in this
+ // encrypted document.
+ // pEncData - EncryptedData object [REQUIRED]
+ // returns 1 if digidoc document is inside
+ //--------------------------------------------------
+ EXP_OPTION int dencOrigContent_isDigiDocInside(DEncEncryptedData* pEncData);
+
+ //--------------------------------------------------
+ // Registers digidoc document as encrypted datatype
+ // and stores it's data file info.
+ // pEncData - EncryptedData object [REQUIRED]
+ // pSigDoc - SignedDoc object [REQUIRED]
+ // returns 1 if digidoc document is inside
+ //--------------------------------------------------
+ EXP_OPTION int dencOrigContent_registerDigiDoc(DEncEncryptedData* pEncData, SignedDoc* pSigDoc);
+
+//====================< other meta-info functions >===================
+
+ //--------------------------------------------------
+ // Sets the library name and version property
+ // pEncData - EncryptedData object [REQUIRED]
+ // returns count or -1 for error.
+ //--------------------------------------------------
+ EXP_OPTION int dencMetaInfo_SetLibVersion(DEncEncryptedData* pEncData);
+
+ //--------------------------------------------------
+ // Sets the format name and version property
+ // pEncData - EncryptedData object [REQUIRED]
+ // returns count or -1 for error.
+ //--------------------------------------------------
+ EXP_OPTION int dencMetaInfo_SetFormatVersion(DEncEncryptedData* pEncData);
+
+ //--------------------------------------------------
+ // Returns the library name and version meta-info of this document
+ // pEncData - EncryptedData object [REQUIRED]
+ // szLibrary - buffer for library name
+ // nLibLen - length of library name buffer
+ // szVersion - buffer for version info
+ // nVerLen - length of version info buffer
+ // returns count or -1 for error.
+ //--------------------------------------------------
+ EXP_OPTION int dencMetaInfo_GetLibVersion(DEncEncryptedData* pEncData, char* szLibrary, int nLibLen, char* szVersion, int nVerLen);
+
+ //--------------------------------------------------
+ // Returns the format name and version meta-info of this document
+ // pEncData - EncryptedData object [REQUIRED]
+ // returns count or -1 for error.
+ //--------------------------------------------------
+ EXP_OPTION int dencMetaInfo_GetFormatVersion(DEncEncryptedData* pEncData, char* szFormat, int nFormatLen, char* szVersion, int nVerLen);
+
+ //--------------------------------------------------
+ // Deletes the meta-info properties
+ // pEncData - EncryptedData object [REQUIRED]
+ // returns error code or ERR_OK
+ //--------------------------------------------------
+ EXP_OPTION int dencMetaInfo_deleteVersionInfo(DEncEncryptedData* pEncData);
+
+ //--------------------------------------------------
+ // Validates cdoc structure
+ // pEncData - EncryptedData object [REQUIRED]
+ // returns error code or ERR_OK
+ //--------------------------------------------------
+ EXP_OPTION int dencValidate(DEncEncryptedData* pEncData);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // __DIGIDOC_ENC_H__
+
+
diff --git a/libdigidoc/DigiDocEncGen.c b/libdigidoc/DigiDocEncGen.c
new file mode 100644
index 0000000..68d613d
--- /dev/null
+++ b/libdigidoc/DigiDocEncGen.c
@@ -0,0 +1,522 @@
+//==================================================
+// FILE: DigiDocEncGen.c
+// PROJECT: Digi Doc Encryption
+// DESCRIPTION: DigiDocEnc XML generation
+// AUTHOR: Veiko Sinivee, S|E|B IT Partner Estonia
+//==================================================
+// Copyright (C) AS Sertifitseerimiskeskus
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+// GNU Lesser General Public Licence is available at
+// http://www.gnu.org/copyleft/lesser.html
+//==========< HISTORY >=============================
+// 11.10.2004 Veiko Sinivee
+// Creation
+//==================================================
+
+#include <libdigidoc/DigiDocDefs.h>
+#include <libdigidoc/DigiDocEncGen.h>
+#include <libdigidoc/DigiDocError.h>
+#include <libdigidoc/DigiDocMem.h>
+#include <libdigidoc/DigiDocLib.h>
+#include <libdigidoc/DigiDocDebug.h>
+#include <libdigidoc/DigiDocConvert.h>
+#include <libdigidoc/DigiDocCert.h>
+#include <libdigidoc/DigiDocGen.h>
+#include <string.h>
+
+#ifdef WIN32
+ #include <wchar.h>
+#endif
+
+//-----------< XML generation functions >----------------------------
+
+//--------------------------------------------------
+// Generates XML for <EncryptionProperty> element
+// pEncProperty - encryption property object [REQUIRED]
+// pBuf - memory buffer for storing xml [REQUIRED]
+// returns error code or ERR_OK
+//--------------------------------------------------
+int dencGenEncryptionProperty_toXML(DEncEncryptionProperty* pEncProperty, DigiDocMemBuf* pBuf)
+{
+ int err = ERR_OK;
+ char* p = 0, *p1 = 0;
+
+ RETURN_IF_NULL_PARAM(pBuf)
+ RETURN_IF_NULL_PARAM(pEncProperty)
+ // start of element
+ err = ddocGen_startElemBegin(pBuf, "denc:EncryptionProperty");
+ if(err) return err;
+ // Id atribute
+ p = (char*)dencEncryptionProperty_GetId(pEncProperty);
+ if(p)
+ err = ddocGen_addAtribute(pBuf, "Id", p);
+ if(err) return err;
+ // Target atribute
+ p = (char*)dencEncryptionProperty_GetTarget(pEncProperty);
+ if(p)
+ err = ddocGen_addAtribute(pBuf, "Target", p);
+ if(err) return err;
+ // Name atribute
+ p = (char*)dencEncryptionProperty_GetName(pEncProperty);
+ if(p)
+ err = ddocGen_addAtribute(pBuf, "Name", p);
+ if(err) return err;
+ // end of element start tag
+ err = ddocGen_startElemEnd(pBuf);
+ if(err) return err;
+ // content
+ p = (char*)dencEncryptionProperty_GetContent(pEncProperty);
+ if(p) {
+ escapeXMLSymbols(p, -1, &p1);
+ err = ddocMemAppendData(pBuf, p1, -1);
+ free(p1);
+ }
+ if(err) return err;
+ err = ddocGen_endElem(pBuf, "denc:EncryptionProperty");
+ return err;
+}
+
+//--------------------------------------------------
+// Generates XML for <EncryptionProperties> element
+// pEncData - encrypted data object [REQUIRED]
+// pBuf - memory buffer for storing xml [REQUIRED]
+// returns error code or ERR_OK
+//--------------------------------------------------
+int dencGenEncryptionProperties_toXML(DEncEncryptedData* pEncData, DigiDocMemBuf* pBuf)
+{
+ int err = ERR_OK;
+ char* p;
+ int n, i;
+
+ RETURN_IF_NULL_PARAM(pBuf)
+ RETURN_IF_NULL_PARAM(pEncData)
+ // count the prperties - do nothing if none exist
+ n = dencEncryptedData_GetEncryptionPropertiesCount(pEncData);
+ if(!n) return err;
+
+ // start of element
+ err = ddocGen_startElemBegin(pBuf, "denc:EncryptionProperties");
+ if(err) return err;
+ // Id atribute
+ p = (char*)dencEncryptedData_GetEncryptionPropertiesId(pEncData);
+ if(p)
+ err = ddocGen_addAtribute(pBuf, "Id", p);
+ if(err) return err;
+ // end of element start tag
+ err = ddocGen_startElemEnd(pBuf);
+ if(err) return err;
+ // content
+ for(i = 0; i < n; i++) {
+ DEncEncryptionProperty* pEncProp = dencEncryptedData_GetEncryptionProperty(pEncData, i);
+ if(pEncProp)
+ err = dencGenEncryptionProperty_toXML(pEncProp, pBuf);
+ if(err) return err;
+ }
+ // end of element
+ err = ddocGen_endElem(pBuf, "denc:EncryptionProperties");
+ return err;
+}
+
+//--------------------------------------------------
+// Generates XML for <EncryptedKey> element
+// pEncKey - encrypted key object [REQUIRED]
+// pBuf - memory buffer for storing xml [REQUIRED]
+// returns error code or ERR_OK
+//--------------------------------------------------
+int dencGenEncryptedKey_toXML(DEncEncryptedKey* pEncKey, DigiDocMemBuf* pBuf)
+{
+ int err = ERR_OK, l1;
+ char* p;
+ X509* pCert;
+
+ RETURN_IF_NULL_PARAM(pBuf)
+ RETURN_IF_NULL_PARAM(pEncKey)
+ // start of element
+ err = ddocGen_startElemBegin(pBuf, "denc:EncryptedKey");
+ if(err) return err;
+ // Id atribute
+ p = (char*)dencEncryptedKey_GetId(pEncKey);
+ if(p)
+ err = ddocGen_addAtribute(pBuf, "Id", p);
+ if(err) return err;
+ // Recipient atribute
+ p = (char*)dencEncryptedKey_GetRecipient(pEncKey);
+ if(p)
+ err = ddocGen_addAtribute(pBuf, "Recipient", p);
+ if(err) return err;
+ // end of element start tag
+ err = ddocGen_startElemEnd(pBuf);
+ if(err) return err;
+ // <EncryptionMethod>
+ p = (char*)dencEncryptedKey_GetEncryptionMethod(pEncKey);
+ if(p) {
+ err = ddocGen_startElemBegin(pBuf, "denc:EncryptionMethod");
+ if(err) return err;
+ err = ddocGen_addAtribute(pBuf, "Algorithm", p);
+ if(err) return err;
+ err = ddocGen_startElemEnd(pBuf);
+ if(err) return err;
+ err = ddocGen_endElem(pBuf, "denc:EncryptionMethod");
+ if(err) return err;
+ }
+ // <KeyInfo>
+ err = ddocGen_startElem(pBuf, "ds:KeyInfo");
+ if(err) return err;
+ // <KeyName>
+ p = (char*)dencEncryptedKey_GetKeyName(pEncKey);
+ if(p) {
+ err = ddocGen_startElem(pBuf, "ds:KeyName");
+ if(err) return err;
+ err = ddocMemAppendData(pBuf, p, -1);
+ if(err) return err;
+ err = ddocGen_endElem(pBuf, "ds:KeyName");
+ if(err) return err;
+ }
+ // <X509Data>/<X509Certificate>
+ pCert = dencEncryptedKey_GetCertificate(pEncKey);
+ if(pCert) {
+ err = ddocGen_startElem(pBuf, "ds:X509Data");
+ if(err) return err;
+ err = ddocGen_startElem(pBuf, "ds:X509Certificate");
+ if(err) return err;
+ p = 0;
+ err = getCertPEM(pCert, 0, &p);
+ if(err) {
+ if(p) free(p);
+ return err;
+ }
+ if(p) {
+ err = ddocMemAppendData(pBuf, p, -1);
+ free(p);
+ p = 0;
+ if(err) return err;
+ }
+ err = ddocGen_endElem(pBuf, "ds:X509Certificate");
+ if(err) return err;
+ err = ddocGen_endElem(pBuf, "ds:X509Data");
+ if(err) return err;
+ }
+ // end of element <KeyInfo>
+ err = ddocGen_endElem(pBuf, "ds:KeyInfo");
+ if(err) return err;
+ // transport key
+ if(pEncKey->mbufTransportKey.pMem && pEncKey->mbufTransportKey.nLen) {
+ l1 = 2 * pEncKey->mbufTransportKey.nLen;
+ p = (char*)malloc(l1);
+ if(!p)
+ SET_LAST_ERROR_RETURN(ERR_BAD_ALLOC, ERR_BAD_ALLOC)
+ memset(p, 0, l1);
+ encode((const byte*)pEncKey->mbufTransportKey.pMem, pEncKey->mbufTransportKey.nLen, (byte*)p, &l1);
+ if(p && l1) {
+ err = ddocGen_startElem(pBuf, "denc:CipherData");
+ if(err) return err;
+ err = ddocGen_startElem(pBuf, "denc:CipherValue");
+ if(err) return err;
+ err = ddocMemAppendData(pBuf, p, -1);
+ free(p);
+ p = 0;
+ if(err) return err;
+ err = ddocGen_endElem(pBuf, "denc:CipherValue");
+ if(err) return err;
+ err = ddocGen_endElem(pBuf, "denc:CipherData");
+ if(err) return err;
+ }
+ }
+ // <CarriedKeyName>
+ p = (char*)dencEncryptedKey_GetCarriedKeyName(pEncKey);
+ if(p) {
+ err = ddocGen_startElem(pBuf, "denc:CarriedKeyName");
+ if(err) return err;
+ err = ddocMemAppendData(pBuf, p, -1);
+ if(err) return err;
+ err = ddocGen_endElem(pBuf, "denc:CarriedKeyName");
+ if(err) return err;
+ }
+ // end of element <EncryptedKey>
+ err = ddocGen_endElem(pBuf, "denc:EncryptedKey");
+ return err;
+}
+
+
+//--------------------------------------------------
+// Generates XML for <EncryptedData> element
+// pEncData - encrypted data object [REQUIRED]
+// pBuf - memory buffer for storing xml [REQUIRED]
+// returns error code or ERR_OK
+//--------------------------------------------------
+EXP_OPTION int dencGenEncryptedData_toXML(DEncEncryptedData* pEncData, DigiDocMemBuf* pBuf)
+{
+ int err = ERR_OK, l1;
+ char* p;
+ int i, n;
+
+ RETURN_IF_NULL_PARAM(pBuf)
+ RETURN_IF_NULL_PARAM(pEncData)
+ // xml header
+ err = ddocMemAppendData(pBuf, "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>", -1);
+ if(err) return err;
+ // start of element
+ err = ddocGen_startElemBegin(pBuf, "denc:EncryptedData");
+ if(err) return err;
+ // xmlns:denc
+ //p = dencEncryptedData_GetXmlNs(pEncData);
+ //if(p)
+ err = ddocGen_addAtribute(pBuf, "xmlns:denc", DENC_XMLNS_XMLENC);
+ if(err) return err;
+ // Id atribute
+ p = (char*)dencEncryptedData_GetId(pEncData);
+ if(p)
+ err = ddocGen_addAtribute(pBuf, "Id", p);
+ if(err) return err;
+ // Type atribute
+ p = (char*)dencEncryptedData_GetType(pEncData);
+ if(p)
+ err = ddocGen_addAtribute(pBuf, "Type", p);
+ if(err) return err;
+ // MimeType atribute
+ p = (char*)dencEncryptedData_GetMimeType(pEncData);
+ if(p)
+ err = ddocGen_addAtribute(pBuf, "MimeType", p);
+ if(err) return err;
+ // Encoding ???
+ // end of element start tag
+ err = ddocGen_startElemEnd(pBuf);
+ if(err) return err;
+ // <EncryptionMethod>
+ p = (char*)dencEncryptedData_GetEncryptionMethod(pEncData);
+ if(p) {
+ err = ddocGen_startElemBegin(pBuf, "denc:EncryptionMethod");
+ if(err) return err;
+ err = ddocGen_addAtribute(pBuf, "Algorithm", p);
+ if(err) return err;
+ // end of element start tag
+ err = ddocGen_startElemEnd(pBuf);
+ if(err) return err;
+ err = ddocGen_endElem(pBuf, "denc:EncryptionMethod");
+ if(err) return err;
+ }
+ n = dencEncryptedData_GetEncryptedKeyCount(pEncData);
+ if(n > 0) {
+ // <KeyInfo>
+ err = ddocGen_startElemBegin(pBuf, "ds:KeyInfo");
+ if(err) return err;
+ // xmlns ???
+ err = ddocGen_addAtribute(pBuf, "xmlns:ds", DENC_XMLNS_XMLDSIG);
+ if(err) return err;
+ err = ddocGen_startElemEnd(pBuf);
+ if(err) return err;
+ // <EncryptedKey>
+ for(i = 0; i < n; i++) {
+ DEncEncryptedKey* pEncKey = dencEncryptedData_GetEncryptedKey(pEncData, i);
+ if(pEncKey) {
+ err = dencGenEncryptedKey_toXML(pEncKey, pBuf);
+ if(err) return err;
+ }
+ }
+ // end of element <KeyInfo>
+ err = ddocGen_endElem(pBuf, "ds:KeyInfo");
+ if(err) return err;
+ }
+ // encrypted data
+ if(pEncData->mbufEncryptedData.pMem && pEncData->mbufEncryptedData.nLen) {
+ l1 = 2 * pEncData->mbufEncryptedData.nLen;
+ p = (char*)malloc(l1);
+ if(!p)
+ SET_LAST_ERROR_RETURN(ERR_BAD_ALLOC, ERR_BAD_ALLOC)
+ memset(p, 0, l1);
+ encode((const byte*)pEncData->mbufEncryptedData.pMem,
+ pEncData->mbufEncryptedData.nLen, (byte*)p, &l1);
+ ddocDebug(4, "dencGenEncryptedData_toXML", "Input data: %d base64: %d", pEncData->mbufEncryptedData.nLen, l1);
+ if(p && l1) {
+ err = ddocGen_startElem(pBuf, "denc:CipherData");
+ if(err) return err;
+ err = ddocGen_startElem(pBuf, "denc:CipherValue");
+ if(err) return err;
+ err = ddocMemAppendData(pBuf, p, -1);
+ free(p);
+ p = 0;
+ if(err) return err;
+ err = ddocGen_endElem(pBuf, "denc:CipherValue");
+ if(err) return err;
+ err = ddocGen_endElem(pBuf, "denc:CipherData");
+ if(err) return err;
+ }
+ }
+ // <EncryptionProperties>
+ if(dencEncryptedData_GetEncryptionPropertiesCount(pEncData) > 0)
+ err = dencGenEncryptionProperties_toXML(pEncData, pBuf);
+ if(err) return err;
+ // end of element <EncryptedData>
+ err = ddocGen_endElem(pBuf, "denc:EncryptedData");
+ return err;
+}
+
+//--------------------------------------------------
+// Writes encrypted data to a file
+// pEncData - encrypted data object [REQUIRED]
+// szFileName - name of the file to write the data [REQUIRED]
+// returns error code or ERR_OK
+//--------------------------------------------------
+EXP_OPTION int dencGenEncryptedData_writeToFile(DEncEncryptedData* pEncData, const char* szFileName)
+{
+ int err = ERR_OK;
+ DigiDocMemBuf mbufEncData;
+ FILE* hFile;
+#ifdef WIN32
+ wchar_t *convFileName = 0;
+ int i= 0;
+ err = utf82unicode((const char*)szFileName, (char**)&convFileName, &i);
+ ddocDebug(3, "ddocGenEncryptedData_writeToFile", "file: %s, conv-file: %s len: %d", szFileName, convFileName, i);
+#else
+ char convFileName[1024];
+ ddocConvertFileName( convFileName, sizeof(convFileName), szFileName );
+#endif
+
+ ddocDebug(3, "dencGenEncryptedData_writeToFile", "filename: %s", szFileName);
+ RETURN_IF_NULL_PARAM(pEncData)
+ RETURN_IF_NULL_PARAM(szFileName)
+ // start of element
+ mbufEncData.pMem = 0;
+ mbufEncData.nLen = 0;
+ err = dencGenEncryptedData_toXML(pEncData, &mbufEncData);
+#ifdef WIN32
+ if(!err && (hFile = _wfopen(convFileName, L"wb")) != NULL) {
+#else
+ if(!err && (hFile = fopen(convFileName, "wb")) != NULL) {
+#endif
+ fwrite(mbufEncData.pMem, mbufEncData.nLen, 1, hFile);
+ fclose(hFile);
+ } else {
+ SET_LAST_ERROR_RETURN_CODE(ERR_FILE_WRITE);
+ ddocDebug(1, "dencGenEncryptedData_writeToFile", "Error writing encrypted document");
+ }
+ // cleanup
+ ddocMemBuf_free(&mbufEncData);
+ return err;
+}
+
+
+//--------------------------------------------------
+// Generates the header of XML for <EncryptedData> element
+// This contains everything upto the start of base64 encoded cipher data
+// pEncData - encrypted data object [REQUIRED]
+// pBuf - memory buffer for storing xml [REQUIRED]
+// returns error code or ERR_OK
+//--------------------------------------------------
+int dencGenEncryptedData_header_toXML(DEncEncryptedData* pEncData, DigiDocMemBuf* pBuf)
+{
+ int err = ERR_OK;
+ char* p;
+ int i, n;
+
+ RETURN_IF_NULL_PARAM(pBuf)
+ RETURN_IF_NULL_PARAM(pEncData)
+ // xml header
+ err = ddocMemAppendData(pBuf, "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>", -1);
+ if(err) return err;
+ // start of element
+ err = ddocGen_startElemBegin(pBuf, "denc:EncryptedData");
+ if(err) return err;
+ // xmlns:denc
+ //p = dencEncryptedData_GetXmlNs(pEncData);
+ //if(p)
+ err = ddocGen_addAtribute(pBuf, "xmlns:denc", DENC_XMLNS_XMLENC);
+ if(err) return err;
+ // Id atribute
+ p = (char*)dencEncryptedData_GetId(pEncData);
+ if(p)
+ err = ddocGen_addAtribute(pBuf, "Id", p);
+ if(err) return err;
+ // Type atribute
+ p = (char*)dencEncryptedData_GetType(pEncData);
+ if(p)
+ err = ddocGen_addAtribute(pBuf, "Type", p);
+ if(err) return err;
+ // MimeType atribute
+ p = (char*)dencEncryptedData_GetMimeType(pEncData);
+ if(p)
+ err = ddocGen_addAtribute(pBuf, "MimeType", p);
+ if(err) return err;
+ // Encoding ???
+ // end of element start tag
+ err = ddocGen_startElemEnd(pBuf);
+ if(err) return err;
+ // <EncryptionMethod>
+ p = (char*)dencEncryptedData_GetEncryptionMethod(pEncData);
+ if(p) {
+ err = ddocGen_startElemBegin(pBuf, "denc:EncryptionMethod");
+ if(err) return err;
+ err = ddocGen_addAtribute(pBuf, "Algorithm", p);
+ if(err) return err;
+ // end of element start tag
+ err = ddocGen_startElemEnd(pBuf);
+ if(err) return err;
+ err = ddocGen_endElem(pBuf, "denc:EncryptionMethod");
+ if(err) return err;
+ }
+ n = dencEncryptedData_GetEncryptedKeyCount(pEncData);
+ if(n > 0) {
+ // <KeyInfo>
+ err = ddocGen_startElemBegin(pBuf, "ds:KeyInfo");
+ if(err) return err;
+ // xmlns ???
+ err = ddocGen_addAtribute(pBuf, "xmlns:ds", DENC_XMLNS_XMLDSIG);
+ if(err) return err;
+ err = ddocGen_startElemEnd(pBuf);
+ if(err) return err;
+ // <EncryptedKey>
+ for(i = 0; i < n; i++) {
+ DEncEncryptedKey* pEncKey = dencEncryptedData_GetEncryptedKey(pEncData, i);
+ if(pEncKey) {
+ err = dencGenEncryptedKey_toXML(pEncKey, pBuf);
+ if(err) return err;
+ }
+ }
+ // end of element <KeyInfo>
+ err = ddocGen_endElem(pBuf, "ds:KeyInfo");
+ if(err) return err;
+ }
+ // encrypted data
+ err = ddocGen_startElem(pBuf, "denc:CipherData");
+ if(err) return err;
+ err = ddocGen_startElem(pBuf, "denc:CipherValue");
+ // here would come the base64 encoded cipher data
+ return err;
+}
+
+
+//--------------------------------------------------
+// Generates the trailer of XML for <EncryptedData> element
+// These are all the XML constructs following the
+// base64 encoded cipher data.
+// pEncData - encrypted data object [REQUIRED]
+// pBuf - memory buffer for storing xml [REQUIRED]
+// returns error code or ERR_OK
+//--------------------------------------------------
+int dencGenEncryptedData_trailer_toXML(DEncEncryptedData* pEncData, DigiDocMemBuf* pBuf)
+{
+ int err = ERR_OK;
+
+ RETURN_IF_NULL_PARAM(pBuf)
+ RETURN_IF_NULL_PARAM(pEncData)
+ // here ends the base64 encoded cipher data
+ err = ddocGen_endElem(pBuf, "denc:CipherValue");
+ if(err) return err;
+ err = ddocGen_endElem(pBuf, "denc:CipherData");
+ if(err) return err;
+ // <EncryptionProperties>
+ if(dencEncryptedData_GetEncryptionPropertiesCount(pEncData) > 0)
+ err = dencGenEncryptionProperties_toXML(pEncData, pBuf);
+ if(err) return err;
+ // end of element <EncryptedData>
+ err = ddocGen_endElem(pBuf, "denc:EncryptedData");
+ return err;
+}
+
diff --git a/libdigidoc/DigiDocEncGen.h b/libdigidoc/DigiDocEncGen.h
new file mode 100644
index 0000000..248a4f9
--- /dev/null
+++ b/libdigidoc/DigiDocEncGen.h
@@ -0,0 +1,74 @@
+#ifndef __DIGIDOC_ENC_GEN_H__
+#define __DIGIDOC_ENC_GEN_H__
+//==================================================
+// FILE: DigiDocEncGen.h
+// PROJECT: Digi Doc Encryption
+// DESCRIPTION: DigiDocEnc XML generation
+// AUTHOR: Veiko Sinivee, S|E|B IT Partner Estonia
+//==================================================
+// Copyright (C) AS Sertifitseerimiskeskus
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+// GNU Lesser General Public Licence is available at
+// http://www.gnu.org/copyleft/lesser.html
+//==========< HISTORY >=============================
+// 11.10.2004 Veiko Sinivee
+// Creation
+//==================================================
+
+
+#include <libdigidoc/DigiDocDefs.h>
+#include <libdigidoc/DigiDocEnc.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+ //--------------------------------------------------
+ // Generates XML for <EncryptedData> element
+ // pEncData - encrypted data object [REQUIRED]
+ // pBuf - memory buffer for storing xml [REQUIRED]
+ // returns error code or ERR_OK
+ //--------------------------------------------------
+ EXP_OPTION int dencGenEncryptedData_toXML(DEncEncryptedData* pEncData, DigiDocMemBuf* pBuf);
+
+ //--------------------------------------------------
+ // Writes encrypted data to a file
+ // pEncData - encrypted data object [REQUIRED]
+ // szFileName - name of the file to write the data [REQUIRED]
+ // returns error code or ERR_OK
+ //--------------------------------------------------
+ EXP_OPTION int dencGenEncryptedData_writeToFile(DEncEncryptedData* pEncData, const char* szFileName);
+
+ //--------------------------------------------------
+ // Generates the header of XML for <EncryptedData> element
+ // This contains everything upto the start of base64 encoded cipher data
+ // pEncData - encrypted data object [REQUIRED]
+ // pBuf - memory buffer for storing xml [REQUIRED]
+ // returns error code or ERR_OK
+ //--------------------------------------------------
+ int dencGenEncryptedData_header_toXML(DEncEncryptedData* pEncData, DigiDocMemBuf* pBuf);
+
+ //--------------------------------------------------
+ // Generates the trailer of XML for <EncryptedData> element
+ // These are all the XML constructs following the
+ // base64 encoded cipher data.
+ // pEncData - encrypted data object [REQUIRED]
+ // pBuf - memory buffer for storing xml [REQUIRED]
+ // returns error code or ERR_OK
+ //--------------------------------------------------
+ int dencGenEncryptedData_trailer_toXML(DEncEncryptedData* pEncData, DigiDocMemBuf* pBuf);
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif // __DIGIDOC_ENC_GEN_H__
+
diff --git a/libdigidoc/DigiDocEncSAXParser.c b/libdigidoc/DigiDocEncSAXParser.c
new file mode 100644
index 0000000..bfd347b
--- /dev/null
+++ b/libdigidoc/DigiDocEncSAXParser.c
@@ -0,0 +1,1155 @@
+//==================================================
+// FILE: DigiDocEncSAXParser.c
+// PROJECT: Digi Doc Encryption
+// DESCRIPTION: DigiDocEnc XML SAX parsing
+// AUTHOR: Veiko Sinivee, S|E|B IT Partner Estonia
+//==================================================
+// Copyright (C) AS Sertifitseerimiskeskus
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+// GNU Lesser General Public Licence is available at
+// http://www.gnu.org/copyleft/lesser.html
+//==========< HISTORY >=============================
+// 11.10.2004 Veiko Sinivee
+// Creation
+//==================================================
+
+#ifdef WIN32
+#include <windows.h>
+#endif
+
+#include <libdigidoc/DigiDocDefs.h>
+#include <libdigidoc/DigiDocEncSAXParser.h>
+#include <libdigidoc/DigiDocError.h>
+#include <libdigidoc/DigiDocDebug.h>
+#include <libdigidoc/DigiDocStack.h>
+#include <libdigidoc/DigiDocConvert.h>
+#include <libdigidoc/DigiDocLib.h>
+#include <libdigidoc/DigiDocPKCS11.h>
+#include <libdigidoc/DigiDocCert.h>
+#include <libdigidoc/DigiDocDfExtract.h>
+
+#include <openssl/sha.h>
+#include <openssl/rsa.h>
+#include <openssl/evp.h>
+#include <zlib.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <memory.h>
+#include <string.h>
+
+
+#include <libxml/globals.h>
+#include <libxml/xmlerror.h>
+#include <libxml/parser.h>
+#include <libxml/parserInternals.h> /* only for xmlNewInputFromFile() */
+
+//===============< SAX handlers >==============================
+
+/*
+* Working area for XML parsing with SAX
+*/
+typedef struct DEncParse_st {
+ DEncEncryptedData* pEncData; // document file to be filled with data
+ int errcode;
+ ElementEntry dencStack; // stack used for keeping the current parsing position
+ DigiDocMemBuf mbufContent; // used for collecting element content
+ int bCollectMode; // flag to switch collection of content on and off
+ char errmsg[100];
+} DEncParse;
+
+
+//--------------------------------------------------
+// Cleans up the memory that might habe been allocated
+// during parsing process
+// pctx - SAX parser context
+//--------------------------------------------------
+void dencSaxCleanup(DEncParse* pctx)
+{
+ ddocMemBuf_free(&(pctx->mbufContent));
+ memset(pctx, 0, sizeof(DEncParse));
+}
+
+//--------------------------------------------------
+// Handles the <EncryptedData> start event
+// pctx - SAX parser context
+// atts - array of atribute names and values
+// returns error code or ERR_OK.
+//--------------------------------------------------
+
+int dencSaxHandleStartEncryptedData(DEncParse* pctx, const xmlChar** atts)
+{
+ int i, err = ERR_OK;
+ char *id = NULL, *type = NULL, *mime = NULL, *xmlns = NULL;
+
+ // check the atributes
+ for(i = 0; atts && atts[i] && atts[i+1]; i++) {
+ if(!strcmp((char*)atts[i], "Id"))
+ id = (char*)atts[i+1];
+ if(!strcmp((char*)atts[i], "Type"))
+ type = (char*)atts[i+1];
+ if(!strcmp((char*)atts[i], "MimeType"))
+ mime = (char*)atts[i+1];
+ if(!strncmp((char*)atts[i], "xmlns", 5))
+ xmlns = (char*)atts[i+1];
+ }
+ // create new EncryptedData object
+ err = dencEncryptedData_new(&(pctx->pEncData), xmlns, NULL, id, type, mime);
+ // delete automatically generated meta info to read the stuff from file
+ err = dencMetaInfo_deleteVersionInfo(pctx->pEncData);
+ return err;
+}
+
+//--------------------------------------------------
+// Handles the <EncryptionMethod> start event
+// pctx - SAX parser context
+// atts - array of atribute names and values
+// returns error code or ERR_OK.
+//--------------------------------------------------
+int dencSaxHandleStartEncryptionMethod(DEncParse* pctx, const xmlChar** atts)
+{
+ int i, err = ERR_OK;
+ char *alg = NULL;
+
+ // check the atributes
+ for(i = 0; atts && atts[i] && atts[i+1]; i++) {
+ if(!strcmp((char*)atts[i], "Algorithm"))
+ alg = (char*)atts[i+1];
+ }
+ // check the EncryptionMethod position in xml doc
+ if(ddocStackHasParentWithName(&(pctx->dencStack), (xmlChar*)"EncryptedKey", NULL)) {
+ DEncEncryptedKey* pEncKey = dencEncryptedData_GetLastEncryptedKey(pctx->pEncData);
+ if(pEncKey)
+ err = dencEncryptedKey_SetEncryptionMethod(pEncKey, alg);
+ } else
+ if(ddocStackHasParentWithName(&(pctx->dencStack), (xmlChar*)"EncryptedData", NULL))
+ err = dencEncryptedData_SetEncryptionMethod(pctx->pEncData, alg);
+ return err;
+}
+
+//--------------------------------------------------
+// Handles the <EncryptedKey> start event
+// pctx - SAX parser context
+// atts - array of atribute names and values
+// returns error code or ERR_OK.
+//--------------------------------------------------
+int dencSaxHandleStartEncryptedKey(DEncParse* pctx, const xmlChar** atts)
+{
+ int i;
+ char *id = NULL, *recipient = NULL;
+ DEncEncryptedKey* pEncKey = 0;
+
+ // check the atributes
+ for(i = 0; atts && atts[i] && atts[i+1]; i++) {
+ if(!strcmp((char*)atts[i], "Id"))
+ id = (char*)atts[i+1];
+ if(!strcmp((char*)atts[i], "Recipient"))
+ recipient = (char*)atts[i+1];
+ }
+ // create new EncryptedData object
+ return dencEncryptedKey_new(pctx->pEncData, &pEncKey, NULL, NULL,
+ id, recipient, NULL, NULL);
+}
+
+//--------------------------------------------------
+// Handles the <X509Certificate> end event
+// pctx - SAX parser context
+// atts - array of atribute names and values
+// returns error code or ERR_OK.
+//--------------------------------------------------
+int dencSaxHandleEndX509Certificate(DEncParse* pctx)
+{
+ int err = ERR_OK;
+ X509 *pCert = 0;
+ DEncEncryptedKey* pEncKey = 0;
+
+ err = ddocDecodeX509PEMData(&pCert, (const char*)pctx->mbufContent.pMem, (int)pctx->mbufContent.nLen);
+ if(err) return err;
+ pEncKey = dencEncryptedData_GetLastEncryptedKey(pctx->pEncData);
+ if(pEncKey)
+ err = dencEncryptedKey_SetCertificate(pEncKey, pCert);
+ ddocDebug(4, "dencSaxHandleEndX509Certificate", "EncKey: %s, cert: %s rc: %d",
+ (pEncKey ? "OK" : "NULL"), (pCert ? "OK" : "NULL"), err);
+ // reset collect mode and cleanup
+ pctx->bCollectMode = 0;
+ ddocMemBuf_free(&(pctx->mbufContent));
+ return err;
+}
+
+//--------------------------------------------------
+// Handles the <KeyName> end event
+// pctx - SAX parser context
+// atts - array of atribute names and values
+// returns error code or ERR_OK.
+//--------------------------------------------------
+int dencSaxHandleEndKeyName(DEncParse* pctx)
+{
+ int err = ERR_OK;
+
+ DEncEncryptedKey* pEncKey = dencEncryptedData_GetLastEncryptedKey(pctx->pEncData);
+ if(pEncKey)
+ err = dencEncryptedKey_SetKeyName(pEncKey, (char*)pctx->mbufContent.pMem);
+ ddocDebug(4, "dencSaxHandleEndKeyName", "EncKey: %s, KeyName: %s rc: %d",
+ (pEncKey ? "OK" : "NULL"), (pctx->mbufContent.pMem ? pctx->mbufContent.pMem : "NULL"), err);
+ // reset collect mode and cleanup
+ pctx->bCollectMode = 0;
+ ddocMemBuf_free(&(pctx->mbufContent));
+ return err;
+}
+
+//--------------------------------------------------
+// Handles the <CarriedKeyName> end event
+// pctx - SAX parser context
+// atts - array of atribute names and values
+// returns error code or ERR_OK.
+//--------------------------------------------------
+int dencSaxHandleEndCarriedKeyName(DEncParse* pctx)
+{
+ int err = ERR_OK;
+
+ DEncEncryptedKey* pEncKey = dencEncryptedData_GetLastEncryptedKey(pctx->pEncData);
+ if(pEncKey)
+ err = dencEncryptedKey_SetCarriedKeyName(pEncKey, (char*)pctx->mbufContent.pMem);
+ ddocDebug(4, "dencSaxHandleEndKeyName", "EncKey: %s, CarriedKeyName: %s rc: %d",
+ (pEncKey ? "OK" : "NULL"), (pctx->mbufContent.pMem ? pctx->mbufContent.pMem : "NULL"), err);
+ // reset collect mode and cleanup
+ pctx->bCollectMode = 0;
+ ddocMemBuf_free(&(pctx->mbufContent));
+ return err;
+}
+
+//--------------------------------------------------
+// Handles the <CipherValue> end event
+// pctx - SAX parser context
+// atts - array of atribute names and values
+// returns error code or ERR_OK.
+//--------------------------------------------------
+int dencSaxHandleEndCipherValue(DEncParse* pctx)
+{
+ int err = ERR_OK, l = 0, i;
+ char *p = 0;
+ EVP_ENCODE_CTX ectx;
+
+ if(pctx->mbufContent.pMem && pctx->mbufContent.nLen) {
+ l = pctx->mbufContent.nLen; // enough since it's shrinking
+ p = (char*)malloc(l);
+ RETURN_IF_BAD_ALLOC(p)
+ //decode((const byte*)pctx->mbufContent.pMem, pctx->mbufContent.nLen, p, &l);
+ EVP_DecodeInit(&ectx);
+ EVP_DecodeUpdate(&ectx, (unsigned char*)p, &l, (unsigned char*)pctx->mbufContent.pMem, pctx->mbufContent.nLen);
+ ddocDebug(3, "dencSaxHandleEndCipherValue", "Initial decoding: %d -> %d bytes", pctx->mbufContent.nLen, l);
+ i = pctx->mbufContent.nLen - l;
+ EVP_DecodeFinal(&ectx, (unsigned char*)p+l, &i);
+ l += i;
+ ddocDebug(3, "dencSaxHandleEndCipherValue", "Final decoding: %d bytes", i);
+ ddocDebug(3, "dencSaxHandleEndCipherValue", "Decoding: %d bytes of base64 data, got: %d bytes", pctx->mbufContent.nLen, l);
+ ddocMemBuf_free(&(pctx->mbufContent));
+ }
+ if(p) {
+ // check the EncryptionMethod position in xml doc
+ if(ddocStackHasParentWithName(&(pctx->dencStack), (xmlChar*)"EncryptedKey", NULL)) {
+ DEncEncryptedKey* pEncKey = dencEncryptedData_GetLastEncryptedKey(pctx->pEncData);
+ if(pEncKey) {
+ pEncKey->mbufTransportKey.pMem = p;
+ pEncKey->mbufTransportKey.nLen = l;
+ ddocDebug(4, "dencSaxHandleEndCipherValue", "Set encrypted tarnsport key: %d bytes", l);
+ } else
+ free(p);
+ } else {
+ if(ddocStackHasParentWithName(&(pctx->dencStack), (xmlChar*)"EncryptedData", NULL)) {
+ pctx->pEncData->mbufEncryptedData.pMem = p;
+ pctx->pEncData->mbufEncryptedData.nLen = l;
+ ddocDebug(4, "dencSaxHandleEndCipherValue", "Set encrypted data: %d bytes", l);
+ if(pctx->pEncData->szMimeType &&
+ (!strcmp(pctx->pEncData->szMimeType, DENC_ENCDATA_MIME_ZLIB)))
+ pctx->pEncData->nDataStatus = DENC_DATA_STATUS_ENCRYPTED_AND_COMPRESSED;
+ else
+ pctx->pEncData->nDataStatus = DENC_DATA_STATUS_ENCRYPTED_AND_NOT_COMPRESSED;
+ } else
+ free(p);
+ }
+ }
+ // reset collect mode and cleanup
+ pctx->bCollectMode = 0;
+ return err;
+}
+
+//--------------------------------------------------
+// Handles the <EncryptionProperties> start event
+// pctx - SAX parser context
+// atts - array of atribute names and values
+// returns error code or ERR_OK.
+//--------------------------------------------------
+int dencSaxHandleStartEncryptionProperties(DEncParse* pctx, const xmlChar** atts)
+{
+ int i, err = ERR_OK;
+ char *id = NULL;
+
+ // check the atributes
+ for(i = 0; atts && atts[i] && atts[i+1]; i++) {
+ if(!strcmp((char*)atts[i], "Id"))
+ id = (char*)atts[i+1];
+ }
+ if(id)
+ err = dencEncryptedData_SetEncryptionPropertiesId(pctx->pEncData, id);
+ return err;
+}
+
+//--------------------------------------------------
+// Handles the <EncryptionProperty> start event
+// pctx - SAX parser context
+// atts - array of atribute names and values
+// returns error code or ERR_OK.
+//--------------------------------------------------
+int dencSaxHandleStartEncryptionProperty(DEncParse* pctx, const xmlChar** atts)
+{
+ int i, err = ERR_OK;
+ char *id = NULL, *target = NULL, *name = NULL;
+ DEncEncryptionProperty* pEncProperty = 0;
+
+ // check the atributes
+ for(i = 0; atts && atts[i] && atts[i+1]; i++) {
+ if(!strcmp((char*)atts[i], "Id"))
+ id = (char*)atts[i+1];
+ if(!strcmp((char*)atts[i], "Target"))
+ target = (char*)atts[i+1];
+ if(!strcmp((char*)atts[i], "Name"))
+ name = (char*)atts[i+1];
+ }
+ err = dencEncryptionProperty_new(pctx->pEncData, &pEncProperty,
+ id, target, name, NULL);
+ if(err) return err;
+ pctx->bCollectMode = 1;
+ ddocMemBuf_free(&(pctx->mbufContent));
+ return err;
+}
+
+//--------------------------------------------------
+// Handles the <EncryptionProperty> end event
+// pctx - SAX parser context
+// atts - array of atribute names and values
+// returns error code or ERR_OK.
+//--------------------------------------------------
+int dencSaxHandleEndEncryptionProperty(DEncParse* pctx)
+{
+ int err = ERR_OK;
+ DEncEncryptionProperty* pEncProperty = 0;
+
+ if(pctx->mbufContent.pMem && pctx->mbufContent.nLen) {
+ pEncProperty = dencEncryptedData_GetLastEncryptionProperty(pctx->pEncData);
+ if(pEncProperty)
+ err = dencEncryptionProperty_SetContent(pEncProperty, (char*)pctx->mbufContent.pMem);
+ ddocMemBuf_free(&(pctx->mbufContent));
+ }
+ pctx->bCollectMode = 0;
+ return err;
+}
+
+
+
+//===============< SAX handlers >==============================
+
+//--------------------------------------------------
+// dencStartElementHandler:
+// @ctxt: An XML parser context
+// @name: The element name
+// called when an opening tag has been processed.
+//--------------------------------------------------
+static void dencStartElementHandler(void *ctx, const xmlChar *name, const xmlChar **atts)
+{
+ DEncParse* pctx = (DEncParse*)ctx;
+ ElementEntry* pCurrElem = 0;
+
+ ddocDebug(5, "dencStartElementHandler", "<%s>, err: %d", (const char*)name, pctx->errcode);
+ if(pctx->errcode) return; // if error skip all additional parsing
+ pctx->errcode = ddocStackPushElementSAX(&(pctx->dencStack), name, atts, &pCurrElem);
+ if(pctx->errcode) return;
+ // check the element name
+ if(pCurrElem) {
+ if(!strcmp((const char*)pCurrElem->tag, "EncryptedData"))
+ pctx->errcode = dencSaxHandleStartEncryptedData(pctx, atts);
+ if(!strcmp((const char*)pCurrElem->tag, "EncryptionMethod"))
+ pctx->errcode = dencSaxHandleStartEncryptionMethod(pctx, atts);
+ if(!strcmp((const char*)pCurrElem->tag, "EncryptedKey"))
+ pctx->errcode = dencSaxHandleStartEncryptedKey(pctx, atts);
+ // start collecting certificate data
+ if(!strcmp((const char*)pCurrElem->tag, "X509Certificate") ||
+ !strcmp((const char*)pCurrElem->tag, "KeyName") ||
+ !strcmp((const char*)pCurrElem->tag, "CipherValue") ||
+ !strcmp((const char*)pCurrElem->tag, "CarriedKeyName") ) {
+ pctx->bCollectMode = 1;
+ ddocMemBuf_free(&(pctx->mbufContent));
+ }
+ if(!strcmp((const char*)pCurrElem->tag, "EncryptionProperties"))
+ pctx->errcode = dencSaxHandleStartEncryptionProperties(pctx, atts);
+ if(!strcmp((const char*)pCurrElem->tag, "EncryptionProperty"))
+ pctx->errcode = dencSaxHandleStartEncryptionProperty(pctx, atts);
+ }
+}
+
+//--------------------------------------------------
+// dencEndElementHandler:
+// @ctxt: An XML parser context
+// @name: The element name
+// called when the end of an element has been detected.
+//--------------------------------------------------
+static void dencEndElementHandler(void *ctx, const xmlChar *name)
+{
+ DEncParse* pctx = (DEncParse*)ctx;
+ ElementEntry* pCurrElem = 0;
+
+ ddocDebug(5, "dencEndElementHandler", "</%s>, err: %d", (const char*)name, pctx->errcode);
+ if(pctx->errcode) return; // if error skip all additional parsing
+ // find last element
+ pCurrElem = ddocStackFindEnd(&(pctx->dencStack));
+ // check the element name
+ if(pCurrElem) {
+ if(!strcmp((const char*)pCurrElem->tag, "X509Certificate"))
+ pctx->errcode = dencSaxHandleEndX509Certificate(pctx);
+ if(!strcmp((const char*)pCurrElem->tag, "KeyName"))
+ pctx->errcode = dencSaxHandleEndKeyName(pctx);
+ if(!strcmp((const char*)pCurrElem->tag, "CarriedKeyName"))
+ pctx->errcode = dencSaxHandleEndCarriedKeyName(pctx);
+ if(!strcmp((const char*)pCurrElem->tag, "CipherValue"))
+ pctx->errcode = dencSaxHandleEndCipherValue(pctx);
+ if(!strcmp((const char*)pCurrElem->tag, "EncryptionProperty"))
+ pctx->errcode = dencSaxHandleEndEncryptionProperty(pctx);
+ }
+ // pop stack
+ pctx->errcode = ddocStackPopElement(&(pctx->dencStack), 0, NULL);
+}
+
+//--------------------------------------------------
+// dencCharactersHandler:
+// @ctxt: An XML parser context
+// @ch: a xmlChar string
+// @len: the number of xmlChar
+// receiving some chars from the parser.
+//--------------------------------------------------
+static void dencCharactersHandler(void *ctx, const xmlChar *ch, int len)
+{
+ DEncParse* pctx = (DEncParse*)ctx;
+
+ ddocDebug(5, "dencCharactersHandler", "err: %d", pctx->errcode);
+ if(pctx->errcode) return; // if error skip all additional parsing
+
+ if(pctx->bCollectMode) {
+ pctx->errcode = ddocMemAppendData(&(pctx->mbufContent), (char*)ch, len);
+ }
+
+ ddocDebug(5, "dencCharactersHandler: %s", "End");
+}
+
+
+//--------------------------------------------------
+// cdataBlockHandler:
+// @ctx: the user data (XML parser context)
+// @value: The pcdata content
+// @len: the block length
+// called when a pcdata block has been parsed
+//--------------------------------------------------
+static void dencCdataBlockHandler(void * ctx, const xmlChar *value, int len)
+{
+ ddocDebug(5, "dencCdataBlockHandler", "SAX.pcdata(%.20s, %d)", (char*)value, len);
+}
+
+
+//--------------------------------------------------
+// dencWarningHandler:
+// @ctxt: An XML parser context
+// @msg: the message to display/transmit
+// @...: extra parameters for the message display
+// Display and format a warning messages, gives file, line, position and
+// extra parameters
+//--------------------------------------------------
+static void dencWarningHandler(void * ctx, const char *msg, ...)
+{
+ va_list args;
+
+ va_start(args, msg);
+ ddocDebug(2, "dencWarningHandler", msg, args);
+ fprintf(stdout, "SAX.warning: ");
+ vfprintf(stdout, msg, args);
+ va_end(args);
+}
+
+//--------------------------------------------------
+// dencErrorHandler:
+// @ctxt: An XML parser context
+// @msg: the message to display/transmit
+// @...: extra parameters for the message display
+// Display and format a error messages, gives file, line, position and
+// extra parameters.
+//--------------------------------------------------
+static void dencErrorHandler(void *ctx, const char *msg, ...)
+{
+ va_list args;
+ DEncParse* pctx = (DEncParse*)ctx;
+
+ va_start(args, msg);
+ pctx->errcode = ERR_DIGIDOC_PARSE;
+ ddocDebugVaArgs(1, "dencErrorHandler", msg, args);
+ addError(pctx->errcode, __FILE__, __LINE__, "XML parsing error");
+ va_end(args);
+}
+
+//--------------------------------------------------
+// dencFatalErrorHandler:
+// @ctxt: An XML parser context
+// @msg: the message to display/transmit
+// @...: extra parameters for the message display
+// Display and format a fatalError messages, gives file, line, position and
+// extra parameters.
+//--------------------------------------------------
+static void dencFatalErrorHandler(void *ctx, const char *msg, ...)
+{
+ va_list args;
+ DEncParse* pctx = (DEncParse*)ctx;
+
+ va_start(args, msg);
+ pctx->errcode = ERR_DIGIDOC_PARSE;
+ ddocDebugVaArgs(1, "dencFatalErrorHandler", msg, args);
+ addError(pctx->errcode, __FILE__, __LINE__, "XML parsing error");
+ va_end(args);
+}
+
+xmlSAXHandler dencSAXHandlerStruct = {
+ NULL, //internalSubsetHandler,
+ NULL, //isStandaloneHandler,
+ NULL, //hasInternalSubsetHandler,
+ NULL, //hasExternalSubsetHandler,
+ NULL, //resolveEntityHandler,
+ NULL, //getEntityHandler,
+ NULL, //entityDeclHandler,
+ NULL, //notationDeclHandler,
+ NULL, //attributeDeclHandler,
+ NULL, //elementDeclHandler,
+ NULL, //unparsedEntityDeclHandler,
+ NULL, //setDocumentLocatorHandler,
+ NULL, //startDocumentHandler,
+ NULL, //endDocumentHandler,
+ dencStartElementHandler,
+ dencEndElementHandler,
+ NULL, //referenceHandler,
+ dencCharactersHandler,
+ NULL, //ignorableWhitespaceHandler,
+ NULL, //processingInstructionHandler,
+ NULL, //commentHandler,
+ dencWarningHandler,
+ dencErrorHandler,
+ dencFatalErrorHandler,
+ NULL, //getParameterEntityHandler,
+ dencCdataBlockHandler,
+ NULL, //externalSubsetHandler,
+ 1
+};
+
+
+xmlSAXHandlerPtr dencSAXHandler = &dencSAXHandlerStruct;
+
+
+
+//--------------------------------------------------
+// Reads in encrypted XML document.
+// ppEncData - address for new encrypted data object [REQUIRED]
+// szFileName - input file name
+// returns error code or ERR_OK
+//--------------------------------------------------
+EXP_OPTION int dencSaxReadEncryptedData(DEncEncryptedData** ppEncData, const char* szFileName)
+{
+ FILE *f;
+ int ret;
+ char chars[1025];
+ xmlParserCtxtPtr ctxt;
+ DEncParse pctx;
+#ifdef WIN32
+ wchar_t *convFileName = 0;
+ int i= 0;
+#endif
+
+ RETURN_IF_NULL_PARAM(szFileName)
+ RETURN_IF_NULL_PARAM(ppEncData)
+ clearErrors();
+ *ppEncData = 0; // mark as not read yet
+ memset(&pctx, 0, sizeof(pctx));
+ //ddocConvertFileName(chars, sizeof(chars), szFileName );
+ ddocDebug(3, "dencSaxReadEncryptedData", "Opening file: %s", szFileName);
+#ifdef WIN32
+ i = 0;
+ ret = utf82unicode((const char*)szFileName, (char**)&convFileName, &i);
+ ddocDebug(3, "dencSaxReadEncryptedData", "file: %s, conv-file: %s len: %d, rc: %d", szFileName, convFileName, i, ret);
+ if((f = _wfopen(convFileName, L"rb")) != NULL) {
+ ddocDebug(3, "dencSaxReadEncryptedData", "Opened w-file: %s", convFileName);
+#else
+ if((f = fopen(szFileName, "rb")) != NULL) {
+ ddocDebug(3, "dencSaxReadEncryptedData", "Opened file: %s", szFileName);
+#endif
+ ret = fread(chars, 1, 1024, f);
+ if (ret > 0) {
+ ddocDebug(3, "dencSaxReadEncryptedData", "Read first %d bytes", ret);
+ ctxt = xmlCreatePushParserCtxt(dencSAXHandler, &pctx,
+ chars, ret, szFileName);
+ while ((ret = fread(chars, 1, 1024, f)) > 0) {
+ ddocDebug(3, "dencSaxReadEncryptedData", "Parsing %d bytes", ret);
+ xmlParseChunk(ctxt, chars, ret, 0);
+ }
+ xmlParseChunk(ctxt, chars, 0, 1);
+ xmlFreeParserCtxt(ctxt);
+ }
+ fclose(f);
+ } else {
+ ddocDebug(1, "dencSaxReadEncryptedData", "Error reading file: %s", szFileName);
+ SET_LAST_ERROR_RETURN_CODE(ERR_FILE_READ);
+ }
+ // cleanup stack
+ ret = pctx.errcode = ddocStackPopElement(&(pctx.dencStack), 1, NULL);
+ ddocDebug(3, "dencSaxReadEncryptedData", "End parsing file: %s - RC: %d", szFileName, ret);
+ if(ret == 0)
+ *ppEncData = pctx.pEncData;
+ // cleanup
+ dencSaxCleanup(&pctx);
+ return ret;
+}
+
+//--------------------------------------------------
+// Reads in encrypted XML document.
+// ppEncData - address for new encrypted data object [REQUIRED]
+// pData - input data [REQUIRED]
+// returns error code or ERR_OK
+//--------------------------------------------------
+EXP_OPTION int dencSaxReadEncryptedDataFromMemory(DEncEncryptedData** ppEncData, DigiDocMemBuf* pData)
+{
+ int ret;
+ DEncParse pctx;
+
+ RETURN_IF_NULL_PARAM(pData)
+ RETURN_IF_NULL_PARAM(ppEncData)
+ clearErrors();
+ *ppEncData = 0; // mark as not read yet
+ memset(&pctx, 0, sizeof(pctx));
+ ddocDebug(3, "dencSaxReadEncryptedData", "Reading from mem %d bytes", pData->nLen);
+ ret = xmlSAXUserParseMemory(dencSAXHandler, &pctx, (const char*)pData->pMem, pData->nLen);
+ // cleanup stack
+ ret = pctx.errcode = ddocStackPopElement(&(pctx.dencStack), 1, NULL);
+ ddocDebug(3, "dencSaxReadEncryptedData", "End parsing mem: %d - RC: %d", pData->nLen, ret);
+ if(ret == 0)
+ *ppEncData = pctx.pEncData;
+ // cleanup
+ dencSaxCleanup(&pctx);
+ return ret;
+}
+
+
+//===============< Large file decryption SAX handlers >==============================
+
+/*
+* Working area for XML parsing with SAX
+*/
+typedef struct DEncDecryptParse_st {
+ int errcode;
+ ElementEntry dencStack; // stack used for keeping the current parsing position
+ FILE* hOutFile;
+ DigiDocMemBuf mbufTransportKey;
+ DigiDocMemBuf mbufTemp;
+ X509* pCert;
+ EVP_PKEY* pkey;
+ char* szPin;
+ int nSlot;
+ long lB64Len, lBinLen, lDecLen;
+ EVP_ENCODE_CTX ectx;
+ EVP_CIPHER_CTX dctx;
+ int nB64SkipMode;
+ char errmsg[100];
+ char szCertSerial[100];
+ int nCipherInited;
+} DEncDecryptParse;
+
+
+//--------------------------------------------------
+// Cleans up data that might have been allocated
+// during the parsing process
+// pctx: An XML parser context
+//--------------------------------------------------
+void dencDecryptSaxCleanup(DEncDecryptParse* pctx)
+{
+ ddocMemBuf_free(&(pctx->mbufTransportKey));
+ ddocMemBuf_free(&(pctx->mbufTemp));
+ if(pctx->pCert)
+ X509_free(pctx->pCert);
+ if(pctx->hOutFile)
+ fclose(pctx->hOutFile);
+ memset(pctx, 0, sizeof(DEncDecryptParse));
+}
+
+//--------------------------------------------------
+// dencDecryptStartElementHandler:
+// @ctxt: An XML parser context
+// @name: The element name
+// called when an opening tag has been processed.
+//--------------------------------------------------
+static void dencDecryptStartElementHandler(void *ctx, const xmlChar *name, const xmlChar **atts)
+{
+ DEncDecryptParse* pctx = (DEncDecryptParse*)ctx;
+ ElementEntry* pCurrElem = 0;
+ char *mime = NULL;
+ int i;
+
+ // check the atributes
+ for(i = 0; atts && atts[i] && atts[i+1]; i++) {
+ if(!strcmp((char*)atts[i], "MimeType")) {
+ mime = (char*)atts[i+1];
+ }
+ }
+ ddocDebug(4, "dencDecryptStartElementHandler", "<%s>, err: %d", (const char*)name, pctx->errcode);
+ if(pctx->errcode) return; // if error skip all additional parsing
+ pctx->errcode = ddocStackPushElementSAX(&(pctx->dencStack), name, atts, &pCurrElem);
+ // initialize decoding and decryption
+ if(pCurrElem && !strcmp((const char*)pCurrElem->tag, "CipherValue") &&
+ !ddocStackHasParentWithName(&(pctx->dencStack), (xmlChar*)"EncryptedKey", NULL)) {
+ if(pctx->nB64SkipMode == 0) {
+ ddocDebug(4, "dencDecryptStartElementHandler", "Decode init");
+ EVP_DecodeInit(&(pctx->ectx));
+ EVP_CIPHER_CTX_init(&(pctx->dctx));
+ pctx->lB64Len = pctx->lBinLen = pctx->lDecLen = 0;
+ }
+ pctx->nB64SkipMode++; // increment skip mode
+ ddocDebug(4, "dencDecryptStartElementHandler", "Decode start, skip: %d", pctx->nB64SkipMode);
+ }
+ // check mime
+ if(strstr((char*)name, "EncryptedData")) {
+
+ }
+ // <X509Certificate>
+ if(strstr((char*)name, "X509Certificate")) {
+ ddocDebug(4, "dencDecryptStartElementHandler", "Start collecting cert");
+ ddocMemBuf_free(&(pctx->mbufTemp));
+ }
+}
+
+//--------------------------------------------------
+// dencDecryptEndElementHandler:
+// @ctxt: An XML parser context
+// @name: The element name
+// called when the end of an element has been detected.
+//--------------------------------------------------
+static void dencDecryptEndElementHandler(void *ctx, const xmlChar *name)
+{
+ DEncDecryptParse* pctx = (DEncDecryptParse*)ctx;
+ char buf1[4096], buf2[4096];
+ int l1, l2, l3;
+ DigiDocMemBuf mbuf1;
+
+ mbuf1.pMem = NULL;
+ mbuf1.nLen = 0;
+ ddocDebug(4, "dencDecryptEndElementHandler", "</%s>, err: %d", (const char*)name, pctx->errcode);
+ if(pctx->errcode) return; // if error skip all additional parsing
+ // decode the certificate data
+ if(strstr((char*)name, "X509Certificate")) {
+ pctx->errcode = ddocDecodeX509PEMData(&(pctx->pCert), (const char*)pctx->mbufTemp.pMem, (int)pctx->mbufTemp.nLen);
+ ddocDebug(4, "dencDecryptEndElementHandler", "Decoding pem: %d cert: %s, rc: %d",
+ pctx->mbufTemp.nLen, (pctx->pCert ? "OK" : "NULL"), pctx->errcode);
+ ddocMemBuf_free(&(pctx->mbufTemp));
+ //EVP_DecodeFinal(&(pctx->ectx),out,outl)
+ pctx->nB64SkipMode = 0;
+ }
+ // check if it was the right key and decrypt transport key
+ if(strstr((char*)name, "EncryptedKey")) {
+ memset(buf1, 0, sizeof(buf1));
+ pctx->errcode = ReadCertSerialNumber(buf1, sizeof(buf1), pctx->pCert);
+ ddocCertGetDN(pctx->pCert, &mbuf1, 0);
+ ddocDebug(4, "dencDecryptEndElementHandler", "Looking for cert: %s, found: %s - %s, rc: %d",
+ pctx->szCertSerial, buf1, (char*)mbuf1.pMem, pctx->errcode);
+ ddocMemBuf_free(&mbuf1);
+ if(!strcmp(pctx->szCertSerial, buf1)) {
+ l1 = sizeof(buf1);
+ memset(buf1, 0, l1);
+ decode((const byte*)pctx->mbufTemp.pMem, pctx->mbufTemp.nLen, (byte*)buf1, &l1);
+ ddocDebug(4, "dencDecryptEndElementHandler", "Decoded key-len: %d got: %d",
+ pctx->mbufTemp.nLen, l1);
+ // cleanup temp buffer
+ ddocMemBuf_free(&(pctx->mbufTemp));
+ if(l1 < DENC_ENCRYPTED_KEY_LEN) {
+ SET_LAST_ERROR(ERR_DENC_DECRYPT);
+ pctx->errcode = ERR_DENC_DECRYPT;
+ return;
+ }
+ // decrypt the transport key
+ pctx->mbufTransportKey.nLen = l1;
+ pctx->mbufTransportKey.pMem = (char*)malloc(l1);
+ if(!pctx->mbufTransportKey.pMem) {
+ SET_LAST_ERROR(ERR_BAD_ALLOC);
+ pctx->errcode = ERR_BAD_ALLOC;
+ return;
+ }
+ memset(pctx->mbufTransportKey.pMem, 0, l1);
+ l3 = pctx->mbufTransportKey.nLen;
+ if(pctx->pkey) {
+#if OPENSSL_VERSION_NUMBER > 0x10000000
+ l3 = EVP_PKEY_decrypt_old((unsigned char *)pctx->mbufTransportKey.pMem,
+ (const unsigned char*)buf1, l1, pctx->pkey);
+#else
+ l3 = EVP_PKEY_decrypt((unsigned char *)pctx->mbufTransportKey.pMem,
+ (const unsigned char*)buf1, l1, pctx->pkey);
+#endif
+ pctx->mbufTransportKey.nLen = l3;
+ if(l3 != 16)
+ pctx->errcode = ERR_DENC_DECRYPT;
+ } else {
+ pctx->errcode = decryptWithEstID(pctx->nSlot, pctx->szPin, (char *)buf1, l1,
+ (char*)pctx->mbufTransportKey.pMem, &l3);
+ pctx->mbufTransportKey.nLen = l3;
+ }
+ ddocDebug(4, "dencDecryptEndElementHandler", "Decrypted key-len: %d rc: %d",
+ pctx->mbufTransportKey.nLen, pctx->errcode);
+ if(pctx->mbufTransportKey.nLen != DENC_DECRYPTED_KEY_LEN) {
+ SET_LAST_ERROR(ERR_DENC_DECRYPT);
+ pctx->errcode = ERR_DENC_DECRYPT;
+ return;
+ }
+ }
+ }
+ // last block of encrypted data
+ if(strstr((char*)name, "CipherValue") &&
+ !ddocStackHasParentWithName(&(pctx->dencStack), (xmlChar*)"EncryptedKey", NULL)) {
+ ddocDebug(4, "dencDecryptEndElementHandler", "Decode end, skip: %d", pctx->nB64SkipMode);
+ if(pctx->nB64SkipMode > 0)
+ pctx->nB64SkipMode--;
+ if(pctx->nB64SkipMode == 0) {
+ l1 = sizeof(buf1);
+ memset(buf1, 0, l1);
+ ddocDebug(4, "dencDecryptEndElementHandler", "Decoding: final into: %d", l1);
+ EVP_DecodeFinal(&(pctx->ectx), (unsigned char*)buf1, &l1);
+ pctx->lBinLen += l1;
+ ddocDebug(4, "dencDecryptEndElementHandler", "Decoded: final got: %d, total %d -> %d", l1, pctx->lB64Len, pctx->lBinLen);
+ // decrypt decoded data
+ l2 = sizeof(buf2);
+ memset(buf2, 0, l2);
+ ddocDebug(3, "dencDecryptEndElementHandler", "Decrypting: final into: %d", l2);
+ EVP_CipherFinal_ex(&(pctx->dctx), (unsigned char*)buf2, &l2);
+ ddocDebug(4, "dencDecryptEndElementHandler", "Decrypted: final got: %d", l2);
+ // write to file
+ if(pctx->hOutFile) {
+ if(l2)
+ pctx->lDecLen += fwrite(buf2, 1, l2, pctx->hOutFile);
+ fclose(pctx->hOutFile);
+ pctx->hOutFile = 0;
+ }
+ ddocDebug(3, "dencDecryptEndElementHandler", "Total base64: %d decoded: %d decrypted: %d RC: %d",
+ pctx->lB64Len, pctx->lBinLen, pctx->lDecLen, pctx->errcode);
+ pctx->nB64SkipMode = 0;
+ }
+ }
+ // pop stack
+ pctx->errcode = ddocStackPopElement(&(pctx->dencStack), 0, NULL);
+}
+
+//--------------------------------------------------
+// dencDecryptCharactersHandler:
+// @ctxt: An XML parser context
+// @ch: a xmlChar string
+// @len: the number of xmlChar
+// receiving some chars from the parser.
+//--------------------------------------------------
+static void dencDecryptCharactersHandler(void *ctx, const xmlChar *ch, int len)
+{
+ DEncDecryptParse* pctx = (DEncDecryptParse*)ctx;
+ ElementEntry* pCurrElem = 0;
+ char *buf1=0, *buf2=0, *p1=0;
+ int l1, l2, i, l;
+
+ ddocDebug(4, "dencDecryptCharactersHandler", "Parsing: %d chars err: %d, skip: %d", len, pctx->errcode, pctx->nB64SkipMode);
+ if(pctx->errcode) return; // if error skip all additional parsing
+ // find last element
+ pCurrElem = ddocStackFindEnd(&(pctx->dencStack));
+ // if this is data belonging to <CipherValue> tag and
+ // the latter is not a child of <EncryptedKey>, thus
+ // it must be the main content, then decrypt it
+ if(pCurrElem && !strcmp((const char*)pCurrElem->tag, "X509Certificate")) {
+ // collect the certificate data
+ pctx->errcode = ddocMemAppendData(&(pctx->mbufTemp), (char*)ch, len);
+ }
+ if(pCurrElem || pctx->nB64SkipMode > 0) {
+ // handle encrypted data
+ if((pCurrElem && !strcmp((const char*)pCurrElem->tag, "CipherValue")) || pctx->nB64SkipMode > 0) {
+ // collect encrypted transport key data
+ if(pCurrElem &&
+ ddocStackHasParentWithName(&(pctx->dencStack), (xmlChar*)"EncryptedKey", NULL)) {
+ pctx->errcode = ddocMemAppendData(&(pctx->mbufTemp), (char*)ch, len);
+ }
+ // if this is the real encrypted content not a key then decrypt it
+ else {
+ // check if the transport key is ready for decryption
+ if(pctx->mbufTransportKey.nLen != DENC_DECRYPTED_KEY_LEN) {
+ ddocDebug(1, "dencDecryptCharactersHandler", "Transport key len: %d", pctx->mbufTransportKey.nLen);
+ SET_LAST_ERROR(ERR_DENC_NO_KEY_FOUND); // not encrypted for this user!
+ pctx->errcode = ERR_DENC_NO_KEY_FOUND;
+ return;
+ }
+ // decode base64 encrypted data
+ pctx->lB64Len += len;
+ l1 = len * 2;
+ buf1 = (char*)malloc(l1);
+ if(!buf1) {
+ SET_LAST_ERROR(ERR_BAD_ALLOC);
+ return;
+ }
+ memset(buf1, 0, l1);
+ ddocDebug(4, "dencDecryptCharactersHandler", "Decoding: %d into: %d, skip: %d", len, l1, pctx->nB64SkipMode);
+ EVP_DecodeUpdate(&(pctx->ectx), (unsigned char*)buf1, &l1, (unsigned char*)ch, len);
+ ddocDebug(4, "dencDecryptCharactersHandler", "Decoded: %d got: %d, skip: %d", len, l1, pctx->nB64SkipMode);
+ // if this was the first block of decoded base64 data
+ // then use the first 16 bytes as the IV value
+ p1 = buf1;
+ if(pctx->lBinLen == 0) {
+ ddocDebug(4, "dencDecryptCharactersHandler", "Using 16 bytes for IV. Initing cipher");
+ p1 += 16; // don't decrypt the IV data
+ l1 -= 16;
+ EVP_CipherInit_ex(&(pctx->dctx), EVP_aes_128_cbc(), NULL,
+ (const unsigned char*)pctx->mbufTransportKey.pMem, (const unsigned char*)buf1, DECRYPT);
+ }
+ pctx->lBinLen += l1;
+ ddocDebug(4, "dencDecryptCharactersHandler", "Decoded: %d got: %d, skip: %d", len, l1, pctx->nB64SkipMode);
+ // decrypt decoded data
+ l = l2 = l1 * 2;
+ buf2 = (char*)malloc(l2);
+ if(!buf2) {
+ SET_LAST_ERROR(ERR_BAD_ALLOC);
+ return;
+ }
+ memset(buf2, 0, l2);
+ //if(pctx->nB64SkipMode == 4)
+ // l1 += 16; // ???
+ ddocDebug(4, "dencDecryptCharactersHandler", "Decrypting: %d into: %d", l1, l2);
+ EVP_CipherUpdate(&(pctx->dctx), (unsigned char*)buf2, &l, (const unsigned char*)p1, l1);
+ ddocDebug(4, "dencDecryptCharactersHandler", "Decrypted: %d got: %d, skip: %d", l1, l, pctx->nB64SkipMode);
+ if(buf1)
+ free(buf1);
+
+ // no padding until the final chunk
+ if((pctx->nB64SkipMode == 0 || pctx->nB64SkipMode == 4)) {
+ // on the last block check for a block with all 0x0F
+ l1 = (int)(unsigned char)buf2[l-1];
+ if(l1 == 16) {
+ ddocDebug(4, "dencDecryptCharactersHandler", "Check 0x0F padding 1: %d", l1);
+ for(i = l - l1; i < l - 1; i++) {
+ ddocDebug(4, "dencDecryptCharactersHandler", "Pad pos: %d = %d", i, buf2[i]);
+ if(buf2[i] != 16) {
+ l1 = 0; // set not matched flag
+ break;
+ }
+ }
+ if(l1) {
+ ddocDebug(4, "dencDecryptCharactersHandler", "Decrypted len: %d reduce by: %d -> %d", l2, l1, (l-l1));
+ l -= l1;
+ }
+ }
+ // remove padding
+ l1 = (int)(unsigned char)buf2[l-1];
+ if(l1 > 0 && l1 <= 16) {
+ ddocDebug(4, "dencDecryptCharactersHandler", "Check padding: %d", l1);
+ for(i = l - l1; i < l - 1; i++) {
+ ddocDebug(4, "dencDecryptCharactersHandler", "Pad pos: %d = %d", i, buf2[i]);
+ if(buf2[i]) {
+ l1 = 0; // set not matched flag
+ break;
+ }
+ }
+ if(l1) {
+ ddocDebug(4, "dencDecryptCharactersHandler", "Decrypted len: %d reduce by: %d -> %d", l2, l1, (l-l1));
+ l -= l1;
+ }
+ }
+ else
+ ddocDebug(4, "dencDecryptCharactersHandler", "Impossible padding: %d", l1);
+ if(pctx->nB64SkipMode == 4)
+ pctx->nB64SkipMode = 1; // reset flag - look for padding
+ }
+ // write to file
+ if(pctx->hOutFile && buf2)
+ pctx->lDecLen += fwrite(buf2, 1, l, pctx->hOutFile);
+ free(buf2);
+ }
+
+ }
+
+ }
+
+ ddocDebug(5, "dencDecryptCharactersHandler", "End");
+}
+
+
+xmlSAXHandler dencDecryptSAXHandlerStruct = {
+ NULL, //internalSubsetHandler,
+ NULL, //isStandaloneHandler,
+ NULL, //hasInternalSubsetHandler,
+ NULL, //hasExternalSubsetHandler,
+ NULL, //resolveEntityHandler,
+ NULL, //getEntityHandler,
+ NULL, //entityDeclHandler,
+ NULL, //notationDeclHandler,
+ NULL, //attributeDeclHandler,
+ NULL, //elementDeclHandler,
+ NULL, //unparsedEntityDeclHandler,
+ NULL, //setDocumentLocatorHandler,
+ NULL, //startDocumentHandler,
+ NULL, //endDocumentHandler,
+ dencDecryptStartElementHandler,
+ dencDecryptEndElementHandler,
+ NULL, //referenceHandler,
+ dencDecryptCharactersHandler,
+ NULL, //ignorableWhitespaceHandler,
+ NULL, //processingInstructionHandler,
+ NULL, //commentHandler,
+ dencWarningHandler,
+ dencErrorHandler,
+ dencFatalErrorHandler,
+ NULL, //getParameterEntityHandler,
+ dencCdataBlockHandler,
+ NULL, //externalSubsetHandler,
+ 1
+};
+
+
+xmlSAXHandlerPtr dencDecryptSAXHandler = &dencDecryptSAXHandlerStruct;
+
+// string used to force parser to flush it's buffers
+static char g_szCipherValueFlush1[] = "</denc:CipherValue>";
+static char g_szCipherValueFlush2[] = "<denc:CipherValue>";
+
+//--------------------------------------------------
+// Decrypts an encrypted XML document and stores the
+// cleartext data in another document.
+// szInputFileName - input file name [REQUIRED]
+// szOutputFileName - output file name [REQUIRED]
+// szPin - PIN1 of the id-card to decrypt the transport key [REQUIRED]
+// szPkcs12File - pkcs12 key container filename [OPTIONAL]
+// returns error code or ERR_OK
+//--------------------------------------------------
+EXP_OPTION int dencSaxReadDecryptFile(const char* szInputFileName,
+ const char* szOutputFileName,
+ const char* szPin, const char* szPkcs12File)
+{
+ FILE *f;
+ int ret;
+ char chars[1025], convInFileName[256], convOutFileName[256], *p;
+ xmlParserCtxtPtr ctxt;
+ DEncDecryptParse pctx;
+ X509* pCert = 0;
+ EVP_PKEY *pkey = NULL;
+ DigiDocMemBuf mbuf1;
+
+ mbuf1.pMem = NULL;
+ mbuf1.nLen = 0;
+ RETURN_IF_NULL_PARAM(szInputFileName)
+ RETURN_IF_NULL_PARAM(szOutputFileName)
+ RETURN_IF_NULL_PARAM(szPin)
+ clearErrors();
+ ddocDebug(3, "dencSaxReadDecryptFile", "input-file: %s, output-file: %s",
+ szInputFileName, szOutputFileName);
+ memset(&pctx, 0, sizeof(pctx));
+
+ ddocConvertFileName(convInFileName, sizeof(convInFileName), szInputFileName);
+ ddocConvertFileName(convOutFileName, sizeof(convOutFileName), szOutputFileName);
+
+ //store decryption params
+ pctx.nSlot = ConfigItem_lookup_int("DIGIDOC_AUTH_KEY_SLOT", 0);
+ pctx.szPin = (char*)szPin;
+ pctx.hOutFile = fopen(convOutFileName, "wb");
+ pctx.nB64SkipMode = 0;
+ if(!pctx.hOutFile) {
+ ddocDebug(1, "dencSaxReadDecryptFile", "Error writing to file: %s", szOutputFileName);
+ SET_LAST_ERROR_RETURN(ERR_FILE_WRITE, ERR_FILE_WRITE)
+ }
+ // if using pkcs12 file for decryption
+ if(szPkcs12File) {
+ pctx.errcode = ReadCertificateByPKCS12(&pCert, szPkcs12File, szPin, &pkey);
+ pctx.pkey = pkey;
+ } else {
+ pctx.errcode = findUsersCertificate(pctx.nSlot, &pCert);
+ }
+ if(pCert) {
+ pctx.errcode = ReadCertSerialNumber(pctx.szCertSerial, sizeof(pctx.szCertSerial), pCert);
+ ddocCertGetDN(pCert, &mbuf1, 0);
+ ddocDebug(3, "dencSaxReadDecryptFile", "Decrypting using certificate: %s - %s", pctx.szCertSerial, (char*)mbuf1.pMem);
+ ddocMemBuf_free(&mbuf1);
+ } else {
+ ddocDebug(1, "dencSaxReadDecryptFile", "Users cert for decryption could not be read from card!");
+ return pctx.errcode;
+ }
+
+ // parse and decrypt data in file
+ if((f = fopen(convInFileName, "r")) != NULL && !pctx.errcode) {
+ ret = fread(chars, 1, 1024, f);
+ if (ret > 0) {
+ ctxt = xmlCreatePushParserCtxt(dencDecryptSAXHandler, &pctx,
+ chars, ret, convInFileName);
+ do {
+ memset(chars, 0, sizeof(chars));
+ ret = fread(chars, 1, 1024, f);
+ if(ret == 0)
+ ret = strlen(chars);
+ ddocDebug(4, "dencSaxReadDecryptFile", "In: %d Parsed: %d, skip: %d", ret, ctxt->nbChars, pctx.nB64SkipMode);
+ // this horrible chemistry is done to prevent
+ // libxml2 to start colecting huge memory structures
+ // Since we cannot disable it we'll just bypass parser
+ // with a large amount of base64 data
+ if(pctx.nB64SkipMode > 0) {
+ p = strchr(chars, '<');
+ // if <CipherValue> was found and no "<" (beginn of new element)
+ // is found then send the "flush command" and enter bypass mode
+ if(pctx.nB64SkipMode == 1 && !p) {
+ pctx.nB64SkipMode += 2;
+ ddocDebug(4, "dencSaxReadDecryptFile", "Starting bypass mode, skip: %d", pctx.nB64SkipMode);
+ // force the parser to release element content
+ // before entering into bypass mode
+ xmlParseChunk(ctxt, g_szCipherValueFlush1, strlen(g_szCipherValueFlush1), 0);
+ ddocDebug(4, "dencSaxReadDecryptFile", "Entering bypass mode, skip: %d", pctx.nB64SkipMode);
+ }
+ if(pctx.nB64SkipMode >= 2 && !p) {
+ ddocDebug(4, "dencSaxReadDecryptFile", "Parsing in bypass mode, skip: %d", pctx.nB64SkipMode);
+ dencDecryptCharactersHandler(&pctx, (const xmlChar *)chars, ret);
+ }
+ // if we reached the first block that contains a start of xml element
+ // then stop bypass mode
+ if(strchr(chars, '<')) {
+ pctx.nB64SkipMode = 2;
+ xmlParseChunk(ctxt, g_szCipherValueFlush2, strlen(g_szCipherValueFlush2), 0);
+ ddocDebug(4, "dencSaxReadDecryptFile", "Ending bypass mode len: %d, skip: %d", ret, pctx.nB64SkipMode);
+ }
+ } // if bypass mode
+ // if in normal mode or finished bypass mode
+ if(pctx.nB64SkipMode == 0 || pctx.nB64SkipMode == 3) {
+ if(pctx.nB64SkipMode == 3)
+ pctx.nB64SkipMode = 4; // used as flag: last block - look for padding
+ ddocDebug(4, "dencSaxReadDecryptFile", "parsing normal chunk");
+ xmlParseChunk(ctxt, chars, ret, 0);
+ }
+ //memset(chars, 0, sizeof(chars));
+ } while(ret == 1024); // do-while
+ // last block of data
+ ddocDebug(4, "dencSaxReadDecryptFile", "parsing final chunk: %d", strlen(chars));
+ if(!pctx.errcode)
+ xmlParseChunk(ctxt, NULL, 0, 1);
+ xmlFreeParserCtxt(ctxt);
+ } // if(ret > 0)
+ fclose(f);
+ } else {
+ ddocDebug(1, "dencSaxReadDecryptFile", "Error reading file: %s", szInputFileName);
+ SET_LAST_ERROR_RETURN_CODE(ERR_FILE_READ);
+ }
+ // cleanup stack
+ ret = pctx.errcode = ddocStackPopElement(&(pctx.dencStack), 1, NULL);
+ // cleanup
+ dencDecryptSaxCleanup(&pctx);
+ ddocDebug(1, "dencSaxReadDecryptFile",
+ "End parsing file: %s - RC: %d", szInputFileName, ret);
+ return ret;
+}
+
diff --git a/libdigidoc/DigiDocEncSAXParser.h b/libdigidoc/DigiDocEncSAXParser.h
new file mode 100644
index 0000000..5795fd3
--- /dev/null
+++ b/libdigidoc/DigiDocEncSAXParser.h
@@ -0,0 +1,70 @@
+#ifndef __DIGIDOC_ENC_SAX_PARSER_H__
+#define __DIGIDOC_ENC_SAX_PARSER_H__
+//==================================================
+// FILE: DigiDocEncSAXParser.h
+// PROJECT: Digi Doc Encryption
+// DESCRIPTION: DigiDocEnc XML SAX parsing
+// AUTHOR: Veiko Sinivee, S|E|B IT Partner Estonia
+//==================================================
+// Copyright (C) AS Sertifitseerimiskeskus
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+// GNU Lesser General Public Licence is available at
+// http://www.gnu.org/copyleft/lesser.html
+//==========< HISTORY >=============================
+// 11.10.2004 Veiko Sinivee
+// Creation
+//==================================================
+
+
+#include <libdigidoc/DigiDocEnc.h>
+#include <libdigidoc/DigiDocDefs.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+ //--------------------------------------------------
+ // Reads in encrypted XML document.
+ // ppEncData - address for new encrypted data object [REQUIRED]
+ // szFileName - input file name
+ // returns error code or ERR_OK
+ //--------------------------------------------------
+ EXP_OPTION int dencSaxReadEncryptedData(DEncEncryptedData** ppEncData, const char* szFileName);
+
+ //--------------------------------------------------
+ // Reads in encrypted XML document.
+ // ppEncData - address for new encrypted data object [REQUIRED]
+ // pData - input data [REQUIRED]
+ // returns error code or ERR_OK
+ //--------------------------------------------------
+ EXP_OPTION int dencSaxReadEncryptedDataFromMemory(DEncEncryptedData** ppEncData, DigiDocMemBuf* pData);
+
+ //--------------------------------------------------
+ // Decrypts an encrypted XML document and stores the
+ // cleartext data in another document. Please note that szCertCN
+ // parameter is no longer required as the users cert will
+ // bea read from smartcard using PKCS#11
+ // szInputFileName - input file name [REQUIRED]
+ // szOutputFileName - output file name [REQUIRED]
+ // szPin - PIN1 of the id-card to decrypt the transport key [REQUIRED]
+ // szPkcs12File - pkcs12 key container filename [OPTIONAL]
+ // returns error code or ERR_OK
+ //--------------------------------------------------
+ EXP_OPTION int dencSaxReadDecryptFile(const char* szInputFileName,
+ const char* szOutputFileName,
+ const char* szPin, const char* szPkcs12File);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif // __DIGIDOC_ENC_SAX_PARSER_H__
diff --git a/libdigidoc/DigiDocError.c b/libdigidoc/DigiDocError.c
new file mode 100644
index 0000000..9f9f2f3
--- /dev/null
+++ b/libdigidoc/DigiDocError.c
@@ -0,0 +1,604 @@
+#ifdef WIN32
+ #include <windows.h>
+#else
+ #ifdef USEPTHREADS
+ #include <pthread.h>
+ #endif
+ #include <sys/types.h>
+ #include <unistd.h>
+#endif
+#include <string.h>
+#include <libdigidoc/DigiDocLib.h>
+#include <libdigidoc/DigiDocDebug.h>
+
+#define ERR_MAX 179 //number of error codes. Increment, if you add a new error code
+
+ErrorMessage g_ddocErrorStrings[ERR_MAX] = {
+/* ERR_OK */ {"No errors", NO_ERRORS},
+/* ERR_UNSUPPORTED_DIGEST */ {"Digest type is not supported", LIBRARY},
+/* ERR_FILE_READ */ {"Could not open file for reading", USER},
+/* ERR_FILE_WRITE */ {"Could not open file for writing", USER},
+/* ERR_DIGEST_LEN */ {"Wrong digest length", LIBRARY},
+/* ERR_BUF_LEN */ {"Insufficient target buffer length", LIBRARY},
+/* ERR_SIGNATURE_LEN */ {"Wrong signature length", LIBRARY},
+/* ERR_PRIVKEY_READ */ {"Failed to read the private key", TECHNICAL},
+/* ERR_PUBKEY_READ */ {"Failed to read the public key", TECHNICAL},
+/* ERR_CERT_READ */ {"Failed to read certificate", USER},
+/* ERR_SIGNEDINFO_CREATE */ {"Could not create SignedInfo object", LIBRARY},
+/* ERR_SIGNEDINFO_DATA */ {"Could not create SignedInfo object", LIBRARY},
+/* ERR_SIGNEDINFO_FINAL */ {"Could not create SignedInfo object", LIBRARY},
+/* ERR_UNSUPPORTED_FORMAT */ {"Wrong signed document format", TECHNICAL},
+/* ERR_BAD_INDEX */ {"Bad index", LIBRARY},
+/* ERR_TIMESTAMP_DECODE */ {"Failed to decode timestamp", TECHNICAL},
+/* ERR_DIGIDOC_PARSE */ {"Error in document parsing", USER},
+/* ERR_UNSUPPORTED_SIGNATURE */ {"Signature type is not supported", LIBRARY},
+/* ERR_CERT_STORE_READ */ {"Could not read read certificate from certificate store", TECHNICAL},
+/* ERR_SIGPROP_DIGEST */ {"Wrong signature properties digest", TECHNICAL},
+/* ERR_COMPARE */ {"Wrong signature", USER},
+/* ERR_DOC_DIGEST */ {"Wrong document digest", USER},
+/* ERR_MIME_DIGEST */ {"Wrong document mime digest", TECHNICAL},
+/* ERR_SIGNATURE */ {"Wrong signature", TECHNICAL},
+/* ERR_CERT_INVALID */ {"Invalid certificate", TECHNICAL},
+/* ERR_OCSP_UNSUCCESSFUL */ {"OCSP request unsuccessful", TECHNICAL},
+/* ERR_OCSP_UNKNOWN_TYPE */ {"Unknown OCSP type", TECHNICAL},
+/* ERR_OCSP_NO_BASIC_RESP */ {"No OCSP basic responce", TECHNICAL},
+/* ERR_OCSP_WRONG_VERSION */ {"Wrong OCSP version", TECHNICAL},
+/* ERR_OCSP_WRONG_RESPID */ {"Wrong OCSP response id", TECHNICAL},
+/* ERR_OCSP_ONE_RESPONSE */ {"Incorrect OCSP response count", TECHNICAL},
+/* ERR_OCSP_RESP_STATUS */ {"Incorrect OCSP response status", USER},
+/* ERR_OCSP_NO_SINGLE_EXT */ {"No single OCSP responce", TECHNICAL},
+/* ERR_OCSP_NO_NONCE */ {"NONCE is missing", LIBRARY},
+/* ERR_NOTARY_NO_SIGNATURE */ {"Missing signature for Notary", TECHNICAL},
+/* ERR_NOTARY_SIG_MATCH */ {"Notary signature mismatch", USER},
+/* ERR_SIGNERS_CERT_NOT_TRUSTED */ {"Signers cert not trusted, missing CA cert!", USER},
+/* ERR_WRONG_CERT */ {"Wrong certificate", USER},
+/* ERR_NULL_POINTER */ {"Null pointer exception", LIBRARY},
+/* ERR_NULL_CERT_POINTER */ {"Certificate pointer is null", LIBRARY},
+/* ERR_NULL_SER_NUM_POINTER */ {"Certificate Number pointer is null", LIBRARY},
+/* ERR_NULL_KEY_POINTER */ {"Key pointer is null", LIBRARY},
+/* ERR_EMPTY_STRING */ {"Empty string", LIBRARY},
+/* ERR_BAD_DATAFILE_INDEX */ {"Datafile index out of range", LIBRARY},
+/* ERR_BAD_DATAFILE_COUNT */ {"Datafile count is out of sync", LIBRARY},
+/* ERR_BAD_ATTR_COUNT */ {"Attribute counter is out of sync", LIBRARY},
+/* ERR_BAD_ATTR_INDEX */ {"Attribute index is out of range", LIBRARY},
+/* ERR_BAD_SIG_INDEX */ {"Signature index is out of range", LIBRARY},
+/* ERR_BAD_SIG_COUNT */ {"Signature count is out of sync", LIBRARY},
+/* ERR_BAD_ROLE_INDEX */ {"Role index is out of range", LIBRARY},
+/* ERR_BAD_DOCINFO_COUNT */ {"Document info count is out of sync", LIBRARY},
+/* ERR_BAD_DOCINFO_INDEX */ {"Document info index is out of range", LIBRARY},
+/* ERR_BAD_NOTARY_INDEX */ {"Notary index is out of range", LIBRARY},
+/* ERR_BAD_NOTARY_ID */ {"Bad notary ID", LIBRARY},
+/* ERR_BAD_NOTARY_COUNT */ {"Notary count is out of sync", LIBRARY},
+/* ERR_X509_DIGEST */ {"X509 digest creation failed", LIBRARY},
+/* ERR_CERT_LENGTH */ {"Wrong certificate length", LIBRARY},
+/* ERR_PKCS_LIB_LOAD */ {"PKCS #11 DLL load failed", TECHNICAL},
+/* ERR_PKCS_SLOT_LIST */ {"Getting PKCS #11 slot list failed", TECHNICAL},
+/* ERR_PKCS_WRONG_SLOT */ {"No such PKCS #11 slot", TECHNICAL},
+/* ERR_PKCS_LOGIN */ {"No EstID card, wrong PIN or PIN blocked", USER},
+/* ERR_PKCS_PK */ {"Locating private key from EstID failed", TECHNICAL},
+/* ERR_PKCS_CERT_LOC */ {"Reading certificate from EstID failed", TECHNICAL},
+/* ERR_PKCS_CERT_DECODE */ {"Decoding certificate failed", LIBRARY},
+/* ERR_PKCS_SIGN_DATA */ {"Signing data with EstID failed", USER},
+/* ERR_PKCS_CARD_READ */ {"Reading EstID card failed", USER},
+/* ERR_CSP_NO_CARD_DATA */ {"No EstID card, or card can not be read", USER},
+/* ERR_CSP_OPEN_STORE */ {"Can not open system store", TECHNICAL},
+/* ERR_CSP_CERT_FOUND*/ {"Certificate not found from store, probably cetificate not registered", USER},
+/* ERR_CSP_SIGN */ {"CSP signing failed", USER},
+/* ERR_CSP_NO_HASH_START */ {"Can not start CSP hashing", TECHNICAL},
+/* ERR_CSP_NO_HASH */ {"CSP hash failed", LIBRARY},
+/* ERR_CSP_NO_HASH_RESULT */ {"Can not read CSP's hashing result", LIBRARY},
+/* ERR_CSP_OPEN_KEY */ {"Can not open key", TECHNICAL},
+/* ERR_CSP_READ_KEY */ {"Can not read key", TECHNICAL},
+/* ERR_OCSP_SIGN_NOT_SUPPORTED */ {"Requuested OCSP sign method not suported", LIBRARY},
+/* ERR_OCSP_SIGN_CSP_NAME */ {"Can not add Signer's name to requst", LIBRARY},
+/* ERR_CSP_CERT_DECODE */ {"Decoding certificate failed", TECHNICAL},
+/* ERR_OCSP_SIGN_PKCS_NAME */ {"Can not add Signer's name to requst", TECHNICAL},
+/* ERR_OCSP_SIGN_OSLL_CERT */ {"Cannot add cert to OCSP request", TECHNICAL},
+/* ERR_OCSP_SIGN */ {"Can not sign OCSP request", USER},
+/* ERR_CERT_ISSUER */ {"Cert not issued by this CA, or wrong cert signature", USER},
+/* ERR_OCSP_PKCS12_CONTAINER */ {"Can not open pkcs12 container", USER},
+/* ERR_MODIFY_SIGNED_DOC */ {"Cannot modify signed doc. Remove signatures first.", USER},
+/* ERR_NOTARY_EXISTS */ {"Cannot remove signature if notary exists", USER},
+/* ERR_UNSUPPORTED_CERT_SEARCH */ {"Unsuported CERT_SEARCH method", LIBRARY},
+/* ERR_INCORRECT_CERT_SEARCH */ {"Incorrct CERT_SEARCH pattern", LIBRARY},
+/* ERR_BAD_OCSP_RESPONSE_DIGEST */{"Incorrect Notary signature digest", USER},
+/* ERR_LAST_ESTID_CACHED */ {"Wrong certificate in cache. Please try again.", USER},
+/* ERR_BAD_DATAFILE_XML */ {"XML content cannot contain the first XML line", USER},
+/* ERR_UNSUPPORTED_VERSION */ {"Unsupported SK-XML version. Please upgrade!", TECHNICAL},
+/* ERR_UNSUPPORTED_CHARSET */ {"Unsupported charset", TECHNICAL},
+/* ERR_PKCS12_EXPIRED */ {"PKCS#12 certificate has expired. Please get a new onew from www.sk.ee", USER},
+/* ERR_CSP_USER_CANCEL */ {"User canceled certificate selection", USER},
+/* ERR_CSP_NODEFKEY_CONTAINER */ {"Can't find default key container", TECHNICAL},
+/* ERR_CONNECTION_FAILURE */ {"Connection error", USER},
+/* ERR_WRONG_URL_OR_PROXY */ {"Wrong URL or Proxy", USER},
+/* ERR_NULL_PARAM */ {"Mandatory parameter is NULL", LIBRARY},
+/* ERR_BAD_ALLOC */ {"Memory allocation error", LIBRARY},
+/* ERR_CONF_FILE */ {"Error opening configuration file", USER},
+/* ERR_CONF_LINE */ {"Error in configuration file", USER},
+/* ERR_OCSP_CERT_REVOKED */ { "Certificate has been revoked!", USER},
+/* ERR_OCSP_CERT_UNKNOWN */ { "Certificate status unknow! Not supported by this CA?", USER},
+/* ERR_OCSP_PKCS12_NO_FILE */ { "PKCS#12 token file not defined!", USER},
+/* ERR_OCSP_PKCS12_NO_PASSWD */ { "PKCS#12 token file password not defined!", USER},
+/* ERR_BAD_DATAFILE_CONTENT_TYPE */ { "Invalid DataFile content type!", TECHNICAL},
+/* ERR_OCSP_WRONG_URL */ { "Wrong OCSP responder URL!", USER},
+/* ERR_OCSP_MALFORMED */ { "Malformed OCSP request!", TECHNICAL},
+/* ERR_OCSP_INTERNALERR */ { "Internal error in OCSP responder!", USER},
+/* ERR_OCSP_TRYLATER */ { "Try later! OCSP responder is busy", USER},
+/* ERR_OCSP_SIGREQUIRED */ { "Must sign OCSP requests!", USER},
+/* ERR_OCSP_UNAUTHORIZED */ { "Unauthorized OCSP request!", USER},
+/* ERR_UNKNOWN_CA */ { "Unknown Certificate issuer!", USER},
+
+/* ERR_DENC_ENC_METHOD */ { "Invalid encryption method!", TECHNICAL},
+/* ERR_DENC_ENC_XMLNS */ { "Invalid xml namespace!", TECHNICAL},
+/* ERR_DENC_BAD_PROP_IDX */ { "Invalid EncryptionProperty index!", TECHNICAL},
+/* ERR_DENC_BAD_KEY_IDX */ { "Invalid EncryptedKey index!", TECHNICAL},
+/* ERR_DENC_KEY_STATUS */ { "Transport key not ready!", USER},
+/* ERR_DENC_DATA_STATUS */ { "Invalid data status for this operation!", USER},
+/* ERR_DENC_DECRYPT */ { "Failed to decrypt the data!", USER},
+/* ERR_CHARSET_CONVERT */ { "Error converting charsets!", TECHNICAL },
+/* ERR_COMPRESS */ { "Error compressing the data!", TECHNICAL },
+/* ERR_DECOMPRESS */ { "Error decompressing the data!", TECHNICAL },
+/* ERR_OCSP_CERT_NOTFOUND */ { "OCSP Responders cetificate not found!", USER },
+/* ERR_INVALID_CONTENT */ { "Invalid characters in manifest or addres!", USER },
+/* ERR_DENC_NO_KEY_FOUND */ { "No transport key for this smartcard!", USER },
+/* ERR_OCSP_RESP_NOT_TRUSTED */ { "OCSP responder is not trusted! No certificate for this responder in local certstore!", USER },
+/* ERR_PRIV_CERT_NOT_FOUND */ { "Certificate not found!", USER },
+/* ERR_NO_OCSP */ { "Signature has no OCSP confirmation!", USER },
+/* ERR_OCSP_WRONG_SIGNATURE */ { "OCSP signature is wrong!", USER },
+/* ERR_BAD_PARAM */ { "Invalid parameter!", TECHNICAL },
+/* ERR_GENERIC_SOAP_ERR */ { "Generic SOAP error", TECHNICAL },
+
+/* ERR_TS_TIMESTAMPINFO_TYPE */ { "Invalid Timestamp type", TECHNICAL },
+/* ERR_TS_BAD_INCLUDEINFO_IDX */ { "Invalid Include index", TECHNICAL },
+/* ERR_TS_BAD_TIMESTAMPINFO_IDX */ { "Invalid TimestampInfo index", TECHNICAL },
+/* ERR_TS_CREATE_TS_REQ */ { "Error creating timestamp request", TECHNICAL },
+/* ERR_CREATE_NONCE */ { "Error creating nonce", TECHNICAL },
+/* ERR_TXT2OID */ { "Error converting text to OID", TECHNICAL },
+/* ERR_HTTP_ERR */ { "Invalid HTTP response code", TECHNICAL },
+/* ERR_BAD_CERTID_IDX */ { "Invalid Include index", TECHNICAL },
+/* ERR_BAD_CERTVALUE_IDX */ { "Invalid Include index", TECHNICAL },
+/* ERR_TS_VERIFY */ { "Timestamp verification error", USER },
+/* ERR_TS_REQUEST */ { "Error getting timestamp", USER },
+/* ERR_TSA_NOT_TRUSTED */ { "TSA is not trusted! No certificate for this TSA in local certstore!", USER },
+/* ERR_ORPHONED_SIGNATURE */ { "Incomplete or orphoned signature!", TECHNICAL },
+
+
+/* ERR_WPKI_UNKNOWN_USER */ { "Unknown WPKI user!", USER },
+/* ERR_WPKI_INVALID_PHONE_NO */ { "Invalid phone number for this WPKI user!", USER },
+/* ERR_WPKI_UNTRUSTED_SRVICE */ { "WPKI service is not trusted!", USER },
+/* ERR_WPKI_UNTRUSTED_USER */ { "Service demands customer authentication!", USER },
+
+/* ERR_WPKI_UNUSABLE_PHONE */ { "Error signing with customers mobile phone! Unusable phone type?", USER },
+/* ERR_WPKI_TIMEOUT */ { "Timeout during mobile signing!", USER },
+/* ERR_WPKI_CANCELLED */ { "User cancelled mobile signing!", USER },
+/* ERR_WPKI_MID_NOT_READY */ { "MID not ready!", USER },
+/* ERR_WPKI_PHONE_NOT_REACHABLE */ { "Users phone is not reachable!", USER },
+/* ERR_WPKI_SENDING_ERROR */ { "Error sending signing request to users mobile phone!", USER },
+/* ERR_WPKI_SIM_ERROR */ { "SIM card error!", USER },
+/* ERR_WPKI_SERVICE_ERR */ { "Mobile signing service internal error!", USER },
+//AM 18.03.08
+/* ERR_ZIP_FILE_READ */ { "File not found in BDOC!", USER },
+/* ERR_ZIP */ { "Error in BDocZip!", USER },
+/* ERR_MANIFEST */ { "Can't parse manifest!", USER },
+/* ERR_DATAFILE_NOT_MANIFEST */ { "Datafile is not described in manifest.xml!", USER },
+/* ERR_SIG_INVALID_PROFILE */ { "Signature does not correspond to profile in manifest.xml!", USER },
+/* ERR_SIGNERS_CERT_NON_REPU */ { "Signers cert does not have non-repudiation bit set!", USER },
+/* ERR_OCSP_NONCE_SIGVAL_NOMATCH */ { "Calculated signature hash doesn't match to OCSP responder nonce field!", USER },
+/* ERR_VALIDATE */ { "Validation error! Invalid ddoc or cdoc document.", USER },
+/* ERR_OCSP_NONCE_INVALID */ { "Invalid nonce length!", TECHNICAL },
+/* ERR_SIGVAL_ASN1 */ { "Invalid signature value! Missing or wrong asn.1 signature structure", TECHNICAL },
+/* ERR_MAX_1_ROLES */ { "Currently supports no more than 1 ClaimedRoles!", USER },
+/* ERR_DF_NAME */ { "Failed to parse DataFile name. Invalid file name!", USER },
+/* ERR_DF_WRONG_DIG */ { "Invalid DataFile digest! Alternate digest matches.", USER },
+/* ERR_ISSUER_XMLNS */ { "X509IssuerName or X509IssuerSerial missing xmlns atribute", USER },
+/* ERR_OLD_VERSION */ { "SK-XML 1.0 and DIGIDOC-XML 1.1 and 1.2 are old signature formats and schould not be used for new documents", USER },
+/* ERR_TEST_SIGNATURE */ { "Test signature!", USER },
+/* ERR_UNKNOWN_ERROR */ { "Multiple errors. Check the error list!", USER },
+/* ERR_TRANSFORM_UNSUPPORTED */ { "Transform elements are currently not supported!", USER },
+/* ERR_NETWORK_SYNC */ { "Error writing file! Network synchronize timeout.", USER },
+/* ERR_XML_VALIDATION */ { "Signature xml structure validation error", USER },
+
+/* */ {"", NO_ERRORS}
+};
+
+
+//==========< global variables >====================
+
+//int g_ddocLastError = ERR_OK;
+
+#define INITIAL_MAX_THREADS 1
+#define NOT_FOUND -1
+
+#if defined(WIN32)
+ #define THREAD_ID DWORD
+#elif defined(USEPTHREADS)
+ #define THREAD_ID pthread_t
+#else
+ #define THREAD_ID pid_t
+#endif
+
+typedef struct ThreadErrors_st {
+ THREAD_ID tid;
+ int currentErrorIdx;
+ int readErrorIdx;
+ ErrorInfo ddocLastErrors[ERROR_BUF_LENGTH];
+} ThreadErrors;
+
+static int g_threads = 0;
+
+static ThreadErrors **ddocErrors = NULL;
+
+// Following mutual exclusion objects are here to
+// protect access to ddocErrors and g_threads; whenever we access these variables
+// we have to use lock/unlock.
+
+#if defined(USEPTHREADS)
+ pthread_mutex_t m_ddocErrors = PTHREAD_MUTEX_INITIALIZER;
+#elif defined(WIN32)
+ //My bad, no static initializer for critical sections; initialized in DigiDocLib.c
+ CRITICAL_SECTION cs_ddocErrors;
+#endif
+
+// Returns unique thread identifier
+static THREAD_ID getTid(void)
+{
+#if defined(WIN32)
+ return GetCurrentThreadId();
+#elif defined(USEPTHREADS)
+ return pthread_self();
+#else
+ return getpid();
+#endif
+}
+
+static void lock(void)
+{
+#if defined WIN32
+ EnterCriticalSection(&cs_ddocErrors);
+#elif defined USEPTHREADS
+ pthread_mutex_lock(&m_ddocErrors);
+#else
+ // Hope it will be optimized away..
+#endif
+}
+
+
+static void unlock(void)
+{
+#if defined WIN32
+ LeaveCriticalSection(&cs_ddocErrors);
+#elif defined USEPTHREADS
+ pthread_mutex_unlock(&m_ddocErrors);
+#else
+ // Hope it will be optimized away..
+#endif
+}
+
+
+// Grows or creates the array of pointers to ThreadErrors
+// Will be always called with locked mutex.
+static int growErrorTable(void)
+{
+ int slotsToAllocate;
+ int i;
+ ThreadErrors **tmpErrors;
+
+ // printf("growErrorTable init : g_threads=%d, ddocErrors=%p\n", g_threads, ddocErrors);
+ if (g_threads == 0)
+ slotsToAllocate = INITIAL_MAX_THREADS; // We have no table so far at all
+ else
+ slotsToAllocate = g_threads * 2; // We'll double the table size everytime
+ tmpErrors = (ThreadErrors**)realloc(ddocErrors, slotsToAllocate * sizeof(ThreadErrors *)); // MEMLEAK: ???
+ if (tmpErrors == NULL)
+ return ERR_BAD_ALLOC;
+ ddocErrors = tmpErrors;
+ for (i = g_threads; i < slotsToAllocate; i++) // Initialize new entries;
+ ddocErrors[i] = NULL;
+ g_threads = slotsToAllocate;
+ // printf("growErrorTable leave : g_threads=%d, ddocErrors=%p\n", g_threads, ddocErrors);
+ return ERR_OK;
+}
+
+static int isThreadEqual(THREAD_ID tid1, THREAD_ID tid2)
+{
+#if defined(WIN32)
+ return tid1 == tid2;
+#elif defined(USETHREADS)
+ return pthread_equal(tid1, tid2);
+#else
+ return tid1 == tid2;
+#endif
+}
+
+// Finds slot number in ddocErrors[] whose pointer points to ThreadErrors belonging to threadID
+// or returns NOT_FOUND;
+static int findSlotByTid(THREAD_ID threadID)
+{
+ int i;
+
+ lock();
+ if (ddocErrors == NULL) {
+ unlock();
+ return NOT_FOUND;
+ }
+
+ for (i = 0; i < g_threads; i++)
+ if (ddocErrors[i] && isThreadEqual(ddocErrors[i]->tid,threadID)) {
+ unlock();
+ return i;
+ }
+ unlock();
+ return NOT_FOUND;
+}
+
+
+// Finds thread's ThreadError structure address, returns NULL if the thread doesn't have it (yet).
+static ThreadErrors *findThreadErrorsByTid(THREAD_ID threadID)
+{
+ ThreadErrors *tmpThreadErrors;
+ int slot = findSlotByTid(threadID);
+
+ if (slot == NOT_FOUND)
+ return NULL;
+ lock();
+ tmpThreadErrors = ddocErrors[slot];
+ unlock();
+ return tmpThreadErrors;
+}
+
+// Creates ThreadErrors structure for thread Tid, returns pointer to
+// created object; returns NULL if the object wasn't created.
+static ThreadErrors *addThreadErrorsByTid(THREAD_ID Tid)
+{
+ int i, slot = NOT_FOUND;
+
+ ThreadErrors *threadErrors = findThreadErrorsByTid(Tid);
+ if (threadErrors != NULL) // Already present, do nothing
+ return threadErrors;
+ lock();
+ for (i = 0; i < g_threads; i++) {
+ if (ddocErrors[i] == NULL) // Won't enter here if g_threads == 0
+ slot = i; // first free slot found
+ }
+ if (slot == NOT_FOUND) {
+ if (growErrorTable() == ERR_OK) {
+ for (i = 0; i < g_threads; i++) { //Try again...
+ if (ddocErrors[i] == NULL)
+ slot = i;
+ }
+ } else {
+ unlock();
+ return NULL;
+ }
+ }
+
+ threadErrors = (ThreadErrors*)malloc(sizeof(ThreadErrors)); // MEMLEAK: ???
+ if (threadErrors == NULL) {
+ unlock();
+ return NULL;
+ }
+
+ memset(threadErrors, 0, sizeof(ThreadErrors));
+ threadErrors->tid = Tid;
+ threadErrors->readErrorIdx = -1;
+ threadErrors->currentErrorIdx = -1;
+
+ ddocErrors[slot] = threadErrors;
+ unlock();
+ return threadErrors;
+}
+
+// Releases memory allocated for ThreadError structure of thread threadID
+EXP_OPTION void freeThreadErrorsByTid(THREAD_ID threadID)
+{
+ ThreadErrors *threadErrors;
+ int slot = findSlotByTid(threadID);
+
+ if (slot == NOT_FOUND)
+ return;
+
+ threadErrors = findThreadErrorsByTid(threadID);
+
+ lock();
+ free(threadErrors);
+ ddocErrors[slot] = NULL;
+ unlock();
+}
+
+//================< error handling functions> =================================
+
+//returns textual explanation of the error code
+EXP_OPTION char* getErrorString(int code)
+{
+ if(code < ERR_MAX && code >= 0)
+ return g_ddocErrorStrings[code].errorMessage;
+ else
+ return "No error message defined for this error";
+}
+
+EXP_OPTION ErrorClass getErrorClass(int code)
+{
+ if(code < ERR_MAX && code >= 0)
+ return g_ddocErrorStrings[code].errorClass;
+ else
+ return NO_ERRORS;
+}
+
+//returns the last
+EXP_OPTION ErrorInfo* getErrorInfo()
+{
+ ErrorInfo *pErrInfo = 0;
+ THREAD_ID Tid = getTid();
+
+ ThreadErrors *threadErrors = findThreadErrorsByTid(Tid);
+ if (threadErrors == NULL)
+ return 0;
+
+ if(threadErrors->readErrorIdx >= 0 &&
+ threadErrors->ddocLastErrors[threadErrors->readErrorIdx].code != ERR_OK) {
+ pErrInfo = &(threadErrors->ddocLastErrors[threadErrors->readErrorIdx]);
+ threadErrors->readErrorIdx--;
+ if(threadErrors->readErrorIdx < 0) //roll over
+ threadErrors->readErrorIdx = ERROR_BUF_LENGTH - 1;
+ }
+ else
+ pErrInfo = 0;
+
+ return pErrInfo;
+}
+
+//returns 1, if all errors are read and 0 otherwise
+EXP_OPTION int hasUnreadErrors()
+{
+ THREAD_ID Tid = getTid();
+
+ ThreadErrors *threadErrors = findThreadErrorsByTid(Tid);
+ if (threadErrors == NULL)
+ return 0;
+ return (threadErrors->readErrorIdx >= 0 ?
+ threadErrors->ddocLastErrors[threadErrors->readErrorIdx].code : ERR_OK);
+}
+
+//returns -1, if all errors are read and valid index otherwise
+EXP_OPTION int getLastErrorsIdx()
+{
+ THREAD_ID Tid = getTid();
+
+ ThreadErrors *threadErrors = findThreadErrorsByTid(Tid);
+ if (threadErrors == NULL)
+ return -1;
+ return threadErrors->readErrorIdx;
+}
+
+//returns NULL, if all errors are read and valid ErrorInfo structre pointer otherwise
+// does not mark error as read so it can be found again
+EXP_OPTION ErrorInfo* getErrorsInfo(int nIdx)
+{
+ ErrorInfo *pErrInfo = 0;
+ THREAD_ID Tid = getTid();
+
+ ThreadErrors *threadErrors = findThreadErrorsByTid(Tid);
+ if (threadErrors == NULL)
+ return 0;
+
+ if(nIdx >= 0 &&
+ threadErrors->ddocLastErrors[nIdx].code != ERR_OK) {
+ pErrInfo = &(threadErrors->ddocLastErrors[nIdx]);
+ }
+ else
+ pErrInfo = 0;
+
+ return pErrInfo;
+}
+
+
+EXP_OPTION void clearErrors()
+{
+ THREAD_ID Tid = getTid();
+ ThreadErrors *threadErrors = findThreadErrorsByTid(Tid);
+ if (threadErrors == NULL)
+ return;
+ memset(threadErrors->ddocLastErrors, 0, sizeof(ErrorInfo) * ERROR_BUF_LENGTH);
+ threadErrors->readErrorIdx = -1;
+ threadErrors->currentErrorIdx = -1;
+}
+
+
+EXP_OPTION void resetError(ErrorInfo *pErrInfo)
+{
+ pErrInfo->code = ERR_OK;
+ pErrInfo->fileName = "";
+ pErrInfo->line = 0;
+ pErrInfo->assertion = "";
+}
+
+
+EXP_OPTION void addError(int code, char *fileName, int line, char *assertion)
+{
+ //no errors found yet. Set a trace-back mark to the end of array.
+ //printf("Error : %d at %s line %d, assertion %s\n", code, fileName, line, assertion);
+
+ ThreadErrors *threadErrors;
+ THREAD_ID Tid = getTid(); //Find our identity
+
+ threadErrors = findThreadErrorsByTid(Tid);
+ // printf("addError init: tid=%ld, threadErrors=%p\n", Tid, threadErrors);
+ if (threadErrors == NULL) { //This Tid has no entry in ThreadErrors table
+ threadErrors = addThreadErrorsByTid(Tid); // MEMLEAK: ???
+ if (threadErrors == NULL)
+ return; // What else can we do?
+ }
+
+ // printf("addError step 1 : tid=%ld, threadErrors=%p\n", Tid, threadErrors);
+ if(threadErrors->currentErrorIdx < 0)
+ resetError(&(threadErrors->ddocLastErrors[ERROR_BUF_LENGTH - 1]));
+
+ threadErrors->currentErrorIdx++;
+
+ //index at the end -> roll it over to the beginning
+ if(threadErrors->currentErrorIdx == ERROR_BUF_LENGTH-1)
+ threadErrors->currentErrorIdx = 0;
+
+ //set the information
+ ddocDebug(4, "addError", "Index: %d Error : %d at %s line %d, assertion %s", threadErrors->currentErrorIdx, code, fileName, line, assertion);
+ threadErrors->ddocLastErrors[threadErrors->currentErrorIdx].code = code;
+ threadErrors->ddocLastErrors[threadErrors->currentErrorIdx].fileName = fileName;
+ threadErrors->ddocLastErrors[threadErrors->currentErrorIdx].line = line;
+ threadErrors->ddocLastErrors[threadErrors->currentErrorIdx].assertion = assertion;
+
+ //index at the end? Set the traceback mark to the beginning
+ if(threadErrors->currentErrorIdx == ERROR_BUF_LENGTH - 1)
+ resetError(&(threadErrors->ddocLastErrors[0]));
+ else //set the traceback mark to the next position
+ resetError(&(threadErrors->ddocLastErrors[threadErrors->currentErrorIdx + 1]));
+
+ threadErrors->readErrorIdx = threadErrors->currentErrorIdx;
+}
+
+//--------------------------------------------------
+// Checks DigiDoc library internal errors
+//--------------------------------------------------
+EXP_OPTION int checkDigiDocErrors()
+{
+ char *errorClass[] = {"NO_ERRORS", "TECHNICAL", "USER", "LIBRARY"};
+ int err = ERR_OK;
+ while(hasUnreadErrors()) {
+ ErrorInfo* pErr = getErrorInfo();
+ char* pErrStr = getErrorString(pErr->code);
+ printf("Error: %d - %s; file: %s line: %d; failed condition: %s, error class : %s\n",
+ pErr->code, pErrStr, pErr->fileName, pErr->line, pErr->assertion, errorClass[getErrorClass(pErr->code)]);
+ err = pErr->code;
+ }
+ clearErrors();
+ return err;
+}
+
+EXP_OPTION int getLastError()
+{
+ THREAD_ID Tid = getTid();
+
+ ThreadErrors *threadErrors = findThreadErrorsByTid(Tid);
+ if (threadErrors == NULL)
+ return 0;
+ return (threadErrors->readErrorIdx >= 0 ?
+ threadErrors->ddocLastErrors[threadErrors->readErrorIdx].code : ERR_OK);
+}
+
+
+EXP_OPTION int checkUnknownErr(SignedDoc* pSigDoc)
+{
+ int n, m = getLastErrorsIdx(), err1 = 0, err2 = 0;
+ ErrorInfo* pErr;
+
+ // list all errors
+ for(n = m; n >= 0; n--) {
+ pErr = getErrorsInfo(n);
+ if(!err1 && pErr) {
+ err1 = pErr->code;
+ }
+ else if(!err2 && pErr && pErr->code != err1)
+ err2 = pErr->code;
+ }
+ return ((err1 != err2 && err2) ? ERR_UNKNOWN_ERROR : err1);
+}
+
diff --git a/libdigidoc/DigiDocError.h b/libdigidoc/DigiDocError.h
new file mode 100644
index 0000000..c8a4608
--- /dev/null
+++ b/libdigidoc/DigiDocError.h
@@ -0,0 +1,310 @@
+#ifndef __DIGI_DOC_ERROR_H__
+#define __DIGI_DOC_ERROR_H__
+//==================================================
+// FILE: DigiDocError.h
+// PROJECT: Digi Doc
+// DESCRIPTION: Digi Doc error codes and functions
+// AUTHOR: Veiko Sinivee, S|E|B IT Partner Estonia
+//==================================================
+// Copyright (C) AS Sertifitseerimiskeskus
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.ode
+// GNU Lesser General Public Licence is available at
+// http://www.gnu.org/copyleft/lesser.html
+//==========< HISTORY >=============================
+//==================================================
+
+#ifdef WIN32
+ #include <windows.h>
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+//==========< error codes >=======================
+
+#define ERR_OK 0
+#define ERR_UNSUPPORTED_DIGEST 1
+#define ERR_FILE_READ 2
+#define ERR_FILE_WRITE 3
+#define ERR_DIGEST_LEN 4
+#define ERR_BUF_LEN 5
+#define ERR_SIGNATURE_LEN 6
+#define ERR_PRIVKEY_READ 7
+#define ERR_PUBKEY_READ 8
+#define ERR_CERT_READ 9
+#define ERR_SIGNEDINFO_CREATE 10
+#define ERR_SIGNEDINFO_DATA 11
+#define ERR_SIGNEDINFO_FINAL 12
+#define ERR_UNSUPPORTED_FORMAT 13
+#define ERR_BAD_INDEX 14
+#define ERR_TIMESTAMP_DECODE 15
+#define ERR_DIGIDOC_PARSE 16
+#define ERR_UNSUPPORTED_SIGNATURE 17
+#define ERR_CERT_STORE_READ 18
+#define ERR_SIGPROP_DIGEST 19
+#define ERR_COMPARE 20
+#define ERR_DOC_DIGEST 21
+#define ERR_MIME_DIGEST 22
+#define ERR_SIGNATURE 23
+#define ERR_CERT_INVALID 24
+#define ERR_OCSP_UNSUCCESSFUL 25
+#define ERR_OCSP_UNKNOWN_TYPE 26
+#define ERR_OCSP_NO_BASIC_RESP 27
+#define ERR_OCSP_WRONG_VERSION 28
+#define ERR_OCSP_WRONG_RESPID 29
+#define ERR_OCSP_ONE_RESPONSE 30
+#define ERR_OCSP_RESP_STATUS 31
+#define ERR_OCSP_NO_SINGLE_EXT 32
+#define ERR_OCSP_NO_NONCE 33
+#define ERR_NOTARY_NO_SIGNATURE 34
+#define ERR_NOTARY_SIG_MATCH 35
+#define ERR_SIGNERS_CERT_NOT_TRUSTED 36
+
+#define ERR_WRONG_CERT 37
+#define ERR_NULL_POINTER 38
+#define ERR_NULL_CERT_POINTER 39
+#define ERR_NULL_SER_NUM_POINTER 40
+#define ERR_NULL_KEY_POINTER 41
+#define ERR_EMPTY_STRING 42
+#define ERR_BAD_DATAFILE_INDEX 43
+#define ERR_BAD_DATAFILE_COUNT 44
+#define ERR_BAD_ATTR_COUNT 45
+#define ERR_BAD_ATTR_INDEX 46
+#define ERR_BAD_SIG_INDEX 47
+#define ERR_BAD_SIG_COUNT 48
+#define ERR_BAD_ROLE_INDEX 49
+#define ERR_BAD_DOCINFO_COUNT 50
+#define ERR_BAD_DOCINFO_INDEX 51
+#define ERR_BAD_NOTARY_INDEX 52
+#define ERR_BAD_NOTARY_ID 53
+#define ERR_BAD_NOTARY_COUNT 54
+#define ERR_X509_DIGEST 55
+#define ERR_CERT_LENGTH 56
+#define ERR_PKCS_LIB_LOAD 57
+#define ERR_PKCS_SLOT_LIST 58
+#define ERR_PKCS_WRONG_SLOT 59
+#define ERR_PKCS_LOGIN 60
+#define ERR_PKCS_PK 61
+#define ERR_PKCS_CERT_LOC 62
+#define ERR_PKCS_CERT_DECODE 63
+#define ERR_PKCS_SIGN_DATA 64
+#define ERR_PKCS_CARD_READ 65
+#define ERR_CSP_NO_CARD_DATA 66
+#define ERR_CSP_OPEN_STORE 67
+#define ERR_CSP_CERT_FOUND 68
+#define ERR_CSP_SIGN 69
+#define ERR_CSP_NO_HASH_START 70
+#define ERR_CSP_NO_HASH 71
+#define ERR_CSP_NO_HASH_RESULT 72
+#define ERR_CSP_OPEN_KEY 73
+#define ERR_CSP_READ_KEY 74
+#define ERR_OCSP_SIGN_NOT_SUPPORTED 75
+#define ERR_OCSP_SIGN_CSP_NAME 76
+#define ERR_CSP_CERT_DECODE 77
+#define ERR_OCSP_SIGN_PKCS_NAME 78
+#define ERR_OCSP_SIGN_OSLL_CERT 79
+#define ERR_OCSP_SIGN 80
+#define ERR_CERT_ISSUER 81
+#define ERR_OCSP_PKCS12_CONTAINER 82
+#define ERR_MODIFY_SIGNED_DOC 83
+#define ERR_NOTARY_EXISTS 84
+#define ERR_UNSUPPORTED_CERT_SEARCH 85
+#define ERR_INCORRECT_CERT_SEARCH 86
+#define ERR_BAD_OCSP_RESPONSE_DIGEST 87
+#define ERR_LAST_ESTID_CACHED 88
+#define ERR_BAD_DATAFILE_XML 89
+#define ERR_UNSUPPORTED_VERSION 90
+#define ERR_UNSUPPORTED_CHARSET 91
+#define ERR_PKCS12_EXPIRED 92
+#define ERR_CSP_USER_CANCEL 93
+#define ERR_CSP_NODEFKEY_CONTAINER 94
+#define ERR_CONNECTION_FAILURE 95
+#define ERR_WRONG_URL_OR_PROXY 96
+#define ERR_NULL_PARAM 97
+#define ERR_BAD_ALLOC 98
+#define ERR_CONF_FILE 99
+#define ERR_CONF_LINE 100
+#define ERR_OCSP_CERT_REVOKED 101
+#define ERR_OCSP_CERT_UNKNOWN 102
+#define ERR_OCSP_PKCS12_NO_FILE 103
+#define ERR_OCSP_PKCS12_NO_PASSWD 104
+#define ERR_BAD_DATAFILE_CONTENT_TYPE 105
+#define ERR_OCSP_WRONG_URL 106
+#define ERR_OCSP_MALFORMED 107
+#define ERR_OCSP_INTERNALERR 108
+#define ERR_OCSP_TRYLATER 109
+#define ERR_OCSP_SIGREQUIRED 110
+#define ERR_OCSP_UNAUTHORIZED 111
+#define ERR_UNKNOWN_CA 112
+// DigiDocEnc errors
+#define ERR_DENC_ENC_METHOD 113
+#define ERR_DENC_ENC_XMLNS 114
+#define ERR_DENC_BAD_PROP_IDX 115
+#define ERR_DENC_BAD_KEY_IDX 116
+#define ERR_DENC_KEY_STATUS 117
+#define ERR_DENC_DATA_STATUS 118
+#define ERR_DENC_DECRYPT 119
+#define ERR_CHARSET_CONVERT 120
+#define ERR_COMPRESS 121
+#define ERR_DECOMPRESS 122
+#define ERR_OCSP_CERT_NOTFOUND 123
+#define ERR_INVALID_CONTENT 124
+#define ERR_DENC_NO_KEY_FOUND 125
+#define ERR_OCSP_RESP_NOT_TRUSTED 126
+#define ERR_PRIV_CERT_NOT_FOUND 127
+#define ERR_NO_OCSP 128
+#define ERR_OCSP_WRONG_SIGNATURE 129
+#define ERR_BAD_PARAM 130
+#define ERR_GENERIC_SOAP_ERR 131
+
+#define ERR_TS_TIMESTAMPINFO_TYPE 132
+#define ERR_TS_BAD_INCLUDEINFO_IDX 133
+#define ERR_TS_BAD_TIMESTAMPINFO_IDX 134
+#define ERR_TS_CREATE_TS_REQ 135
+#define ERR_CREATE_NONCE 136
+#define ERR_TXT2OID 137
+#define ERR_HTTP_ERR 138
+
+#define ERR_BAD_CERTID_IDX 139
+#define ERR_BAD_CERTVALUE_IDX 140
+#define ERR_TS_VERIFY 141
+#define ERR_TS_REQUEST 142
+#define ERR_TSA_NOT_TRUSTED 143
+#define ERR_ORPHONED_SIGNATURE 144
+
+#define ERR_WPKI_UNKNOWN_USER 145
+#define ERR_WPKI_INVALID_PHONE_NO 146
+#define ERR_WPKI_UNTRUSTED_SRVICE 147
+#define ERR_WPKI_UNTRUSTED_USER 148
+
+#define ERR_WPKI_UNUSABLE_PHONE 149
+#define ERR_WPKI_TIMEOUT 150
+#define ERR_WPKI_CANCELLED 151
+#define ERR_WPKI_MID_NOT_READY 152
+#define ERR_WPKI_PHONE_NOT_REACHABLE 153
+#define ERR_WPKI_SENDING_ERROR 154
+#define ERR_WPKI_SIM_ERROR 155
+#define ERR_WPKI_SERVICE_ERR 156
+//AM 18.03.08
+#define ERR_ZIP_FILE_READ 157
+#define ERR_ZIP 158
+#define ERR_MANIFEST 159
+#define ERR_DATAFILE_NOT_MANIFEST 160
+#define ERR_SIG_INVALID_PROFILE 161
+#define ERR_SIGNERS_CERT_NON_REPU 162
+#define ERR_OCSP_NONCE_SIGVAL_NOMATCH 163
+#define ERR_VALIDATE 164
+#define ERR_OCSP_NONCE_INVALID 165
+#define ERR_SIGVAL_ASN1 166
+#define ERR_MAX_1_ROLES 167
+#define ERR_DF_NAME 168
+#define ERR_DF_WRONG_DIG 169
+#define ERR_ISSUER_XMLNS 170
+#define ERR_OLD_VERSION 171
+#define ERR_TEST_SIGNATURE 172
+#define ERR_UNKNOWN_ERROR 173
+#define ERR_TRANSFORM_UNSUPPORTED 174
+#define ERR_NETWORK_SYNC 175
+#define ERR_XML_VALIDATION 176
+
+#define ERROR_BUF_LENGTH 20
+
+
+typedef struct ErrorMessage_st {
+ char *errorMessage;
+ int errorClass;
+} ErrorMessage;
+
+typedef int ErrorClass;
+
+// Error classes
+
+// Wasn't an error at all, no reaction neccessary
+#define NO_ERRORS 0
+// Various problems of technical nature
+#define TECHNICAL 1
+// User-repairable errors
+#define USER 2
+// Bug in DigiDoc library (?)
+#define LIBRARY 3
+
+//==========< error info structure >==============
+
+typedef struct ErrorInfo_st {
+ int code;
+ char *fileName;
+ int line;
+ char *assertion;
+} ErrorInfo;
+
+#ifdef WIN32
+extern CRITICAL_SECTION cs_ddocErrors;
+#endif
+
+// checks and prints errors
+EXP_OPTION long checkErrors();
+
+//returns textual explanation of the error code
+EXP_OPTION char* getErrorString(int code);
+
+//returns the classification for the error code
+EXP_OPTION ErrorClass getErrorClass(int code);
+
+//returns the code of the error that occurred in the library
+EXP_OPTION ErrorInfo* getErrorInfo(void);
+
+//returns 1, if all errors are read and 0 otherwise
+EXP_OPTION int hasUnreadErrors(void);
+
+//resets error information
+EXP_OPTION void clearErrors(void);
+
+EXP_OPTION void addError(int code, char *fileName, int line, char *assertion);
+
+EXP_OPTION int checkDigiDocErrors(void);
+
+EXP_OPTION int getLastError();
+
+//returns -1, if all errors are read and valid index otherwise
+EXP_OPTION int getLastErrorsIdx();
+
+//returns NULL, if all errors are read and valid ErrorInfo structre pointer otherwise
+// does not mark error as read so it can be found again
+EXP_OPTION ErrorInfo* getErrorsInfo(int nIdx);
+
+// return ERR_UNKNOWN_ERROR if multiple different errors exist, otherwise first error code
+EXP_OPTION int checkUnknownErr();
+
+//==========< macros >====================
+
+#define SET_LAST_ERROR(code) (addError((code), __FILE__, __LINE__, ""))
+#define SET_LAST_ERROR_IF_NOT(expr, code) { if(!(expr)) addError((code), __FILE__, __LINE__, #expr); }
+#define SET_LAST_ERROR_RETURN(code, retVal) { SET_LAST_ERROR(code); return (retVal); }
+#define SET_LAST_ERROR_RETURN_IF_NOT(expr, code, retVal) { if(!(expr)) { addError((code), __FILE__, __LINE__, #expr); return (retVal); } }
+#define SET_LAST_ERROR_RETURN_VOID_IF_NOT(expr, code) { if(!(expr)) { addError((code), __FILE__, __LINE__, #expr); return; } }
+#define SET_LAST_ERROR_RETURN_VOID_IF(expr, code) { if(expr) { addError((code), __FILE__, __LINE__, #expr); return; } }
+#define RETURN_IF_NOT(expr, code) SET_LAST_ERROR_RETURN_IF_NOT((expr), (code), (code));
+#define RETURN_IF_NULL(p) RETURN_IF_NOT((p), ERR_NULL_POINTER);
+#define RETURN_VOID_IF_NULL(p) SET_LAST_ERROR_RETURN_VOID_IF_NOT((p), ERR_NULL_POINTER);
+#define RETURN_OBJ_IF_NULL(p, obj) SET_LAST_ERROR_RETURN_IF_NOT((p), ERR_NULL_POINTER, (obj));
+#define SET_LAST_ERROR_RETURN_CODE(code) { SET_LAST_ERROR(code); return (code); }
+#define RETURN_IF_NULL_PARAM(p) RETURN_IF_NOT((p), ERR_NULL_PARAM);
+#define RETURN_IF_BAD_ALLOC(p) RETURN_IF_NOT((p), ERR_BAD_ALLOC)
+#define RETURN_VOID_IF_BAD_ALLOC(p) SET_LAST_ERROR_RETURN_VOID_IF_NOT((p), ERR_BAD_ALLOC);
+
+//========================================
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/libdigidoc/DigiDocGen.c b/libdigidoc/DigiDocGen.c
new file mode 100644
index 0000000..dc016b1
--- /dev/null
+++ b/libdigidoc/DigiDocGen.c
@@ -0,0 +1,1925 @@
+//==================================================
+// FILE: DigiDocGen.c
+// PROJECT: Digi Doc
+// DESCRIPTION: DigiDoc helper routines for XML generation
+// AUTHOR: Veiko Sinivee, S|E|B IT Partner Estonia
+//==================================================
+// Copyright (C) AS Sertifitseerimiskeskus
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+// GNU Lesser General Public Licence is available at
+// http://www.gnu.org/copyleft/lesser.html
+//==========< HISTORY >=============================
+// 11.04.2006 Veiko Sinivee
+// Creation
+//==================================================
+
+
+#include <libdigidoc/DigiDocDefs.h>
+#include <libdigidoc/DigiDocLib.h>
+#include <libdigidoc/DigiDocDebug.h>
+#include <libdigidoc/DigiDocConfig.h>
+#include <libdigidoc/DigiDocConvert.h>
+#include <libdigidoc/DigiDocCert.h>
+#include <libdigidoc/DigiDocSAXParser.h>
+#include <libdigidoc/DigiDocDfExtract.h>
+#include <libdigidoc/DigiDocGen.h>
+#include <libdigidoc/DigiDocError.h>
+#include <string.h>
+#include <time.h>
+
+#include <libxml/globals.h>
+#include <libxml/xmlerror.h>
+#include <libxml/parser.h>
+#include <libxml/parserInternals.h> /* only for xmlNewInputFromFile() */
+#include <libxml/tree.h>
+#include <libxml/debugXML.h>
+#include <libxml/xmlmemory.h>
+#include <libxml/c14n.h>
+#include <libxml/xpath.h>
+#include <libxml/xpathInternals.h>
+
+#include <fcntl.h>
+
+//-----------< helper functions >----------------------------
+
+
+//--------------------------------------------------
+// Appends an xml element start to buffer, but no ">"
+// pBuf - memory buffer to store xml [REQUIRED]
+// elemName - xml element name [REQUIRED]
+// returns error code or ERR_OK
+//--------------------------------------------------
+int ddocGen_startElemBegin(DigiDocMemBuf* pBuf, const char* elemName)
+{
+ int err = ERR_OK;
+ RETURN_IF_NULL_PARAM(pBuf)
+ RETURN_IF_NULL_PARAM(elemName)
+ err = ddocMemAppendData(pBuf, "<", -1);
+ if(err) return err;
+ err = ddocMemAppendData(pBuf, elemName, -1);
+ return err;
+}
+
+//--------------------------------------------------
+// Appends an xml element start tag end to buffer - ">"
+// pBuf - memory buffer to store xml [REQUIRED]
+// returns error code or ERR_OK
+//--------------------------------------------------
+int ddocGen_startElemEnd(DigiDocMemBuf* pBuf)
+{
+ RETURN_IF_NULL_PARAM(pBuf)
+ return ddocMemAppendData(pBuf, ">", -1);
+}
+
+//--------------------------------------------------
+// Appends an xml element start to buffer - <tag>
+// pBuf - memory buffer to store xml [REQUIRED]
+// elemName - xml element name [REQUIRED]
+// returns error code or ERR_OK
+//--------------------------------------------------
+int ddocGen_startElem(DigiDocMemBuf* pBuf, const char* elemName)
+{
+ int err = ERR_OK;
+ RETURN_IF_NULL_PARAM(pBuf)
+ RETURN_IF_NULL_PARAM(elemName)
+ err = ddocMemAppendData(pBuf, "<", -1);
+ if(err) return err;
+ err = ddocMemAppendData(pBuf, elemName, -1);
+ if(err) return err;
+ err = ddocMemAppendData(pBuf, ">", -1);
+ return err;
+}
+
+//--------------------------------------------------
+// Appends an xml element end to buffer
+// pBuf - memory buffer to store xml [REQUIRED]
+// elemName - xml element name [REQUIRED]
+// returns error code or ERR_OK
+//--------------------------------------------------
+int ddocGen_endElem(DigiDocMemBuf* pBuf, const char* elemName)
+{
+ int err = ERR_OK;
+ RETURN_IF_NULL_PARAM(pBuf)
+ RETURN_IF_NULL_PARAM(elemName)
+ err = ddocMemAppendData(pBuf, "</", -1);
+ if(err) return err;
+ err = ddocMemAppendData(pBuf, elemName, -1);
+ if(err) return err;
+ err = ddocMemAppendData(pBuf, ">", -1);
+ return err;
+}
+
+//--------------------------------------------------
+// Appends an xml element's atribute to buffer
+// pBuf - memory buffer to store xml [REQUIRED]
+// name - xml atribute name [REQUIRED]
+// value - xml atribute value [REQUIRED]
+// returns error code or ERR_OK
+//--------------------------------------------------
+int ddocGen_addAtribute(DigiDocMemBuf* pBuf, const char* name, const char* value)
+{
+ int err = ERR_OK;
+ RETURN_IF_NULL_PARAM(pBuf)
+ RETURN_IF_NULL_PARAM(name)
+ RETURN_IF_NULL_PARAM(value)
+ err = ddocMemAppendData(pBuf, " ", -1);
+ if(err) return err;
+ err = ddocMemAppendData(pBuf, name, -1);
+ if(err) return err;
+ err = ddocMemAppendData(pBuf, "=\"", -1);
+ if(err) return err;
+ err = ddocMemAppendData(pBuf, value, -1);
+ if(err) return err;
+ err = ddocMemAppendData(pBuf, "\"", -1);
+ return err;
+}
+
+//================< functions Timestamp_st > =================================
+#ifdef WITH_TIMETSTAMP_STRUCT
+
+//===================================================================
+// converts string to timestamp
+// IN const char* szTimestamp - timestamp string
+// OUT Timestamp* pTimestamp
+//===================================================================
+EXP_OPTION int convertStringToTimestamp(const SignedDoc* pSigDoc, const char* szTimestamp, Timestamp* pTimestamp)
+{
+ RETURN_IF_NULL_PARAM(szTimestamp);
+ RETURN_IF_NULL_PARAM(pTimestamp);
+ RETURN_IF_NULL_PARAM(pSigDoc);
+ // in version 1.3 we use format CCYY-MM-DDTHH:MM:SS-TZ
+ if(!strcmp(pSigDoc->szFormatVer, DIGIDOC_XML_1_3_VER) ) {
+ sscanf(szTimestamp, "%04d-%02d-%04dT%02d:%02d:%02dZ",
+ &(pTimestamp->year), &(pTimestamp->mon), &(pTimestamp->day),
+ &(pTimestamp->hour), &(pTimestamp->min), &(pTimestamp->sec));
+ pTimestamp->tz = 0;
+ } else
+ // in version 1.0 we use format CCYY.MM.DDTHH:MM:SS-TZ
+ if(!strcmp(pSigDoc->szFormat, SK_XML_1_NAME) && !strcmp(pSigDoc->szFormatVer, SK_XML_1_VER)) {
+ sscanf(szTimestamp, "%04d.%02d.%04dT%02d:%02d:%02d%3d:00",
+ &(pTimestamp->year), &(pTimestamp->mon), &(pTimestamp->day),
+ &(pTimestamp->hour), &(pTimestamp->min), &(pTimestamp->sec), &(pTimestamp->tz));
+ } else { // in version 1.1 we use format CCYY.MM.DDTHH:MM:SSZ and allways UTC time
+ sscanf(szTimestamp, "%04d.%02d.%04dT%02d:%02d:%02dZ",
+ &(pTimestamp->year), &(pTimestamp->mon), &(pTimestamp->day),
+ &(pTimestamp->hour), &(pTimestamp->min), &(pTimestamp->sec));
+ pTimestamp->tz = 0;
+ }
+ return ERR_OK;
+}
+
+//===================================================================
+// converts string to timestamp
+// IN const char* szTimestamp - timestamp string
+// OUT Timestamp* pTimestamp
+//===================================================================
+EXP_OPTION int convertTimestampToString(const SignedDoc* pSigDoc, const Timestamp* pTimestamp,
+ char* szTimestamp, int len)
+{
+ RETURN_IF_NULL_PARAM(szTimestamp);
+ RETURN_IF_NULL_PARAM(pTimestamp);
+ //RETURN_IF_NULL_PARAM(pSigDoc); // if null then latest format is used
+
+ // in version 1.3 we use format CCYY-MM-DDTHH:MM:SS-TZ
+ //AM 30.04.08 also in bdoc
+ if(!pSigDoc || (pSigDoc && (
+ !strcmp(pSigDoc->szFormatVer, DIGIDOC_XML_1_3_VER) ))) {
+ snprintf(szTimestamp, len, "%04d-%02d-%02dT%02d:%02d:%02dZ",pTimestamp->year,
+ pTimestamp->mon, pTimestamp->day, pTimestamp->hour , pTimestamp->min,
+ pTimestamp->sec);
+ } else // in version 1.0 we use format CCYY.MM.DDTHH:MM:SS-TZ
+ if(!strcmp(pSigDoc->szFormat, SK_XML_1_NAME) && !strcmp(pSigDoc->szFormatVer, SK_XML_1_VER)) {
+ snprintf(szTimestamp, len, "%04d.%02d.%02dT%02d:%02d:%02d%+03d:00",pTimestamp->year,
+ pTimestamp->mon, pTimestamp->day, pTimestamp->hour , pTimestamp->min,
+ pTimestamp->sec, pTimestamp->tz);
+ } else { // in version 1.1 we use format CCYY.MM.DDTHH:MM:SSZ and allways UTC time
+ snprintf(szTimestamp, len, "%04d.%02d.%02dT%02d:%02d:%02dZ",pTimestamp->year,
+ pTimestamp->mon, pTimestamp->day, pTimestamp->hour , pTimestamp->min,
+ pTimestamp->sec);
+ }
+ return ERR_OK;
+}
+
+// converts date integers to timestamp object
+EXP_OPTION int Timestamp_new(Timestamp **ppTimestamp, int year,int month,int day,int hour,int minute,int second,int timezone){
+ Timestamp* pTimestamp;
+ pTimestamp = (Timestamp*)malloc(sizeof(Timestamp));
+ RETURN_IF_BAD_ALLOC(pTimestamp);
+ memset(pTimestamp, 0, sizeof(Timestamp));
+ pTimestamp->year=year;
+ pTimestamp->mon=month;
+ pTimestamp->day=day;
+ pTimestamp->hour=hour;
+ pTimestamp->min=minute;
+ pTimestamp->sec=second;
+ pTimestamp->tz=timezone;
+ *ppTimestamp = pTimestamp;
+ return ERR_OK;
+}
+
+//======================================================================
+// frees timestamp object
+//======================================================================
+EXP_OPTION void Timestamp_free(Timestamp* pTimestamp){
+ free(pTimestamp);
+}
+
+
+#endif
+
+//===================================================================
+// converts timestamp string to time_t value
+// IN const char* szTimestamp - timestamp string
+// OUT Timestamp* pTimestamp
+//===================================================================
+EXP_OPTION time_t convertStringToTimeT(const SignedDoc* pSigDoc, const char* szTimestamp)
+{
+ struct tm tm1;
+ int tz, dmz = 0;
+ time_t t2;
+
+ memset(&tm1, 0, sizeof(tm1));
+ tzset();
+ t2 = 0;
+ // in version 1.0 we use format CCYY.MM.DDTHH:MM:SS-TZ
+ if(!strcmp(pSigDoc->szFormat, SK_XML_1_NAME) && !strcmp(pSigDoc->szFormatVer, SK_XML_1_VER)) {
+ sscanf(szTimestamp, "%04d.%02d.%02dT%02d:%02d:%02d+%03d:00",
+ &(tm1.tm_year), &(tm1.tm_mon), &(tm1.tm_mday),
+ &(tm1.tm_hour) , &(tm1.tm_min), &(tm1.tm_sec), &tz);
+ } else if(!strcmp(pSigDoc->szFormatVer, DIGIDOC_XML_1_1_VER) ||
+ !strcmp(pSigDoc->szFormatVer, DIGIDOC_XML_1_2_VER)) { // in version 1.1 we use format CCYY.MM.DDTHH:MM:SSZ and allways UTC time
+ sscanf(szTimestamp, "%04d.%02d.%02dT%02d:%02d:%02dZ", //crash?
+ &(tm1.tm_year), &(tm1.tm_mon), &(tm1.tm_mday),
+ &(tm1.tm_hour), &(tm1.tm_min), &(tm1.tm_sec));
+ } else { // in version 1.3 we use format CCYY-MM-DDTHH:MM:SSZ and allways UTC time
+ sscanf(szTimestamp, "%04d-%02d-%02dT%02d:%02d:%02dZ",
+ &(tm1.tm_year), &(tm1.tm_mon), &(tm1.tm_mday),
+ &(tm1.tm_hour), &(tm1.tm_min), &(tm1.tm_sec));
+ }
+ tm1.tm_year -= 1900;
+ tm1.tm_mon -= 1;
+ tm1.tm_isdst = daylight;
+ t2 = mktime(&tm1);
+ if(_daylight != 0) {
+ if(_timezone < 0)
+ dmz = (_timezone / 3600) - daylight;
+ else
+ dmz = (_timezone / 3600) + daylight;
+ }
+ else
+ dmz = _timezone / 3600;
+ t2 -= (dmz * 3600);
+ return t2;
+}
+
+
+//================< functions generating DigiDoc formats 1.0 - 1.3 > =================================
+
+
+
+//============================================================
+// Creates a timestamp string
+// buf - output buffer
+// len - length of output buffer
+// returns number of output bytes written
+//============================================================
+int createTimestamp(const SignedDoc* pSigDoc, char* buf, int len)
+{
+ time_t t;
+ struct tm tm1;
+ Timestamp *pTimestamp;
+ int dmz=0;
+
+ RETURN_OBJ_IF_NULL(buf, 0);
+ _tzset();
+ time(&t);
+ // in version 1.0 we use format CCYY.MM.DDTHH:MM:SS-TZ
+ if(pSigDoc && pSigDoc->szFormatVer && !strcmp(pSigDoc->szFormatVer, "1.0")) {
+ ddocLocalTime(&t, &tm1, 1);
+ if(_daylight != 0) {
+ /*if(_timezone<0){*/
+ dmz=(_timezone - (_daylight*3600))/ 3600;
+ /*}else{
+ dmz=(_timezone + (_daylight*3600))/ 3600;
+ }*/
+ }else{
+ dmz = _timezone / 3600;
+ }
+ } else { // in version 1.1 we use UTC time
+ ddocLocalTime(&t, &tm1, 0);
+ }
+ (void)Timestamp_new(&pTimestamp, tm1.tm_year + 1900, tm1.tm_mon + 1, tm1.tm_mday,
+ tm1.tm_hour, tm1.tm_min, tm1.tm_sec, dmz);
+ (void)convertTimestampToString(pSigDoc, pTimestamp, buf, len);
+ Timestamp_free(pTimestamp);
+ return strlen(buf);
+}
+
+//============================================================
+// Canonicalizes XML
+// source - input data
+// len - input length
+// returns a newly allocated buffer with canonicalized XML
+// Caller must free() the result.
+//============================================================
+char* canonicalizeXML(char* source, int len)
+{
+ xmlDocPtr doc = NULL;
+ xmlChar* pBuf = NULL;
+ int rc, n;
+ char* dest = NULL;
+
+ ddocDebug(5, "canonicalizeXML", "Canonicalizing: %d bytes", len);
+ if((doc = xmlParseMemory(source, len)) != NULL) {
+ ddocDebug(5, "canonicalizeXML", "Canonicalizing parse: %s", (doc ? "OK" : "ERROR"));
+ rc = xmlC14NDocDumpMemory(doc, NULL, 0, NULL, 0, &pBuf);
+ ddocDebug(5, "canonicalizeXML", "Canonicalizing RC: %d: BUF: %s", rc, (pBuf ? "OK" : "ERROR"));
+ if(pBuf) {
+ n = strlen((char*)pBuf);
+ dest = (char*)malloc(n + 1);
+ if(dest) {
+ strncpy(dest, (char*)pBuf, n);
+ dest[n] = 0;
+ }
+ else
+ SET_LAST_ERROR_IF_NOT(dest, ERR_BAD_ALLOC);
+ xmlFree(pBuf);
+ }
+ xmlFreeDoc(doc);
+ }
+ return dest;
+}
+
+
+
+
+//============================================================
+// Canonicalizes XML
+// source - input data
+// len - input length
+// returns a newly allocated buffer with canonicalized XML
+// Caller must free() the result.
+//============================================================
+char* canonicalizeXMLBlock(char* source, int len, char* block, char* prefix)
+{
+ xmlDocPtr doc = NULL;
+ xmlChar* pBuf = NULL;
+ int rc, n;
+ char* dest = NULL;
+ xmlXPathContextPtr xpathCtx;
+ xmlXPathObjectPtr xpathObj;
+ //xmlChar* incpref[] = {(xmlChar*)"ds", (xmlChar*)"xades", NULL};
+
+ ddocDebug(5, "canonicalizeXMLBlock", "Canonicalizing: %d bytes", len);
+ if((doc = xmlParseMemory(source, len)) != NULL) {
+ ddocDebug(5, "canonicalizeXMLBlock", "Canonicalizing parse: %s", (doc ? "OK" : "ERROR"));
+ /* Create xpath evaluation context */
+ xpathCtx = xmlXPathNewContext(doc);
+ if(xpathCtx == NULL) {
+ ddocDebug(5, "canonicalizeXMLBlock", "Error: unable to create new XPath context");
+ xmlFreeDoc(doc);
+ return NULL;
+ }
+ if(prefix && strlen(prefix)){
+ ddocDebug(5, "canonicalizeXMLBlock","xmlXPathRegisterNs");
+ if(xmlXPathRegisterNs(xpathCtx, prefix, "http://www.w3.org/2000/09/xmldsig#") != 0) {
+ ddocDebug(5, "canonicalizeXMLBlock","Error: failed to register namespace");
+ xmlXPathFreeContext(xpathCtx);
+ xmlFreeDoc(doc);
+ return NULL;
+ }
+ }
+ ddocDebug(5, "canonicalizeXMLBlock","xmlXPathRegisterNs123");
+ if(xmlXPathRegisterNs(xpathCtx, "xs", "http://uri.etsi.org/01903/v1.3.2#") != 0) {
+ ddocDebug(5, "canonicalizeXMLBlock","Error: failed to register namespace2\n");
+ xmlXPathFreeContext(xpathCtx);
+ xmlFreeDoc(doc);
+ return NULL;
+ }
+ /* Evaluate xpath expression */
+ xpathObj = xmlXPathEvalExpression(block, xpathCtx);
+ if(xpathObj == NULL) {
+ ddocDebug(5, "canonicalizeXMLBlock","Error: unable to evaluate xpath expression \"%s\"\n", block);
+ xmlXPathFreeContext(xpathCtx);
+ xmlFreeDoc(doc);
+ }
+ rc = xmlC14NDocDumpMemory(doc, xpathObj->nodesetval, 0, NULL, 0, &pBuf);
+ ddocDebug(5, "canonicalizeXMLBlock", "Canonicalizing RC: %d: BUF: %s", rc, (pBuf ? "OK" : "ERROR"));
+ if(pBuf) {
+ n = strlen((char*)pBuf);
+ dest = (char*)malloc(n + 1);
+ if(dest)
+ strncpy(dest, (char*)pBuf, n+1);
+ else
+ SET_LAST_ERROR_IF_NOT(dest, ERR_BAD_ALLOC);
+ xmlFree(pBuf);
+ }
+ xmlFreeDoc(doc);
+ }
+ return dest;
+}
+
+//--------------------------------------------------
+// Helper function that escapes XML special chars in xml element body
+// src - input data
+// srclen - length of input data. Use -1 for 0 terminated strings
+// dest - address of output buffer. Caller is responsible for deallocating it!
+// returns error code or ERR_OK
+//--------------------------------------------------
+int escapeTextNode(const char* src, int srclen, char** dest)
+{
+ int j, i, n = srclen, l;
+ char *p = 0;
+
+ RETURN_IF_NULL_PARAM(src);
+ RETURN_IF_NULL_PARAM(dest);
+ *dest = 0;
+ if(n < 0)
+ n = strlen(src);
+ if(n > 0 && ConfigItem_lookup_int("DEBUG_LEVEL", 1) >= 5) {
+ p = (char*)malloc(n+1);
+ if(p) {
+ memset(p, 0, n+1);
+ memcpy(p, src, n);
+ ddocDebug(5, "escapeTextNode", "src: \"%s\" len: %d", p, n);
+ free(p);
+ }
+ }
+ else
+ ddocDebug(5, "escapeTextNode", "src: \"%s\" len: %d", src, n);
+ // count the amount of memory needed for conversion
+ for(i = l = 0; i < n; i++) {
+ switch(src[i]) {
+ case '<': l += 4; break;
+ case '>': l += 4; break;
+ case '&': l += 5; break;
+ case '\r': l += 5; break;
+ default: l ++; break;
+ }
+ }
+ // count the last terminator char
+ l++;
+ ddocDebug(5, "escapeTextNode", "allocating: %d bytes", l);
+ *dest = (char*)malloc(l);
+ memset(*dest, 0, l);
+ // now convert the data
+ for(i = j = 0; i < n; i++) {
+ switch(src[i]) {
+ case '<': strncat(*dest, "&lt;", l - strlen(*dest)); j += 4; break;
+ case '>': strncat(*dest, "&gt;", l - strlen(*dest)); j += 4; break;
+ case '&':
+ if(src[i+3] != ';' && src[i+4] != ';' && src[i+5] != ';') {
+ if(src[i+1] != '#') {
+ strncat(*dest, "&amp;", l - strlen(*dest)); j += 5; break;
+ } else {
+ if(!strncmp(src+i, "&#38;", 5)) {
+ strncat(*dest, "&amp;", l - strlen(*dest)); j += 5; i += 4; break;
+ }
+ // but others?
+ }
+ } else {
+ (*dest)[j] = src[i]; j++;
+ }
+ break;
+ case '\r': strncat(*dest, "&#xD;", l - strlen(*dest)); j += 5; break;
+ default: (*dest)[j] = src[i]; j++; break;
+ }
+ }
+ ddocDebug(4, "escapeTextNode", "Src: %s Converted: \'%s\' len: %d", src, *dest, j);
+ return ERR_OK;
+}
+
+//--------------------------------------------------
+// Helper function that escapes XML special chars
+// src - input data
+// srclen - length of input data. Use -1 for 0 terminated strings
+// dest - address of output buffer. Caller is responsible for deallocating it!
+// returns error code or ERR_OK
+//--------------------------------------------------
+int escapeXMLSymbols(const char* src, int srclen, char** dest)
+{
+ int j, i, n = srclen, l;
+ char *p = 0;
+
+ RETURN_IF_NULL_PARAM(src);
+ RETURN_IF_NULL_PARAM(dest);
+ *dest = 0;
+ if(n < 0)
+ n = strlen(src);
+ if(n > 0 && ConfigItem_lookup_int("DEBUG_LEVEL", 1) >= 5) {
+ p = (char*)malloc(n+1);
+ if(p) {
+ memset(p, 0, n+1);
+ memcpy(p, src, n);
+ ddocDebug(5, "escapeXMLSymbols", "src: \"%s\" len: %d", p, n);
+ free(p);
+ }
+ }
+ else
+ ddocDebug(5, "escapeXMLSymbols", "src: \"%s\" len: %d", src, n);
+ // count the amount of memory needed for conversion
+ for(i = l = 0; i < n; i++) {
+ switch(src[i]) {
+ case '<': l += 4; break;
+ case '>': l += 4; break;
+ case '&': l += 5; break;
+ case '\r': l += 5; break;
+ case '\'': l += 6; break;
+ case '\"': l += 6; break;
+ default: l ++; break;
+ }
+ }
+ // count the last terminator char
+ l++;
+ ddocDebug(5, "escapeXMLSymbols", "allocating: %d bytes", l);
+ *dest = (char*)malloc(l);
+ memset(*dest, 0, l);
+ // now convert the data
+ for(i = j = 0; i < n; i++) {
+ switch(src[i]) {
+ case '<': strncat(*dest, "&lt;", l - strlen(*dest)); j += 4; break;
+ case '>': strncat(*dest, "&gt;", l - strlen(*dest)); j += 4; break;
+ case '&':
+ if(src[i+3] != ';' && src[i+4] != ';' && src[i+5] != ';') {
+ if(src[i+1] != '#') {
+ strncat(*dest, "&amp;", l - strlen(*dest)); j += 5; break;
+ } else {
+ if(!strncmp(src+i, "&#38;", 5)) {
+ strncat(*dest, "&amp;", l - strlen(*dest)); j += 5; i += 4; break;
+ }
+ // but others?
+ }
+ } else {
+ (*dest)[j] = src[i]; j++;
+ }
+ break;
+ case '\r': strncat(*dest, "&#xD;", l - strlen(*dest)); j += 5; break;
+ case '\'': strncat(*dest, "&apos;", l - strlen(*dest)); j += 6; break;
+ case '\"': strncat(*dest, "&quot;", l - strlen(*dest)); j += 6; break;
+ default: (*dest)[j] = src[i]; j++; break;
+ }
+ }
+ ddocDebug(4, "escapeXMLSymbols", "Src: %s Converted: \'%s\' len: %d", src, *dest, j);
+ return ERR_OK;
+}
+
+
+//============================================================
+// Creates a <SignedProperties> XML block
+// pSigDoc - signed document pointer
+// pSigInfo - signature info data
+// bWithEscapes - 1=escape xml symbols, 0=don't escape
+// returns new <SignedProperties> node
+//============================================================
+char* createXMLSignedProperties(const SignedDoc* pSigDoc, const SignatureInfo* pSigInfo, int bWithEscapes)
+{
+ char buf1[1024], *pRet = 0, *p1, *p2;
+ int len1, i, err;
+ xmlNodePtr pSigProp, pSigSigProp, pSigCert, pN1, pN2, pN3;
+ static xmlChar nl[] = "\n";
+ xmlDocPtr doc;
+ DigiDocMemBuf *pMBuf1;
+ xmlChar *pBuf = NULL;
+
+ // XML doc
+ doc = xmlNewDoc((const xmlChar*)"1.0");
+ // <SignedProperties>
+ pSigProp = doc->children = xmlNewDocNode(doc, NULL, (const xmlChar*)"SignedProperties", NULL);
+ // Ver 1.76 - in format 1.3 xmlns atribute is not used
+ // in ver 1.1 we need this namespace def
+ if(!strcmp(pSigDoc->szFormatVer, DIGIDOC_XML_1_1_VER) ||
+ !strcmp(pSigDoc->szFormatVer, DIGIDOC_XML_1_2_VER)) {
+ xmlNewNs(pSigProp, (const xmlChar*)NAMESPACE_XML_DSIG, NULL);
+ } else if(!strcmp(pSigDoc->szFormatVer, DIGIDOC_XML_1_3_VER)) { // in 1.3 we use the correct etsi namespace
+ xmlNewNs(pSigProp, (const xmlChar*)NAMESPACE_XADES_111, NULL);
+ }
+ // in 1.0 we had this buggy URI
+ if(!strcmp(pSigDoc->szFormat, SK_XML_1_NAME) && !strcmp(pSigDoc->szFormatVer, SK_XML_1_VER))
+ snprintf(buf1, sizeof(buf1), "#%s-SignedProperties", pSigInfo->szId);
+ else // current version is 1.1
+ snprintf(buf1, sizeof(buf1), "%s-SignedProperties", pSigInfo->szId);
+ xmlSetProp(pSigProp, (const xmlChar*)"Id", (const xmlChar*)buf1);
+
+ // Ver 1.76 - in format 1.3 Target atribute is not used
+ if(strcmp(pSigDoc->szFormatVer, DIGIDOC_XML_1_3_VER) ) {
+ snprintf(buf1, sizeof(buf1), "#%s", pSigInfo->szId);
+ xmlSetProp(pSigProp, (const xmlChar*)"Target", (const xmlChar*)buf1);
+ }
+ // <SignedSignatureProperties>
+ pSigSigProp = xmlNewChild(pSigProp, NULL, (const xmlChar*)"SignedSignatureProperties", nl);
+ // <SigningTime>
+ pN1 = xmlNewChild(pSigSigProp, NULL, (const xmlChar*)"SigningTime", (const xmlChar*)pSigInfo->szTimeStamp);
+ xmlNodeAddContent(pSigSigProp, nl);
+ // <SigningCertificate>
+ pSigCert = xmlNewChild(pSigSigProp, NULL, (const xmlChar*)"SigningCertificate", nl);
+ // <Cert>
+ pN1 = xmlNewChild(pSigCert, NULL, (const xmlChar*)"Cert", nl);
+ // Ver 1.76 - in format 1.3 Id atribute is not used
+ if(strcmp(pSigDoc->szFormatVer, DIGIDOC_XML_1_3_VER) ) {
+ // in 1.0 we had this buggy URI
+ if(!strcmp(pSigDoc->szFormat, SK_XML_1_NAME) && !strcmp(pSigDoc->szFormatVer, SK_XML_1_VER))
+ snprintf(buf1, sizeof(buf1), "#%s-CERTINFO", pSigInfo->szId);
+ else
+ snprintf(buf1, sizeof(buf1), "%s-CERTINFO", pSigInfo->szId);
+ xmlSetProp(pN1, (const xmlChar*)"Id", (const xmlChar*)buf1);
+ }
+ // <CertDigest>
+ pN2 = xmlNewChild(pN1, NULL, (const xmlChar*)"CertDigest", nl);
+ // <DigestMethod>
+ pN3 = xmlNewChild(pN2, NULL, (const xmlChar*)"DigestMethod", nl);
+
+ xmlNodeAddContent(pN2, nl);
+ xmlSetProp(pN3, (const xmlChar*)"Algorithm", (const xmlChar*)DIGEST_METHOD_SHA1);
+
+ // <DigestValue>
+ len1 = sizeof(buf1);
+ buf1[0] = 0;
+ pMBuf1 = ddocSigInfo_GetSignersCert_DigestValue(pSigInfo);
+ if(pMBuf1)
+ encode((const byte*)pMBuf1->pMem, pMBuf1->nLen, (byte*)buf1, &len1);
+ pN3 = xmlNewChild(pN2, NULL, (const xmlChar*)"DigestValue", (const xmlChar*)buf1);
+
+ xmlNodeAddContent(pN2, nl);
+ // <IssuerSerial>
+ xmlNodeAddContent(pN1, nl);
+ // In 1.3 we use subelements of <IssuerSerial>
+ if(!strcmp(pSigDoc->szFormatVer, DIGIDOC_XML_1_3_VER) ) {
+ pN2 = xmlNewChild(pN1, NULL, (const xmlChar*)"IssuerSerial", nl);
+ pN3 = xmlNewChild(pN2, NULL, (const xmlChar*)"X509IssuerName",
+ (const xmlChar*)ddocSigInfo_GetSignersCert_IssuerName((SignatureInfo*)pSigInfo));
+ xmlSetProp(pN3, (const xmlChar*)"xmlns", (const xmlChar*)NAMESPACE_XML_DSIG);
+ xmlNodeAddContent(pN2, nl);
+ pN3 = xmlNewChild(pN2, NULL, (const xmlChar*)"X509SerialNumber",
+ (const xmlChar*)ddocSigInfo_GetSignersCert_IssuerSerial((SignatureInfo*)pSigInfo));
+ xmlSetProp(pN3, (const xmlChar*)"xmlns", (const xmlChar*)NAMESPACE_XML_DSIG);
+ xmlNodeAddContent(pN2, nl);
+ } else {
+ pN2 = xmlNewChild(pN1, NULL, (const xmlChar*)"IssuerSerial",
+ (const xmlChar*)ddocSigInfo_GetSignersCert_IssuerSerial((SignatureInfo*)pSigInfo));
+ }
+ // <SignaturePolicyIdentifier>
+ if((!strcmp(pSigDoc->szFormatVer, SK_XML_1_VER) && !strcmp(pSigDoc->szFormat, SK_XML_1_NAME)) ||
+ !strcmp(pSigDoc->szFormatVer, DIGIDOC_XML_1_1_VER) ||
+ !strcmp(pSigDoc->szFormatVer, DIGIDOC_XML_1_2_VER) ||
+ !strcmp(pSigDoc->szFormatVer, DIGIDOC_XML_1_3_VER)) {
+ xmlNodeAddContent(pSigSigProp, nl);
+ pN1 = xmlNewChild(pSigSigProp, NULL, (const xmlChar*)"SignaturePolicyIdentifier", nl);
+ // <SignaturePolicyImplied>
+ pN2 = xmlNewChild(pN1, NULL, (const xmlChar*)"SignaturePolicyImplied", nl);
+ xmlNodeAddContent(pN1, nl);
+ }
+ // <SignatureProductionPlace>
+ if(pSigInfo->sigProdPlace.szCity || pSigInfo->sigProdPlace.szStateOrProvince ||
+ pSigInfo->sigProdPlace.szPostalCode || pSigInfo->sigProdPlace.szCountryName) {
+ xmlNodeAddContent(pSigSigProp, nl);
+ pN1 = xmlNewChild(pSigSigProp, NULL, (const xmlChar*)"SignatureProductionPlace", nl);
+ if(pSigInfo->sigProdPlace.szCity) {
+ if(bWithEscapes) {
+ escapeTextNode(pSigInfo->sigProdPlace.szCity, -1, &p2);
+ pN2 = xmlNewChild(pN1, NULL, (const xmlChar*)"City", (const xmlChar*)p2);
+ free(p2);
+ }
+ else
+ pN2 = xmlNewTextChild(pN1, NULL, (const xmlChar*)"City", (const xmlChar*)pSigInfo->sigProdPlace.szCity);
+ xmlNodeAddContent(pN1, nl);
+ }
+ if(pSigInfo->sigProdPlace.szStateOrProvince) {
+ if(bWithEscapes) {
+ escapeTextNode(pSigInfo->sigProdPlace.szStateOrProvince, -1, &p2);
+ pN2 = xmlNewChild(pN1, NULL, (const xmlChar*)"StateOrProvince", (const xmlChar*)p2);
+ free(p2);
+ }
+ else
+ pN2 = xmlNewTextChild(pN1, NULL, (const xmlChar*)"StateOrProvince", (const xmlChar*)pSigInfo->sigProdPlace.szStateOrProvince);
+ xmlNodeAddContent(pN1, nl);
+ }
+ if(pSigInfo->sigProdPlace.szPostalCode) {
+ if(bWithEscapes) {
+ escapeTextNode(pSigInfo->sigProdPlace.szPostalCode, -1, &p2);
+ pN2 = xmlNewChild(pN1, NULL, (const xmlChar*)"PostalCode", (const xmlChar*)p2);
+ free(p2);
+ }
+ else
+ pN2 = xmlNewTextChild(pN1, NULL, (const xmlChar*)"PostalCode", (const xmlChar*)pSigInfo->sigProdPlace.szPostalCode);
+ xmlNodeAddContent(pN1, nl);
+ }
+ if(pSigInfo->sigProdPlace.szCountryName) {
+ if(bWithEscapes) {
+ escapeTextNode(pSigInfo->sigProdPlace.szCountryName, -1, &p2);
+ pN2 = xmlNewChild(pN1, NULL, (const xmlChar*)"CountryName", (const xmlChar*)p2);
+ free(p2);
+ }
+ else
+ pN2 = xmlNewTextChild(pN1, NULL, (const xmlChar*)"CountryName", (const xmlChar*)pSigInfo->sigProdPlace.szCountryName);
+ xmlNodeAddContent(pN1, nl);
+ }
+ xmlNodeAddContent(pSigSigProp, nl);
+ }
+ // <SignerRole>
+ if(pSigInfo->signerRole.nClaimedRoles ||
+ pSigInfo->signerRole.nCertifiedRoles) {
+ pN1 = xmlNewChild(pSigSigProp, NULL, (const xmlChar*)"SignerRole", nl);
+ // <ClaimedRoles>
+ if(pSigInfo->signerRole.nClaimedRoles) {
+ pN2 = xmlNewChild(pN1, NULL, (const xmlChar*)"ClaimedRoles", nl);
+ for(i = 0; i < pSigInfo->signerRole.nClaimedRoles; i++) {
+ if(bWithEscapes) {
+ escapeTextNode(pSigInfo->signerRole.pClaimedRoles[i], -1, &p2);
+ ddocDebug(4, "createXMLSignedProperties", "role: %s --> %s", pSigInfo->signerRole.pClaimedRoles[i], p2);
+ pN3 = xmlNewChild(pN2, NULL, (const xmlChar*)"ClaimedRole", (const xmlChar*)p2);
+ free(p2);
+ } else
+ pN3 = xmlNewTextChild(pN2, NULL, (const xmlChar*)"ClaimedRole", (const xmlChar*)pSigInfo->signerRole.pClaimedRoles[i]);
+ xmlNodeAddContent(pN2, nl);
+ }
+ xmlNodeAddContent(pN1, nl);
+ }
+ // <CertifiedRoles>
+ if(pSigInfo->signerRole.nCertifiedRoles) {
+ pN2 = xmlNewChild(pN1, NULL, (const xmlChar*)"CertifiedRoles", nl);
+ for(i = 0; i < pSigInfo->signerRole.nClaimedRoles; i++) {
+ p2 = NULL;
+ escapeXMLSymbols(pSigInfo->signerRole.pCertifiedRoles[i], -1, &p2);
+ if(p2)
+ pN3 = xmlNewChild(pN2, NULL, (const xmlChar*)"CertifiedRole", (const xmlChar*)p2);
+ free(p2);
+ p2 = NULL;
+ xmlNodeAddContent(pN2, nl);
+ }
+ xmlNodeAddContent(pN1, nl);
+ }
+ xmlNodeAddContent(pSigSigProp, nl);
+ }
+ // <SignedDataObjectProperties>
+ xmlNodeAddContent(pSigProp, nl);
+ pN1 = xmlNewChild(pSigProp, NULL, (const xmlChar*)"SignedDataObjectProperties", nl);
+ xmlNodeAddContent(pSigProp, nl);
+ // convert to string
+ err = xmlC14NDocDumpMemory(doc, NULL, 0, NULL, 0, &pBuf);
+ if(pBuf) {
+ len1 = strlen((char*)pBuf);
+ pRet = malloc(len1+1);
+ if(pRet) {
+ strncpy(pRet, (char*)pBuf, len1);
+ pRet[len1] = 0;
+ }
+ xmlFree(pBuf);
+ }
+ xmlFreeDoc(doc);
+ // return <SignedProperties> node
+ return pRet;
+}
+
+
+//============================================================
+// Creates a <SignedInfo> XML block for a signature
+// This is the actual data to be signed
+// pSigInfo - signature info data
+// buf - output buffer
+// returns number of output bytes written
+//============================================================
+EXP_OPTION char* createXMLSignedInfo(const SignedDoc* pSigDoc, const SignatureInfo* pSigInfo)
+{
+ char buf1[300], *pRet = 0, *p1, *p2;
+ int i, err, l1;
+ xmlNodePtr pnSigInfo, pN1, pN2, pN3;
+ static xmlChar nl[] = "\n";
+ xmlDocPtr doc;
+ xmlChar* pBuf;
+ //FILE* hFile;
+ DataFile* pDF;
+ DigiDocMemBuf mbuf1;
+ //AM 13.02.09 ecdsa-sha1 support
+ EVP_PKEY* pubKey = NULL;
+
+ mbuf1.pMem = 0;
+ mbuf1.nLen = 0;
+ RETURN_OBJ_IF_NULL(pSigInfo, 0);
+ // XML doc
+ doc = xmlNewDoc((const xmlChar*)"1.0");
+ doc->children = xmlNewDocNode(doc, NULL, (const xmlChar*)"", NULL);
+ // <SignedInfo>
+ pnSigInfo = xmlNewChild(doc->children, NULL, (const xmlChar*)"SignedInfo", nl);
+ // in ver 1.1 we need this namespace def
+ xmlNewNs(pnSigInfo, (const xmlChar*)NAMESPACE_XML_DSIG, NULL);
+ // <CanonicalizationMethod>
+ pN1 = xmlNewChild(pnSigInfo, NULL, (const xmlChar*)"CanonicalizationMethod", nl);
+ xmlSetProp(pN1, (const xmlChar*)"Algorithm", (const xmlChar*)"http://www.w3.org/TR/2001/REC-xml-c14n-20010315");
+ xmlNodeAddContent(pnSigInfo, nl);
+ // <SignatureMethod>
+ pN1 = xmlNewChild(pnSigInfo, NULL, (const xmlChar*)"SignatureMethod", nl);
+ err = GetPublicKey(&pubKey, ddocSigInfo_GetSignersCert(pSigInfo));
+ if(pubKey) {
+#ifdef WITH_ECDSA
+ if(pubKey->type==NID_X9_62_id_ecPublicKey)
+ xmlSetProp(pN1, (const xmlChar*)"Algorithm", (const xmlChar*)"http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha1");
+ else
+#endif
+ xmlSetProp(pN1, (const xmlChar*)"Algorithm", (const xmlChar*)"http://www.w3.org/2000/09/xmldsig#rsa-sha1");
+ EVP_PKEY_free(pubKey);
+ }
+ xmlNodeAddContent(pnSigInfo, nl);
+ // <Reference>
+ for(i = 0; i < pSigInfo->nDocs; i++) {
+ // documents digest
+ pN1 = xmlNewChild(pnSigInfo, NULL, (const xmlChar*)"Reference", nl);
+ snprintf(buf1, sizeof(buf1), "#%s", pSigInfo->pDocs[i]->szDocId);
+ xmlSetProp(pN1, (const xmlChar*)"URI", (const xmlChar*)buf1);
+ pDF = getDataFileWithId(pSigDoc, pSigInfo->pDocs[i]->szDocId);
+ pN2 = xmlNewChild(pN1, NULL, (const xmlChar*)"DigestMethod", nl);
+ xmlSetProp(pN2, (const xmlChar*)"Algorithm", (const xmlChar*)"http://www.w3.org/2000/09/xmldsig#sha1");
+ xmlNodeAddContent(pN1, nl);
+ // in ver 1.0 we use Transforms
+ if(!strcmp(pSigDoc->szFormat, SK_XML_1_NAME) && !strcmp(pSigDoc->szFormatVer, SK_XML_1_VER)) {
+ pN2 = xmlNewChild(pN1, NULL, (const xmlChar*)"Transforms", NULL);
+ pN3 = xmlNewChild(pN2, NULL, (const xmlChar*)"Transform", NULL);
+ xmlSetProp(pN3, (const xmlChar*)"Algorithm", (const xmlChar*)"http://www.w3.org/2000/09/xmldsig#enveloped-signature");
+ xmlNodeAddContent(pN1, nl);
+ }
+ l1 = sizeof(buf1);
+ encode(pSigInfo->pDocs[i]->szDigest,
+ pSigInfo->pDocs[i]->nDigestLen, (byte*)buf1, &l1);
+ pN2 = xmlNewChild(pN1, NULL, (const xmlChar*)"DigestValue", (const xmlChar*)buf1);
+ xmlNodeAddContent(pN1, nl);
+ xmlNodeAddContent(pnSigInfo, nl);
+ // in ver 1.1 we don't use mime digest Reference blocks
+ //AM 29.08.10
+ if(!strcmp(pSigDoc->szFormatVer, SK_XML_1_VER) && !strcmp(pSigDoc->szFormat, SK_XML_1_NAME)) {
+ // document mime type digest
+ pN1 = xmlNewChild(pnSigInfo, NULL, (const xmlChar*)"Reference", nl);
+ if(!strcmp(pSigDoc->szFormatVer, "1.0"))
+ snprintf(buf1, sizeof(buf1), "#%s-MIME", pSigInfo->pDocs[i]->szDocId);
+ else // current version is 1.1
+ snprintf(buf1, sizeof(buf1), "#%s@MimeType", pSigInfo->pDocs[i]->szDocId);
+ xmlSetProp(pN1, (const xmlChar*)"URI", (const xmlChar*)buf1);
+ pN2 = xmlNewChild(pN1, NULL, (const xmlChar*)"DigestMethod", nl);
+ xmlSetProp(pN2, (const xmlChar*)"Algorithm", (const xmlChar*)DIGEST_METHOD_SHA1);
+ xmlNodeAddContent(pN1, nl);
+ pN2 = xmlNewChild(pN1, NULL, (const xmlChar*)"Transforms", NULL);
+ pN3 = xmlNewChild(pN2, NULL, (const xmlChar*)"Transform", NULL);
+ xmlSetProp(pN3, (const xmlChar*)"Algorithm", (const xmlChar*)"http://www.w3.org/2000/09/xmldsig#enveloped-signature");
+ xmlNodeAddContent(pN1, nl);
+ l1 = sizeof(buf1);
+ encode(pSigInfo->pDocs[i]->szMimeDigest,
+ pSigInfo->pDocs[i]->nMimeDigestLen, (byte*)buf1, &l1);
+ pN2 = xmlNewChild(pN1, NULL, (const xmlChar*)"DigestValue", (const xmlChar*)buf1);
+ xmlNodeAddContent(pN1, nl);
+ }
+ }
+ // signed properties digest
+ pN1 = xmlNewChild(pnSigInfo, NULL, (const xmlChar*)"Reference", nl);
+ snprintf(buf1, sizeof(buf1), "#%s-SignedProperties", pSigInfo->szId);
+ xmlSetProp(pN1, (const xmlChar*)"URI", (const xmlChar*)buf1);
+ // in version 1.2 we ise the Type atribute
+ // for References that contain <SignedProperties> digest
+ if(!strcmp(pSigDoc->szFormatVer, DIGIDOC_XML_1_2_VER) ||
+ !strcmp(pSigDoc->szFormatVer, DIGIDOC_XML_1_3_VER)) {
+ xmlSetProp(pN1, (const xmlChar*)"Type", (const xmlChar*)"http://uri.etsi.org/01903/v1.1.1#SignedProperties");
+ }
+ pN2 = xmlNewChild(pN1, NULL, (const xmlChar*)"DigestMethod", nl);
+ xmlSetProp(pN2, (const xmlChar*)"Algorithm", (const xmlChar*)DIGEST_METHOD_SHA1);
+ xmlNodeAddContent(pN1, nl);
+ // in 1.0 we used transforms here
+ if(!strcmp(pSigDoc->szFormat, SK_XML_1_NAME) && !strcmp(pSigDoc->szFormatVer, SK_XML_1_VER)) {
+ pN2 = xmlNewChild(pN1, NULL, (const xmlChar*)"Transforms", NULL);
+ pN3 = xmlNewChild(pN2, NULL, (const xmlChar*)"Transform", NULL);
+ xmlSetProp(pN3, (const xmlChar*)"Algorithm", (const xmlChar*)"http://www.w3.org/2000/09/xmldsig#enveloped-signature");
+ xmlNodeAddContent(pN1, nl);
+ }
+ ddocEncodeBase64(ddocDigestValue_GetDigestValue(pSigInfo->pSigPropDigest), &mbuf1);
+ pN2 = xmlNewChild(pN1, NULL, (const xmlChar*)"DigestValue", (const xmlChar*)mbuf1.pMem);
+ ddocMemBuf_free(&mbuf1);
+ xmlNodeAddContent(pN1, nl);
+ xmlNodeAddContent(pnSigInfo, nl);
+ // convert to string
+ pBuf = NULL;
+ err = xmlC14NDocDumpMemory(doc, NULL, 0, NULL, 0, &pBuf);
+ p1 = strstr((const char*)pBuf, "<SignedInfo");
+ l1 = strlen(p1);
+ if(p1) {
+ p2 = strstr((const char*)pBuf, "</SignedInfo>");
+ if(p2) {
+ p2[strlen("</SignedInfo>")] = 0;
+ pRet = malloc(l1);
+ if(pRet) {
+ memset(pRet, 0, l1);
+ strncpy(pRet, p1, strlen(p1));
+ //pRet = strdup(p1);
+ }
+ }
+ }
+ xmlFree(pBuf);
+ xmlFreeDoc(doc);
+ return pRet;
+}
+
+//============================================================
+// Calculates the digest of OCSP_RESPONSE
+// pResp - OCSP_RESPONSE data
+// digBuf - signature buffer
+// digLen - signature buffer length
+// returns error code
+//============================================================
+int calculateOcspBasicResponseDigest(OCSP_BASICRESP* pBsResp, byte* digBuf, int* digLen)
+{
+ int err = ERR_OK, l1;
+ byte *buf, *p;
+
+ RETURN_IF_NULL_PARAM(pBsResp);
+ l1 = i2d_OCSP_BASICRESP(pBsResp, NULL);
+ buf = (byte*)malloc(l1+10);
+ RETURN_IF_BAD_ALLOC(buf);
+ p = buf;
+ i2d_OCSP_BASICRESP(pBsResp, &p);
+ err = calculateDigest(buf, l1, DIGEST_SHA1, digBuf, digLen);
+ free(buf);
+ if (err != ERR_OK) SET_LAST_ERROR(err);
+ return err;
+}
+
+//============================================================
+// Writes OCSP_RESPONSE to file without the usual PEM headers
+// bout - output file
+// pResp - OCSP_RESPONSE
+// returns error code
+//============================================================
+/*int writeOcspToXMLFile(DigiDocMemBuf* pBuf, OCSP_RESPONSE* pResp)
+{
+ int l1, l2;
+ char *p1, *p2;
+
+ RETURN_IF_NULL_PARAM(pBuf);
+ RETURN_IF_NULL_PARAM(pResp);
+ l1 = i2d_OCSP_RESPONSE(pResp, NULL);
+ p1 = (char*)malloc(l1+10);
+ RETURN_IF_BAD_ALLOC(p1);
+ p2 = p1;
+ i2d_OCSP_RESPONSE(pResp, (unsigned char**)&p2);
+ l2 = l1 * 2;
+ p2 = (char*)malloc(l2);
+ if(p2 == NULL) {
+ free(p1);
+ RETURN_IF_BAD_ALLOC(p2);
+ }
+ encode((const byte*)p1, l1, (byte*)p2, &l2);
+ ddocMemAppendData(pBuf, p2, -1);
+ free(p2);
+ free(p1);
+ return ERR_OK;
+}*/
+
+
+//============================================================
+// Adds a notary signature to signed document buffer
+// pMBufXML - output buffer
+// pSigDoc - signed doc pointer
+// pNotInfo - notary signature info
+// returns error code
+//============================================================
+int addNotaryInfoXML(DigiDocMemBuf *pMBufXML, const SignedDoc *pSigDoc, const SignatureInfo* pSigInfo, const NotaryInfo* pNotInfo)
+{
+ int err = ERR_OK, i;
+ DigiDocMemBuf mbuf1;
+ const DigiDocMemBuf *pMBuf;
+ CertValue *pCertValue = 0;
+
+ RETURN_IF_NULL_PARAM(pSigInfo);
+ RETURN_IF_NULL_PARAM(pNotInfo);
+ RETURN_IF_NULL_PARAM(pMBufXML);
+ mbuf1.pMem = 0;
+ mbuf1.nLen = 0;
+ // unsigned prop begin
+ // Ver 1.76 - in format 1.3 we don't use the Target atribute
+ if(!strcmp(pSigDoc->szFormatVer, DIGIDOC_XML_1_3_VER)) {
+ ddocMemAppendData(pMBufXML,"<UnsignedProperties>\n<UnsignedSignatureProperties>", -1);
+ } else {
+ ddocMemAppendData(pMBufXML,"<UnsignedProperties Target=\"", -1);
+ ddocMemAppendData(pMBufXML,pSigInfo->szId, -1);
+ ddocMemAppendData(pMBufXML,"\">\n<UnsignedSignatureProperties>", -1);
+ }
+ // <CompleteCertificateRefs>
+ err = ddocCompleteCertificateRefs_toXML((SignedDoc*)pSigDoc, (SignatureInfo*)pSigInfo, &mbuf1);
+ ddocMemAppendData(pMBufXML,(const char*)mbuf1.pMem, -1);
+ ddocMemBuf_free(&mbuf1);
+ // <CompleteRevocationRefs>
+ err = ddocCompleteRevocationRefs_toXML((SignedDoc*)pSigDoc, (SignatureInfo*)pSigInfo, &mbuf1);
+ ddocMemAppendData(pMBufXML,(const char*)mbuf1.pMem, -1);
+ ddocMemBuf_free(&mbuf1);
+
+ // responder cert
+ ddocMemAppendData(pMBufXML,"<CertificateValues>\n", -1);
+ // TODO format cert without header
+ for(i = 0; i < ddocCertValueList_GetCertValuesCount(pSigInfo->pCertValues); i++) {
+ pCertValue = ddocCertValueList_GetCertValue(pSigInfo->pCertValues, i);
+ if(pCertValue && pCertValue->nType != CERTID_VALUE_SIGNERS_CERT) {
+ ddocDebug(3, "addNotaryInfoXML", "Write CertVal-type: %d cert: %s", pCertValue->nType, (pCertValue->pCert ? "OK" : "NULL"));
+ ddocCertValue_toXML(pCertValue, &mbuf1);
+ ddocMemAppendData(pMBufXML, (const char*)mbuf1.pMem, -1);
+ ddocMemAppendData(pMBufXML, "\n", -1);
+ ddocMemBuf_free(&mbuf1);
+ }
+ }
+ ddocMemAppendData(pMBufXML, "</CertificateValues>\n", -1);
+ // revocation values
+ ddocMemAppendData(pMBufXML, "<RevocationValues>", -1);
+ // Ver 1.76 - in format 1.3 we use here additionally element <OCSPValues>
+ if(!strcmp(pSigDoc->szFormatVer, DIGIDOC_XML_1_3_VER))
+ ddocMemAppendData(pMBufXML, "<OCSPValues>", -1);
+ // OCSP response
+ ddocMemAppendData(pMBufXML, "<EncapsulatedOCSPValue Id=\"", -1);
+ ddocMemAppendData(pMBufXML, pNotInfo->szId, -1);
+ ddocMemAppendData(pMBufXML, "\">\n", -1);
+ pMBuf = ddocNotInfo_GetOCSPResponse(pNotInfo);
+ RETURN_IF_NULL(pMBuf);
+ // fix for backward compatibility with 2.1.5
+ // remove trailing \n after base64 content
+ if(mbuf1.pMem && ((char*)mbuf1.pMem)[strlen((const char*)mbuf1.pMem)-1] == '\n')
+ ((char*)mbuf1.pMem)[strlen((const char*)mbuf1.pMem)-1] = 0;
+ ddocEncodeBase64(pMBuf, &mbuf1);
+ ddocMemAppendData(pMBufXML, (const char*)mbuf1.pMem, -1);
+ ddocMemBuf_free(&mbuf1);
+ ddocMemAppendData(pMBufXML, "</EncapsulatedOCSPValue>\n", -1);
+ // Ver 1.76 - in format 1.3 we use here additionally element <OCSPValues>
+ if(!strcmp(pSigDoc->szFormatVer, DIGIDOC_XML_1_3_VER))
+ ddocMemAppendData(pMBufXML,"</OCSPValues>", -1);
+ ddocMemAppendData(pMBufXML,"</RevocationValues>", -1);
+ // unsigned prop end
+ ddocMemAppendData(pMBufXML, "</UnsignedSignatureProperties>\n</UnsignedProperties>", -1);
+ if (err != ERR_OK) SET_LAST_ERROR(err);
+ return err;
+}
+
+//============================================================
+// Swaps bytes in this byte array. Length must be an even number
+// used for big-endian <--> small-endian conversion
+//============================================================
+void swapBytes(byte* src, int len)
+{
+ byte b;
+ int i;
+
+ if(len % 2 == 0) {
+ for(i = 0; i < (len / 2); i++) {
+ b = src[i];
+ src[i] = src[len - i - 1];
+ src[len - i - 1] = b;
+ }
+ }
+}
+
+
+//============================================================
+// Adds a signature to signed document file
+// hFile - output file
+// pSigInfo - signature info
+// cert - signers certificate
+// returns error code
+//============================================================
+int addSignatureInfoXML(DigiDocMemBuf *pMBufXML, SignedDoc* pSigDoc, SignatureInfo* pSigInfo)
+{
+ int err = ERR_OK;
+ unsigned char buf2[500], *buf1 = 0;
+ int len2, len1;
+ EVP_PKEY* pubKey = NULL;
+ SignatureValue *pSigVal;
+ DigiDocMemBuf mbuf1;
+
+ RETURN_IF_NULL_PARAM(pMBufXML);
+ RETURN_IF_NULL_PARAM(pSigDoc);
+ RETURN_IF_NULL_PARAM(pSigInfo);
+ mbuf1.pMem = 0;
+ mbuf1.nLen = 0;
+ //TODO: xmlns = http://uri.etsi.org/01903/v1.3.2#
+ ddocMemAppendData(pMBufXML,"<Signature Id=\"", -1);
+ ddocMemAppendData(pMBufXML,pSigInfo->szId, -1);
+ ddocMemAppendData(pMBufXML,"\" xmlns=\"http://www.w3.org/2000/09/xmldsig#\">\n", -1);
+ buf1 = (unsigned char*)createXMLSignedInfo(pSigDoc, pSigInfo);
+ RETURN_IF_NULL(buf1);
+ ddocMemAppendData(pMBufXML,(const char*)buf1, -1);
+ free(buf1);
+ buf1 = 0; // mark free
+ len1 = 1024;
+ buf1 = (unsigned char*)malloc(len1);
+ RETURN_IF_BAD_ALLOC(buf1);
+ memset(buf1, 0, len1);
+ // <SignatureValue>
+ pSigVal = ddocSigInfo_GetSignatureValue(pSigInfo);
+ //RETURN_IF_NULL(pSigVal);
+ ddocSignatureValue_toXML(pSigVal, &mbuf1);
+ ddocMemAppendData(pMBufXML,(const char*)mbuf1.pMem, -1);
+ ddocMemBuf_free(&mbuf1);
+ // cert data...
+ if(!strcmp(pSigDoc->szFormat, SK_XML_1_NAME) && !strcmp(pSigDoc->szFormatVer, SK_XML_1_VER)) {
+ ddocMemAppendData(pMBufXML,"<KeyInfo><X509Data><X509Certificate Id=\"", -1);
+ ddocMemAppendData(pMBufXML,pSigInfo->szId, -1);
+ ddocMemAppendData(pMBufXML,"-CERT\">\n", -1);
+ } else {
+ // RSA KEY value
+ ddocMemAppendData(pMBufXML,"<KeyInfo>\n", -1);
+ err = GetPublicKey(&pubKey, ddocSigInfo_GetSignersCert(pSigInfo));
+ // FIXME
+ // modulus
+ //AM 11.02.09
+ if(!err && pubKey->type==NID_rsaEncryption) {
+ ddocMemAppendData(pMBufXML,"<KeyValue>\n<RSAKeyValue>\n", -1);
+ len1 = BN_bn2bin(pubKey->pkey.rsa->n, buf1);
+ // in version 1.1 we output modulus as it is
+ // starting from 1.2 we convert it to big-endian
+ /*len2 = sizeof(buf2);
+ memset(buf2, 0, len2);
+ encode(buf1, len1, buf2, &len2);
+ printf("Old modulus: %s\n", buf2);
+ if(!strcmp(pSigDoc->szFormatVer, DIGIDOC_XML_1_1_VER)) {
+ swapBytes((byte*)buf1, len1);
+ }*/
+ len2 = sizeof(buf2);
+ memset(buf2, 0, len2);
+ encode(buf1, len1, buf2, &len2);
+ //printf("New modulus: %s len: %d\n", buf2, len1);
+ ddocMemAppendData(pMBufXML, "<Modulus>", -1);
+ ddocMemAppendData(pMBufXML, (char*)buf2, -1);
+ ddocMemAppendData(pMBufXML,"</Modulus>\n", -1);
+ // exponent
+ memset(buf1, 0, len1);
+ len1 = BN_bn2bin(pubKey->pkey.rsa->e, buf1);
+ len2 = sizeof(buf2);
+ memset(buf2, 0, len2);
+ encode(buf1, len1, buf2, &len2);
+ ddocMemAppendData(pMBufXML,"<Exponent>", -1);
+ ddocMemAppendData(pMBufXML, (char*)buf2, -1);
+ ddocMemAppendData(pMBufXML,"</Exponent>\n", -1);
+ ddocMemAppendData(pMBufXML,"</RSAKeyValue>\n</KeyValue>\n", -1);
+ }
+ // cert data
+ ddocMemAppendData(pMBufXML,"<X509Data><X509Certificate>\n", -1);
+ }
+ free(buf1);
+ buf1 = 0; // mark freed
+ RETURN_IF_NOT(err == ERR_OK, err); // check sig-value encode errors
+ err = getCertPEM(ddocSigInfo_GetSignersCert(pSigInfo), 0, (char**)&buf1);
+ RETURN_IF_NULL(buf1);
+ ddocMemAppendData(pMBufXML, (char*)buf1, -1);
+ free(buf1);
+ ddocMemAppendData(pMBufXML,"</X509Certificate></X509Data></KeyInfo>\n", -1);
+ // VS in releases prior to 1.76 we had incorrect <QualifyingProperties> atributes
+ if(!strcmp(pSigDoc->szFormatVer, DIGIDOC_XML_1_3_VER)) {
+ ddocMemAppendData(pMBufXML,"<Object><QualifyingProperties xmlns=\"http://uri.etsi.org/01903/v1.1.1#\" Target=\"#", -1);
+ ddocMemAppendData(pMBufXML,pSigInfo->szId, -1);
+ ddocMemAppendData(pMBufXML,"\">\n", -1);
+ } else {
+ ddocMemAppendData(pMBufXML,"<Object><QualifyingProperties>\n", -1);
+ }
+ EVP_PKEY_free(pubKey);
+ // signed properties
+ buf1 = (unsigned char*)createXMLSignedProperties(pSigDoc, pSigInfo, 1);
+ RETURN_IF_NULL(buf1);
+ ddocMemAppendData(pMBufXML,(const char*)buf1, -1);
+ free(buf1);
+ // unsigned properties
+ if(pSigInfo->pNotary)
+ addNotaryInfoXML(pMBufXML, pSigDoc, pSigInfo, pSigInfo->pNotary);
+ // qualifying properties end
+ ddocMemAppendData(pMBufXML,"</QualifyingProperties></Object>\n", -1);
+ // signature end
+ ddocMemAppendData(pMBufXML,"</Signature>\n", -1);
+ if (err != ERR_OK) SET_LAST_ERROR(err);
+ ddocMemBuf_free(&mbuf1);
+ return err;
+}
+
+
+//============================================================
+// Canonicalizes PCDATA text value. Simple caninicalization
+// only that replaces "\n\r" with "\n", by removing the "\r"
+// and shifting the data left. Modification is done in place.
+// src - input data. will be modified
+// return error code or ERR_OK
+//============================================================
+int ddocCanonicalizePCDATA(char * src)
+{
+ int i, j;
+
+ RETURN_IF_NULL_PARAM(src);
+ for(i = j = 0; src[j]; ) {
+ if(src[j] == '\r') {
+ j++;
+ } else {
+ if(i != j)
+ src[i] = src[j];
+ i++;
+ j++;
+ }
+ }
+ src[i] = 0;
+ return ERR_OK;
+}
+
+//============================================================
+// Generates DataFile elements XML form and stores it in a file
+// pSigDoc - signed document
+// pDataFile - data file object to be converted
+// szDataFile - input file name
+// hFile - output file handle
+// pMBufDigest - pointer to buffer for digest if we only want the digest
+// pMBufXML - output buffer if we want data to be returned in mem buf
+//============================================================
+EXP_OPTION int generateDataFileXML(SignedDoc* pSigDoc, DataFile* pDataFile,
+ const char* szDataFile, FILE* hFile, DigiDocMemBuf* pMBufXML)
+{
+ int err = ERR_OK, len1, len2, j, k;
+ char buf1[2050], buf2[5000], fixedFileName[1024], *p = 0;
+ char *name, *value, *fName;
+ FILE *fIn = 0;
+ EVP_ENCODE_CTX ectx;
+ SHA_CTX sctx;
+ DigiDocMemBuf mbuf1, mbuf2, mbuf3;
+#ifdef WIN32
+ wchar_t *convFileName = 0;
+#endif
+
+ RETURN_IF_NULL_PARAM(pSigDoc);
+ RETURN_IF_NULL_PARAM(pDataFile);
+ //RETURN_IF_NULL_PARAM(szDataFile);
+
+ mbuf1.pMem = 0;
+ mbuf1.nLen = 0;
+ mbuf2.pMem = 0;
+ mbuf2.nLen = 0;
+ len1 = sizeof(buf1);
+ ddocDebug(3, "generateDataFileXML", "DF: %s in-df-file: %s out-file: %s mbuf: %s", pDataFile->szId, szDataFile, (hFile ? "Y" : "N"), (pMBufXML ? "Y" : "N"));
+ // replaces '&' with '&amp;'
+ memset(fixedFileName, 0, sizeof(fixedFileName));
+ fName = (char*)getSimpleFileName(pDataFile->szFileName);
+ escapeXMLSymbols(fName, -1, &p);
+ if(p)
+ strncpy(fixedFileName, p, sizeof(fixedFileName));
+ free(p); p = 0;
+ //in versions 1.0, 1.1 and 1.2 we used bad encoding
+ if((!strcmp(pSigDoc->szFormatVer, SK_XML_1_VER) && !strcmp(pSigDoc->szFormat, SK_XML_1_NAME)) ||
+ !strcmp(pSigDoc->szFormatVer, DIGIDOC_XML_1_1_VER) ||
+ !strcmp(pSigDoc->szFormatVer, DIGIDOC_XML_1_2_VER)) {
+#ifdef WIN32
+ utf82oem(fixedFileName, buf1, sizeof(buf1));
+ len2 = sizeof(buf2);
+ ascii2utf8(buf1, buf2, &len2);
+#else
+ convFNameToWin(fixedFileName, buf2, sizeof(buf2));
+#endif
+ strncpy(fixedFileName, buf2, sizeof(fixedFileName));
+ }
+ // in version 1.0 we use DigestType and DigestValue attributes, PR. - size fix
+ ddocMemSetLength(&mbuf2, 1024);
+ if((!strcmp(pSigDoc->szFormat, SK_XML_1_NAME) && !strcmp(pSigDoc->szFormatVer, SK_XML_1_VER))) {
+ ddocEncodeBase64(ddocDataFile_GetDigestValue(pDataFile), &mbuf1);
+ //AM 17.11.08 moved these 2 lines after ddocEncodeBase64
+ if(mbuf1.pMem && ((char*)mbuf1.pMem)[strlen((const char*)mbuf1.pMem)-1] == '\n')
+ ((char*)mbuf1.pMem)[strlen((const char*)mbuf1.pMem)-1] = 0;
+ snprintf((char*)mbuf2.pMem, mbuf2.nLen,
+ "<DataFile ContentType=\"%s\" Filename=\"%s\" Id=\"%s\" MimeType=\"%s\" Size=\"%ld\" DigestType=\"%s\" DigestValue=\"%s\"",
+ pDataFile->szContentType,
+ fixedFileName, pDataFile->szId, pDataFile->szMimeType,
+ pDataFile->nSize, pDataFile->szDigestType, (char*)mbuf1.pMem);
+ ddocMemBuf_free(&mbuf1);
+ } else {
+ snprintf((char*)mbuf2.pMem, mbuf2.nLen, "<DataFile ContentType=\"%s\" Filename=\"%s\" Id=\"%s\" MimeType=\"%s\" Size=\"%ld\"",
+ pDataFile->szContentType,
+ fixedFileName, pDataFile->szId, pDataFile->szMimeType, pDataFile->nSize);
+ }
+ mbuf2.nLen = strlen((const char*)mbuf2.pMem);
+ k = getCountOfDataFileAttributes(pDataFile);
+ for(j = 0; j < k; j++) {
+ getDataFileAttribute(pDataFile, j, &name, &value);
+ escapeXMLSymbols(value, -1, &p);
+ ddocMemAppendData(&mbuf2, " ", -1);
+ ddocMemAppendData(&mbuf2, name, -1);
+ ddocMemAppendData(&mbuf2, "=\"", -1);
+ if(p)
+ ddocMemAppendData(&mbuf2, p, -1);
+ ddocMemAppendData(&mbuf2, "\"", -1);
+ free(p);
+ p = NULL;
+ }
+ // VS - ver 1.80 - in format 1.3 we started using SignedDoc schema
+ if(!strcmp(pSigDoc->szFormatVer, DIGIDOC_XML_1_3_VER))
+ ddocMemAppendData(&mbuf2, " xmlns=\"http://www.sk.ee/DigiDoc/v1.3.0#\"", -1);
+ ddocMemAppendData(&mbuf2, ">", -1); // end of generating <DataFile> header
+ // if DataFile content is already in memory then convert to base64 and use it
+ if(pDataFile->mbufContent.pMem && pDataFile->mbufContent.nLen && pMBufXML) {
+ if(!strcmp(pDataFile->szContentType, CONTENT_EMBEDDED) ||
+ !strcmp(pDataFile->szContentType, CONTENT_EMBEDDED_BASE64)) { //allready in base64
+ ddocMemAppendData(&mbuf2, pDataFile->mbufContent.pMem, pDataFile->mbufContent.nLen);
+ }
+ ddocMemAppendData(&mbuf2, "</DataFile>", -1);
+ p = canonicalizeXML((char*)mbuf2.pMem, mbuf2.nLen);
+ RETURN_IF_NULL(p);
+ ddocDebug(3, "generateDataFileXML", "canonicalized df: \'%s\'", p);
+ //ddocDebugWriteFile(3, "df-data0.txt", &mbuf2);
+ SHA1_Init(&sctx);
+ SHA1_Update(&sctx, (const char*)p, strlen(p));
+ free(p); p = 0;
+ len2 = sizeof(buf2);
+ SHA1_Final((unsigned char*)buf2, &sctx);
+ ddocDataFile_SetDigestValue(pDataFile, buf2, DIGEST_LEN);
+ if(pMBufXML)
+ ddocMemAppendData(pMBufXML, mbuf2.pMem, mbuf2.nLen);
+ if(hFile)
+ fwrite(mbuf2.pMem, sizeof(char), mbuf2.nLen, hFile);
+
+ ddocMemBuf_free(&mbuf2);
+ len1 = sizeof(buf1);
+ bin2hex(pDataFile->mbufDigest.pMem, pDataFile->mbufDigest.nLen, buf1, &len1);
+ ddocDebug(3, "generateDataFileXML", "DataFile: %s calc-digest: %s", pDataFile->szId, buf1);
+ len1 = sizeof(buf1);
+ encode((const byte*)pDataFile->mbufDigest.pMem, pDataFile->mbufDigest.nLen, (byte*)buf1, &len1);
+ ddocDebug(3, "generateDataFileXML", "DataFile: %s calc-digest: %s", pDataFile->szId, buf1);
+
+ return err;
+ }
+
+ if(hFile)
+ fputs((const char*)mbuf2.pMem, hFile);
+#ifdef WITH_BASE64_HASHING_HACK
+ SHA1_Init(&sctx);
+ if(!strcmp(pDataFile->szContentType, CONTENT_EMBEDDED_BASE64) &&
+ strcmp(pSigDoc->szFormat, SK_XML_1_NAME)) { // in ddoc 1.0 we calculate hash over original data
+ ddocMemAppendData(&mbuf2, "</DataFile>", -1);
+ p = canonicalizeXML((char*)mbuf2.pMem, mbuf2.nLen);
+ RETURN_IF_NULL(p);
+ p[strlen(p)-11] = 0;
+ ddocDebug(4, "generateDataFileXML", "sha1 initial update: \'%s\'", p);
+ mbuf3.pMem = p;
+ mbuf3.nLen = strlen(p);
+ ddocDebugWriteFile(4, "df-data0.txt", &mbuf3);
+ SHA1_Update(&sctx, (const char*)p, strlen(p));
+ free(p); p = 0;
+ }
+#endif
+// in base64 hashing hack mode we don't keep DF content constantly in memory
+#ifdef WITH_BASE64_HASHING_HACK
+ if(!strcmp(pDataFile->szContentType, CONTENT_EMBEDDED_BASE64))
+ ddocMemBuf_free(&mbuf2);
+#endif
+
+ //err = ddocConvertFileName(fixedFileName, sizeof(fixedFileName), pDataFile->szFileName);
+ //if(err) return err;
+ strncpy(fixedFileName, pDataFile->szFileName, sizeof(fixedFileName));
+ // if this is our temp file not a real input file
+ // then don't change anything in it.
+ if(strcmp(pDataFile->szFileName, szDataFile) != 0) {
+#ifdef WIN32
+ len2 = 0;
+ err = utf82unicode((const char*)szDataFile, (char**)&convFileName, &len2);
+ fIn = _wfopen(convFileName, L"rb");
+ ddocDebug(3, "generateDataFileXML", "Opening FILE1: %s, conv-file: %s len: %d, RC: %d", szDataFile, convFileName, len2, (fIn != NULL));
+ free(convFileName); // now I don't need it any more
+ if(fIn != NULL) {
+#else
+ if((fIn = fopen(szDataFile, "rb")) != NULL) {
+#endif
+ ddocDebug(4, "generateDataFileXML", "Opened FILE01: %s", szDataFile);
+ if(!strcmp(pSigDoc->szFormat, SK_XML_1_NAME))
+ EVP_DecodeInit(&ectx);
+ while((len1 = fread(buf1, 1, sizeof(buf1)-2, fIn)) > 0) {
+#ifdef WITH_BASE64_HASHING_HACK
+ if(!strcmp(pDataFile->szContentType, CONTENT_EMBEDDED_BASE64)) {
+ buf1[len1] = 0;
+#ifdef WIN32 // must remove \r that was generated during data file extact
+ if(strcmp(pSigDoc->szFormat, SK_XML_1_NAME)) {
+ ddocCanonicalizePCDATA(buf1);
+ len1 = strlen(buf1);
+ }
+#endif
+ if(strcmp(pSigDoc->szFormat, SK_XML_1_NAME)) {
+ ddocDebug(4, "generateDataFileXML", "sha1 update: \'%s\'", buf1);
+ SHA1_Update(&sctx, (const char*)buf1, len1);
+ mbuf3.pMem = buf1;
+ mbuf3.nLen = len1;
+ ddocDebugWriteFile(4, "df-data0.txt", &mbuf3);
+ } else { // in ddoc 1.0 we calculate hash over original data
+ p = buf1;
+ while(*p == ' ' || *p == '\n' || *p == '\r') p++;
+ ddocDebug(4, "generateDataFileXML", "decode: %s", p);
+ len2 = sizeof(buf2);
+ EVP_DecodeUpdate(&ectx, (unsigned char*)buf2, &len2, (unsigned char*)p, strlen(p));
+ ddocDebug(4, "generateDataFileXML", "sha1 update orig: %d: dec: %d", len1, len2);
+ SHA1_Update(&sctx, (const char*)buf2, len2);
+ //ddocDebugWriteFile(4, "df-data0.txt", &mbuf3);
+ }
+ } else {
+#endif
+ ddocMemAppendData(&mbuf2, buf1, len1);
+#ifdef WITH_BASE64_HASHING_HACK
+ }
+#endif
+
+ if(hFile)
+ fwrite(buf1, sizeof(char), len1, hFile);
+ }
+ fclose(fIn);
+ ddocDebug(4, "generateDataFileXML", "Closed FILE01: %s", szDataFile);
+ fIn = 0;
+ if(!strcmp(pSigDoc->szFormat, SK_XML_1_NAME)) {
+ len2 = sizeof(buf2);
+ EVP_DecodeFinal(&ectx, (unsigned char*)buf2, &len2);
+ SHA1_Update(&sctx, (const char*)buf2, len2);
+ ddocDebug(4, "generateDataFileXML", "sha1 final dec: %d", len1, len2);
+ len2 = sizeof(buf2);
+ SHA1_Final((unsigned char*)buf2, &sctx);
+ ddocDataFile_SetDigestValue(pDataFile, buf2, DIGEST_LEN);
+ len1 = sizeof(buf1);
+ bin2hex(pDataFile->mbufDigest.pMem, pDataFile->mbufDigest.nLen, buf1, &len1);
+ ddocDebug(3, "generateDataFileXML", "DataFile: %s calc-digest: %s", pDataFile->szId, buf1);
+ }
+ }
+ } else {
+ // if the file must be embedded
+ if(!strcmp(pDataFile->szContentType, CONTENT_EMBEDDED_BASE64) ||
+ !strcmp(pDataFile->szContentType, CONTENT_EMBEDDED)) {
+#ifdef WIN32
+ len2 = 0;
+ err = utf82unicode((const char*)fixedFileName, (char**)&convFileName, &len2);
+ fIn = _wfopen(convFileName, L"rb");
+ ddocDebug(3, "generateDataFileXML", "Opening FILE2: %s, conv-file: %s len: %d, RC: %d", fixedFileName, convFileName, len2, (fIn != NULL));
+ free(convFileName); // now I don't need it any more
+ if(fIn != NULL) {
+#else
+ if((fIn = fopen(fixedFileName, "rb")) != NULL) {
+#endif
+ ddocDebug(4, "generateDataFileXML", "Opened FILE2: %s", fixedFileName);
+ // if encoded
+ if(!strcmp(pDataFile->szContentType, CONTENT_EMBEDDED_BASE64)) {
+ EVP_EncodeInit(&ectx);
+ while((len1 = fread(buf1, 1, sizeof(buf1), fIn)) > 0) {
+ len2 = sizeof(buf2);
+ EVP_EncodeUpdate(&ectx, (unsigned char*)buf2, &len2, (unsigned char*)buf1, len1);
+ buf2[len2] = 0;
+#ifdef WITH_BASE64_HASHING_HACK
+ ddocCanonicalizePCDATA(buf2);
+ len2 = strlen(buf2);
+ ddocDebug(4, "generateDataFileXML", "sha1 update: \'%s\'", buf2);
+ SHA1_Update(&sctx, (const char*)buf2, len2);
+ mbuf3.pMem = buf2;
+ mbuf3.nLen = len2;
+ ddocDebugWriteFile(4, "df-data0.txt", &mbuf3);
+#else
+ ddocMemAppendData(&mbuf2, buf2, len2);
+#endif
+ if(hFile)
+ fwrite(buf2, sizeof(char), len2, hFile);
+ }
+ EVP_EncodeFinal(&ectx, (unsigned char*)buf2, &len2);
+ buf2[len2] = 0;
+#ifdef WITH_BASE64_HASHING_HACK
+ ddocCanonicalizePCDATA(buf2);
+ len2 = strlen(buf2);
+ ddocDebug(4, "generateDataFileXML", "sha1 update: \'%s\'", buf2);
+ SHA1_Update(&sctx, (const char*)buf2, len2);
+ mbuf3.pMem = buf2;
+ mbuf3.nLen = len2;
+ ddocDebugWriteFile(4, "df-data0.txt", &mbuf3);
+#else
+ ddocMemAppendData(&mbuf2, buf2, len2);
+#endif
+ if(hFile)
+ fwrite(buf2, sizeof(char), len2, hFile);
+ } else
+ if(!strcmp(pDataFile->szContentType, CONTENT_EMBEDDED)) {
+ while((len1 = fread(buf1, 1, sizeof(buf1), fIn)) > 0) {
+ if(!strcmp(pDataFile->szCharset, CHARSET_UTF_8)) {
+ ddocMemAppendData(&mbuf2, buf1, len1);
+ if(hFile)
+ fwrite(buf1, sizeof(char), len1, hFile);
+ } else
+ if(!strcmp(pDataFile->szCharset, CHARSET_ISO_8859_1)) {
+ len2 = sizeof(buf2);
+ memset(buf2, 0, len2);
+ isolat1ToUTF8((unsigned char*)buf2, &len2,
+ (const unsigned char*)buf1, &len1);
+ ddocMemAppendData(&mbuf2, buf2, len2);
+ if(hFile)
+ fwrite(buf2, sizeof(char), len2, hFile);
+ //if(pMBufXML)
+ // ddocMemAppendData(pMBufXML, buf2, len2);
+ } else
+ SET_LAST_ERROR(ERR_UNSUPPORTED_CHARSET);
+ }
+ if(!strcmp(pDataFile->szCharset, CHARSET_UTF_8)) {
+ ddocMemAppendData(&mbuf2, buf1, len1);
+ if(hFile)
+ fwrite(buf1, sizeof(char), len1, hFile);
+ //if(pMBufXML)
+ // ddocMemAppendData(pMBufXML, buf1, len1);
+ } else
+ if(!strcmp(pDataFile->szCharset, CHARSET_ISO_8859_1)) {
+ len2 = sizeof(buf2);
+ memset(buf2, 0, len2);
+ isolat1ToUTF8((unsigned char*)buf2, &len2,
+ (const unsigned char*)buf1, &len1);
+ ddocMemAppendData(&mbuf2, buf2, len2);
+ if(hFile)
+ fwrite(buf2, sizeof(char), len2, hFile);
+ //if(pMBufXML)
+ // ddocMemAppendData(pMBufXML, buf2, len2);
+ } else
+ SET_LAST_ERROR(ERR_UNSUPPORTED_CHARSET);
+ }
+ fclose(fIn);
+ ddocDebug(4, "generateDataFileXML", "Closed FILE2: %s", szDataFile);
+ fIn = 0;
+ } else {
+ ddocDebug(1, "generateDataFileXML", "Error reading FILE2: %s", szDataFile);
+ err = ERR_FILE_READ;
+ }
+ }
+ } // not temp file
+ // print suffix-whitespace
+ //if(pDataFile->szDataSuffix)
+ // BIO_puts(bOutFile, pDataFile->szDataSuffix);
+ setString(&(pDataFile->szDigestType), DIGEST_SHA1_NAME, -1);
+#ifdef WITH_BASE64_HASHING_HACK
+ if(!strcmp(pDataFile->szContentType, CONTENT_EMBEDDED_BASE64)) {
+ if(strcmp(pSigDoc->szFormat, SK_XML_1_NAME)) { // in ddoc 1.0 we calculate hash over original data
+ ddocDebug(4, "generateDataFileXML", "sha1 update: \'%s\'", "</DataFile>");
+ SHA1_Update(&sctx, "</DataFile>", 11);
+ mbuf3.pMem = "</DataFile>";
+ mbuf3.nLen = strlen("</DataFile>");
+ ddocDebugWriteFile(4, "df-data0.txt", &mbuf3);
+ }
+ memset(buf2, 0, sizeof(buf2));
+ SHA1_Final((unsigned char*)buf2, &sctx);
+ ddocDataFile_SetDigestValue(pDataFile, buf2, DIGEST_LEN);
+ ddocEncodeBase64(ddocDataFile_GetDigestValue(pDataFile), &mbuf2);
+ if(pMBufXML) {
+ if(((char*)mbuf2.pMem)[strlen((char*)mbuf2.pMem)-1] == '\n')
+ ((char*)mbuf2.pMem)[strlen((char*)mbuf2.pMem)-1] = 0;
+ ddocMemAppendData(pMBufXML, (const char*)mbuf2.pMem, -1);
+ }
+ ddocDebug(4, "generateDataFileXML", "DF digest: %s", (char*)mbuf2.pMem);
+ ddocMemBuf_free(&mbuf2);
+ } else {
+#endif
+ ddocMemAppendData(&mbuf2, "</DataFile>", -1);
+ memset(buf2, 0, sizeof(buf2));
+ p = canonicalizeXML((char*)mbuf2.pMem, mbuf2.nLen);
+ ddocMemBuf_free(&mbuf2);
+ RETURN_IF_NULL(p);
+ SHA1((const unsigned char*)p, strlen(p), (unsigned char*)buf2);
+ ddocDebug(4, "generateDataFileXML", "CANONICAL XML: \'%s\'", p);
+ free(p);
+ ddocDebug(4, "generateDataFileXML", "will update DF digest as ctype is %s", pDataFile->szContentType);
+ ddocDataFile_SetDigestValue(pDataFile, buf2, DIGEST_LEN);
+ ddocEncodeBase64(ddocDataFile_GetDigestValue(pDataFile), &mbuf2);
+ if(pMBufXML) {
+ if(((char*)mbuf2.pMem)[strlen((char*)mbuf2.pMem)-1] == '\n')
+ ((char*)mbuf2.pMem)[strlen((char*)mbuf2.pMem)-1] = 0;
+ ddocMemAppendData(pMBufXML, (const char*)mbuf2.pMem, -1);
+ }
+ ddocDebug(4, "generateDataFileXML", "DF digest: %s", (char*)mbuf2.pMem);
+ ddocMemBuf_free(&mbuf2);
+#ifdef WITH_BASE64_HASHING_HACK
+ }
+#endif
+ if(hFile)
+ fputs("</DataFile>", hFile);
+ if(pMBufXML) {
+ ddocMemAppendData(pMBufXML, (const char*)"\">", -1);
+ ddocMemAppendData(pMBufXML, "</DataFile>", -1);
+ }
+ if (err != ERR_OK) SET_LAST_ERROR(err);
+ ddocDebug(4, "generateDataFileXML", "done: %d", err);
+ return err;
+}
+
+#define DD_TEMP_FILE_MAX 200
+
+//--------------------------------------------------
+// Creates a new signed XML document
+// pSigDoc - signed doc info
+// szSigDocFile - output XML file name. If the file exists,
+// pMBufXML - output buffer if required to pass back in memory
+// then it will be used to read in embedded DataFile contents.
+// returns error code or ERR_OK for success
+//--------------------------------------------------
+int createSignedXMLDoc(SignedDoc* pSigDoc, const char* szOldFile, const char* szSigDocFile, DigiDocMemBuf* pMBufXML)
+{
+ int err = ERR_OK, i, nFiles;
+ FILE *hFile = 0;
+ DataFile* pDf = NULL;
+ char ** arrTempFiles = NULL;
+ char buf1[1024];
+ DigiDocMemBuf mbuf1;
+#ifdef WIN32
+ wchar_t *convFileName = 0;
+#endif
+
+ RETURN_IF_NULL_PARAM(pSigDoc);
+ //RETURN_IF_NULL_PARAM(szSigDocFile || pMBufXML);
+ mbuf1.pMem = 0;
+ mbuf1.nLen = 0;
+ buf1[0] = 0;
+ nFiles = getCountOfDataFiles(pSigDoc);
+ ddocDebug(3, "createSignedXMLDoc", "Old file: %s new file: %s mbuf: %s, DFs: %d",
+ szOldFile, (szSigDocFile ? szSigDocFile : "NULL"), (pMBufXML ? "Y" : "N"), nFiles);
+ // check if the file exists allready
+ // and extracts data files. They
+ // will be used later to construct
+ // a new document and then removed
+ if(szOldFile && checkFileExists(szOldFile)) {
+ arrTempFiles = (char**)malloc(nFiles * sizeof(void*));
+ RETURN_IF_BAD_ALLOC(arrTempFiles);
+ memset(arrTempFiles, 0, nFiles * sizeof(void*));
+ for(i = 0; i < nFiles; i++) {
+ pDf = getDataFile(pSigDoc, i);
+ ddocDebug(3, "createSignedXMLDoc", "DataFile: %s - %s", pDf->szId, pDf->szFileName);
+ arrTempFiles[i] = (char*)malloc(DD_TEMP_FILE_MAX);
+ arrTempFiles[i][0] = 0;
+ // do not copy newly added files
+ if(!strchr((const char*)pDf->szFileName, '/') &&
+ !strchr((const char*)pDf->szFileName, '\\')) {
+ err = getTempFileName(arrTempFiles[i], DD_TEMP_FILE_MAX);
+ // VS: test the new parser based on xmlReader interface
+ //err = ddocXRdrCopyDataFile(pSigDoc, szOldFile, (const char*)arrTempFiles[i], pDf->szId, CHARSET_ISO_8859_1, CHARSET_ISO_8859_1);
+ ddocDebug(3, "createSignedXMLDoc", "Store DataFile: %s to: %s size: %d", pDf->szId, (const char*)arrTempFiles[i], pDf->nSize);
+ err = ddocExtractDataFile(pSigDoc, szOldFile, (const char*)arrTempFiles[i], pDf->szId, "NO-CHANGE");
+ }
+ }
+ }
+ if(szSigDocFile) {
+#ifdef WIN32
+ i = 0;
+ err = utf82unicode((const char*)szSigDocFile, (char**)&convFileName, &i);
+ ddocDebug(3, "createSignedXMLDoc", "Opening FILE: %s, conv-file: %s len: %d", szSigDocFile, convFileName, i);
+ if(err) return err;
+#else
+ err = ddocConvertFileName(buf1, sizeof(buf1), szSigDocFile);
+ ddocDebug(3, "createSignedXMLDoc", "Opening FILE: %s", buf1);
+ if(err) return err;
+#endif
+ }
+ // now create the new document
+#ifdef WIN32
+ if((szSigDocFile && (hFile = _wfopen(convFileName, L"wb")) != NULL) || pMBufXML) {
+#else
+ if((szSigDocFile && (hFile = fopen(buf1, "wb")) != NULL) || pMBufXML) {
+#endif
+ if(szSigDocFile)
+ fputs("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n", hFile);
+ if(pMBufXML)
+ ddocMemAppendData(pMBufXML, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n", -1);
+ // VS: ver 1.80 - in version 1.3 we started using SignedDoc namespace
+ if(!strcmp(pSigDoc->szFormatVer, DIGIDOC_XML_1_3_VER)) {
+ if(szSigDocFile)
+ fprintf(hFile, "<SignedDoc format=\"%s\" version=\"%s\" xmlns=\"http://www.sk.ee/DigiDoc/v1.3.0#\">\n", pSigDoc->szFormat, pSigDoc->szFormatVer);
+ if(pMBufXML) {
+ ddocMemAppendData(pMBufXML, "<SignedDoc format=\"", -1);
+ ddocMemAppendData(pMBufXML, pSigDoc->szFormat, -1);
+ ddocMemAppendData(pMBufXML, "\" version=\"", -1);
+ ddocMemAppendData(pMBufXML, pSigDoc->szFormatVer, -1);
+ ddocMemAppendData(pMBufXML, "\" xmlns=\"http://www.sk.ee/DigiDoc/v1.3.0#\">\n", -1);
+ }
+ } else {
+ if(szSigDocFile)
+ fprintf(hFile, "<SignedDoc format=\"%s\" version=\"%s\">\n", pSigDoc->szFormat, pSigDoc->szFormatVer);
+ if(pMBufXML) {
+ ddocMemAppendData(pMBufXML, "<SignedDoc format=\"", -1);
+ ddocMemAppendData(pMBufXML, pSigDoc->szFormat, -1);
+ ddocMemAppendData(pMBufXML, "\" version=\"", -1);
+ ddocMemAppendData(pMBufXML, pSigDoc->szFormatVer, -1);
+ ddocMemAppendData(pMBufXML, "\">\n", -1);
+ }
+ }
+ // DataFile objects
+ for(i = 0; i < nFiles; i++) {
+ pDf = getDataFile(pSigDoc, i);
+ ddocDebug(3, "createSignedXMLDoc", "DF: %d file: %s temp: %s", i, pDf->szFileName, (arrTempFiles ? arrTempFiles[i] : "NONE"));
+ // if the file must be embedded
+ if(arrTempFiles && arrTempFiles[i] && checkFileExists(arrTempFiles[i])) {
+ ddocDebug(3, "createSignedXMLDoc", "Use temp file: %s", arrTempFiles[i]);
+ err = generateDataFileXML(pSigDoc, pDf, (const char*)arrTempFiles[i], hFile, &mbuf1);
+ ddocDebug(3, "createSignedXMLDoc", "Use temp file: %s rc: %d", arrTempFiles[i], err);
+ if(!err && pMBufXML)
+ ddocMemAppendData(pMBufXML, mbuf1.pMem, mbuf1.nLen);
+ ddocMemBuf_free(&mbuf1);
+ ddocDebug(3, "createSignedXMLDoc", "Used temp file: %s", arrTempFiles[i]);
+ } else if(checkFileExists(pDf->szFileName) || pDf->mbufContent.pMem) { // TODO: test id out-mem sign works
+ ddocDebug(3, "createSignedXMLDoc", "Create new data file: %s", pDf->szFileName);
+ err = generateDataFileXML(pSigDoc, pDf, (const char*)pDf->szFileName, hFile, &mbuf1);
+ ddocDebug(3, "createSignedXMLDoc", "Create new data file: %s rc: %d", pDf->szFileName, err);
+ if(!err && pMBufXML)
+ ddocMemAppendData(pMBufXML, mbuf1.pMem, mbuf1.nLen);
+ ddocMemBuf_free(&mbuf1);
+ ddocDebug(3, "createSignedXMLDoc", "Created new data file: %s", pDf->szFileName);
+ }
+ if(szSigDocFile)
+ fputs("\n", hFile);
+ if(pMBufXML)
+ ddocMemAppendData(pMBufXML, "\n", -1);
+ }
+ ddocDebug(3, "createSignedXMLDoc", "Gen sigs");
+ for(i = 0; i < pSigDoc->nSignatures; i++) {
+ ddocDebug(3, "createSignedXMLDoc", "Gen sig: %d", i);
+
+ // VS: if Signature has been read from file then
+ // use the original content
+ if(pSigDoc->pSignatures[i]->mbufOrigContent.pMem) {
+ if(szSigDocFile)
+ fwrite(pSigDoc->pSignatures[i]->mbufOrigContent.pMem, sizeof(char),
+ pSigDoc->pSignatures[i]->mbufOrigContent.nLen, hFile);
+ if(pMBufXML)
+ err = ddocMemAppendData(pMBufXML, (const char*)pSigDoc->pSignatures[i]->mbufOrigContent.pMem,
+ pSigDoc->pSignatures[i]->mbufOrigContent.nLen);
+ } else {
+ err = addSignatureInfoXML(&mbuf1, pSigDoc, pSigDoc->pSignatures[i]);
+ if(szSigDocFile)
+ fputs((char*)mbuf1.pMem, hFile);
+ if(pMBufXML)
+ err = ddocMemAppendData(pMBufXML, (const char*)mbuf1.pMem, mbuf1.nLen);
+ ddocMemBuf_free(&mbuf1);
+ }
+ } // for i < pSigDoc->nSignatures
+ if(szSigDocFile) {
+ fputs("</SignedDoc>", hFile);
+ }
+ if(hFile) {
+ ddocDebug(3, "createSignedXMLDoc", "Closing FILE: %s", buf1);
+ fclose(hFile);
+ }
+ if(pMBufXML)
+ ddocMemAppendData(pMBufXML, "</SignedDoc>", -1);
+ ddocDebug(3, "createSignedXMLDoc", "Generated");
+
+ // delete temporary files we created when
+ // extracting the data files from original XML signed doc
+ // VS: fix the bug of deleting input files
+ // This happened because prefix was empty and
+ // thus doc names where the same as original
+ // input file names
+ if(szOldFile && arrTempFiles) { // check if temp files were created
+ for(i = 0; i < nFiles; i++) {
+ pDf = getDataFile(pSigDoc, i);
+ // ignore not being able to delete temp file. It returns -1
+ //_unlink((const char*)arrTempFiles[i]);
+ free(arrTempFiles[i]);
+ }
+ free(arrTempFiles);
+ }
+ } else {
+ err = ERR_FILE_WRITE;
+ #ifdef WIN32
+ ddocDebug(1, "createSignedXMLDoc", "Error1: %d opening file: %s errno: %d doserrno: %d perror: %s",
+ err, szSigDocFile, _errno, _doserrno, strerror(_errno));
+ if(_errno == 1933280595) {
+ err = ERR_NETWORK_SYNC;
+ ddocDebug(1, "createSignedXMLDoc", "Error2 %d opening file for writing. Network sync err?", err);
+ }
+ #endif
+ }
+ ddocDebug(3, "createSignedXMLDoc", "Cleanup1");
+#ifdef WIN32
+ if(convFileName) free(convFileName);
+#endif
+ if (err != ERR_OK) SET_LAST_ERROR(err);
+ ddocDebug(3, "createSignedXMLDoc", "Done");
+ return err;
+}
+
+
+//--------------------------------------------------
+// Creates a new signed document
+// pSigDoc - signed doc info
+// returns error code or ERR_OK for success
+//--------------------------------------------------
+EXP_OPTION int createSignedDoc(SignedDoc* pSigDoc, const char* szOldFile, const char* szOutputFile)
+{
+ int err = ERR_OK;
+ int nWait, nRetries, i;
+ long lSize = 0;
+ RETURN_IF_NULL_PARAM(pSigDoc);
+ RETURN_IF_NULL_PARAM(szOutputFile);
+ RETURN_IF_NULL_PARAM(pSigDoc->szFormat);
+ if(szOldFile && strlen(szOldFile)) {
+ calculateFileSize(szOldFile, &lSize);
+ ddocDebug(3, "createSignedDoc", "Old file: %s ddoc-size: %ld", szOldFile, lSize);
+ if(lSize == 0) {
+ ddocDebug(1, "createSignedDoc", "Invalid old file: %s ddoc-size: %ld", szOldFile, lSize);
+ SET_LAST_ERROR(ERR_FILE_READ);
+ return ERR_FILE_READ;
+ }
+ }
+ clearErrors();
+ if(hasSignatureWithWrongDataFileHash(pSigDoc)) {
+ ddocDebug(1, "createSignedDoc", "Cannot save ddoc: %s size: %ld with invalid DataFile hashes!", szOldFile, lSize);
+ return ERR_FILE_WRITE;
+ }
+ if(!strcmp(pSigDoc->szFormatVer, DIGIDOC_XML_1_3_VER) &&
+ !strcmp(pSigDoc->szFormat, DIGIDOC_XML_1_1_NAME)) {
+ err = createSignedXMLDoc(pSigDoc, szOldFile, szOutputFile, NULL);
+ ddocDebug(3, "createSignedDoc", "Done, rc: %d", err);
+ #ifdef WIN32
+ if(err = ERR_NETWORK_SYNC) {
+ nWait = 1; // oli parameeter NETWORK_SYNC_WAIT
+ nRetries = 3; // oli parameeter NETWORK_SYNC_RETRIES
+ ddocDebug(3, "createSignedDoc", "Network sync wait: %d retries: %d", nWait, nRetries);
+ for(i = 0; (err == ERR_NETWORK_SYNC) && (i < nRetries); i++) {
+ ddocDebug(3, "createSignedDoc", "Network sync wait: %d", nWait);
+ Sleep(1000 * nWait);
+ ddocDebug(3, "createSignedDoc", "Network sync write: %d of: %d retries", i, nRetries);
+ clearErrors(); // reset errors from past failed write attempt
+ err = createSignedXMLDoc(pSigDoc, szOldFile, szOutputFile, NULL);
+ }
+ }
+ #endif
+ }
+ else
+ err = ERR_UNSUPPORTED_FORMAT;
+ if (err != ERR_OK) SET_LAST_ERROR(err);
+ return err;
+}
+
+//--------------------------------------------------
+// Creates a new signed document in memory buffer
+// pSigDoc - signed doc info
+// szOldFile - name of old file on disk to copy DataFile contents
+// pMBuf - buffer for new digidoc document
+// returns error code or ERR_OK for success
+//--------------------------------------------------
+EXP_OPTION int createSignedDocInMemory(SignedDoc* pSigDoc, const char* szOldFile, DigiDocMemBuf* pMBuf)
+{
+ int err = ERR_OK;
+
+ RETURN_IF_NULL_PARAM(pSigDoc);
+ RETURN_IF_NULL_PARAM(pMBuf);
+ RETURN_IF_NULL_PARAM(pSigDoc->szFormat);
+ clearErrors();
+ if(hasSignatureWithWrongDataFileHash(pSigDoc)) {
+ ddocDebug(1, "createSignedDocInMemory", "Cannot save ddoc: %s with invalid DataFile hashes!", szOldFile);
+ return ERR_FILE_WRITE;
+ }
+ if(!strcmp(pSigDoc->szFormatVer, DIGIDOC_XML_1_3_VER) &&
+ !strcmp(pSigDoc->szFormat, DIGIDOC_XML_1_1_NAME)) {
+ err = createSignedXMLDoc(pSigDoc, szOldFile, NULL, pMBuf);
+ }
+ else
+ err = ERR_UNSUPPORTED_FORMAT;
+ if (err != ERR_OK) SET_LAST_ERROR(err);
+ return err;
+}
+
+//--------------------------------------------------
+// Removes incomplete or orphoned signatures.
+// Signature is incomplete if it hasn't got the signature
+// value
+// pSigDoc - signed doc info
+// returns error code or ERR_OK for success
+//--------------------------------------------------
+EXP_OPTION int removeIncompleteSignatures(SignedDoc* pSigDoc)
+{
+ int err = ERR_OK, i, n, b;
+ SignatureInfo *pSigInfo;
+
+ RETURN_IF_NULL_PARAM(pSigDoc);
+ do {
+ b = 0;
+ n = getCountOfSignatures(pSigDoc);
+ for(i = 0; i < n; i++){
+ pSigInfo = getSignature(pSigDoc, i);
+ if(!pSigInfo->pSigValue ||
+ (pSigInfo->pSigValue && !pSigInfo->pSigValue->mbufSignatureValue.pMem)) {
+ SignatureInfo_free(pSigInfo); // remove incomplete signature
+ break;
+ }
+ }
+ } while(b);
+ return err;
+}
+
+//--------------------------------------------------
+// Checks for incomplete or orphoned signatures.
+// Signature is incomplete if it hasn't got the signature
+// value
+// pSigDoc - signed doc info
+// returns error code if DigiDoc has orphoned signature or ERR_OK for success
+//--------------------------------------------------
+EXP_OPTION int hasIncompleteSignatures(SignedDoc* pSigDoc)
+{
+ int i;
+ SignatureInfo *pSigInfo;
+
+ RETURN_IF_NULL_PARAM(pSigDoc);
+ for(i = 0; i < getCountOfSignatures(pSigDoc); i++){
+ pSigInfo = getSignature(pSigDoc, i);
+ if(!pSigInfo->pSigValue ||
+ (pSigInfo->pSigValue && !pSigInfo->pSigValue->mbufSignatureValue.pMem)) {
+ return ERR_ORPHONED_SIGNATURE;
+ }
+ }
+ return ERR_OK;
+}
+
diff --git a/libdigidoc/DigiDocGen.h b/libdigidoc/DigiDocGen.h
new file mode 100644
index 0000000..85db6d5
--- /dev/null
+++ b/libdigidoc/DigiDocGen.h
@@ -0,0 +1,200 @@
+#ifndef __DIGIDOC_GEN_H__
+#define __DIGIDOC_GEN_H__
+//==================================================
+// FILE: DigiDocGen.h
+// PROJECT: Digi Doc
+// DESCRIPTION: DigiDoc helper routines for XML generation
+// AUTHOR: Veiko Sinivee, S|E|B IT Partner Estonia
+//==================================================
+// Copyright (C) AS Sertifitseerimiskeskus
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+// GNU Lesser General Public Licence is available at
+// http://www.gnu.org/copyleft/lesser.html
+//==========< HISTORY >=============================
+// 11.04.2006 Veiko Sinivee
+// Creation
+//==================================================
+
+#include <libdigidoc/DigiDocDefs.h>
+#include <libdigidoc/DigiDocObj.h>
+#include <libdigidoc/DigiDocMem.h>
+
+
+//==========< XML generation routines >========================
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef WITH_TIMETSTAMP_STRUCT
+// contains timestamp data
+typedef struct Timestamp_st {
+ int year;
+ int mon;
+ int day;
+ int hour;
+ int min;
+ int sec;
+ int tz;
+} Timestamp;
+
+// converts timestamp string to it's components
+EXP_OPTION int convertStringToTimestamp(const SignedDoc* pSigDoc, const char* szTimestamp, Timestamp* pTimestamp);
+// converts timestamp to string
+EXP_OPTION int convertTimestampToString(const SignedDoc* pSigDoc, const Timestamp* pTimestamp, char* szTimestamp, int len);
+// creates new timestamp object
+EXP_OPTION int Timestamp_new(Timestamp **, int year,int month,int day,int hour,int minute,int second,int timezone);
+// frees this timestamp object
+EXP_OPTION void Timestamp_free(Timestamp* pTimestamp);
+
+#endif
+
+//============================================================
+// Creates a timestamp string
+// buf - output buffer
+// len - length of output buffer
+// returns number of output bytes written
+//============================================================
+int createTimestamp(const SignedDoc* pSigDoc, char* buf, int len);
+
+// converts timestamp string to time_t value
+EXP_OPTION time_t convertStringToTimeT(const SignedDoc* pSigDoc, const char* szTimestamp);
+
+
+//--------------------------------------------------
+// Appends an xml element start to buffer, but no ">"
+// pBuf - memory buffer to store xml [REQUIRED]
+// elemName - xml element name [REQUIRED]
+// returns error code or ERR_OK
+//--------------------------------------------------
+int ddocGen_startElemBegin(DigiDocMemBuf* pBuf, const char* elemName);
+
+//--------------------------------------------------
+// Appends an xml element start tag end to buffer - ">"
+// pBuf - memory buffer to store xml [REQUIRED]
+// returns error code or ERR_OK
+//--------------------------------------------------
+int ddocGen_startElemEnd(DigiDocMemBuf* pBuf);
+
+//--------------------------------------------------
+// Appends an xml element start to buffer - <tag>
+// pBuf - memory buffer to store xml [REQUIRED]
+// elemName - xml element name [REQUIRED]
+// returns error code or ERR_OK
+//--------------------------------------------------
+int ddocGen_startElem(DigiDocMemBuf* pBuf, const char* elemName);
+
+//--------------------------------------------------
+// Appends an xml element end to buffer
+// pBuf - memory buffer to store xml [REQUIRED]
+// elemName - xml element name [REQUIRED]
+// returns error code or ERR_OK
+//--------------------------------------------------
+int ddocGen_endElem(DigiDocMemBuf* pBuf, const char* elemName);
+
+//--------------------------------------------------
+// Appends an xml element's atribute to buffer
+// pBuf - memory buffer to store xml [REQUIRED]
+// name - xml atribute name [REQUIRED]
+// value - xml atribute value [REQUIRED]
+// returns error code or ERR_OK
+//--------------------------------------------------
+int ddocGen_addAtribute(DigiDocMemBuf* pBuf, const char* name, const char* value);
+
+
+//--------------------------------------------------
+// Helper function that escapes XML special chars
+// src - input data
+// srclen - length of input data. Use -1 for 0 terminated strings
+// dest - address of output buffer. Caller is responsible for deallocating it!
+// returns error code or ERR_OK
+//--------------------------------------------------
+int escapeXMLSymbols(const char* src, int srclen, char** dest);
+
+//--------------------------------------------------
+// Helper function that escapes XML special chars in xml element body
+// src - input data
+// srclen - length of input data. Use -1 for 0 terminated strings
+// dest - address of output buffer. Caller is responsible for deallocating it!
+// returns error code or ERR_OK
+//--------------------------------------------------
+int escapeTextNode(const char* src, int srclen, char** dest);
+
+
+//================< functions generating DigiDoc formats 1.0 - 1.3 > =================================
+
+// writes the signed doc to a file
+EXP_OPTION int createSignedDoc(SignedDoc* pSigDoc, const char* szOldFile, const char* szSigDocFile);
+
+//============================================================
+// Canonicalizes XML
+// source - input data
+// len - input length
+// returns a newly allocated buffer with canonicalized XML
+// Caller must free() the result.
+//============================================================
+char* canonicalizeXML(char* source, int len);
+
+char* canonicalizeXMLBlock(char* source, int len, char* block, char* prefix);
+
+//============================================================
+// Creates a <SignedProperties> XML block
+// pSigDoc - signed document pointer
+// pSigInfo - signature info data
+// bWithEscapes - 1=escape xml sümbols, 0=don't escape
+// returns new <SignedProperties> node
+//============================================================
+char* createXMLSignedProperties(const SignedDoc* pSigDoc, const SignatureInfo* pSigInfo, int bWithEscapes);
+
+//============================================================
+// Generates DataFile elements XML form and stores it in a file
+// pSigDoc - signed document
+// pDataFile - data file object to be converted
+// szDataFile - input file name
+// hFile - output file handle
+// pMBufXML - output buffer if we want data to be returned in mem buf
+//============================================================
+EXP_OPTION int generateDataFileXML(SignedDoc* pSigDoc, DataFile* pDataFile,
+ const char* szDataFile, FILE* hFile, DigiDocMemBuf* pMBufXML);
+
+//--------------------------------------------------
+// Creates a new signed document in memory buffer
+// pSigDoc - signed doc info
+// szOldFile - name of old file on disk to copy DataFile contents
+// pMBuf - buffer for new digidoc document
+// returns error code or ERR_OK for success
+//--------------------------------------------------
+EXP_OPTION int createSignedDocInMemory(SignedDoc* pSigDoc, const char* szOldFile, DigiDocMemBuf* pMBuf);
+
+//--------------------------------------------------
+// Removes incomplete or orphoned signatures.
+// Signature is incomplete if it hasn't got the signature
+// value
+// pSigDoc - signed doc info
+// returns error code or ERR_OK for success
+//--------------------------------------------------
+EXP_OPTION int removeIncompleteSignatures(SignedDoc* pSigDoc);
+
+//--------------------------------------------------
+// Checks for incomplete or orphoned signatures.
+// Signature is incomplete if it hasn't got the signature
+// value
+// pSigDoc - signed doc info
+// returns error code if DigiDoc has orphoned signature or ERR_OK for success
+//--------------------------------------------------
+EXP_OPTION int hasIncompleteSignatures(SignedDoc* pSigDoc);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif // __DIGIDOC_GEN_H__
diff --git a/libdigidoc/DigiDocGlobals.c b/libdigidoc/DigiDocGlobals.c
new file mode 100644
index 0000000..fc3939c
--- /dev/null
+++ b/libdigidoc/DigiDocGlobals.c
@@ -0,0 +1,65 @@
+//==================================================
+// FILE: DigiDocGlobals.c
+// PROJECT: Digi Doc Encryption
+// DESCRIPTION: DigiDoc TSA profiles
+// AUTHOR: Veiko Sinivee, S|E|B IT Partner Estonia
+//==================================================
+// Copyright (C) AS Sertifitseerimiskeskus
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+// GNU Lesser General Public Licence is available at
+// http://www.gnu.org/copyleft/lesser.html
+//=================================================
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include <libdigidoc/DigiDocDefs.h>
+#include <libdigidoc/DigiDocGlobals.h>
+#include <libdigidoc/DigiDocConfig.h>
+
+
+// default TSAProfile (to be extended)
+LPTSAProfile g_current_TSAProfile = 0;
+
+//--------------------------------------------------
+// Initializes TSA profile block
+// returns pointer to global TSA profile
+//--------------------------------------------------
+EXP_OPTION TSAProfile* TSAProfile_init()
+{
+ TSAProfile* p = g_current_TSAProfile;
+
+ if(!p) {
+ p = (TSAProfile*)malloc(sizeof(TSAProfile));
+ if(p) {
+ memset(p, 0, sizeof(TSAProfile));
+ g_current_TSAProfile = p;
+ p->g_bAddSignatureTimeStamp = 1;
+ p->g_bAddSigAndRefsTimeStamp = 1;
+ p->g_nTsaMaxTsInterval = 1;
+ p->m_nDebugLevel = 0;
+ strncpy(p->g_szTsaUrl, "http://ns.szikszi.hu:8080/tsa", sizeof(p->g_szTsaUrl));
+ memset(p->m_szDebugFilePath, 0, sizeof(p->m_szDebugFilePath)); // VS: changed initialization
+ g_current_TSAProfile = p;
+ }
+ // init config store
+ if(!isConfigInited())
+ initConfigStore(NULL);
+ }
+ return p;
+}
+
+EXP_OPTION void TSAProfile_free()
+{
+ if(g_current_TSAProfile)
+ free(g_current_TSAProfile);
+ g_current_TSAProfile = 0;
+} \ No newline at end of file
diff --git a/libdigidoc/DigiDocGlobals.h b/libdigidoc/DigiDocGlobals.h
new file mode 100644
index 0000000..1e72763
--- /dev/null
+++ b/libdigidoc/DigiDocGlobals.h
@@ -0,0 +1,69 @@
+#ifndef __DIGIDOC_PROFILE_H__
+#define __DIGIDOC_PROFILE_H__
+//==================================================
+// FILE: DigiDocGlobals.h
+// PROJECT: Digi Doc Encryption
+// DESCRIPTION: DigiDoc TSA profiles
+// AUTHOR: Veiko Sinivee, S|E|B IT Partner Estonia
+//==================================================
+// Copyright (C) AS Sertifitseerimiskeskus
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+// GNU Lesser General Public Licence is available at
+// http://www.gnu.org/copyleft/lesser.html
+//==========< HISTORY >=============================
+// 01.06.2006 Arvo Sulakatko
+// Creation
+// 08.06.2006 Veiko Sinivee
+// Changed implementation and assignment of profile values
+//==================================================
+
+#include <libdigidoc/DigiDocDefs.h>
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+// TSAProfile
+typedef struct tag_TSAProfile *LPTSAProfile;
+
+// TSAProfile
+typedef struct tag_TSAProfile
+{
+ char g_szTsaPolicy[255];
+ char g_szTsaUrl[255];
+ int g_nTsaMaxTsInterval;
+ int g_bAddSignatureTimeStamp;
+ int g_bAddSigAndRefsTimeStamp;
+
+ char m_szDebugFilePath[0xFF];
+ int m_nDebugLevel;
+
+} TSAProfile, *LPTSAProfile;
+
+
+//--------------------------------------------------
+// Initializes TSA profile block
+// returns pointer to global TSA profile
+//--------------------------------------------------
+EXP_OPTION TSAProfile* TSAProfile_init();
+
+
+// default TSAProfile (to be extended)
+//extern LPTSAProfile g_current_TSAProfile;
+
+EXP_OPTION void TSAProfile_free();
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // __DIGIDOC_PROFILE_H__
+
diff --git a/libdigidoc/DigiDocHTTP.c b/libdigidoc/DigiDocHTTP.c
new file mode 100644
index 0000000..3152996
--- /dev/null
+++ b/libdigidoc/DigiDocHTTP.c
@@ -0,0 +1,44 @@
+#include <libdigidoc/DigiDocHTTP.h>
+#include <libdigidoc/DigiDocError.h>
+#include <string.h>
+#include <ctype.h>
+#include <stdlib.h>
+
+//--------------------------------------------------
+// Returns HTTP return code
+// pBuf- buffer with HTTP response
+// returns error code or HTTP response code
+//--------------------------------------------------
+int ddocGetHttpResponseCode(DigiDocMemBuf* pBuf)
+{
+ int rc = ERR_OK;
+ char *p = (char*)pBuf->pMem;
+ RETURN_IF_NULL_PARAM(pBuf);
+ if(p && !strncmp(p, "HTTP", 4)) {
+ while(*p && *p != ' ') p++;
+ while(*p && !isdigit(*p)) p++;
+ rc = atoi(p);
+ } else
+ return ERR_HTTP_ERR;
+ return rc;
+}
+
+//--------------------------------------------------
+// Returns HTTP response body
+// pInBuf- buffer with HTTP response
+// pOutBuf - buffer for response body
+// returns error code or ERR_OK
+//--------------------------------------------------
+int ddocGetHttpPayload(DigiDocMemBuf* pInBuf, DigiDocMemBuf* pOutBuf)
+{
+ int err = ERR_OK;
+ char *p;
+ RETURN_IF_NULL_PARAM(pInBuf);
+ RETURN_IF_NULL_PARAM(pOutBuf);
+ if((p = strstr((char*)pInBuf->pMem, "\r\n\r\n")) != NULL) {
+ p += 4;
+ err = ddocMemAssignData(pOutBuf, p, pInBuf->nLen - (int)(p - (char*)pInBuf->pMem));
+ } else
+ return ERR_HTTP_ERR;
+ return err;
+}
diff --git a/libdigidoc/DigiDocHTTP.h b/libdigidoc/DigiDocHTTP.h
new file mode 100644
index 0000000..ed1b70d
--- /dev/null
+++ b/libdigidoc/DigiDocHTTP.h
@@ -0,0 +1,4 @@
+#include <libdigidoc/DigiDocMem.h>
+
+int ddocGetHttpResponseCode(DigiDocMemBuf* pBuf);
+int ddocGetHttpPayload(DigiDocMemBuf* pInBuf, DigiDocMemBuf* pOutBuf);
diff --git a/libdigidoc/DigiDocLib.c b/libdigidoc/DigiDocLib.c
new file mode 100644
index 0000000..4ec82e2
--- /dev/null
+++ b/libdigidoc/DigiDocLib.c
@@ -0,0 +1,1173 @@
+//==================================================
+// FILE: DigiDocLib.c
+// PROJECT: Digi Doc
+// DESCRIPTION: Digi Doc functions for creating
+// and reading signed documents.
+// AUTHOR: Veiko Sinivee, S|E|B IT Partner Estonia
+//==================================================
+// Copyright (C) AS Sertifitseerimiskeskus
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+// GNU Lesser General Public Licence is available at
+// http://www.gnu.org/copyleft/lesser.html
+//==========< HISTORY >=============================
+// 20.09.2004 Changed createOCSPRequest() to use custom functions for adding
+// OCSP nonce to OCSP request for digidoc formats 1.0, 1.1 and 1.2
+// thereby guaranteing that in case of those formats only 20 bytes are sent.
+// This is necessary to guarantee backward compatibility with OpenSSL 0.9.6
+// 22.08.2004 Added DataFile content caching, function ddocGetDataFileCachedData()
+// and modified functions readSignedDoc(), extractDataFile(),
+// ddocExtractDataFile(), ddocGetDataFile() and ddocCopyDataFile() to use it.
+// Added function ddocSaxReadSignedDocFromMemory()
+// New debugging interface ddocDebug()
+// 12.08.2004 Moved all SAX xml parsing functions to DigiDocSAXParser.c
+// and fixed some memory problems
+// 03.08.2004 Added check to initializeNotaryInfoWithOCSP() to handle 22 byte ASN.1
+// encoded nonce with OpenSSL 0.9.7d
+// added a check on output filename for extractDataFile() function.
+// added a check for verifyNotaryInfoCERT() function to check empty certificate array size.
+// Added back the function verifyCertificateByOCSP()
+// 14.06.2004 Changed generateDataFileXML() to replaces '&' with '&amp;'
+// int file names. Changed handleStartDataFile() acordingly.
+// 20.05.2004 Added new error codes to handle OCSP response
+// status and fixed initializeNotaryInfoWithOCSP()
+// 19.05.2004 Added a nullpointer test to checkFileExists()
+// 12.05.2004 Fixed convertStringToTimeT() by changing
+// timestamp format pattern according to 1.3 format version
+// 11.05.2004 Added error code ERR_OCSP_WRONG_URL to sendOCSPRequest
+// to indicate that the given server is not an OCSP server
+// 23.03.2004 fixed setSignatureValueFromFile() that was affected
+// by siganture caching. Fixed getConfirmation() to
+// allowe sending not signed OCSP requests.
+// 17.03.2004 fixed getSignerCode() to handle certs that
+// have no comma in CN. Fixed NotaryInfo_new to
+// reset szOrigContent of signature. Added function
+// handleOCSPCertStatus() to check cert status
+// and modified initializeNotaryInfoWithOCSP() and
+// checkNonceAndCertbyOCSP()
+// 11.03.2004 added SignedDoc namespace in format 1.3
+// generateDataFileXML(), createSignedXMLDoc()
+// handleStartDataFile(),
+// bugs in emptying buffers
+// unicode2ascii(), getSignerLastName()
+// Veiko Sinivee
+// 25.11.2003 added functions calculateFileLength(),
+// verifyCertificateByOCSP() and helper functions
+// 21.11.2003 Fixed SignatureValue decoding problem
+// Veiko Sinivee
+// 17.11.2003 Aare Amenberg
+// Changed error texts
+// Changed sendOCSPRequest
+// (added more error checkings)
+// 14.11.2003 Aare Amenberg
+// Removed WriteOCSPResponse
+// Changed addNotaryInfoXML by Veiko
+// 11.11.2003 Aare Amenberg
+// Added CorrectCharacters
+// Added error 96 ERR_WRONG_URL_OR_PROXY
+// 31.10.2003 Aare Amenberg
+// Added error text 95
+// Removed if(single->singleExtensions)
+// SET_LAST_ERROR_RETURN_CODE(ERR_OCSP_NO_SINGLE_EXT);
+// Function initializeNotaryInfoWithOCSP
+// 29.10.2003 Aare Amenberg
+// WIN32_CSP functions moved
+// to module DigiDocCsp
+// 1.0 09.04.2002 Veiko Sinivee
+// Supports XML format (Type: SK-XML-1.0)
+//==================================================
+
+#include <libdigidoc/DigiDocDefs.h>
+
+#define WIN32_PKCS 1
+
+#ifdef WIN32
+ #include <wincrypt.h>
+#endif
+
+#include <config.h>
+
+#include <libdigidoc/DigiDocLib.h>
+#include <libdigidoc/DigiDocSAXParser.h>
+#include <libdigidoc/DigiDocDebug.h>
+#include <libdigidoc/DigiDocConvert.h>
+#include <libdigidoc/DigiDocConfig.h>
+#include <libdigidoc/DigiDocCert.h>
+#include <libdigidoc/DigiDocGen.h>
+//AM
+#include <libdigidoc/DigiDocObj.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <memory.h>
+#include <string.h>
+#include <assert.h>
+#include <ctype.h>
+#include <fcntl.h>
+#include <time.h>
+
+#include <openssl/sha.h>
+#include <openssl/rsa.h>
+#include <openssl/evp.h>
+#include <openssl/objects.h>
+#include <openssl/x509.h>
+#include <openssl/x509v3.h>
+#include <openssl/err.h>
+#include <openssl/pem.h>
+#include <openssl/ssl.h>
+#include <openssl/ocsp.h>
+#include <openssl/pkcs12.h>
+#include <openssl/rand.h>
+
+long int tzone = -7200; /* default for Estonia, but see initDigiDocLib() */
+int daylight = 0; /* default, but see initDigiDocLib() */
+
+//==========< global constants >====================
+
+char g_szLibName[] = "CDigiDoc";
+char g_szLibVer[] = DIGIDOC_VERSION;
+//char g_szLibVer[] = VERSION;
+char* g_szSupportedVersions[] = { "1.0", "1.1", "1.2", "1.3", "0.7"
+ };
+
+char* g_arrFormats[] = { SK_XML_1_NAME, DIGIDOC_XML_1_1_NAME, 0 };
+
+FormatAndVer g_supportedFormatsAndVersions[] = {
+ { SK_XML_1_NAME, SK_XML_1_VER },
+ { DIGIDOC_XML_1_1_NAME, DIGIDOC_XML_1_1_VER },
+ { DIGIDOC_XML_1_1_NAME, DIGIDOC_XML_1_2_VER },
+ { DIGIDOC_XML_1_1_NAME, DIGIDOC_XML_1_3_VER },
+ { NULL, NULL } // list end marker
+};
+
+// static buffer for name & version of the program using this library
+#define GUI_VERSION_LEN 100
+char g_szGUIVersion[GUI_VERSION_LEN];
+
+//==========< global variables >====================
+
+
+
+// forward deklaratsioon
+int notary2ocspBasResp(const SignedDoc* pSigDoc, const NotaryInfo* pNotInfo, X509* notCert, OCSP_BASICRESP** pBasResp);
+int calculateOcspBasicResponseDigest(OCSP_BASICRESP* pBsResp, byte* digBuf, int* digLen);
+
+int createOCSPRequest(SignedDoc* pSigDoc, OCSP_REQUEST **req,
+ X509 *cert, X509 *pCA, byte* nonce, int nlen);
+EXP_OPTION int signOCSPRequestPKCS12(OCSP_REQUEST *req, const char* filename, const char* passwd);
+
+int verifyOCSPResponse(OCSP_RESPONSE* pResp,
+ const X509** caCerts, const char *CApath,
+ const X509* notCert);
+int checkNonceAndCertbyOCSP(OCSP_RESPONSE* resp, X509* cert, byte* nonce1, int nonceLen);
+
+int verifyResp(OCSP_BASICRESP* bs, const char *CA2file, const char *CA1file,
+ const char *CApath, const char* notCertFile);
+
+extern int writeCertToXMLFile(BIO* bout, X509* cert);
+
+//==========< utility functions >====================
+
+
+#ifdef WIN32
+ CRITICAL_SECTION cs_ddocLocaltime;
+#endif
+
+//--------------------------------------------------
+// Converts timestamp (time_t) value to a struct
+// tm value. Caller must provide address of tm struct.
+// This function is used because loacltime() is not
+// thread-safe and win32 has no equvalent of localtime_r().
+// pTime - time_t value address
+// pTmStruct - struct tm address
+// bLocal - 1=localtime_r, 0=gmtime_r
+// returns error code or ERR_OK
+//--------------------------------------------------
+EXP_OPTION int ddocLocalTime(time_t* pTime, struct tm* pTmStruct, int bLocal)
+{
+#ifdef WIN32
+ struct tm *pTm;
+#endif
+ RETURN_IF_NULL_PARAM(pTime);
+ RETURN_IF_NULL_PARAM(pTmStruct);
+
+#ifdef WIN32
+ EnterCriticalSection(&cs_ddocLocaltime);
+ if(bLocal)
+ pTm = localtime(pTime);
+ else
+ pTm = gmtime(pTime);
+ *pTmStruct = *pTm;
+ LeaveCriticalSection(&cs_ddocLocaltime);
+#else
+ if(bLocal)
+ localtime_r(pTime, pTmStruct);
+ else
+ gmtime_r(pTime, pTmStruct);
+#endif
+ return ERR_OK;
+}
+
+
+//==========< admin functions >====================
+
+//--------------------------------------------------
+// returns the library name
+//--------------------------------------------------
+EXP_OPTION const char* getLibName()
+{
+ return g_szLibName;
+}
+
+//--------------------------------------------------
+// returns the library version
+//--------------------------------------------------
+EXP_OPTION const char* getLibVersion()
+{
+ return g_szLibVer;
+}
+
+//--------------------------------------------------
+// returns an array of supported formats terminated by NULL
+//--------------------------------------------------
+EXP_OPTION const char** getSupportedFormats()
+{
+ return (const char**)g_arrFormats;
+}
+
+//--------------------------------------------------
+// returns an array of supported formats and versions terminated by NULL
+//--------------------------------------------------
+EXP_OPTION FormatAndVer* getSupportedFormatsAndVersions()
+{
+ return g_supportedFormatsAndVersions;
+}
+
+//--------------------------------------------------
+// Cheks a combination of format and version for validity
+// format - digidoc format name
+// version - version name
+// returns error code or ERR_OK
+//--------------------------------------------------
+int ddocCheckFormatAndVer(const char* format, const char* version)
+{
+ int i;
+ if(!format || !version)
+ return ERR_UNSUPPORTED_FORMAT;
+ for(i = 0; i < SUPPORTED_VERSION_COUNT; i++)
+ if(!strcmp(g_supportedFormatsAndVersions[i].szFormat, format) &&
+ !strcmp(g_supportedFormatsAndVersions[i].szVersion, version))
+ return ERR_OK;
+ return ERR_UNSUPPORTED_FORMAT;
+}
+
+//--------------------------------------------------
+// initializes DigiDoc library
+//--------------------------------------------------
+EXP_OPTION void initDigiDocLib()
+{
+ memset(g_szGUIVersion, 0, sizeof(g_szGUIVersion));
+#if defined(__FreeBSD__)
+ struct tm local_tm;
+ time_t t;
+ time(&t);
+ ddocLocalTime(&t, &local_tm, 1); // Extract timezone info from struct tm
+ _timezone = - local_tm.tm_gmtoff;
+ _daylight = local_tm.tm_isdst;
+#endif
+ //ddocDebug(1, "initDigiDocLib", "init openssl & digidoc lib");
+ ERR_load_ERR_strings();
+ ERR_load_crypto_strings();
+ ERR_clear_error();
+ OpenSSL_add_all_algorithms();
+ SSL_library_init();
+#ifdef WIN32
+ InitializeCriticalSection(&cs_ddocErrors);
+ InitializeCriticalSection(&cs_ddocLocaltime);
+#endif
+}
+
+//--------------------------------------------------
+// returns the GUI version
+//--------------------------------------------------
+EXP_OPTION const char* getGUIVersion()
+{
+ return g_szGUIVersion;
+}
+
+//--------------------------------------------------
+// sets the GUI version
+//--------------------------------------------------
+EXP_OPTION void setGUIVersion(const char* szVer)
+{
+ strncpy(g_szGUIVersion, szVer, sizeof(g_szGUIVersion)-1);
+}
+
+//--------------------------------------------------
+// cleanup of DigiDoc library
+//--------------------------------------------------
+EXP_OPTION void finalizeDigiDocLib()
+{
+ ERR_free_strings();
+ EVP_cleanup();
+}
+
+//==========< general crypto fucntions >============
+
+
+//--------------------------------------------------
+// Checks and prints errors
+//--------------------------------------------------
+EXP_OPTION long checkErrors()
+{
+ char buf[200];
+ long e=0;
+
+ while((ERR_peek_error()) > ERR_LIB_NONE) {
+ e = ERR_get_error();
+ ERR_error_string_n(e, buf, sizeof(buf));
+ // VS: keep silent !!!
+ printf("ERROR: %ld - %s \n", e, buf);
+ }
+ ERR_clear_error();
+ return e;
+}
+
+
+
+
+//--------------------------------------------------
+// Calculates files SHA1 digest
+// szFileName - file name
+// nDigestType - digest type. Supports only SHA1 (0)
+// pDigestBuf - buffer to store the digest
+// nDigestLen - buffer size, must be at least 20
+// will be updated by actual digest length
+// lFileLen - pointer to a buffer where to store the file length
+// returns error code or ERR_OK for success
+//--------------------------------------------------
+EXP_OPTION int calculateFileDigest(const char* szFileName, int nDigestType,
+ byte* pDigestBuf, int* nDigestLen, long* lFileLen)
+{
+ int err = ERR_OK;
+ byte buf[FILE_BUFSIZE];
+ int i;
+ FILE *f = NULL;
+
+ RETURN_IF_NULL_PARAM(szFileName);
+ RETURN_IF_NULL_PARAM(pDigestBuf);
+ RETURN_IF_NULL_PARAM(nDigestLen);
+ RETURN_IF_NULL_PARAM(lFileLen);
+
+ memset(pDigestBuf, 0, *nDigestLen);
+ if(nDigestType == DIGEST_SHA1) {
+ if(*nDigestLen >= SHA_DIGEST_LENGTH) {
+ SHA_CTX ctx;
+ *nDigestLen = SHA_DIGEST_LENGTH;
+ if((f = fopen(szFileName,"rb")) != NULL) {
+ //byte *data,*temp_data;
+ SHA1_Init(&ctx);
+ *lFileLen = 0;
+ for (;;) {
+ i = fread(buf, sizeof(char), FILE_BUFSIZE, f);
+ if (i <= 0) break;
+ *lFileLen += i;
+ SHA1_Update(&ctx, buf, (unsigned long)i);
+ }
+ SHA1_Final(pDigestBuf,&ctx);
+ fclose(f);
+ } // if - fopen
+ else
+ err = ERR_FILE_READ;
+ }
+ else
+ err = ERR_DIGEST_LEN;
+ } //AM 22.04.08
+ else if(nDigestType == DIGEST_SHA256){
+ if(*nDigestLen >= SHA_DIGEST_LENGTH) {
+ SHA256_CTX ctx;
+ *nDigestLen = SHA256_DIGEST_LENGTH;
+ if((f = fopen(szFileName,"rb")) != NULL) {
+ //byte *data,*temp_data;
+ SHA256_Init(&ctx);
+ *lFileLen = 0;
+ for (;;) {
+ i = fread(buf, sizeof(char), FILE_BUFSIZE, f);
+ if (i <= 0) break;
+ *lFileLen += i;
+ SHA256_Update(&ctx, buf, (unsigned long)i);
+ }
+ SHA256_Final(pDigestBuf,&ctx);
+ fclose(f);
+ } // if - fopen
+ else
+ err = ERR_FILE_READ;
+ }
+ else
+ err = ERR_DIGEST_LEN;
+ }
+ else
+ err = ERR_UNSUPPORTED_DIGEST;
+ if (err != ERR_OK) SET_LAST_ERROR(err);
+ return err;
+}
+
+
+//--------------------------------------------------
+// Calculates file size
+// szFileName - file name
+// lFileLen - pointer to a buffer where to store the file length
+// returns error code or ERR_OK for success
+//--------------------------------------------------
+EXP_OPTION int calculateFileSize(const char* szFileName, long* lFileLen)
+{
+ FILE* hFile = 0;
+#ifdef WIN32
+ int i = 0, err = ERR_OK;
+ wchar_t *convFileName = 0;
+#endif
+
+ RETURN_IF_NULL_PARAM(szFileName);
+ RETURN_IF_NULL_PARAM(lFileLen);
+ if(!szFileName || !strlen(szFileName)) return 0;
+#ifdef WIN32
+ err = utf82unicode((const char*)szFileName, (char**)&convFileName, &i);
+ ddocDebug(3, "calculateFileSize", "Opening FILE: %s, conv-file: %s len: %d", szFileName, convFileName, i);
+ if((hFile = _wfopen(convFileName,L"rb")) != NULL) {
+#else
+ if((hFile = fopen(szFileName,"rb")) != NULL) {
+#endif
+ fseek(hFile, 0, SEEK_END);
+ (*lFileLen) = ftell(hFile);
+ ddocDebug(3, "calculateFileSize", "Closing FILE: %s, size: %ld", szFileName, (*lFileLen));
+ fclose(hFile);
+ } // if - fopen
+ else
+ SET_LAST_ERROR_RETURN_CODE(ERR_FILE_READ);
+#ifdef WIN32
+ if(convFileName) free(convFileName);
+#endif
+
+ return ERR_OK;
+}
+
+
+//--------------------------------------------------
+// Calculates files SHA1-RSA signature
+// szFileName - file name
+// nDigestType - digest type. Supports only SHA1 (0)
+// pSigBuf - buffer to store the signature
+// nSigLen - buffer size, must be at least 128
+// will be updated by actual signature length
+// keyfile - name of the private key file
+// passwd - private key password
+// returns error code or ERR_OK for success
+//--------------------------------------------------
+EXP_OPTION int calculateFileSignature(const char* szFileName, int nDigestType,
+ byte* pSigBuf, int* nSigLen,
+ const char *keyfile, const char* passwd)
+{
+ int err = ERR_OK;
+ EVP_MD_CTX ctx;
+ byte buf[FILE_BUFSIZE];
+ int i;
+ FILE *f = NULL;
+ EVP_PKEY* pkey = NULL;
+
+ RETURN_IF_NULL_PARAM(szFileName);
+ RETURN_IF_NULL_PARAM(pSigBuf);
+ RETURN_IF_NULL_PARAM(nSigLen);
+ RETURN_IF_NULL_PARAM(keyfile);
+ RETURN_IF_NULL_PARAM(passwd);
+
+ memset(pSigBuf, 0, *nSigLen);
+ if(nDigestType == DIGEST_SHA1) {
+ if(*nSigLen >= SIGNATURE_LEN) {
+ if((err = ReadPrivateKey(&pkey, keyfile, passwd, FILE_FORMAT_PEM)) == ERR_OK) {
+ if((f = fopen(szFileName,"rb")) != NULL) {
+ EVP_SignInit(&ctx, EVP_sha1());
+ for (;;) {
+ i = fread(buf, sizeof(char), FILE_BUFSIZE, f);
+ if (i <= 0) break;
+ EVP_SignUpdate (&ctx, buf, (unsigned long)i);
+ }
+ err = EVP_SignFinal(&ctx, pSigBuf, (unsigned int*)nSigLen, pkey);
+ if(err == ERR_LIB_NONE)
+ err = ERR_OK;
+ fclose(f);
+ EVP_PKEY_free(pkey);
+ } // if - fopen
+ else
+ err = ERR_FILE_READ;
+ }
+ else
+ err = ERR_PRIVKEY_READ;
+ }
+ else
+ err = ERR_SIGNATURE_LEN;
+ }
+ else
+ err = ERR_UNSUPPORTED_DIGEST;
+ if (err != ERR_OK) SET_LAST_ERROR(err);
+ return err;
+}
+
+
+//--------------------------------------------------
+// Calculates input datas SHA1-RSA signature
+// data - input data
+// dlen - input data length
+// nDigestType - digest type. Supports only SHA1 (0)
+// pSigBuf - buffer to store the signature
+// nSigLen - buffer size, must be at least 128
+// will be updated by actual signature length
+// keyfile - name of the private key file
+// passwd - private key password
+// returns error code or ERR_OK for success
+//--------------------------------------------------
+EXP_OPTION int signData(const byte* data, int dlen, byte* pSigBuf, int* nSigLen,
+ int nDigestType, const char *keyfile, const char* passwd)
+{
+ int err = ERR_OK;
+ EVP_MD_CTX ctx;
+ EVP_PKEY* pkey;
+
+ RETURN_IF_NULL_PARAM(data);
+ RETURN_IF_NULL_PARAM(pSigBuf);
+ RETURN_IF_NULL_PARAM(nSigLen);
+ RETURN_IF_NULL_PARAM(keyfile);
+ RETURN_IF_NULL_PARAM(passwd);
+
+ memset(pSigBuf, 0, *nSigLen);
+ if(nDigestType == DIGEST_SHA1) {
+ if(*nSigLen >= SIGNATURE_LEN) {
+ if((err = ReadPrivateKey(&pkey, keyfile, passwd, FILE_FORMAT_PEM)) == ERR_OK) {
+ EVP_SignInit(&ctx, EVP_sha1());
+ EVP_SignUpdate (&ctx, data, (unsigned long)dlen);
+ err = EVP_SignFinal(&ctx, pSigBuf, (unsigned int*)nSigLen, pkey);
+ if(err == ERR_LIB_NONE)
+ err = ERR_OK;
+ EVP_PKEY_free(pkey);
+ }
+ else
+ err = ERR_PRIVKEY_READ;
+ }
+ else
+ err = ERR_SIGNATURE_LEN;
+ }
+ else
+ err = ERR_UNSUPPORTED_DIGEST;
+
+ if (err != ERR_OK) SET_LAST_ERROR(err);
+ return err;
+}
+
+//--------------------------------------------------
+// Calculates files SHA1 digest
+// szFileName - file name
+// nDigestType - digest type. Supports only SHA1 (0)
+// pDigestBuf - buffer to store the digest
+// nDigestLen - buffer size, must be at least 20
+// will be updated by actual digest length
+// returns error code or ERR_OK for success
+//--------------------------------------------------
+EXP_OPTION int calculateDigest(const byte* data, int nDataLen, int nDigestType,
+ byte* pDigestBuf, int* nDigestLen)
+{
+ int err = ERR_OK;
+
+ RETURN_IF_NULL_PARAM(data);
+ RETURN_IF_NULL_PARAM(pDigestBuf);
+ RETURN_IF_NULL_PARAM(nDigestLen);
+ memset(pDigestBuf, 0, *nDigestLen);
+ if(nDigestType == DIGEST_SHA1) {
+ if(*nDigestLen >= SHA_DIGEST_LENGTH) {
+ *nDigestLen = SHA_DIGEST_LENGTH;
+ SHA1(data, nDataLen, pDigestBuf);
+ }
+ }//AM 22.04.08
+ else if(nDigestType == DIGEST_SHA256) {
+ if(*nDigestLen >= SHA256_DIGEST_LENGTH) {
+ *nDigestLen = SHA256_DIGEST_LENGTH;
+ SHA256(data, nDataLen, pDigestBuf);
+ }
+ else
+ err = ERR_DIGEST_LEN;
+ }
+ else
+ err = ERR_UNSUPPORTED_DIGEST;
+ if (err != ERR_OK) SET_LAST_ERROR(err);
+ return err;
+}
+
+
+
+
+//==========< signed doc fucntions >================
+
+
+
+//============================================================
+// Get the filename part of full file name
+//============================================================
+EXP_OPTION const char* getSimpleFileName(const char* szFileName)
+{
+ const char *p;
+
+ RETURN_OBJ_IF_NULL(szFileName, NULL);
+
+ for(p = szFileName + strlen(szFileName) -1;
+ (p > szFileName) && (*p != '\\') && (*p != '/');
+ p--);
+ if((*p == '\\') || (*p == '/'))
+ p++;
+ return p;
+}
+
+//============================================================
+// Get the absolute filename with path
+//============================================================
+EXP_OPTION int getFullFileName(const char* szFileName, char* szDest, int len)
+{
+ int err = ERR_OK;
+ memset(szDest, 0, len);
+ // if this is a filename with path then we are ready
+ if(strchr(szFileName, '/') || strchr(szFileName, '\\')) {
+ strncpy(szDest, szFileName, len);
+ } else { // local filename, must prepend directory
+ _getcwd(szDest, len);
+#ifdef WIN32
+ if(strlen(szDest) < (size_t)(len - 2))
+ strncat(szDest, "\\", sizeof(szDest) - strlen(szDest));
+#else
+ if(strlen(szDest) < (size_t)(len - 2))
+ strncat(szDest, "/", sizeof(szDest) - strlen(szDest));
+#endif
+ if(strlen(szDest) + strlen(szFileName) < (size_t)(len - 2))
+ strncat(szDest, szFileName, sizeof(szDest) - strlen(szDest));
+ }
+ return err;
+}
+
+
+//============================================================
+// Get the path part of full file name
+//============================================================
+EXP_OPTION int getFileNamePath(const char* szFileName, char* szPath, int len)
+{
+ int nFound = 0, i, err = ERR_OK;
+
+ RETURN_IF_NULL_PARAM(szFileName);
+ RETURN_IF_NULL_PARAM(szPath);
+ strncpy(szPath, szFileName, len);
+ for(i = strlen(szPath); i >= 0; i--) {
+ if(szPath[i] == '\\') {
+ szPath[i+1] = 0;
+ nFound = 1;
+ break;
+ }
+ }
+ if(!nFound)
+ szPath[0] = 0;
+ return err;
+}
+
+
+//============================================================
+// Gets a new temporary filename
+// buf - filename buffer
+//============================================================
+EXP_OPTION int getTempFileName(char* szFileName, int len)
+{
+ int f = 0;
+ char* pFileName = 0;
+ RETURN_IF_NULL_PARAM(szFileName);
+ memset(szFileName, 0, len);
+#ifdef WIN32
+ pFileName = _tempnam(0, "ddoc");
+#else
+ pFileName = tempnam(0, "ddoc");
+#endif
+ strncpy(szFileName, pFileName, len);
+ free(pFileName);
+ return ERR_OK;
+}
+
+
+//============================================================
+// Sets the signatures certificate and calculates
+// certificate digest & serial number
+// pSigInfo - signature info object
+// cert - certficate
+//============================================================
+EXP_OPTION int setSignatureCert(SignatureInfo* pSigInfo, X509* cert)
+{
+ int err = ERR_OK;
+
+ RETURN_IF_NULL_PARAM(pSigInfo);
+ RETURN_IF_NULL_PARAM(cert);
+ err = ddocSigInfo_addCert(pSigInfo, cert, CERTID_TYPE_SIGNERS_CERTID);
+ // release old content if it exists
+ ddocMemBuf_free(&(pSigInfo->mbufOrigContent));
+ return ERR_OK;
+}
+
+//============================================================
+// Sets the signatures certificate and calculates
+// certificate digest & serial number
+// pSigInfo - signature info object
+// certFile - certficate file in PEM
+//============================================================
+EXP_OPTION int setSignatureCertFile(SignatureInfo* pSigInfo, const char* certFile)
+{
+ X509 *cert = NULL;
+ int err = ERR_OK;
+
+ RETURN_IF_NULL_PARAM(pSigInfo);
+ RETURN_IF_NULL_PARAM(certFile);
+ err = ReadCertificate(&cert, certFile);
+ RETURN_IF_NOT(err == ERR_OK, err);
+ return setSignatureCert(pSigInfo, cert);;
+}
+
+
+//--------------------------------------------------
+// Checks if this file exists
+// szFileName - file name
+// returns 1 if exists
+// AA 2004/05/20 debuggeri all viga, kui null pikkus
+//--------------------------------------------------
+EXP_OPTION int checkFileExists(const char* szFileName)
+{
+ FILE* hFile = 0;
+ int exists = 0;
+#ifdef WIN32
+ int i = 0, err = ERR_OK;
+ wchar_t *convFileName = 0;
+#endif
+ if(szFileName && strlen(szFileName) > 0) {
+#ifdef WIN32
+ err = utf82unicode((const char*)szFileName, (char**)&convFileName, &i);
+ if((hFile = _wfopen(convFileName, L"r")) != NULL) {
+#else
+ if((hFile = fopen(szFileName, "r")) != NULL) {
+#endif
+ exists = 1;
+ fclose(hFile);
+ }
+ }
+#ifdef WIN32
+ if(convFileName) free(convFileName);
+#endif
+ return exists;
+}
+
+
+//================< certficate info functions> =================================
+
+//--------------------------------------------------
+// Returns the user signatures certificate data
+// pSignInfo - signature object
+// returns cert data. This is actually X509*. Obsolete function
+//--------------------------------------------------
+EXP_OPTION X509* getSignCertData(const SignatureInfo* pSignInfo)
+{
+ RETURN_OBJ_IF_NULL(pSignInfo, 0);
+ return ddocSigInfo_GetSignersCert(pSignInfo);
+}
+
+
+//--------------------------------------------------
+// sends an OCSP_REQUES object to remore server and
+// retrieves the OCSP_RESPONSE object
+// resp - buffer to store the new responses pointer
+// req - request objects pointer
+// url - OCSP responder URL
+//--------------------------------------------------
+int ddocPullUrl(const char* url, DigiDocMemBuf* pSendData, DigiDocMemBuf* pRecvData,
+ const char* proxyHost, const char* proxyPort)
+{
+ BIO* cbio = 0, *sbio = 0;
+ SSL_CTX *ctx = NULL;
+ char *host = NULL, *port = NULL, *path = "/", buf[200];
+ int err = ERR_OK, use_ssl = -1, rc;
+ long e;
+
+ //RETURN_IF_NULL_PARAM(pSendData); // may be null if nothing to send?
+ RETURN_IF_NULL_PARAM(pRecvData);
+ RETURN_IF_NULL_PARAM(url);
+
+ ddocDebug(4, "ddocPullUrl", "URL: %s, in: %d bytes", url, pSendData->nLen);
+ //there is an HTTP proxy - connect to that instead of the target host
+ if (proxyHost != 0 && *proxyHost != '\0') {
+ host = (char*)proxyHost;
+ if(proxyPort != 0 && *proxyPort != '\0')
+ port = (char*)proxyPort;
+ path = (char*)url;
+ } else {
+ if(OCSP_parse_url((char*)url, &host, &port, &path, &use_ssl) == 0) {
+ ddocDebug(1, "ddocPullUrl", "Failed to parse the URL");
+ return ERR_WRONG_URL_OR_PROXY;
+ }
+ }
+
+ if((cbio = BIO_new_connect(host)) != 0) {
+ ddocDebug(4, "ddocPullUrl", "Host: %s port: %s", host, port);
+ if(port != NULL) {
+ BIO_set_conn_port(cbio, port);
+ }
+ if(use_ssl == 1) {
+ ctx = SSL_CTX_new(SSLv23_client_method());
+ SSL_CTX_set_mode(ctx, SSL_MODE_AUTO_RETRY);
+ sbio = BIO_new_ssl(ctx, 1);
+ cbio = BIO_push(sbio, cbio);
+ }
+ if ((rc = BIO_do_connect(cbio)) > 0) {
+ ddocDebug(4, "ddocPullUrl", "Connected: %d", rc);
+ if(pSendData && pSendData->nLen && pSendData->pMem) {
+ rc = BIO_write(cbio, pSendData->pMem, pSendData->nLen);
+ ddocDebug(4, "ddocPullUrl", "Sent: %d bytes, got: %d", pSendData->nLen, rc);
+ }
+ do {
+ memset(buf, 0, sizeof(buf));
+ rc = BIO_read(cbio, buf, sizeof(buf)-1);
+ ddocDebug(4, "ddocPullUrl", "Received: %d bytes\n", rc);
+ if(rc > 0)
+ err = ddocMemAppendData(pRecvData, buf, rc);
+ } while(rc > 0);
+ ddocDebug(4, "ddocPullUrl", "Total received: %d bytes\n", pRecvData->nLen);
+ } else {
+ //if no connection
+ e = checkErrors();
+ if(ERR_GET_REASON(e) == BIO_R_BAD_HOSTNAME_LOOKUP ||
+ ERR_GET_REASON(e) == OCSP_R_SERVER_WRITE_ERROR)
+ err = ERR_CONNECTION_FAILURE;
+ else
+ err = (host != NULL) ? ERR_WRONG_URL_OR_PROXY : ERR_CONNECTION_FAILURE;
+ }
+ BIO_free_all(cbio);
+ if (use_ssl != -1) {
+ OPENSSL_free(host);
+ OPENSSL_free(port);
+ OPENSSL_free(path);
+ SSL_CTX_free(ctx);
+ }
+ }
+ else
+ err = ERR_CONNECTION_FAILURE;
+ return(err);
+}
+
+
+
+
+// ASN1 structure prefix - RSA-SHA1 signature with 20 bytes follows
+char g_sigPrefix[] = { 48, 33, 48, 9, 6, 5, 43, 14, 3, 2, 26, 5, 0, 4, 20 };
+
+//--------------------------------------------------
+// Prepares a new signature for signing and calculates
+// the final hash value to sign.
+// pSigDoc - signed document object
+// ppSigInfo - pointer for address of newly allocated signature
+// manifest - manifest or role
+// city - signers address , city
+// state - signers address , state or province
+// zip - signers address , postal code
+// country - signers address , country name
+// id - id for new signature. Optional, use NULL for default
+// return returns error code or ERR_OK
+//--------------------------------------------------
+EXP_OPTION int ddocPrepareSignature(SignedDoc* pSigDoc, SignatureInfo** ppSigInfo,
+ const char* manifest, const char* city,
+ const char* state, const char* zip,
+ const char* country, X509* pCert, const char* id)
+{
+ int err = ERR_OK, l1;
+ DigiDocMemBuf mbuf1, *pMBuf1;
+ char buf1[50];
+
+ mbuf1.pMem = 0;
+ mbuf1.nLen = 0;
+ ddocDebug(3, "ddocPrepareSignature", "Preparing signature manifest: %s country: %s, state: %s, city: %s, zip: %s, cert: %s, id: %s",
+ (manifest ? manifest : "NULL"), (country ? country : "NULL"),
+ (state ? state : "NULL"), (city ? city : "NULL"), (zip ? zip : "NULL"),
+ (pCert ? "OK" : "ERROR"), (id ? id : "NULL"));
+ // check mandator fields
+ RETURN_IF_NULL_PARAM(pSigDoc);
+ RETURN_IF_NULL_PARAM(ppSigInfo);
+ RETURN_IF_NULL_PARAM(pCert);
+ clearErrors();
+ // add new signature
+ err = SignatureInfo_new(ppSigInfo, pSigDoc, id);
+ RETURN_IF_NOT(err == ERR_OK, err);
+ // automatically calculate doc-info elements for this signature
+ addAllDocInfos(pSigDoc, *ppSigInfo);
+ // add signature production place
+ if (city || state || zip || country)
+ err = setSignatureProductionPlace(*ppSigInfo, city, state, zip, country);
+ // add user roles/manifests
+ if (manifest)
+ err = addSignerRole(*ppSigInfo, 0, manifest, -1, 0);
+ RETURN_IF_NOT(err == ERR_OK, err);
+ // add signers certificate
+ err = setSignatureCert(*ppSigInfo, pCert);
+ RETURN_IF_NOT(err == ERR_OK, err);
+ // timestamp
+ createTimestamp(pSigDoc, (char*)buf1, sizeof(buf1));
+ setString((char**)&((*ppSigInfo)->szTimeStamp), (const char*)buf1, -1);
+ // now calculate signed properties digest
+ err = calculateSignedPropertiesDigest(pSigDoc, *ppSigInfo);
+ // TODO: replace later
+ pMBuf1 = ddocDigestValue_GetDigestValue((*ppSigInfo)->pSigPropDigest);
+ ddocSigInfo_SetSigPropRealDigest(*ppSigInfo,
+ (const char*)pMBuf1->pMem, pMBuf1->nLen);
+ // signature type & val
+ ddocSignatureValue_new(&((*ppSigInfo)->pSigValue), 0, SIGN_RSA_NAME, 0, 0);
+ // calc signed-info digest
+ l1 = sizeof(buf1);
+ err = calculateSignedInfoDigest(pSigDoc, *ppSigInfo, (byte*)buf1, &l1);
+ err = ddocSigInfo_SetSigInfoRealDigest(*ppSigInfo, buf1, l1);
+ // debug output - final hash to sign
+ pMBuf1 = ddocDigestValue_GetDigestValue((*ppSigInfo)->pSigInfoRealDigest);
+ ddocEncodeBase64(pMBuf1, &mbuf1);
+ ddocDebug(3, "ddocPrepareSignature", "signing hash %s len: %d b64len: %d",
+ (char*)mbuf1.pMem, mbuf1.nLen, l1);
+ ddocMemBuf_free(&mbuf1);
+ return err;
+}
+
+//--------------------------------------------------
+// Returns the hash to be signed with or without ASN1
+// prefix and with or without base64 encoding
+// pSigInfo - signature address
+// pBuf - buffer for hash value with or without prefix
+// pBufLen - pointer to buffer length
+// enc - return 0=unencoded, 1=base64, 2=hex
+// bWithAsn1Prefix - return with or without ASN1 prefix 1/0
+// return returns error code or ERR_OK
+//--------------------------------------------------
+EXP_OPTION int ddocGetSignedHash(SignatureInfo* pSigInfo,
+ char* pBuf, int* pBufLen, int enc, int bWithAsn1Prefix)
+{
+ int err = ERR_OK, l1 = 0;
+ char buf1[50];
+ DigiDocMemBuf *pMBuf;
+
+ RETURN_IF_NULL_PARAM(pSigInfo);
+ RETURN_IF_NULL_PARAM(pBuf);
+ //RETURN_IF_NOT(err == ERR_OK, err);
+ // TODO: check buflen
+ pMBuf = ddocDigestValue_GetDigestValue(pSigInfo->pSigInfoRealDigest);
+ RETURN_IF_NULL_PARAM(pMBuf);
+ memset(buf1, 0, sizeof(buf1));
+ if(enc == 2) { // hex mode
+ if(bWithAsn1Prefix) {
+ if(sizeof(buf1) > sizeof(g_sigPrefix) + pMBuf->nLen) {
+ memcpy(buf1, g_sigPrefix, sizeof(g_sigPrefix));
+ memcpy(buf1 + sizeof(g_sigPrefix), pMBuf->pMem, pMBuf->nLen);
+ l1 = pMBuf->nLen + sizeof(g_sigPrefix);
+ }
+ else
+ err = ERR_BUF_LEN;
+ }
+ else {
+ if(sizeof(buf1) > (size_t)pMBuf->nLen) {
+ memcpy(buf1, pMBuf->pMem, pMBuf->nLen);
+ l1 = pMBuf->nLen;
+ }
+ else
+ err = ERR_BUF_LEN;
+ }
+ bin2hex((const byte*)buf1, l1, (char*)pBuf, pBufLen);
+ } else if(enc == 1) { // base64 mode
+ if(bWithAsn1Prefix) {
+ if(sizeof(buf1) > sizeof(g_sigPrefix) + (size_t)pMBuf->nLen) {
+ memcpy(buf1, g_sigPrefix, sizeof(g_sigPrefix));
+ memcpy(buf1 + sizeof(g_sigPrefix), pMBuf->pMem, pMBuf->nLen);
+ l1 = pMBuf->nLen + sizeof(g_sigPrefix);
+ }
+ else
+ err = ERR_BUF_LEN;
+ }
+ else {
+ if(sizeof(buf1) > (size_t)pMBuf->nLen) {
+ memcpy(buf1, pMBuf->pMem, pMBuf->nLen);
+ l1 = pMBuf->nLen;
+ }
+ else
+ err = ERR_BUF_LEN;
+ }
+ encode((const byte*)buf1, l1, (byte*)pBuf, pBufLen);
+ } else {
+ if(bWithAsn1Prefix) {
+ if(*pBufLen > (int)sizeof(g_sigPrefix) + pMBuf->nLen) {
+ memcpy(pBuf, g_sigPrefix, sizeof(g_sigPrefix));
+ memcpy(pBuf + sizeof(g_sigPrefix), pMBuf->pMem, pMBuf->nLen);
+ *pBufLen = pMBuf->nLen + sizeof(g_sigPrefix);
+ }
+ else
+ err = ERR_BUF_LEN;
+ }
+ else {
+ if(*pBufLen > pMBuf->nLen) {
+ *pBufLen = pMBuf->nLen;
+ memcpy(pBuf, pMBuf->pMem, pMBuf->nLen);
+ }
+ else
+ err = ERR_BUF_LEN;
+ }
+ }
+ return err;
+}
+
+//================< deprecated functions> =================================
+
+#ifdef WITH_DEPRECATED_FUNCTIONS
+
+// get signers id-code
+EXP_OPTION int getSignerCode(const SignatureInfo* pSigInfo, char* buf)
+{
+ int err, l1;
+ X509* cert;
+ char buf1[500], *p;
+
+ RETURN_IF_NULL_PARAM(pSigInfo);
+ RETURN_IF_NULL_PARAM(buf);
+ cert = getSignCertData(pSigInfo);
+ if (!cert) SET_LAST_ERROR_RETURN_CODE(ERR_CERT_INVALID);
+ l1 = sizeof(buf1);
+ err = getCertSubjectName(cert, buf1, &l1);
+ if (err != ERR_OK) SET_LAST_ERROR_RETURN_CODE(err);
+ err = ERR_CERT_READ;
+ p = strstr(buf1, "CN=");
+ if (p) {
+ p = strchr(p, ',');
+ if(p) {
+ p = strchr(p+1, ',');
+ if(p) {
+ strncpy(buf, p+1, 11);
+ buf[11] = 0;
+ err = ERR_OK;
+ }
+ } else { // no comma -> no id-code !
+ buf[0] = 0;
+ // is this really an error ?
+ err = ERR_WRONG_CERT;
+ }
+ }
+ if (err != ERR_OK) SET_LAST_ERROR(err);
+ return err;
+}
+
+// get signers first name
+EXP_OPTION int getSignerFirstName(const SignatureInfo* pSigInfo, char* buf)
+{
+ int err = ERR_OK, l1;
+ X509* cert;
+ char buf1[500], *p, *p2, *p1;
+
+ RETURN_IF_NULL_PARAM(pSigInfo);
+ RETURN_IF_NULL_PARAM(buf);
+ cert = getSignCertData(pSigInfo);
+ if (!cert) SET_LAST_ERROR_RETURN_CODE(ERR_CERT_INVALID);
+ l1 = sizeof(buf1);
+ err = getCertSubjectName(cert, buf1, &l1);
+ if (err != ERR_OK) SET_LAST_ERROR_RETURN_CODE(err);
+ p = strstr(buf1, "CN=");
+ if (p) {
+ p1 = strchr(p, ',');
+ if(!p1)
+ p1 = strchr(p, '/');
+ if (p1) {
+ p1 += 1;
+ p2 = strchr(p1, ',');
+ if(!p2)
+ p2 = strchr(p1, '/');
+ if(p2) {
+ strncpy(buf, p1, p2-p1);
+ buf[p2-p1] = 0;
+ err = ERR_OK;
+ }
+ }
+ }
+ if (err != ERR_OK) SET_LAST_ERROR(err);
+ return err;
+}
+
+// get signers last name
+EXP_OPTION int getSignerLastName(const SignatureInfo* pSigInfo, char* buf)
+{
+ int err = ERR_OK, l1;
+ X509* cert;
+ char buf1[500], *p, *p2;
+
+ RETURN_IF_NULL_PARAM(pSigInfo);
+ RETURN_IF_NULL_PARAM(buf);
+ cert = getSignCertData(pSigInfo);
+ if (!cert) SET_LAST_ERROR_RETURN_CODE(ERR_CERT_INVALID);
+ l1 = sizeof(buf1);
+ err = getCertSubjectName(cert, buf1, &l1);
+ if (err != ERR_OK) SET_LAST_ERROR_RETURN_CODE(err);
+ p = strstr(buf1, "CN=");
+ if(p) {
+ p += 3;
+ p2 = strchr(p, ',');
+ if(!p2)
+ p2 = strchr(p, '/');
+ if(p2) {
+ strncpy(buf, p, p2-p);
+ buf[p2-p] = 0;
+ err = ERR_OK;
+ } else {
+ strncpy(buf, p, strlen(p));
+ }
+ }
+ if (err != ERR_OK) SET_LAST_ERROR(err);
+ return err;
+}
+
+EXP_OPTION int getSignerCN(const SignatureInfo* pSigInfo, char* buf, int bUTF8)
+{
+ int err = ERR_OK, l1;
+ X509* cert;
+ char buf1[500], *p, *p2, buf2[500];
+
+ RETURN_IF_NULL_PARAM(pSigInfo);
+ RETURN_IF_NULL_PARAM(buf);
+ cert = getSignCertData(pSigInfo);
+ if (!cert) SET_LAST_ERROR_RETURN_CODE(ERR_CERT_INVALID);
+ l1 = sizeof(buf1);
+ err = getCertSubjectName(cert, buf1, &l1);
+ if (err != ERR_OK) SET_LAST_ERROR_RETURN_CODE(err);
+ if(!bUTF8) {
+ l1 = sizeof(buf2);
+ utf82ascii(buf1, buf2, &l1);
+ strncpy(buf1, buf2, sizeof(buf1));
+ }
+ err = ERR_CERT_READ;
+ p = strstr(buf1, "CN=");
+ if (p) {
+ p += 3;
+ p2 = strchr(p, '/');
+ if(!p2)
+ p2 = p + strlen(p);
+ if (p2) {
+ strncpy(buf, p, p2-p);
+ buf[p2-p] = 0;
+ err = ERR_OK;
+ }
+ }
+
+ if (err != ERR_OK) SET_LAST_ERROR(err);
+ return err;
+}
+
+#endif // WITH_DEPRECATED_FUNCTIONS
+
+
diff --git a/libdigidoc/DigiDocLib.h b/libdigidoc/DigiDocLib.h
new file mode 100644
index 0000000..51220ef
--- /dev/null
+++ b/libdigidoc/DigiDocLib.h
@@ -0,0 +1,239 @@
+#ifndef __DIGI_DOC_LIB_H__
+#define __DIGI_DOC_LIB_H__
+//==================================================
+// FILE: DigiDocLib.h
+// PROJECT: Digi Doc
+// DESCRIPTION: Digi Doc functions for creating
+// and reading signed documents.
+// AUTHOR: Veiko Sinivee, S|E|B IT Partner Estonia
+//==================================================
+// Copyright (C) AS Sertifitseerimiskeskus
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.ode
+// GNU Lesser General Public Licence is available at
+// http://www.gnu.org/copyleft/lesser.html
+//==========< HISTORY >=============================
+// 10.02.2004 Integrated
+// 02.01.2004 Veiko Sinivee
+// Added support for format 1.3
+// 29.10.2003 Aare Amenberg
+// Added some function headers
+// (needed for compiling COM)
+// 1.0 09.04.2002 Veiko Sinivee
+// Supports XML format (Type: SK-XML-1.0)
+//==================================================
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <openssl/x509.h>
+#include <openssl/ocsp.h>
+#include <libdigidoc/DigiDocMem.h>
+#include <libdigidoc/DigiDocDefs.h>
+#include <libdigidoc/DigiDocError.h>
+#include <libdigidoc/DigiDocObj.h>
+#include <libdigidoc/DigiDocVerify.h>
+
+
+//==========< data structures >====================
+
+// supported format and version combination
+typedef struct FormatAndVer_st {
+ char* szFormat;
+ char* szVersion;
+} FormatAndVer;
+
+
+//==========< admin functions >====================
+
+// returns the library name
+EXP_OPTION const char* getLibName();
+// returns the library version
+EXP_OPTION const char* getLibVersion();
+// returns an array of supported formats terminated by NULL
+EXP_OPTION const char** getSupportedFormats();
+// returns an array of supported formats and versions terminated by NULL
+EXP_OPTION FormatAndVer* getSupportedFormatsAndVersions();
+// returns the GUI version
+EXP_OPTION const char* getGUIVersion();
+// sets the GUI version
+EXP_OPTION void setGUIVersion(const char* szVer);
+
+// initializes error library
+EXP_OPTION void initDigiDocLib();
+// cleanup of error library
+EXP_OPTION void finalizeDigiDocLib();
+
+// trim leading and trailing whitespace
+EXP_OPTION char* trim(char* src);
+
+// Sets a string element of a struct to a new value
+EXP_OPTION int setString(char** dest, const char* value, int valLen);
+
+EXP_OPTION int checkFileExists(const char* szFileName);
+
+int ddocPullUrl(const char* url, DigiDocMemBuf* pSendData, DigiDocMemBuf* pRecvData,
+ const char* proxyHost, const char* proxyPort);
+
+// Cheks a combination of format and version for validity
+int ddocCheckFormatAndVer(const char* format, const char* version);
+
+
+//--------------------------------------------------
+// Converts timestamp (time_t) value to a struct
+// tm value. Caller must provide address of tm struct.
+// This function is used because loacltime() is not
+// thread-safe and win32 has no equvalent of localtime_r().
+// pTime - time_t value address
+// pTmStruct - struct tm address
+// bLocal - 1=localtime_r, 0=gmtime_r
+// returns error code or ERR_OK
+//--------------------------------------------------
+EXP_OPTION int ddocLocalTime(time_t* pTime, struct tm* pTmStruct, int bLocal);
+
+EXP_OPTION int getTempFileName(char* szFileName, int len);
+
+//==========< general crypto fucntions >============
+
+// calculates input files digest.
+// supports only SHA1
+EXP_OPTION int calculateFileDigest(const char* szFileName, int nDigestType,
+ byte* pDigestBuf, int* nDigestLen, long* lFileLen);
+
+// calculate file size
+EXP_OPTION int calculateFileSize(const char* szFileName, long* lFileLen);
+
+// calculates files RSA+SHA1 signature
+EXP_OPTION int calculateFileSignature(const char* szFileName, int nDigestType,
+ byte* pSigBuf, int* nSigLen,
+ const char *keyfile, const char* passwd);
+
+// sign some arbitrary daya
+EXP_OPTION int signData(const byte* data, int dlen, byte* pSigBuf, int* nSigLen,
+ int nDigestType, const char *keyfile, const char* passwd);
+
+// calculate digest over some arbitrary data
+EXP_OPTION int calculateDigest(const byte* data, int nDataLen, int nDigestType,
+ byte* pDigestBuf, int* nDigestLen);
+
+
+
+//--------------------------------------------------
+// Prepares a new signature for signing and calculates
+// the final hash value to sign.
+// pSigDoc - signed document object
+// ppSigInfo - pointer for address of newly allocated signature
+// manifest - manifest or role
+// city - signers address , city
+// state - signers address , state or province
+// zip - signers address , postal code
+// country - signers address , country name
+// id - id for new signature. Optional, use NULL for default
+
+// return returns error code or ERR_OK
+//--------------------------------------------------
+EXP_OPTION int ddocPrepareSignature(SignedDoc* pSigDoc, SignatureInfo** ppSigInfo,
+ const char* manifest, const char* city,
+ const char* state, const char* zip,
+ const char* country, X509* pCert, const char* id);
+
+//--------------------------------------------------
+// Returns the hash to be signed with or without ASN1
+// prefix and with or without base64 encoding
+// pSigInfo - signature address
+// pBuf - buffer for hash value with or without prefix
+// pBufLen - pointer to buffer length
+// enc - return 0=unencoded, 1=base64, 2=hex
+// bWithAsn1Prefix - return with or without ASN1 prefix 1/0
+// return returns error code or ERR_OK
+//--------------------------------------------------
+EXP_OPTION int ddocGetSignedHash(SignatureInfo* pSigInfo, char* pBuf, int* pBufLen, int enc, int bWithAsn1Prefix);
+
+
+//==========< XML generating functions >=================
+// thse functions generate certain XML form info, that
+// is used as input data for either signing or digesting
+
+// creates XML <SignedInfo> block (actually signed info)
+EXP_OPTION char* createXMLSignedInfo(const SignedDoc* pSigDoc, const SignatureInfo* pSigInfo);
+// creates XML mime type <SinatureProperty> block for signing
+EXP_OPTION int createMimeType(char* buf, const char* mime,
+ const char* sigId, const char* docId);
+
+//==========< memory mgmt functions >=================
+
+// Get the filename part of full file name
+EXP_OPTION const char* getSimpleFileName(const char* szFileName);
+// Get the absolute filename with path
+EXP_OPTION int getFullFileName(const char* szFileName, char* szDest, int len);
+// Get the path part of full file name
+ EXP_OPTION int getFileNamePath(const char* szFileName, char* szPath, int len);
+
+
+//------------------------ ??
+
+// Sets the signatures certificate and calculates
+EXP_OPTION int setSignatureCertFile(SignatureInfo* pSigInfo, const char* certFile);
+// Sets the signatures certificate and calculates it's digest
+EXP_OPTION int setSignatureCert(SignatureInfo* pSigInfo, X509* cert);
+
+// Sets the signature value
+EXP_OPTION int setSignatureValue(SignatureInfo* pSigInfo, byte* szSignature, int sigLen);
+
+// Sets the signature value from a file that contains
+// the base64 encoded signature value
+EXP_OPTION int setSignatureValueFromFile(SignatureInfo* pSigInfo, char* szSigFile);
+
+
+//================< certficate info functions> =================================
+
+// Decodes a signature value
+void decodeSignatureValue(const char* b64val, int b64len, char* value, int* vlen);
+
+// Returns the user signatures certificate data
+EXP_OPTION X509* getSignCertData(const SignatureInfo* pSignInfo);
+// Returns the notary signatures certificate data
+//EXP_OPTION X509* getNotCertData(const NotaryInfo* pNotInfo);
+
+
+
+//================< deprecated functions> =================================
+// these functions are deprecated. Use the replacements in DigiDocCert.h
+// these functions will be removed in future releases!
+#ifdef WITH_DEPRECATED_FUNCTIONS
+
+// get signers id-code
+// USE: ddocCertGetSubjectPerCode(getSignCertData(pSignInfo), pMemBuf);
+EXP_OPTION int getSignerCode(const SignatureInfo* pSigInfo, char* buf);
+
+// get signers first name
+// USE: ddocCertGetSubjectFirstName(getSignCertData(pSignInfo), pMemBuf);
+EXP_OPTION int getSignerFirstName(const SignatureInfo* pSigInfo, char* buf);
+
+// get signers last name
+// USE: ddocCertGetSubjectLastName(getSignCertData(pSignInfo), pMemBuf);
+EXP_OPTION int getSignerLastName(const SignatureInfo* pSigInfo, char* buf);
+
+// get the whole signers CN in desired charset
+// USE: ddocCertGetSubjectCN(getSignCertData(pSignInfo), pMemBuf);
+EXP_OPTION int getSignerCN(const SignatureInfo* pSigInfo, char* buf, int bUTF8);
+
+#endif // WITH_DEPRECATED_FUNCTIONS
+
+//==================================================================================
+void CorrectCharacters(char *psText);
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif // __DIGI_DOC_LIB_H__
+
diff --git a/libdigidoc/DigiDocMem.c b/libdigidoc/DigiDocMem.c
new file mode 100644
index 0000000..f026452
--- /dev/null
+++ b/libdigidoc/DigiDocMem.c
@@ -0,0 +1,291 @@
+//==================================================
+// FILE: DigiDocMem.c
+// PROJECT: Digi Doc
+// DESCRIPTION: Digi Doc functions for memory buffer management
+// AUTHOR: Veiko Sinivee, S|E|B IT Partner Estonia
+//==================================================
+// Copyright (C) AS Sertifitseerimiskeskus
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+// GNU Lesser General Public Licence is available at
+// http://www.gnu.org/copyleft/lesser.html
+//==========< HISTORY >=============================
+// 09.09.2004 Veiko Sinivee
+// Creation
+//==================================================
+
+#include <libdigidoc/DigiDocMem.h>
+#include <libdigidoc/DigiDocLib.h>
+#include <libdigidoc/DigiDocError.h>
+#include <libdigidoc/DigiDocDebug.h>
+#include <string.h>
+
+//--------------------------------------------------
+// Helper function to append data to a memory buffer
+// and grow it as required.
+// pBuf - address of memory buffer pointer
+// data - new data to be appended
+// len - length of data or -1 for zero terminated strings
+//--------------------------------------------------
+EXP_OPTION int ddocMemAppendData(DigiDocMemBuf* pBuf, const char* data, long len)
+{
+ long addLen = len;
+
+ RETURN_IF_NULL_PARAM(pBuf);
+ RETURN_IF_NULL_PARAM(data);
+ if(addLen == -1)
+ addLen = strlen(data);
+ // ddocDebug(7, "ddocAppendData", "Len: %ld data: \'%s\'", addLen, data);
+ pBuf->pMem = realloc(pBuf->pMem, pBuf->nLen + addLen + 1);
+ if(!pBuf->pMem)
+ SET_LAST_ERROR_RETURN(ERR_BAD_ALLOC, ERR_BAD_ALLOC);
+ memset((char*)pBuf->pMem + pBuf->nLen, 0, addLen+1);
+ memcpy((char*)pBuf->pMem + pBuf->nLen, data, addLen);
+ pBuf->nLen += addLen;
+ // ddocDebug(8, "ddocAppendData", "BUFFER Len: %ld data:\'%s\'", pBuf->nLen, pBuf->pMem);
+ return ERR_OK;
+}
+
+//--------------------------------------------------
+// Helper function to set buffer length as required
+// It will fill acquired mem with zeros.
+// pBuf - address of memory buffer pointer
+// len - new length of buffer
+//--------------------------------------------------
+EXP_OPTION int ddocMemSetLength(DigiDocMemBuf* pBuf, long len)
+{
+ long addLen = len;
+
+ RETURN_IF_NULL_PARAM(pBuf);
+ addLen = len - pBuf->nLen;
+ // ddocDebug(7, "ddocMemSetLength", "Len: %ld", addLen);
+ pBuf->pMem = realloc(pBuf->pMem, pBuf->nLen + addLen + 1);
+ if(!pBuf->pMem)
+ SET_LAST_ERROR_RETURN(ERR_BAD_ALLOC, ERR_BAD_ALLOC);
+ memset((char*)pBuf->pMem + pBuf->nLen, 0, addLen+1);
+ pBuf->nLen += addLen;
+ // ddocDebug(8, "ddocMemSetLength", "BUFFER Len: %ld data:\'%s\'", pBuf->nLen, pBuf->pMem);
+ return ERR_OK;
+}
+
+//--------------------------------------------------
+// Helper function to assign data to a memory buffer
+// and release old content if necessary
+// pBuf - address of memory buffer pointer
+// data - new data to be appended
+// len - length of data or -1 for zero terminated strings
+//--------------------------------------------------
+EXP_OPTION int ddocMemAssignData(DigiDocMemBuf* pBuf, const char* data, long len)
+{
+ RETURN_IF_NULL_PARAM(pBuf);
+ RETURN_IF_NULL_PARAM(data);
+ // ddocDebug(7, "ddocAssignData", "Len: %d data: \'%s\'", len, data);
+ if(pBuf->pMem)
+ free(pBuf->pMem);
+ pBuf->pMem = 0;
+ pBuf->nLen = 0;
+ return ddocMemAppendData(pBuf, data, len);
+}
+
+EXP_OPTION int ddocMemAssignData2(DigiDocMemBuf* pBuf, const char* data, long len)
+{
+ RETURN_IF_NULL_PARAM(pBuf);
+ RETURN_IF_NULL_PARAM(data);
+ // ddocDebug(7, "ddocAssignData", "Len: %d data: \'%s\'", len, data);
+ pBuf->pMem = 0;
+ pBuf->nLen = 0;
+ return ddocMemAppendData(pBuf, data, len);
+}
+
+//--------------------------------------------------
+// Helper function to free/cleanup memory buffer
+// This does not attempt to release the buffer object
+// itself but only it's contents.
+// pBuf - memory buffer pointer
+//--------------------------------------------------
+EXP_OPTION int ddocMemBuf_free(DigiDocMemBuf* pBuf)
+{
+ RETURN_IF_NULL_PARAM(pBuf);
+ if(pBuf->pMem)
+ free(pBuf->pMem);
+ pBuf->pMem = 0;
+ pBuf->nLen = 0;
+ return ERR_OK;
+}
+
+
+//--------------------------------------------------
+// Helper function to assign zero terminated strings
+// and release old content if necessary
+// dest - destination address
+// src - new data to be assigned
+//--------------------------------------------------
+EXP_OPTION int ddocMemAssignString(char** dest, const char* src)
+{
+ int i;
+ RETURN_IF_NULL_PARAM(dest);
+ RETURN_IF_NULL_PARAM(src);
+
+ if(*dest)
+ free(*dest);
+ i = strlen(src) + 10;
+ *dest = malloc(i);
+ if(*dest) {
+ memset(*dest, 0, i);
+ strncpy(*dest, src, strlen(src));
+ }
+ //*dest = (char*)strdup(src);
+ if(!dest)
+ SET_LAST_ERROR_RETURN(ERR_BAD_ALLOC, ERR_BAD_ALLOC)
+ else
+ return ERR_OK;
+}
+
+//--------------------------------------------------
+// Replaces a substring with another substring
+// pBuf1 - memory buffer to search in
+// pBuf2 - memory buffer to write converted value to
+// search - search value
+// replacement - replacement value
+//--------------------------------------------------
+EXP_OPTION int ddocMemReplaceSubstr(DigiDocMemBuf* pBuf1, DigiDocMemBuf* pBuf2,
+ const char* search, const char* replacement)
+{
+ int err = ERR_OK, i, n;
+
+ RETURN_IF_NULL_PARAM(pBuf1);
+ RETURN_IF_NULL_PARAM(pBuf1->pMem);
+ RETURN_IF_NULL_PARAM(pBuf2);
+ RETURN_IF_NULL_PARAM(search);
+ RETURN_IF_NULL_PARAM(replacement);
+ //ddocDebug(7, "ddocMemReplaceSubstr", "Replace: \'%s\' with: \'%s\' in: \'%s\'",
+ // search, replacement, (const char*)pBuf1->pMem);
+ ddocMemBuf_free(pBuf2);
+ n = strlen(search);
+ for(i = 0; !err && (i < pBuf1->nLen); i++) {
+ if(!strncmp((char*)pBuf1->pMem + i, search, n)) { // match
+ err = ddocMemAppendData(pBuf2, replacement, -1);
+ i += strlen(search) - 1;
+ } else { // no match
+ err = ddocMemAppendData(pBuf2, (char*)pBuf1->pMem + i, 1);
+ }
+ }
+ return err;
+}
+//AM SMARTLINK
+EXP_OPTION int ddocMemGetSubstr(DigiDocMemBuf* pBuf1, DigiDocMemBuf* pBuf2,
+ const char* search, const char* replacement)
+{
+ int err = ERR_OK, i, n,found=0;
+
+ RETURN_IF_NULL_PARAM(pBuf1);
+ RETURN_IF_NULL_PARAM(pBuf1->pMem);
+ RETURN_IF_NULL_PARAM(pBuf2);
+ RETURN_IF_NULL_PARAM(search);
+ RETURN_IF_NULL_PARAM(replacement);
+ //ddocDebug(7, "ddocMemReplaceSubstr", "Replace: \'%s\' with: \'%s\' in: \'%s\'",
+ // search, replacement, (const char*)pBuf1->pMem);
+ ddocMemBuf_free(pBuf2);
+ n = strlen(search);
+ for(i = 0; !err && (i < pBuf1->nLen); i++) {
+ if(!strncmp((char*)pBuf1->pMem + i, search, n) && !found) { // match
+ err = ddocMemAppendData(pBuf2, search, -1);
+ i += strlen(search) - 1; found = 1;
+ } else if (found){
+ if(!strncmp((char*)pBuf1->pMem + i, replacement, n) && found) { // match
+ err = ddocMemAppendData(pBuf2, replacement, -1);
+ i += strlen(replacement) - 1; break;
+ }
+ err = ddocMemAppendData(pBuf2, (char*)pBuf1->pMem + i, 1);
+ }
+ }
+ return err;
+}
+
+
+//--------------------------------------------------
+// Replaces a substring with another substring
+// pBuf1 - memory buffer to search in
+// pBuf2 - memory buffer to write converted value to
+// search - search value
+// replacement - replacement value
+//--------------------------------------------------
+EXP_OPTION char *replaceStr(char *str, char *orig, char *rep)
+{
+ static char buffer[4096];
+ char *p;
+
+ if(!(p = strstr(str, orig)))
+ return str;
+
+ strncpy(buffer, str, p-str);
+ buffer[p-str] = '\0';
+
+ sprintf(buffer+(p-str), "%s%s", rep, p+strlen(orig));
+
+ return buffer;
+}
+
+
+//--------------------------------------------------
+// Compares memory buffers
+// pBuf1 - memory buffer to value 1
+// pBuf2 - memory buffer to value 2
+// return 0 if both buffers are equal, 1 if not equal
+//--------------------------------------------------
+EXP_OPTION int ddocMemCompareMemBufs(DigiDocMemBuf* pBuf1, DigiDocMemBuf* pBuf2)
+{
+ int i;
+
+ RETURN_IF_NULL_PARAM(pBuf1);
+ RETURN_IF_NULL_PARAM(pBuf1->pMem);
+ RETURN_IF_NULL_PARAM(pBuf2);
+ RETURN_IF_NULL_PARAM(pBuf2->pMem);
+ if(pBuf1->nLen != pBuf2->nLen)
+ return 1;
+ for(i = 0; (i < pBuf1->nLen); i++) {
+ if(((char*)pBuf1->pMem)[i] != ((char*)pBuf2->pMem)[i])
+ return 1;
+ }
+ return 0;
+}
+
+int ddocMemPush(DigiDocMemBuf* pBuf, const char* tag)
+{
+ RETURN_IF_NULL_PARAM(pBuf);
+ RETURN_IF_NULL_PARAM(tag);
+ //ddocDebug(3, "ddocMemPush", "Len: %ld data: \'%s\'", strlen(tag), tag);
+ ddocMemAppendData(pBuf, "/", -1);
+ ddocMemAppendData(pBuf, tag, -1);
+ //ddocDebug(3, "ddocMemPush", "BUFFER Len: %ld data:\'%s\'", pBuf->nLen, pBuf->pMem);
+ return ERR_OK;
+}
+
+const char* ddocMemPop(DigiDocMemBuf* pBuf)
+{
+ char* p = 0;
+ int n = 0;
+
+ // set prt to end
+ if(pBuf && pBuf->nLen > 0) {
+ n = pBuf->nLen - 1;
+ p = &((char*)pBuf->pMem)[pBuf->nLen-1];
+ while(n > 0 && ((char*)pBuf->pMem)[n] != '/') {
+ p--;
+ n--;
+ }
+ if(n >= 0 && *p == '/') {
+ *p = 0;
+ pBuf->nLen = n;
+ p++; // return popped value
+ }
+ }
+ return p;
+}
+
diff --git a/libdigidoc/DigiDocMem.h b/libdigidoc/DigiDocMem.h
new file mode 100644
index 0000000..b5ac805
--- /dev/null
+++ b/libdigidoc/DigiDocMem.h
@@ -0,0 +1,108 @@
+#ifndef __DIGIDOC_MEM_H__
+#define __DIGIDOC_MEM_H__
+//==================================================
+// FILE: DigiDocMem.h
+// PROJECT: Digi Doc
+// DESCRIPTION: Digi Doc functions for memory buffer management
+// AUTHOR: Veiko Sinivee, S|E|B IT Partner Estonia
+//==================================================
+// Copyright (C) AS Sertifitseerimiskeskus
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+// GNU Lesser General Public Licence is available at
+// http://www.gnu.org/copyleft/lesser.html
+//==========< HISTORY >=============================
+// 09.09.2004 Veiko Sinivee
+// Creation
+//==================================================
+
+#include "DigiDocDefs.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+ typedef struct DigiDocMemBuf_st {
+ void* pMem; // functions will assign allocated memory address here
+ long nLen; // length of data in number of bytes
+ } DigiDocMemBuf;
+
+ //--------------------------------------------------
+ // Helper function to append data to a memory buffer
+ // and grow it as required.
+ // pBuf - address of memory buffer pointer
+ // data - new data to be appended
+ // len - length of data or -1 for zero terminated strings
+ //--------------------------------------------------
+ EXP_OPTION int ddocMemAppendData(DigiDocMemBuf* pBuf, const char* data, long len);
+
+ //--------------------------------------------------
+ // Helper function to assign data to a memory buffer
+ // and release old content if necessary
+ // pBuf - address of memory buffer pointer
+ // data - new data to be appended
+ // len - length of data or -1 for zero terminated strings
+ //--------------------------------------------------
+ EXP_OPTION int ddocMemAssignData(DigiDocMemBuf* pBuf, const char* data, long len);
+ EXP_OPTION int ddocMemAssignData2(DigiDocMemBuf* pBuf, const char* data, long len);
+
+ //--------------------------------------------------
+ // Helper function to set buffer length as required
+ // It will fill acquired mem with zeros.
+ // pBuf - address of memory buffer pointer
+ // len - new length of buffer
+ //--------------------------------------------------
+ EXP_OPTION int ddocMemSetLength(DigiDocMemBuf* pBuf, long len);
+
+ //--------------------------------------------------
+ // Helper function to free/cleanup memory buffer
+ // This does not attempt to release the buffer object
+ // itself but only it's contents.
+ // pBuf - memory buffer pointer
+ //--------------------------------------------------
+ EXP_OPTION int ddocMemBuf_free(DigiDocMemBuf* pBuf);
+
+ //--------------------------------------------------
+ // Helper function to assign zero terminated strings
+ // and release old content if necessary
+ // dest - destination address
+ // src - new data to be assigned
+ //--------------------------------------------------
+ EXP_OPTION int ddocMemAssignString(char** dest, const char* src);
+
+ //--------------------------------------------------
+ // Replaces a substring with another substring
+ // pBuf1 - memory buffer to search in
+ // pBuf2 - memory buffer to write converted value to
+ // search - search value
+ // replacement - replacement value
+ //--------------------------------------------------
+ EXP_OPTION int ddocMemReplaceSubstr(DigiDocMemBuf* pBuf1, DigiDocMemBuf* pBuf2,
+ const char* search, const char* replacment);
+ EXP_OPTION int ddocMemGetSubstr(DigiDocMemBuf* pBuf1, DigiDocMemBuf* pBuf2,
+ const char* search, const char* replacment);
+EXP_OPTION char *replaceStr(char *str, char *orig, char *rep);
+ //--------------------------------------------------
+ // Compares memory buffers
+ // pBuf1 - memory buffer to value 1
+ // pBuf2 - memory buffer to value 2
+ // return 0 if both buffers are equal, 1 if not equal
+ //--------------------------------------------------
+ EXP_OPTION int ddocMemCompareMemBufs(DigiDocMemBuf* pBuf1, DigiDocMemBuf* pBuf2);
+
+ int ddocMemPush(DigiDocMemBuf* pBuf1, const char* tag);
+ const char* ddocMemPop(DigiDocMemBuf* pBuf1);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // __DIGIDOC_MEM_H__
diff --git a/libdigidoc/DigiDocOCSP.c b/libdigidoc/DigiDocOCSP.c
new file mode 100644
index 0000000..48973e7
--- /dev/null
+++ b/libdigidoc/DigiDocOCSP.c
@@ -0,0 +1,1670 @@
+//==================================================
+// FILE: DigiDocOCSP.c
+// PROJECT: Digi Doc
+// DESCRIPTION: DigiDoc OCSP handling routines
+// AUTHOR: Veiko Sinivee, S|E|B IT Partner Estonia
+//==================================================
+// Copyright (C) AS Sertifitseerimiskeskus
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+// GNU Lesser General Public Licence is available at
+// http://www.gnu.org/copyleft/lesser.html
+//==========< HISTORY >=============================
+// 26.04.2006 Veiko Sinivee
+// Creation
+//==================================================
+
+#include <libdigidoc/DigiDocConfig.h>
+#include <libdigidoc/DigiDocOCSP.h>
+#include <libdigidoc/DigiDocError.h>
+#include <libdigidoc/DigiDocDebug.h>
+#include <libdigidoc/DigiDocConvert.h>
+#include <libdigidoc/DigiDocLib.h>
+#include <libdigidoc/DigiDocCert.h>
+#include <libdigidoc/DigiDocVerify.h>
+#include <libdigidoc/DigiDocHTTP.h>
+#include <openssl/sha.h>
+#include <openssl/rsa.h>
+#include <openssl/evp.h>
+#include <openssl/objects.h>
+#include <openssl/x509.h>
+#include <openssl/x509v3.h>
+#include <openssl/err.h>
+#include <openssl/pem.h>
+#include <openssl/ssl.h>
+#include <openssl/ocsp.h>
+#include <openssl/pkcs12.h>
+#include <openssl/rand.h>
+#include <ctype.h>
+
+#ifdef FRAMEWORK
+#ifdef __APPLE__
+#include <Security/Security.h>
+#endif
+
+static int password_callback(char *buf, int bufsiz, int verify, void *cb_data)
+{
+ static const char password[] = "pass";
+ int res = strlen(password);
+ if (res > bufsiz)
+ res = bufsiz;
+ memcpy(buf, password, res);
+ return res;
+}
+#endif
+
+//================< OCSP functions> =================================
+
+static int ddocOcspProxyAuthInfo(char *authinfo, const char *user, const char *pass)
+{
+ BIO *b64 = 0, *hash = 0;
+ char *data = 0;
+
+ RETURN_IF_NULL_PARAM(authinfo);
+ authinfo[0] = 0;
+
+ if(!user && !pass)
+ return ERR_OK;
+
+ b64 = BIO_new(BIO_f_base64());
+ RETURN_IF_NOT(b64, ERR_NULL_POINTER);
+ BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL);
+
+ hash = BIO_push(b64, BIO_new(BIO_s_mem()));
+ RETURN_IF_NOT(hash, ERR_NULL_POINTER);
+
+ BIO_printf(hash, "%s:%s", user, pass);
+ (void)BIO_flush(hash);
+
+ BIO_get_mem_data(hash, &data);
+ sprintf(authinfo, "Proxy-Authorization: Basic %s\r\n", data);
+
+ BIO_free_all(hash);
+ return ERR_OK;
+}
+
+
+//============================================================
+// Decodes binary (DER) OCSP_RESPONSE data and returns a OCSP_RESPONSE object
+// ppResp - pointer to a buffer to receive newly allocated OCSP_RESPONSE pointer
+// data - (DER) OCSP_RESPONSE data
+// len - length of data in bytes
+//============================================================
+EXP_OPTION int ddocDecodeOCSPResponseData(OCSP_RESPONSE **ppResp, const byte* data, int len)
+{
+ BIO* b1 = 0;
+
+ // check input params
+ RETURN_IF_NULL_PARAM(data);
+ RETURN_IF_NULL_PARAM(ppResp);
+ // mark as not read yet
+ *ppResp = 0;
+ // create BIO
+ b1 = BIO_new_mem_buf((void*)data, len);
+ RETURN_IF_NOT(b1, ERR_NULL_POINTER);
+ // decode OCSP
+ *ppResp = d2i_OCSP_RESPONSE_bio(b1, NULL);
+ BIO_free(b1);
+ ddocDebug(3, "ddocDecodeOCSPResponseData", "Decoding %d bytes DER data - OCSP_RESPONSE %s", len, (*ppResp ? "OK" : "ERROR"));
+ RETURN_IF_NOT(*ppResp, ERR_OCSP_UNKNOWN_TYPE);
+ return ERR_OK;
+}
+
+//============================================================
+// Decodes base64 (PEM) OCSP_RESPONSE data and returns a OCSP_RESPONSE object
+// ppResp - pointer to a buffer to receive newly allocated OCSP_RESPONSE pointer
+// data - (PEM) OCSP_RESPONSE data
+// len - length of data in bytes
+//============================================================
+EXP_OPTION int ddocDecodeOCSPResponsePEMData(OCSP_RESPONSE **ppResp, const byte* data, int len)
+{
+ byte* p1 = 0;
+ int l1 = 0, err = ERR_OK;
+
+ // check input params
+ RETURN_IF_NULL_PARAM(data);
+ RETURN_IF_NULL_PARAM(ppResp);
+ // mark as not read yet
+ *ppResp = 0;
+ // allocate memory for decoding
+ l1 = len; // should be enough as it shrinks
+ p1 = (byte*)malloc(l1);
+ RETURN_IF_BAD_ALLOC(p1);
+ memset(p1, 0, l1);
+ // decode base64 data
+ decode((const byte*)data, len, p1, &l1);
+ // decode OCSP
+ err = ddocDecodeOCSPResponseData(ppResp, p1, l1);
+ // cleanup
+ if(p1)
+ free(p1);
+ ddocDebug(3, "ddocDecodeOCSPResponsePEMData", "Decoding %d bytes PEM data - OSCP_RESPONSE %s", len, (*ppResp ? "OK" : "ERROR"));
+ return err;
+}
+
+//============================================================
+// Reads in an OCSP Response file in DER format
+// szFileName - OCSP response file name
+//============================================================
+int ReadOCSPResponse(OCSP_RESPONSE **newOCSP_RESPONSE, const char* szFileName)
+{
+ BIO *bin = NULL;
+ OCSP_RESPONSE *resp = NULL;
+ int err = ERR_OK;
+
+ ddocDebug(4, "ReadOCSPResponse", "File: %s", szFileName);
+ RETURN_IF_NULL_PARAM(newOCSP_RESPONSE);
+ RETURN_IF_NULL_PARAM(szFileName);
+
+ if((bin = BIO_new_file(szFileName, "rb")) != NULL) {
+ ddocDebug(4, "ReadOCSPResponse", "File opened");
+ resp = d2i_OCSP_RESPONSE_bio(bin, NULL);
+ BIO_free(bin);
+ if (resp == NULL) {
+ err = ERR_OCSP_WRONG_VERSION;
+ }
+ } else {
+ ddocDebug(4, "ReadOCSPResponse", "Cannot read file:%s", szFileName);
+ err =ERR_FILE_READ;
+ }
+ if (err != ERR_OK) SET_LAST_ERROR(err);
+ *newOCSP_RESPONSE = resp;
+ return err;
+}
+
+//============================================================
+// Writes an OCSP Response to a file in DER format
+// szFileName - OCSP response file name
+// resp - OCSP response object
+//============================================================
+int WriteOCSPResponse(const char* szFileName, const OCSP_RESPONSE* resp)
+{
+ BIO* bout = 0;
+
+ RETURN_IF_NULL_PARAM(szFileName);
+ RETURN_IF_NULL_PARAM(resp);
+ if((bout = BIO_new_file(szFileName, "wb")) != NULL) {
+#if OPENSSL_VERSION_NUMBER > 0x00908000
+ ASN1_i2d_bio((int (*)(void*, unsigned char**))i2d_OCSP_RESPONSE, bout, (unsigned char*)resp);
+#else
+ ASN1_i2d_bio((int (*)())i2d_OCSP_RESPONSE, bout, (unsigned char*)resp);
+#endif
+ //i2d_OCSP_RESPONSE_bio((unsigned char*)bout, resp);
+ BIO_free(bout);
+ } else
+ SET_LAST_ERROR_RETURN_CODE(ERR_FILE_WRITE);
+ return ERR_OK;
+}
+
+//============================================================
+// Reads in an OCSP Request file in DER format
+// szFileName - OCSP Request file name
+//============================================================
+int ReadOCSPRequest(OCSP_REQUEST **newOCSP_REQUEST, const char* szFileName)
+{
+ BIO *bin = NULL;
+ OCSP_REQUEST *req = NULL;
+ int err = ERR_OK;
+
+ RETURN_IF_NULL_PARAM(*newOCSP_REQUEST);
+ RETURN_IF_NULL_PARAM(szFileName);
+
+ if((bin = BIO_new_file(szFileName, "rb")) != NULL) {
+ req = d2i_OCSP_REQUEST_bio(bin, NULL);
+ BIO_free(bin);
+ if (req == NULL) {
+ err = ERR_OCSP_WRONG_VERSION;
+ }
+ } else
+ err =ERR_FILE_READ;
+ if (err != ERR_OK) SET_LAST_ERROR(err);
+ *newOCSP_REQUEST = req;
+ return err;
+}
+
+//============================================================
+// Writes an OCSP Request to a file in DER format
+// szFileName - OCSP Request file name
+// resp - OCSP Request object
+//============================================================
+int WriteOCSPRequest(const char* szFileName, const OCSP_REQUEST* req)
+{
+ BIO* bout = 0;
+
+ if((bout = BIO_new_file(szFileName, "wb")) != NULL) {
+#if OPENSSL_VERSION_NUMBER > 0x00908000
+ ASN1_i2d_bio((int (*)(void*, unsigned char**))i2d_OCSP_RESPONSE, bout, (unsigned char*)req);
+#else
+ ASN1_i2d_bio((int (*)())i2d_OCSP_RESPONSE, bout, (unsigned char*)req);
+#endif
+ //i2d_OCSP_REQUEST_bio(bout, req);
+ BIO_free(bout);
+ } else
+ SET_LAST_ERROR_RETURN_CODE(ERR_FILE_WRITE);
+ return ERR_OK;
+}
+
+
+
+//============================================================
+// Checks OCSP certificate status and handles errors
+// status - status code
+// return error code
+//============================================================
+int handleOCSPCertStatus(int status)
+{
+ int err = ERR_OK;
+ switch(status) {
+ case V_OCSP_CERTSTATUS_GOOD: // cert is ok, do nothing
+ break;
+ case V_OCSP_CERTSTATUS_REVOKED: // cert has been revoked
+ err = ERR_OCSP_CERT_REVOKED;
+ break;
+ case V_OCSP_CERTSTATUS_UNKNOWN: // cert status unknown
+ err = ERR_OCSP_CERT_UNKNOWN;
+ break;
+ default: // should never happen?
+ err = ERR_OCSP_RESP_STATUS;
+ }
+ return err;
+}
+
+//============================================================
+// Calculates NotaryInfo digest if possible
+// pSigDoc - digidoc main object pointer
+// pNotary - NotaryInfo object to be initialized
+// return error code
+//============================================================
+int calcNotaryDigest(SignedDoc* pSigDoc, NotaryInfo* pNotary)
+{
+ int err = ERR_OK, l1;
+ //AM 24.04.08 increased buffer size for sha256
+ char buf1[DIGEST_LEN256+2];
+
+ RETURN_IF_NULL_PARAM(pNotary);
+ RETURN_IF_NULL_PARAM(pSigDoc);
+ l1 = sizeof(buf1);
+ err = calculateNotaryInfoDigest(pSigDoc, pNotary, (byte*)buf1, &l1);
+ //err = calculateOcspBasicResponseDigest(br, buf1, &l1);
+ if(!err) {
+ err = ddocNotInfo_SetOcspDigest(pNotary, buf1, l1);
+ }
+ return err;
+}
+
+//============================================================
+// Initializes NotaryInfo object with data from OCSP object
+// pSigDoc - digidoc main object pointer
+// pNotary - NotaryInfo object to be initialized
+// resp - OCSP response object
+// notCert - Notary cert object
+// return error code
+//============================================================
+int initializeNotaryInfoWithOCSP(SignedDoc *pSigDoc, NotaryInfo *pNotary,
+ OCSP_RESPONSE *resp, X509 *notCert, int initDigest)
+{
+ int n, err = ERR_OK;
+ char buf[500];
+ OCSP_RESPBYTES *rb = NULL;
+ OCSP_BASICRESP *br = NULL;
+ OCSP_RESPDATA *rd = NULL;
+ OCSP_RESPID *rid = NULL;
+ // OCSP_CERTSTATUS *cst = NULL;
+ OCSP_SINGLERESP *single = NULL;
+ OCSP_CERTID *cid = NULL;
+ X509_EXTENSION *nonce;
+ //AM 26.09.08
+ DigiDocMemBuf mbuf1;
+ mbuf1.pMem = 0;
+ mbuf1.nLen = 0;
+
+
+ RETURN_IF_NULL_PARAM(pNotary);
+ RETURN_IF_NULL_PARAM(resp);
+ ddocDebug(3, "initializeNotaryInfoWithOCSP", "OCSP status: %d", OCSP_response_status(resp));
+ // save the response in memory
+ err = ddocNotInfo_SetOCSPResponse_Value(pNotary, resp);
+
+ // check the OCSP Response validity
+ switch(OCSP_response_status(resp)) {
+ case OCSP_RESPONSE_STATUS_SUCCESSFUL: // OK
+ break;
+ case OCSP_RESPONSE_STATUS_MALFORMEDREQUEST:
+ SET_LAST_ERROR_RETURN_CODE(ERR_OCSP_MALFORMED);
+ case OCSP_RESPONSE_STATUS_INTERNALERROR:
+ SET_LAST_ERROR_RETURN_CODE(ERR_OCSP_INTERNALERR);
+ case OCSP_RESPONSE_STATUS_TRYLATER:
+ SET_LAST_ERROR_RETURN_CODE(ERR_OCSP_TRYLATER);
+ case OCSP_RESPONSE_STATUS_SIGREQUIRED:
+ SET_LAST_ERROR_RETURN_CODE(ERR_OCSP_SIGREQUIRED);
+ case OCSP_RESPONSE_STATUS_UNAUTHORIZED:
+ SET_LAST_ERROR_RETURN_CODE(ERR_OCSP_UNAUTHORIZED);
+ default:
+ SET_LAST_ERROR_RETURN_CODE(ERR_OCSP_UNSUCCESSFUL);
+ }
+ RETURN_IF_NULL_PARAM(resp->responseBytes);
+ rb = resp->responseBytes;
+ if(OBJ_obj2nid(rb->responseType) != NID_id_pkix_OCSP_basic)
+ SET_LAST_ERROR_RETURN_CODE(ERR_OCSP_UNKNOWN_TYPE);
+ if((br = OCSP_response_get1_basic(resp)) == NULL)
+ SET_LAST_ERROR_RETURN_CODE(ERR_OCSP_NO_BASIC_RESP);
+ ddocDebug(4, "initializeNotaryInfoWithOCSP", "test2");
+ rd = br->tbsResponseData;
+ if(ASN1_INTEGER_get(rd->version) != 0)
+ SET_LAST_ERROR_RETURN_CODE(ERR_OCSP_WRONG_VERSION);
+ n = sk_OCSP_SINGLERESP_num(rd->responses);
+ if(n != 1)
+ SET_LAST_ERROR_RETURN_CODE(ERR_OCSP_ONE_RESPONSE);
+ single = sk_OCSP_SINGLERESP_value(rd->responses, 0);
+ RETURN_IF_NULL(single);
+ cid = single->certId;
+ RETURN_IF_NULL(cid);
+ ddocDebug(4, "initializeNotaryInfoWithOCSP", "CertStatus-type: %d", single->certStatus->type);
+ //printf("TYPE: %d\n", single->certStatus->type);
+ if(single->certStatus->type != 0) {
+ ddocDebug(4, "initializeNotaryInfoWithOCSP", "errcode: %d", handleOCSPCertStatus(single->certStatus->type));
+ SET_LAST_ERROR_RETURN_CODE(handleOCSPCertStatus(single->certStatus->type));
+ }
+ //Removed 31.10.2003
+ //if(single->singleExtensions)
+ // SET_LAST_ERROR_RETURN_CODE(ERR_OCSP_NO_SINGLE_EXT);
+ if(!rd->responseExtensions ||
+ (sk_X509_EXTENSION_num(rd->responseExtensions) != 1) ||
+ ((nonce = sk_X509_EXTENSION_value(rd->responseExtensions, 0)) == NULL))
+ SET_LAST_ERROR_RETURN_CODE(ERR_OCSP_NO_NONCE);
+ i2t_ASN1_OBJECT(buf,sizeof(buf),nonce->object);
+ if(strcmp(buf, OCSP_NONCE_NAME))
+ SET_LAST_ERROR_RETURN_CODE(ERR_OCSP_NO_NONCE);
+ rid = rd->responderId;
+ if(rid->type == V_OCSP_RESPID_NAME) {
+ pNotary->nRespIdType = RESPID_NAME_TYPE;
+ } else if(rid->type == V_OCSP_RESPID_KEY) {
+ pNotary->nRespIdType = RESPID_KEY_TYPE;
+ } else {
+ SET_LAST_ERROR_RETURN_CODE(ERR_OCSP_WRONG_RESPID);
+ }
+ // producedAt
+ err = asn1time2str(pSigDoc, rd->producedAt, buf, sizeof(buf));
+ setString(&(pNotary->timeProduced), buf, -1);
+ n = sizeof(buf);
+ if(rid->type == V_OCSP_RESPID_NAME){
+ //X509_NAME_oneline(rid->value.byName,buf,n);
+ err = ddocCertGetDNFromName(rid->value.byName, &mbuf1);
+ err = ddocNotInfo_SetResponderId(pNotary, (char*)mbuf1.pMem, -1);
+ ddocMemBuf_free(&mbuf1);
+ }
+ if(rid->type == V_OCSP_RESPID_KEY) {
+ err = ddocNotInfo_SetResponderId(pNotary, (const char*)rid->value.byKey->data, rid->value.byKey->length);
+ }
+ // digest type
+ i2t_ASN1_OBJECT(buf,sizeof(buf),cid->hashAlgorithm->algorithm);
+ //AM 24.11.09 why its needed? added if. 08.12.09 used for gen
+ if(!pNotary->szDigestType){
+ setString(&(pNotary->szDigestType), buf, -1);
+ }
+ // signature algorithm
+ i2t_ASN1_OBJECT(buf,sizeof(buf),br->signatureAlgorithm->algorithm);
+ setString(&(pNotary->szSigType), buf, -1);
+ // notary cert
+ if(notCert && !err)
+ err = addNotaryInfoCert(pSigDoc, pNotary, notCert);
+ // get the digest from original OCSP data
+ if(initDigest && notCert) {
+ err = calcNotaryDigest(pSigDoc, pNotary);
+ }
+ if(br != NULL)
+ OCSP_BASICRESP_free(br);
+ if (err != ERR_OK) SET_LAST_ERROR(err);
+ return err;
+}
+
+int initializeNotaryInfoWithOCSP2(SignedDoc *pSigDoc, NotaryInfo *pNotary,
+ OCSP_RESPONSE *resp, X509 *notCert, int initDigest)
+{
+ int n, err = ERR_OK;
+ char buf[500];
+ OCSP_RESPBYTES *rb = NULL;
+ OCSP_BASICRESP *br = NULL;
+ OCSP_RESPDATA *rd = NULL;
+ OCSP_RESPID *rid = NULL;
+ // OCSP_CERTSTATUS *cst = NULL;
+ OCSP_SINGLERESP *single = NULL;
+ OCSP_CERTID *cid = NULL;
+ X509_EXTENSION *nonce;
+ //AM 26.09.08
+ DigiDocMemBuf mbuf1;
+ mbuf1.pMem = 0;
+ mbuf1.nLen = 0;
+
+
+ RETURN_IF_NULL_PARAM(pNotary);
+ RETURN_IF_NULL_PARAM(resp);
+ // check the OCSP Response validity
+ switch(OCSP_response_status(resp)) {
+ case OCSP_RESPONSE_STATUS_SUCCESSFUL: // OK
+ break;
+ case OCSP_RESPONSE_STATUS_MALFORMEDREQUEST:
+ SET_LAST_ERROR_RETURN_CODE(ERR_OCSP_MALFORMED);
+ case OCSP_RESPONSE_STATUS_INTERNALERROR:
+ SET_LAST_ERROR_RETURN_CODE(ERR_OCSP_INTERNALERR);
+ case OCSP_RESPONSE_STATUS_TRYLATER:
+ SET_LAST_ERROR_RETURN_CODE(ERR_OCSP_TRYLATER);
+ case OCSP_RESPONSE_STATUS_SIGREQUIRED:
+ SET_LAST_ERROR_RETURN_CODE(ERR_OCSP_SIGREQUIRED);
+ case OCSP_RESPONSE_STATUS_UNAUTHORIZED:
+ SET_LAST_ERROR_RETURN_CODE(ERR_OCSP_UNAUTHORIZED);
+ default:
+ SET_LAST_ERROR_RETURN_CODE(ERR_OCSP_UNSUCCESSFUL);
+ }
+ RETURN_IF_NULL_PARAM(resp->responseBytes);;
+ rb = resp->responseBytes;
+ if(OBJ_obj2nid(rb->responseType) != NID_id_pkix_OCSP_basic)
+ SET_LAST_ERROR_RETURN_CODE(ERR_OCSP_UNKNOWN_TYPE);
+ if((br = OCSP_response_get1_basic(resp)) == NULL)
+ SET_LAST_ERROR_RETURN_CODE(ERR_OCSP_NO_BASIC_RESP);
+ rd = br->tbsResponseData;
+ if(ASN1_INTEGER_get(rd->version) != 0)
+ SET_LAST_ERROR_RETURN_CODE(ERR_OCSP_WRONG_VERSION);
+ n = sk_OCSP_SINGLERESP_num(rd->responses);
+ if(n != 1)
+ SET_LAST_ERROR_RETURN_CODE(ERR_OCSP_ONE_RESPONSE);
+ single = sk_OCSP_SINGLERESP_value(rd->responses, 0);
+ RETURN_IF_NULL(single);
+ cid = single->certId;
+ RETURN_IF_NULL(cid);
+ ddocDebug(4, "initializeNotaryInfoWithOCSP", "CertStatus-type: %d", single->certStatus->type);
+ //printf("TYPE: %d\n", single->certStatus->type);
+ //Am test
+ /*if(single->certStatus->type != 0) {
+ ddocDebug(4, "initializeNotaryInfoWithOCSP", "errcode: %d", handleOCSPCertStatus(single->certStatus->type));
+ SET_LAST_ERROR_RETURN_CODE(handleOCSPCertStatus(single->certStatus->type));
+ }*/
+ //Removed 31.10.2003
+ //if(single->singleExtensions)
+ // SET_LAST_ERROR_RETURN_CODE(ERR_OCSP_NO_SINGLE_EXT);
+ if(!rd->responseExtensions ||
+ (sk_X509_EXTENSION_num(rd->responseExtensions) != 1) ||
+ ((nonce = sk_X509_EXTENSION_value(rd->responseExtensions, 0)) == NULL))
+ SET_LAST_ERROR_RETURN_CODE(ERR_OCSP_NO_NONCE);
+ i2t_ASN1_OBJECT(buf,sizeof(buf),nonce->object);
+ if(strcmp(buf, OCSP_NONCE_NAME))
+ SET_LAST_ERROR_RETURN_CODE(ERR_OCSP_NO_NONCE);
+ rid = rd->responderId;
+ if(rid->type == V_OCSP_RESPID_NAME) {
+ pNotary->nRespIdType = RESPID_NAME_TYPE;
+ } else if(rid->type == V_OCSP_RESPID_KEY) {
+ pNotary->nRespIdType = RESPID_KEY_TYPE;
+ } else {
+ SET_LAST_ERROR_RETURN_CODE(ERR_OCSP_WRONG_RESPID);
+ }
+ // producedAt
+ err = asn1time2str(pSigDoc, rd->producedAt, buf, sizeof(buf));
+ setString(&(pNotary->timeProduced), buf, -1);
+ n = sizeof(buf);
+ if(rid->type == V_OCSP_RESPID_NAME){
+ err = ddocCertGetDNFromName(rid->value.byName, &mbuf1);
+ RETURN_IF_NOT(err == ERR_OK, err);
+ err = ddocNotInfo_SetResponderId(pNotary, (char*)mbuf1.pMem, -1);
+ ddocMemBuf_free(&mbuf1);
+ }
+ if(rid->type == V_OCSP_RESPID_KEY) {
+ err = ddocNotInfo_SetResponderId(pNotary, (const char*)rid->value.byKey->data, rid->value.byKey->length);
+ }
+ // digest type
+ i2t_ASN1_OBJECT(buf,sizeof(buf),cid->hashAlgorithm->algorithm);
+ setString(&(pNotary->szDigestType), buf, -1);
+ // signature algorithm
+ i2t_ASN1_OBJECT(buf,sizeof(buf),br->signatureAlgorithm->algorithm);
+ setString(&(pNotary->szSigType), buf, -1);
+ // notary cert
+ if(notCert && !err)
+ err = addNotaryInfoCert(pSigDoc, pNotary, notCert);
+ // save the response in memory
+ err = ddocNotInfo_SetOCSPResponse_Value(pNotary, resp);
+ // get the digest from original OCSP data
+ if(initDigest && notCert) {
+ err = calcNotaryDigest(pSigDoc, pNotary);
+ }
+ if(br != NULL)
+ OCSP_BASICRESP_free(br);
+ if (err != ERR_OK) SET_LAST_ERROR(err);
+ return err;
+}
+
+//--------------------------------------------------
+// Helper function to read OCSP_RESPONSE from binary input data
+// ppResp - address of newly allocated OCSP_RESPONSE object
+// pMBufInData - input data
+// returns error code or ERR_OK
+//--------------------------------------------------
+int ddocOcspReadOcspResp(OCSP_RESPONSE** ppResp, DigiDocMemBuf* pMBufInData)
+{
+ int err = ERR_OK;
+ unsigned char* p1;
+
+ RETURN_IF_NULL_PARAM(ppResp);
+ RETURN_IF_NULL_PARAM(pMBufInData);
+ RETURN_IF_NULL_PARAM(pMBufInData->pMem);
+ *ppResp = 0;
+ ddocDebug(4, "ddocOcspReadOcspResp", "converting: %d bytes to OCSP_RESPONSE", pMBufInData->nLen);
+ p1 = (unsigned char*)pMBufInData->pMem;
+ d2i_OCSP_RESPONSE(ppResp, (const unsigned char**)&p1, pMBufInData->nLen);
+ ddocDebug(4, "ddocOcspReadOcspResp", "OCSP_RESPONSE: %s", (*ppResp ? "OK" : "ERR"));
+ if(!(*ppResp)) err = ERR_OCSP_UNSUCCESSFUL;
+ return err;
+}
+
+//--------------------------------------------------
+// Helper function to write OCSP_RESPONSE to binary output data
+// pResp - address of OCSP_RESPONSE object
+// pMBufOutData - output data
+// returns error code or ERR_OK
+//--------------------------------------------------
+int ddocOcspWriteOcspResp(OCSP_RESPONSE* pResp, DigiDocMemBuf* pMBufOutData)
+{
+ int err = ERR_OK, l1;
+ unsigned char* p1;
+
+ RETURN_IF_NULL_PARAM(pResp);
+ RETURN_IF_NULL_PARAM(pMBufOutData);
+ pMBufOutData->pMem = NULL;
+ pMBufOutData->nLen = 0;
+ // find out how big a buffer we need
+ l1 = i2d_OCSP_RESPONSE(pResp, NULL);
+ ddocDebug(4, "ddocOcspReadOcspResp", "converting: %d bytes from OCSP_RESPONSE", l1);
+ // alloc mem
+ err = ddocMemSetLength(pMBufOutData, l1 + 50);
+ p1 = (unsigned char*)pMBufOutData->pMem;
+ l1 = i2d_OCSP_RESPONSE(pResp, &p1);
+ pMBufOutData->nLen = l1;
+ ddocDebug(4, "ddocOcspReadOcspResp", "Converted data: %d", l1);
+ return err;
+}
+
+//============================================================
+// Converts OCSP_RESPONSE to PEM form with or without the headers
+// pResp - OCSP_RESPONSE
+// bHeaders - 1= with headers, 0=no headers
+// buf - output buffer newly allocated
+// returns error code
+//============================================================
+EXP_OPTION int getOcspPEM(OCSP_RESPONSE* pResp, int bHeaders, char** buf)
+{
+ int l1, l2;
+ char *p1, *p2;
+
+ RETURN_IF_NULL_PARAM(buf);
+ RETURN_IF_NULL_PARAM(pResp);
+ l1 = i2d_OCSP_RESPONSE(pResp, NULL);
+ p1 = (char*)malloc(l1+10);
+ RETURN_IF_BAD_ALLOC(p1);
+ p2 = p1;
+ i2d_OCSP_RESPONSE(pResp, (unsigned char**)&p2);
+ l2 = l1 * 2 + 200;
+ *buf = (char*)malloc(l2);
+ if(*buf == NULL) {
+ free(p1);
+ RETURN_IF_BAD_ALLOC(*buf);
+ }
+ memset(*buf, 0, l2);
+ if(bHeaders)
+ strncpy(*buf, "-----BEGIN OCSP RESPONSE-----\n", l2);
+ encode((const byte*)p1, l1, (byte*)strchr(*buf, 0), &l2);
+ if(bHeaders)
+ strncat(*buf, "\n-----END OCSP RESPONSE-----", l2 - strlen(*buf));
+ free(p1);
+ return ERR_OK;
+}
+
+//============================================================
+// Converts OCSP_REQUEST to DER form
+// pResp - OCSP_REQUEST
+// pMBuf - output buffer for OCSP req
+// returns error code
+//============================================================
+EXP_OPTION int ddocWriteOcspDER(OCSP_REQUEST* pReq, DigiDocMemBuf* pMBuf)
+{
+ int l1;
+ char *p1, *p2;
+
+ RETURN_IF_NULL_PARAM(pMBuf);
+ RETURN_IF_NULL_PARAM(pReq);
+ l1 = i2d_OCSP_REQUEST(pReq, NULL);
+ p1 = (char*)malloc(l1+10);
+ RETURN_IF_BAD_ALLOC(p1);
+ p2 = p1;
+ i2d_OCSP_REQUEST(pReq, (unsigned char**)&p2);
+ ddocMemAppendData(pMBuf, p1, l1);
+ free(p1);
+ return ERR_OK;
+}
+
+
+//--------------------------------------------------
+// Helper function to return OCSP_RESPONSE in base64 form
+// Memory buffer will be resized as necessary.
+// Caller must release output buffer.
+// pNotary - Notary object
+// bHeaders - 1= with headers, 0=no headers
+// pMBufOutData - output data
+// returns error code or ERR_OK
+//--------------------------------------------------
+EXP_OPTION int ddocGetOcspBase64(NotaryInfo *pNotary, int bHeaders, DigiDocMemBuf* pMBufOutData)
+{
+ const DigiDocMemBuf *pMBuf = 0;
+ DigiDocMemBuf mbuf1;
+
+ RETURN_IF_NULL_PARAM(pNotary);
+ RETURN_IF_NULL_PARAM(pMBufOutData);
+ pMBufOutData->pMem = 0;
+ pMBufOutData->nLen = 0;
+ mbuf1.pMem = 0;
+ mbuf1.nLen = 0;
+ pMBuf = ddocNotInfo_GetOCSPResponse(pNotary);
+ RETURN_IF_NULL(pMBuf);
+ if(bHeaders) {
+ ddocMemAppendData(pMBufOutData, "-----BEGIN OCSP RESPONSE-----\n", -1);
+ ddocEncodeBase64(pMBuf, &mbuf1);
+ ddocMemAppendData(pMBufOutData, (const char*)mbuf1.pMem, mbuf1.nLen);
+ ddocMemAppendData(pMBufOutData, "\n-----END OCSP RESPONSE-----", -1);
+ ddocMemBuf_free(&mbuf1);
+ }
+ else
+ ddocEncodeBase64(pMBuf, pMBufOutData);
+ return ERR_OK;
+}
+
+
+//--------------------------------------------------
+// teeb 00:0a:df stiilis hexprinditud stringist tagasi tavalise
+//--------------------------------------------------
+// Tanel - ver 1.66
+unsigned char *decodeHex(unsigned char *str)
+{
+ unsigned int i, j, k, len;
+ unsigned char *ret;
+ static unsigned char hex[] = { '0', '1', '2', '3', '4', '5', '6', '7',
+ '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
+
+ len = (int)(strlen((const char*)str) / 3) + 2;
+ if((ret=(unsigned char*)malloc(len)) == NULL)
+ return NULL;
+ memset(ret, 0, len);
+ for(i=0, j=0; i<strlen((const char*)str); i+=3) {
+ for(k=0; k<16; k++)
+ if(str[i] == hex[k])
+ ret[j] = (unsigned char)(k<<4);
+ for(k=0; k<16; k++)
+ if(str[i+1] == hex[k])
+ ret[j++] += (unsigned char)k;
+ }
+ return(ret);
+}
+
+//--------------------------------------------------
+// otsib X.509v3 laienduste seest Authority Key Identifieri välja
+//--------------------------------------------------
+// Tanel - ver 1.66
+unsigned char *get_authority_key(STACK_OF(X509_EXTENSION) *exts)
+{
+ int i, found=0;
+ X509_EXTENSION *ex=0;
+ ASN1_OBJECT *obj;
+ X509V3_EXT_METHOD *met;
+ void *st = NULL;
+ unsigned char *p;
+ STACK_OF(CONF_VALUE) *vals=NULL;
+ CONF_VALUE *val;
+ unsigned char *ret = 0;
+
+ for(i=0; i<sk_X509_EXTENSION_num(exts); i++) {
+ ex = sk_X509_EXTENSION_value(exts, i);
+ obj = X509_EXTENSION_get_object(ex);
+ if(OBJ_obj2nid(obj) == NID_authority_key_identifier) {
+ found++;
+ break;
+ }
+ }
+
+ if(!found) {
+ ddocDebug(4, "get_authority_key", "Extension not found");
+ return(NULL);
+ }
+
+ met = (X509V3_EXT_METHOD*)X509V3_EXT_get(ex);
+ p = ex->value->data;
+#if OPENSSL_VERSION_NUMBER > 0x00908000
+ // crashes here!
+ st = ASN1_item_d2i(NULL, (const unsigned char**)&p, ex->value->length, ASN1_ITEM_ptr(met->it));
+#else
+ st = ASN1_item_d2i(NULL, &p, ex->value->length, ASN1_ITEM_ptr(met->it));
+#endif
+ vals = met->i2v(met, st, NULL);
+
+ /* P.R */
+ ASN1_item_free((ASN1_VALUE *)st, ASN1_ITEM_ptr(met->it));
+ /* P.R */
+
+ for(i=0; i<sk_CONF_VALUE_num(vals); i++) {
+ val = sk_CONF_VALUE_value(vals, i);
+ ddocDebug(4, "get_authority_key", "Extension %s - %s", val->name, val->value);
+ if(val->name && (strcmp(val->name, "keyid") == 0))
+ ret = decodeHex((unsigned char*)val->value);
+ }
+ /* P.R */
+ sk_CONF_VALUE_pop_free(vals, X509V3_conf_free);
+ /* P.R */
+
+ return ret;
+
+}
+
+
+
+//--------------------------------------------------
+// otsib X.509 seest Authority Key Identifieri välja
+//--------------------------------------------------
+unsigned char *get_authority_key_from_cert(X509 *x)
+{
+ unsigned char *ret = 0;
+ AUTHORITY_KEYID *val = (AUTHORITY_KEYID*)X509_get_ext_d2i( x, NID_authority_key_identifier, NULL, NULL );
+ if(!val) {
+ ddocDebug(4, "get_authority_key_from_cert", "Extension not found");
+ return(NULL);
+ }
+
+ //ret = ASN1_STRING_data(val->keyid);
+ // workaround encode/decode bugs
+ ret = decodeHex((unsigned char*)hex_to_string(ASN1_STRING_data(val->keyid), ASN1_STRING_length(val->keyid)));
+ AUTHORITY_KEYID_free(val);
+
+ return ret;
+}
+
+
+
+//--------------------------------------------------
+// creates OCSP_CERTID without using the issuer cert
+// cert - certificate for which we need certid
+// returns OCSP_CERTID pointer
+//--------------------------------------------------
+// Tanel - ver 1.66
+OCSP_CERTID* createOCSPCertid(X509 *cert, X509* pCACert)
+{
+ OCSP_CERTID *pId = NULL;
+ X509_NAME *iname;
+ unsigned char *ikey = NULL;
+ ASN1_INTEGER *sno;
+ const EVP_MD *dgst;
+ X509_ALGOR *alg;
+ unsigned char md[EVP_MAX_MD_SIZE], buf1[100];
+ unsigned int len;
+ int l1;
+ DigiDocMemBuf mbuf1, mbuf2;
+
+ mbuf1.pMem = mbuf2.pMem = NULL;
+ mbuf1.nLen = mbuf2.nLen = 0;
+ l1 = (int)sizeof(buf1);
+ memset(buf1, 0, l1);
+ if(cert != NULL) {
+ ddocCertGetSubjectDN(cert, &mbuf1);
+ // standard variant would be
+ //pId = OCSP_cert_to_id(EVP_sha1(), cert, issuer);
+ if(pCACert) {
+ ddocCertGetSubjectDN(pCACert, &mbuf2);
+ ddocDebug(3, "createOCSPCertid", "Create ocsp id for cert: %s by CA: %s", (char*)mbuf1.pMem, (char*)mbuf2.pMem);
+ pId = OCSP_cert_to_id(EVP_sha1(), cert, pCACert);
+
+ } else { // CA unknown
+ ddocDebug(3, "createOCSPCertid", "Create ocsp id for cert: %s unknown CA", (char*)mbuf1.pMem);
+ // issuer name hashi arvutamine
+ iname = X509_get_issuer_name(cert);
+ dgst = EVP_sha1();
+ len = sizeof(md);
+ if(X509_NAME_digest(iname, dgst, md, &len)) {
+ // issuer key hashi lugemine
+ //ikey = get_authority_key(cert->cert_info->extensions);
+ ikey = get_authority_key_from_cert(cert);
+ if(ikey != NULL) {
+ // serial numbri lugemine
+ sno = X509_get_serialNumber(cert);
+ // OCSP certid koostamine
+ if((pId = OCSP_CERTID_new()) != NULL) {
+ // replace default algorithm ???
+ alg = pId->hashAlgorithm;
+ if(alg->algorithm != NULL)
+ ASN1_OBJECT_free(alg->algorithm);
+ alg->algorithm = OBJ_nid2obj(EVP_MD_type(dgst));
+ if((alg->parameter = ASN1_TYPE_new()) != NULL) {
+ alg->parameter->type = V_ASN1_NULL;
+ ASN1_INTEGER_free(pId->serialNumber);
+ pId->serialNumber = ASN1_INTEGER_dup(sno);
+ if(!ASN1_OCTET_STRING_set(pId->issuerNameHash, md, len) ||
+ !ASN1_OCTET_STRING_set(pId->issuerKeyHash, ikey, strlen((const char*)ikey)) ||
+ !pId->serialNumber)
+ {
+ fprintf(stderr, "Unable to fill in CID\n");
+ OCSP_CERTID_free(pId);
+ pId = NULL;
+ }
+ } // else - failed to create algorithm
+ }
+ // cleanup ikey
+ free(ikey);
+ }
+ } // else - SHA1 failed
+ }
+ }
+ ddocMemBuf_free(&mbuf1);
+ ddocMemBuf_free(&mbuf2);
+ if(pId)
+ bin2hex((const byte*)pId->issuerKeyHash->data, pId->issuerKeyHash->length, (byte*)buf1, &l1);
+ ddocDebug(3, "createOCSPCertid", "Created ocsp id %s issuer-key-hash: %s", (pId ? "OK" : "ERR"), buf1);
+ return pId;
+}
+
+
+//--------------------------------------------------
+// Creates an OCSP_REQUEST object
+// pSigDoc - address of signed document. If not NULL then
+// used to check if older openssl 0.9.6 style request must
+// be constructed.
+// req - buffer for storing the pointer of new object
+// cert - client certificate to verify
+// nonce - nonce value (e.g. client signature value RSA-128 bytes)
+// nlen - nonce value length
+// pkey - public key used to signe th request (not used yet)
+//--------------------------------------------------
+// VS - ver 1.66
+int createOCSPRequest(SignedDoc* pSigDoc, OCSP_REQUEST **req,
+ X509 *cert, X509* pCACert, byte* nonce, int nlen)
+{
+ int err = ERR_OK, l2;
+ OCSP_CERTID *id = 0;
+ byte buf2[DIGEST_LEN256 * 2 + 2];
+
+ RETURN_IF_NULL_PARAM(req);
+ RETURN_IF_NULL_PARAM(cert);
+ RETURN_IF_NULL_PARAM(nonce);
+ //RETURN_IF_NULL_PARAM(pCACert);
+ if((*req = OCSP_REQUEST_new()) != 0) {
+ if((id = createOCSPCertid(cert, pCACert)) != 0) {
+ if(OCSP_request_add0_id(*req, id)) {
+ if((err = OCSP_request_add1_nonce(*req, nonce, nlen)) != 0)
+ err = ERR_OK;
+ // debug
+ l2 = sizeof(buf2);
+ memset(buf2, 0, l2);
+ if(nlen <= DIGEST_LEN256) {
+ bin2hex((const char*)nonce, nlen, (byte*)buf2, &l2);
+ ddocDebug(3, "createOCSPRequest", "Sending nonce: %s len: %d err: %d", buf2, nlen, err);
+ }
+ }
+ }
+ }
+ return err;
+}
+
+/* Quick and dirty HTTP OCSP request handler.
+ * Could make this a bit cleverer by adding
+ * support for non blocking BIOs and a few
+ * other refinements.
+ * Qick and dirty adaption of openssl -s
+ * OCSP_sendreq_bio() to add UserAgent HTTP header
+ */
+
+OCSP_RESPONSE *OCSP_sendreq_bio_withParams(BIO *b, char *path,
+ OCSP_REQUEST *req, unsigned long ip_addr )
+{
+ BIO *mem = NULL;
+ char tmpbuf[1024], adrhdr[100];
+ OCSP_RESPONSE *resp = NULL;
+ char *p, *q, *r;
+ int len, retcode;
+ static char req_txt[] =
+"POST %s HTTP/1.0\r\n\
+Content-Type: application/ocsp-request\r\n\
+User-Agent: LIB %s/%s APP %s\r\n%s\
+Content-Length: %d\r\n\r\n";
+
+ adrhdr[0] = 0;
+ if(ip_addr > 0)
+ snprintf(adrhdr, sizeof(adrhdr), "From: %d.%d.%d.%d\r\n",
+ (int)(ip_addr>>24)&0xFF, (int)(ip_addr>>16)&0xFF, (int)(ip_addr>>8)&0xFF, (int)(ip_addr&0xFF));
+ len = i2d_OCSP_REQUEST(req, NULL);
+ if(BIO_printf(b, req_txt, path, getLibName(), getLibVersion(),
+ getGUIVersion(), (ip_addr > 0 ? adrhdr : ""), len) < 0) {
+ OCSPerr(OCSP_F_OCSP_SENDREQ_BIO,OCSP_R_SERVER_WRITE_ERROR);
+ goto err;
+ }
+#if OPENSSL_VERSION_NUMBER > 0x00908000
+ retcode = ASN1_i2d_bio((int (*)(void*, unsigned char**))i2d_OCSP_REQUEST, b, (unsigned char*)req);
+#else
+ retcode = ASN1_i2d_bio((int (*)())i2d_OCSP_REQUEST, b, (unsigned char*)req);
+#endif
+ if(retcode <= 0) {
+ OCSPerr(OCSP_F_OCSP_SENDREQ_BIO,OCSP_R_SERVER_WRITE_ERROR);
+ goto err;
+ }
+ mem = BIO_new(BIO_s_mem());
+ if(!mem) goto err;
+ /* Copy response to a memory BIO: socket bios can't do gets! */
+ do {
+ len = BIO_read(b, tmpbuf, sizeof tmpbuf);
+ if(len < 0) {
+ OCSPerr(OCSP_F_OCSP_SENDREQ_BIO,OCSP_R_SERVER_READ_ERROR);
+ goto err;
+ }
+ BIO_write(mem, tmpbuf, len);
+ } while(len > 0);
+ if(BIO_gets(mem, tmpbuf, 512) <= 0) {
+ OCSPerr(OCSP_F_OCSP_SENDREQ_BIO,OCSP_R_SERVER_RESPONSE_PARSE_ERROR);
+ goto err;
+ }
+ /* Parse the HTTP response. This will look like this:
+ * "HTTP/1.0 200 OK". We need to obtain the numeric code and
+ * (optional) informational message.
+ */
+
+ /* Skip to first white space (passed protocol info) */
+ for(p = tmpbuf; *p && !isspace((unsigned char)*p); p++) continue;
+ if(!*p) {
+ OCSPerr(OCSP_F_OCSP_SENDREQ_BIO,OCSP_R_SERVER_RESPONSE_PARSE_ERROR);
+ goto err;
+ }
+ /* Skip past white space to start of response code */
+ while(*p && isspace((unsigned char)*p)) p++;
+ if(!*p) {
+ OCSPerr(OCSP_F_OCSP_SENDREQ_BIO,OCSP_R_SERVER_RESPONSE_PARSE_ERROR);
+ goto err;
+ }
+ /* Find end of response code: first whitespace after start of code */
+ for(q = p; *q && !isspace((unsigned char)*q); q++) continue;
+ if(!*q) {
+ OCSPerr(OCSP_F_OCSP_SENDREQ_BIO,OCSP_R_SERVER_RESPONSE_PARSE_ERROR);
+ goto err;
+ }
+ /* Set end of response code and start of message */
+ *q++ = 0;
+ /* Attempt to parse numeric code */
+ retcode = strtoul(p, &r, 10);
+ if(*r) goto err;
+ /* Skip over any leading white space in message */
+ while(*q && isspace((unsigned char)*q)) q++;
+ if(*q) {
+ /* Finally zap any trailing white space in message (include CRLF) */
+ /* We know q has a non white space character so this is OK */
+ for(r = q + strlen(q) - 1; isspace((unsigned char)*r); r--) *r = 0;
+ }
+ if(retcode != 200) {
+ OCSPerr(OCSP_F_OCSP_SENDREQ_BIO,OCSP_R_SERVER_RESPONSE_ERROR);
+ if(!*q) {
+ ERR_add_error_data(2, "Code=", p);
+ }
+ else {
+ ERR_add_error_data(4, "Code=", p, ",Reason=", q);
+ }
+ goto err;
+ }
+ /* Find blank line marking beginning of content */
+ while(BIO_gets(mem, tmpbuf, 512) > 0)
+ {
+ for(p = tmpbuf; *p && isspace((unsigned char)*p); p++) continue;
+ if(!*p) break;
+ }
+ if(*p) {
+ OCSPerr(OCSP_F_OCSP_SENDREQ_BIO,OCSP_R_NO_CONTENT);
+ goto err;
+ }
+ resp = d2i_OCSP_RESPONSE_bio(mem, NULL);
+ if(!resp) {
+ OCSPerr(OCSP_F_OCSP_SENDREQ_BIO,ERR_R_NESTED_ASN1_ERROR);
+ goto err;
+ }
+ err:
+ BIO_free(mem);
+ return resp;
+}
+
+
+//--------------------------------------------------
+// sends an OCSP_REQUES object to remore server and
+// retrieves the OCSP_RESPONSE object
+// resp - buffer to store the new responses pointer
+// req - request objects pointer
+// url - OCSP responder URL
+// ip_addr - senders ip address if known or 0
+//--------------------------------------------------
+int sendOCSPRequest(OCSP_RESPONSE** resp, OCSP_REQUEST *req,
+ char* url, char* proxyHost, char* proxyPort,
+ unsigned long ip_addr)
+{
+ BIO* cbio = 0, *sbio = 0;
+ SSL_CTX *ctx = NULL;
+ char *host = NULL, *port = NULL, *path = "/";
+ int err = ERR_OK, use_ssl = -1;
+ int connResult = 0;
+ long e = 0;
+
+ RETURN_IF_NULL_PARAM(resp);
+ RETURN_IF_NULL_PARAM(req);
+ RETURN_IF_NULL_PARAM(url);
+
+ //there is an HTTP proxy - connect to that instead of the target host
+ ddocDebug(3, "sendOCSPRequest", "Send OCSP to: %s over: %s:%s", url,
+ (proxyHost ? proxyHost : ""), (proxyPort ? proxyPort : ""));
+ if (proxyHost != 0 && *proxyHost != '\0') {
+ host = proxyHost;
+ if(proxyPort != 0 && *proxyPort != '\0')
+ port = proxyPort;
+ path = url;
+ } else {
+ if((err = OCSP_parse_url(url, &host, &port, &path, &use_ssl)) == 0) {
+ //printf("BIO_parse_url failed\n");
+ ddocDebug(1, "sendOCSPRequest", "BIO_parse_url failed: %d - %s", err, url);
+ return ERR_WRONG_URL_OR_PROXY;
+ }
+ }
+ if((cbio = BIO_new_connect(host)) != 0) {
+ if(port != NULL)
+ BIO_set_conn_port(cbio, port);
+ if (use_ssl == 1) {
+ ctx = SSL_CTX_new(SSLv23_client_method());
+ SSL_CTX_set_mode(ctx, SSL_MODE_AUTO_RETRY);
+ sbio = BIO_new_ssl(ctx, 1);
+ cbio = BIO_push(sbio, cbio);
+ }
+ if ((connResult = BIO_do_connect(cbio)) > 0) {
+ e = checkErrors();
+ //printf("BIO_do_connect returned %d\n", connResult);
+ *resp = OCSP_sendreq_bio_withParams(cbio, path, req, ip_addr);
+ //printf("OCSP_sendreq_bio answered %lX\n", *resp);
+ e = checkErrors();
+ if(ERR_GET_REASON(e) == BIO_R_BAD_HOSTNAME_LOOKUP ||
+ ERR_GET_REASON(e) == OCSP_R_SERVER_WRITE_ERROR)
+ err = ERR_CONNECTION_FAILURE;
+ //if(ERR_GET_REASON(e) == BIO_R_BAD_HOSTNAME_LOOKUP)
+ // err = ERR_CONNECTION_FAILURE;
+ else
+ err = (*resp == 0) ? ERR_OCSP_WRONG_URL : ERR_OK;
+ //if (*resp == 0)
+ // printErrors();
+ } else {
+ ddocDebug(1, "sendOCSPRequest", "BIO-Connection error: %d - %ld", err, e);
+ //printf("BIO_do_connect failed, rc = %d, shouldRetry = %d\n", connResult, BIO_should_retry(cbio));
+ //printErrors();
+ //if no connection
+ if (host != NULL)
+ err = ERR_WRONG_URL_OR_PROXY;
+ else
+ err = ERR_CONNECTION_FAILURE;
+ }
+ BIO_free_all(cbio);
+ if (use_ssl != -1) {
+ OPENSSL_free(host);
+ OPENSSL_free(port);
+ OPENSSL_free(path);
+ SSL_CTX_free(ctx);
+ }
+ }
+ else {
+ err = ERR_CONNECTION_FAILURE;
+ ddocDebug(1, "sendOCSPRequest", "Connection error: %d", err);
+ }
+ return(err);
+}
+
+
+//--------------------------------------------------
+// sends an OCSP_REQUES object to remore server and
+// retrieves the OCSP_RESPONSE object
+// resp - buffer to store the new responses pointer
+// req - request objects pointer
+// url - OCSP responder URL
+// ip_addr - senders ip address if known or 0
+//--------------------------------------------------
+int sendOCSPRequest2(OCSP_RESPONSE** resp, OCSP_REQUEST *req,
+ char* url, char* proxyHost, char* proxyPort, char *proxyUser, char *proxyPass,
+ unsigned long ip_addr)
+{
+ int err = ERR_OK, l1 = 0;
+ DigiDocMemBuf mbuf1, mbuf2, mbuf3;
+ char buf1[30], buf2[200], buf3[100], *p1;
+
+ mbuf1.pMem = 0;
+ mbuf1.nLen = 0;
+ mbuf2.pMem = 0;
+ mbuf2.nLen = 0;
+ mbuf3.pMem = 0;
+ mbuf3.nLen = 0;
+ ddocMemAssignData(&mbuf1, "POST ", -1);
+ if(proxyHost || (proxyPort && atoi(proxyPort) > 0)) {
+ ddocMemAppendData(&mbuf1, url, -1);
+ } else {
+ p1 = strstr(url, "://");
+ if(p1) p1 += 3;
+ if(p1) p1 = strchr(p1, '/');
+ if(p1)
+ ddocMemAppendData(&mbuf1, p1, -1);
+ else
+ ddocMemAppendData(&mbuf1, "/", -1);
+ }
+ ddocMemAppendData(&mbuf1, " HTTP/1.0\r\n", -1);
+ buf1[0] = buf2[0] = 0;
+ if(ip_addr > 0)
+ snprintf(buf1, sizeof(buf1), "From: %d.%d.%d.%d\r\n",
+ (int)(ip_addr>>24)&0xFF, (int)(ip_addr>>16)&0xFF, (int)(ip_addr>>8)&0xFF, (int)ip_addr&0xFF);
+ snprintf(buf2, sizeof(buf2), "User-Agent: LIB %s/%s APP %s\r\n%s",
+ getLibName(), getLibVersion(), getGUIVersion(), (ip_addr > 0 ? buf1 : ""));
+ ddocMemAppendData(&mbuf1, "Content-Type: application/ocsp-request\r\n", -1);
+ ddocMemAppendData(&mbuf1, buf2, -1);
+ //ddocMemAppendData(&mbuf1, "Host: www.sk.ee\r\n", -1);
+ //ddocMemAppendData(&mbuf1, "Accept: */*\r\n", -1);
+ // convert OCSP req
+ err = ddocWriteOcspDER(req, &mbuf3);
+ if(!err) {
+ snprintf(buf1, sizeof(buf1), "Content-Length: %d\r\n", (int)mbuf3.nLen);
+ ddocMemAppendData(&mbuf1, buf1, -1);
+ ddocMemAppendData(&mbuf1, "Connection: Close\r\n", -1);
+ if(proxyUser || proxyPass) {
+ err = ddocOcspProxyAuthInfo(buf3, proxyUser, proxyPass);
+ ddocMemAppendData(&mbuf1, buf3, -1);
+ }
+ if(proxyHost || (proxyPort && atoi(proxyPort) > 0)) // if we use proxy then send also Proxy-Connection
+ ddocMemAppendData(&mbuf1, "Proxy-Connection: Close\r\n", -1);
+ ddocMemAppendData(&mbuf1, "\r\n", -1);
+ ddocMemAppendData(&mbuf1, mbuf3.pMem, mbuf3.nLen);
+ ddocMemBuf_free(&mbuf3);
+ ddocDebug(3, "sendOCSPRequest2", "Send to host: %s request len: %d", url, mbuf1.nLen);
+ err = ddocPullUrl(url, &mbuf1, &mbuf2, proxyHost, proxyPort);
+ ddocDebug(3, "sendOCSPRequest2", "Recevied len: %d RC: %d", mbuf2.nLen, err);
+ if(!err && ((l1 = ddocGetHttpResponseCode(&mbuf2)) == 200)) {
+ ddocDebug(4, "sendOCSPRequest2", "HTTP response\n-----\n%s\n-----\n", mbuf2.pMem);
+ err = ddocGetHttpPayload(&mbuf2, &mbuf3);
+ if(!err)
+ err = ddocOcspReadOcspResp(resp, &mbuf3);
+ } else {
+ ddocDebug(1, "sendOCSPRequest2", "Ocsp request failed with http code: %d rc: %d", l1, err);
+ err = ERR_OCSP_UNSUCCESSFUL;
+ ddocDebug(1, "sendOCSPRequest2", "HTTP error message\n-----\n%s\n-----\n", mbuf2.pMem);
+ }
+ }
+ // cleanup
+ ddocMemBuf_free(&mbuf1);
+ ddocMemBuf_free(&mbuf2);
+ ddocMemBuf_free(&mbuf3);
+ return err;
+}
+
+
+//--------------------------------------------------
+// Creates and writes an OCSP_REQUEST object
+// to disk
+// pSigDoc - signedDoc address
+// signerCertFile - cert file to verify
+// issuertCertFile - this certs direct CA cert
+// nonce - nonce (signature value)
+// nlen - nonce length
+// szOutputFile - output filename
+//--------------------------------------------------
+ EXP_OPTION int writeOCSPRequest(SignedDoc* pSigDoc,
+ const char* signerCertFile, const char* issuertCertFile,
+ byte* nonce, int nlen, const char* szOutputFile)
+
+{
+ OCSP_REQUEST *req = 0;
+ X509 *cert = 0, *issuer = 0;
+ int err = ERR_OK, l1;
+ //EVP_PKEY* pkey;
+ byte buf1[DIGEST_LEN+2];
+
+ RETURN_IF_NULL_PARAM(signerCertFile);
+ RETURN_IF_NULL_PARAM(issuertCertFile);
+ RETURN_IF_NULL_PARAM(nonce);
+ RETURN_IF_NULL_PARAM(szOutputFile);
+
+ if((err = ReadCertificate(&cert, signerCertFile)) == ERR_OK) {
+ //pkey = ReadPublicKey(signerCertFile);
+ if((err = ReadCertificate(&issuer, issuertCertFile)) == ERR_OK) {
+ l1 = sizeof(buf1);
+ calculateDigest(nonce, nlen, DIGEST_SHA1, buf1, &l1);
+ err = createOCSPRequest(pSigDoc, &req, cert, issuer, buf1, l1);
+ //WriteOCSPRequest(szOutputFile, req);
+ X509_free(issuer);
+ //AM 22.04.08
+ if(req)
+ OCSP_REQUEST_free(req);
+ }
+ X509_free(cert);
+ }
+ return err;
+}
+
+//--------------------------------------------------
+// Signs an OCSP_REQUEST using PKCS#12 conteiner
+// req - OCSP_REQUEST
+// filename - PKCS#12 conteiner file
+// passwd - key decryption passwd
+//--------------------------------------------------
+EXP_OPTION int signOCSPRequestPKCS12(OCSP_REQUEST *req, const char* filename, const char* passwd)
+{
+ EVP_PKEY *pkey;
+ int err = ERR_OK;
+
+ STACK_OF(X509)* certs = NULL;
+ X509* x509=0;
+#ifdef FRAMEWORK
+ SecIdentityRef identity = 0;
+ err = SecIdentityCopyPreference(CFSTR("ocsp.sk.ee"), 0, 0, &identity);
+ if(identity) {
+ SecCertificateRef certref = 0;
+ SecKeyRef keyref = 0;
+ err = SecIdentityCopyCertificate(identity, &certref);
+ err = SecIdentityCopyPrivateKey(identity, &keyref);
+ CFRelease(identity);
+ RETURN_IF_NULL(certref);
+ RETURN_IF_NULL(keyref);
+
+ CFDataRef certdata = SecCertificateCopyData(certref);
+ CFRelease(certref);
+ RETURN_IF_NULL(certdata);
+ const unsigned char *p = CFDataGetBytePtr(certdata);
+ x509 = d2i_X509(0, &p, CFDataGetLength(certdata));
+ CFRelease(certdata);
+ RETURN_IF_NULL(x509);
+
+ CFDataRef keydata = 0;
+ SecKeyImportExportParameters params;
+ memset( &params, 0, sizeof(params) );
+ params.version = SEC_KEY_IMPORT_EXPORT_PARAMS_VERSION;
+ params.passphrase = CFSTR("pass");
+ err = SecKeychainItemExport(keyref, kSecFormatWrappedPKCS8, 0, &params, &keydata);
+ CFRelease(keyref);
+ RETURN_IF_NULL(keydata);
+ BIO *bio = BIO_new_mem_buf((void*)CFDataGetBytePtr(keydata), CFDataGetLength(keydata));
+ pkey = d2i_PKCS8PrivateKey_bio(bio, 0, &password_callback, 0);
+ CFRelease(keydata);
+ BIO_free(bio);
+
+ RETURN_IF_NULL(pkey);
+ } else {
+#endif
+ RETURN_IF_NULL_PARAM(filename);
+ if(strlen(filename) == 0)
+ return ERR_OK;
+
+ err = ReadCertificateByPKCS12(&x509, filename, passwd, &pkey);
+ RETURN_IF_NOT(err == ERR_OK, err);
+#ifdef FRAMEWORK
+ }
+#endif
+
+#if 0 // miscalulates on mac time zone
+ // VS: ver 1.66
+ time(&tNow);
+ err = isCertValid(x509, tNow);
+#else
+ if( X509_cmp_current_time(x509->cert_info->validity->notBefore) >= 0 &&
+ X509_cmp_current_time(x509->cert_info->validity->notAfter) <= 0)
+ err = ERR_CERT_INVALID;
+#endif
+ if (err != ERR_OK)
+ X509_free(x509);
+ RETURN_IF_NOT(err == ERR_OK, ERR_PKCS12_EXPIRED);
+ certs = sk_X509_new_null();
+ RETURN_IF_NULL(certs);
+
+ //sk_X509_push(certs, x509);
+ if (! OCSP_request_sign(req,x509,pkey,EVP_sha1(),certs,0)) {
+ EVP_PKEY_free(pkey);
+ err = ERR_OCSP_SIGN;
+ SET_LAST_ERROR(err);
+ }
+ X509_free(x509);
+ EVP_PKEY_free(pkey);
+ //AM 22.04.08
+ sk_X509_free(certs);
+ return err;
+}
+
+//--------------------------------------------------
+// Signs an OCSP_REQUEST using X509 cert and separate keyfile
+// req - OCSP_REQUEST
+// certFile - signers certificate file
+// keyfile - signer's key file
+// passwd - key decryption passwd
+//--------------------------------------------------
+EXP_OPTION int signOCSPRequest(OCSP_REQUEST *req,const char* certFile,const char* keyfile,const char* passwd){
+
+ EVP_PKEY *pkey;
+ int err = ERR_OK;
+ STACK_OF(X509)* certs = NULL;
+ X509* x509 = NULL;
+
+ certs = sk_X509_new_null();
+ RETURN_IF_NULL_PARAM(certs);
+
+ if((err = ReadCertificate(&x509, certFile)) != ERR_OK) {
+ SET_LAST_ERROR_RETURN_CODE(ERR_PKCS_CERT_LOC);
+ }
+ sk_X509_push(certs, x509);
+ if((err = ReadPrivateKey(&pkey, keyfile, passwd, FILE_FORMAT_PEM)) == ERR_OK) {
+ //ASN1_item_sign(ASN1_ITEM_rptr(OCSP_REQINFO),req->optionalSignature->signatureAlgorithm,NULL,req->optionalSignature->signature,req->tbsRequest,pkey,setSignAlgorithm(EVP_sha1()));
+ //OCSP_request_sign_internal(req, x509,pkey, NULL);
+ if(! OCSP_request_sign(req,x509,pkey,EVP_sha1(),certs,0)){
+ EVP_PKEY_free(pkey);
+ SET_LAST_ERROR_RETURN_CODE(ERR_OCSP_SIGN);
+ }
+ //printf("OCSP_request_sign()=%d \n",r);
+ EVP_PKEY_free(pkey);
+ }else{
+ SET_LAST_ERROR_RETURN_CODE(ERR_PRIVKEY_READ);
+ }
+ return err;
+}
+
+//--------------------------------------------------
+// Creates and sends an OCSP_REQUEST object
+// to the notary server, receives the response
+// and uses it to create a confirmation object.
+// pSigDoc - signed doc info
+// pSigInfo - signature info
+// caCerts - responder CA certs chain
+// notaryCert - notarys cert search
+// pkcs12FileName -
+// pkcs12Password -
+// notaryURL - notarys URL
+// proxyHost - proxy host if needed
+// proxyPort - proxy port if needed
+//--------------------------------------------------
+EXP_OPTION int getConfirmation(SignedDoc* pSigDoc, SignatureInfo* pSigInfo,
+ const X509** caCerts, const X509* pNotCert,
+ char* pkcs12FileName, char* pkcs12Password,
+ char* notaryURL, char* proxyHost, char* proxyPort)
+
+{
+ // default way to invoke it is without callers ip.
+ return getConfirmationWithIp(pSigDoc, pSigInfo, caCerts, pNotCert,
+ pkcs12FileName, pkcs12Password,
+ notaryURL, proxyHost, proxyPort, 0);
+}
+
+//--------------------------------------------------
+// Creates and sends an OCSP_REQUEST object
+// to the notary server, receives the response
+// and uses it to create a confirmation object.
+// pSigDoc - signed doc info
+// pSigInfo - signature info
+// caCerts - responder CA certs chain
+// notaryCert - notarys cert search
+// pkcs12FileName -
+// pkcs12Password -
+// notaryURL - notarys URL
+// proxyHost - proxy host if needed
+// proxyPort - proxy port if needed
+// ip - callers ip address if known
+//--------------------------------------------------
+EXP_OPTION int getConfirmationWithIp(SignedDoc* pSigDoc, SignatureInfo* pSigInfo,
+ const X509** caCerts, const X509* pNotCert,
+ char* pkcs12FileName, char* pkcs12Password,
+ char* notaryURL, char* proxyHost, char* proxyPort,
+ unsigned long ip)
+{
+ return getConfirmationWithIpEx(pSigDoc, pSigInfo, caCerts, pNotCert,
+ pkcs12FileName, pkcs12Password, notaryURL, proxyHost, proxyPort, 0, 0, ip);
+}
+
+//--------------------------------------------------
+// Creates and sends an OCSP_REQUEST object
+// to the notary server, receives the response
+// and uses it to create a confirmation object.
+// pSigDoc - signed doc info
+// pSigInfo - signature info
+// caCerts - responder CA certs chain
+// notaryCert - notarys cert search
+// pkcs12FileName -
+// pkcs12Password -
+// notaryURL - notarys URL
+// proxyHost - proxy host if needed
+// proxyPort - proxy port if needed
+// proxyUser - proxy user if needed
+// proxyPass - proxy pass if needed
+// ip - callers ip address if known
+//--------------------------------------------------
+EXP_OPTION int getConfirmationWithIpEx(SignedDoc* pSigDoc, SignatureInfo* pSigInfo,
+ const X509** caCerts, const X509* pNotCert,
+ char* pkcs12FileName, char* pkcs12Password,
+ char* notaryURL, char* proxyHost, char* proxyPort,
+ char* proxyUser, char* proxyPass, unsigned long ip)
+{
+ OCSP_REQUEST *req = 0;
+ OCSP_RESPONSE *resp = 0;
+ X509 *cert = 0, *pCA = 0;
+ int err = ERR_OK, l1, i;
+ byte buf1[DIGEST_LEN256+2];
+ NotaryInfo* pNotInf = NULL;
+ DigiDocMemBuf* pMBuf;
+
+ RETURN_IF_NULL_PARAM(pSigDoc);
+ RETURN_IF_NULL_PARAM(pSigInfo);
+ cert = ddocSigInfo_GetSignersCert(pSigInfo);
+ RETURN_IF_NULL(cert);
+ RETURN_IF_NULL_PARAM(notaryURL);
+
+ clearErrors();
+
+ l1 = sizeof(buf1);
+ pMBuf = ddocSigInfo_GetSignatureValue_Value(pSigInfo);
+ RETURN_IF_NOT(pMBuf, err);
+#ifdef WIN32
+ RAND_screen();
+ RAND_bytes((unsigned char*)buf1, DIGEST_LEN);
+#else
+ if((l1 = RAND_load_file("/dev/urandom", 1024)) > 0) {
+ RAND_bytes((unsigned char*)buf1, DIGEST_LEN);
+ l1 = DIGEST_LEN;
+ }
+#endif
+ err = calculateDigest(pMBuf->pMem, pMBuf->nLen, DIGEST_SHA1, buf1, &l1);
+ RETURN_IF_NOT(err == ERR_OK, err);
+
+ // find lowest CA cert
+ for(i = 0; (caCerts != NULL) && (caCerts[i] != NULL); i++)
+ pCA = (X509*)caCerts[i];
+ err = createOCSPRequest(pSigDoc, &req, cert, pCA, buf1, l1);
+
+ // if both are NULL then this means don't sign OCSP requests
+ if(!err && ConfigItem_lookup_bool("SIGN_OCSP", 1) /*pkcs12FileName && pkcs12Password*/) {
+ ddocDebug(3, "getConfirmationWithIp", "Sign OCSP request with: %s", pkcs12FileName);
+ err=signOCSPRequestPKCS12(req, pkcs12FileName, pkcs12Password);
+ ddocDebug(3, "getConfirmationWithIp", "Signing ocsp rc: %d", err);
+ }
+
+ if(!err) {
+ ddocDebug(3, "getConfirmationWithIp", "Send OCSP to: %s over: %s:%s", notaryURL,
+ (proxyHost ? proxyHost : ""), (proxyPort ? proxyPort : ""));
+ err = sendOCSPRequest2(&resp, req, notaryURL, proxyHost, proxyPort, proxyUser, proxyPass, ip);
+ }
+ if(!err)
+ err = NotaryInfo_new(&pNotInf, pSigDoc, pSigInfo);
+ //AM initializeNotaryInfoWithOCSP2?
+ if(!err)
+ err = initializeNotaryInfoWithOCSP(pSigDoc, pNotInf, resp, NULL, 1);
+
+ if(!err && caCerts && pNotCert) {
+ err = finalizeAndVerifyNotary(pSigDoc, pSigInfo, pNotInf, caCerts, pNotCert);
+ }
+ // VS - if finalizing notary fails then remove it - #8602
+ if(err) {
+ if(pNotInf)
+ ddocDebug(3, "getConfirmationWithIp", "Delete notary: %s because of error: %d", pNotInf->szId, err);
+ NotaryInfo_delete(pSigInfo);
+ }
+ if(resp)
+ OCSP_RESPONSE_free(resp);
+ if(req)
+ OCSP_REQUEST_free(req);
+ return err;
+}
+
+//--------------------------------------------------
+// Adds responder certificate to notary, searches it's
+// CA chain and then verifies notary
+// pSigDoc - signed doc info
+// pSigInfo - signature info
+// caCertSearches - responder CA certs chain
+// notaryCert - notarys cert search
+// returns error code
+//--------------------------------------------------
+int EXP_OPTION finalizeAndVerifyNotary2(SignedDoc* pSigDoc, SignatureInfo* pSigInfo,
+ NotaryInfo* pNotInf,
+ const X509** caCerts, const X509* pNotCert, const X509* pSigCa)
+{
+ int err = ERR_OK;
+
+ RETURN_IF_NULL_PARAM(pNotCert);
+ RETURN_IF_NULL_PARAM(caCerts);
+ ddocDebug(3, "finalizeAndVerifyNotary2", "Notary: %s cert: %s", pNotInf->szId, (pNotCert ? "OK" : "NULL"));
+ err = addNotaryInfoCert(pSigDoc, pNotInf, (X509*)pNotCert);
+ RETURN_IF_NOT(err == ERR_OK, err);
+ err = calcNotaryDigest(pSigDoc, pNotInf);
+ RETURN_IF_NOT(err == ERR_OK, err);
+ err = verifyNotaryInfoCERT2(pSigDoc, pSigInfo, pNotInf, caCerts, NULL, pNotCert, pSigCa);
+ RETURN_IF_NOT(err == ERR_OK, err);
+ ddocDebug(3, "finalizeAndVerifyNotary2", "rc: %d cert: %s cert2: %s", err, (pNotCert ? "OK" : "NULL"), (ddocSigInfo_GetOCSPRespondersCert(pSigInfo) ? "OK" : "NULL"));
+ return ERR_OK;
+}
+
+//--------------------------------------------------
+// Adds responder certificate to notary, searches it's
+// CA chain and then verifies notary
+// pSigDoc - signed doc info
+// pSigInfo - signature info
+// caCertSearches - responder CA certs chain
+// notaryCert - notarys cert search
+// returns error code
+//--------------------------------------------------
+int EXP_OPTION finalizeAndVerifyNotary(SignedDoc* pSigDoc, SignatureInfo* pSigInfo,
+ NotaryInfo* pNotInf,
+ const X509** caCerts, const X509* pNotCert)
+{
+ return finalizeAndVerifyNotary2(pSigDoc, pSigInfo, pNotInf, caCerts, pNotCert, NULL);
+}
+
+
+//--------------------------------------------------
+// Verfies OCSP_RESPONSE signature
+// pResp - signed OCSP response
+// caCerts - CA certificate pointer array terminated with NULL
+// CApath - path to (directory) all certs
+// notCertFile - Notary (e.g. OCSP responder) cert file
+//--------------------------------------------------
+int verifyOCSPResponse(OCSP_RESPONSE* pResp,
+ const X509** caCerts, const char *CApath,
+ const X509* notCert)
+{
+ X509_STORE *store;
+ OCSP_BASICRESP* bs = NULL;
+ STACK_OF(X509)* ver_certs = NULL;
+ int err = ERR_OK;
+
+ RETURN_IF_NULL_PARAM(pResp);
+ RETURN_IF_NOT(ASN1_ENUMERATED_get(pResp->responseStatus) == 0, ERR_OCSP_UNSUCCESSFUL);
+ RETURN_IF_NOT(OBJ_obj2nid(pResp->responseBytes->responseType) == NID_id_pkix_OCSP_basic, ERR_OCSP_UNKNOWN_TYPE);
+ RETURN_IF_NOT(caCerts != NULL, ERR_OCSP_RESP_NOT_TRUSTED);
+ RETURN_IF_NOT(notCert != NULL, ERR_OCSP_CERT_NOTFOUND);
+ RETURN_IF_NOT((bs = OCSP_response_get1_basic(pResp)) != NULL, ERR_OCSP_NO_BASIC_RESP);
+ // now create an OCSP object and check its validity
+ if((setup_verifyCERT(&store, CApath, caCerts)) == ERR_OK) {
+ // new basic response
+ // create OCSP basic response
+ ver_certs = sk_X509_new_null();
+ if(ver_certs) {
+ sk_X509_push(ver_certs, notCert);
+ err = OCSP_basic_verify(bs, ver_certs, store, OCSP_TRUSTOTHER);
+ if(err == ERR_LIB_NONE) {
+ err = ERR_OK;
+ } else {
+ //checkErrors();
+ SET_LAST_ERROR(ERR_OCSP_WRONG_RESPID);
+ err = ERR_OCSP_WRONG_RESPID;
+ }
+ // cleanup
+ sk_X509_free(ver_certs);
+ }
+ X509_STORE_free(store);
+ }
+ if(bs)
+ OCSP_BASICRESP_free(bs);
+ return err;
+}
+
+int checkNonceAndCertbyOCSP(OCSP_RESPONSE* resp, X509* cert, byte* nonce1, int nonceLen)
+{
+ int err = ERR_OK, n;
+ char buf[100];
+ OCSP_BASICRESP *br = NULL;
+ OCSP_RESPDATA *rd = NULL;
+ OCSP_SINGLERESP *single = NULL;
+ OCSP_CERTID *cid = NULL;
+ X509_EXTENSION *nonce;
+ X509_NAME *iname;
+ unsigned char *ikey;
+
+ RETURN_IF_NULL_PARAM(resp);
+ RETURN_IF_NULL_PARAM(cert);
+ if((br = OCSP_response_get1_basic(resp)) == NULL)
+ SET_LAST_ERROR_RETURN_CODE(ERR_OCSP_NO_BASIC_RESP);
+ rd = br->tbsResponseData;
+ n = sk_OCSP_SINGLERESP_num(rd->responses);
+ RETURN_IF_NOT(n == 1, ERR_OCSP_ONE_RESPONSE);
+ single = sk_OCSP_SINGLERESP_value(rd->responses, 0);
+ RETURN_IF_NOT(single, ERR_OCSP_ONE_RESPONSE);
+ cid = single->certId;
+ RETURN_IF_NULL(cid);
+ err = handleOCSPCertStatus(single->certStatus->type);
+ if(err)
+ SET_LAST_ERROR_RETURN_CODE(err);
+ if(single->singleExtensions)
+ SET_LAST_ERROR_RETURN_CODE(ERR_OCSP_NO_SINGLE_EXT);
+ if(!rd->responseExtensions ||
+ (sk_X509_EXTENSION_num(rd->responseExtensions) != 1) ||
+ ((nonce = sk_X509_EXTENSION_value(rd->responseExtensions, 0)) == NULL))
+ SET_LAST_ERROR_RETURN_CODE(ERR_OCSP_NO_NONCE);
+ i2t_ASN1_OBJECT(buf, sizeof(buf), nonce->object);
+ if(strcmp(buf, OCSP_NONCE_NAME))
+ SET_LAST_ERROR_RETURN_CODE(ERR_OCSP_NO_NONCE);
+ // check serial number
+ if(ASN1_INTEGER_cmp(X509_get_serialNumber(cert), cid->serialNumber) != 0)
+ SET_LAST_ERROR_RETURN_CODE(ERR_WRONG_CERT);
+ // check issuer name hash
+ iname = X509_get_issuer_name(cert);
+ n = sizeof(buf);
+ X509_NAME_digest(iname, EVP_sha1(), (byte*)buf, (unsigned int*)&n);
+ err = compareByteArrays((byte*)buf, (unsigned int)n, cid->issuerNameHash->data, cid->issuerNameHash->length);
+ RETURN_IF_NOT(err == ERR_OK, err);
+ // check issuer key hash
+ if((ikey = get_authority_key(cert->cert_info->extensions)) != NULL) {
+ err = compareByteArrays(ikey, strlen((const char*)ikey),
+ cid->issuerKeyHash->data, cid->issuerKeyHash->length);
+ // cleanup ikey
+ free(ikey);
+ }
+ // verify nonce value
+ if(nonce->value->length == DIGEST_LEN)
+ err = compareByteArrays(nonce->value->data, nonce->value->length, nonce1, nonceLen);
+ else
+ err = compareByteArrays(nonce->value->data + 2, nonce->value->length - 2, nonce1, nonceLen);
+ ddocDebug(3, "checkNonceAndCertbyOCSP", "nonce1-len: %d nonce2-len: %d err: %d", nonce->value->length, nonceLen, err);
+ if (err != ERR_OK) SET_LAST_ERROR(err);
+ if(br)
+ OCSP_BASICRESP_free(br);
+ return err;
+}
+
diff --git a/libdigidoc/DigiDocOCSP.h b/libdigidoc/DigiDocOCSP.h
new file mode 100644
index 0000000..072d38e
--- /dev/null
+++ b/libdigidoc/DigiDocOCSP.h
@@ -0,0 +1,152 @@
+#ifndef __DIGIDOC_OCSP_H__
+#define __DIGIDOC_OCSP_H__
+//==================================================
+// FILE: DigiDocOCSP.h
+// PROJECT: Digi Doc
+// DESCRIPTION: DigiDoc OCSP handling routines
+// AUTHOR: Veiko Sinivee, S|E|B IT Partner Estonia
+//==================================================
+// Copyright (C) AS Sertifitseerimiskeskus
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+// GNU Lesser General Public Licence is available at
+// http://www.gnu.org/copyleft/lesser.html
+//==========< HISTORY >=============================
+// 26.04.2006 Veiko Sinivee
+// Creation
+//==================================================
+
+#include <libdigidoc/DigiDocDefs.h>
+#include <libdigidoc/DigiDocObj.h>
+#include <libdigidoc/DigiDocMem.h>
+
+#include <openssl/ocsp.h>
+
+//==========< XML generation routines >========================
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+//--------------------------------------------------
+// sends an OCSP_REQUES object to remore server and
+// retrieves the OCSP_RESPONSE object
+// resp - buffer to store the new responses pointer
+// req - request objects pointer
+// url - OCSP responder URL
+// ip_addr - senders ip address if known or 0
+//--------------------------------------------------
+int sendOCSPRequest(OCSP_RESPONSE** resp, OCSP_REQUEST *req,
+ char* url, char* proxyHost, char* proxyPort,
+ unsigned long ip_addr);
+
+// Decodes binary (DER) OCSP_RESPONSE data and returns a OCSP_RESPONSE object
+EXP_OPTION int ddocDecodeOCSPResponseData(OCSP_RESPONSE **ppResp, const byte* data, int len);
+
+// Decodes base64 (PEM) OCSP_RESPONSE data and returns a OCSP_RESPONSE object
+EXP_OPTION int ddocDecodeOCSPResponsePEMData(OCSP_RESPONSE **ppResp, const byte* data, int len);
+
+EXP_OPTION int writeOCSPRequest(SignedDoc* pSigDoc, const char* signerCertFile,
+ const char* issuertCertFile,
+ byte* nonce, int nlen, const char* szOutputFile);
+
+// Creates and sends an OCSP_REQUEST object
+// to the notary server, receives the response
+// and uses it to create a confirmation object.
+EXP_OPTION int getConfirmation(SignedDoc* pSigDoc, SignatureInfo* pSigInfo,
+ const X509** caCerts, const X509* pNotCert,
+ char* pkcs12FileName, char* pkcs12Password,
+ char* notaryURL, char* proxyHost, char* proxyPort);
+
+// another way to get OCSP confirmation by sending also callers ip address
+EXP_OPTION int getConfirmationWithIp(SignedDoc* pSigDoc, SignatureInfo* pSigInfo,
+ const X509** caCerts, const X509* pNotCert,
+ char* pkcs12FileName, char* pkcs12Password,
+ char* notaryURL, char* proxyHost, char* proxyPort,
+ unsigned long ip);
+
+// another way to get OCSP confirmation by sending also callers ip address
+EXP_OPTION int getConfirmationWithIpEx(SignedDoc* pSigDoc, SignatureInfo* pSigInfo,
+ const X509** caCerts, const X509* pNotCert,
+ char* pkcs12FileName, char* pkcs12Password,
+ char* notaryURL, char* proxyHost, char* proxyPort,
+ char* proxyUser, char* proxyPass, unsigned long ip);
+
+// use this if you passed NULL-s to getConfirmation() param notaryCert
+EXP_OPTION int finalizeAndVerifyNotary(SignedDoc* pSigDoc, SignatureInfo* pSigInfo,
+ NotaryInfo* pNotInf,
+ const X509** caCerts, const X509* pNotCert);
+
+//--------------------------------------------------
+// Adds responder certificate to notary, searches it's
+// CA chain and then verifies notary
+// pSigDoc - signed doc info
+// pSigInfo - signature info
+// caCertSearches - responder CA certs chain
+// notaryCert - notarys cert search
+// returns error code
+//--------------------------------------------------
+int EXP_OPTION finalizeAndVerifyNotary2(SignedDoc* pSigDoc, SignatureInfo* pSigInfo,
+ NotaryInfo* pNotInf,
+ const X509** caCerts, const X509* pNotCert, const X509* pSigCa);
+
+int ReadOCSPResponse(OCSP_RESPONSE **newOCSP_RESPONSE, const char* szFileName);
+int initializeNotaryInfoWithOCSP(SignedDoc *pSigDoc, NotaryInfo *pNotary,
+ OCSP_RESPONSE *resp, X509 *notCert, int initDigest);
+int initializeNotaryInfoWithOCSP2(SignedDoc *pSigDoc, NotaryInfo *pNotary,
+ OCSP_RESPONSE *resp, X509 *notCert, int initDigest);
+
+//--------------------------------------------------
+// Verfies OCSP_RESPONSE signature
+// pResp - signed OCSP response
+// caCerts - CA certificate pointer array terminated with NULL
+// CApath - path to (directory) all certs
+// notCertFile - Notary (e.g. OCSP responder) cert file
+//--------------------------------------------------
+int verifyOCSPResponse(OCSP_RESPONSE* pResp,
+ const X509** caCerts, const char *CApath,
+ const X509* notCert);
+
+//--------------------------------------------------
+// Helper function to read OCSP_RESPONSE from binary input data
+// ppResp - address of newly allocated OCSP_RESPONSE object
+// pMBufInData - input data
+// returns error code or ERR_OK
+//--------------------------------------------------
+int ddocOcspReadOcspResp(OCSP_RESPONSE** ppResp, DigiDocMemBuf* pMBufInData);
+
+//--------------------------------------------------
+// Helper function to write OCSP_RESPONSE to binary output data
+// pResp - address of OCSP_RESPONSE object
+// pMBufOutData - output data
+// returns error code or ERR_OK
+//--------------------------------------------------
+int ddocOcspWriteOcspResp(OCSP_RESPONSE* pResp, DigiDocMemBuf* pMBufOutData);
+
+// get OCSP in PEM form
+EXP_OPTION int getOcspPEM(OCSP_RESPONSE* pResp, int bHeaders, char** buf);
+
+//--------------------------------------------------
+// Helper function to return OCSP_RESPONSE in base64 form.
+// Memory buffer will be resized as necessary.
+// Caller must release output buffer.
+// pNotary - Notary object
+// bHeaders - 1= with headers, 0=no headers
+// pMBufOutData - output data
+// returns error code or ERR_OK
+//--------------------------------------------------
+EXP_OPTION int ddocGetOcspBase64(NotaryInfo *pNotary, int bHeaders, DigiDocMemBuf* pMBufOutData);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // __DIGIDOC_OCSP_H__
+
+
diff --git a/libdigidoc/DigiDocObj.c b/libdigidoc/DigiDocObj.c
new file mode 100644
index 0000000..4845f3e
--- /dev/null
+++ b/libdigidoc/DigiDocObj.c
@@ -0,0 +1,4415 @@
+//==================================================
+// FILE: DigiDocObj.c
+// PROJECT: Digi Doc
+// DESCRIPTION: DigiDoc helper routines for accessing dogidoc data
+// AUTHOR: Veiko Sinivee, S|E|B IT Partner Estonia
+//==================================================
+// Copyright (C) AS Sertifitseerimiskeskus
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+// GNU Lesser General Public Licence is available at
+// http://www.gnu.org/copyleft/lesser.html
+//==========< HISTORY >=============================
+// 26.04.2006 Veiko Sinivee
+// Creation
+//==================================================
+
+#include "DigiDocObj.h"
+#include "DigiDocGen.h"
+#include "DigiDocError.h"
+#include "DigiDocConvert.h"
+#include "DigiDocDebug.h"
+#include "DigiDocCert.h"
+#include "DigiDocOCSP.h"
+#include "DigiDocConfig.h"
+#include "DigiDocError.h"
+#include <string.h>
+#include <ctype.h>
+#include <openssl/rsa.h>
+#include <openssl/evp.h>
+#include <openssl/err.h>
+
+//============================================================
+// Sets a string element of a struct to a new value
+// dest - element pointer
+// value - new value
+// valLen - value length (use -1 for null terminated strings)
+//============================================================
+EXP_OPTION int setString(char** dest, const char* value, int valLen)
+{
+ RETURN_IF_NULL_PARAM(dest);
+ RETURN_IF_NULL_PARAM(value);
+
+ if(*dest) {
+ free(*dest);
+ *dest = NULL;
+ }
+ if(valLen == -1) {
+ *dest = (char*)malloc(strlen(value)+1);
+ RETURN_IF_BAD_ALLOC(*dest);
+ strncpy(*dest, value, strlen(value)+1);
+ } else {
+ *dest = (char*)malloc(valLen);
+ RETURN_IF_BAD_ALLOC(*dest);
+ memcpy(*dest, value, valLen);
+ }
+ return ERR_OK;
+}
+
+//============================================================
+// Allocates a new SignedDoc element and initializes it
+// format - format name
+// version - format version
+//============================================================
+EXP_OPTION int SignedDoc_new(SignedDoc **pSignedDoc, const char* format, const char* version)
+{
+ SignedDoc* pSigDoc = NULL;
+
+ RETURN_IF_NULL_PARAM(format);
+ RETURN_IF_NULL_PARAM(version);
+ ddocDebug(3, "SignedDoc_new", "format: %s version: %s", (format ? format : "NULL"), (version ? version : "NULL"));
+ pSigDoc = (SignedDoc*)malloc(sizeof(SignedDoc));
+ RETURN_IF_BAD_ALLOC(pSigDoc);
+ memset(pSigDoc, 0, sizeof(SignedDoc));
+ if(!strcmp(format, DIGIDOC_XML_1_1_NAME) &&
+ !strcmp(version, DIGIDOC_XML_1_3_VER)) {
+ setString(&(pSigDoc->szFormat), format, -1);
+ setString(&(pSigDoc->szFormatVer), version, -1);
+ setString(&(pSigDoc->szFileName), "", -1);
+ } else {
+ ddocDebug(3, "SignedDoc_new", "unsupported version");
+ SET_LAST_ERROR_RETURN_CODE(ERR_UNSUPPORTED_FORMAT);
+ }
+ *pSignedDoc = pSigDoc;
+ return ERR_OK;
+}
+
+//============================================================
+// Frees the memory of SignedDoc element
+// pSigDoc - element to free
+//============================================================
+EXP_OPTION void SignedDoc_free(SignedDoc* pSigDoc)
+{
+ int i;
+
+ RETURN_VOID_IF_NULL(pSigDoc);
+ for(i = 0; (pSigDoc->pDataFiles != NULL) &&
+ (i < pSigDoc->nDataFiles); i++)
+ DataFile_free(pSigDoc->pDataFiles[i]);
+ if(pSigDoc->pDataFiles)
+ free(pSigDoc->pDataFiles);
+ for(i = 0; (pSigDoc->pSignatures != NULL) &&
+ (i < pSigDoc->nSignatures); i++)
+ SignatureInfo_free(pSigDoc->pSignatures[i]);
+ if(pSigDoc->pSignatures)
+ free(pSigDoc->pSignatures);
+ if(pSigDoc->szFormat)
+ free(pSigDoc->szFormat);
+ if(pSigDoc->szFormatVer)
+ free(pSigDoc->szFormatVer);
+ if(pSigDoc->szFileName)
+ free(pSigDoc->szFileName);
+ if(pSigDoc->szProfile)
+ free(pSigDoc->szProfile);
+ if(pSigDoc)
+ free(pSigDoc);
+}
+
+
+//============================================================
+// Returns the number of data files
+// pSigDoc - signed doc pointer
+//============================================================
+EXP_OPTION int getCountOfDataFiles(const SignedDoc* pSigDoc)
+{
+ RETURN_OBJ_IF_NULL(pSigDoc, 0);
+ return pSigDoc->nDataFiles;
+}
+
+//============================================================
+// Returns the next free data file id
+// pSigDoc - signed doc pointer
+//============================================================
+EXP_OPTION int getNextDataFileId(const SignedDoc* pSigDoc)
+{
+ int id = 0, n, i;
+
+ RETURN_OBJ_IF_NULL(pSigDoc, 0);
+ for(i = 0; i < pSigDoc->nDataFiles; i++) {
+ DataFile* pDataFile = pSigDoc->pDataFiles[i];
+ RETURN_OBJ_IF_NULL(pDataFile, 0);
+ RETURN_OBJ_IF_NULL(pDataFile->szId, 0);
+ SET_LAST_ERROR_RETURN_IF_NOT(strlen(pDataFile->szId) > 1, ERR_EMPTY_STRING, 0);
+ n = atoi(pDataFile->szId+1);
+ if(id <= n)
+ id = n+1;
+ }
+ return id;
+}
+
+//============================================================
+// Returns the desired DataFile object
+// pSigDoc - signed doc pointer
+// nIdx - DataFile index (starting with 0)
+//============================================================
+EXP_OPTION DataFile* getDataFile(const SignedDoc* pSigDoc, int nIdx)
+{
+ RETURN_OBJ_IF_NULL(pSigDoc, NULL);
+ SET_LAST_ERROR_RETURN_IF_NOT(nIdx < pSigDoc->nDataFiles, ERR_BAD_DATAFILE_INDEX, NULL);
+ RETURN_OBJ_IF_NULL(pSigDoc->pDataFiles[nIdx], 0);
+ return pSigDoc->pDataFiles[nIdx];
+}
+
+//============================================================
+// Returns the last DataFile object
+// pSigDoc - signed doc pointer
+//============================================================
+EXP_OPTION DataFile* ddocGetLastDataFile(const SignedDoc* pSigDoc)
+{
+ int nIdx;
+ RETURN_OBJ_IF_NULL(pSigDoc, NULL);
+ nIdx = pSigDoc->nDataFiles - 1;
+ SET_LAST_ERROR_RETURN_IF_NOT(nIdx >= 0, ERR_BAD_DATAFILE_INDEX, NULL);
+ RETURN_OBJ_IF_NULL(pSigDoc->pDataFiles[nIdx], 0);
+ return pSigDoc->pDataFiles[nIdx];
+}
+
+//============================================================
+// Returns the DataFile object with the given id
+// pSigDoc - signed doc pointer
+// id - DataFile id
+//============================================================
+EXP_OPTION DataFile* getDataFileWithId(const SignedDoc* pSigDoc, const char* id)
+{
+ DataFile* pDataFile = NULL;
+ int i;
+ //AA 12.11.2003
+ RETURN_OBJ_IF_NULL(id, NULL);
+ RETURN_OBJ_IF_NULL(pSigDoc, NULL);
+ ddocDebug(4, "getDataFileWithId", "id: \'%s\', files: %d", id, pSigDoc->nDataFiles);
+ for(i = 0; i < pSigDoc->nDataFiles; i++) {
+ RETURN_OBJ_IF_NULL(pSigDoc->pDataFiles[i], NULL);
+ RETURN_OBJ_IF_NULL(pSigDoc->pDataFiles[i]->szId, NULL);
+ if(!strcmp(pSigDoc->pDataFiles[i]->szId, id)) {
+ pDataFile = pSigDoc->pDataFiles[i];
+ break;
+ }
+ }
+ return pDataFile;
+}
+
+
+//============================================================
+// Adds a new DataFile element to a SignedDoc element and initializes it
+// pSigDoc - signed document
+// id - data file id
+// filename - filename
+// contentType - EMBEDDED or EMBEDDED_BASE64
+// mime - mime type
+// size - file size
+// digType - digestType
+// digest - file digest (SHA1)
+// digLen - digest length
+//============================================================
+EXP_OPTION int DataFile_new(DataFile **newDataFile,
+ SignedDoc* pSigDoc, const char* id,
+ const char* filename, const char* contentType,
+ const char* mime, long size,
+ const byte* digest, int digLen,
+ const char* digType, const char* szCharset)
+{
+ char buf1[300];
+ int nId = 0, i, j, n;
+ DataFile **pDataFiles;
+ DataFile *pDataFile;
+ FILE* hFile;
+
+ RETURN_IF_NULL_PARAM(newDataFile);
+ RETURN_IF_NULL_PARAM(pSigDoc);
+ ddocDebug(3, "DataFile_new", "SigDoc ver: %s, file: %s, contentType: %s, mimeType: %s",
+ (pSigDoc ? pSigDoc->szFormatVer : "NULL"), (filename ? filename : "NULL"), contentType, mime);
+ //clearErrors();
+ if(!id)
+ nId = getNextDataFileId(pSigDoc);
+ if(pSigDoc->nDataFiles == 0) {
+ SET_LAST_ERROR_RETURN_IF_NOT(!pSigDoc->pDataFiles, ERR_BAD_DATAFILE_COUNT, 0);
+ pSigDoc->nDataFiles = 1;
+ }
+ else
+ pSigDoc->nDataFiles++;
+ pDataFiles = (DataFile**)malloc((pSigDoc->nDataFiles) * sizeof(void *));
+
+ RETURN_IF_BAD_ALLOC(pDataFiles);
+ for(i = 0; i < pSigDoc->nDataFiles-1; i++)
+ pDataFiles[i] = pSigDoc->pDataFiles[i];
+ pDataFile = (DataFile*)malloc(sizeof(DataFile));
+ RETURN_IF_BAD_ALLOC(pDataFile);
+ memset(pDataFile, 0, sizeof(DataFile));
+ pDataFiles[pSigDoc->nDataFiles-1] = pDataFile;
+ if(pSigDoc->pDataFiles)
+ free(pSigDoc->pDataFiles);
+ pSigDoc->pDataFiles = pDataFiles;
+ if(id) {
+ j = 0; n = strlen(id);
+ if(n < 2 || id[0] != 'D') j = -1;
+ if(j == 0 && n >= 2 && !isdigit(id[1]) && id[1] != 'O') j = -1;
+ for(i = 2; j == 0 && i < n; i++)
+ if(!isdigit(id[i])) j = -1;
+ if(j == -1) {
+ ddocDebug(1, "DataFile_new", "Invalid DataFile id: %s", id);
+ SET_LAST_ERROR(ERR_BAD_PARAM);
+ }
+ setString(&(pDataFile->szId), id, -1);
+ } else {
+ snprintf(buf1, sizeof(buf1), "D%d", nId);
+ setString(&(pDataFile->szId), buf1, -1);
+ }
+ if(szCharset)
+ setString(&(pDataFile->szCharset), szCharset, -1);
+ else
+ setString(&(pDataFile->szCharset), CHARSET_ISO_8859_1, -1);
+ if(filename) {
+ // in versions 1.0, 1.1 and 1.2 we used wrong encoding for OEM windows charset
+ setString(&(pDataFile->szFileName), filename, -1);
+ if(!strcmp(contentType, CONTENT_EMBEDDED)) {
+ if((hFile = fopen(pDataFile->szFileName, "rt")) != NULL) {
+ fgets(buf1, sizeof(buf1), hFile);
+ if(strstr(buf1, "<?xml"))
+ SET_LAST_ERROR(ERR_BAD_DATAFILE_XML);
+ fclose(hFile);
+ }
+ }
+ }
+ if(mime)
+ setString(&(pDataFile->szMimeType), mime, -1);
+ if((!contentType || strcmp(contentType, CONTENT_EMBEDDED_BASE64))
+ && !ConfigItem_lookup_bool("EMBEDDED_XML_SUPPORT", 0)) {
+ SET_LAST_ERROR(ERR_BAD_DATAFILE_CONTENT_TYPE);
+ return ERR_BAD_DATAFILE_CONTENT_TYPE;
+ }
+ if(contentType)
+ setString(&(pDataFile->szContentType), contentType, -1);
+ pDataFile->nSize = size;
+ if(digType && strlen(digType))
+ setString(&(pDataFile->szDigestType), digType, -1);
+ if(digest && digLen)
+ ddocMemAssignData(&(pDataFile->mbufDigest), (const char*)digest, digLen);
+ *newDataFile = pDataFile;
+ return ERR_OK;
+}
+
+
+//============================================================
+// Removes this DataFile from signed doc and frees it's memory
+// pSigDoc - signed doc object
+// id - DataFile id to be removed
+//============================================================
+EXP_OPTION int DataFile_delete(SignedDoc* pSigDoc, const char* id)
+{
+ int err = ERR_OK, n, i, j;
+ DataFile* pDataFile = NULL;
+ DataFile** pDataFiles = NULL;
+
+ RETURN_IF_NULL_PARAM(pSigDoc);
+ ddocDebug(3, "DataFile_delete", "id: %s", id);
+ if(pSigDoc->nSignatures > 0)
+ SET_LAST_ERROR_RETURN_CODE(ERR_MODIFY_SIGNED_DOC);
+ if((pDataFile = getDataFileWithId(pSigDoc, id)) != 0) {
+ n = pSigDoc->nDataFiles - 1;
+ if(n > 0) {
+ pDataFiles = (DataFile**)malloc(n * sizeof(void*));
+ RETURN_IF_BAD_ALLOC(pDataFiles);
+ for(i = j = 0; i < pSigDoc->nDataFiles; i++) {
+ if(strcmp(pSigDoc->pDataFiles[i]->szId, id))
+ pDataFiles[j++] = pSigDoc->pDataFiles[i];
+ else{
+ DataFile_free(pSigDoc->pDataFiles[i]);}
+ }
+ free(pSigDoc->pDataFiles);
+ pSigDoc->pDataFiles = pDataFiles;
+ pSigDoc->nDataFiles = n;
+ } else {
+ for(i = 0; i < pSigDoc->nDataFiles; i++){
+ DataFile_free(pSigDoc->pDataFiles[i]);}
+ free(pSigDoc->pDataFiles);
+ pSigDoc->pDataFiles = NULL;
+ pSigDoc->nDataFiles = 0;
+ }
+ }
+ else
+ err = ERR_BAD_DATAFILE_INDEX;
+ if (err != ERR_OK) SET_LAST_ERROR(err);
+ return err;
+}
+
+//============================================================
+// Retrieve and convert cached DataFile data if possible
+// pSigDoc - signed document object
+// szDocId - datafile id
+// ppBuf - address of buffer pointer
+// pLen - address of lenght of bytes
+//============================================================
+EXP_OPTION int ddocGetDataFileCachedData(SignedDoc* pSigDoc, const char* szDocId, void** ppBuf, long* pLen)
+{
+ DataFile* pDf;
+ DigiDocMemBuf mbuf1;
+ int err1 = 0;
+
+ mbuf1.pMem = 0; mbuf1.nLen = 0;
+
+ //RETURN_IF_NULL_PARAM(pSigDoc); // if null then don't check for cached data (old logic)
+ RETURN_IF_NULL_PARAM(szDocId);
+ RETURN_IF_NULL_PARAM(ppBuf);
+ RETURN_IF_NULL_PARAM(pLen);
+ *ppBuf = 0;
+ *pLen = 0;
+ if(pSigDoc) {
+ pDf = getDataFileWithId(pSigDoc, szDocId);
+ if(pDf && pDf->mbufContent.pMem) { // gotcha!
+ int len;
+ // base64 content, allocate exact length and initialize
+ if(!strcmp(pDf->szContentType, CONTENT_EMBEDDED_BASE64)) {
+ err1 = ddocMemSetLength(&mbuf1, pDf->mbufContent.nLen);
+ if(err1) {
+ ddocMemBuf_free(&mbuf1);
+ return err1;
+ }
+ *ppBuf = mbuf1.pMem;
+ *pLen = mbuf1.nLen;
+ err1 = ddocDecodeBase64(&(pDf->mbufContent), &mbuf1);
+ if(err1) {
+ ddocMemBuf_free(&mbuf1);
+ return err1;
+ }
+ mbuf1.pMem = 0; mbuf1.nLen = 0; // release ownership
+ }
+ // simple text content. Make it zero terminated string
+ else if(!strcmp(pDf->szContentType, CONTENT_EMBEDDED)) {
+ *ppBuf = malloc(pDf->mbufContent.nLen+1);
+ RETURN_IF_BAD_ALLOC(*ppBuf);
+ *pLen = pDf->mbufContent.nLen;
+ memcpy(*ppBuf, pDf->mbufContent.pMem, pDf->mbufContent.nLen);
+ ((char*)(*ppBuf))[*pLen] = 0;
+ }
+ }
+ }
+ return ERR_OK;
+}
+
+//============================================================
+// Retrieve and convert DataFile Filename atribute and convert
+// to proper UTF-8 if necessary.
+// pSigDoc - signed document object
+// szDocId - datafile id
+// ppBuf - address of buffer pointer. Caller must free the buffer
+// pLen - address of lenght of bytes. Will be changed.
+//============================================================
+EXP_OPTION int ddocGetDataFileFilename(SignedDoc* pSigDoc, const char* szDocId, void** ppBuf, int* pLen)
+{
+ DataFile* pDf;
+
+ RETURN_IF_NULL_PARAM(pSigDoc);
+ RETURN_IF_NULL_PARAM(szDocId);
+ RETURN_IF_NULL_PARAM(ppBuf);
+ RETURN_IF_NULL_PARAM(pLen);
+ *ppBuf = 0;
+ *pLen = 0;
+ if(pSigDoc) {
+ pDf = getDataFileWithId(pSigDoc, szDocId);
+ if(pDf && pDf->szFileName) { // gotcha!
+ *ppBuf = unescapeXmlsym((const char*)pDf->szFileName);
+ *pLen = strlen((const char*)*ppBuf);
+ // in version 1.2 and earlier we had bad UTF-8 for some chars
+ // check and fix it for newer clients
+ if((!strcmp(pSigDoc->szFormatVer, SK_XML_1_VER) && !strcmp(pSigDoc->szFormat, SK_XML_1_NAME)) ||
+ !strcmp(pSigDoc->szFormatVer, DIGIDOC_XML_1_1_VER) ||
+ !strcmp(pSigDoc->szFormatVer, DIGIDOC_XML_1_2_VER)) {
+ convWinToFName(pDf->szFileName, (char*)*ppBuf, *pLen+1);
+ }
+ }
+ }
+ return ERR_OK;
+}
+
+//--------------------------------------------------
+// Checks if the size of this DataFile is less than
+// max size for memory cache and if so caches the data.
+// pDf - DataFile object
+// maxLen - max cacheable DataFile size
+// value - character values read from file
+// len - length of chars ???
+// isBase64 - is allready in base64 form or not (1/0)
+//--------------------------------------------------
+EXP_OPTION void ddocAppendDataFileData(DataFile* pDf, int maxLen, void* data, int len, int isBase64)
+{
+ DigiDocMemBuf mbuf1, mbuf2;
+
+ mbuf1.pMem = 0;
+ mbuf1.nLen = 0;
+ ddocDebug(5, "ddocAppendDataFileData", "append: %d, max: %d", len, maxLen);
+ if(pDf && pDf->nSize < maxLen) {
+ ddocDebug(6, "ddocAppendDataFileData", "DF: %s, size: %d, max: %d", pDf->szId, pDf->nSize, maxLen);
+ // original content must be kept in the form it will exist in file
+ if(!strcmp(pDf->szContentType, CONTENT_EMBEDDED_BASE64) && !isBase64) {
+ mbuf2.pMem = data;
+ mbuf2.nLen = len;
+ ddocEncodeBase64(&mbuf2, &mbuf1);
+ ddocMemAppendData(&(pDf->mbufContent), mbuf1.pMem, mbuf1.nLen);
+ ddocMemBuf_free(&mbuf1);
+ }
+ else
+ ddocMemAppendData(&(pDf->mbufContent), data, len);
+ }
+}
+
+//--------------------------------------------------
+// Creates new DataFile and assigns contet from memory
+// ppDataFile address of pointer to return new DataFile object
+// pSigDoc - SignedDoc object
+// id - new DataFile id. Use NULL for default
+// filename - filename
+// contentType - content type
+// mime - mime type
+// pData - address of DataFile content to be assigned
+// size - length of data in bytes
+// return error code
+//--------------------------------------------------
+EXP_OPTION int createDataFileInMemory(DataFile **ppDataFile, SignedDoc* pSigDoc, const char* id,
+ const char* filename, const char* contentType,
+ const char* mime, const char* pData, long size)
+{
+ int err = ERR_OK;
+ DigiDocMemBuf mbuf1;
+
+ mbuf1.pMem = 0;
+ mbuf1.nLen = 0;
+ err = DataFile_new(ppDataFile, pSigDoc, id,
+ filename, contentType,
+ mime, size, NULL, 0, DIGEST_SHA1_NAME, NULL);
+ if(!err && pData) {
+ ddocAppendDataFileData(*ppDataFile, size+1, (void*)pData, size, 0);
+ // calculate hash so it can be used in signing
+ err = generateDataFileXML(pSigDoc, *ppDataFile, NULL, NULL, &mbuf1);
+ ddocMemBuf_free(&mbuf1);
+ }
+ return err;
+}
+
+//============================================================
+// cleanup DataFile memory
+// pDataFile - data file object to be cleaned up
+//============================================================
+EXP_OPTION void DataFile_free(DataFile* pDataFile)
+{
+ int i=0;
+
+ RETURN_VOID_IF_NULL(pDataFile);
+ if(pDataFile->szId)
+ free(pDataFile->szId);
+ if(pDataFile->szFileName)
+ free(pDataFile->szFileName);
+ if(pDataFile->szMimeType)
+ free(pDataFile->szMimeType);
+ if(pDataFile->szDigestType)
+ free(pDataFile->szDigestType);
+ ddocMemBuf_free(&(pDataFile->mbufDigest));
+ ddocMemBuf_free(&(pDataFile->mbufWrongDigest));
+ ddocMemBuf_free(&(pDataFile->mbufDetachedDigest));
+ if(pDataFile->szContentType)
+ free(pDataFile->szContentType);
+ for(i = 0; i < pDataFile->nAttributes; i++) {
+ free(pDataFile->pAttNames[i]);
+ free(pDataFile->pAttValues[i]);
+ }
+ if(pDataFile->szCharset)
+ free(pDataFile->szCharset);
+ if(pDataFile->pAttNames)
+ free(pDataFile->pAttNames);
+ if(pDataFile->pAttValues)
+ free(pDataFile->pAttValues);
+ ddocMemBuf_free(&(pDataFile->mbufContent));
+ free(pDataFile);
+}
+
+//--------------------------------------------------
+// Accessor for Digest atribute of DataFile object.
+// pDataFile - address of object [REQUIRED]
+// returns value of atribute or NULL.
+//--------------------------------------------------
+EXP_OPTION DigiDocMemBuf* ddocDataFile_GetDigestValue(DataFile* pDataFile)
+{
+ RETURN_OBJ_IF_NULL(pDataFile, NULL)
+ return &(pDataFile->mbufDigest);
+}
+
+//--------------------------------------------------
+// Mutatoror for Digest atribute of DataFile object.
+// pDataFile - address of object [REQUIRED]
+// value - new value for atribute [REQUIRED]
+// len - length of value in bytes [REQUIRED]
+// returns error code or ERR_OK
+//--------------------------------------------------
+EXP_OPTION int ddocDataFile_SetDigestValue(DataFile* pDataFile,
+ const char* value, long len)
+{
+ int err = ERR_OK;
+ RETURN_IF_NULL_PARAM(pDataFile)
+ RETURN_IF_NULL_PARAM(value)
+ err = ddocMemAssignData(&(pDataFile->mbufDigest), value, len);
+ return err;
+}
+
+
+//--------------------------------------------------
+// Accessor for DetachedDigest atribute of DataFile object.
+// pDataFile - address of object [REQUIRED]
+// returns value of atribute or NULL.
+//--------------------------------------------------
+EXP_OPTION DigiDocMemBuf* ddocDataFile_GetDetachedDigestValue(DataFile* pDataFile)
+{
+ RETURN_OBJ_IF_NULL(pDataFile, NULL)
+ return &(pDataFile->mbufDetachedDigest);
+}
+
+//--------------------------------------------------
+// Mutatoror for DetachedDigest atribute of DataFile object.
+// pDataFile - address of object [REQUIRED]
+// value - new value for atribute [REQUIRED]
+// len - length of value in bytes [REQUIRED]
+// returns error code or ERR_OK
+//--------------------------------------------------
+EXP_OPTION int ddocDataFile_SetDetachedDigestValue(DataFile* pDataFile,
+ const char* value, long len)
+{
+ int err = ERR_OK;
+ RETURN_IF_NULL_PARAM(pDataFile)
+ RETURN_IF_NULL_PARAM(value)
+ err = ddocMemAssignData(&(pDataFile->mbufDetachedDigest), value, len);
+ return err;
+}
+
+//--------------------------------------------------
+// Accessor for WrongDigest atribute of DataFile object.
+// pDataFile - address of object [REQUIRED]
+// returns value of atribute or NULL.
+//--------------------------------------------------
+EXP_OPTION DigiDocMemBuf* ddocDataFile_GetWrongDigestValue(DataFile* pDataFile)
+{
+ RETURN_OBJ_IF_NULL(pDataFile, NULL)
+ return &(pDataFile->mbufWrongDigest);
+}
+
+//--------------------------------------------------
+// Mutatoror for WrongDigest atribute of DataFile object.
+// pDataFile - address of object [REQUIRED]
+// value - new value for atribute [REQUIRED]
+// len - length of value in bytes [REQUIRED]
+// returns error code or ERR_OK
+//--------------------------------------------------
+EXP_OPTION int ddocDataFile_SetWrongDigestValue(DataFile* pDataFile,
+ const char* value, long len)
+{
+ int err = ERR_OK;
+ RETURN_IF_NULL_PARAM(pDataFile)
+ RETURN_IF_NULL_PARAM(value)
+ err = ddocMemAssignData(&(pDataFile->mbufWrongDigest), value, len);
+ return err;
+}
+
+//============================================================
+// Removes this NotaryInfo from signed doc and frees it's memory
+// pSigInfo - signature object
+// id - notary id to be removed
+//============================================================
+EXP_OPTION int NotaryInfo_delete(SignatureInfo* pSigInfo)
+{
+ RETURN_IF_NULL_PARAM(pSigInfo);
+ if(pSigInfo->pNotary) {
+ NotaryInfo_free(pSigInfo->pNotary);
+ pSigInfo->pNotary = 0;
+ }
+ return ERR_OK;
+}
+
+//============================================================
+// Returns number of DataFile attributes
+// pDataFile - data file
+//============================================================
+EXP_OPTION int getCountOfDataFileAttributes(const DataFile* pDataFile)
+{
+ RETURN_OBJ_IF_NULL(pDataFile, -1);
+ return pDataFile->nAttributes;
+}
+
+//============================================================
+// Adds an attribute to data file
+// pDataFile - data file
+// name - attribute name
+// value - attribute value
+//============================================================
+// FIXME : Badly in need for a rewrite - memory leaks, when something fails.
+int addDataFileAttribute(DataFile* pDataFile, const char* name, const char* value)
+{
+ char **pp;
+ int i;
+
+ RETURN_IF_NULL_PARAM(pDataFile);
+ RETURN_IF_NULL_PARAM(name);
+ RETURN_IF_NULL_PARAM(value);
+ if(pDataFile->nAttributes == 0) {
+ RETURN_IF_NOT(!pDataFile->pAttNames, ERR_BAD_ATTR_COUNT);
+ RETURN_IF_NOT(!pDataFile->pAttValues, ERR_BAD_ATTR_COUNT);
+ pDataFile->nAttributes = 1;
+ }
+ else
+ pDataFile->nAttributes++;
+ // set name
+ pp = (char**)malloc((pDataFile->nAttributes) * sizeof(char *));
+ RETURN_IF_BAD_ALLOC(pp);
+ for(i = 0; i < pDataFile->nAttributes-1; i++)
+ pp[i] = pDataFile->pAttNames[i];
+ if(pDataFile->pAttNames)
+ free(pDataFile->pAttNames);
+ pDataFile->pAttNames = pp;
+ pp[pDataFile->nAttributes-1] = NULL;
+ setString(&(pp[pDataFile->nAttributes-1]), name, -1);
+ // set value
+ pp = (char**)malloc((pDataFile->nAttributes) * sizeof(char *));
+ RETURN_IF_BAD_ALLOC(pp);
+ for(i = 0; i < pDataFile->nAttributes-1; i++)
+ pp[i] = pDataFile->pAttValues[i];
+ if(pDataFile->pAttValues)
+ free(pDataFile->pAttValues);
+ pDataFile->pAttValues = pp;
+ pp[pDataFile->nAttributes-1] = NULL;
+ setString(&(pp[pDataFile->nAttributes-1]), value, -1);
+ return ERR_OK;
+}
+
+
+//============================================================
+// Gets an attribute of a data file
+// pDataFile - data file
+// name - buffer for attribute name pointer
+// value - buffer for attribute value pointer
+//============================================================
+EXP_OPTION int getDataFileAttribute(DataFile* pDataFile, int idx, char** name, char** value)
+{
+
+ RETURN_IF_NULL_PARAM(pDataFile);
+ RETURN_IF_NOT(idx < pDataFile->nAttributes, ERR_BAD_ATTR_INDEX);
+ RETURN_IF_NULL_PARAM(name);
+ RETURN_IF_NULL_PARAM(value);
+ *name = pDataFile->pAttNames[idx];
+ *value = pDataFile->pAttValues[idx];
+ return ERR_OK;
+}
+
+//============================================================
+// Calculates the file size and digest
+// pSigDoc - signed document
+// id - data file id
+// filename - filename
+// digType - digestType (code)
+//============================================================
+EXP_OPTION int calculateDataFileSizeAndDigest(SignedDoc* pSigDoc, const char* id,
+ const char* filename, int digType)
+{
+ int err = ERR_OK, len1 = 0;
+ char buf1[DIGEST_LEN+2];
+ long len2 = 0;
+ DataFile* pDataFile;
+
+ RETURN_IF_NULL_PARAM(pSigDoc);
+ ddocDebug(3, "calculateDataFileSizeAndDigest", "File: %s id: %s", filename, id);
+ pDataFile = getDataFileWithId(pSigDoc, id);
+ RETURN_IF_NOT(pDataFile, ERR_FILE_READ);
+ if(digType == DIGEST_SHA1) {
+ // in version 1.0 we use DigestType and DigestValue
+ // attrributes of DataFile element and calculate the digest
+ // over the original content
+ if(!strcmp(pSigDoc->szFormat, SK_XML_1_NAME) && !strcmp(pSigDoc->szFormatVer, SK_XML_1_VER)) {
+ len1 = sizeof(buf1);
+ err = calculateFileDigest(filename, digType,
+ (byte*)buf1, &len1, &len2);
+ RETURN_IF_NOT(err == ERR_OK, err);
+ ddocDataFile_SetDigestValue(pDataFile, buf1, len1);
+ pDataFile->nSize = len2;
+ }
+ // in version 1.1 we don't use those attributes
+ // and we calculate the digest over the whole
+ // DataFile element including the tags
+ else {
+ err = calculateFileSize(filename, &pDataFile->nSize);
+ ddocDebug(4, "calculateDataFileSizeAndDigest", "File: %s size: %d", filename, pDataFile->nSize);
+ err = generateDataFileXML(pSigDoc, pDataFile, filename, NULL, NULL);
+ }
+ }
+ else
+ SET_LAST_ERROR_RETURN_CODE(ERR_UNSUPPORTED_DIGEST);
+ return err;
+}
+
+
+//=======================< DigestValue >=====================================
+
+//--------------------------------------------------
+// "Constructor" of DigestValue object
+// ppDigestValue - address of buffer for newly allocated object [REQUIRED]
+// szDigestMethod - digest method [OPTIONAL]
+// szDigVal/lDigLen - digest value and length [OPTIONAL]
+// returns error code or ERR_OK
+//--------------------------------------------------
+EXP_OPTION int ddocDigestValue_new(DigestValue** ppDigestValue,
+ const char* szDigestMethod,
+ void* szDigVal, long lDigLen)
+{
+ int err = ERR_OK;
+
+ // check input parameters
+ ddocDebug(4, "ddocDigestValue_new", "DigestMethod: %s, dig-len: %ld",
+ (szDigestMethod ? szDigestMethod : "NULL"), lDigLen);
+ RETURN_IF_NULL_PARAM(ppDigestValue);
+ *ppDigestValue = 0; // mark as not yet allocated
+ // allocate memory for new DigestValue
+ *ppDigestValue = (DigestValue*)malloc(sizeof(DigestValue));
+ if(!(*ppDigestValue))
+ SET_LAST_ERROR_RETURN(ERR_BAD_ALLOC, ERR_BAD_ALLOC)
+ memset(*ppDigestValue, 0, sizeof(DigestValue));
+ // set optional fields
+ if(szDigestMethod) {
+ err = ddocMemAssignString((char**)&((*ppDigestValue)->szDigestMethod), szDigestMethod);
+ if(err) return err;
+ } else { // default is sha1
+ err = ddocMemAssignString((char**)&((*ppDigestValue)->szDigestMethod), DIGEST_METHOD_SHA1);
+ }
+ if(szDigVal && lDigLen)
+ err = ddocMemAssignData(&((*ppDigestValue)->mbufDigestValue), szDigVal, lDigLen);
+ return err;
+}
+
+//--------------------------------------------------
+// "Destructor" of DigestValue object
+// pDigestValue - address of object to be deleted [REQUIRED]
+// returns error code or ERR_OK
+//--------------------------------------------------
+EXP_OPTION int ddocDigestValue_free(DigestValue* pDigestValue)
+{
+ int err = ERR_OK;
+ RETURN_IF_NULL_PARAM(pDigestValue)
+ // cleanup this object
+ if(pDigestValue->szDigestMethod)
+ free(pDigestValue->szDigestMethod);
+ ddocMemBuf_free(&(pDigestValue->mbufDigestValue));
+ free(pDigestValue);
+ return err;
+}
+
+//--------------------------------------------------
+// Accessor for DigestMethod atribute of DigestValue object.
+// pDigestValue - address of object [REQUIRED]
+// returns value of atribute or NULL.
+//--------------------------------------------------
+EXP_OPTION const char* ddocDigestValue_GetDigestMethod(DigestValue* pDigestValue)
+{
+ RETURN_OBJ_IF_NULL(pDigestValue, NULL)
+ return pDigestValue->szDigestMethod;
+}
+
+//--------------------------------------------------
+// Mutatoror for DigestMethod atribute of DigestValue object.
+// pDigestValue - address of object [REQUIRED]
+// value - new value for atribute [REQUIRED]
+// returns error code or ERR_OK
+//--------------------------------------------------
+EXP_OPTION int ddocDigestValue_SetDigestMethod(DigestValue* pDigestValue, const char* value)
+{
+ int err = ERR_OK;
+ RETURN_IF_NULL_PARAM(pDigestValue)
+ RETURN_IF_NULL_PARAM(value)
+ err = ddocMemAssignString((char**)&(pDigestValue->szDigestMethod), value);
+ return err;
+}
+
+//--------------------------------------------------
+// Accessor for DigestValue atribute of DigestValue object.
+// pDigestValue - address of object [REQUIRED]
+// returns value of atribute or NULL.
+//--------------------------------------------------
+EXP_OPTION DigiDocMemBuf* ddocDigestValue_GetDigestValue(DigestValue* pDigestValue)
+{
+ RETURN_OBJ_IF_NULL(pDigestValue, NULL)
+ return &(pDigestValue->mbufDigestValue);
+}
+
+//--------------------------------------------------
+// Mutatoror for DigestValue atribute of DigestValue object.
+// pDigestValue - address of object [REQUIRED]
+// value - new value for atribute [REQUIRED]
+// len - length of value in bytes [REQUIRED]
+// returns error code or ERR_OK
+//--------------------------------------------------
+EXP_OPTION int ddocDigestValue_SetDigestValue(DigestValue* pDigestValue,
+ const char* value, long len)
+{
+ int err = ERR_OK;
+ RETURN_IF_NULL_PARAM(pDigestValue)
+ RETURN_IF_NULL_PARAM(value)
+ err = ddocMemAssignData(&(pDigestValue->mbufDigestValue), value, len);
+ return err;
+}
+
+//--------------------------------------------------
+// Compares two DigestValue structure on equality
+// pDigest1 - address of first digest [REQUIRED]
+// pDigest2 - address of second digest [REQUIRED]
+// returns error code or ERR_OK
+//--------------------------------------------------
+int ddocCompareDigestValues(DigestValue* pDigest1, DigestValue* pDigest2)
+{
+ RETURN_IF_NULL_PARAM(pDigest1)
+ RETURN_IF_NULL_PARAM(pDigest2)
+ return compareByteArrays((const byte*)pDigest1->mbufDigestValue.pMem,
+ pDigest1->mbufDigestValue.nLen,
+ (const byte*)pDigest2->mbufDigestValue.pMem,
+ pDigest2->mbufDigestValue.nLen);
+}
+
+//--------------------------------------------------
+// Generates XML for <DigestValue> element
+// pSigDoc - signed doc object [REQUIRED]
+// pDigestValue - DigestValue object [REQUIRED]
+// pBuf - memory buffer for storing xml [REQUIRED]
+// returns error code or ERR_OK
+//--------------------------------------------------
+int ddocDigestValue_toXML(const DigestValue* pDigestValue, DigiDocMemBuf* pBuf)
+{
+ int err = ERR_OK;
+ DigiDocMemBuf mbuf1;
+
+ RETURN_IF_NULL_PARAM(pBuf)
+ RETURN_IF_NULL_PARAM(pDigestValue)
+ mbuf1.pMem = 0;
+ mbuf1.nLen = 0;
+ // DigestMethod
+ if(pDigestValue->szDigestMethod) {
+ err = ddocGen_startElemBegin(pBuf, "DigestMethod");
+ if(err) return err;
+ // Algorithm atribute
+ err = ddocGen_addAtribute(pBuf, "Algorithm", pDigestValue->szDigestMethod);
+ if(err) return err;
+ //err = ddocGen_startElemEnd(pBuf);
+ //err = ddocGen_endElem(pBuf, "DigestMethod");
+ // end of element start tag
+ err = ddocMemAppendData(pBuf, "/>\n", -1);
+ }
+ if(pDigestValue->mbufDigestValue.pMem) {
+ err = ddocGen_startElem(pBuf, "DigestValue");
+ }
+
+ if(err) return err;
+ // digest value
+ ddocEncodeBase64(&(pDigestValue->mbufDigestValue), &mbuf1);
+ //AM 17.11.08 to remove newline after base64
+ if(mbuf1.pMem && ((char*)mbuf1.pMem)[strlen((const char*)mbuf1.pMem)-1] == '\n')
+ ((char*)mbuf1.pMem)[strlen((const char*)mbuf1.pMem)-1] = 0;
+ err = ddocMemAppendData(pBuf, (char*)mbuf1.pMem, -1);
+ ddocMemBuf_free(&mbuf1);
+ if(err) return err;
+ err = ddocGen_endElem(pBuf, "DigestValue");
+ err = ddocMemAppendData(pBuf, "\n", -1);
+ return err;
+}
+
+//======================< SignatureValue >====================================
+
+//--------------------------------------------------
+// "Constructor" of SignatureValue object
+// ppSignatureValue - address of buffer for newly allocated object [REQUIRED]
+// szId - Id atribute value [OPTIONAL]
+// szType - signature type [OPTIONAL]
+// szDigVal/lDigLen - digest value and length [OPTIONAL]
+// returns error code or ERR_OK
+//--------------------------------------------------
+EXP_OPTION int ddocSignatureValue_new(SignatureValue** ppSignatureValue,
+ const char* szId, const char* szType,
+ void* szSigVal, long lSigLen)
+{
+ int err = ERR_OK;
+
+ // check input parameters
+ ddocDebug(4, "ddocSignatureValue_new", "id: %s, type: %s, dig-len: %ld",
+ (szId ? szId : "NULL"), (szType ? szType : "NULL"), lSigLen);
+ RETURN_IF_NULL_PARAM(ppSignatureValue);
+ *ppSignatureValue = 0; // mark as not yet allocated
+ // allocate memory for new DigestValue
+ *ppSignatureValue = (SignatureValue*)malloc(sizeof(SignatureValue));
+ if(!(*ppSignatureValue))
+ SET_LAST_ERROR_RETURN(ERR_BAD_ALLOC, ERR_BAD_ALLOC)
+ memset(*ppSignatureValue, 0, sizeof(SignatureValue));
+ // set optional fields
+ if(szId) {
+ err = ddocMemAssignString((char**)&((*ppSignatureValue)->szId), szId);
+ if(err) return err;
+ }
+ if(szType) {
+ err = ddocMemAssignString((char**)&((*ppSignatureValue)->szType), szType);
+ if(err) return err;
+ }
+ if(szSigVal && lSigLen)
+ err = ddocMemAssignData(&((*ppSignatureValue)->mbufSignatureValue), szSigVal, lSigLen);
+ return err;
+}
+
+//--------------------------------------------------
+// "Destructor" of SignatureValue object
+// pSignatureValue - address of object to be deleted [REQUIRED]
+// returns error code or ERR_OK
+//--------------------------------------------------
+EXP_OPTION int ddocSignatureValue_free(SignatureValue* pSignatureValue)
+{
+ int err = ERR_OK;
+ RETURN_IF_NULL_PARAM(pSignatureValue)
+ // cleanup this object
+ if(pSignatureValue->szId)
+ free(pSignatureValue->szId);
+ if(pSignatureValue->szType)
+ free(pSignatureValue->szType);
+ ddocMemBuf_free(&(pSignatureValue->mbufSignatureValue));
+ free(pSignatureValue);
+ return err;
+}
+
+//--------------------------------------------------
+// Accessor for Id atribute of SignatureValue object.
+// pSignatureValue - address of object [REQUIRED]
+// returns value of atribute or NULL.
+//--------------------------------------------------
+EXP_OPTION const char* ddocSignatureValue_GetId(const SignatureValue* pSignatureValue)
+{
+ RETURN_OBJ_IF_NULL(pSignatureValue, NULL)
+ return pSignatureValue->szId;
+}
+
+//--------------------------------------------------
+// Mutatoror for Id atribute of SignatureValue object.
+// pSignatureValue - address of object [REQUIRED]
+// value - new value for atribute [REQUIRED]
+// returns error code or ERR_OK
+//--------------------------------------------------
+EXP_OPTION int ddocSignatureValue_SetId(SignatureValue* pSignatureValue, const char* value)
+{
+ int err = ERR_OK;
+ RETURN_IF_NULL_PARAM(pSignatureValue)
+ RETURN_IF_NULL_PARAM(value)
+ err = ddocMemAssignString((char**)&(pSignatureValue->szId), value);
+ return err;
+}
+
+//--------------------------------------------------
+// Accessor for Type atribute of SignatureValue object.
+// pSignatureValue - address of object [REQUIRED]
+// returns value of atribute or NULL.
+//--------------------------------------------------
+EXP_OPTION const char* ddocSignatureValue_GetType(const SignatureValue* pSignatureValue)
+{
+ RETURN_OBJ_IF_NULL(pSignatureValue, NULL)
+ return pSignatureValue->szType;
+}
+
+//--------------------------------------------------
+// Mutatoror for Type atribute of SignatureValue object.
+// pSignatureValue - address of object [REQUIRED]
+// value - new value for atribute [REQUIRED]
+// returns error code or ERR_OK
+//--------------------------------------------------
+EXP_OPTION int ddocSignatureValue_SetType(SignatureValue* pSignatureValue, const char* value)
+{
+ int err = ERR_OK;
+ RETURN_IF_NULL_PARAM(pSignatureValue)
+ RETURN_IF_NULL_PARAM(value)
+ err = ddocMemAssignString((char**)&(pSignatureValue->szType), value);
+ return err;
+}
+
+//--------------------------------------------------
+// Accessor for SignatureValue atribute of SignatureValue object.
+// pSignatureValue - address of object [REQUIRED]
+// returns value of atribute or NULL.
+//--------------------------------------------------
+EXP_OPTION DigiDocMemBuf* ddocSignatureValue_GetSignatureValue(const SignatureValue* pSignatureValue)
+{
+ RETURN_OBJ_IF_NULL(pSignatureValue, NULL)
+ return &(((SignatureValue*)pSignatureValue)->mbufSignatureValue);
+}
+
+//--------------------------------------------------
+// Mutatoror for SignatureValue atribute of SignatureValue object.
+// pSignatureValue - address of object [REQUIRED]
+// value - new value for atribute [REQUIRED]
+// len - length of value in bytes [REQUIRED]
+// returns error code or ERR_OK
+//--------------------------------------------------
+EXP_OPTION int ddocSignatureValue_SetSignatureValue(SignatureValue* pSignatureValue,
+ const char* value, long len)
+{
+ int err = ERR_OK;
+ RETURN_IF_NULL_PARAM(pSignatureValue)
+ RETURN_IF_NULL_PARAM(value)
+ err = ddocMemAssignData(&(pSignatureValue->mbufSignatureValue), value, len);
+ return err;
+}
+
+//--------------------------------------------------
+// Generates XML for <SignatureValue> element
+// pSignatureValue - SignatureValue object [REQUIRED]
+// pBuf - memory buffer for storing xml [REQUIRED]
+// returns error code or ERR_OK
+//--------------------------------------------------
+int ddocSignatureValue_toXML(const SignatureValue* pSignatureValue, DigiDocMemBuf* pBuf)
+{
+ int err = ERR_OK;
+ char* p;
+ DigiDocMemBuf mbuf1;
+
+ RETURN_IF_NULL_PARAM(pBuf)
+ //RETURN_IF_NULL_PARAM(pSignatureValue)
+ mbuf1.pMem = 0;
+ mbuf1.nLen = 0;
+ // start of element
+ err = ddocGen_startElemBegin(pBuf, "SignatureValue");
+ if(err) return err;
+ // Id atribute
+ if(pSignatureValue) {
+ p = (char*)ddocSignatureValue_GetId(pSignatureValue);
+ if(p)
+ err = ddocGen_addAtribute(pBuf, "Id", p);
+ if(err) return err;
+ }
+ // end of element start tag
+ err = ddocGen_startElemEnd(pBuf);
+ //err = ddocMemAppendData(pBuf, "\n", -1);
+ if(err) return err;
+ // signature value
+ if(pSignatureValue) {
+ ddocEncodeBase64(ddocSignatureValue_GetSignatureValue(pSignatureValue), &mbuf1);
+ //AM 17.11.08 to remove newline after base64
+ if(mbuf1.pMem && ((char*)mbuf1.pMem)[strlen((const char*)mbuf1.pMem)-1] == '\n')
+ ((char*)mbuf1.pMem)[strlen((const char*)mbuf1.pMem)-1] = 0;
+ err = ddocMemAppendData(pBuf, (char*)mbuf1.pMem, -1);
+ ddocMemBuf_free(&mbuf1);
+ }
+ err = ddocGen_endElem(pBuf, "SignatureValue");
+ err = ddocMemAppendData(pBuf, "\n", -1);
+ return err;
+}
+
+//======================< CertID >====================================
+
+//--------------------------------------------------
+// "Constructor" of CertID object
+// ppCertID - address of buffer for newly allocated object [REQUIRED]
+// szId - Id atribute value [OPTIONAL]
+// nType - certid internal type (signers or responders cert) [REQUIRED]
+// szIssuerSerial - issuer serial number [OPTIONAL]
+// szIssuerName - issuer DN [OPTIONAL]
+// szDigVal/lDigLen - digest value and length [OPTIONAL]
+// returns error code or ERR_OK
+//--------------------------------------------------
+EXP_OPTION int ddocCertID_new(CertID** ppCertID,
+ int nType, const char* szId,
+ const char* szIssuerSerial, const char* szIssuerName,
+ void* szDigVal, long lDigLen)
+{
+ int err = ERR_OK;
+
+ // check input parameters
+ ddocDebug(4, "ddocCertID_new", "id: %s, type: %d, issuer-serial: %s issuer-name: %s, dig-len: %ld",
+ (szId ? szId : "NULL"), nType,
+ (szIssuerSerial ? szIssuerSerial : "NULL"),
+ (szIssuerName ? szIssuerName : "NULL"), lDigLen);
+ RETURN_IF_NULL_PARAM(ppCertID);
+ *ppCertID = 0; // mark as not yet allocated
+ // allocate memory for new CertID
+ *ppCertID = (CertID*)malloc(sizeof(CertID));
+ if(!(*ppCertID))
+ SET_LAST_ERROR_RETURN(ERR_BAD_ALLOC, ERR_BAD_ALLOC)
+ memset(*ppCertID, 0, sizeof(CertID));
+ (*ppCertID)->nType = nType;
+ // set optional fields
+ if(szId) {
+ err = ddocMemAssignString((char**)&((*ppCertID)->szId), szId);
+ if(err) return err;
+ }
+ if(szIssuerSerial) {
+ err = ddocMemAssignString((char**)&((*ppCertID)->szIssuerSerial), szIssuerSerial);
+ if(err) return err;
+ }
+ if(szIssuerName) {
+ err = ddocMemAssignString((char**)&((*ppCertID)->szIssuerName), szIssuerName);
+ if(err) return err;
+ }
+ if(szDigVal && lDigLen) {
+ if(!(*ppCertID)->pDigestValue)
+ ddocDigestValue_new(&((*ppCertID)->pDigestValue), 0, szDigVal, lDigLen);
+ else
+ err = ddocDigestValue_SetDigestValue((*ppCertID)->pDigestValue, szDigVal, lDigLen);
+ }
+ return err;
+}
+EXP_OPTION int bdocCertID_new(CertID** ppCertID,
+ int nType, const char* szId,
+ const char* szIssuerSerial, const char* szIssuerName,
+ void* szDigVal, long lDigLen)
+{
+ int err = ERR_OK;
+
+ // check input parameters
+ ddocDebug(4, "ddocCertID_new", "id: %s, type: %d, issuer-serial: %s issuer-name: %s, dig-len: %ld",
+ (szId ? szId : "NULL"), nType,
+ (szIssuerSerial ? szIssuerSerial : "NULL"),
+ (szIssuerName ? szIssuerName : "NULL"), lDigLen);
+ RETURN_IF_NULL_PARAM(ppCertID);
+ *ppCertID = 0; // mark as not yet allocated
+ // allocate memory for new CertID
+ *ppCertID = (CertID*)malloc(sizeof(CertID));
+ if(!(*ppCertID))
+ SET_LAST_ERROR_RETURN(ERR_BAD_ALLOC, ERR_BAD_ALLOC)
+ memset(*ppCertID, 0, sizeof(CertID));
+ (*ppCertID)->nType = nType;
+ // set optional fields
+ if(szId) {
+ err = ddocMemAssignString((char**)&((*ppCertID)->szId), szId);
+ if(err) return err;
+ }
+ if(szIssuerSerial) {
+ err = ddocMemAssignString((char**)&((*ppCertID)->szIssuerSerial), szIssuerSerial);
+ if(err) return err;
+ }
+ if(szIssuerName) {
+ err = ddocMemAssignString((char**)&((*ppCertID)->szIssuerName), szIssuerName);
+ if(err) return err;
+ }
+ if(szDigVal && lDigLen) {
+ if(!(*ppCertID)->pDigestValue){
+ ddocDigestValue_new(&((*ppCertID)->pDigestValue), 0, szDigVal, lDigLen);
+ }else
+ err = ddocDigestValue_SetDigestValue((*ppCertID)->pDigestValue, szDigVal, lDigLen);
+ }
+ return err;
+}
+
+//--------------------------------------------------
+// "Destructor" of CertID object
+// pCertID - address of object to be deleted [REQUIRED]
+// returns error code or ERR_OK
+//--------------------------------------------------
+EXP_OPTION int ddocCertID_free(CertID* pCertID)
+{
+ int err = ERR_OK;
+ RETURN_IF_NULL_PARAM(pCertID)
+ // cleanup this object
+ if(pCertID->szId)
+ free(pCertID->szId);
+ if(pCertID->szIssuerSerial)
+ free(pCertID->szIssuerSerial);
+ if(pCertID->szIssuerName)
+ free(pCertID->szIssuerName);
+ if(pCertID->pDigestValue)
+ ddocDigestValue_free(pCertID->pDigestValue);
+ if(pCertID->szDigestType)
+ free(pCertID->szDigestType);
+ free(pCertID);
+ return err;
+}
+
+//--------------------------------------------------
+// Accessor for IssuerSerial atribute of CertID object.
+// pCertID - address of object [REQUIRED]
+// returns value of atribute or NULL.
+//--------------------------------------------------
+EXP_OPTION const char* ddocCertID_GetIssuerSerial(const CertID* pCertID)
+{
+ RETURN_OBJ_IF_NULL(pCertID, NULL)
+ return pCertID->szIssuerSerial;
+}
+
+//--------------------------------------------------
+// Mutatoror for IssuerSerial atribute of CertID object.
+// pCertID - address of object [REQUIRED]
+// value - new value for atribute [REQUIRED]
+// returns error code or ERR_OK
+//--------------------------------------------------
+EXP_OPTION int ddocCertID_SetIssuerSerial(CertID* pCertID, const char* value)
+{
+ int err = ERR_OK;
+ RETURN_IF_NULL_PARAM(pCertID)
+ RETURN_IF_NULL_PARAM(value)
+ err = ddocMemAssignString((char**)&(pCertID->szIssuerSerial), value);
+ return err;
+}
+
+//--------------------------------------------------
+// Accessor for Id atribute of CertID object.
+// pCertID - address of object [REQUIRED]
+// returns value of atribute or NULL.
+//--------------------------------------------------
+EXP_OPTION const char* ddocCertID_GetId(const CertID* pCertID)
+{
+ RETURN_OBJ_IF_NULL(pCertID, NULL)
+ return pCertID->szId;
+}
+
+//--------------------------------------------------
+// Mutatoror for Id atribute of CertID object.
+// pCertID - address of object [REQUIRED]
+// value - new value for atribute [REQUIRED]
+// returns error code or ERR_OK
+//--------------------------------------------------
+EXP_OPTION int ddocCertID_SetId(CertID* pCertID, const char* value)
+{
+ int err = ERR_OK;
+ RETURN_IF_NULL_PARAM(pCertID)
+ RETURN_IF_NULL_PARAM(value)
+ err = ddocMemAssignString((char**)&(pCertID->szId), value);
+ return err;
+}
+
+//--------------------------------------------------
+// Accessor for IssuerName atribute of CertID object.
+// pCertID - address of object [REQUIRED]
+// returns value of atribute or NULL.
+//--------------------------------------------------
+EXP_OPTION const char* ddocCertID_GetIssuerName(const CertID* pCertID)
+{
+ RETURN_OBJ_IF_NULL(pCertID, NULL)
+ return pCertID->szIssuerName;
+}
+
+//--------------------------------------------------
+// Mutatoror for IssuerName atribute of CertID object.
+// pCertID - address of object [REQUIRED]
+// value - new value for atribute [REQUIRED]
+// returns error code or ERR_OK
+//--------------------------------------------------
+EXP_OPTION int ddocCertID_SetIssuerName(CertID* pCertID, const char* value)
+{
+ int err = ERR_OK;
+ RETURN_IF_NULL_PARAM(pCertID)
+ RETURN_IF_NULL_PARAM(value)
+ err = ddocMemAssignString((char**)&(pCertID->szIssuerName), value);
+ return err;
+}
+
+//--------------------------------------------------
+// Accessor for DigestValue atribute of CertID object.
+// pCertID - address of object [REQUIRED]
+// returns value of atribute or NULL.
+//--------------------------------------------------
+EXP_OPTION DigiDocMemBuf* ddocCertID_GetDigestValue(const CertID* pCertID)
+{
+ RETURN_OBJ_IF_NULL(pCertID, NULL)
+ return ddocDigestValue_GetDigestValue(pCertID->pDigestValue);
+}
+
+//--------------------------------------------------
+// Mutatoror for DigestValue atribute of CertID object.
+// pCertID - address of object [REQUIRED]
+// value - new value for atribute [REQUIRED]
+// len - length of value in bytes [REQUIRED]
+// returns error code or ERR_OK
+//--------------------------------------------------
+EXP_OPTION int ddocCertID_SetDigestValue(CertID* pCertID,
+ const char* value, long len)
+{
+ int err = ERR_OK;
+ RETURN_IF_NULL_PARAM(pCertID)
+ RETURN_IF_NULL_PARAM(value)
+ if(!pCertID->pDigestValue)
+ err = ddocDigestValue_new(&(pCertID->pDigestValue), 0, (char*)value, len);
+ else
+ err = ddocDigestValue_SetDigestValue(pCertID->pDigestValue, value, len);
+ return err;
+}
+
+//--------------------------------------------------
+// Generates XML for <Cert> element
+// pSigDoc - SignedDoc object [REQUIRED]
+// pCertID - CertID object [REQUIRED]
+// pBuf - memory buffer for storing xml [REQUIRED]
+// returns error code or ERR_OK
+//--------------------------------------------------
+int ddocCertID_toXML(const SignedDoc* pSigDoc, const CertID* pCertID, DigiDocMemBuf* pBuf)
+{
+ int err = ERR_OK;
+
+ RETURN_IF_NULL_PARAM(pBuf)
+ RETURN_IF_NULL_PARAM(pCertID)
+ RETURN_IF_NULL_PARAM(pSigDoc)
+ // start of element
+ err = ddocGen_startElemBegin(pBuf, "Cert");
+ if(err) return err;
+ // only formats 1.0, 1.1 and 1.2 we use the Id atribute
+ //AM 28.10.08 can also have 1.0 version
+ if((!strcmp(pSigDoc->szFormatVer, SK_XML_1_VER) && !strcmp(pSigDoc->szFormat, SK_XML_1_NAME)) ||
+ !strcmp(pSigDoc->szFormatVer, DIGIDOC_XML_1_1_VER) ||
+ !strcmp(pSigDoc->szFormatVer, DIGIDOC_XML_1_2_VER)) {
+ // Id atribute
+ if(pCertID->szId)
+ err = ddocGen_addAtribute(pBuf, "Id", pCertID->szId);
+ if(err) return err;
+ }
+ // end of element start tag
+ err = ddocGen_startElemEnd(pBuf);
+ // <CertDigest>
+ err = ddocGen_startElem(pBuf, "CertDigest");
+ if(err) return err;
+ ddocDigestValue_toXML(pCertID->pDigestValue, pBuf);
+ err = ddocGen_endElem(pBuf, "CertDigest");
+ if(err) return err;
+ err = ddocMemAppendData(pBuf, "\n", -1);
+ // <IssuerSerial
+ err = ddocGen_startElem(pBuf, "IssuerSerial");
+ if(err) return err;
+ err = ddocMemAppendData(pBuf, "\n", -1);
+ // only formats 1.0, 1.1 and 1.2 we use the IssuerSerial element alone
+ //AM 29.10.08
+ if((!strcmp(pSigDoc->szFormatVer, SK_XML_1_VER) && !strcmp(pSigDoc->szFormat, SK_XML_1_NAME))||
+ !strcmp(pSigDoc->szFormatVer, DIGIDOC_XML_1_1_VER) ||
+ !strcmp(pSigDoc->szFormatVer, DIGIDOC_XML_1_2_VER)) {
+ err = ddocMemAppendData(pBuf, ddocCertID_GetIssuerSerial(pCertID), -1);
+ } else { // in 1.3 and 1.4 we use all subelement of <IssuerSerial>
+ err = ddocGen_startElemBegin(pBuf, "X509IssuerName");
+ if(err) return err;
+ err = ddocGen_addAtribute(pBuf, "xmlns", NAMESPACE_XML_DSIG);
+ // end of element start tag
+ err = ddocGen_startElemEnd(pBuf);
+ if(err) return err;
+ err = ddocMemAppendData(pBuf, ddocCertID_GetIssuerName(pCertID), -1);
+ if(err) return err;
+ err = ddocGen_endElem(pBuf, "X509IssuerName");
+ if(err) return err;
+ err = ddocMemAppendData(pBuf, "\n", -1);
+ err = ddocGen_startElemBegin(pBuf, "X509SerialNumber");
+ if(err) return err;
+ err = ddocGen_addAtribute(pBuf, "xmlns", NAMESPACE_XML_DSIG);
+ // end of element start tag
+ err = ddocGen_startElemEnd(pBuf);
+ if(err) return err;
+ err = ddocMemAppendData(pBuf, ddocCertID_GetIssuerSerial(pCertID), -1);
+ if(err) return err;
+ err = ddocGen_endElem(pBuf, "X509SerialNumber");
+ if(err) return err;
+ err = ddocMemAppendData(pBuf, "\n", -1);
+ }
+ err = ddocGen_endElem(pBuf, "IssuerSerial");
+ if(err) return err;
+ err = ddocMemAppendData(pBuf, "\n", -1);
+ if(err) return err;
+ err = ddocGen_endElem(pBuf, "Cert");
+ return err;
+}
+
+
+//--------------------------------------------------
+// Generates XML for <CompleteCertificateRefs> element
+// pSigDoc - SignedDoc object [REQUIRED]
+// pBuf - memory buffer for storing xml [REQUIRED]
+// returns error code or ERR_OK
+//--------------------------------------------------
+int ddocCompleteCertificateRefs_toXML(const SignedDoc* pSigDoc,
+ const SignatureInfo* pSigInfo, DigiDocMemBuf* pBuf)
+{
+ int err = ERR_OK, i, n;
+ CertID* pCertID;
+
+ RETURN_IF_NULL_PARAM(pBuf)
+ RETURN_IF_NULL_PARAM(pSigDoc)
+ RETURN_IF_NULL_PARAM(pSigInfo)
+ RETURN_IF_NULL(pSigInfo->pCertIDs)
+ // <CompleteCertificateRefs>
+ err = ddocGen_startElemBegin(pBuf, "CompleteCertificateRefs");
+ if(err) return err;
+ // end of element start tag
+ err = ddocGen_startElemEnd(pBuf);
+ if(err) return err;
+ // <CertRefs> (not used in 1.0, 1.1 and 1.2
+ if((strcmp(pSigDoc->szFormatVer, SK_XML_1_VER) && strcmp(pSigDoc->szFormat, SK_XML_1_NAME)) &&
+ strcmp(pSigDoc->szFormatVer, DIGIDOC_XML_1_1_VER) &&
+ strcmp(pSigDoc->szFormatVer, DIGIDOC_XML_1_2_VER)) {
+ err = ddocGen_startElem(pBuf, "CertRefs");
+ if(err) return err;
+ }
+ n = ddocCertIDList_GetCertIDsCount(pSigInfo->pCertIDs);
+ for(i = 0; i < n; i++) {
+ pCertID = ddocCertIDList_GetCertID(pSigInfo->pCertIDs, i);
+ if(pCertID && pCertID->nType != CERTID_TYPE_SIGNERS_CERTID)
+ ddocCertID_toXML(pSigDoc, pCertID, pBuf);
+ }
+ // </CertRefs> (not used in 1.0, 1.1 and 1.2
+ //AM 29.10.08
+ if((strcmp(pSigDoc->szFormatVer, SK_XML_1_VER) && strcmp(pSigDoc->szFormat, SK_XML_1_NAME)) &&
+ strcmp(pSigDoc->szFormatVer, DIGIDOC_XML_1_1_VER) &&
+ strcmp(pSigDoc->szFormatVer, DIGIDOC_XML_1_2_VER)) {
+ err = ddocGen_endElem(pBuf, "CertRefs");
+ }
+ if(err) return err;
+ err = ddocGen_endElem(pBuf, "CompleteCertificateRefs");
+ return err;
+}
+
+//--------------------------------------------------
+// Generates XML for <CompleteRevocationRefs> element
+// pSigDoc - SignedDoc object [REQUIRED]
+// pBuf - memory buffer for storing xml [REQUIRED]
+// returns error code or ERR_OK
+//--------------------------------------------------
+int ddocCompleteRevocationRefs_toXML(const SignedDoc* pSigDoc,
+ const SignatureInfo* pSigInfo, DigiDocMemBuf* pBuf)
+{
+ int err = ERR_OK, l1, l2;
+ //AM 28.04.04 increased buffer for sha256
+ char buf1[80], buf2[80], *p1, *p2;
+ const DigiDocMemBuf *pMBuf = 0;
+
+ RETURN_IF_NULL_PARAM(pBuf)
+ RETURN_IF_NULL_PARAM(pSigDoc)
+ RETURN_IF_NULL_PARAM(pSigInfo)
+ RETURN_IF_NULL(pSigInfo->pNotary)
+ // <CompleteRevocationRefs>
+ err = ddocGen_startElemBegin(pBuf, "CompleteRevocationRefs");
+ if(err) return err;
+ // end of element start tag
+ err = ddocGen_startElemEnd(pBuf);
+ if(err) return err;
+ err = ddocMemAppendData(pBuf, "\n", -1);
+ if(err) return err;
+ // <OCSPRefs>
+ err = ddocGen_startElem(pBuf, "OCSPRefs");
+ if(err) return err;
+ err = ddocMemAppendData(pBuf, "\n", -1);
+ if(err) return err;
+ // <OCSPRef>
+ err = ddocGen_startElem(pBuf, "OCSPRef");
+ if(err) return err;
+ err = ddocMemAppendData(pBuf, "\n", -1);
+ if(err) return err;
+ // <OCSPIdentifier>
+ err = ddocGen_startElemBegin(pBuf, "OCSPIdentifier");
+ if(err) return err;
+ snprintf(buf1, sizeof(buf1), "#%s", pSigInfo->pNotary->szId);
+ err = ddocGen_addAtribute(pBuf, "URI", buf1);
+ err = ddocGen_startElemEnd(pBuf);
+ if(err) return err;
+ // <ResponderID>
+ err = ddocGen_startElem(pBuf, "ResponderID");
+ if(err) return err;
+ if(pSigInfo->pNotary->nRespIdType == RESPID_NAME_TYPE) {
+ p1 = (char*)ddocNotInfo_GetResponderId_Value(pSigInfo->pNotary);
+ RETURN_IF_NULL(p1);
+ err = ddocMemAppendData(pBuf, p1, -1);
+ if(err) return err;
+ } else if(pSigInfo->pNotary->nRespIdType == RESPID_KEY_TYPE) {
+ pMBuf = ddocNotInfo_GetResponderId(pSigInfo->pNotary);
+ RETURN_IF_NULL(pMBuf);
+ l2 = pMBuf->nLen * 2 + 10;
+ p2 = (char*)malloc(l2);
+ RETURN_IF_NULL(p2);
+ memset(p2, 0, l2);
+ encode((const byte*)pMBuf->pMem, pMBuf->nLen, (byte*)p2, &l2);
+ err = ddocMemAppendData(pBuf, p2, -1);
+ if(err) return err;
+ } else {
+ SET_LAST_ERROR_RETURN_CODE(ERR_OCSP_WRONG_RESPID);
+ }
+ err = ddocGen_endElem(pBuf, "ResponderID");
+ if(err) return err;
+ err = ddocMemAppendData(pBuf, "\n", -1);
+ if(err) return err;
+ // <ProducedAt>
+ err = ddocGen_startElem(pBuf, "ProducedAt");
+ if(err) return err;
+ err = ddocMemAppendData(pBuf, pSigInfo->pNotary->timeProduced, -1);
+ if(err) return err;
+ err = ddocGen_endElem(pBuf, "ProducedAt");
+ if(err) return err;
+ err = ddocMemAppendData(pBuf, "\n", -1);
+ if(err) return err;
+ // </OCSPRef>
+ err = ddocGen_endElem(pBuf, "OCSPIdentifier");
+ if(err) return err;
+ err = ddocMemAppendData(pBuf, "\n", -1);
+ if(err) return err;
+ // <DigestAlgAndValue>
+ err = ddocGen_startElem(pBuf, "DigestAlgAndValue");
+ if(err) return err;
+ err = ddocMemAppendData(pBuf, "\n", -1);
+ if(err) return err;
+ // <DigestMethod>
+ err = ddocGen_startElemBegin(pBuf, "DigestMethod");
+ if(err) return err;
+ err = ddocGen_addAtribute(pBuf, "Algorithm", DIGEST_METHOD_SHA1);
+ err = ddocGen_startElemEnd(pBuf);
+ if(err) return err;
+ err = ddocGen_endElem(pBuf, "DigestMethod");
+ if(err) return err;
+ err = ddocMemAppendData(pBuf, "\n", -1);
+ if(err) return err;
+ // <DigestValue>
+ err = ddocGen_startElem(pBuf, "DigestValue");
+ if(err) return err;
+ l2 = sizeof(buf2);
+ err = calculateNotaryInfoDigest(pSigDoc, pSigInfo->pNotary, (byte*)buf2, &l2);
+ l1 = sizeof(buf1);
+ encode((const byte*)buf2, l2, (byte*)buf1, &l1);
+ err = ddocMemAppendData(pBuf, buf1, -1);
+ err = ddocGen_endElem(pBuf, "DigestValue");
+ if(err) return err;
+ err = ddocMemAppendData(pBuf, "\n", -1);
+ if(err) return err;
+ // </DigestAlgAndValue>
+ err = ddocGen_endElem(pBuf, "DigestAlgAndValue");
+ if(err) return err;
+ // </OCSPRef>
+ err = ddocGen_endElem(pBuf, "OCSPRef");
+ if(err) return err;
+ err = ddocMemAppendData(pBuf, "\n", -1);
+ if(err) return err;
+ // </OCSPRefs>
+ err = ddocGen_endElem(pBuf, "OCSPRefs");
+ if(err) return err;
+ err = ddocMemAppendData(pBuf, "\n", -1);
+ if(err) return err;
+ // </CompleteRevocationRefs>
+ err = ddocGen_endElem(pBuf, "CompleteRevocationRefs");
+ if(err) return err;
+ err = ddocMemAppendData(pBuf, "\n", -1);
+ return err;
+}
+
+
+//==========< CertIDList >====================
+
+//--------------------------------------------------
+// "Constructor" of CertIDList object
+// ppCertIDList - address of buffer for newly allocated object [REQUIRED]
+// returns error code or ERR_OK
+//--------------------------------------------------
+EXP_OPTION int ddocCertIDList_new(CertIDList** ppCertIDList)
+{
+ int err = ERR_OK;
+
+ // check input parameters
+ ddocDebug(3, "ddocCertIDList_new", "Create new certid list");
+ RETURN_IF_NULL_PARAM(ppCertIDList);
+ *ppCertIDList = (CertIDList*)malloc(sizeof(CertIDList));
+ // allocate new object
+ RETURN_IF_BAD_ALLOC(*ppCertIDList);
+ memset(*ppCertIDList, 0, sizeof(CertIDList));
+ return err;
+}
+
+//--------------------------------------------------
+// "Destructor" of CertIDList object
+// pCertIDList - address of object to be deleted [REQUIRED]
+// returns error code or ERR_OK
+//--------------------------------------------------
+EXP_OPTION int ddocCertIDList_free(CertIDList* pCertIDList)
+{
+ int i, err = ERR_OK;
+ RETURN_IF_NULL_PARAM(pCertIDList)
+ // free timestamp-infos
+ for(i = 0; i < pCertIDList->nCertIDs; i++) {
+ if(pCertIDList->pCertIDs[i]) {
+ err = ddocCertID_free(pCertIDList->pCertIDs[i]);
+ if(err) return err;
+ }
+ }
+ free(pCertIDList->pCertIDs);
+ free(pCertIDList);
+ return err;
+}
+
+//--------------------------------------------------
+// Accessor for count of CertIDs subelement of CertIDList object.
+// pCertIDList - pointer to CertIDList object [REQUIRED]
+// returns error code or ERR_OK
+//--------------------------------------------------
+int ddocCertIDList_addCertID(CertIDList* pCertIDList, CertID* pCertID)
+{
+ CertID** pCertIDs = 0;
+
+ RETURN_IF_NULL_PARAM(pCertIDList)
+ RETURN_IF_NULL_PARAM(pCertID)
+ pCertIDs = (CertID**)realloc(pCertIDList->pCertIDs, sizeof(CertID*) * (pCertIDList->nCertIDs + 1));
+ RETURN_IF_BAD_ALLOC(pCertIDs);
+ pCertIDList->pCertIDs = pCertIDs;
+ pCertIDList->pCertIDs[pCertIDList->nCertIDs] = pCertID;
+ pCertIDList->nCertIDs++;
+ ddocDebug(3, "ddocCertIDList_addCertID", "added certid: %s type: %d", pCertID->szId, pCertID->nType);
+ return ERR_OK;
+}
+
+
+//--------------------------------------------------
+// Accessor for count of CertIDs subelement of CertIDList object.
+// pCertIDList - pointer to CertIDList object [REQUIRED]
+// returns count or -1 for error. Then use error API to check errors
+//--------------------------------------------------
+EXP_OPTION int ddocCertIDList_GetCertIDsCount(CertIDList* pCertIDList)
+{
+ SET_LAST_ERROR_RETURN_IF_NOT(pCertIDList, ERR_NULL_POINTER, -1)
+ return pCertIDList->nCertIDs;
+}
+
+//--------------------------------------------------
+// Accessor for CertIDs subelement of CertIDList object.
+// pCertIDList - pointer to CertIDList object [REQUIRED]
+// nIdx - index of CertID object [REQUIRED]
+// returns CertID pointer or NULL for error
+//--------------------------------------------------
+EXP_OPTION CertID* ddocCertIDList_GetCertID(CertIDList* pCertIDList, int nIdx)
+{
+ RETURN_OBJ_IF_NULL(pCertIDList, NULL)
+ SET_LAST_ERROR_RETURN_IF_NOT(nIdx >= 0 && nIdx < pCertIDList->nCertIDs, ERR_BAD_CERTID_IDX, NULL);
+ RETURN_OBJ_IF_NULL(pCertIDList->pCertIDs[nIdx], 0);
+ return pCertIDList->pCertIDs[nIdx];
+}
+
+
+//--------------------------------------------------
+// Accessor for last CertIDs subelement of CertIDList object.
+// pCertIDList - pointer to CertIDList object [REQUIRED]
+// returns CertID pointer or NULL for error
+//--------------------------------------------------
+EXP_OPTION CertID* ddocCertIDList_GetLastCertID(CertIDList* pCertIDList)
+{
+ RETURN_OBJ_IF_NULL(pCertIDList, NULL)
+ SET_LAST_ERROR_RETURN_IF_NOT(pCertIDList->nCertIDs > 0, ERR_BAD_CERTID_IDX, NULL);
+ RETURN_OBJ_IF_NULL(pCertIDList->pCertIDs[pCertIDList->nCertIDs-1], 0);
+ return pCertIDList->pCertIDs[pCertIDList->nCertIDs-1];
+}
+
+
+//--------------------------------------------------
+// Deletes CertID subelement of CertIDList object.
+// pCertIDList - pointer to CertIDList object [REQUIRED]
+// nIdx - index of CertID object to be removed [REQUIRED]
+// returns error code or ERR_OK
+//--------------------------------------------------
+EXP_OPTION int ddocCertIDList_DeleteCertID(CertIDList* pCertIDList, int nIdx)
+{
+ int err = ERR_OK, i;
+
+ RETURN_IF_NULL_PARAM(pCertIDList)
+ SET_LAST_ERROR_RETURN_IF_NOT(nIdx >= 0 && nIdx < pCertIDList->nCertIDs, ERR_BAD_CERTID_IDX, ERR_BAD_CERTID_IDX);
+ RETURN_IF_NULL_PARAM(pCertIDList->pCertIDs[nIdx]);
+ // delete the given object
+ err = ddocCertID_free(pCertIDList->pCertIDs[nIdx]);
+ if(err) return err;
+ pCertIDList->pCertIDs[nIdx] = 0;
+ // move other objects 1 step close to array start
+ for(i = nIdx; i < pCertIDList->nCertIDs; i++)
+ pCertIDList->pCertIDs[i] = pCertIDList->pCertIDs[i+1];
+ pCertIDList->pCertIDs[pCertIDList->nCertIDs - 1] = 0;
+ pCertIDList->nCertIDs--;
+ return err;
+}
+
+//--------------------------------------------------
+// Finds a CertID object with required type
+// pCertIDList - pointer to CertIDList object [REQUIRED]
+// nType - type of CertID object [REQUIRED]
+// returns CertID pointer or NULL for error
+//--------------------------------------------------
+EXP_OPTION CertID* ddocCertIDList_GetCertIDOfType(CertIDList* pCertIDList, int nType)
+{
+ int i;
+
+ RETURN_OBJ_IF_NULL(pCertIDList, NULL)
+ ddocDebug(4, "ddocCertIDList_GetCertIDOfType", "find type: %d", nType);
+ for(i = 0; i < pCertIDList->nCertIDs; i++) {
+ ddocDebug(4, "ddocCertIDList_GetCertIDOfType", "idx: %d type: %d", i, pCertIDList->pCertIDs[i]->nType);
+ if(pCertIDList->pCertIDs[i]->nType == nType)
+ return pCertIDList->pCertIDs[i];
+ }
+ return NULL;
+}
+
+//--------------------------------------------------
+// Finds a CertID object with serial nr
+// pCertIDList - pointer to CertIDList object [REQUIRED]
+// nType - type of CertID object [REQUIRED]
+// returns CertID pointer or NULL for error
+//--------------------------------------------------
+EXP_OPTION CertID* ddocCertIDList_GetCertIDOfSerial(CertIDList* pCertIDList, const char* szSerial)
+{
+ int i;
+
+ RETURN_OBJ_IF_NULL(pCertIDList, NULL)
+ RETURN_OBJ_IF_NULL(szSerial, NULL)
+ ddocDebug(4, "ddocCertIDList_GetCertIDOfSerial", "find serial: %s", szSerial);
+ for(i = 0; i < pCertIDList->nCertIDs; i++) {
+ //AM 19.09.08
+ if(pCertIDList->pCertIDs[i]->szIssuerSerial){
+ if(!strcmp(pCertIDList->pCertIDs[i]->szIssuerSerial, szSerial))
+ return pCertIDList->pCertIDs[i];
+ }
+ }
+ return NULL;
+}
+
+//--------------------------------------------------
+// Finds a CertID object with required type or creates a new one
+// pCertIDList - pointer to CertIDList object [REQUIRED]
+// nType - type of CertID object [REQUIRED]
+// returns CertID pointer or NULL for error
+//--------------------------------------------------
+EXP_OPTION CertID* ddocCertIDList_GetOrCreateCertIDOfType(CertIDList* pCertIDList, int nType)
+{
+ CertID* pCertID = ddocCertIDList_GetCertIDOfType(pCertIDList, nType);
+ if(!pCertID) {
+ ddocCertID_new(&pCertID, nType, 0, 0, 0, 0, 0);
+ if(pCertID)
+ ddocCertIDList_addCertID(pCertIDList, pCertID);
+ }
+ return pCertID;
+}
+
+//======================< CertValue >====================================
+
+//--------------------------------------------------
+// "Constructor" of CertValue object
+// ppCertValue - address of buffer for newly allocated object [REQUIRED]
+// szId - Id atribute value [OPTIONAL]
+// nType - certid internal type (signers or responders cert) [REQUIRED]
+// pCert - certificate itself [OPTIONAL]. Must fill in later. Do not X509_free() param!
+// returns error code or ERR_OK
+//--------------------------------------------------
+EXP_OPTION int ddocCertValue_new(CertValue** ppCertValue,
+ int nType, const char* szId,
+ X509* pCert)
+{
+ int err = ERR_OK;
+
+ // check input parameters
+ ddocDebug(4, "ddocCertValue_new", "id: %s, type: %d, cert: %s",
+ (szId ? szId : "NULL"), nType, (pCert ? "OK" : "NULL"));
+ RETURN_IF_NULL_PARAM(ppCertValue);
+ //RETURN_IF_NULL_PARAM(pCert);
+ *ppCertValue = 0; // mark as not yet allocated
+ // allocate memory for new CertValue
+ *ppCertValue = (CertValue*)malloc(sizeof(CertValue));
+ if(!(*ppCertValue))
+ SET_LAST_ERROR_RETURN(ERR_BAD_ALLOC, ERR_BAD_ALLOC)
+ memset(*ppCertValue, 0, sizeof(CertValue));
+ (*ppCertValue)->nType = nType;
+ if(pCert)
+ (*ppCertValue)->pCert = pCert;
+ // set optional fields
+ if(szId) {
+ err = ddocMemAssignString((char**)&((*ppCertValue)->szId), szId);
+ if(err) return err;
+ }
+ return err;
+}
+
+//--------------------------------------------------
+// "Destructor" of CertValue object
+// pCertValue - address of object to be deleted [REQUIRED]
+// returns error code or ERR_OK
+//--------------------------------------------------
+EXP_OPTION int ddocCertValue_free(CertValue* pCertValue)
+{
+ int err = ERR_OK;
+ RETURN_IF_NULL_PARAM(pCertValue)
+ // cleanup this object
+ if(pCertValue->szId)
+ free(pCertValue->szId);
+ if(pCertValue->pCert)
+ X509_free(pCertValue->pCert);
+ free(pCertValue);
+ return err;
+}
+
+//--------------------------------------------------
+// Accessor for Id atribute of CertValue object.
+// pCertValue - address of object [REQUIRED]
+// returns value of atribute or NULL.
+//--------------------------------------------------
+EXP_OPTION const char* ddocCertValue_GetId(CertValue* pCertValue)
+{
+ RETURN_OBJ_IF_NULL(pCertValue, NULL)
+ return pCertValue->szId;
+}
+
+//--------------------------------------------------
+// Mutatoror for Id atribute of CertValue object.
+// pCertValue - address of object [REQUIRED]
+// value - new value for atribute [REQUIRED]
+// returns error code or ERR_OK
+//--------------------------------------------------
+EXP_OPTION int ddocCertValue_SetId(CertValue* pCertValue, const char* value)
+{
+ int err = ERR_OK;
+ RETURN_IF_NULL_PARAM(pCertValue)
+ RETURN_IF_NULL_PARAM(value)
+ err = ddocMemAssignString((char**)&(pCertValue->szId), value);
+ return err;
+}
+
+//--------------------------------------------------
+// Accessor for Cert atribute of CertValue object.
+// pCertValue - address of object [REQUIRED]
+// returns value of atribute or NULL.
+//--------------------------------------------------
+EXP_OPTION X509* ddocCertValue_GetCert(CertValue* pCertValue)
+{
+ RETURN_OBJ_IF_NULL(pCertValue, NULL)
+ return pCertValue->pCert;
+}
+
+//--------------------------------------------------
+// Mutatoror for Cert atribute of CertValue object.
+// pCertValue - address of object [REQUIRED]
+// pCert - new value for atribute [REQUIRED]
+// returns error code or ERR_OK
+//--------------------------------------------------
+EXP_OPTION int ddocCertValue_SetCert(CertValue* pCertValue, X509* pCert)
+{
+ int err = ERR_OK;
+ RETURN_IF_NULL_PARAM(pCertValue)
+ RETURN_IF_NULL_PARAM(pCert)
+ if(pCertValue->pCert && pCertValue->pCert != pCert) // free old cert
+ X509_free(pCertValue->pCert);
+ else
+ ddocDebug(3, "ddocCertValue_SetCert", "Not freeing old cert");
+ pCertValue->pCert = pCert;
+ ddocDebug(3, "ddocCertValue_SetCert", "id: %s type: %d cert: %s", pCertValue->szId, pCertValue->nType, (pCert ? "OK" : "NULL"));
+ return err;
+}
+
+//--------------------------------------------------
+// Generates XML for <EncapsulatedX509Certificate> element
+// pCertID - CertID object [REQUIRED]
+// pBuf - memory buffer for storing xml [REQUIRED]
+// returns error code or ERR_OK
+//--------------------------------------------------
+int ddocCertValue_toXML(const CertValue* pCertValue, DigiDocMemBuf* pBuf)
+{
+ int err = ERR_OK;
+ char *p1 = 0;
+
+ RETURN_IF_NULL_PARAM(pBuf)
+ RETURN_IF_NULL_PARAM(pCertValue)
+ // start of element
+ err = ddocGen_startElemBegin(pBuf, "EncapsulatedX509Certificate");
+ if(err) return err;
+ if(pCertValue->szId)
+ err = ddocGen_addAtribute(pBuf, "Id", pCertValue->szId);
+ if(err) return err;
+ err = ddocGen_startElemEnd(pBuf);
+ if(err) return err;
+ //err = ddocMemAppendData(pBuf, "\n", -1);
+ if(pCertValue->pCert) {
+ err = getCertPEM(pCertValue->pCert, 0, &p1);
+ if(p1) {
+ err = ddocMemAppendData(pBuf, p1, -1);
+ free(p1);
+ }
+ }
+ if(err) return err;
+ err = ddocGen_endElem(pBuf, "EncapsulatedX509Certificate");
+ return err;
+}
+
+//==========< CertValueList >====================
+
+//--------------------------------------------------
+// "Constructor" of CertValueList object
+// ppCertValueList - address of buffer for newly allocated object [REQUIRED]
+// returns error code or ERR_OK
+//--------------------------------------------------
+EXP_OPTION int ddocCertValueList_new(CertValueList** ppCertValueList)
+{
+ int err = ERR_OK;
+
+ // check input parameters
+ ddocDebug(3, "ddocCertValueList_new", "Create new cerValue list");
+ RETURN_IF_NULL_PARAM(ppCertValueList);
+ *ppCertValueList = (CertValueList*)malloc(sizeof(CertValueList));
+ // allocate new object
+ RETURN_IF_BAD_ALLOC(*ppCertValueList);
+ memset(*ppCertValueList, 0, sizeof(CertValueList));
+ return err;
+}
+
+//--------------------------------------------------
+// "Destructor" of CertValueList object
+// pCertValueList - address of object to be deleted [REQUIRED]
+// returns error code or ERR_OK
+//--------------------------------------------------
+EXP_OPTION int ddocCertValueList_free(CertValueList* pCertValueList)
+{
+ int i, err = ERR_OK;
+ RETURN_IF_NULL_PARAM(pCertValueList)
+ // free timestamp-infos
+ for(i = 0; i < pCertValueList->nCertValues; i++) {
+ if(pCertValueList->pCertValues[i]) {
+ err = ddocCertValue_free(pCertValueList->pCertValues[i]);
+ if(err) return err;
+ }
+ }
+ free(pCertValueList->pCertValues);
+ free(pCertValueList);
+ return err;
+}
+
+//--------------------------------------------------
+// Adds a CertValue element to CertValueList object.
+// pCertValueList - pointer to CertValueList object [REQUIRED]
+// pCertValue - new object [REQUIRED]
+// returns error code or ERR_OK
+//--------------------------------------------------
+EXP_OPTION int ddocCertValueList_addCertValue(CertValueList* pCertValueList, CertValue* pCertValue)
+{
+ CertValue** pCertValues = 0;
+
+ RETURN_IF_NULL_PARAM(pCertValueList)
+ RETURN_IF_NULL_PARAM(pCertValue)
+ pCertValues = (CertValue**)realloc(pCertValueList->pCertValues, sizeof(CertValue*) * (pCertValueList->nCertValues + 1));
+ RETURN_IF_BAD_ALLOC(pCertValues);
+ pCertValueList->pCertValues = pCertValues;
+ pCertValueList->pCertValues[pCertValueList->nCertValues] = pCertValue;
+ pCertValueList->nCertValues++;
+ ddocDebug(4, "ddocCertValueList_addCertValue", "added cert: %s type: %d", pCertValue->szId, pCertValue->nType);
+ return ERR_OK;
+}
+
+//--------------------------------------------------
+// Accessor for count of CertValues subelement of CertValueList object.
+// pCertValueList - pointer to CertValueList object [REQUIRED]
+// returns count or -1 for error. Then use error API to check errors
+//--------------------------------------------------
+EXP_OPTION int ddocCertValueList_GetCertValuesCount(CertValueList* pCertValueList)
+{
+ SET_LAST_ERROR_RETURN_IF_NOT(pCertValueList, ERR_NULL_POINTER, -1)
+ return pCertValueList->nCertValues;
+}
+
+//--------------------------------------------------
+// Accessor for CertValues subelement of CertValueList object.
+// pCertValueList - pointer to CertValueList object [REQUIRED]
+// nIdx - index of CertValue object [REQUIRED]
+// returns CertValue pointer or NULL for error
+//--------------------------------------------------
+EXP_OPTION CertValue* ddocCertValueList_GetCertValue(CertValueList* pCertValueList, int nIdx)
+{
+ RETURN_OBJ_IF_NULL(pCertValueList, NULL)
+ SET_LAST_ERROR_RETURN_IF_NOT(nIdx >= 0 && nIdx < pCertValueList->nCertValues, ERR_BAD_CERTVALUE_IDX, NULL);
+ RETURN_OBJ_IF_NULL(pCertValueList->pCertValues[nIdx], 0);
+ return pCertValueList->pCertValues[nIdx];
+}
+
+//--------------------------------------------------
+// Deletes CertValue subelement of CertValueList object.
+// pCertValueList - pointer to CertValueList object [REQUIRED]
+// nIdx - index of CertValue object to be removed [REQUIRED]
+// returns error code or ERR_OK
+//--------------------------------------------------
+EXP_OPTION int ddocCertValueList_DeleteCertValue(CertValueList* pCertValueList, int nIdx)
+{
+ int err = ERR_OK, i;
+
+ RETURN_IF_NULL_PARAM(pCertValueList)
+ SET_LAST_ERROR_RETURN_IF_NOT(nIdx >= 0 && nIdx < pCertValueList->nCertValues, ERR_BAD_CERTVALUE_IDX, ERR_BAD_CERTVALUE_IDX);
+ RETURN_IF_NULL_PARAM(pCertValueList->pCertValues[nIdx]);
+ // delete the given object
+ err = ddocCertValue_free(pCertValueList->pCertValues[nIdx]);
+ if(err) return err;
+ pCertValueList->pCertValues[nIdx] = 0;
+ // move other objects 1 step close to array start
+ for(i = nIdx; i < pCertValueList->nCertValues; i++)
+ pCertValueList->pCertValues[i] = pCertValueList->pCertValues[i+1];
+ pCertValueList->pCertValues[pCertValueList->nCertValues - 1] = 0;
+ pCertValueList->nCertValues--;
+ return err;
+}
+
+//--------------------------------------------------
+// Finds a CertValue object with required type
+// pCertValueList - pointer to CertValueList object [REQUIRED]
+// nType - type of CertValue object [REQUIRED]
+// returns CertValue pointer or NULL for error
+//--------------------------------------------------
+EXP_OPTION CertValue* ddocCertValueList_GetCertValueOfType(CertValueList* pCertValueList, int nType)
+{
+ int i;
+
+ RETURN_OBJ_IF_NULL(pCertValueList, NULL)
+ ddocDebug(4, "ddocCertValueList_GetCertValueOfType", "find type: %d", nType);
+ for(i = 0; i < pCertValueList->nCertValues; i++) {
+ ddocDebug(4, "ddocCertValueList_GetCertValueOfType", "idx: %d", i);
+ ddocDebug(4, "ddocCertValueList_GetCertValueOfType", "idx: %d type: %d", i, pCertValueList->pCertValues[i]->nType);
+ if(pCertValueList->pCertValues[i]->nType == nType){
+ ddocDebug(4, "ddocCertValueList_GetCertValueOfType", "found");
+ return pCertValueList->pCertValues[i];}
+ }
+ return NULL;
+}
+
+//--------------------------------------------------
+// Finds a CertValue object with required type or creates a new one
+// pCertValueList - pointer to CertValueList object [REQUIRED]
+// nType - type of CertValue object [REQUIRED]
+// returns CertValue pointer or NULL for error
+//--------------------------------------------------
+EXP_OPTION CertValue* ddocCertValueList_GetOrCreateCertValueOfType(CertValueList* pCertValueList, int nType)
+{
+
+ CertValue* pCertValue = ddocCertValueList_GetCertValueOfType(pCertValueList, nType);
+ if(!pCertValue) {
+ ddocCertValue_new(&pCertValue, nType, 0, 0);
+ if(pCertValue)
+ ddocCertValueList_addCertValue(pCertValueList, pCertValue);
+ }
+ return pCertValue;
+}
+
+
+//======================< SignatureInfo >====================================
+
+//============================================================
+// Returns the number of signatures
+// pSigDoc - signed doc pointer
+//============================================================
+EXP_OPTION int getCountOfSignatures(const SignedDoc* pSigDoc)
+{
+ RETURN_OBJ_IF_NULL(pSigDoc, -1);
+ return pSigDoc->nSignatures;
+}
+
+//============================================================
+// Returns the next free signature id
+// pSigDoc - signed doc pointer
+//============================================================
+EXP_OPTION int getNextSignatureId(const SignedDoc* pSigDoc)
+{
+ int id = 0, n, i;
+
+ RETURN_OBJ_IF_NULL(pSigDoc, -1);
+ for(i = 0; i < pSigDoc->nSignatures; i++) {
+ SignatureInfo* pSignature = pSigDoc->pSignatures[i];
+ RETURN_OBJ_IF_NULL(pSignature, -1);
+ RETURN_OBJ_IF_NULL(pSignature->szId, -1);
+ SET_LAST_ERROR_RETURN_IF_NOT(strlen(pSignature->szId) > 1, ERR_EMPTY_STRING, -1);
+ n = atoi(pSignature->szId+1);
+ if(id <= n)
+ id = n+1;
+ }
+ return id;
+}
+
+//============================================================
+// Returns the signature object for the given Notary
+// pSigDoc - signed doc pointer
+//============================================================
+EXP_OPTION SignatureInfo* ddocGetSignatureForNotary(const SignedDoc* pSigDoc,
+ const NotaryInfo* pNotInfo)
+{
+ int i;
+
+ RETURN_OBJ_IF_NULL(pSigDoc, NULL);
+ for(i = 0; i < pSigDoc->nSignatures; i++) {
+ SignatureInfo* pSignature = pSigDoc->pSignatures[i];
+ RETURN_OBJ_IF_NULL(pSignature, NULL);
+ if(pSignature->pNotary == pNotInfo)
+ return pSignature;
+ }
+ return NULL;
+}
+
+//============================================================
+// Returns the desired SignatureInfo object
+// pSigDoc - signed doc pointer
+// nIdx - SignatureInfo index (starting with 0)
+//============================================================
+EXP_OPTION SignatureInfo* getSignature(const SignedDoc* pSigDoc, int nIdx)
+{
+ RETURN_OBJ_IF_NULL(pSigDoc, NULL);
+ SET_LAST_ERROR_RETURN_IF_NOT(nIdx < pSigDoc->nSignatures, ERR_BAD_SIG_INDEX, NULL);
+ RETURN_OBJ_IF_NULL(pSigDoc->pSignatures[nIdx], NULL);
+ return pSigDoc->pSignatures[nIdx];
+}
+
+//============================================================
+// Returns the last SignatureInfo object
+// pSigDoc - signed doc pointer
+//============================================================
+EXP_OPTION SignatureInfo* ddocGetLastSignature(const SignedDoc* pSigDoc)
+{
+ int nIdx;
+ RETURN_OBJ_IF_NULL(pSigDoc, NULL);
+ nIdx = pSigDoc->nSignatures - 1;
+ SET_LAST_ERROR_RETURN_IF_NOT(nIdx < pSigDoc->nSignatures, ERR_BAD_SIG_INDEX, NULL);
+ RETURN_OBJ_IF_NULL(pSigDoc->pSignatures && pSigDoc->pSignatures[nIdx], NULL);
+ return pSigDoc->pSignatures[nIdx];
+}
+
+//============================================================
+// Returns the SignatureInfo object with the given id
+// pSigDoc - signed doc pointer
+// id - SignatureInfo id
+//============================================================
+EXP_OPTION SignatureInfo* getSignatureWithId(const SignedDoc* pSigDoc, const char* id)
+{
+ SignatureInfo* pSignature = NULL;
+ int i;
+
+ RETURN_OBJ_IF_NULL(pSigDoc, NULL);
+ RETURN_OBJ_IF_NULL(id, NULL);
+ for(i = 0; i < pSigDoc->nSignatures; i++) {
+ RETURN_OBJ_IF_NULL(pSigDoc->pSignatures[i], NULL);
+ RETURN_OBJ_IF_NULL(pSigDoc->pSignatures[i]->szId, NULL);
+ if(!strcmp(pSigDoc->pSignatures[i]->szId, id)) {
+ pSignature = pSigDoc->pSignatures[i];
+ break;
+ }
+ }
+ return pSignature;
+}
+
+
+//============================================================
+// Adds a new SignedInfo element to a SignedDoc element and initializes it
+// id - signature id (use NULL for default)
+// return the newly created structure
+//============================================================
+// FIXME : memory leaks possible..
+EXP_OPTION int SignatureInfo_new(SignatureInfo **newSignatureInfo,
+ SignedDoc* pSigDoc, const char* id)
+{
+ int i, nId = 0;
+ SignatureInfo** pSignatures = NULL;
+ SignatureInfo* pSigInfo = NULL;
+ char buf[100];
+
+ RETURN_IF_NULL_PARAM(pSigDoc);
+ //clearErrors();
+ if(hasSignatureWithWrongDataFileHash(pSigDoc)) {
+ ddocDebug(1, "SignatureInfo_new", "Cannot add signature in ddoc with invalid DataFile hashes!");
+ return ERR_FILE_WRITE;
+ }
+ if(!id)
+ nId = getNextSignatureId(pSigDoc);
+ if(pSigDoc->nSignatures == 0) {
+ RETURN_IF_NOT(!pSigDoc->pSignatures, ERR_BAD_SIG_COUNT);
+ pSigDoc->nSignatures = 1;
+ }
+ else
+ pSigDoc->nSignatures++;
+ pSignatures = (SignatureInfo**)malloc((pSigDoc->nSignatures) * sizeof(void *));
+ RETURN_IF_BAD_ALLOC(pSignatures);
+ for(i = 0; i < pSigDoc->nSignatures-1; i++)
+ pSignatures[i] = pSigDoc->pSignatures[i];
+ pSigInfo = (SignatureInfo*)malloc(sizeof(SignatureInfo));
+ RETURN_IF_BAD_ALLOC(pSigInfo);
+ memset(pSigInfo, 0, sizeof(SignatureInfo));
+ pSignatures[pSigDoc->nSignatures-1] = pSigInfo;
+ if(pSigDoc->pSignatures)
+ free(pSigDoc->pSignatures);
+ pSigDoc->pSignatures = pSignatures;
+ if(id) {
+ setString(&(pSigInfo->szId), id, -1);
+ } else {
+ snprintf(buf, sizeof(buf), "S%d", nId);
+ setString(&(pSigInfo->szId), buf, -1);
+ }
+ // create timestamp
+ createTimestamp(pSigDoc, buf, sizeof(buf));
+ setString(&(pSigInfo->szTimeStamp), buf, -1);
+ *newSignatureInfo = pSigInfo;
+ return ERR_OK;
+}
+
+
+//============================================================
+// Sets the signature production place info
+// pSigInfo - signature info object
+// city - city name
+// state - state or province name
+// zip - postal code
+// country - country name
+//============================================================
+EXP_OPTION int setSignatureProductionPlace(SignatureInfo* pSigInfo,
+ const char* city, const char* state,
+ const char* zip, const char* country)
+{
+ char* p = 0;
+ RETURN_IF_NULL_PARAM(pSigInfo);
+ if(city) {
+ p = (char*)escape2xmlsym(city);
+ if(p) {
+ setString(&(pSigInfo->sigProdPlace.szCity), p, -1);
+ free(p);
+ }
+ }
+ if(state) {
+ p = (char*)escape2xmlsym(state);
+ if(p) {
+ setString(&(pSigInfo->sigProdPlace.szStateOrProvince), p, -1);
+ free(p);
+ }
+ }
+ if(zip) {
+ p = (char*)escape2xmlsym(zip);
+ if(p) {
+ setString(&(pSigInfo->sigProdPlace.szPostalCode), p, -1);
+ free(p);
+ }
+ }
+ if(country) {
+ p = (char*)escape2xmlsym(country);
+ if(p) {
+ setString(&(pSigInfo->sigProdPlace.szCountryName), country, -1);
+ free(p);
+ }
+ }
+ return ERR_OK;
+}
+
+
+
+//============================================================
+// Adds a signer role
+// pSigInfo - signature info object
+// nCertified - certified role? (1/0)
+// role - role data
+// rLen - role data length
+// encode - 1=encode it with Base64, 0=use as is
+//============================================================
+// FIXME : memory leaks possible...
+EXP_OPTION int addSignerRole(SignatureInfo* pSigInfo, int nCertified,
+ const char* role, int rLen, int enc)
+{
+ int n, i;
+ char **p = NULL, *b = NULL, *p1;
+
+ RETURN_IF_NULL_PARAM(pSigInfo);
+ //if(!enc && role && (strchr(role, '<') || strchr(role, '>')))
+ // SET_LAST_ERROR_RETURN(ERR_INVALID_CONTENT, ERR_INVALID_CONTENT);
+
+ if(nCertified) {
+ n = pSigInfo->signerRole.nCertifiedRoles + 1;
+ p = (char**)malloc(n * sizeof(void*));
+ RETURN_IF_BAD_ALLOC(p);
+ if(pSigInfo->signerRole.nCertifiedRoles) {
+ RETURN_IF_NULL(pSigInfo->signerRole.pCertifiedRoles);
+ for(i = 0; i < pSigInfo->signerRole.nCertifiedRoles; i++)
+ p[i] = pSigInfo->signerRole.pCertifiedRoles[i];
+ free(pSigInfo->signerRole.pCertifiedRoles);
+ }
+ p[n-1] = 0;
+ if(enc) {
+ b = (char*)malloc(rLen * 2);
+ RETURN_IF_BAD_ALLOC(b);
+ i = sizeof(b);
+ encode((const byte*)role, rLen, (byte*)b, &i);
+ b[i] = 0;
+ setString(&(p[n-1]), b, i);
+ }
+ else
+ setString(&(p[n-1]), role, rLen);
+ pSigInfo->signerRole.pCertifiedRoles = p;
+ pSigInfo->signerRole.nCertifiedRoles = n;
+ } else {
+ n = pSigInfo->signerRole.nClaimedRoles + 1;
+ p = (char**)malloc(n * sizeof(void*));
+ RETURN_IF_BAD_ALLOC(p);
+ if(pSigInfo->signerRole.nClaimedRoles) {
+ RETURN_IF_NULL(pSigInfo->signerRole.pClaimedRoles);
+ for(i = 0; i < pSigInfo->signerRole.nClaimedRoles; i++)
+ p[i] = pSigInfo->signerRole.pClaimedRoles[i];
+ free(pSigInfo->signerRole.pClaimedRoles);
+ }
+ p[n-1] = 0;
+ if(enc) {
+ b = (char*)malloc(rLen * 2);
+ RETURN_IF_BAD_ALLOC(b);
+ i = sizeof(b);
+ encode((const byte*)role, rLen, (byte*)b, &i);
+ b[i] = 0;
+ setString(&(p[n-1]), b, i);
+ }
+ else {
+ p1 = (char*)escape2xmlsym(role);
+ if(p1) {
+ setString(&(p[n-1]), p1, -1);
+ free(p1);
+ }
+ }
+ pSigInfo->signerRole.pClaimedRoles = p;
+ pSigInfo->signerRole.nClaimedRoles = n;
+ }
+ return ERR_OK;
+}
+
+//============================================================
+// Returns the number of signer roles
+// pSigInfo - signature info object
+// nCertified - certified role? (1/0)
+//============================================================
+EXP_OPTION int getCountOfSignerRoles(SignatureInfo* pSigInfo, int nCertified)
+{
+ RETURN_OBJ_IF_NULL(pSigInfo, -1);
+ if(nCertified)
+ return pSigInfo->signerRole.nCertifiedRoles;
+ else
+ return pSigInfo->signerRole.nClaimedRoles;
+}
+
+
+//============================================================
+// Returns the desired signer role
+// pSigInfo - signature info object
+// nCertified - certified role? (1/0)
+//============================================================
+EXP_OPTION const char* getSignerRole(SignatureInfo* pSigInfo, int nCertified, int nIdx)
+{
+ RETURN_OBJ_IF_NULL(pSigInfo, 0);
+ if(nCertified) {
+ SET_LAST_ERROR_RETURN_IF_NOT(nIdx < pSigInfo->signerRole.nCertifiedRoles, ERR_BAD_ROLE_INDEX, 0);
+ RETURN_OBJ_IF_NULL(pSigInfo->signerRole.pCertifiedRoles[nIdx], 0);
+ return pSigInfo->signerRole.pCertifiedRoles[nIdx];
+ } else {
+ SET_LAST_ERROR_RETURN_IF_NOT(nIdx < pSigInfo->signerRole.nClaimedRoles, ERR_BAD_ROLE_INDEX, 0);
+ RETURN_OBJ_IF_NULL(pSigInfo->signerRole.pClaimedRoles[nIdx], 0);
+ return pSigInfo->signerRole.pClaimedRoles[nIdx];
+ }
+}
+
+
+//============================================================
+// Removes this SignatureInfo from signed doc and frees it's memory
+// pSigDoc - signed doc object
+// id - signature id to be removed
+//============================================================
+EXP_OPTION int SignatureInfo_delete(SignedDoc* pSigDoc, const char* id)
+{
+ int n, i, j, err = ERR_OK;
+ SignatureInfo* pSignature;
+ SignatureInfo** pSignatures;
+
+ RETURN_IF_NULL_PARAM(pSigDoc);
+ ddocDebug(3, "SignatureInfo_delete", "id: %s", id);
+ if(hasSignatureWithWrongDataFileHash(pSigDoc)) {
+ ddocDebug(1, "SignatureInfo_delete", "Cannot delete signature in ddoc with invalid DataFile hashes!");
+ return ERR_FILE_WRITE;
+ }
+ if((pSignature = getSignatureWithId(pSigDoc, id)) != NULL) {
+ n = pSigDoc->nSignatures - 1;
+ if(n > 0) {
+ pSignatures = (SignatureInfo**)malloc(n * sizeof(void*));
+ RETURN_IF_BAD_ALLOC(pSignatures);
+ for(i = j = 0; i < pSigDoc->nSignatures; i++) {
+ if(strcmp(pSigDoc->pSignatures[i]->szId, id)) {
+ pSignatures[j++] = pSigDoc->pSignatures[i];
+ } else {
+ SignatureInfo_free(pSigDoc->pSignatures[i]);
+ }
+ }
+ free(pSigDoc->pSignatures);
+ pSigDoc->pSignatures = pSignatures;
+ pSigDoc->nSignatures = j;
+ } else {
+ for(i = 0; i < pSigDoc->nSignatures; i++){
+ SignatureInfo_free(pSigDoc->pSignatures[i]);
+ free(pSigDoc->pSignatures);
+ pSigDoc->pSignatures = NULL;
+ pSigDoc->nSignatures = 0;}
+ }
+ }
+ else
+ err = ERR_BAD_SIG_INDEX;
+ if (err != ERR_OK) SET_LAST_ERROR(err);
+ return err;
+}
+
+
+//============================================================
+// cleanup SignatureInfo memory
+// pSigInfo - object to be cleaned up
+//============================================================
+EXP_OPTION void SignatureInfo_free(SignatureInfo* pSigInfo)
+{
+ int i;
+
+ RETURN_VOID_IF_NULL(pSigInfo);
+ if(pSigInfo->szId)
+ free(pSigInfo->szId);
+ if(pSigInfo->szTimeStamp)
+ free(pSigInfo->szTimeStamp);
+ if(pSigInfo->pSigPropDigest)
+ ddocDigestValue_free(pSigInfo->pSigPropDigest);
+ if(pSigInfo->pSigPropRealDigest)
+ ddocDigestValue_free(pSigInfo->pSigPropRealDigest);
+ if(pSigInfo->pSigInfoRealDigest)
+ ddocDigestValue_free(pSigInfo->pSigInfoRealDigest);
+ if(pSigInfo->pSigValue)
+ ddocSignatureValue_free(pSigInfo->pSigValue);
+ for(i = 0; i < pSigInfo->nDocs; i++) {
+ DocInfo_free(pSigInfo->pDocs[i]);
+ }
+ if(pSigInfo->pDocs)
+ free(pSigInfo->pDocs);
+ // signature production place
+ if(pSigInfo->sigProdPlace.szCity)
+ free(pSigInfo->sigProdPlace.szCity);
+ if(pSigInfo->sigProdPlace.szStateOrProvince)
+ free(pSigInfo->sigProdPlace.szStateOrProvince);
+ if(pSigInfo->sigProdPlace.szPostalCode)
+ free(pSigInfo->sigProdPlace.szPostalCode);
+ if(pSigInfo->sigProdPlace.szCountryName)
+ free(pSigInfo->sigProdPlace.szCountryName);
+ // signer role
+ for(i = 0; i < pSigInfo->signerRole.nClaimedRoles; i++) {
+ if(pSigInfo->signerRole.pClaimedRoles[i])
+ free(pSigInfo->signerRole.pClaimedRoles[i]);
+ }
+ if(pSigInfo->signerRole.pClaimedRoles)
+ free(pSigInfo->signerRole.pClaimedRoles);
+ for(i = 0; i < pSigInfo->signerRole.nCertifiedRoles; i++) {
+ if (pSigInfo->signerRole.pCertifiedRoles[i])
+ free(pSigInfo->signerRole.pCertifiedRoles[i]);
+ }
+ if(pSigInfo->signerRole.pCertifiedRoles)
+ free(pSigInfo->signerRole.pCertifiedRoles);
+ ddocMemBuf_free(&(pSigInfo->mbufOrigContent));
+ if(pSigInfo->pNotary)
+ NotaryInfo_free(pSigInfo->pNotary);
+ if(pSigInfo->pCertIDs)
+ ddocCertIDList_free(pSigInfo->pCertIDs);
+ if(pSigInfo->pCertValues)
+ ddocCertValueList_free(pSigInfo->pCertValues);
+ //AM 23.05.08
+ if(pSigInfo->szDigestType)
+ free(pSigInfo->szDigestType);
+ free(pSigInfo);
+}
+
+//============================================================
+// Sets signatures signed properties digest
+// pSigInfo - signature info object
+// value - new binary digest value
+// len - length of the value
+//============================================================
+EXP_OPTION int ddocSigInfo_SetSigPropDigest(SignatureInfo* pSigInfo, const char* value, long len)
+{
+ RETURN_IF_NULL_PARAM(pSigInfo);
+ RETURN_IF_NULL_PARAM(value);
+ if(!pSigInfo->pSigPropDigest)
+ ddocDigestValue_new(&(pSigInfo->pSigPropDigest), 0, 0, 0);
+ return ddocDigestValue_SetDigestValue(pSigInfo->pSigPropDigest, value, len);
+}
+
+//============================================================
+// Sets signatures signed properties real digest as read from file
+// pSigInfo - signature info object
+// value - new binary digest value
+// len - length of the value
+//============================================================
+EXP_OPTION int ddocSigInfo_SetSigPropRealDigest(SignatureInfo* pSigInfo, const char* value, long len)
+{
+ RETURN_IF_NULL_PARAM(pSigInfo);
+ RETURN_IF_NULL_PARAM(value);
+ if(!pSigInfo->pSigPropRealDigest)
+ ddocDigestValue_new(&(pSigInfo->pSigPropRealDigest), 0, 0, 0);
+ return ddocDigestValue_SetDigestValue(pSigInfo->pSigPropRealDigest, value, len);
+}
+
+//============================================================
+// Sets signatures signed info real digest as read from file
+// pSigInfo - signature info object
+// value - new binary digest value
+// len - length of the value
+//============================================================
+EXP_OPTION int ddocSigInfo_SetSigInfoRealDigest(SignatureInfo* pSigInfo, const char* value, long len)
+{
+ RETURN_IF_NULL_PARAM(pSigInfo);
+ RETURN_IF_NULL_PARAM(value);
+ if(!pSigInfo->pSigInfoRealDigest)
+ ddocDigestValue_new(&(pSigInfo->pSigInfoRealDigest), 0, 0, 0);
+ return ddocDigestValue_SetDigestValue(pSigInfo->pSigInfoRealDigest, value, len);
+}
+
+//============================================================
+// Returns signatures signed properties digest
+// pSigInfo - signature info object
+// return digest value as DigiDocMemBuf pointer or NULL
+//============================================================
+EXP_OPTION DigiDocMemBuf* ddocSigInfo_GetSigPropDigest(SignatureInfo* pSigInfo)
+{
+ RETURN_OBJ_IF_NULL(pSigInfo, NULL);
+ return ddocDigestValue_GetDigestValue(pSigInfo->pSigPropDigest);
+}
+
+//============================================================
+// Returns signatures signed properties digest as read from file
+// pSigInfo - signature info object
+// return digest value as DigiDocMemBuf pointer or NULL
+//============================================================
+EXP_OPTION DigiDocMemBuf* ddocSigInfo_GetSigPropRealDigest(SignatureInfo* pSigInfo)
+{
+ RETURN_OBJ_IF_NULL(pSigInfo, NULL);
+ return ddocDigestValue_GetDigestValue(pSigInfo->pSigPropRealDigest);
+}
+
+//============================================================
+// Returns signatures signed info digest as read from file
+// pSigInfo - signature info object
+// return digest value as DigiDocMemBuf pointer or NULL
+//============================================================
+EXP_OPTION DigiDocMemBuf* ddocSigInfo_GetSigInfoRealDigest(SignatureInfo* pSigInfo)
+{
+ RETURN_OBJ_IF_NULL(pSigInfo, NULL);
+ return ddocDigestValue_GetDigestValue(pSigInfo->pSigInfoRealDigest);
+}
+
+//============================================================
+// Returns signatures signature-value
+// pSigInfo - signature info object
+// return signature-value as SignatureValue pointer or NULL
+//============================================================
+EXP_OPTION SignatureValue* ddocSigInfo_GetSignatureValue(SignatureInfo* pSigInfo)
+{
+ RETURN_OBJ_IF_NULL(pSigInfo, NULL);
+ return pSigInfo->pSigValue;
+}
+
+//============================================================
+// Returns signatures signature-value
+// pSigInfo - signature info object
+// return signature-value as DigiDocMemBuf pointer or NULL
+//============================================================
+EXP_OPTION DigiDocMemBuf* ddocSigInfo_GetSignatureValue_Value(SignatureInfo* pSigInfo)
+{
+ RETURN_OBJ_IF_NULL(pSigInfo, NULL);
+ return ddocSignatureValue_GetSignatureValue(pSigInfo->pSigValue);
+}
+
+//============================================================
+// Sets signatures signature-value
+// pSigInfo - signature info object
+// value - new binary signature value
+// len - length of the value
+//============================================================
+EXP_OPTION int ddocSigInfo_SetSignatureValue(SignatureInfo* pSigInfo, const char* value, long len)
+{
+ char buf1[30];
+
+ RETURN_IF_NULL_PARAM(pSigInfo);
+ RETURN_IF_NULL_PARAM(value);
+ snprintf(buf1, sizeof(buf1), "%s-SIG", pSigInfo->szId);
+ if(!pSigInfo->pSigValue)
+ ddocSignatureValue_new(&(pSigInfo->pSigValue), 0, 0, 0, 0);
+ ddocSignatureValue_SetId(pSigInfo->pSigValue, buf1);
+ return ddocSignatureValue_SetSignatureValue(pSigInfo->pSigValue, value, len);
+}
+
+//============================================================
+// Returns signaers certs - issuer-serial
+// pSigInfo - signature info object
+// return required atribute value
+//============================================================
+EXP_OPTION const char* ddocSigInfo_GetSignersCert_IssuerSerial(const SignatureInfo* pSigInfo)
+{
+ CertID* pCertID = 0;
+ RETURN_OBJ_IF_NULL(pSigInfo, NULL);
+ pCertID = ddocCertIDList_GetCertIDOfType(pSigInfo->pCertIDs, CERTID_TYPE_SIGNERS_CERTID);
+ RETURN_OBJ_IF_NULL(pCertID, NULL);
+ return ddocCertID_GetIssuerSerial(pCertID);
+}
+
+//============================================================
+// Sets signers certs issuer serial
+// pSigInfo - signature info object
+// value - new value
+//============================================================
+EXP_OPTION int ddocSigInfo_SetSignersCert_IssuerSerial(SignatureInfo* pSigInfo, const char* value)
+{
+ CertID* pCertID = 0;
+ RETURN_IF_NULL_PARAM(pSigInfo);
+ RETURN_IF_NULL_PARAM(value);
+ pCertID = ddocCertIDList_GetOrCreateCertIDOfType(pSigInfo->pCertIDs, CERTID_TYPE_SIGNERS_CERTID);
+ return ddocCertID_SetIssuerSerial(pCertID, value);
+}
+
+//============================================================
+// Returns signaers certs - issuer-name
+// pSigInfo - signature info object
+// return required atribute value
+//============================================================
+EXP_OPTION const char* ddocSigInfo_GetSignersCert_IssuerName(const SignatureInfo* pSigInfo)
+{
+ CertID* pCertID = 0;
+ RETURN_OBJ_IF_NULL(pSigInfo, NULL);
+ pCertID = ddocCertIDList_GetCertIDOfType(pSigInfo->pCertIDs, CERTID_TYPE_SIGNERS_CERTID);
+ RETURN_OBJ_IF_NULL(pCertID, NULL);
+ return ddocCertID_GetIssuerName(pCertID);
+}
+
+//============================================================
+// Returns signaers certs - issuer-name
+// pSigInfo - signature info object
+// pMbuf - memory buffer to return hash
+// return required atribute value
+//============================================================
+EXP_OPTION const char* ddocSigInfo_GetSignersCert_IssuerNameAndHash(const SignatureInfo* pSigInfo, DigiDocMemBuf *pMbuf)
+{
+ CertID* pCertID = 0;
+ X509* pCert = 0;
+/* DigiDocMemBuf mbuf1, mbuf2, mbuf3;
+
+ mbuf1.pMem = 0;
+ mbuf1.nLen = 0;
+ mbuf2.pMem = 0;
+ mbuf2.nLen = 0;
+ mbuf3.pMem = 0;
+ mbuf3.nLen = 0;
+*/
+ RETURN_OBJ_IF_NULL(pSigInfo, NULL);
+ RETURN_OBJ_IF_NULL(pMbuf, NULL);
+ pCertID = ddocCertIDList_GetCertIDOfType(pSigInfo->pCertIDs, CERTID_TYPE_SIGNERS_CERTID);
+ RETURN_OBJ_IF_NULL(pCertID, NULL);
+ pCert = ddocSigInfo_GetSignersCert(pSigInfo);
+ RETURN_OBJ_IF_NULL(pCert, NULL);
+ /*ddocCertGetSubjectCN(pCert, &mbuf1);
+ readSubjectKeyIdentifier(pCert, &mbuf2);
+ ddocEncodeBase64(&mbuf2, &mbuf3);
+ ddocMemBuf_free(&mbuf2);
+ readAuthorityKeyIdentifier(pCert, pMbuf);
+ ddocEncodeBase64(pMbuf, &mbuf2);
+ ddocDebug(3, "ddocSigInfo_GetSignersCert_IssuerNameAndHash", "CN: %s subj-hash: %s issuer-hash: %s", (char*)mbuf1.pMem, (char*)mbuf3.pMem, (char*)mbuf2.pMem);
+ ddocMemBuf_free(&mbuf1);
+ ddocMemBuf_free(&mbuf2);
+ ddocMemBuf_free(&mbuf3);*/
+ readAuthorityKeyIdentifier(pCert, pMbuf);
+ return ddocCertID_GetIssuerName(pCertID);
+}
+
+//============================================================
+// Sets signers certs issuer name
+// pSigInfo - signature info object
+// value - new value
+//============================================================
+EXP_OPTION int ddocSigInfo_SetSignersCert_IssuerName(SignatureInfo* pSigInfo, const char* value)
+{
+ CertID* pCertID = 0;
+ RETURN_IF_NULL_PARAM(pSigInfo);
+ RETURN_IF_NULL_PARAM(value);
+ pCertID = ddocCertIDList_GetOrCreateCertIDOfType(pSigInfo->pCertIDs, CERTID_TYPE_SIGNERS_CERTID);
+ return ddocCertID_SetIssuerName(pCertID, value);
+}
+
+//============================================================
+// Returns signers certs digest as DigiDocMemBuf object
+// pSigInfo - signature info object
+// return signers certs digest as DigiDocMemBuf pointer or NULL
+//============================================================
+EXP_OPTION DigiDocMemBuf* ddocSigInfo_GetSignersCert_DigestValue(const SignatureInfo* pSigInfo)
+{
+ CertID* pCertID = 0;
+ RETURN_OBJ_IF_NULL(pSigInfo, NULL);
+ pCertID = ddocCertIDList_GetCertIDOfType(pSigInfo->pCertIDs, CERTID_TYPE_SIGNERS_CERTID);
+ RETURN_OBJ_IF_NULL(pCertID, NULL);
+ return ddocCertID_GetDigestValue(pCertID);
+}
+
+//============================================================
+// Sets signers certs digest
+// pSigInfo - signature info object
+// value - new binary signature value
+// len - length of the value
+//============================================================
+EXP_OPTION int ddocSigInfo_SetSignersCert_DigestValue(SignatureInfo* pSigInfo, const char* value, long len)
+{
+ CertID* pCertID = 0;
+ RETURN_IF_NULL_PARAM(pSigInfo);
+ RETURN_IF_NULL_PARAM(value);
+ pCertID = ddocCertIDList_GetOrCreateCertIDOfType(pSigInfo->pCertIDs, CERTID_TYPE_SIGNERS_CERTID);
+ return ddocCertID_SetDigestValue(pCertID, value, len);
+}
+
+//--------------------------------------------------
+// Finds a CertID object with required type
+// pSigInfo - signature info object [REQUIRED]
+// nType - type of CertID object [REQUIRED]
+// returns CertID pointer or NULL for error
+//--------------------------------------------------
+EXP_OPTION CertID* ddocSigInfo_GetCertIDOfType(const SignatureInfo* pSigInfo, int nType)
+{
+ RETURN_OBJ_IF_NULL(pSigInfo, NULL);
+ if(pSigInfo->pCertIDs)
+ return ddocCertIDList_GetCertIDOfType(pSigInfo->pCertIDs, nType);
+ return NULL;
+}
+
+//--------------------------------------------------
+// Finds last CertID object of this signature
+// pSigInfo - signature info object [REQUIRED]
+// returns CertID pointer or NULL for error
+//--------------------------------------------------
+EXP_OPTION CertID* ddocSigInfo_GetLastCertID(const SignatureInfo* pSigInfo)
+{
+ RETURN_OBJ_IF_NULL(pSigInfo, NULL);
+ if(pSigInfo->pCertIDs)
+ return ddocCertIDList_GetLastCertID(pSigInfo->pCertIDs);
+ return NULL;
+}
+
+
+//--------------------------------------------------
+// Finds a CertID object with required type or creates a new one
+// pSigInfo - signature info object [REQUIRED]
+// nType - type of CertID object [REQUIRED]
+// returns CertID pointer or NULL for error
+//--------------------------------------------------
+EXP_OPTION CertID* ddocSigInfo_GetOrCreateCertIDOfType(SignatureInfo* pSigInfo, int nType)
+{
+ RETURN_OBJ_IF_NULL(pSigInfo, NULL);
+ if(!pSigInfo->pCertIDs)
+ ddocCertIDList_new(&(pSigInfo->pCertIDs));
+ RETURN_OBJ_IF_NULL(pSigInfo->pCertIDs, NULL);
+ return ddocCertIDList_GetOrCreateCertIDOfType(pSigInfo->pCertIDs, nType);
+}
+
+//--------------------------------------------------
+// Finds a CertValue object with required type
+// pSigInfo - signature info object [REQUIRED]
+// nType - type of CertValue object [REQUIRED]
+// returns CertValue pointer or NULL for error
+//--------------------------------------------------
+EXP_OPTION CertValue* ddocSigInfo_GetCertValueOfType(const SignatureInfo* pSigInfo, int nType)
+{
+ RETURN_OBJ_IF_NULL(pSigInfo, NULL);
+ ddocDebug(9, "ddocSigInfo_GetCertValueOfType", "start");
+ if(pSigInfo->pCertValues)
+ return ddocCertValueList_GetCertValueOfType(pSigInfo->pCertValues, nType);
+ ddocDebug(9, "ddocSigInfo_GetCertValueOfType", "end");
+ return NULL;
+}
+
+//--------------------------------------------------
+// Finds a CertValue object with required type or creates a new one
+// pSigInfo - signature info object [REQUIRED]
+// nType - type of CertValue object [REQUIRED]
+// returns CertValue pointer or NULL for error
+//--------------------------------------------------
+EXP_OPTION CertValue* ddocSigInfo_GetOrCreateCertValueOfType(SignatureInfo* pSigInfo, int nType)
+{
+ RETURN_OBJ_IF_NULL(pSigInfo, NULL);
+ if(!pSigInfo->pCertValues)
+ ddocCertValueList_new(&(pSigInfo->pCertValues));
+ RETURN_OBJ_IF_NULL(pSigInfo->pCertValues, NULL);
+ return ddocCertValueList_GetOrCreateCertValueOfType(pSigInfo->pCertValues, nType);
+}
+
+//--------------------------------------------------
+// Finds last CertValue
+// pSigInfo - signature info object [REQUIRED]
+// returns CertValue pointer or NULL for error
+//--------------------------------------------------
+EXP_OPTION CertValue* ddocSigInfo_GetLastCertValue(const SignatureInfo* pSigInfo)
+{
+ RETURN_OBJ_IF_NULL(pSigInfo, NULL);
+ if(pSigInfo->pCertValues)
+ return ddocCertValueList_GetCertValue(pSigInfo->pCertValues,
+ ddocCertValueList_GetCertValuesCount(pSigInfo->pCertValues) - 1);
+ return NULL;
+}
+
+//--------------------------------------------------
+// Finds the signers certificate
+// pSigInfo - signature info object [REQUIRED]
+// returns certificate or NULL
+//--------------------------------------------------
+EXP_OPTION X509* ddocSigInfo_GetSignersCert(const SignatureInfo* pSigInfo)
+{
+ X509 *pCert = 0;
+ CertValue *pCertValue = 0;
+ RETURN_OBJ_IF_NULL(pSigInfo, NULL);
+ if(pSigInfo->pCertValues) {
+ pCertValue = ddocSigInfo_GetCertValueOfType(pSigInfo, CERTID_VALUE_SIGNERS_CERT);
+ if(pCertValue)
+ pCert = pCertValue->pCert;
+ }
+ return pCert;
+}
+
+//--------------------------------------------------
+// Sets the signers certificate
+// pSigInfo - signature info object [REQUIRED]
+// pCert - certificate [REQUIRED]
+// returns error code or ERR_OK
+//--------------------------------------------------
+EXP_OPTION int ddocSigInfo_SetSignersCert(SignatureInfo* pSigInfo, X509* pCert)
+{
+ int err = ERR_OK;
+ CertValue *pCertValue = 0;
+ char buf1[50];
+
+ RETURN_IF_NULL_PARAM(pSigInfo);
+ RETURN_IF_NULL_PARAM(pCert);
+ pCertValue = ddocSigInfo_GetOrCreateCertValueOfType(pSigInfo, CERTID_VALUE_SIGNERS_CERT);
+ if(pCertValue) {
+ snprintf(buf1, sizeof(buf1), "%s-SIGNER_CERT", pSigInfo->szId);
+ err = ddocCertValue_SetId(pCertValue, buf1);
+ if(!err && pCert)
+ err = ddocCertValue_SetCert(pCertValue, pCert);
+ }
+ return err;
+}
+
+//--------------------------------------------------
+// Finds the OCSP responders certificate
+// pSigInfo - signature info object [REQUIRED]
+// returns certificate or NULL
+//--------------------------------------------------
+EXP_OPTION X509* ddocSigInfo_GetOCSPRespondersCert(const SignatureInfo* pSigInfo)
+{
+ X509 *pCert = 0;
+ CertValue *pCertValue = 0;
+ RETURN_OBJ_IF_NULL(pSigInfo, NULL);
+ if(pSigInfo->pCertValues) {
+ ddocDebug(5, "ddocSigInfo_GetOCSPRespondersCert", "start");
+ pCertValue = ddocSigInfo_GetCertValueOfType(pSigInfo, CERTID_VALUE_RESPONDERS_CERT);
+ ddocDebug(5, "ddocSigInfo_GetOCSPRespondersCert", "end");
+ if(pCertValue){
+ pCert = pCertValue->pCert;
+ ddocDebug(5, "ddocSigInfo_GetOCSPRespondersCert", "test");}
+ }
+ ddocDebug(5, "ddocSigInfo_GetOCSPRespondersCert", "end2");
+ if(pCert) ddocDebug(5, "ddocSigInfo_GetOCSPRespondersCert", "pCert exists" );
+ return pCert;
+}
+
+//--------------------------------------------------
+// Sets the OCSP Responders certificate
+// pSigInfo - signature info object [REQUIRED]
+// pCert - certificate [REQUIRED]
+// returns error code or ERR_OK
+//--------------------------------------------------
+EXP_OPTION int ddocSigInfo_SetOCSPRespondersCert(SignatureInfo* pSigInfo, X509* pCert)
+{
+ int err = ERR_OK;
+ CertValue *pCertValue = 0;
+ char buf1[50];
+
+ RETURN_IF_NULL_PARAM(pSigInfo);
+ RETURN_IF_NULL_PARAM(pCert);
+ pCertValue = ddocSigInfo_GetOrCreateCertValueOfType(pSigInfo, CERTID_VALUE_RESPONDERS_CERT);
+ if(pCertValue) {
+ snprintf(buf1, sizeof(buf1), "%s-RESPONDER_CERT", pSigInfo->szId);
+ err = ddocCertValue_SetId(pCertValue, buf1);
+ if(!err)
+ err = ddocCertValue_SetCert(pCertValue, pCert);
+ }
+ return err;
+}
+
+//============================================================
+// Adds a certificate and it's certid to this signature
+// pSigInfo - signature info object [REQUIRED]
+// pCert - vertificate [REQUIRED]
+// nCertIdType - type of cert [REQUIRED]
+// return error code or ERR_OK
+//============================================================
+EXP_OPTION int ddocSigInfo_addCert(SignatureInfo* pSigInfo, X509* pCert, int nCertIdType)
+{
+ int err = ERR_OK, l1;
+ char buf1[100], buf2[200], buf3[300], buf4[100];
+ CertID *pCertID = 0;
+ DigiDocMemBuf mbuf1;
+ mbuf1.pMem = 0;
+ mbuf1.nLen = 0;
+
+ RETURN_IF_NULL_PARAM(pSigInfo);
+ RETURN_IF_NULL_PARAM(pCert);
+
+ RETURN_IF_NOT(err == ERR_OK, err);
+ l1 = sizeof(buf1);
+ RETURN_IF_NOT(X509_digest(pCert, EVP_sha1(), (unsigned char*)buf1,
+ (unsigned int*)&l1), ERR_X509_DIGEST);
+ if(err) return err;
+ err = ReadCertSerialNumber(buf2, sizeof(buf2), pCert);
+ memset(buf3, 0, sizeof(buf3));
+ err = ddocCertGetIssuerDN(pCert, &mbuf1);
+ RETURN_IF_NOT(err == ERR_OK, err);
+ // now set all those atributes
+ switch(nCertIdType) {
+ case CERTID_TYPE_SIGNERS_CERTID:
+ err = ddocSigInfo_SetSignersCert(pSigInfo, pCert);
+ snprintf(buf4, sizeof(buf4), "%s-CERTINFO", pSigInfo->szId);
+ ddocCertID_new(&pCertID, CERTID_TYPE_SIGNERS_CERTID, buf4, buf2, (char*)mbuf1.pMem, buf1, l1);
+ break;
+ case CERTID_TYPE_RESPONDERS_CERTID:
+ err = ddocSigInfo_SetOCSPRespondersCert(pSigInfo, pCert);
+ snprintf(buf4, sizeof(buf4), "%s-OCSP_CERTINFO", pSigInfo->szId);
+ ddocCertID_new(&pCertID, CERTID_TYPE_RESPONDERS_CERTID, buf4, buf2, (char*)mbuf1.pMem, buf1, l1);
+ break;
+ }
+ RETURN_IF_NOT(pCertID, ERR_BAD_ALLOC);
+ if(!pSigInfo->pCertIDs) {
+ err = ddocCertIDList_new(&(pSigInfo->pCertIDs));
+ //ddocCertID_free(pCertID); // not owner any more!
+ SET_LAST_ERROR_IF_NOT(err == ERR_OK, err);
+ }
+ if(pCertID) {
+ ddocCertIDList_addCertID(pSigInfo->pCertIDs, pCertID);
+ ddocDebug(3, "ddocSigInfo_addCert", "Added signers cert-id: %s type: %d", pCertID->szId, pCertID->nType);
+ }
+ ddocMemBuf_free(&mbuf1);
+ return err;
+}
+
+
+
+//======================< DocInfo functions >=========================================
+
+
+//============================================================
+// Adds a new DocInfo element to a SignatureInfo element and initializes it
+// pSigInfo - signature info object
+// docId - document id (use NULL for default)
+// digType - digest type
+// digest - documents digest
+// digLen - digest length
+// mime - mime type
+// mimeDig - mime digest
+// mimeDigLen - mime digest length
+// return the newly created structure
+//============================================================
+EXP_OPTION int addDocInfo(DocInfo **newDocInfo, SignatureInfo* pSigInfo, const char* docId,
+ const char* digType, const byte* digest,
+ int digLen, const byte* mimeDig, int mimeDigLen)
+{
+ DocInfo** pDocInfos = NULL;
+ DocInfo* pDocInfo = NULL;
+ int i;
+
+ RETURN_IF_NULL_PARAM(pSigInfo);
+ if(pSigInfo->nDocs == 0) {
+ RETURN_IF_NOT(!pSigInfo->pDocs, ERR_BAD_DOCINFO_COUNT);
+ pSigInfo->nDocs = 1;
+ }
+ else
+ pSigInfo->nDocs++;
+ pDocInfos = (DocInfo**)malloc((pSigInfo->nDocs) * sizeof(void *));
+ RETURN_IF_BAD_ALLOC(pDocInfos);
+ for(i = 0; i < pSigInfo->nDocs-1; i++)
+ pDocInfos[i] = pSigInfo->pDocs[i];
+ pDocInfo = (DocInfo*)malloc(sizeof(DocInfo)); // MEMLEAK: ???
+ if (!pDocInfo) {
+ free(pDocInfos);
+ SET_LAST_ERROR_RETURN_CODE(ERR_BAD_ALLOC);
+ }
+ memset(pDocInfo, 0, sizeof(DocInfo));
+ pDocInfos[pSigInfo->nDocs-1] = pDocInfo;
+ // PR. leak found
+ if(pSigInfo->pDocs)
+ free(pSigInfo->pDocs);
+ pSigInfo->pDocs = pDocInfos;
+ if(docId)
+ setString(&(pDocInfo->szDocId), docId, -1);
+ if(digType)
+ setString(&(pDocInfo->szDigestType), digType, -1);
+ if(digest) {
+ setString((char**)&(pDocInfo->szDigest), (const char*)digest, digLen);
+ pDocInfo->nDigestLen = digLen;
+ }
+ if(mimeDig && strlen((const char*)mimeDig)) {
+ setString((char**)&(pDocInfo->szMimeDigest), (const char*)mimeDig, mimeDigLen);
+ pDocInfo->nMimeDigestLen = mimeDigLen;
+ }
+ *newDocInfo = pDocInfo;
+ return ERR_OK;
+}
+
+//============================================================
+// cleanup DocInfo memory
+// pDocInfo - object to be cleaned up
+//============================================================
+EXP_OPTION void DocInfo_free(DocInfo* pDocInfo)
+{
+ RETURN_VOID_IF_NULL(pDocInfo);
+ //assert(pDocInfo);
+ if(pDocInfo->szDocId)
+ free(pDocInfo->szDocId);
+ if(pDocInfo->szDigestType)
+ free(pDocInfo->szDigestType);
+ if(pDocInfo->szDigest)
+ free(pDocInfo->szDigest);
+ if(pDocInfo->szMimeDigest)
+ free(pDocInfo->szMimeDigest);
+ // free the object itself
+ free(pDocInfo);
+}
+
+//============================================================
+// Returns number of DocInfos
+// pSigInfo - signature info pointer
+//============================================================
+EXP_OPTION int getCountOfDocInfos(const SignatureInfo* pSigInfo)
+{
+ RETURN_OBJ_IF_NULL(pSigInfo, -1);
+ return pSigInfo->nDocs;
+}
+
+//============================================================
+// Returns the desired DocInfo
+// pSigInfo - signature info pointer
+// idx - DocInfo index
+//============================================================
+EXP_OPTION DocInfo* getDocInfo(const SignatureInfo* pSigInfo, int idx)
+{
+ ddocDebug(3, "getDocInfo", "Idx: %d, Docs: %d", idx, pSigInfo->nDocs);
+ RETURN_OBJ_IF_NULL(pSigInfo, NULL);
+ SET_LAST_ERROR_RETURN_IF_NOT(idx < pSigInfo->nDocs, ERR_BAD_DOCINFO_INDEX, NULL);
+ RETURN_OBJ_IF_NULL(pSigInfo->pDocs, NULL);
+ RETURN_OBJ_IF_NULL(pSigInfo->pDocs[idx], NULL);
+ return pSigInfo->pDocs[idx];
+}
+
+//============================================================
+// Returns the last DocInfo
+// pSigInfo - signature info pointer
+// idx - DocInfo index
+//============================================================
+EXP_OPTION DocInfo* ddocGetLastDocInfo(const SignatureInfo* pSigInfo)
+{
+ int idx;
+
+ RETURN_OBJ_IF_NULL(pSigInfo, NULL);
+ idx = pSigInfo->nDocs - 1;
+ SET_LAST_ERROR_RETURN_IF_NOT(idx < pSigInfo->nDocs, ERR_BAD_DOCINFO_INDEX, NULL);
+ RETURN_OBJ_IF_NULL(pSigInfo->pDocs, NULL);
+ RETURN_OBJ_IF_NULL(pSigInfo->pDocs[idx], NULL);
+ return pSigInfo->pDocs[idx];
+}
+
+//============================================================
+// Returns the DocInfo object with the given id
+// pSigInfo - signature info pointer
+// id - SignatureInfo id
+//============================================================
+EXP_OPTION DocInfo* getDocInfoWithId(const SignatureInfo* pSigInfo, const char* id)
+{
+ DocInfo* pDocInfo = NULL;
+ int i;
+
+ RETURN_OBJ_IF_NULL(pSigInfo, NULL);
+ //RETURN_OBJ_IF_NULL(id, NULL);
+ for(i = 0; i < pSigInfo->nDocs; i++) {
+ RETURN_OBJ_IF_NULL(pSigInfo->pDocs[i], NULL);
+ RETURN_OBJ_IF_NULL(pSigInfo->pDocs[i]->szDocId, NULL);
+ if((id && !strcmp(pSigInfo->pDocs[i]->szDocId, id)) || !id) {
+ pDocInfo = pSigInfo->pDocs[i];
+ break;
+ }
+ }
+ return pDocInfo;
+}
+
+//============================================================
+// Sets the DocInfo objects document digest and digest type
+// pDocInfo - document info pointer
+// digest - digest value
+// digLen - digest value length
+// digType - digest type
+//============================================================
+EXP_OPTION void setDocInfoDigest(DocInfo* pDocInfo, const byte* digest,
+ int digLen, const char* digType)
+{
+ RETURN_VOID_IF_NULL(pDocInfo);
+ if(digType)
+ setString(&(pDocInfo->szDigestType), digType, -1);
+ if(digest) {
+ setString((char**)&(pDocInfo->szDigest), (const char*)digest, digLen);
+ pDocInfo->nDigestLen = digLen;
+ }
+}
+
+//============================================================
+// Sets the DocInfo objects mime digest and mime type
+// pDocInfo - document info pointer
+// mimeDig - mime digest value
+// mimeDigLen - mime digest value length
+//============================================================
+EXP_OPTION void setDocInfoMimeDigest(DocInfo* pDocInfo, const byte* mimeDig,
+ int mimeDigLen)
+{
+ RETURN_VOID_IF_NULL(pDocInfo);
+ if(mimeDig) {
+ setString((char**)&(pDocInfo->szMimeDigest), (const char*)mimeDig, mimeDigLen);
+ pDocInfo->nMimeDigestLen = mimeDigLen;
+ }
+}
+
+//============================================================
+// Adds all DocInfo elements in this file to a SignatureInfo element
+// pSigInfo - signature info object
+// pSigDoc - signed document
+//============================================================
+EXP_OPTION int addAllDocInfos(SignedDoc* pSigDoc, SignatureInfo* pSigInfo)
+{
+ int i, c, l2;
+ int len = 0;
+ //Added by AA 28/10/2003 - not defined len value
+ DataFile *pDf = NULL;
+ DocInfo *pDocInfo = NULL;
+ byte buf[DIGEST_LEN+2], buf2[50];
+
+ RETURN_IF_NULL_PARAM(pSigDoc);
+ RETURN_IF_NULL_PARAM(pSigInfo);
+ c = getCountOfDataFiles(pSigDoc);
+ for(i = 0; i < c; i++ ) {
+ pDf = getDataFile(pSigDoc, i);
+ RETURN_IF_NULL(pDf);
+ buf[0] = 0;
+ // in version 1.0 we use mime digest
+ if(!strcmp(pSigDoc->szFormatVer, SK_XML_1_VER) && !strcmp(pSigDoc->szFormat, SK_XML_1_NAME)) {
+ len = sizeof(buf);
+ calculateDigest((const byte*)pDf->szMimeType, strlen(pDf->szMimeType),
+ DIGEST_SHA1, buf, &len);
+ }
+ // in 1.1 we don't use mime digest
+ memset(buf2, 0, sizeof(buf2));
+ l2 = 0;
+ encode((const byte*)pDf->mbufDigest.pMem, pDf->mbufDigest.nLen, (byte*)buf2, &l2);
+ ddocDebug(3, "addAllDocInfos", "DF: %s digest \'%s\'", pDf->szId, buf2);
+ addDocInfo(&pDocInfo, pSigInfo, pDf->szId,
+ pDf->szDigestType, (byte*)pDf->mbufDigest.pMem,
+ pDf->mbufDigest.nLen, buf, len);
+ }
+ return ERR_OK;
+}
+
+//============================================================
+// Calculates and stores a signature for this SignatureInfo object
+// pSigInfo - signature info object
+// nSigType - signature type code
+// keyfile - RSA key file
+// passwd - key password
+// certfile - certificate file
+//============================================================
+EXP_OPTION int calculateSigInfoSignature(const SignedDoc* pSigDoc,
+ SignatureInfo* pSigInfo, int nSigType,
+ const char* keyfile, const char* passwd,
+ const char* certfile)
+{
+ int err = ERR_OK;
+ char buf2[SIGNATURE_LEN], *buf1 = NULL;
+ int l2, l1;
+ X509 *pCert = 0;
+
+ RETURN_IF_NULL_PARAM(pSigInfo);
+ clearErrors();
+ if(nSigType == SIGNATURE_RSA) {
+ err = ddocSignatureValue_new(&(pSigInfo->pSigValue), 0, SIGN_RSA_NAME, 0, 0);
+ if(err) return err;
+
+ err = ReadCertificate(&pCert, certfile);
+ if(!err && pCert)
+ err = ddocSigInfo_SetSignersCert(pSigInfo, pCert);
+ RETURN_IF_NOT(err == ERR_OK, ERR_CERT_READ);
+ // Signed properties digest
+ buf1 = createXMLSignedProperties(pSigDoc, pSigInfo, 0);
+ RETURN_IF_NULL(buf1);
+ l1 = strlen(buf1);
+ l2 = sizeof(buf2);
+ calculateDigest((const byte*)buf1, l1, DIGEST_SHA1, (byte*)buf2, &l2);
+ free(buf1);
+ err = ddocSigInfo_SetSigPropDigest(pSigInfo, buf2, l2);
+ // SignedInfo digest
+ buf1 = createXMLSignedInfo(pSigDoc, pSigInfo);
+ RETURN_IF_NULL(buf1);
+ l2 = sizeof(buf2);
+ err = signData((const byte*)buf1, strlen(buf1), (byte*)buf2, &l2, DIGEST_SHA1,
+ keyfile, passwd);
+ free(buf1);
+ err = ddocSigInfo_SetSignatureValue(pSigInfo, buf2, l2);
+ } else
+ err = ERR_UNSUPPORTED_SIGNATURE;
+ if (err != ERR_OK) SET_LAST_ERROR(err);
+ return err;
+}
+
+//============================================================
+// Calculates <SignedProperties> digest
+// pSigInfo - signature info object
+//============================================================
+EXP_OPTION int calculateSignedPropertiesDigest(SignedDoc* pSigDoc, SignatureInfo* pSigInfo)
+{
+ int err = ERR_OK, l1, l2;
+ byte buf1[DIGEST_LEN256+2], *buf2 = 0, *buf3 = 0;
+
+ RETURN_IF_NULL_PARAM(pSigInfo);
+ /* P.R 0->1 */
+ buf2 = (byte*)createXMLSignedProperties(pSigDoc, pSigInfo, 1);
+ RETURN_IF_NULL(buf2);
+ buf3 = canonicalizeXML((char*)buf2, strlen((const char*)buf2));
+ //dumpInFile("sigprop-sig1.txt", buf2);
+ l2 = (int)strlen((const char*)buf3);
+ l1 = (int)sizeof(buf1);
+ calculateDigest(buf3, l2, DIGEST_SHA1, buf1, &l1);
+ free(buf2);
+ free(buf3);
+ err = ddocSigInfo_SetSigPropDigest(pSigInfo, (char*)buf1, l1);
+ return err;
+}
+
+//============================================================
+// Returns 1 if this signature has 1 reference that was verified
+// by wrong DataFile hash calculated not using xmlns atribute
+// pSigInfo - signature info pointer
+//============================================================
+EXP_OPTION int verifiedByWrongDataFileHash(const SignatureInfo* pSigInfo)
+{
+ int i;
+
+ RETURN_IF_NULL_PARAM(pSigInfo);
+ for(i = 0; i < pSigInfo->nDocs; i++) {
+ RETURN_IF_NULL_PARAM(pSigInfo->pDocs[i]);
+ if(pSigInfo->pDocs[i] && pSigInfo->pDocs[i]->szDigestType &&
+ !strcmp(pSigInfo->pDocs[i]->szDigestType, DIGEST_SHA1_WRONG))
+ return 1;
+ }
+ return 0;
+}
+
+//============================================================
+// Returns 1 if one signature has 1 reference that was verified
+// by wrong DataFile hash calculated not using xmlns atribute
+// pSigDoc - signed doc container pointer
+//============================================================
+EXP_OPTION int hasSignatureWithWrongDataFileHash(const SignedDoc* pSigDoc)
+{
+ int i, d, j;
+ SignatureInfo *pSigInfo = 0;
+
+ RETURN_IF_NULL_PARAM(pSigDoc);
+ d = getCountOfSignatures(pSigDoc);
+ for(i = 0; i < d; i++) {
+ pSigInfo = getSignature(pSigDoc, i);
+ j = verifiedByWrongDataFileHash(pSigInfo);
+ if(j) return j;
+ }
+ return 0;
+}
+
+//============================================================
+// Calculates <SignedInfo> digest
+// pSigInfo - signature info object
+// digBuf - buffer for digest value
+// digLen - address of buffer length. Must be initialized
+// with buf max len, will be changed to actual length
+//============================================================
+EXP_OPTION int calculateSignedInfoDigest(SignedDoc* pSigDoc, SignatureInfo* pSigInfo, byte* digBuf, int* digLen)
+{
+ int err = ERR_OK, l2;
+ byte *buf2 = NULL;
+
+ RETURN_IF_NULL_PARAM(pSigInfo);
+ RETURN_IF_NULL_PARAM(digBuf);
+ buf2 = (byte*)createXMLSignedInfo(pSigDoc, pSigInfo);
+ RETURN_IF_NULL(buf2);
+ l2 = strlen((const char*)buf2);
+ calculateDigest(buf2, l2, DIGEST_SHA1, digBuf, digLen);
+ free(buf2);
+ return err;
+}
+
+//============================================================
+// Sets the signature value from a file that contains
+// the base64 encoded signature value
+// pSigInfo - signature info object
+// szSigFile - filename
+//============================================================
+EXP_OPTION int setSignatureValueFromFile(SignatureInfo* pSigInfo, char* szSigFile)
+{
+ int err = ERR_OK, i, j, slen;
+ FILE* hFile = 0;
+ byte buf[FILE_BUFSIZE], sbuf[300], buf1[30];
+ DigiDocMemBuf mbuf1;
+ char *p1;
+
+ RETURN_IF_NULL_PARAM(pSigInfo);
+ RETURN_IF_NULL_PARAM(szSigFile);
+ mbuf1.pMem = 0;
+ mbuf1.nLen = 0;
+ ddocDebug(3, "setSignatureValueFromFile", "reading: %s", szSigFile);
+ if((hFile = fopen(szSigFile, "rb")) != NULL) {
+ slen = 0;
+ memset(sbuf, 0, sizeof(sbuf));
+ // collect all hex chars to sbuf
+ while((i = fread(buf, sizeof(char), FILE_BUFSIZE, hFile)) > 0) {
+ ddocDebug(3, "setSignatureValueFromFile", "read: %d", i);
+ for(j = 0; j < i; j++) {
+ if(isxdigit(buf[j])) {
+ if(isdigit(buf[j])) {
+ sbuf[slen++] = buf[j];
+ } else {
+ sbuf[slen++] = toupper(buf[j]);
+ } // else
+ } // if
+ } // for
+ }
+ ddocDebug(3, "setSignatureValueFromFile", "input: %d - \'%s\'", slen, sbuf);
+ // decode hex
+ memset(buf, 0, sizeof(buf));
+ j = 0;
+ hex2bin((const char*)sbuf, (byte*)buf, &j);
+ ddocDebug(3, "setSignatureValueFromFile", "decoded: %d", j);
+ // encode in base64 again as we need it this way for signature value
+ memset(sbuf, 0, sizeof(sbuf));
+ slen = 0;
+ encode((const byte*)buf, j, (byte*)sbuf, &slen);
+ ddocDebug(3, "setSignatureValueFromFile", "encoded: %d - \'%s\'", slen, sbuf);
+ if(j == SIGNATURE_LEN) {
+ snprintf((char*)buf1, sizeof(buf1), "#%s-SIG", pSigInfo->szId);
+ ddocSignatureValue_new(&(pSigInfo->pSigValue), (char*)buf1, SIGN_RSA_NAME, (char*)buf, j);
+ //ddocMemBuf_free(&(pSigInfo->mbufOrigContent));
+ if(pSigInfo->mbufOrigContent.pMem) {
+ p1 = strstr((char*)pSigInfo->mbufOrigContent.pMem, "<SignatureValue");
+ if(p1) p1 = strchr(p1, '>');
+ if(p1) p1++;
+ if(p1) *p1 = 0;
+ if(p1) {
+ ddocMemAssignData(&mbuf1, (char*)pSigInfo->mbufOrigContent.pMem, -1);
+ ddocMemAppendData(&mbuf1, (char*)sbuf, -1);
+ p1++;
+ //ddocDebug(3, "setSignatureValueFromFile", "add: %s", p1);
+ ddocMemAppendData(&mbuf1, p1, -1);
+ }
+ ddocMemAssignData(&(pSigInfo->mbufOrigContent), (const char*)mbuf1.pMem, mbuf1.nLen);
+ ddocMemBuf_free(&mbuf1);
+ }
+ }
+ else
+ err = ERR_SIGNATURE;
+ fclose(hFile);
+ }
+ else
+ err = ERR_FILE_READ;
+ if (err != ERR_OK) SET_LAST_ERROR(err);
+ return err;
+}
+
+//============================================================
+// Sets the signature value
+// pSigInfo - signature info object
+// szSignature - signature value
+// sigLen - signature length
+//============================================================
+EXP_OPTION int setSignatureValue(SignatureInfo* pSigInfo, byte* szSignature, int sigLen)
+{
+ RETURN_IF_NULL_PARAM(pSigInfo);
+ RETURN_IF_NULL_PARAM(szSignature);
+
+ //clearErrors();
+ // VS: not quite sure if there's not a second constant to use instead of removing the check
+ //RETURN_IF_NOT(sigLen == SIGNATURE_LEN, ERR_SIGNATURE);
+ ddocSignatureValue_new(&(pSigInfo->pSigValue), 0, SIGN_RSA_NAME, szSignature, sigLen);
+ ddocMemBuf_free(&(pSigInfo->mbufOrigContent));
+ return ERR_OK;
+}
+
+
+//=====================< NotaryInfo >======================================
+
+
+//============================================================
+// Returns the number of notary infos
+// pSigDoc - signed doc pointer
+//============================================================
+EXP_OPTION int getCountOfNotaryInfos(const SignedDoc* pSigDoc)
+{
+ int n = 0, i = 0;
+ SignatureInfo* pSigInfo = 0;
+ RETURN_OBJ_IF_NULL(pSigDoc, -1);
+ for(i = 0; i < getCountOfSignatures(pSigDoc); i++) {
+ pSigInfo = getSignature(pSigDoc, i);
+ if(pSigInfo->pNotary)
+ n++;
+ }
+ return n;
+}
+
+//============================================================
+// Returns the next free notary id
+// pSigDoc - signed doc pointer
+//============================================================
+EXP_OPTION int getNextNotaryId(const SignedDoc* pSigDoc)
+{
+ int id = 0, n, i;
+ SignatureInfo* pSigInfo = 0;
+
+ RETURN_OBJ_IF_NULL(pSigDoc, -1);
+ for(i = 0; i < getCountOfSignatures(pSigDoc); i++) {
+ pSigInfo = getSignature(pSigDoc, i);
+ if(pSigInfo->pNotary && pSigInfo->pNotary->szId) {
+ n = atoi(pSigInfo->pNotary->szId+1);
+ if(id <= n)
+ id = n+1;
+ }
+ }
+ return id;
+}
+
+//============================================================
+// Returns the desired NotaryInfo object
+// pSigDoc - signed doc pointer
+// nIdx - NotaryInfo index (starting with 0)
+//============================================================
+EXP_OPTION NotaryInfo* getNotaryInfo(const SignedDoc* pSigDoc, int nIdx)
+{
+ SignatureInfo* pSigInfo = 0;
+ NotaryInfo* pNotInfo = 0;
+ int n = 0, i = 0;
+
+ RETURN_OBJ_IF_NULL(pSigDoc, NULL);
+ for(i = 0; i < getCountOfSignatures(pSigDoc); i++) {
+ pSigInfo = getSignature(pSigDoc, i);
+ if(pSigInfo->pNotary) {
+ n++;
+ if(n == nIdx) {
+ pNotInfo = pSigInfo->pNotary;
+ break;
+ }
+ }
+ }
+ return pNotInfo;
+}
+
+//============================================================
+// Returns the last NotaryInfo object
+// pSigDoc - signed doc pointer
+// nIdx - NotaryInfo index (starting with 0)
+//============================================================
+EXP_OPTION NotaryInfo* ddocGetLastNotaryInfo(const SignedDoc* pSigDoc)
+{
+ SignatureInfo* pSigInfo;
+
+ RETURN_OBJ_IF_NULL(pSigDoc, NULL);
+ pSigInfo = ddocGetLastSignature(pSigDoc);
+ RETURN_OBJ_IF_NULL(pSigInfo, NULL);
+ return pSigInfo->pNotary;
+}
+
+//============================================================
+// Returns the NotaryInfo object with the given id
+// pSigDoc - signed doc pointer
+// id - NotaryInfo id
+//============================================================
+EXP_OPTION NotaryInfo* getNotaryWithId(const SignedDoc* pSigDoc, const char* id)
+{
+ SignatureInfo* pSigInfo = 0;
+ int i = 0;
+
+ RETURN_OBJ_IF_NULL(pSigDoc, NULL);
+ for(i = 0; i < getCountOfSignatures(pSigDoc); i++) {
+ pSigInfo = getSignature(pSigDoc, i);
+ if(pSigInfo->pNotary && pSigInfo->pNotary->szId &&
+ !strcmp(pSigInfo->pNotary->szId, id)) {
+ return pSigInfo->pNotary;
+ }
+ }
+ return NULL;
+}
+
+//============================================================
+// Returns the NotaryInfo object that corresponds to the given signature
+// pSigDoc - signed doc pointer
+// id - NotaryInfo id
+//============================================================
+NotaryInfo* getNotaryWithSigId(const SignedDoc* pSigDoc, const char* sigId)
+{
+ SignatureInfo* pSigInfo = NULL;
+
+ RETURN_OBJ_IF_NULL(pSigDoc, NULL);
+ RETURN_OBJ_IF_NULL(sigId, NULL);
+ pSigInfo = getSignatureWithId(pSigDoc, sigId);
+ RETURN_OBJ_IF_NULL(pSigInfo, NULL);
+ return pSigInfo->pNotary;
+}
+
+//============================================================
+// Returns the NotaryInfo object that corresponds to the given signature
+// ore creates a new one
+// pSigDoc - signed doc pointer
+// id - SignatureInfo id
+//============================================================
+NotaryInfo* getOrCreateNotaryWithSigId(SignedDoc* pSigDoc, const char* sigId)
+{
+ NotaryInfo* pNotary = 0;
+ SignatureInfo* pSigInfo = 0;
+ RETURN_OBJ_IF_NULL(pSigDoc, NULL);
+ RETURN_OBJ_IF_NULL(sigId, NULL);
+ pNotary = getNotaryWithSigId(pSigDoc, sigId);
+ if(!pNotary) {
+ pSigInfo = getSignatureWithId(pSigDoc, sigId);
+ RETURN_OBJ_IF_NULL(pSigInfo, NULL);
+ NotaryInfo_new(&pNotary, pSigDoc, pSigInfo);
+ }
+ return pNotary;
+}
+
+
+//============================================================
+// Adds a new Notary element to a SignedDoc element and
+// initializes it partly
+// pSigInfo - signature object to be verified by this notary
+// return the newly created structure
+//============================================================
+EXP_OPTION int NotaryInfo_new(NotaryInfo **newNotaryInfo, SignedDoc* pSigDoc, SignatureInfo* pSigInfo)
+{
+ int n;
+ char buf[10];
+
+ RETURN_IF_NULL_PARAM(pSigDoc);
+ RETURN_IF_NULL_PARAM(pSigInfo);
+ // get next notary id
+ if (pSigInfo) {
+ strncpy(buf, pSigInfo->szId, sizeof(buf));
+ buf[0] = 'N';
+ // make sure we reset the szOrigContent on this signature
+ // otherwise the new confirmation will not be written to file!
+ ddocMemBuf_free(&(pSigInfo->mbufOrigContent));
+ } else {
+ n = getNextNotaryId(pSigDoc);
+ RETURN_IF_NOT(n >= 0, ERR_BAD_NOTARY_ID);
+ snprintf(buf, sizeof(buf), "N%d", n);
+ }
+ // memory management
+ pSigInfo->pNotary = (NotaryInfo*)malloc(sizeof(NotaryInfo)); // MEMLEAK: ???
+ if (!pSigInfo->pNotary)
+ RETURN_IF_BAD_ALLOC(pSigInfo->pNotary);
+ memset(pSigInfo->pNotary, 0, sizeof(NotaryInfo));
+ // set id
+ setString(&(pSigInfo->pNotary->szId), buf, -1);
+ // version
+ setString(&(pSigInfo->pNotary->szNotType), SK_NOT_VERSION, -1);
+
+ *newNotaryInfo = pSigInfo->pNotary;
+ return ERR_OK;
+}
+
+//============================================================
+// cleanup NotaryInfo memory
+// pNotary - object to be cleaned up
+//============================================================
+EXP_OPTION void NotaryInfo_free(NotaryInfo* pNotary)
+{
+ RETURN_VOID_IF_NULL(pNotary);
+ //assert(pNotary);
+ if(pNotary->szId)
+ free(pNotary->szId);
+ if(pNotary->szNotType)
+ free(pNotary->szNotType);
+ if(pNotary->timeProduced)
+ free(pNotary->timeProduced);
+ if(pNotary->szProducedAt)
+ free(pNotary->szProducedAt);
+ ddocMemBuf_free(&(pNotary->mbufRespId));
+ if(pNotary->szDigestType)
+ free(pNotary->szDigestType);
+ if(pNotary->szSigType)
+ free(pNotary->szSigType);
+ ddocMemBuf_free(&(pNotary->mbufOcspDigest));
+ ddocMemBuf_free(&(pNotary->mbufOcspResponse));
+ // free the object itself
+ free(pNotary);
+}
+
+//============================================================
+// Returns OCSP responders id as in XML document
+// pNotary - Notary info
+// return DigiDocMemBuf buffer pointer or NULL for error
+//============================================================
+EXP_OPTION const DigiDocMemBuf* ddocNotInfo_GetResponderId(const NotaryInfo* pNotary)
+{
+ RETURN_OBJ_IF_NULL(pNotary, NULL);
+ return &(pNotary->mbufRespId);
+}
+
+//============================================================
+// Returns OCSP responders id value as string
+// pNotary - Notary info
+// return responder id value or NULL
+//============================================================
+EXP_OPTION const char* ddocNotInfo_GetResponderId_Value(const NotaryInfo* pNotary)
+{
+ RETURN_OBJ_IF_NULL(pNotary, NULL);
+ return (const char*)pNotary->mbufRespId.pMem;
+}
+
+//============================================================
+// Sets OCSP responders id as in XML document
+// pNotary - Notary info
+// data - new responder id value
+// len - length of value
+// return DigiDocMemBuf buffer pointer or NULL for error
+//============================================================
+int ddocNotInfo_SetResponderId(NotaryInfo* pNotary, const char* data, long len)
+{
+ int err = ERR_OK;
+ RETURN_IF_NULL_PARAM(pNotary);
+ RETURN_IF_NULL_PARAM(data);
+ err = ddocMemAssignData(&(pNotary->mbufRespId), data, len);
+ return err;
+}
+
+//============================================================
+// Returns OCSP response as memory buffer
+// pNotary - Notary info
+// return DigiDocMemBuf buffer pointer or NULL for error
+//============================================================
+const DigiDocMemBuf* ddocNotInfo_GetOCSPResponse(const NotaryInfo* pNotary)
+{
+ RETURN_OBJ_IF_NULL(pNotary, NULL);
+ return &(pNotary->mbufOcspResponse);
+}
+
+//============================================================
+// Retrieves OCSP responses responder id type and value
+// pResp - OCSP response
+// pType - buffer for type
+// pMbufRespId - responder id
+// returns error code or ERR_OK
+//============================================================
+int ddocGetOcspRespIdTypeAndValue(OCSP_RESPONSE* pResp,
+ int *pType, DigiDocMemBuf* pMbufRespId)
+{
+ int err = ERR_OK;
+ OCSP_BASICRESP *br = NULL;
+
+ RETURN_IF_NULL_PARAM(pResp);
+ RETURN_IF_NULL_PARAM(pType);
+ RETURN_IF_NULL_PARAM(pMbufRespId);
+ if((br = OCSP_response_get1_basic(pResp)) == NULL)
+ SET_LAST_ERROR_RETURN_CODE(ERR_OCSP_NO_BASIC_RESP);
+ if(!err && br) {
+ switch(br->tbsResponseData->responderId->type) {
+ case V_OCSP_RESPID_NAME:
+ *pType = RESPID_NAME_TYPE;
+ ddocMemSetLength(pMbufRespId, 300);
+ //X509_NAME_oneline(br->tbsResponseData->responderId->value.byName, (char*)pMbufRespId->pMem, pMbufRespId->nLen);
+ //AM 26.09.08
+ err = ddocCertGetDNFromName(br->tbsResponseData->responderId->value.byName, pMbufRespId);
+ //RETURN_IF_NOT(err == ERR_OK, err);
+ break;
+ case V_OCSP_RESPID_KEY:
+ *pType = RESPID_KEY_TYPE;
+ err = ddocMemAssignData(pMbufRespId,
+ (const char*)br->tbsResponseData->responderId->value.byKey->data,
+ br->tbsResponseData->responderId->value.byKey->length);
+ break;
+ default:
+ SET_LAST_ERROR(ERR_OCSP_WRONG_RESPID);
+ }
+ }
+ if(br)
+ OCSP_BASICRESP_free(br);
+ return err;
+}
+
+//============================================================
+// Sets OCSP respondese value as in XML document. Must pass in
+// binary DER data!
+// pNotary - Notary info
+// data - new responder id value
+// len - length of value
+// return DigiDocMemBuf buffer pointer or NULL for error
+//============================================================
+int ddocNotInfo_SetOCSPResponse(NotaryInfo* pNotary, const char* data, long len)
+{
+ int err = ERR_OK;
+ RETURN_IF_NULL_PARAM(pNotary);
+ RETURN_IF_NULL_PARAM(data);
+ err = ddocMemAssignData(&(pNotary->mbufOcspResponse), data, len);
+ return err;
+}
+
+//============================================================
+// Returns OCSP response value
+// pNotary - Notary info
+// return OCSP_RESPONSE pointer or NULL for error. Caller must
+// use OCSP_RESPONSE_free() to release it.
+//============================================================
+OCSP_RESPONSE* ddocNotInfo_GetOCSPResponse_Value(const NotaryInfo* pNotary)
+{
+ OCSP_RESPONSE* pResp = NULL;
+
+ RETURN_OBJ_IF_NULL(pNotary, NULL);
+ RETURN_OBJ_IF_NULL(pNotary->mbufOcspResponse.pMem, NULL);
+ ddocOcspReadOcspResp(&pResp, (DigiDocMemBuf*)&(pNotary->mbufOcspResponse));
+ return pResp;
+}
+
+//============================================================
+// Sets OCSP respondese value. Must pass in real OCSP_RESPONSE
+// pNotary - Notary info
+// data - new responder id value
+// len - length of value
+// return DigiDocMemBuf buffer pointer or NULL for error
+//============================================================
+int ddocNotInfo_SetOCSPResponse_Value(NotaryInfo* pNotary, OCSP_RESPONSE* pResp)
+{
+ int err = ERR_OK;
+ RETURN_IF_NULL_PARAM(pNotary);
+ RETURN_IF_NULL_PARAM(pResp);
+ err = ddocOcspWriteOcspResp(pResp, (DigiDocMemBuf*)&(pNotary->mbufOcspResponse));
+ return err;
+}
+
+//============================================================
+// Helper function to get OCSP response parts
+// pNotary - notary object
+// ppResp - adr for OCSP_RESPONSE - must free!
+// ppBasResp - adr for OCSP_BASICRESP - don't free
+// ppSingle - optional adr for OCSP_SINGLERESP - don't free
+//============================================================
+int ddocNotInfo_GetBasicResp(const NotaryInfo* pNotary, OCSP_RESPONSE **ppResp,
+ OCSP_BASICRESP **ppBasResp, OCSP_SINGLERESP **ppSingle)
+{
+ int err = ERR_OK;
+
+ // check input
+ RETURN_IF_NULL_PARAM(pNotary);
+ RETURN_IF_NULL_PARAM(ppResp);
+ RETURN_IF_NULL_PARAM(ppBasResp);
+ // single response retrieval is optional - don't check it
+ *ppResp = ddocNotInfo_GetOCSPResponse_Value(pNotary);
+ if(*ppResp && ppBasResp) {
+ *ppBasResp = OCSP_response_get1_basic(*ppResp);
+ if(*ppBasResp) {
+ if(ppSingle)
+ *ppSingle = sk_OCSP_SINGLERESP_value((*ppBasResp)->tbsResponseData->responses, 0);
+ }
+ else
+ return ERR_OCSP_NO_BASIC_RESP;
+ }
+ return err;
+}
+
+//============================================================
+// Returns OCSP responders id type as string
+// pNotary - Notary info
+// return responder id type or NULL. DO NOT free() it!
+//============================================================
+EXP_OPTION const char* ddocNotInfo_GetResponderId_Type(const NotaryInfo* pNotary)
+{
+ int err = ERR_OK;
+ OCSP_RESPONSE *pResp = 0;
+ OCSP_BASICRESP *br = NULL;
+ char *p1 = RESPID_NAME_VALUE; // default value is name - usefull in format 1.0 where we had no good OCSP response
+
+ RETURN_OBJ_IF_NULL(pNotary, NULL);
+ err = ddocNotInfo_GetBasicResp(pNotary, &pResp, &br, NULL);
+ if(!err && br) {
+ switch(br->tbsResponseData->responderId->type) {
+ case V_OCSP_RESPID_NAME: p1 = RESPID_NAME_VALUE; break;
+ case V_OCSP_RESPID_KEY: p1 = RESPID_KEY_VALUE; break;
+ default:
+ SET_LAST_ERROR(ERR_OCSP_WRONG_RESPID);
+ }
+ }
+ if(pResp)
+ OCSP_RESPONSE_free(pResp);
+ // PR. leak found
+ if(br)
+ OCSP_BASICRESP_free(br);
+ return p1;
+}
+
+//============================================================
+// Returns OCSP responses thisUpdate atribute as string
+// pNotary - Notary info
+// pMBuf - buffer for thisUpdate value
+// return error code OR ERR_OK.
+//============================================================
+EXP_OPTION int ddocNotInfo_GetThisUpdate(const NotaryInfo* pNotary, DigiDocMemBuf* pMBuf)
+{
+ int err = ERR_OK;
+ OCSP_RESPONSE *pResp = 0;
+ OCSP_BASICRESP *br = NULL;
+ OCSP_SINGLERESP *single = NULL;
+
+ RETURN_IF_NULL_PARAM(pNotary);
+ RETURN_IF_NULL_PARAM(pMBuf);
+ err = ddocNotInfo_GetBasicResp(pNotary, &pResp, &br, &single);
+ if(!err && br && single) {
+ err = ddocMemSetLength(pMBuf, 50);
+ ddocDebug(3, "ddocNotInfo_GetThisUpdate", "This update: %s", single->thisUpdate);
+ if(!err && single->thisUpdate)
+ err = asn1time2str(NULL, single->thisUpdate, (char*)pMBuf->pMem, pMBuf->nLen);
+ }
+ if(pResp)
+ OCSP_RESPONSE_free(pResp);
+ // PR. leak found
+ if(br)
+ OCSP_BASICRESP_free(br);
+ return err;
+}
+
+
+//============================================================
+// Returns OCSP responses thisUpdate atribute as time_t
+// pNotary - Notary info
+// pTime - address of time_t variable
+// return error code OR ERR_OK.
+//============================================================
+int ddocNotInfo_GetThisUpdate_timet(const NotaryInfo* pNotary, time_t* pTime)
+{
+ int err = ERR_OK;
+ OCSP_RESPONSE *pResp = 0;
+ OCSP_BASICRESP *br = NULL;
+ OCSP_SINGLERESP *single = NULL;
+
+ RETURN_IF_NULL_PARAM(pNotary);
+ RETURN_IF_NULL_PARAM(pTime);
+ err = ddocNotInfo_GetBasicResp(pNotary, &pResp, &br, &single);
+ if(!err && br && single) {
+ if(!err && single->thisUpdate)
+ err = asn1time2time_t_local(single->thisUpdate, pTime);
+ }
+ if(pResp)
+ OCSP_RESPONSE_free(pResp);
+ // PR. leak found
+ if(br)
+ OCSP_BASICRESP_free(br);
+ return err;
+}
+
+//============================================================
+// Returns OCSP responses producedAt atribute as time_t
+// pNotary - Notary info
+// pTime - address of time_t variable
+// return error code OR ERR_OK.
+//============================================================
+int ddocNotInfo_GetProducedAt_timet(const NotaryInfo* pNotary, time_t* pTime)
+{
+ int err = ERR_OK;
+ OCSP_RESPONSE *pResp = 0;
+ OCSP_BASICRESP *br = NULL;
+
+
+ RETURN_IF_NULL_PARAM(pNotary);
+ RETURN_IF_NULL_PARAM(pTime);
+ err = ddocNotInfo_GetBasicResp(pNotary, &pResp, &br, NULL);
+ if(!err && br && br->tbsResponseData && br->tbsResponseData->producedAt) {
+ err = asn1time2time_t_local(br->tbsResponseData->producedAt, pTime);
+ }
+ //AM 22.06.08 lets free br too
+ if(br)
+ OCSP_BASICRESP_free(br);
+ if(pResp)
+ OCSP_RESPONSE_free(pResp);
+ return err;
+}
+
+//============================================================
+// Returns OCSP responses producedAt from xml as time_t
+// pNotary - Notary info
+// pTime - address of time_t variable
+// return error code OR ERR_OK.
+//============================================================
+int ddocNotInfo_GetProducedAtXml_timet(const NotaryInfo* pNotary, time_t* pTime)
+{
+ int err = ERR_OK;
+
+ RETURN_IF_NULL_PARAM(pNotary);
+ RETURN_IF_NULL_PARAM(pTime);
+ if(!err && pNotary->szProducedAt) {
+ err = str2time_t(pNotary->szProducedAt, pTime);
+ }
+ return err;
+}
+
+//============================================================
+// Returns OCSP responses nextUpdate atribute as string
+// pNotary - Notary info
+// pMBuf - buffer for nextUpdate value
+// return error code OR ERR_OK.
+//============================================================
+EXP_OPTION int ddocNotInfo_GetNextUpdate(const NotaryInfo* pNotary, DigiDocMemBuf* pMBuf)
+{
+ int err = ERR_OK;
+ OCSP_RESPONSE *pResp = 0;
+ OCSP_BASICRESP *br = NULL;
+ OCSP_SINGLERESP *single = NULL;
+
+ RETURN_IF_NULL_PARAM(pNotary);
+ RETURN_IF_NULL_PARAM(pMBuf);
+ err = ddocNotInfo_GetBasicResp(pNotary, &pResp, &br, &single);
+ if(!err && br && single) {
+ err = ddocMemSetLength(pMBuf, 50);
+ if(!err && single->nextUpdate)
+ err = asn1time2str(NULL, single->nextUpdate, (char*)pMBuf->pMem, pMBuf->nLen);
+ }
+ if(pResp)
+ OCSP_RESPONSE_free(pResp);
+ // PR. leak found
+ if(br)
+ OCSP_BASICRESP_free(br);
+ return err;
+}
+
+//============================================================
+// Returns OCSP responses IssuerNameHash atribute
+// pNotary - Notary info
+// pMBuf - buffer for IssuerNameHash value
+// return error code OR ERR_OK.
+//============================================================
+int ddocNotInfo_GetIssuerNameHash(const NotaryInfo* pNotary, DigiDocMemBuf* pMBuf)
+{
+ int err = ERR_OK;
+ OCSP_RESPONSE *pResp = 0;
+ OCSP_BASICRESP *br = NULL;
+ OCSP_SINGLERESP *single = NULL;
+
+ RETURN_IF_NULL_PARAM(pNotary);
+ RETURN_IF_NULL_PARAM(pMBuf);
+ err = ddocNotInfo_GetBasicResp(pNotary, &pResp, &br, &single);
+ if(!err && br && single->certId) {
+ err = ddocMemAssignData(pMBuf, (const char*)single->certId->issuerNameHash->data,
+ single->certId->issuerNameHash->length);
+ }
+ if(pResp)
+ OCSP_RESPONSE_free(pResp);
+ // PR. leak found
+ if(br)
+ OCSP_BASICRESP_free(br);
+ return err;
+}
+
+//============================================================
+// Returns OCSP responses IssuerKeyHash atribute
+// pNotary - Notary info
+// pMBuf - buffer for IssuerKeyHash value
+// return error code OR ERR_OK.
+//============================================================
+int ddocNotInfo_GetIssuerKeyHash(const NotaryInfo* pNotary, DigiDocMemBuf* pMBuf)
+{
+ int err = ERR_OK;
+ OCSP_RESPONSE *pResp = 0;
+ OCSP_BASICRESP *br = NULL;
+ OCSP_SINGLERESP *single = NULL;
+
+ RETURN_IF_NULL_PARAM(pNotary);
+ RETURN_IF_NULL_PARAM(pMBuf);
+ err = ddocNotInfo_GetBasicResp(pNotary, &pResp, &br, &single);
+ if(!err && br && single->certId) {
+ err = ddocMemAssignData(pMBuf, (const char*)single->certId->issuerKeyHash->data,
+ single->certId->issuerKeyHash->length);
+ }
+ if(pResp)
+ OCSP_RESPONSE_free(pResp);
+ // PR. leak found
+ if(br)
+ OCSP_BASICRESP_free(br);
+ return err;
+}
+
+//============================================================
+// Returns OCSP responses real digest from response data
+// pNotary - Notary info
+// pMBuf - buffer for digest value
+// return error code OR ERR_OK.
+//============================================================
+int ddocNotInfo_GetOcspRealDigest(const SignedDoc* pSigDoc, const NotaryInfo* pNotary, DigiDocMemBuf* pMBuf)
+{
+ int err = ERR_OK, nIdx = 0, l1 = 0, l2 = 0, nCheckOcspLen = 0;
+ OCSP_RESPONSE *pResp = 0;
+ OCSP_BASICRESP *br = NULL;
+ OCSP_SINGLERESP *single = NULL;
+ X509_EXTENSION *ext = NULL;
+ byte* p = 0, buf2[DIGEST_LEN256 * 2 + 2];
+
+ RETURN_IF_NULL_PARAM(pNotary);
+ RETURN_IF_NULL_PARAM(pMBuf);
+ err = ddocNotInfo_GetBasicResp(pNotary, &pResp, &br, &single);
+ nCheckOcspLen = ConfigItem_lookup_bool("CHECK_OCSP_NONCE", 0);
+ if(!err && br) {
+ nIdx = OCSP_BASICRESP_get_ext_by_NID(br, NID_id_pkix_OCSP_Nonce, -1);
+ if(nIdx >= 0) {
+ ext = OCSP_BASICRESP_get_ext(br, nIdx);
+ if(ext != NULL) {
+ int l1 = ASN1_STRING_length(ext->value);
+ p = ASN1_STRING_data(ext->value);
+ if(l1 > 20 && p[0] == V_ASN1_OCTET_STRING && p[1] == l1-2)
+ err = ddocMemAssignData(pMBuf, (const char*)p+2, l1-2);
+ else
+ err = ddocMemAssignData(pMBuf, (const char*)p, l1);
+ // debug
+ l2 = sizeof(buf2);
+ memset(buf2, 0, l2);
+ if(l1 <= DIGEST_LEN256) {
+ bin2hex((const byte*)p, l1, (byte*)buf2, &l2);
+ ddocDebug(3, "ddocNotInfo_GetOcspRealDigest", "Not: %s nonce: %s len: %d err: %d",
+ pNotary->szId, buf2, l1, err);
+ }
+ if(l1 != 22 && nCheckOcspLen && pSigDoc && strcmp(pSigDoc->szFormat, SK_XML_1_NAME)) {
+ ddocDebug(1, "ddocNotInfo_GetOcspRealDigest", "Not: %s invalid nonce: %s len: %d err: %d",
+ pNotary->szId, buf2, l1, err);
+ err = ERR_OCSP_NONCE_INVALID;
+ }
+ }
+ }
+ else
+ err = ERR_OCSP_NO_NONCE;
+ }
+ if(pResp)
+ OCSP_RESPONSE_free(pResp);
+ if(br)
+ OCSP_BASICRESP_free(br);
+ return err;
+}
+
+//============================================================
+// Returns OCSP responses signature value
+// pNotary - Notary info
+// pMBuf - buffer for signature value
+// return error code OR ERR_OK.
+//============================================================
+int ddocNotInfo_GetOcspSignatureValue(const NotaryInfo* pNotary, DigiDocMemBuf* pMBuf)
+{
+ int err = ERR_OK;
+ OCSP_RESPONSE *pResp = 0;
+ OCSP_BASICRESP *br = NULL;
+
+ RETURN_IF_NULL_PARAM(pNotary);
+ RETURN_IF_NULL_PARAM(pMBuf);
+ err = ddocNotInfo_GetBasicResp(pNotary, &pResp, &br, NULL);
+ if(!err && br) {
+ err = ddocMemAssignData(pMBuf, (const char*)br->signature->data,
+ br->signature->length);
+ }
+ if(pResp)
+ OCSP_RESPONSE_free(pResp);
+ // PR. leak found
+ if(br)
+ OCSP_BASICRESP_free(br);
+ return err;
+}
+
+//============================================================
+// Returns OCSP response digest as in XML document
+// pNotary - Notary info
+// return DigiDocMemBuf buffer pointer or NULL for error
+//============================================================
+EXP_OPTION const DigiDocMemBuf* ddocNotInfo_GetOcspDigest(const NotaryInfo* pNotary)
+{
+ RETURN_OBJ_IF_NULL(pNotary, NULL);
+ return &(pNotary->mbufOcspDigest);
+}
+
+//============================================================
+// Sets OCSP response digest id as in XML document
+// pNotary - Notary info
+// data - new digest value
+// len - length of value
+// return DigiDocMemBuf buffer pointer or NULL for error
+//============================================================
+int ddocNotInfo_SetOcspDigest(NotaryInfo* pNotary, const char* data, long len)
+{
+ int err = ERR_OK;
+ RETURN_IF_NULL_PARAM(pNotary);
+ RETURN_IF_NULL_PARAM(data);
+ err = ddocMemAssignData(&(pNotary->mbufOcspDigest), data, len);
+ return err;
+}
+
+
+
+//============================================================
+// Adds a certificate to Notary and initializes Notary
+// pNotary - Notary info
+// cert - responders certificate
+// return error code
+//============================================================
+int addNotaryInfoCert(SignedDoc *pSigDoc, NotaryInfo *pNotary, X509 *cert)
+{
+ int err = ERR_OK, n;
+ char buf[300];
+ CertID* pCertID = 0;
+ SignatureInfo* pSigInfo = 0;
+ DigiDocMemBuf mbuf1;
+
+ mbuf1.pMem = 0;
+ mbuf1.nLen = 0;
+ ddocDebug(3, "addNotaryInfoCert", "adding cert: %s to notary: %s", (cert ? "OK" : "NULL"), pNotary->szId);
+ RETURN_IF_NULL_PARAM(pNotary);
+ pSigInfo = ddocGetSignatureForNotary(pSigDoc, pNotary);
+ RETURN_IF_NULL_PARAM(pSigInfo);
+ RETURN_IF_NULL_PARAM(cert);
+ RETURN_IF_NOT(err == ERR_OK, err);
+ if(!ddocSigInfo_GetOCSPRespondersCert(pSigInfo))
+ err = ddocSigInfo_SetOCSPRespondersCert(pSigInfo, cert);
+ buf[0] = 0;
+ err = ReadCertSerialNumber(buf, sizeof(buf), cert);
+ if(strlen(buf)){
+ pCertID = ddocCertIDList_GetCertIDOfSerial(pSigInfo->pCertIDs, buf);
+ }
+ if(!pCertID)
+ pCertID = ddocSigInfo_GetOrCreateCertIDOfType(pSigInfo, CERTID_TYPE_RESPONDERS_CERTID);
+ else //AM quick fix for smartlink bdoc
+ if(pCertID->nType==0)pCertID->nType = CERTID_TYPE_RESPONDERS_CERTID;
+ RETURN_IF_NULL(pCertID);
+ ddocCertID_SetIssuerSerial(pCertID, buf);
+ n = sizeof(buf);
+ memset(buf, 0, sizeof(buf));
+ n = 40;
+ RETURN_IF_NOT(X509_digest(cert, EVP_sha1(), (unsigned char*)buf, (unsigned int*)&n), ERR_X509_DIGEST);
+ if(!pCertID->pDigestValue)
+ ddocCertID_SetDigestValue(pCertID, (const char*)buf, n);
+ ddocCertGetSubjectDN(cert, &mbuf1);
+ ddocCertID_SetIssuerName(pCertID, (char*)mbuf1.pMem);
+ ddocMemBuf_free(&mbuf1);
+ snprintf(buf, sizeof(buf), "%s-RESPONDER_CERTINFO", pSigInfo->szId);
+ ddocCertID_SetId(pCertID, buf);
+ ddocDebug(4, "addNotaryInfoCert", "cert: %s to notary: %s", (cert ? "OK" : "NULL"), pNotary->szId, err);
+ return err;
+}
+
+
+//============================================================
+// Removes Notary cert value and id after unsucessful verification attempt
+// pSigInfo - signature info [REQUIRED]
+// return error code
+//============================================================
+int removeNotaryInfoCert(SignatureInfo* pSigInfo)
+{
+ CertID* pCertID;
+ CertValue* pCertVal;
+ int i;
+
+ RETURN_IF_NULL_PARAM(pSigInfo);
+ // remove cert values of type responder
+ for(i = 0; i < ddocCertValueList_GetCertValuesCount(pSigInfo->pCertValues); i++) {
+ pCertVal = ddocCertValueList_GetCertValue(pSigInfo->pCertValues, i);
+ if(pCertVal && pCertVal->nType == CERTID_VALUE_RESPONDERS_CERT)
+ ddocCertValueList_DeleteCertValue(pSigInfo->pCertValues, i);
+ }
+ // remove cert ids of type responder
+ for(i = 0; i < ddocCertIDList_GetCertIDsCount(pSigInfo->pCertIDs); i++) {
+ pCertID = ddocCertIDList_GetCertID(pSigInfo->pCertIDs, i);
+ if(pCertID && pCertID->nType == CERTID_TYPE_RESPONDERS_CERTID)
+ ddocCertIDList_DeleteCertID(pSigInfo->pCertIDs, i);
+ }
+ return ERR_OK;
+}
+
+//============================================================
+// Adds a new Notary SignedInfo element to a SignedDoc
+// element and initializes it
+// newNotaryInfo - newly created structure
+// pSigDoc - signed doc data
+// pSigInfo - signature object to be verified by this notary
+// ocspRespFile - OCSP response file name
+// notaryCertFile - Notary cert file name
+// returns error code or ERR_OK if no error.
+//============================================================
+// FIXME : What to do if initializeNotaryInfoWithOCSP fails?
+EXP_OPTION int NotaryInfo_new_file(NotaryInfo **newNotaryInfo, SignedDoc *pSigDoc,
+ const SignatureInfo *pSigInfo, const char *ocspRespFile,
+ const char *notaryCertFile)
+
+{
+ OCSP_RESPONSE* resp;
+ X509* notCert;
+ NotaryInfo* pNotInf = NULL;
+ int err = ERR_OK;
+
+ RETURN_IF_NULL_PARAM(pSigDoc);
+ RETURN_IF_NULL_PARAM(pSigInfo);
+ RETURN_IF_NULL_PARAM(ocspRespFile);
+ RETURN_IF_NULL_PARAM(notaryCertFile);
+ err = ReadOCSPResponse(&resp, ocspRespFile);
+ RETURN_IF_NOT(err == ERR_OK, ERR_FILE_READ);
+ err = ReadCertificate(&notCert, notaryCertFile);
+ RETURN_IF_NOT(err == ERR_OK, ERR_CERT_READ);
+ err = NotaryInfo_new(&pNotInf, pSigDoc, (SignatureInfo*)pSigInfo);
+ RETURN_IF_NOT(err == ERR_OK, err);
+ *newNotaryInfo = pNotInf;
+ err = initializeNotaryInfoWithOCSP(pSigDoc, pNotInf, resp, notCert, 1);
+ RETURN_IF_NOT(err == ERR_OK, err);
+ return ERR_OK;
+}
+
+// forward deklaratsioon
+int notary2ocspBasResp(const SignedDoc* pSigDoc, const NotaryInfo* pNotInfo, X509* notCert, OCSP_BASICRESP** pBasResp);
+int calculateOcspBasicResponseDigest(OCSP_BASICRESP* pBsResp, byte* digBuf, int* digLen);
+
+//============================================================
+// Calculates the digest of NotaryInfo
+// pSigDoc - signed document pointer
+// pNotInfo - notary signature info
+// digBuf - signature buffer
+// digLen - signature buffer length
+// returns error code
+//============================================================
+EXP_OPTION int calculateNotaryInfoDigest(const SignedDoc* pSigDoc,
+ const NotaryInfo* pNotInfo, byte* digBuf, int* digLen)
+{
+ SignatureInfo* pSigInfo;
+ int err = ERR_OK;
+ const DigiDocMemBuf *pMBuf = 0;
+
+ pMBuf = ddocNotInfo_GetOCSPResponse(pNotInfo);
+ RETURN_IF_NULL(pMBuf);
+ pSigInfo = ddocGetSignatureForNotary(pSigDoc, pNotInfo);
+ RETURN_IF_NULL_PARAM(pSigInfo);
+ if(!strcmp(pNotInfo->szDigestType,DIGEST_SHA256_NAME))
+ err = calculateDigest((const byte*)pMBuf->pMem, pMBuf->nLen, DIGEST_SHA256, digBuf, digLen);
+ else
+ err = calculateDigest((const byte*)pMBuf->pMem, pMBuf->nLen, DIGEST_SHA1, digBuf, digLen);
+ if (err != ERR_OK) SET_LAST_ERROR(err);
+ return err;
+}
+
+//AM 12.03.08
+//--------------------------------------------------
+// Sets the CA Responders certificate
+// pSigInfo - signature info object [REQUIRED]
+// pCert - certificate [REQUIRED]
+// returns error code or ERR_OK
+//--------------------------------------------------
+EXP_OPTION int ddocSigInfo_SetCACert(SignatureInfo* pSigInfo, X509* pCert)
+{
+ int err = ERR_OK;
+ CertValue *pCertValue = 0;
+ char buf1[50];
+
+ RETURN_IF_NULL_PARAM(pSigInfo);
+ RETURN_IF_NULL_PARAM(pCert);
+ pCertValue = ddocSigInfo_GetOrCreateCertValueOfType(pSigInfo, CERTID_VALUE_CA_CERT);
+ if(pCertValue) {
+ snprintf(buf1, sizeof(buf1), "%s-CA_CERT", pSigInfo->szId);
+ err = ddocCertValue_SetId(pCertValue, buf1);
+ if(!err)
+ err = ddocCertValue_SetCert(pCertValue, pCert);
+ }
+ return err;
+}
+
+//============================================================
+// Calculates and stores a signature for this SignatureInfo object
+// Uses PKCS#12 file to sign the info
+// pSigInfo - signature info object
+// nSigType - signature type code
+// szPkcs12File - PKCS#12 file
+// passwd - key password
+//============================================================
+EXP_OPTION int calculateSignatureWithPkcs12(SignedDoc* pSigDoc, SignatureInfo* pSigInfo,
+ const char* szPkcs12File, const char* passwd)
+{
+ int err = ERR_OK;
+ int sigLen;
+ char sigDig[100];
+ char signature[256];
+ char* buf1;
+ int l2;
+ EVP_PKEY *pkey = 0;
+ X509* x509 = 0;
+ EVP_MD_CTX ctx;
+ DigiDocMemBuf mbuf1;
+
+ RETURN_IF_NULL_PARAM(pSigInfo);
+ RETURN_IF_NULL_PARAM(pSigDoc);
+ RETURN_IF_NULL_PARAM(szPkcs12File);
+ ddocDebug(3, "calculateSignatureWithPkcs12", "Keystore: %s passwd-len: %d",
+ szPkcs12File, (passwd ? strlen(passwd) : 0));
+ // read pkcs12 file
+ err = ReadCertificateByPKCS12(&x509, szPkcs12File, passwd, &pkey);
+ RETURN_IF_NOT(err == ERR_OK, err);
+ // try key-usage check
+ if(ConfigItem_lookup_int("KEY_USAGE_CHECK", 1) && x509) {
+ if(!ddocCertCheckKeyUsage(x509, KUIDX_NON_REPUDIATION)) {
+ X509_free(x509);
+ EVP_PKEY_free(pkey);
+ SET_LAST_ERROR(ERR_SIGNERS_CERT_NON_REPU);
+ return ERR_SIGNERS_CERT_NON_REPU;
+ }
+ }
+ // set signers cert
+ setSignatureCert(pSigInfo, x509);
+ // create signing timestamp
+ createTimestamp(pSigDoc, (char*)sigDig, sizeof(sigDig));
+ setString((char**)&(pSigInfo->szTimeStamp), (const char*)sigDig, -1);
+ // Signed properties digest
+ buf1 = createXMLSignedProperties(pSigDoc, pSigInfo, 0);
+ mbuf1.pMem = canonicalizeXML((char*)buf1, strlen(buf1));
+ mbuf1.nLen = strlen((const char*)mbuf1.pMem);
+ ddocDebugWriteFile(4, "sigprop-signed.txt", &mbuf1);
+ l2 = sizeof(sigDig);
+ err = calculateDigest((const byte*)mbuf1.pMem, mbuf1.nLen, DIGEST_SHA1, sigDig, &l2);
+ free(buf1);
+ ddocMemBuf_free(&mbuf1);
+ if (err != ERR_OK) {
+ SET_LAST_ERROR(err);
+ return err;
+ }
+ ddocSigInfo_SetSigPropDigest(pSigInfo, (const char*)sigDig, l2);
+ ddocSigInfo_SetSigPropRealDigest(pSigInfo, (const char*)sigDig, l2);
+ // create signed info
+ buf1 = createXMLSignedInfo(pSigDoc, pSigInfo);
+ if (!buf1) {
+ err = ERR_NULL_POINTER;
+ SET_LAST_ERROR(err);
+ return err ;
+ }
+ mbuf1.pMem = buf1; //canonicalizeXML((char*)buf1, strlen(buf1));
+ mbuf1.nLen = strlen((const char*)mbuf1.pMem);
+ //ddocDebugWriteFile(4, "siginf-signed.txt", &mbuf1);
+ // get digest
+ l2 = sizeof(sigDig);
+ err = calculateDigest((const byte*)buf1, strlen(buf1), DIGEST_SHA1, (byte*)sigDig, &l2);
+ // debug
+ sigLen = sizeof(signature);
+ bin2hex((const byte*)sigDig, l2, (char*)signature, &sigLen);
+ sigLen = sizeof(signature);
+ encode((const byte*)sigDig, l2, (char*)signature, &sigLen);
+ ddocDebug(3, "calculateSignatureWithPkcs12", "Sig-inf hash b64: %s", signature);
+ if (err != ERR_OK) {
+ err = ERR_NULL_POINTER;
+ SET_LAST_ERROR(err);
+ return err;
+ }
+ ddocSigInfo_SetSigInfoRealDigest(pSigInfo, (const char*)sigDig, l2);
+ // sign data
+ sigLen = sizeof(signature);
+ memset(signature, 0, sizeof(signature));
+ // sign data
+ EVP_SignInit(&ctx, EVP_sha1());
+ EVP_SignUpdate(&ctx, buf1, (unsigned long)strlen(buf1));
+ err = EVP_SignFinal(&ctx, signature, &sigLen, pkey);
+ free(buf1);
+ if(err == ERR_LIB_NONE)
+ err = ERR_OK;
+ // set signature value
+ ddocSigInfo_SetSignatureValue(pSigInfo, (const char*)signature, (int)sigLen);
+ ddocDebug(3, "calculateSignatureWithPkcs12", "Sig-len: %ld", sigLen);
+ //X509_free(x509);
+ EVP_PKEY_free(pkey);
+
+ return err;
+}
+
+
diff --git a/libdigidoc/DigiDocObj.h b/libdigidoc/DigiDocObj.h
new file mode 100644
index 0000000..4236901
--- /dev/null
+++ b/libdigidoc/DigiDocObj.h
@@ -0,0 +1,1291 @@
+#ifndef __DIGIDOC_OBJ_H__
+#define __DIGIDOC_OBJ_H__
+//==================================================
+// FILE: DigiDocGen.h
+// PROJECT: Digi Doc
+// DESCRIPTION: DigiDoc helper routines for accessing dogidoc data
+// AUTHOR: Veiko Sinivee, S|E|B IT Partner Estonia
+//==================================================
+// Copyright (C) AS Sertifitseerimiskeskus
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+// GNU Lesser General Public Licence is available at
+// http://www.gnu.org/copyleft/lesser.html
+//==========< HISTORY >=============================
+// 26.04.2006 Veiko Sinivee
+// Creation
+//==================================================
+
+#include "DigiDocDefs.h"
+#include "DigiDocMem.h"
+#include <openssl/x509.h>
+#include <openssl/ocsp.h>
+
+//==========< DigiDoc object structure >========================
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+// contains the signed attributes of each document file entry
+typedef struct DocInfo_st {
+ char* szDocId; // document id
+ char* szDigestType; // digest method used
+ byte* szDigest; // digest value
+ int nDigestLen; // digest value length
+ byte* szMimeDigest; // digest value
+ int nMimeDigestLen; // digest value length
+} DocInfo;
+
+typedef struct SignatureProductionPlace_st {
+ char* szCity;
+ char* szStateOrProvince;
+ char* szPostalCode;
+ char* szCountryName;
+} SignatureProductionPlace;
+
+typedef struct SignerRole_st {
+ int nClaimedRoles;
+ char** pClaimedRoles;
+ int nCertifiedRoles;
+ char** pCertifiedRoles;
+} SignerRole;
+
+typedef struct DigestValue_st {
+ char* szDigestMethod;
+ DigiDocMemBuf mbufDigestValue;
+} DigestValue;
+ /*
+typedef struct ReferenceInfo_st {
+ char* szId;
+ char* szUri;
+ char* szType;
+ DigestValue digestValue;
+} ReferenceInfo;
+ */
+typedef struct SignatureValue_st {
+ char* szId;
+ char* szType;
+ DigiDocMemBuf mbufSignatureValue;
+} SignatureValue;
+
+#define CERTID_TYPE_UNKNOWN 0
+#define CERTID_TYPE_SIGNERS_CERTID 1
+#define CERTID_TYPE_RESPONDERS_CERTID 2
+#define CERTID_TYPE_TSA_CERTID 3
+//AM 12.03.08
+#define CERTID_VALUE_CA_CERT 4
+
+
+typedef struct CertID_st {
+ int nType; // internal CertID type:
+ char* szId;
+ char* szIssuerSerial;
+ char* szIssuerName;
+ DigestValue* pDigestValue;
+ //AM 24.04.08
+ char* szDigestType; // digest method used
+} CertID;
+
+typedef struct CertIDList_st {
+ int nCertIDs;
+ CertID** pCertIDs;
+} CertIDList;
+
+#define CERTID_VALUE_UNKNOWN 0
+#define CERTID_VALUE_SIGNERS_CERT 1
+#define CERTID_VALUE_RESPONDERS_CERT 2
+#define CERTID_VALUE_TSA_CERT 3
+//AM 12.03.08
+#define CERTID_TYPE_CA_CERTID 4
+#define ERR_VER_1_0 300
+
+typedef struct CertValue_st {
+ int nType;
+ char* szId;
+ X509* pCert;
+} CertValue;
+
+typedef struct CertValueList_st {
+ int nCertValues;
+ CertValue** pCertValues;
+} CertValueList;
+
+// data file entry for each data file
+typedef struct DataFile_st {
+ char* szId; // data file id
+ char* szFileName; // signed doc file name
+ char* szMimeType; // date file mime type
+ char* szContentType; // EMBEDDED or EMBEDDED_BASE64
+ long nSize; // file size (unencoded)
+ char* szDigestType; // digest type
+ DigiDocMemBuf mbufDigest; // real DataFile digest value
+ DigiDocMemBuf mbufWrongDigest; // bad digest calculated in some versions
+ DigiDocMemBuf mbufDetachedDigest; // detached file digest
+ int nAttributes; // number of other attributes
+ char* szCharset; // datafile initial codepage
+ char** pAttNames; // other attribute names
+ char** pAttValues; // other attribute values
+ DigiDocMemBuf mbufContent;
+} DataFile;
+
+typedef struct NotaryInfo_sk {
+ char* szId; // Notary id
+ char* szNotType; // notary info type (OCSP-1.0)
+ char* timeProduced; // producedAt
+ char* szProducedAt; // producedAt in xml
+ int nRespIdType; // RESP_ID_NAME, RESP_ID_KEY
+ DigiDocMemBuf mbufRespId; // responder id value
+ char* szDigestType; // digest method used
+ // notaries personal signature
+ char* szSigType; // signature type used
+ DigiDocMemBuf mbufOcspDigest; // OCSP response digest (as in XML
+ DigiDocMemBuf mbufOcspResponse; // OCSP response (in memory held in DER)
+} NotaryInfo;
+
+// signature info for each user signature
+typedef struct SignatureInfo_st {
+ char* szId; // signature id
+ int nDocs; // number of separate documents signed
+ DocInfo** pDocs; // info for each signed document
+ char* szTimeStamp; // signature timestamp in format "YYYY-MM-DDTHH:MM:SSZ"
+ DigestValue *pSigPropDigest;
+ DigestValue *pSigPropRealDigest;
+ DigestValue *pSigInfoRealDigest;
+ SignatureValue *pSigValue; // RSA+SHA1 signature value
+ X509* pX509Cert; // X509Cert certificate (used internally for data during loading)
+ SignatureProductionPlace sigProdPlace;
+ SignerRole signerRole;
+ DigiDocMemBuf mbufOrigContent;
+ NotaryInfo* pNotary;
+ CertIDList *pCertIDs;
+ CertValueList *pCertValues;
+ //AM 24.04.08
+ char* szDigestType; // digest method used
+ int nErr1; // possible parse error codes, need many?
+} SignatureInfo;
+
+
+
+typedef struct SignedDoc_st {
+ char* szFormat; // data format name
+ char* szFormatVer; // data format version
+ int nDataFiles;
+ DataFile** pDataFiles;
+ int nSignatures;
+ SignatureInfo** pSignatures;
+ //AM 14.03.08
+ char* szFileName;
+ //AM 13.05.08
+ char* szProfile;
+} SignedDoc;
+
+//============================================================
+// Sets a string element of a struct to a new value
+// dest - element pointer
+// value - new value
+// valLen - value length (use -1 for null terminated strings)
+//============================================================
+EXP_OPTION int setString(char** dest, const char* value, int valLen);
+
+// creates a new <SignedDoc> structure
+EXP_OPTION int SignedDoc_new(SignedDoc **newSignedDoc, const char* format, const char* version);
+// cleanup signed doc data
+EXP_OPTION void SignedDoc_free(SignedDoc* pSigDoc);
+
+//======================< DataFile functions >=============================
+
+// returns the number of data files
+EXP_OPTION int getCountOfDataFiles(const SignedDoc* pSigDoc);
+// returns the n-th DataFile object
+EXP_OPTION DataFile* getDataFile(const SignedDoc* pSigDoc, int nIdx);
+// returns the last DataFile object
+EXP_OPTION DataFile* ddocGetLastDataFile(const SignedDoc* pSigDoc);
+// Retrieve and convert DataFile Filename atribute and convert
+EXP_OPTION int ddocGetDataFileFilename(SignedDoc* pSigDoc, const char* szDocId, void** ppBuf, int* pLen);
+// returns the DataFile object with the given id
+EXP_OPTION DataFile* getDataFileWithId(const SignedDoc* pSigDoc, const char* id);
+// add a <DataFile> block to <SignedDoc>
+// use NULL for any parameter you don't have the value
+// use NULL for id if you want to auto-calculate it (recommended!!!)
+EXP_OPTION int DataFile_new(DataFile **newDataFile, SignedDoc* pSigDoc, const char* id,
+ const char* filename, const char* contentType,
+ const char* mime, long size,
+ const byte* digest, int digLen,
+ const char* digType, const char* szCharset);
+// cleanup DataFile memory
+EXP_OPTION void DataFile_free(DataFile* pDataFile);
+
+// Removes this DataFile from signed doc and frees it's memory
+EXP_OPTION int DataFile_delete(SignedDoc* pSigDoc, const char* id);
+
+//--------------------------------------------------
+// Accessor for Digest atribute of DataFile object.
+// pDataFile - address of object [REQUIRED]
+// returns value of atribute or NULL.
+//--------------------------------------------------
+EXP_OPTION DigiDocMemBuf* ddocDataFile_GetDigestValue(DataFile* pDataFile);
+
+//--------------------------------------------------
+// Mutatoror for Digest atribute of DataFile object.
+// pDataFile - address of object [REQUIRED]
+// value - new value for atribute [REQUIRED]
+// len - length of value in bytes [REQUIRED]
+// returns error code or ERR_OK
+//--------------------------------------------------
+EXP_OPTION int ddocDataFile_SetDigestValue(DataFile* pDataFile,
+ const char* value, long len);
+
+//--------------------------------------------------
+// Accessor for DetachedDigest atribute of DataFile object.
+// pDataFile - address of object [REQUIRED]
+// returns value of atribute or NULL.
+//--------------------------------------------------
+EXP_OPTION DigiDocMemBuf* ddocDataFile_GetDetachedDigestValue(DataFile* pDataFile);
+
+//--------------------------------------------------
+// Mutatoror for DetachedDigest atribute of DataFile object.
+// pDataFile - address of object [REQUIRED]
+// value - new value for atribute [REQUIRED]
+// len - length of value in bytes [REQUIRED]
+// returns error code or ERR_OK
+//--------------------------------------------------
+EXP_OPTION int ddocDataFile_SetDetachedDigestValue(DataFile* pDataFile,
+ const char* value, long len);
+
+//--------------------------------------------------
+// Accessor for WrongDigest atribute of DataFile object.
+// pDataFile - address of object [REQUIRED]
+// returns value of atribute or NULL.
+//--------------------------------------------------
+EXP_OPTION DigiDocMemBuf* ddocDataFile_GetWrongDigestValue(DataFile* pDataFile);
+
+//--------------------------------------------------
+// Mutatoror for WrongDigest atribute of DataFile object.
+// pDataFile - address of object [REQUIRED]
+// value - new value for atribute [REQUIRED]
+// len - length of value in bytes [REQUIRED]
+// returns error code or ERR_OK
+//--------------------------------------------------
+EXP_OPTION int ddocDataFile_SetWrongDigestValue(DataFile* pDataFile,
+ const char* value, long len);
+
+// Returns number of DataFile attributes
+EXP_OPTION int getCountOfDataFileAttributes(const DataFile* pDataFile);
+// Adds an attribute to data file
+EXP_OPTION int addDataFileAttribute(DataFile* pDataFile, const char* name,
+ const char* value);
+// Gets an attribute of a data file
+EXP_OPTION int getDataFileAttribute(DataFile* pDataFile, int idx, char** name, char** value);
+
+// get datafile cahed data
+EXP_OPTION int ddocGetDataFileCachedData(SignedDoc* pSigDoc, const char* szDocId, void** ppBuf, long* pLen);
+
+// apppends DataFile content to cache
+EXP_OPTION void ddocAppendDataFileData(DataFile* pDf, int maxLen, void* data, int len, int isBase64);
+
+// calculates file size and digest and store in the
+// given DataFile object
+EXP_OPTION int calculateDataFileSizeAndDigest(SignedDoc* pSigDoc, const char* id,
+ const char* filename, int digType);
+
+//--------------------------------------------------
+// Creates new DataFile and assigns contet from memory
+// ppDataFile address of pointer to return new DataFile object
+// pSigDoc - SignedDoc object
+// id - new DataFile id. Use NULL for default
+// filename - filename
+// contentType - content type
+// mime - mime type
+// pData - address of DataFile content to be assigned
+// size - length of data in bytes
+//--------------------------------------------------
+EXP_OPTION int createDataFileInMemory(DataFile **ppDataFile, SignedDoc* pSigDoc, const char* id,
+ const char* filename, const char* contentType,
+ const char* mime, const char* pData, long size);
+
+//======================< DigestValue functions >=============================
+
+//--------------------------------------------------
+// "Constructor" of DigestValue object
+// ppDigestValue - address of buffer for newly allocated object [REQUIRED]
+// szDigestMethod - digest method [OPTIONAL]
+// szDigVal/lDigLen - digest value and length [OPTIONAL]
+// returns error code or ERR_OK
+//--------------------------------------------------
+EXP_OPTION int ddocDigestValue_new(DigestValue** ppDigestValue,
+ const char* szDigestMethod,
+ void* szDigVal, long lDigLen);
+
+//--------------------------------------------------
+// "Destructor" of DigestValue object
+// pDigestValue - address of object to be deleted [REQUIRED]
+// returns error code or ERR_OK
+//--------------------------------------------------
+EXP_OPTION int ddocDigestValue_free(DigestValue* pDigestValue);
+
+//--------------------------------------------------
+// Accessor for DigestMethod atribute of DigestValue object.
+// pDigestValue - address of object [REQUIRED]
+// returns value of atribute or NULL.
+//--------------------------------------------------
+EXP_OPTION const char* ddocDigestValue_GetDigestMethod(DigestValue* pDigestValue);
+
+//--------------------------------------------------
+// Mutatoror for DigestMethod atribute of DigestValue object.
+// pDigestValue - address of object [REQUIRED]
+// value - new value for atribute [REQUIRED]
+// returns error code or ERR_OK
+//--------------------------------------------------
+EXP_OPTION int ddocDigestValue_SetDigestMethod(DigestValue* pDigestValue, const char* value);
+
+//--------------------------------------------------
+// Accessor for DigestValue atribute of DigestValue object.
+// pDigestValue - address of object [REQUIRED]
+// returns value of atribute or NULL.
+//--------------------------------------------------
+EXP_OPTION DigiDocMemBuf* ddocDigestValue_GetDigestValue(DigestValue* pDigestValue);
+
+//--------------------------------------------------
+// Mutatoror for DigestValue atribute of DigestValue object.
+// pDigestValue - address of object [REQUIRED]
+// value - new value for atribute [REQUIRED]
+// len - length of value in bytes [REQUIRED]
+// returns error code or ERR_OK
+//--------------------------------------------------
+EXP_OPTION int ddocDigestValue_SetDigestValue(DigestValue* pDigestValue,
+ const char* value, long len);
+
+//--------------------------------------------------
+// Compares two DigestValue structure on equality
+// pDigest1 - address of first digest [REQUIRED]
+// pDigest2 - address of second digest [REQUIRED]
+// returns error code or ERR_OK
+//--------------------------------------------------
+int ddocCompareDigestValues(DigestValue* pDigest1, DigestValue* pDigest2);
+
+//--------------------------------------------------
+// Generates XML for <DigestValue> element
+// pDigestValue - DigestValue object [REQUIRED]
+// pBuf - memory buffer for storing xml [REQUIRED]
+// returns error code or ERR_OK
+//--------------------------------------------------
+int ddocDigestValue_toXML(const DigestValue* pDigestValue, DigiDocMemBuf* pBuf);
+
+//======================< SignatureValue functions >=============================
+
+//============================================================
+// Returns the next free signature id
+// pSigDoc - signed doc pointer
+//============================================================
+EXP_OPTION int getNextSignatureId(const SignedDoc* pSigDoc);
+
+//--------------------------------------------------
+// "Constructor" of SignatureValue object
+// ppSignatureValue - address of buffer for newly allocated object [REQUIRED]
+// szId - Id atribute value [OPTIONAL]
+// szType - signature type [OPTIONAL]
+// szDigVal/lDigLen - digest value and length [OPTIONAL]
+// returns error code or ERR_OK
+//--------------------------------------------------
+EXP_OPTION int ddocSignatureValue_new(SignatureValue** ppSignatureValue,
+ const char* szId, const char* szType,
+ void* szSigVal, long lSigLen);
+
+//--------------------------------------------------
+// "Destructor" of SignatureValue object
+// pSignatureValue - address of object to be deleted [REQUIRED]
+// returns error code or ERR_OK
+//--------------------------------------------------
+EXP_OPTION int ddocSignatureValue_free(SignatureValue* pSignatureValue);
+
+//--------------------------------------------------
+// Accessor for Id atribute of SignatureValue object.
+// pSignatureValue - address of object [REQUIRED]
+// returns value of atribute or NULL.
+//--------------------------------------------------
+EXP_OPTION const char* ddocSignatureValue_GetId(const SignatureValue* pSignatureValue);
+
+//--------------------------------------------------
+// Mutatoror for Id atribute of SignatureValue object.
+// pSignatureValue - address of object [REQUIRED]
+// value - new value for atribute [REQUIRED]
+// returns error code or ERR_OK
+//--------------------------------------------------
+EXP_OPTION int ddocSignatureValue_SetId(SignatureValue* pSignatureValue, const char* value);
+
+//--------------------------------------------------
+// Accessor for Type atribute of SignatureValue object.
+// pSignatureValue - address of object [REQUIRED]
+// returns value of atribute or NULL.
+//--------------------------------------------------
+EXP_OPTION const char* ddocSignatureValue_GetType(const SignatureValue* pSignatureValue);
+
+//--------------------------------------------------
+// Mutatoror for Type atribute of SignatureValue object.
+// pSignatureValue - address of object [REQUIRED]
+// value - new value for atribute [REQUIRED]
+// returns error code or ERR_OK
+//--------------------------------------------------
+EXP_OPTION int ddocSignatureValue_SetType(SignatureValue* pSignatureValue, const char* value);
+
+//--------------------------------------------------
+// Accessor for SignatureValue atribute of SignatureValue object.
+// pSignatureValue - address of object [REQUIRED]
+// returns value of atribute or NULL.
+//--------------------------------------------------
+EXP_OPTION DigiDocMemBuf* ddocSignatureValue_GetSignatureValue(const SignatureValue* pSignatureValue);
+
+//--------------------------------------------------
+// Mutatoror for SignatureValue atribute of SignatureValue object.
+// pSignatureValue - address of object [REQUIRED]
+// value - new value for atribute [REQUIRED]
+// len - length of value in bytes [REQUIRED]
+// returns error code or ERR_OK
+//--------------------------------------------------
+EXP_OPTION int ddocSignatureValue_SetSignatureValue(SignatureValue* pSignatureValue,
+ const char* value, long len);
+
+//--------------------------------------------------
+// Generates XML for <IncludeInfo> element
+// pSignatureValue - SignatureValue object [REQUIRED]
+// pBuf - memory buffer for storing xml [REQUIRED]
+// returns error code or ERR_OK
+//--------------------------------------------------
+int ddocSignatureValue_toXML(const SignatureValue* pSignatureValue, DigiDocMemBuf* pBuf);
+
+//======================< CertID >====================================
+
+//--------------------------------------------------
+// "Constructor" of CertID object
+// ppCertID - address of buffer for newly allocated object [REQUIRED]
+// szId - Id atribute value [OPTIONAL]
+// nType - certid internal type (signers or responders cert) [REQUIRED]
+// szIssuerSerial - issuer serial number [OPTIONAL]
+// szIssuerName - issuer DN [OPTIONAL]
+// szDigVal/lDigLen - digest value and length [OPTIONAL]
+// returns error code or ERR_OK
+//--------------------------------------------------
+EXP_OPTION int ddocCertID_new(CertID** ppCertID,
+ int nType, const char* szId,
+ const char* szIssuerSerial, const char* szIssuerName,
+ void* szDigVal, long lDigLen);
+
+//--------------------------------------------------
+// "Destructor" of CertID object
+// pCertID - address of object to be deleted [REQUIRED]
+// returns error code or ERR_OK
+//--------------------------------------------------
+EXP_OPTION int ddocCertID_free(CertID* pCertID);
+
+//--------------------------------------------------
+// Accessor for Id atribute of CertID object.
+// pCertID - address of object [REQUIRED]
+// returns value of atribute or NULL.
+//--------------------------------------------------
+EXP_OPTION const char* ddocCertID_GetId(const CertID* pCertID);
+
+//--------------------------------------------------
+// Mutatoror for Id atribute of CertID object.
+// pCertID - address of object [REQUIRED]
+// value - new value for atribute [REQUIRED]
+// returns error code or ERR_OK
+//--------------------------------------------------
+EXP_OPTION int ddocCertID_SetId(CertID* pCertID, const char* value);
+
+//--------------------------------------------------
+// Accessor for IssuerSerial atribute of CertID object.
+// pCertID - address of object [REQUIRED]
+// returns value of atribute or NULL.
+//--------------------------------------------------
+EXP_OPTION const char* ddocCertID_GetIssuerSerial(const CertID* pCertID);
+
+//--------------------------------------------------
+// Mutatoror for IssuerSerial atribute of CertID object.
+// pCertID - address of object [REQUIRED]
+// value - new value for atribute [REQUIRED]
+// returns error code or ERR_OK
+//--------------------------------------------------
+EXP_OPTION int ddocCertID_SetIssuerSerial(CertID* pCertID, const char* value);
+
+//--------------------------------------------------
+// Accessor for IssuerName atribute of CertID object.
+// pCertID - address of object [REQUIRED]
+// returns value of atribute or NULL.
+//--------------------------------------------------
+EXP_OPTION const char* ddocCertID_GetIssuerName(const CertID* pCertID);
+
+//--------------------------------------------------
+// Mutatoror for IssuerName atribute of CertID object.
+// pCertID - address of object [REQUIRED]
+// value - new value for atribute [REQUIRED]
+// returns error code or ERR_OK
+//--------------------------------------------------
+EXP_OPTION int ddocCertID_SetIssuerName(CertID* pCertID, const char* value);
+
+//--------------------------------------------------
+// Accessor for DigestValue atribute of CertID object.
+// pCertID - address of object [REQUIRED]
+// returns value of atribute or NULL.
+//--------------------------------------------------
+EXP_OPTION DigiDocMemBuf* ddocCertID_GetDigestValue(const CertID* pCertID);
+
+
+//--------------------------------------------------
+// Mutatoror for DigestValue atribute of CertID object.
+// pCertID - address of object [REQUIRED]
+// value - new value for atribute [REQUIRED]
+// len - length of value in bytes [REQUIRED]
+// returns error code or ERR_OK
+//--------------------------------------------------
+EXP_OPTION int ddocCertID_SetDigestValue(CertID* pCertID,
+ const char* value, long len);
+
+//--------------------------------------------------
+// Generates XML for <Cert> element
+// pCertID - CertID object [REQUIRED]
+// pBuf - memory buffer for storing xml [REQUIRED]
+// returns error code or ERR_OK
+//--------------------------------------------------
+int ddocCertID_toXML(const SignedDoc* pSigDoc, const CertID* pCertID, DigiDocMemBuf* pBuf);
+
+//--------------------------------------------------
+// Generates XML for <CompleteCertificateRefs> element
+// pSigDoc - SignedDoc object [REQUIRED]
+// pBuf - memory buffer for storing xml [REQUIRED]
+// returns error code or ERR_OK
+//--------------------------------------------------
+int ddocCompleteCertificateRefs_toXML(const SignedDoc* pSigDoc, const SignatureInfo* pSigInfo, DigiDocMemBuf* pBuf);
+int bdocCompleteCertificateRefs_toXML(const SignedDoc* pSigDoc, const SignatureInfo* pSigInfo, DigiDocMemBuf* pBuf);
+
+//--------------------------------------------------
+// Generates XML for <CompleteRevocationRefs> element
+// pSigDoc - SignedDoc object [REQUIRED]
+// pBuf - memory buffer for storing xml [REQUIRED]
+// returns error code or ERR_OK
+//--------------------------------------------------
+int ddocCompleteRevocationRefs_toXML(const SignedDoc* pSigDoc, const SignatureInfo* pSigInfo, DigiDocMemBuf* pBuf);
+
+
+//==========< CertIDList >====================
+
+//--------------------------------------------------
+// "Constructor" of CertIDList object
+// ppCertIDList - address of buffer for newly allocated object [REQUIRED]
+// returns error code or ERR_OK
+//--------------------------------------------------
+EXP_OPTION int ddocCertIDList_new(CertIDList** ppCertIDList);
+
+//--------------------------------------------------
+// "Destructor" of CertIDList object
+// pCertIDList - address of object to be deleted [REQUIRED]
+// returns error code or ERR_OK
+//--------------------------------------------------
+EXP_OPTION int ddocCertIDList_free(CertIDList* pCertIDList);
+
+//--------------------------------------------------
+// Accessor for count of CertIDs subelement of CertIDList object.
+// pCertIDList - pointer to CertIDList object [REQUIRED]
+// returns error code or ERR_OK
+//--------------------------------------------------
+int ddocCertIDList_addCertID(CertIDList* pCertIDList, CertID* pCertID);
+
+//--------------------------------------------------
+// Accessor for count of CertIDs subelement of CertIDList object.
+// pCertIDList - pointer to CertIDList object [REQUIRED]
+// returns count or -1 for error. Then use error API to check errors
+//--------------------------------------------------
+EXP_OPTION int ddocCertIDList_GetCertIDsCount(CertIDList* pCertIDList);
+
+//--------------------------------------------------
+// Accessor for CertIDs subelement of CertIDList object.
+// pCertIDList - pointer to CertIDList object [REQUIRED]
+// nIdx - index of CertID object [REQUIRED]
+// returns CertID pointer or NULL for error
+//--------------------------------------------------
+EXP_OPTION CertID* ddocCertIDList_GetCertID(CertIDList* pCertIDList, int nIdx);
+
+//--------------------------------------------------
+// Accessor for last CertIDs subelement of CertIDList object.
+// pCertIDList - pointer to CertIDList object [REQUIRED]
+// returns CertID pointer or NULL for error
+//--------------------------------------------------
+EXP_OPTION CertID* ddocCertIDList_GetLastCertID(CertIDList* pCertIDList);
+
+//--------------------------------------------------
+// Deletes CertID subelement of CertIDList object.
+// pCertIDList - pointer to CertIDList object [REQUIRED]
+// nIdx - index of CertID object to be removed [REQUIRED]
+// returns error code or ERR_OK
+//--------------------------------------------------
+EXP_OPTION int ddocCertIDList_DeleteCertID(CertIDList* pCertIDList, int nIdx);
+
+//--------------------------------------------------
+// Finds a CertID object with required type
+// pCertIDList - pointer to CertIDList object [REQUIRED]
+// nType - type of CertID object [REQUIRED]
+// returns CertID pointer or NULL for error
+//--------------------------------------------------
+EXP_OPTION CertID* ddocCertIDList_GetCertIDOfType(CertIDList* pCertIDList, int nType);
+
+//--------------------------------------------------
+// Finds a CertID object with required serial nr
+// pCertIDList - pointer to CertIDList object [REQUIRED]
+// szSerial - issuer serial
+// returns CertID pointer or NULL for error
+//--------------------------------------------------
+EXP_OPTION CertID* ddocCertIDList_GetCertIDOfSerial(CertIDList* pCertIDList, const char* szSerial);
+
+//--------------------------------------------------
+// Finds a CertID object with required type or creates a new one
+// pCertIDList - pointer to CertIDList object [REQUIRED]
+// nType - type of CertID object [REQUIRED]
+// returns CertID pointer or NULL for error
+//--------------------------------------------------
+EXP_OPTION CertID* ddocCertIDList_GetOrCreateCertIDOfType(CertIDList* pCertIDList, int nType);
+
+//======================< CertValue >====================================
+
+//--------------------------------------------------
+// "Constructor" of CertValue object
+// ppCertValue - address of buffer for newly allocated object [REQUIRED]
+// szId - Id atribute value [OPTIONAL]
+// nType - certid internal type (signers or responders cert) [REQUIRED]
+// pCert - certificate itself [OPTIONAL]. Must fill in later. Do not X509_free() param!
+// returns error code or ERR_OK
+//--------------------------------------------------
+EXP_OPTION int ddocCertValue_new(CertValue** ppCertValue,
+ int nType, const char* szId,
+ X509* pCert);
+
+//--------------------------------------------------
+// "Destructor" of CertValue object
+// pCertValue - address of object to be deleted [REQUIRED]
+// returns error code or ERR_OK
+//--------------------------------------------------
+EXP_OPTION int ddocCertValue_free(CertValue* pCertValue);
+
+//--------------------------------------------------
+// Accessor for Id atribute of CertValue object.
+// pCertValue - address of object [REQUIRED]
+// returns value of atribute or NULL.
+//--------------------------------------------------
+EXP_OPTION const char* ddocCertValue_GetId(CertValue* pCertValue);
+
+//--------------------------------------------------
+// Mutatoror for Id atribute of CertValue object.
+// pCertValue - address of object [REQUIRED]
+// value - new value for atribute [REQUIRED]
+// returns error code or ERR_OK
+//--------------------------------------------------
+EXP_OPTION int ddocCertValue_SetId(CertValue* pCertValue, const char* value);
+
+//--------------------------------------------------
+// Accessor for Cert atribute of CertValue object.
+// pCertValue - address of object [REQUIRED]
+// returns value of atribute or NULL.
+//--------------------------------------------------
+EXP_OPTION X509* ddocCertValue_GetCert(CertValue* pCertValue);
+
+//--------------------------------------------------
+// Mutatoror for Cert atribute of CertValue object.
+// pCertValue - address of object [REQUIRED]
+// pCert - new value for atribute [REQUIRED]
+// returns error code or ERR_OK
+//--------------------------------------------------
+EXP_OPTION int ddocCertValue_SetCert(CertValue* pCertValue, X509* pCert);
+
+//--------------------------------------------------
+// Generates XML for <EncapsulatedX509Certificate> element
+// pCertID - CertID object [REQUIRED]
+// pBuf - memory buffer for storing xml [REQUIRED]
+// returns error code or ERR_OK
+//--------------------------------------------------
+int ddocCertValue_toXML(const CertValue* pCertValue, DigiDocMemBuf* pBuf);
+
+//==========< CertValueList >====================
+
+//--------------------------------------------------
+// "Constructor" of CertValueList object
+// ppCertValueList - address of buffer for newly allocated object [REQUIRED]
+// returns error code or ERR_OK
+//--------------------------------------------------
+EXP_OPTION int ddocCertValueList_new(CertValueList** ppCertValueList);
+
+//--------------------------------------------------
+// "Destructor" of CertValueList object
+// pCertValueList - address of object to be deleted [REQUIRED]
+// returns error code or ERR_OK
+//--------------------------------------------------
+EXP_OPTION int ddocCertValueList_free(CertValueList* pCertValueList);
+
+//--------------------------------------------------
+// Adds a CertValue element to CertValueList object.
+// pCertValueList - pointer to CertValueList object [REQUIRED]
+// pCertValue - new object [REQUIRED]
+// returns error code or ERR_OK
+//--------------------------------------------------
+EXP_OPTION int ddocCertValueList_addCertValue(CertValueList* pCertValueList, CertValue* pCertValue);
+
+//--------------------------------------------------
+// Accessor for count of CertValues subelement of CertValueList object.
+// pCertValueList - pointer to CertValueList object [REQUIRED]
+// returns count or -1 for error. Then use error API to check errors
+//--------------------------------------------------
+EXP_OPTION int ddocCertValueList_GetCertValuesCount(CertValueList* pCertValueList);
+
+//--------------------------------------------------
+// Accessor for CertValues subelement of CertValueList object.
+// pCertValueList - pointer to CertValueList object [REQUIRED]
+// nIdx - index of CertValue object [REQUIRED]
+// returns CertValue pointer or NULL for error
+//--------------------------------------------------
+EXP_OPTION CertValue* ddocCertValueList_GetCertValue(CertValueList* pCertValueList, int nIdx);
+
+//--------------------------------------------------
+// Deletes CertValue subelement of CertValueList object.
+// pCertValueList - pointer to CertValueList object [REQUIRED]
+// nIdx - index of CertValue object to be removed [REQUIRED]
+// returns error code or ERR_OK
+//--------------------------------------------------
+EXP_OPTION int ddocCertValueList_DeleteCertValue(CertValueList* pCertValueList, int nIdx);
+
+//--------------------------------------------------
+// Finds a CertValue object with required type
+// pCertValueList - pointer to CertValueList object [REQUIRED]
+// nType - type of CertValue object [REQUIRED]
+// returns CertValue pointer or NULL for error
+//--------------------------------------------------
+EXP_OPTION CertValue* ddocCertValueList_GetCertValueOfType(CertValueList* pCertValueList, int nType);
+
+//--------------------------------------------------
+// Finds a CertValue object with required type or creates a new one
+// pCertValueList - pointer to CertValueList object [REQUIRED]
+// nType - type of CertValue object [REQUIRED]
+// returns CertValue pointer or NULL for error
+//--------------------------------------------------
+EXP_OPTION CertValue* ddocCertValueList_GetOrCreateCertValueOfType(CertValueList* pCertValueList, int nType);
+
+//======================< SignatureInfo functions >=============================
+
+// returns the number of signatures
+EXP_OPTION int getCountOfSignatures(const SignedDoc* pSigDoc);
+// Returns the desired SignatureInfo object
+EXP_OPTION SignatureInfo* getSignature(const SignedDoc* pSigDoc, int nIdx);
+
+//============================================================
+// Returns signatures signed properties digest
+// pSigInfo - signature info object
+// return digest value as DigiDocMemBuf pointer or NULL
+//============================================================
+EXP_OPTION DigiDocMemBuf* ddocSigInfo_GetSigPropDigest(SignatureInfo* pSigInfo);
+
+//============================================================
+// Sets signatures signed properties digest
+// pSigInfo - signature info object
+// value - new binary digest value
+// len - length of the value
+//============================================================
+EXP_OPTION int ddocSigInfo_SetSigPropDigest(SignatureInfo* pSigInfo, const char* value, long len);
+
+//============================================================
+// Returns signatures signed properties digest as read from file
+// pSigInfo - signature info object
+// return digest value as DigiDocMemBuf pointer or NULL
+//============================================================
+EXP_OPTION DigiDocMemBuf* ddocSigInfo_GetSigPropRealDigest(SignatureInfo* pSigInfo);
+
+//============================================================
+// Sets signatures signed properties real digest as read from file
+// pSigInfo - signature info object
+// value - new binary digest value
+// len - length of the value
+//============================================================
+EXP_OPTION int ddocSigInfo_SetSigPropRealDigest(SignatureInfo* pSigInfo, const char* value, long len);
+
+//============================================================
+// Returns signatures signed info digest as read from file
+// pSigInfo - signature info object
+// return digest value as DigiDocMemBuf pointer or NULL
+//============================================================
+EXP_OPTION DigiDocMemBuf* ddocSigInfo_GetSigInfoRealDigest(SignatureInfo* pSigInfo);
+
+//============================================================
+// Sets signatures signed info real digest as read from file
+// pSigInfo - signature info object
+// value - new binary digest value
+// len - length of the value
+//============================================================
+EXP_OPTION int ddocSigInfo_SetSigInfoRealDigest(SignatureInfo* pSigInfo, const char* value, long len);
+
+//============================================================
+// Returns signatures signature-value
+// pSigInfo - signature info object
+// return signature-value as SignatureValue pointer or NULL
+//============================================================
+EXP_OPTION SignatureValue* ddocSigInfo_GetSignatureValue(SignatureInfo* pSigInfo);
+
+//============================================================
+// Returns signatures signature-value
+// pSigInfo - signature info object
+// return signature-value as DigiDocMemBuf pointer or NULL
+//============================================================
+EXP_OPTION DigiDocMemBuf* ddocSigInfo_GetSignatureValue_Value(SignatureInfo* pSigInfo);
+
+//============================================================
+// Sets signatures signature-value
+// pSigInfo - signature info object
+// value - new binary signature value
+// len - length of the value
+//============================================================
+EXP_OPTION int ddocSigInfo_SetSignatureValue(SignatureInfo* pSigInfo, const char* value, long len);
+
+//============================================================
+// Returns signaers certs - issuer-serial
+// pSigInfo - signature info object
+// return required atribute value
+//============================================================
+EXP_OPTION const char* ddocSigInfo_GetSignersCert_IssuerSerial(const SignatureInfo* pSigInfo);
+
+//============================================================
+// Sets signers certs issuer serial
+// pSigInfo - signature info object
+// value - new value
+//============================================================
+EXP_OPTION int ddocSigInfo_SetSignersCert_IssuerSerial(SignatureInfo* pSigInfo, const char* value);
+
+//============================================================
+// Returns signaers certs - issuer-name
+// pSigInfo - signature info object
+// return required atribute value
+//============================================================
+EXP_OPTION const char* ddocSigInfo_GetSignersCert_IssuerName(const SignatureInfo* pSigInfo);
+
+//============================================================
+// Returns signaers certs - issuer-name
+// pSigInfo - signature info object
+// pMbuf - memory buffer to return hash
+// return required atribute value
+//============================================================
+EXP_OPTION const char* ddocSigInfo_GetSignersCert_IssuerNameAndHash(const SignatureInfo* pSigInfo, DigiDocMemBuf *pMbuf);
+
+//============================================================
+// Sets signers certs issuer name
+// pSigInfo - signature info object
+// value - new value
+//============================================================
+EXP_OPTION int ddocSigInfo_SetSignersCert_IssuerName(SignatureInfo* pSigInfo, const char* value);
+
+//============================================================
+// Returns signers certs digest as DigiDocMemBuf object
+// pSigInfo - signature info object
+// return signers certs digest as DigiDocMemBuf pointer or NULL
+//============================================================
+EXP_OPTION DigiDocMemBuf* ddocSigInfo_GetSignersCert_DigestValue(const SignatureInfo* pSigInfo);
+
+//============================================================
+// Sets signers certs digest
+// pSigInfo - signature info object
+// value - new binary signature value
+// len - length of the value
+//============================================================
+EXP_OPTION int ddocSigInfo_SetSignersCert_DigestValue(SignatureInfo* pSigInfo, const char* value, long len);
+
+//--------------------------------------------------
+// Finds a CertID object with required type
+// pSigInfo - signature info object [REQUIRED]
+// nType - type of CertID object [REQUIRED]
+// returns CertID pointer or NULL for error
+//--------------------------------------------------
+EXP_OPTION CertID* ddocSigInfo_GetCertIDOfType(const SignatureInfo* pSigInfo, int nType);
+
+//--------------------------------------------------
+// Finds a CertID object with required type or creates a new one
+// pSigInfo - signature info object [REQUIRED]
+// nType - type of CertID object [REQUIRED]
+// returns CertID pointer or NULL for error
+//--------------------------------------------------
+EXP_OPTION CertID* ddocSigInfo_GetOrCreateCertIDOfType(SignatureInfo* pSigInfo, int nType);
+
+//--------------------------------------------------
+// Finds last CertID object of this signature
+// pSigInfo - signature info object [REQUIRED]
+// returns CertID pointer or NULL for error
+//--------------------------------------------------
+EXP_OPTION CertID* ddocSigInfo_GetLastCertID(const SignatureInfo* pSigInfo);
+
+//--------------------------------------------------
+// Finds a CertValue object with required type
+// pSigInfo - signature info object [REQUIRED]
+// nType - type of CertValue object [REQUIRED]
+// returns CertValue pointer or NULL for error
+//--------------------------------------------------
+EXP_OPTION CertValue* ddocSigInfo_GetCertValueOfType(const SignatureInfo* pSigInfo, int nType);
+
+//--------------------------------------------------
+// Finds last CertValue
+// pSigInfo - signature info object [REQUIRED]
+// returns CertValue pointer or NULL for error
+//--------------------------------------------------
+EXP_OPTION CertValue* ddocSigInfo_GetLastCertValue(const SignatureInfo* pSigInfo);
+
+//--------------------------------------------------
+// Finds a CertValue object with required type or creates a new one
+// pSigInfo - signature info object [REQUIRED]
+// nType - type of CertValue object [REQUIRED]
+// returns CertValue pointer or NULL for error
+//--------------------------------------------------
+EXP_OPTION CertValue* ddocSigInfo_GetOrCreateCertValueOfType(SignatureInfo* pSigInfo, int nType);
+
+//--------------------------------------------------
+// Finds the signers certificate
+// pSigInfo - signature info object [REQUIRED]
+// returns certificate or NULL
+//--------------------------------------------------
+EXP_OPTION X509* ddocSigInfo_GetSignersCert(const SignatureInfo* pSigInfo);
+
+//--------------------------------------------------
+// Sets the signers certificate
+// pSigInfo - signature info object [REQUIRED]
+// pCert - certificate [REQUIRED]
+// returns error code or ERR_OK
+//--------------------------------------------------
+EXP_OPTION int ddocSigInfo_SetSignersCert(SignatureInfo* pSigInfo, X509* pCert);
+
+//--------------------------------------------------
+// Finds the OCSP responders certificate
+// pSigInfo - signature info object [REQUIRED]
+// returns certificate or NULL
+//--------------------------------------------------
+EXP_OPTION X509* ddocSigInfo_GetOCSPRespondersCert(const SignatureInfo* pSigInfo);
+
+//--------------------------------------------------
+// Sets the OCSP Responders certificate
+// pSigInfo - signature info object [REQUIRED]
+// pCert - certificate [REQUIRED]
+// returns error code or ERR_OK
+//--------------------------------------------------
+EXP_OPTION int ddocSigInfo_SetOCSPRespondersCert(SignatureInfo* pSigInfo, X509* pCert);
+
+//============================================================
+// Adds a certificate and it's certid to this signature
+// pSigInfo - signature info object [REQUIRED]
+// pCert - vertificate [REQUIRED]
+// nCertIdType - type of cert [REQUIRED]
+// return error code or ERR_OK
+//============================================================
+EXP_OPTION int ddocSigInfo_addCert(SignatureInfo* pSigInfo, X509* pCert, int nCertIdType);
+//AM
+EXP_OPTION int bdocSigInfo_addCert(SignatureInfo* pSigInfo, X509* pCert, int nCertIdType);
+
+
+
+// Returns the last SignatureInfo object
+EXP_OPTION SignatureInfo* ddocGetLastSignature(const SignedDoc* pSigDoc);
+// Returns the SignatureInfo object with the given id
+EXP_OPTION SignatureInfo* getSignatureWithId(const SignedDoc* pSigDoc, const char* id);
+// Returns the SignatureInfo for the given NotaryInfo
+EXP_OPTION SignatureInfo* ddocGetSignatureForNotary(const SignedDoc* pSigDoc, const NotaryInfo* pNotInfo);
+
+// Adds a new SignedInfo element to a SignedDoc element and initializes it
+EXP_OPTION int SignatureInfo_new(SignatureInfo **newSignatureInfo, SignedDoc* pSigDoc, const char* id);
+
+// Sets the signature production place info (use NULL for unknown attributes)
+EXP_OPTION int setSignatureProductionPlace(SignatureInfo* pSigInfo,
+ const char* city, const char* state,
+ const char* zip, const char* country);
+// Adds a signer role
+EXP_OPTION int addSignerRole(SignatureInfo* pSigInfo, int nCertified,
+ const char* role, int rLen, int encode);
+// Returns the number of signer roles
+EXP_OPTION int getCountOfSignerRoles(SignatureInfo* pSigInfo, int nCertified);
+// Returns the desired signer role
+EXP_OPTION const char* getSignerRole(SignatureInfo* pSigInfo, int nCertified, int nIdx);
+
+// Removes this SignatureInfo from signed doc and frees it's memory
+EXP_OPTION int SignatureInfo_delete(SignedDoc* pSigDoc, const char* id);
+
+// cleanup SignatureInfo memory
+EXP_OPTION void SignatureInfo_free(SignatureInfo* pSigInfo);
+
+//======================< DocInfo functions >=============================
+
+// Adds a new DocInfo element to a SignatureInfo element and initializes it
+EXP_OPTION int addDocInfo(DocInfo **newDocInfo, SignatureInfo* pSigInfo, const char* docId,
+ const char* digType, const byte* digest,
+ int digLen, const byte* mimeDig, int mimeDigLen);
+// cleanup DocInfo memory
+EXP_OPTION void DocInfo_free(DocInfo* pDocInfo);
+// Returns number of DocInfos
+EXP_OPTION int getCountOfDocInfos(const SignatureInfo* pSigInfo);
+// Returns the desired DocInfo
+EXP_OPTION DocInfo* getDocInfo(const SignatureInfo* pSigInfo, int idx);
+// Returns the last DocInfo
+EXP_OPTION DocInfo* ddocGetLastDocInfo(const SignatureInfo* pSigInfo);
+
+
+// Returns the DocInfo object with the given id
+EXP_OPTION DocInfo* getDocInfoWithId(const SignatureInfo* pSigInfo, const char* id);
+// Sets the DocInfo objects document digest and digest type
+EXP_OPTION void setDocInfoDigest(DocInfo* pDocInfo, const byte* digest,
+ int digLen, const char* digType);
+// Sets the DocInfo objects mime digest and mime type
+EXP_OPTION void setDocInfoMimeDigest(DocInfo* pDocInfo, const byte* mimeDig, int mimeDigLen);
+
+// Adds all DocInfo elements in this file to a SignatureInfo element
+EXP_OPTION int addAllDocInfos(SignedDoc* pSigDoc, SignatureInfo* pSigInfo);
+
+//======================< NotaryInfo functions >=============================
+
+// returns the number of notarys
+EXP_OPTION int getCountOfNotaryInfos(const SignedDoc* pSigDoc);
+// Returns the desired NotaryInfo object
+EXP_OPTION NotaryInfo* getNotaryInfo(const SignedDoc* pSigDoc, int nIdx);
+// Returns the last NotaryInfo object
+EXP_OPTION NotaryInfo* ddocGetLastNotaryInfo(const SignedDoc* pSigDoc);
+// Returns the NotaryInfo object with the given id
+EXP_OPTION NotaryInfo* getNotaryWithId(const SignedDoc* pSigDoc, const char* id);
+// Returns the NotaryInfo object that corresponds to the given signature
+EXP_OPTION NotaryInfo* getNotaryWithSigId(const SignedDoc* pSigDoc, const char* sigId);
+// Returns the NotaryInfo object that corresponds to the given signature
+// ore creates a new one
+EXP_OPTION NotaryInfo* getOrCreateNotaryWithSigId(SignedDoc* pSigDoc, const char* sigId);
+
+// Adds a new NotaryInfo element to a SignedDoc element and initializes it partly
+EXP_OPTION int NotaryInfo_new(NotaryInfo** newNotaryInfo, SignedDoc* pSigDoc, SignatureInfo* pSigInfo);
+// the same as above, but reads response and cert from file
+EXP_OPTION int NotaryInfo_new_file(NotaryInfo** newNotaryInfo, SignedDoc* pSigDoc, const SignatureInfo* pSigInfo,
+ const char* ocspRespFile, const char* notaryCertFile);
+// cleanup NotaryInfo memory
+EXP_OPTION void NotaryInfo_free(NotaryInfo* pNotary);
+
+//============================================================
+// Returns OCSP responders id as in XML document
+// pNotary - Notary info
+// return DigiDocMemBuf buffer pointer or NULL for error
+//============================================================
+EXP_OPTION const DigiDocMemBuf* ddocNotInfo_GetResponderId(const NotaryInfo* pNotary);
+
+//============================================================
+// Returns OCSP responders id value as string
+// pNotary - Notary info
+// return responder id value or NULL
+//============================================================
+EXP_OPTION const char* ddocNotInfo_GetResponderId_Value(const NotaryInfo* pNotary);
+
+//============================================================
+// Sets OCSP responders id as in XML document
+// pNotary - Notary info
+// data - new responder id value
+// len - length of value
+// return DigiDocMemBuf buffer pointer or NULL for error
+//============================================================
+int ddocNotInfo_SetResponderId(NotaryInfo* pNotary, const char* data, long len);
+
+//============================================================
+// Returns OCSP response as memory buffer
+// pNotary - Notary info
+// return DigiDocMemBuf buffer pointer or NULL for error
+//============================================================
+const DigiDocMemBuf* ddocNotInfo_GetOCSPResponse(const NotaryInfo* pNotary);
+
+//============================================================
+// Retrieves OCSP responses responder id type and value
+// pResp - OCSP response
+// pType - buffer for type
+// pMbufRespId - responder id
+// returns error code or ERR_OK
+//============================================================
+int ddocGetOcspRespIdTypeAndValue(OCSP_RESPONSE* pResp,
+ int *pType, DigiDocMemBuf* pMbufRespId);
+
+//============================================================
+// Sets OCSP respondese value as in XML document. Must pass in
+// binary DER data!
+// pNotary - Notary info
+// data - new responder id value
+// len - length of value
+// return DigiDocMemBuf buffer pointer or NULL for error
+//============================================================
+int ddocNotInfo_SetOCSPResponse(NotaryInfo* pNotary, const char* data, long len);
+
+//============================================================
+// Returns OCSP response value
+// pNotary - Notary info
+// return OCSP_RESPONSE pointer or NULL for error. Caller must
+// use OCSP_RESPONSE_free() to release it.
+//============================================================
+OCSP_RESPONSE* ddocNotInfo_GetOCSPResponse_Value(const NotaryInfo* pNotary);
+
+//============================================================
+// Sets OCSP respondese value. Must pass in real OCSP_RESPONSE
+// pNotary - Notary info
+// data - new responder id value
+// len - length of value
+// return DigiDocMemBuf buffer pointer or NULL for error
+//============================================================
+int ddocNotInfo_SetOCSPResponse_Value(NotaryInfo* pNotary, OCSP_RESPONSE* pResp);
+
+//============================================================
+// Returns OCSP responders id type as string
+// pNotary - Notary info
+// return responder id type or NULL. DO NOT free() it!
+//============================================================
+EXP_OPTION const char* ddocNotInfo_GetResponderId_Type(const NotaryInfo* pNotary);
+
+//============================================================
+// Returns OCSP responses thisUpdate atribute as string
+// pNotary - Notary info
+// pMBuf - buffer for thisUpdate value
+// return error code OR ERR_OK.
+//============================================================
+EXP_OPTION int ddocNotInfo_GetThisUpdate(const NotaryInfo* pNotary, DigiDocMemBuf* pMBuf);
+
+//============================================================
+// Returns OCSP responses producedAt atribute as time_t
+// pNotary - Notary info
+// pTime - address of time_t variable
+// return error code OR ERR_OK.
+//============================================================
+int ddocNotInfo_GetProducedAt_timet(const NotaryInfo* pNotary, time_t* pTime);
+
+//============================================================
+// Returns OCSP responses producedAt from xml as time_t
+// pNotary - Notary info
+// pTime - address of time_t variable
+// return error code OR ERR_OK.
+//============================================================
+int ddocNotInfo_GetProducedAtXml_timet(const NotaryInfo* pNotary, time_t* pTime);
+
+//============================================================
+// Returns OCSP responses thisUpdate atribute as time_t
+// pNotary - Notary info
+// pTime - address of time_t variable
+// return error code OR ERR_OK.
+//============================================================
+int ddocNotInfo_GetThisUpdate_timet(const NotaryInfo* pNotary, time_t* pTime);
+
+//============================================================
+// Returns OCSP responses nextUpdate atribute as string
+// pNotary - Notary info
+// pMBuf - buffer for thisUpdate value
+// return error code OR ERR_OK.
+//============================================================
+EXP_OPTION int ddocNotInfo_GetNextUpdate(const NotaryInfo* pNotary, DigiDocMemBuf* pMBuf);
+
+//============================================================
+// Returns OCSP responses IssuerNameHash atribute
+// pNotary - Notary info
+// pMBuf - buffer for IssuerNameHash value
+// return error code OR ERR_OK.
+//============================================================
+int ddocNotInfo_GetIssuerNameHash(const NotaryInfo* pNotary, DigiDocMemBuf* pMBuf);
+
+//============================================================
+// Returns OCSP responses IssuerKeyHash atribute
+// pNotary - Notary info
+// pMBuf - buffer for IssuerKeyHash value
+// return error code OR ERR_OK.
+//============================================================
+int ddocNotInfo_GetIssuerKeyHash(const NotaryInfo* pNotary, DigiDocMemBuf* pMBuf);
+
+//============================================================
+// Returns OCSP responses real digest from response data
+// pNotary - Notary info
+// pMBuf - buffer for digest value
+// return error code OR ERR_OK.
+//============================================================
+int ddocNotInfo_GetOcspRealDigest(const SignedDoc* pSigDoc, const NotaryInfo* pNotary, DigiDocMemBuf* pMBuf);
+
+//============================================================
+// Returns OCSP response digest as in XML document
+// pNotary - Notary info
+// return DigiDocMemBuf buffer pointer or NULL for error
+//============================================================
+EXP_OPTION const DigiDocMemBuf* ddocNotInfo_GetOcspDigest(const NotaryInfo* pNotary);
+
+//============================================================
+// Sets OCSP response digest id as in XML document
+// pNotary - Notary info
+// data - new digest value
+// len - length of value
+// return DigiDocMemBuf buffer pointer or NULL for error
+//============================================================
+int ddocNotInfo_SetOcspDigest(NotaryInfo* pNotary, const char* data, long len);
+
+//============================================================
+// Returns OCSP responses signature value
+// pNotary - Notary info
+// pMBuf - buffer for signature value
+// return error code OR ERR_OK.
+//============================================================
+int ddocNotInfo_GetOcspSignatureValue(const NotaryInfo* pNotary, DigiDocMemBuf* pMBuf);
+
+
+// Removes this NotaryInfo from signed doc and frees it's memory
+EXP_OPTION int NotaryInfo_delete(SignatureInfo* pSigInfo);
+
+// Calculates and stores a signature for this SignatureInfo object
+EXP_OPTION int calculateSigInfoSignature(const SignedDoc* pSigDoc, SignatureInfo* pSigInfo, int nSigType,
+ const char* keyfile, const char* passwd, const char* certfile);
+
+//============================================================
+// Adds a certificate to Notary and initializes Notary
+// pNotary - Notary info
+// cert - responders certificate
+// return error code
+//============================================================
+int addNotaryInfoCert(SignedDoc *pSigDoc, NotaryInfo *pNotary, X509 *cert);
+
+//============================================================
+// Removes Notary cert value and id after unsucessful verification attempt
+// pSigInfo - signature info [REQUIRED]
+// return error code
+//============================================================
+int removeNotaryInfoCert(SignatureInfo* pSigInfo);
+
+// Calculates <SignedProperties> digest
+EXP_OPTION int calculateSignedPropertiesDigest(SignedDoc* pSigDoc, SignatureInfo* pSigInfo);
+// Calculates <SignedInfo> digest
+EXP_OPTION int calculateSignedInfoDigest(SignedDoc* pSigDoc, SignatureInfo* pSigInfo, byte* digBuf, int* digLen);
+
+//============================================================
+// Returns 1 if this signature has 1 reference that was verified
+// by wrong DataFile hash calculated not using xmlns atribute
+// pSigInfo - signature info pointer
+//============================================================
+DIGIDOC_DEPRECATED EXP_OPTION int verifiedByWrongDataFileHash(const SignatureInfo* pSigInfo);
+
+//============================================================
+// Returns 1 if one signature has 1 reference that was verified
+// by wrong DataFile hash calculated not using xmlns atribute
+// pSigDoc - signed doc container pointer
+//============================================================
+EXP_OPTION int hasSignatureWithWrongDataFileHash(const SignedDoc* pSigDoc);
+
+//============================================================
+// Calculates and stores a signature for this SignatureInfo object
+// Uses PKCS#12 file to sign the info
+// pSigInfo - signature info object
+// nSigType - signature type code
+// szPkcs12File - PKCS#12 file
+// passwd - key password
+//============================================================
+EXP_OPTION int calculateSignatureWithPkcs12(SignedDoc* pSigDoc, SignatureInfo* pSigInfo,
+ const char* szPkcs12File, const char* passwd);
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif // __DIGIDOC_OBJ_H__
+
+
diff --git a/libdigidoc/DigiDocPKCS11.c b/libdigidoc/DigiDocPKCS11.c
new file mode 100644
index 0000000..158c63d
--- /dev/null
+++ b/libdigidoc/DigiDocPKCS11.c
@@ -0,0 +1,956 @@
+//==================================================
+// FILE: DigiDocPKCS11.c
+// PROJECT: Digi Doc
+// DESCRIPTION: Digi Doc functions for signing using PKCS#11 API
+// AUTHOR: Veiko Sinivee, S|E|B IT Partner Estonia
+//==================================================
+// Copyright (C) AS Sertifitseerimiskeskus
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+// GNU Lesser General Public Licence is available at
+// http://www.gnu.org/copyleft/lesser.html
+//==========< HISTORY >=============================
+// 10.02.2004 Integrated
+// 26.01.2004 Aare
+// Removed function signOCSPRequestWithPKCS11onWin
+// 13.01.2004 Veiko Sinivee
+// Creation
+//==================================================
+
+
+#include "DigiDocPKCS11.h"
+#include "DigiDocConfig.h"
+#include "DigiDocDebug.h"
+#include "DigiDocCert.h"
+#include "DigiDocGen.h"
+#include "DigiDocConvert.h"
+
+#include <stdio.h>
+#include <string.h>
+
+
+
+static CK_FUNCTION_LIST_PTR ckFunc = 0;
+
+//AA 04/01/26
+extern X509_ALGOR* setSignAlgorithm(const EVP_MD * type);
+
+// I suppose there won't be so many slots
+
+#define INVALID_SLOTIID 1000
+
+//============================================================
+// Attempts to load and initialize on PKCS#11 driver DLL.
+//============================================================
+EXP_OPTION LIBHANDLE initPKCS11Library(const char* libName)
+{
+ LIBHANDLE pLibrary = 0;
+ CK_C_GetFunctionList pC_GetFunctionList;
+ CK_RV rv;
+
+ // load PKCS#11 driver
+ ddocDebug(3, "initPKCS11Library", "Loading driver: %s", libName);
+#ifdef WIN32
+ pLibrary = LoadLibrary((LPCSTR)libName);
+#else
+ pLibrary = dlopen(libName, RTLD_NOW);
+#endif
+ if(pLibrary != NULL) {
+ // printf("Resolve PKCS#11 function index!\n");
+ // Get function pointer to C_GetFunctionList
+#ifdef WIN32
+ pC_GetFunctionList = (CK_C_GetFunctionList)GetProcAddress(/*(HINSTANCE__*)*/pLibrary, "C_GetFunctionList");
+#else
+ pC_GetFunctionList = (CK_C_GetFunctionList)dlsym(pLibrary, "C_GetFunctionList");
+#endif
+ if(pC_GetFunctionList != NULL) {
+ ddocDebug(3, "initPKCS11Library", "Getting PKCS#11 func!");
+ // Get function pointers to all PKCS #11 functions
+ rv = (*pC_GetFunctionList)(&ckFunc);
+ if(rv == CKR_OK) {
+ ddocDebug(3, "initPKCS11Library", "Initializing PKCS#11 library:");
+ // Initalize Cryptoki
+ rv = (*ckFunc->C_Initialize)(0);
+ ddocDebug(3, "initPKCS11Library", "Initlialized: %d", (int)rv);
+ if(rv != CKR_OK) {
+ ddocDebug(2, "initPKCS11Library", "Error initializing library!");
+ pLibrary = NULL; // error initializing the library
+ }
+ } else {
+ ddocDebug(2, "initPKCS11Library", "Error getting PKCS#11 func!");
+ pLibrary = NULL; // error getting function pointers
+ }
+ } else {
+ ddocDebug(2, "initPKCS11Library", "Error resolving PKCS#11 function index!");
+ pLibrary = NULL; // error getting function list function
+ }
+ } else {
+#ifdef WIN32
+ ddocDebug(2, "initPKCS11Library", "Error loading driver : %s", libName);
+#else
+ ddocDebug(2, "initPKCS11Library", "Error loading driver : %s", dlerror());
+#endif
+ }
+ return pLibrary;
+}
+
+//============================================================
+// Cleanup PKCS#11 library session
+//============================================================
+EXP_OPTION void closePKCS11Library(LIBHANDLE pLibrary, CK_SESSION_HANDLE hSession)
+{
+ CK_RV rv;
+
+ // close session
+ if(hSession > 0) {
+ ddocDebug(3, "closePKCS11Library", "Closing PKCS#11 session!");
+ rv = (*ckFunc->C_CloseSession)(hSession);
+ }
+ // finalize library
+ rv = (*ckFunc->C_Finalize)(0);
+ // remove .so from memory
+ ddocDebug(3, "closePKCS11Library", "Closing PKCS#11 library!\n");
+ if(pLibrary)
+#ifdef WIN32
+ FreeLibrary(/*(HINSTANCE__*)*/pLibrary);
+#else
+ dlclose(pLibrary);
+#endif
+}
+
+//============================================================
+// Retrieves the slotid list
+//============================================================
+EXP_OPTION CK_RV GetSlotIds(CK_SLOT_ID_PTR pSlotids, CK_ULONG_PTR pLen)
+{
+ CK_RV rv;
+
+ rv = (*ckFunc->C_GetSlotList)(TRUE, pSlotids, pLen);
+ return rv;
+}
+
+//============================================================
+// Retrieves one tokens info
+//============================================================
+EXP_OPTION CK_RV GetTokenInfo(CK_TOKEN_INFO_PTR pTokInfo, CK_SLOT_ID id)
+{
+ CK_RV rv;
+
+ rv = (*ckFunc->C_GetTokenInfo)(id, pTokInfo);
+ return rv;
+}
+
+//============================================================
+// Retrieves one slots info
+//============================================================
+EXP_OPTION CK_RV GetSlotInfo(CK_SLOT_INFO_PTR pSlotInfo, CK_SLOT_ID id)
+{
+ CK_RV rv;
+
+ rv = (*ckFunc->C_GetSlotInfo)(id, pSlotInfo);
+ return rv;
+}
+
+//============================================================
+// Loads the PKCS#11 driver and
+// tests if the driver loaded correctly
+// Returns 0 for ok otherwise error code
+//============================================================
+int loadAndTestDriver(const char* driver, LIBHANDLE* pLibrary, CK_SLOT_ID* slotids, int slots, CK_ULONG slot)
+{
+ CK_TOKEN_INFO tokinfo;
+ CK_SLOT_INFO slotinfo;
+ CK_ULONG idlen, i, ok;
+ CK_RV rv;
+ int err = ERR_OK;
+
+ // initialize
+ *pLibrary = NULL;
+ memset(slotids, 0, sizeof(CK_SLOT_ID) * slots);
+ // try to load the driver
+ *pLibrary = initPKCS11Library(driver);
+ if(!(*pLibrary))
+ SET_LAST_ERROR_RETURN_CODE(ERR_PKCS_LIB_LOAD);
+ idlen = slots;
+ rv = GetSlotIds(slotids, &idlen);
+ ddocDebug(3, "loadAndTestDriver", "RV: %d slots: %ld", (int)rv, (long)idlen);
+ if (rv != CKR_OK) {
+ err = ERR_PKCS_SLOT_LIST;
+ SET_LAST_ERROR(err);
+ }
+ if ((slot < 0) || (slot >= (int)idlen)) {
+ err = ERR_PKCS_WRONG_SLOT;
+ SET_LAST_ERROR(err);
+ }
+ // it's useful to test DLL load status this way:
+ ok = 0;
+ for(i = 0; i < (int)idlen; i++) {
+ rv = GetSlotInfo(&slotinfo, slotids[i]);
+ if(slotinfo.flags & CKF_TOKEN_PRESENT) {
+ ddocDebug(3, "loadAndTestDriver", "Read Token: %ld", (long)i);
+ rv = GetTokenInfo(&tokinfo, slotids[i]); // if !CKR_OK test
+ tokinfo.label[31] = 0;
+ ddocDebug(3, "loadAndTestDriver", "RV: %d Token: %s", (int)rv, tokinfo.label);
+ if(rv != CKR_OK)
+ slotids[i] = INVALID_SLOTIID; // set bad slotids to 0
+ else
+ ok++; // count the good slots
+ } else {
+ slotids[i] = INVALID_SLOTIID; // no tokne in this slot
+ }
+ }
+ // fill other slotid's with invalid slotid
+ for(i = idlen; i < (CK_ULONG)slots; i++)
+ slotids[i] = INVALID_SLOTIID;
+ if(ok < slot) {
+ err = ERR_PKCS_CARD_READ; // if not enough good slots
+ SET_LAST_ERROR(err);
+ }
+ // in case of error try to unload the module and notify caller
+ if (err) {
+ if (*pLibrary)
+ closePKCS11Library(*pLibrary, 0);
+ *pLibrary = NULL;
+ }
+ return err;
+}
+
+//============================================================
+// Opens smart card session.
+// slotId - id of the sert slot
+// pin - card pin
+// return session id or -1 for failure
+//============================================================
+CK_SESSION_HANDLE OpenSession(CK_SLOT_ID slotId, const char *pin)
+{
+ CK_SESSION_HANDLE hSession = 0;
+ /*
+ Ainult SERIAL_SESSION toetatud, Digiallkirja andvat privaatvo~tit kasutav sessioon
+ on initsialiseeritud CKS_RO_USER_FUNCTIONS staatusesse, seda on tehtud Netscape lolli-
+ tamiseks, et see igal vo~imalikul ja vo~imatul juhul ei ku"siks pin'i vo~tme jaoks
+ mida ta niiehknii kasutada ei oska. Selle jaoks tuleb vajaduse korral ikka C_Login
+ va"lja kutsuda.
+ */
+ CK_RV rv = (*ckFunc->C_OpenSession)(slotId, CKF_SERIAL_SESSION,0,0,&hSession);
+ ddocDebug(3, "OpenSession", "Open sess for slot id: %u - sess: %uld RV = %u", slotId, hSession, rv);
+ if(rv == CKR_OK && pin) { // don't login if pin is null. Session can be used also to read certs.
+ /* Kommentaar: Ainult CKU_USER toetatud. */
+ rv = (*ckFunc->C_Login)(hSession, CKU_USER, (unsigned char*)pin, strlen(pin));
+ ddocDebug(3, "OpenSession", "Login for slot id: %u - sess: %uld RV = %u", slotId, hSession, rv);
+ if(rv != CKR_OK)
+ hSession = CK_INVALID_HANDLE; // mark session bad!
+ }
+ // Return the session handle and exit
+ return hSession;
+}
+
+//============================================================
+// Sign a string using a private key referred by the supplied handle.
+// hSession - card session handle
+// hPrivateKey - private key handle
+// Signature - buffer for signature
+// ulSignatureLen - signature buffer length
+// sigData - data to be signed
+//============================================================
+CK_RV SignData(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hPrivateKey,
+ CK_BYTE* Signature, CK_ULONG* ulSignatureLen,
+ CK_BYTE* sigData, CK_ULONG dataLen)
+{
+ // Set up mechanism for PKCS #1 signing
+ CK_MECHANISM Mechanism = { CKM_RSA_PKCS, 0, 0 };
+ // Initiate the signature operation
+ CK_RV rv = (*ckFunc->C_SignInit)(hSession,&Mechanism,hPrivateKey);
+ if(rv == CKR_OK) {
+ // Kommentaar: Realiseeritud meetodi CKM_RSA_PKCS jaoks.
+ rv = (*ckFunc->C_Sign)(hSession, sigData, dataLen,
+ Signature, ulSignatureLen);
+ if(rv != CKR_OK)
+ ddocDebug(1, "SignData", "Error signing - sess: %u pkey: %uld slen: %uld dlen: %uld. RV = %u",
+ hSession, hPrivateKey, ulSignatureLen, dataLen, rv);
+ } // if C_SignInit
+ else
+ ddocDebug(1, "SignData", "Error initing sign session. RV = %ld", rv);
+ ddocDebug(3, "SignData", "RV = %ld", rv);
+ return rv;
+}
+
+
+//============================================================
+// Locates a certificate on the token on basis of its CKA_LABEL attribute.
+// hSession - card session handle
+// label - key label
+// return objects handle or -1 for failure
+//============================================================
+CK_OBJECT_HANDLE LocateCertificate(CK_SESSION_HANDLE hSession,
+ CK_BYTE_PTR certData, CK_ULONG_PTR certLen,
+ char idData[20][20], CK_ULONG idLen[20],
+ int* pSelKey)
+{
+ CK_OBJECT_HANDLE Objects[10];
+ CK_ULONG ulObjectCount = sizeof(Objects)/sizeof(CK_OBJECT_HANDLE), i, j;
+ CK_BYTE buf1[20];
+ CK_OBJECT_HANDLE hCert = CK_INVALID_HANDLE;
+ CK_RV rv;
+
+ // Set up a template to search for Certificate token objects
+ // in the given session and thus slot
+ CK_OBJECT_CLASS ObjClass = CKO_CERTIFICATE;
+ CK_ATTRIBUTE Template1[] = {
+ { CKA_CLASS, &ObjClass, sizeof(ObjClass) },
+ { CKA_ID, (void*)0, 0 }
+ };
+ CK_ATTRIBUTE Template3[] = {
+ { CKA_CLASS, &ObjClass, sizeof(ObjClass) },
+ };
+ CK_ATTRIBUTE Template2[] = {
+ { CKA_VALUE, (void*)0, *certLen },
+ { CKA_ID, (void*)0, 0 }
+ };
+ CK_ULONG ulCount = 0;
+
+ if(idLen)
+ ulCount = sizeof(Template1)/sizeof(CK_ATTRIBUTE);
+ else
+ ulCount = sizeof(Template3)/sizeof(CK_ATTRIBUTE);
+ *certLen = 0;
+ /*
+ ** Initiate the object search
+ C_FindObjectsInit initializes a search for token and session objects that match a template.
+ hSession is the sessions handle; pTemplate points to a search template that specifies the
+ attribute values to match; ulCount is the number of attributes in the search template. The
+ matching criterion is an exact byte-for-byte match with all attributes in the template.
+ To find all objects, set ulCount to 0.
+ */
+
+ for(j = 0; j < 20 && !(*certLen); j++) {
+ if(idLen && idLen[j]) {
+ memset(buf1, 0, sizeof(buf1));
+ memcpy(buf1, idData[j], idLen[j]);
+ Template1[1].pValue = buf1;
+ Template1[1].ulValueLen = idLen[j];
+ }
+ rv = (*ckFunc->C_FindObjectsInit)(hSession, (idLen ? Template1 : Template3), 1); //ulCount);
+ if(rv==CKR_OK) {
+ rv = (*ckFunc->C_FindObjects)(hSession,Objects,ulObjectCount, &ulObjectCount);
+ ddocDebug(3, "LocateCertificate", "search key-id: %s, found: %ld rv: %ld", buf1, ulObjectCount, rv);
+ if(rv==CKR_OK) {
+ // pick the first cert that is valid
+ // list and ignore any other
+ for(i = 0; i < ulObjectCount; i++) {
+ hCert = Objects[i];
+ memset(certData, 0, *certLen);
+ ulCount = sizeof(Template2) / sizeof(CK_ATTRIBUTE);
+ // get cert length
+ *certLen = 0;
+ Template2[1].pValue = buf1;
+ Template2[1].ulValueLen = sizeof(buf1);
+ rv = (*ckFunc->C_GetAttributeValue)(hSession, hCert, Template2, ulCount);
+ ddocDebug(3, "LocateCertificate", "cert-id: %s", buf1);
+ if(rv == CKR_OK && (!idLen ||
+ (idLen && !memcmp(idData[j], buf1, idLen[1])))) {
+ *certLen = Template2[0].ulValueLen;
+ // now get cert data
+ Template2[0].pValue = certData;
+ rv = (*ckFunc->C_GetAttributeValue)(hSession, hCert, Template2, ulCount);
+ ddocDebug(3, "LocateCertificate", "cert-len: %ld", *certLen);
+ if(*certLen > 0 && pSelKey) {
+ *pSelKey = j;
+ break; // found it
+ }
+
+ } // if rv == CKR_OK
+ } // for i < ulObjectCount
+ } // if rv
+ } // if rv
+ rv = (*ckFunc->C_FindObjectsFinal)(hSession);
+ } // for j
+ //if(hCert == CK_INVALID_HANDLE)
+ // *certLen = 0;
+ return hCert;
+}
+
+//============================================================
+// Locates a private key on the token on basis of its CKA_LABEL attribute.
+// hSession - card session handle
+// idData - address of an array of label buffers
+// idlen - array of label lengths
+// return objects handle or -1 for failure
+//============================================================
+CK_RV LocatePrivateKey(CK_SESSION_HANDLE hSession, char idData[20][20], CK_ULONG idLen[20], CK_OBJECT_HANDLE_PTR hKeys)
+{
+ CK_OBJECT_HANDLE Objects[10];
+ CK_RV rv;
+ CK_ULONG ulObjectCount = sizeof(Objects)/sizeof(CK_OBJECT_HANDLE), i;
+ // Set up a template to search for all Private Key tokens
+ // Given the session context, that is associated with
+ // one slot we will find only one object
+ CK_OBJECT_CLASS ObjClass = CKO_PRIVATE_KEY;
+ char buf1[20];
+ CK_ATTRIBUTE Template1[] = {
+ { CKA_CLASS, &ObjClass, sizeof(ObjClass) }
+ };
+ CK_ATTRIBUTE Template2[] = {
+ { CKA_ID, (void*)0, idLen[0] }
+ };
+ CK_ULONG ulCount = sizeof(Template1) / sizeof(CK_ATTRIBUTE);
+
+ /*
+ ** Initiate the object search
+ C_FindObjectsInit initializes a search for token and session objects that match a template.
+ hSession is the sessions handle; pTemplate points to a search template that specifies the
+ attribute values to match; ulCount is the number of attributes in the search template. The
+ matching criterion is an exact byte-for-byte match with all attributes in the template.
+ To find all objects, set ulCount to 0.
+ */
+ ddocDebug(3, "LocatePrivateKey", "LocatePrivateKey");
+ rv = (*ckFunc->C_FindObjectsInit)(hSession,Template1,ulCount);
+ if(rv==CKR_OK) {
+ // Get list of object handles
+ rv = (*ckFunc->C_FindObjects)(hSession,Objects,ulObjectCount, &ulObjectCount);
+ ddocDebug(3, "LocatePrivateKey", "Find: %d count: %ld", rv, ulObjectCount);
+ if(rv==CKR_OK) {
+ // get labels of all possible private keys
+ for(i = 0; i < ulObjectCount; i++) {
+ hKeys[i] = Objects[i];
+ ulCount = sizeof(Template2) / sizeof(CK_ATTRIBUTE);
+ // get key id length
+ rv = (*ckFunc->C_GetAttributeValue)(hSession, hKeys[i], Template2, ulCount);
+ if(rv == CKR_OK) {
+ idLen[i] = Template2[0].ulValueLen;
+ // now get key id data
+ Template2[0].pValue = buf1;
+ memset(buf1, 0, sizeof(buf1));
+ rv = (*ckFunc->C_GetAttributeValue)(hSession, hKeys[i], Template2, ulCount);
+ ddocDebug(3, "LocatePrivateKey", "key: %d id %s len: %ld", i, buf1, idLen[i]);
+ memcpy(idData[i], buf1, idLen[i]);
+ }
+ } // for i < ulObjectsCount
+ }
+ }
+ // Remember to call C_FindObjectsFinal to terminate the search
+ rv = (*ckFunc->C_FindObjectsFinal)(hSession);
+ return rv;
+}
+
+//============================================================
+// Locates a private key on the token on basis of its CKA_ID attribute.
+// hSession - card session handle
+// idData - id value
+// idLen - length of id value
+// hKey - address of key handle to be returned
+// return objects handle or -1 for failure
+//============================================================
+CK_RV LocatePrivateKeyWithId(CK_SESSION_HANDLE hSession, CK_BYTE_PTR idData, CK_ULONG idLen, CK_OBJECT_HANDLE_PTR hKey)
+{
+ CK_OBJECT_HANDLE Objects[10];
+ CK_RV rv;
+ CK_ULONG ulObjectCount = sizeof(Objects)/sizeof(CK_OBJECT_HANDLE), i;
+ CK_OBJECT_CLASS ObjClass = CKO_PRIVATE_KEY;
+ CK_ATTRIBUTE Template1[] = {
+ { CKA_CLASS, &ObjClass, sizeof(ObjClass) },
+ { CKA_ID, (void*)idData, idLen }
+ };
+ CK_ULONG ulCount = sizeof(Template1) / sizeof(CK_ATTRIBUTE);
+ char buf2[40];
+ int l2;
+
+ l2 = sizeof(buf2);
+ bin2hex((const byte*)idData, idLen, (char*)buf2, &l2);
+ ddocDebug(3, "LocatePrivateKeyWithId", "LocatePrivateKey with id: %s", buf2);
+ //Template1[1].pValue = idData;
+ rv = (*ckFunc->C_FindObjectsInit)(hSession, Template1, ulCount);
+ if(rv==CKR_OK) {
+ // Get list of object handles
+ rv = (*ckFunc->C_FindObjects)(hSession,Objects,ulObjectCount, &ulObjectCount);
+ ddocDebug(3, "LocatePrivateKeyWithId", "Find: %d count: %ld", rv, ulObjectCount);
+ if(rv==CKR_OK) {
+ // get labels of all possible private keys
+ for(i = 0; i < ulObjectCount; i++) {
+ ddocDebug(3, "LocatePrivateKeyWithId", "Key handle: %d", Objects[i]);
+ *hKey = Objects[i];
+ } // for i < ulObjectsCount
+ }
+ }
+ // Remember to call C_FindObjectsFinal to terminate the search
+ rv = (*ckFunc->C_FindObjectsFinal)(hSession);
+ return rv;
+}
+
+
+
+int ddocLocateSlotWithSignatureCert(LIBHANDLE pLibrary, CK_SLOT_ID* slotids,
+ CK_SLOT_ID* pSlotId, X509** ppCert,
+ char idData[20], int* pIdLen, int nSlot, int* pIdx)
+{
+ int err = ERR_PRIVKEY_READ, i, j, nMatch, l3;
+ CK_RV rv;
+ CK_SESSION_HANDLE hSession = 0;
+ CK_OBJECT_HANDLE objects[10];
+ CK_BYTE buf2[20], buf3[40];
+ CK_ULONG ulObjectCount = sizeof(objects)/sizeof(CK_OBJECT_HANDLE), ulCount = 0, l1 = 0, l2 = 0;
+ CK_OBJECT_CLASS ObjClass = CKO_CERTIFICATE;
+
+ CK_ATTRIBUTE Template1[] = {
+ { CKA_CLASS, &ObjClass, sizeof(ObjClass) }
+ };
+ CK_ATTRIBUTE Template2[] = {
+ { CKA_VALUE, (void*)0, l1 },
+ { CKA_ID, (void*)0, sizeof(buf2)}
+ };
+ char buf1[3000], buf4[64];
+ X509* pCert = 0;
+ DigiDocMemBuf mbuf1;
+
+ mbuf1.pMem = 0;
+ mbuf1.nLen = 0;
+ RETURN_IF_NULL_PARAM(pLibrary);
+ RETURN_IF_NULL_PARAM(pSlotId);
+ RETURN_IF_NULL_PARAM(slotids);
+ RETURN_IF_NULL_PARAM(idData);
+ RETURN_IF_NULL_PARAM(ppCert);
+ // mark as not found
+ memset(idData, 0, *pIdLen);
+ ddocDebug(3, "ddocLocateSlotWithSignatureCert", "Driver handle: %d err = %d", pLibrary, err);
+ // now check every slot
+ for(i = 0, nMatch = 0; (i < 20) && !(*ppCert); i++) {
+ if(slotids[i] != INVALID_SLOTIID) {
+ ddocDebug(3, "ddocLocateSlotWithSignatureCert", "Checking slot nr: %d id: %d", i, slotids[i]);
+ // open session to slot but no login since we just need the cert
+ rv = (*ckFunc->C_OpenSession)(slotids[i], CKF_SERIAL_SESSION,0,0,&hSession);
+ ddocDebug(3, "ddocLocateSlotWithSignatureCert", "Login rv: %ld session: %ld", rv, hSession);
+ if(rv == CKR_OK) {
+ ulCount = sizeof(Template1)/sizeof(CK_ATTRIBUTE);
+ rv = (*ckFunc->C_FindObjectsInit)(hSession, Template1, ulCount);
+ if(rv == CKR_OK) {
+ rv = (*ckFunc->C_FindObjects)(hSession, objects, ulObjectCount, &ulObjectCount);
+ ddocDebug(3, "ddocLocateSlotWithSignatureCert", "slot id: %ld, objects: %ld",
+ slotids[i], ulObjectCount);
+ if(rv == CKR_OK && ulObjectCount > 0) {
+ ulCount = sizeof(Template2) / sizeof(CK_ATTRIBUTE);
+ for(j = 0; j < (int)ulObjectCount; j++) {
+ l1 = sizeof(buf1);
+ memset(buf1, 0, l1);
+ l2 = sizeof(buf2);
+ memset(buf2, 0, l2);
+ Template2[0].pValue = 0; // check length first
+ rv = (*ckFunc->C_GetAttributeValue)(hSession, objects[j], Template2, ulCount);
+ if(rv == CKR_OK && Template2[0].ulValueLen < sizeof(buf1)) {
+ l1 = Template2[0].ulValueLen;
+ // now get cert data
+ Template2[0].pValue = buf1;
+ Template2[1].pValue = buf2;
+ rv = (*ckFunc->C_GetAttributeValue)(hSession, objects[j], Template2, ulCount);
+ ddocDebug(3, "ddocLocateSlotWithSignatureCert", "slot id: %ld, object: %ld cert-len: %ld rv: %ld",
+ slotids[i], j, l1, rv);
+ pCert = 0;
+ err = ddocDecodeX509Data(&pCert, (const byte*)buf1, l1);
+ if(pCert) {
+ // debug
+ memset(buf4, 0, sizeof(buf4));
+ ReadCertSerialNumber(buf4, sizeof(buf4), pCert);
+ ddocCertGetSubjectCN(pCert, &mbuf1);
+ ddocDebug(3, "ddocLocateSlotWithSignatureCert", "slot id: %ld, object: %ld cert-serial: %s CN: %s",
+ slotids[i], j, buf4, (char*)mbuf1.pMem);
+ if(ddocCertCheckKeyUsage(pCert, KUIDX_NON_REPUDIATION)) {
+ if((!nSlot || nSlot == nMatch) && !(*ppCert)) {
+ l3 = sizeof(buf3);
+ memset(buf3, 0, l3);
+ bin2hex((const byte*)buf2, (int)Template2[1].ulValueLen, (char*)buf3, &l3);
+ ddocDebug(3, "ddocLocateSlotWithSignatureCert", "Selecting slot: %d id: %d key-id %s", i, slotids[i], buf3);
+ *pSlotId = slotids[i];
+ *pIdx = i;
+ // keep this cert for signing
+ if(*ppCert)
+ X509_free(*ppCert);
+ (*ppCert) = pCert;
+ pCert = NULL; // mark as used
+ memcpy(idData, buf2, Template2[1].ulValueLen);
+ *pIdLen = Template2[1].ulValueLen;
+ err = ERR_OK; // found it
+ ddocDebug(3, "ddocLocateSlotWithSignatureCert", "Selected key/cert: %s - %s", buf4, (char*)mbuf1.pMem);
+ } else { // useable slot but not a match by slot id
+ ddocDebug(3, "ddocLocateSlotWithSignatureCert", "Useable slot: %d but search: %d", nMatch, nSlot);
+ nMatch++;
+ }
+ } // if non-repu cert
+ ddocMemBuf_free(&mbuf1);
+ } // if pCert
+ if(pCert)
+ X509_free(pCert);
+ pCert = 0;
+
+ } // if get-attribute ok
+ } // for j < ulObjectCount
+ } // if found any certs
+ } // if find-init ok
+ rv = (*ckFunc->C_FindObjectsFinal)(hSession);
+ } // if login ok
+ rv = (*ckFunc->C_CloseSession)(hSession);
+ } // if slotid
+ } // for i
+
+ return err;
+}
+
+extern void dumpInFile(const char* fileName, const char* data);
+
+//============================================================
+// Calculates and stores a signature for this SignatureInfo object
+// Uses EstEID card to sign the info
+// pSigInfo - signature info object
+// nSigType - signature type code
+// keyfile - RSA key file
+// passwd - key password
+// certfile - certificate file
+//============================================================
+EXP_OPTION int calculateSignatureWithEstID(SignedDoc* pSigDoc, SignatureInfo* pSigInfo,
+ int slot, const char* passwd)
+{
+ int err = ERR_OK, nKey;
+ LIBHANDLE pLibrary = 0;
+ CK_ULONG certLen, sigLen, padDigLen;
+ CK_RV rv;
+ CK_SLOT_ID slotids[20], slId = 0;
+ CK_SESSION_HANDLE hSession = 0;
+ CK_OBJECT_HANDLE hPrivateKey = 0, hKeys[20], hCert;
+ char keyId[20][20], kId[20];
+ CK_ULONG keyIdLen[20];
+ CK_BYTE certData[2048];
+ CK_BYTE sigDig[100], padDig[130];
+ CK_BYTE signature[256];
+ CK_BYTE padding[] = { 48, 33, 48, 9, 6, 5, 43, 14, 3, 2, 26, 5, 0, 4, 20 };
+ //CK_BYTE padding256[] = { 48, 49, 48, 13, 6, 9, 96, 134, 72, 1 ,101, 3, 4, 2, 1, 5, 0, 4, 32};
+ //CK_BYTE padding256[] = { 48, 33, 48, 13, 6, 9, 96, 134, 72, 1 ,101, 3, 4, 2, 1, 5, 0, 4, 32};
+ char* buf1;
+ int l1, l2, kILen;
+ X509* x509 = 0;
+ DigiDocMemBuf mbuf1;
+
+ RETURN_IF_NULL_PARAM(pSigInfo);
+ RETURN_IF_NULL_PARAM(pSigDoc);
+ // try active driver driver first
+ snprintf((char*)signature, sizeof(signature), "DIGIDOC_DRIVER_%d_FILE",
+ ConfigItem_lookup_int("DIGIDOC_DEFAULT_DRIVER", 1));
+ for(l1 = 0; l1 < 20; l1++)
+ slotids[l1] = INVALID_SLOTIID; // initialize
+ err = loadAndTestDriver(ConfigItem_lookup((const char*)signature),
+ &pLibrary, (CK_SLOT_ID*)slotids, 20, (CK_ULONG)slot);
+ ddocDebug(3, "calculateSignatureWithEstID", "Driver handle: %d err = %d slot: %d",
+ pLibrary, err, slot);
+ RETURN_IF_NOT(err == ERR_OK, err);
+ // inittialize
+ slId = INVALID_SLOTIID; // not found yet
+ // try key-usage check
+ if(ConfigItem_lookup_int("KEY_USAGE_CHECK", 1)) {
+ kILen = sizeof(kId);
+ ddocDebug(3, "calculateSignatureWithEstID", "Find slot by key-usage, slot: %d", slot);
+ err = ddocLocateSlotWithSignatureCert(pLibrary, slotids, &slId, &x509, kId, &kILen, slot, &l1);
+ ddocDebug(3, "calculateSignatureWithEstID",
+ "Select by key-usage slot idx: %d = %d err: %d key-id: %s, kid-len: %d", l1, slId, err, kId, kILen);
+ if(err != ERR_OK || l1 < 0 || l1 >= 20) {
+ SET_LAST_ERROR(ERR_SIGNERS_CERT_NON_REPU);
+ return ERR_SIGNERS_CERT_NON_REPU;
+ }
+ } else {
+ ddocDebug(3, "calculateSignatureWithEstID", "Find slot by slot idx: %d", slot);
+ for(l1 = 0; (l1 < 20) && (slId == INVALID_SLOTIID); l1++) {
+ if(slotids[l1] != INVALID_SLOTIID)
+ ddocDebug(3, "calculateSignatureWithEstID",
+ "Slot idx: %d = %d", l1, slotids[l1]);
+ if(slotids[l1] != INVALID_SLOTIID && l1 == slot) {
+ slId = slotids[l1];
+ ddocDebug(3, "calculateSignatureWithEstID",
+ "Select idx: %d slot: %d", l1, slId);
+ } // if slotid
+ } // for
+ }
+ // use default if not found by key-id or direct
+ if(slId == INVALID_SLOTIID) {
+ l1 = ConfigItem_lookup_int("DIGIDOC_SIGNATURE_SLOT", 0);
+ if(slotids[l1] != INVALID_SLOTIID) {
+ ddocDebug(3, "calculateSignatureWithEstID",
+ "Select default slot idx: %d = %d", l1, slotids[l1]);
+ slId = slotids[l1];
+ }
+ }
+
+ // open session
+ if(slId != INVALID_SLOTIID) {
+ hSession = OpenSession(slId, passwd);
+ ddocDebug(3, "calculateSignatureWithEstID",
+ "Open sess for slot: %d sess = %d", slId, hSession);
+ if (hSession == CK_INVALID_HANDLE) { err = ERR_PKCS_LOGIN; SET_LAST_ERROR(err); return err; }
+ ddocDebug(3, "calculateSignatureWithEstID", "OpenSession ok, hSession1 = %d", (int)hSession);
+
+ if(!x509) {
+ ddocDebug(3, "calculateSignatureWithEstID", "Cert ok");
+ // get private key
+ for(l1 = 0; l1 < 20; l1++) {
+ memset(keyId[l1], 0, 20);
+ keyIdLen[l1] = 0;
+ }
+ err = LocatePrivateKey(hSession, keyId, keyIdLen, hKeys);
+ //ddocDebug(3, "calculateSignatureWithEstID", "Priv key: %s", keyId);
+ //
+
+ // get cert
+ memset(certData, 0, sizeof(certData));
+ certLen = sizeof(certData);
+ hCert = LocateCertificate(hSession, certData, &certLen, keyId, keyIdLen, &nKey);
+ hPrivateKey = hKeys[nKey];
+ ddocDebug(3, "calculateSignatureWithEstID", "selected priv-key: %ld pos %d id: %s", hPrivateKey, nKey, keyId[nKey]);
+ ddocDebug(3, "calculateSignatureWithEstID", "Cert-len: %ld", certLen);
+ //printf("Cert: %s", certData);
+ if (hCert == (CK_OBJECT_HANDLE)-1) { err = ERR_PKCS_CERT_LOC; SET_LAST_ERROR(err); return err; }
+
+ // set cert data
+ err = ddocDecodeX509Data(&x509, certData, certLen);
+
+
+ } else { // cert already found
+ //kILen = sizeof(kId);
+ ddocDebug(3, "calculateSignatureWithEstID", "Locate priv key2 id: %s, len: %d, hkey: %d", kId, kILen, hPrivateKey);
+ err = LocatePrivateKeyWithId(hSession, (CK_BYTE_PTR)kId, kILen, &hPrivateKey);
+ ddocDebug(3, "calculateSignatureWithEstID", "Priv key-id: %s len: %d hkey: %d err: %d", kId, kILen, hPrivateKey, err);
+ }
+ ddocDebug(3, "calculateSignatureWithEstID", "Priv key: %d err: %d", hPrivateKey, err);
+ if (hPrivateKey == CK_INVALID_HANDLE) { err = ERR_PKCS_PK; SET_LAST_ERROR(err); return err; }
+ if (!x509) { err = ERR_PKCS_CERT_DECODE; }
+
+ // save cert in file
+ if(ConfigItem_lookup_int("DEBUG_LEVEL", 1) > 3)
+ saveCert(x509, "signer.pem", FILE_FORMAT_PEM);
+ setSignatureCert(pSigInfo, x509);
+
+ // FIXME
+ createTimestamp(pSigDoc, (char*)sigDig, sizeof(sigDig));
+ setString((char**)&(pSigInfo->szTimeStamp), (const char*)sigDig, -1);
+
+ // Signed properties digest
+ buf1 = createXMLSignedProperties(pSigDoc, pSigInfo, 0);
+ //dumpInFile("sigprop-sign1.txt", buf1);
+ if (!buf1) {
+ err = ERR_NULL_POINTER;
+ SET_LAST_ERROR(err);
+ return err;
+ }
+ mbuf1.pMem = canonicalizeXML((char*)buf1, strlen(buf1));
+ mbuf1.nLen = strlen((const char*)mbuf1.pMem);
+ ddocDebugWriteFile(4, "sigprop-signed.txt", &mbuf1);
+ l2 = sizeof(sigDig);
+ err = calculateDigest((const byte*)mbuf1.pMem, mbuf1.nLen, DIGEST_SHA1, sigDig, &l2);
+ free(buf1);
+ ddocMemBuf_free(&mbuf1);
+ if (err != ERR_OK) {
+ SET_LAST_ERROR(err);
+ return err;
+ }
+ ddocSigInfo_SetSigPropDigest(pSigInfo, (const char*)sigDig, l2);
+ ddocSigInfo_SetSigPropRealDigest(pSigInfo, (const char*)sigDig, l2);
+ // create signed info
+ buf1 = createXMLSignedInfo(pSigDoc, pSigInfo);
+ if (!buf1) {
+ err = ERR_NULL_POINTER;
+ SET_LAST_ERROR(err);
+ return err ;
+ }
+ // get digest
+ l2 = sizeof(sigDig);
+ err = calculateDigest((const byte*)buf1, strlen(buf1), DIGEST_SHA1, sigDig, &l2);
+ free(buf1);
+ if (err != ERR_OK) {
+ err = ERR_NULL_POINTER;
+ SET_LAST_ERROR(err);
+ return err;
+ }
+ ddocSigInfo_SetSigInfoRealDigest(pSigInfo, (const char*)sigDig, l2);
+ // sign data
+ sigLen = sizeof(signature);
+ memset(signature, 0, sizeof(signature));
+ // pad PKCS#1 ver 1
+ padDigLen = 35;
+ memset(padDig, 0, sizeof(padDig));
+ memcpy(padDig, padding, 15);
+ memcpy(padDig + 15, sigDig, l2);
+ //rv = RSA_padding_add_PKCS1_type_1(padDig, padDigLen, sigDig, l2);
+ //rv = RSA_padding_check_PKCS1_type_1(sigDig, l2, padDig, padDigLen, padDigLen+1);
+ // checkErrors();
+ // sign data
+ rv = SignData(hSession, hPrivateKey,
+ signature, &sigLen, padDig, padDigLen);
+ if (rv != CKR_OK) {
+ err = ERR_PKCS_SIGN_DATA;
+ SET_LAST_ERROR(err);
+ return err;
+ }
+
+ // set signature value
+ ddocSigInfo_SetSignatureValue(pSigInfo, (const char*)signature, (int)sigLen);
+ ddocDebug(3, "calculateSignatureWithEstID", "Sig-len: %ld", sigLen);
+
+ } // if slotid found
+
+ if(hSession)
+ closePKCS11Library(pLibrary, hSession);
+ return err;
+}
+
+//============================================================
+// Loads the PKCS#11 driver and
+// tests if the driver loaded correctly
+// Returns 0 for ok otherwise error code
+//============================================================
+EXP_OPTION CK_RV getDriverInfo(CK_INFO_PTR pInfo)
+{
+ return (*ckFunc->C_GetInfo)(pInfo);
+}
+
+//============================================================
+// Decrypts RSA encrypted data with the private key
+// slot - number of the slot for decryption key. On ID card allways 0
+// pin - corresponding pin for the key. On ID card - PIN1
+// encData - encrypted data
+// encLen - length of encrypted data
+// decData - buffer for decrypted data
+// encLen - length of buffer. Will be modified by amount of decrypted data
+// return error code or ERR_OK
+//============================================================
+EXP_OPTION int decryptWithEstID(int slot, const char* pin,
+ const char* encData, int encLen,
+ char* decData, int *decLen)
+{
+ int err = ERR_OK, l1, l2;
+ LIBHANDLE pLibrary = 0;
+ CK_ULONG keyIdLen[20];
+ CK_RV rv;
+ CK_SLOT_ID slotids[20], slId;
+ CK_SESSION_HANDLE hSession = 0;
+ CK_OBJECT_HANDLE hPrivateKey, hKeys[20];
+ char keyId[20][20];
+ char driver[100];
+ CK_MECHANISM Mechanism = { CKM_RSA_PKCS, 0, 0 };
+ CK_ULONG outlen;
+
+ ddocDebug(3, "decryptWithEstID", "slot: %d enc-data: %d bytes buffer size: %d", slot, encLen, *decLen);
+ snprintf(driver, sizeof(driver), "DIGIDOC_DRIVER_%d_FILE", ConfigItem_lookup_int("DIGIDOC_DEFAULT_DRIVER", 1));
+ ddocDebug(3, "decryptWithEstID", "Driver nr: %d - %s",
+ ConfigItem_lookup_int("DIGIDOC_DEFAULT_DRIVER", 1),
+ ConfigItem_lookup(driver));
+ err = loadAndTestDriver(ConfigItem_lookup(driver),
+ &pLibrary, (CK_SLOT_ID*)slotids, 20, (CK_ULONG)slot);
+ if(err) return err;
+
+ // find the right slotid
+ for(l1 = l2 = 0; l1 < 20; l1++) {
+ if(slotids[l1] != INVALID_SLOTIID) {
+ if(l2 == slot)
+ slId = slotids[l1];
+ l2++;
+ }
+ }
+ // open session
+ //ddocDebug(3, "decryptWithEstID", "OpenSession id = %d, pin: %s", (int)slId, pin);
+ hSession = OpenSession(slId, pin);
+ if (hSession == CK_INVALID_HANDLE) { SET_LAST_ERROR(ERR_PKCS_LOGIN); return ERR_PKCS_LOGIN; }
+ ddocDebug(3, "decryptWithEstID", "OpenSession ok, hSession = %d", (int)hSession);
+
+ // get private key
+ for(l1 = 0; l1 < 20; l1++) {
+ memset(keyId[l1], 0, 20);
+ keyIdLen[l1] = 0;
+ }
+ err = LocatePrivateKey(hSession, keyId, keyIdLen, hKeys);
+ hPrivateKey = hKeys[0]; //???
+ //ddocDebug(3, "decryptWithEstID", "Priv key: %s", keyId);
+ //if (hPrivateKey == CK_INVALID_HANDLE) { SET_LAST_ERROR(ERR_PKCS_PK); return ERR_PKCS_PK; }
+ // init decrypt
+ rv = (*ckFunc->C_DecryptInit)(hSession, &Mechanism, hPrivateKey);
+ ddocDebug(3, "decryptWithEstID", "DecryptInit: %d", (int)rv);
+ if(rv != CKR_OK) SET_LAST_ERROR_RETURN(ERR_DENC_DECRYPT, ERR_DENC_DECRYPT)
+ // decrypt data
+ outlen = *decLen;
+ rv = (*ckFunc->C_Decrypt)(hSession, (CK_BYTE_PTR)encData, (CK_ULONG)encLen, (CK_BYTE_PTR)decData, (CK_ULONG_PTR)&outlen);
+ *decLen = outlen;
+ ddocDebug(3, "decryptWithEstID", "RV: %d, dec-len: %d", (int)rv, *decLen);
+ if(hSession)
+ closePKCS11Library(pLibrary, hSession);
+ if(rv != CKR_OK)
+ SET_LAST_ERROR_RETURN(ERR_DENC_DECRYPT, ERR_DENC_DECRYPT)
+ return err;
+}
+
+
+//============================================================
+// Locates and reads users certificate from smartcard
+// slot - number of the slot for decryption key. On ID card allways 0
+// ppCert - address for newly allocated certificate pointer
+// return error code or ERR_OK
+//============================================================
+EXP_OPTION int findUsersCertificate(int slot, X509** ppCert)
+{
+ int err = ERR_OK, l1, l2;
+ LIBHANDLE pLibrary = 0;
+ CK_RV rv = 0;
+ CK_SLOT_ID slotids[20], slId;
+ CK_OBJECT_HANDLE hCert;
+ CK_SESSION_HANDLE hSession = 0;
+ CK_ULONG certLen;
+ CK_BYTE certData[2048];
+ char driver[100];
+
+
+ *ppCert = 0;
+ snprintf(driver, sizeof(driver), "DIGIDOC_DRIVER_%d_FILE", ConfigItem_lookup_int("DIGIDOC_DEFAULT_DRIVER", 1));
+ ddocDebug(3, "findUsersCertificate", "Slot: %d Driver nr: %d - %s", slot,
+ ConfigItem_lookup_int("DIGIDOC_DEFAULT_DRIVER", 1),
+ ConfigItem_lookup(driver));
+ err = loadAndTestDriver(ConfigItem_lookup(driver),
+ &pLibrary, (CK_SLOT_ID*)slotids, 20, (CK_ULONG)slot);
+ if(err) return err;
+ //debug
+ for(l1 = l2 = 0; l1 < 20; l1++) {
+ if(slotids[l1] != INVALID_SLOTIID) {
+ ddocDebug(3, "findUsersCertificate", "Slot1: %d, id %d", l1, slotids[l1]);
+ }
+ }
+ // find the right slotid
+ for(l1 = l2 = 0; l1 < 20; l1++) {
+ if(slotids[l1] != INVALID_SLOTIID) {
+ ddocDebug(3, "findUsersCertificate", "Slot2: %d, id %d", l1, slotids[l1]);
+ if(l2 == slot)
+ slId = slotids[l1];
+ l2++;
+ }
+ }
+ // open session
+ ddocDebug(3, "findUsersCertificate", "OpenSession slotid %d", slId);
+ hSession = OpenSession(slId, NULL);
+ if (hSession == CK_INVALID_HANDLE) { SET_LAST_ERROR(ERR_PKCS_LOGIN); return ERR_PKCS_LOGIN; }
+ ddocDebug(3, "findUsersCertificate", "OpenSession ok, hSession = %d", (int)hSession);
+
+ // get cert
+ memset(certData, 0, sizeof(certData));
+ certLen = sizeof(certData);
+ hCert = LocateCertificate(hSession, certData, &certLen, 0, 0, 0);
+ ddocDebug(3, "findUsersCertificate", "hCert = %d, len: %d", (int)hCert, certLen);
+ if (hCert == (CK_OBJECT_HANDLE)-1) { err = ERR_PKCS_CERT_LOC; SET_LAST_ERROR(err); }
+
+ // set cert data
+ if(certLen)
+ err = ddocDecodeX509Data(ppCert, certData, certLen);
+
+
+ ddocDebug(3, "findUsersCertificate", "RV: %d, cert: %s", (int)rv, (*ppCert ? "OK" : "NULL"));
+ if(hSession)
+ closePKCS11Library(pLibrary, hSession);
+
+ return err;
+}
+
+
diff --git a/libdigidoc/DigiDocPKCS11.h b/libdigidoc/DigiDocPKCS11.h
new file mode 100644
index 0000000..5491e76
--- /dev/null
+++ b/libdigidoc/DigiDocPKCS11.h
@@ -0,0 +1,86 @@
+#ifndef __DIGI_DOC_PKCS11_H__
+#define __DIGI_DOC_PKCS11_H__
+//==================================================
+// FILE: DigiDocPKCS11.h
+// PROJECT: Digi Doc
+// DESCRIPTION: Digi Doc functions for signing using PKCS#11 API
+// AUTHOR: Veiko Sinivee, S|E|B IT Partner Estonia
+//==================================================
+// Copyright (C) AS Sertifitseerimiskeskus
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+// GNU Lesser General Public Licence is available at
+// http://www.gnu.org/copyleft/lesser.html
+//==========< HISTORY >=============================
+// 13.01.2004 Veiko Sinivee
+// Creation
+//==================================================
+
+#include <libdigidoc/DigiDocDefs.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef WIN32
+ #include <windows.h>
+ #define LIBHANDLE HANDLE
+ #include "pkcs11/cryptoki.h"
+#else
+ #include <dlfcn.h> // Linux .so loading interface
+ #define LIBHANDLE void*
+ #include "pkcs11/pkcs11.h"
+#endif
+
+
+
+#include <libdigidoc/DigiDocLib.h>
+#include <openssl/ocsp.h>
+
+
+EXP_OPTION LIBHANDLE initPKCS11Library(const char* libName);
+EXP_OPTION void closePKCS11Library(LIBHANDLE pLibrary, CK_SESSION_HANDLE hSession);
+EXP_OPTION int calculateSignatureWithEstID(SignedDoc* pSigDoc, SignatureInfo* pSigInfo,
+ int slot, const char* passwd);
+
+EXP_OPTION CK_RV GetSlotIds(CK_SLOT_ID_PTR pSlotids, CK_ULONG_PTR pLen);
+EXP_OPTION CK_RV GetTokenInfo(CK_TOKEN_INFO_PTR pTokInfo, CK_SLOT_ID id);
+int loadAndTestDriver(const char* driver, LIBHANDLE* pLibrary, CK_SLOT_ID* slotids,
+ int slots, CK_ULONG slot);
+EXP_OPTION CK_RV getDriverInfo(CK_INFO_PTR pInfo);
+EXP_OPTION CK_RV GetSlotInfo(CK_SLOT_INFO_PTR pSlotInfo, CK_SLOT_ID id);
+
+//============================================================
+// Decrypts RSA encrypted data with the private key
+// slot - number of the slot for decryption key. On ID card allways 0
+// pin - corresponding pin for the key. On ID card - PIN1
+// encData - encrypted data
+// encLen - length of encrypted data
+// decData - buffer for decrypted data
+// encLen - length of buffer. Will be modified by amount of decrypted data
+// return error code or ERR_OK
+//============================================================
+EXP_OPTION int decryptWithEstID(int slot, const char* pin,
+ const char* encData, int encLen,
+ char* decData, int *decLen);
+
+//============================================================
+// Locates and reads users certificate from smartcard
+// slot - number of the slot for decryption key. On ID card allways 0
+// ppCert - address for newly allocated certificate pointer
+// return error code or ERR_OK
+//============================================================
+EXP_OPTION int findUsersCertificate(int slot, X509** ppCert);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // __DIGI_DOC_PKCS11_H__
+
diff --git a/libdigidoc/DigiDocParser.c b/libdigidoc/DigiDocParser.c
new file mode 100644
index 0000000..0b9b4a4
--- /dev/null
+++ b/libdigidoc/DigiDocParser.c
@@ -0,0 +1,1243 @@
+//==================================================
+// FILE: DigiDocParser.c
+// PROJECT: Digi Doc
+// DESCRIPTION: Digi Doc functions for xml parsing
+// AUTHOR: Veiko Sinivee, S|E|B IT Partner Estonia
+//==================================================
+// Copyright (C) AS Sertifitseerimiskeskus
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+// GNU Lesser General Public Licence is available at
+// http://www.gnu.org/copyleft/lesser.html
+//==========< HISTORY >=============================
+// 10.07.2004 Veiko Sinivee
+// Creation
+//==================================================
+
+// config data comes from there
+#ifndef WIN32
+ #if HAVE_CONFIG_H
+ #include <config.h>
+ #endif
+#endif // no win32
+
+#include <libdigidoc/DigiDocDefs.h>
+#include <libdigidoc/DigiDocConvert.h>
+#include <libdigidoc/DigiDocCert.h>
+#include <libdigidoc/DigiDocParser.h>
+#include <libdigidoc/DigiDocDebug.h>
+#include <libdigidoc/DigiDocStack.h>
+#include <libdigidoc/DigiDocMem.h>
+#include <libdigidoc/DigiDocLib.h>
+#include <libdigidoc/DigiDocOCSP.h>
+
+#include <libxml/xmlreader.h>
+#include <string.h>
+#define MAX_FILENAME 255
+
+//=====================< DataFile extraction function >=============================
+
+#define EXTRACT_OP_WITH_TAGS 1 // copy <DataFile> with enclosing XML tags
+#define EXTRACT_OP_NO_TAGS 2 // copy <DataFile> content, no changes, no decoding but no tags
+#define EXTRACT_OP_BODY_ONLY 3 // copy only the <DataFile> content and base64 decode if necessary
+#define EXTRACT_OP_BODY_MEM 4 // return the <DataFile> content in memory and base64 decode if necessary
+#define MAX_CONTENT_TYPE 50 // maximum length for ContentType atribute
+
+extern char* canonicalizeXML(char* source, int len);
+
+
+
+
+
+//--------------------------------------------------
+// Processes node contents. This function is used
+// internally and not meant to be called directly
+// by the users of this library!
+// reader - XML reader cursor to current node
+// phFile - address of FILE pointer. Used also as flag: searching/storing
+// szDocId - Id atribute value of <DataFile> to extract
+// szDataFile - name of file to stor it in
+// operation - operation code:
+// EXTRACT_OP_WITH_TAGS = copy <DataFile> with enclosing XML tags
+// EXTRACT_OP_BODY_ONLY = copy only the <DataFile> content and base64 decode if necessary
+// pszContentType - address of DataFile content type atribute value
+// pBuf - address of memory buffer for EXTRACT_OP_BODY_MEM
+//--------------------------------------------------
+int ddocExtractProcessNode(xmlTextReaderPtr reader, FILE** phFile,
+ const char* szDocId, const char* szDataFile,
+ int operation, char* pszContentType, DigiDocMemBuf* pBuf)
+{
+ int err = ERR_OK, n;
+ xmlChar *name = 0, *value = 0, *an, *av, *p;
+
+ RETURN_IF_NULL_PARAM(reader);
+ RETURN_IF_NULL_PARAM(phFile);
+ RETURN_IF_NULL_PARAM(szDocId);
+ RETURN_IF_NULL_PARAM(pszContentType);
+ name = xmlTextReaderName(reader);
+ ddocDebug(4, "ddocExtractProcessNode", "Node %d, name: %s depth: %d",
+ xmlTextReaderNodeType(reader), (name ? (char*)name : "-"), xmlTextReaderDepth(reader));
+ if(name) {
+ xmlFree(name);
+ name = 0;
+ }
+ switch(xmlTextReaderNodeType(reader)) {
+ case XML_READER_TYPE_ELEMENT:
+ name = xmlTextReaderName(reader);
+ if(name) {
+ if(!xmlStrcmp(name, (xmlChar*)"DataFile") && !*phFile) { // possible start
+ value = xmlTextReaderGetAttribute(reader, (const xmlChar*)"Id");
+ if(value) {
+ ddocDebug(4, "ddocExtractProcessNode", "DataFile Id=%s, search: %s", (const char*)value, szDocId);
+ if(!xmlStrcmp(value, (xmlChar*)szDocId)) { // found it
+ ddocDebug(4, "ddocExtractProcessNode", "open file: %s", szDataFile);
+ if(operation == EXTRACT_OP_BODY_MEM) {
+ *phFile = (FILE*)1; // we return in memory. Set this dummy value to indicate start of searched data
+ } else {
+ RETURN_IF_NULL_PARAM(szDataFile);
+ *phFile = fopen(szDataFile, "wb"); // open file for it
+ }
+ if(!*phFile) {
+ ddocDebug(1, "ddocExtractProcessNode", "Failed to open file: %s", szDataFile);
+ SET_LAST_ERROR_RETURN_CODE(ERR_FILE_WRITE);
+ } else
+ if(operation != EXTRACT_OP_BODY_MEM)
+ ddocDebug(4, "ddocExtractProcessNode", "Successfully opened file: %s", szDataFile);
+ }
+ xmlFree(value);
+ value = xmlTextReaderGetAttribute(reader, (const xmlChar*)"ContentType");
+ if(value) {
+ ddocDebug(4, "ddocExtractProcessNode", "ContentType=%s", (const char*)value);
+ strncpy(pszContentType, (const char*)value, MAX_CONTENT_TYPE-1);
+ pszContentType[MAX_CONTENT_TYPE-1] = 0;
+ xmlFree(value);
+ }
+ }
+ if(*phFile &&
+ ((operation == EXTRACT_OP_WITH_TAGS && !xmlStrcmp(name, (xmlChar*)"DataFile")) ||
+ xmlStrcmp(name, (xmlChar*)"DataFile"))) {
+ if(operation == EXTRACT_OP_BODY_MEM) {
+ RETURN_IF_NULL_PARAM(pBuf);
+ err = ddocMemAppendData(pBuf, "<", -1);
+ err = ddocMemAppendData(pBuf, (const char*)name, -1);
+ } else {
+ fprintf(*phFile, "<%s", name);
+ }
+ while(xmlTextReaderMoveToNextAttribute(reader)) {
+ an = av = 0;
+ an = xmlTextReaderName(reader);
+ av = xmlTextReaderValue(reader);
+ if(operation == EXTRACT_OP_BODY_MEM) {
+ RETURN_IF_NULL_PARAM(pBuf);
+ err = ddocMemAppendData(pBuf, " ", -1);
+ err = ddocMemAppendData(pBuf, (const char*)an, -1);
+ err = ddocMemAppendData(pBuf, "=\"", -1);
+ err = ddocMemAppendData(pBuf, (const char*)av, -1);
+ err = ddocMemAppendData(pBuf, "\"", -1);
+ } else
+ fprintf(*phFile, " %s=\"%s\"", (const char*)an, (const char*)av);
+ if(an)
+ xmlFree(an);
+ if(av)
+ xmlFree(av);
+ }
+ if(operation == EXTRACT_OP_BODY_MEM) {
+ RETURN_IF_NULL_PARAM(pBuf);
+ err = ddocMemAppendData(pBuf, ">", -1);
+ } else {
+ fputs(">", *phFile);
+ }
+ }
+ }
+ if(name)
+ xmlFree(name);
+ }
+ break;
+ case XML_READER_TYPE_END_ELEMENT:
+ name = xmlTextReaderName(reader);
+ // handle end element
+ if(*phFile &&
+ ((operation == EXTRACT_OP_WITH_TAGS && !xmlStrcmp(name, (xmlChar*)"DataFile")) ||
+ xmlStrcmp(name, (xmlChar*)"DataFile"))) {
+ if(operation == EXTRACT_OP_BODY_MEM) {
+ RETURN_IF_NULL_PARAM(pBuf);
+ err = ddocMemAppendData(pBuf, "</", -1);
+ err = ddocMemAppendData(pBuf, (const char*)name, -1);
+ err = ddocMemAppendData(pBuf, ">", -1);
+ } else {
+ fprintf(*phFile, "</%s>", name);
+ }
+ }
+ // check if it's the correct end element
+ if(!xmlStrcmp(name, (xmlChar*)"DataFile")) { // possible end
+ if(*phFile && *phFile != (FILE*)1) { // file opened then it's the correct end element
+ err = -1;
+ ddocDebug(4, "ddocExtractProcessNode", "close file: %s", szDataFile);
+ fclose(*phFile);
+ }
+ if(*phFile)
+ *phFile = 0;
+ }
+ // PR. fix mem leak
+ if(name)
+ xmlFree(name);
+ break;
+ case XML_READER_TYPE_ATTRIBUTE:
+ break;
+ case XML_READER_TYPE_TEXT:
+ // handle text node
+ if(*phFile) {
+ value = xmlTextReaderValue(reader);
+ if(value) {
+ ddocDebug(4, "ddocExtractProcessNode", "TEXT: \'%s\'", (const char*)value);
+ if(operation != EXTRACT_OP_WITH_TAGS &&
+ operation != EXTRACT_OP_NO_TAGS &&
+ !strcmp(pszContentType, CONTENT_EMBEDDED_BASE64)) {
+ n = strlen((const char*)value)+1; // decoding will make it 25% smaller, so this must be enough
+ p = (xmlChar*)malloc(n);
+ if(p) {
+ decode((const byte*)value, strlen((const char*)value), p, &n);
+ ddocDebug(4, "ddocExtractProcessNode", "Decoded: %d bytes", n);
+ if(operation == EXTRACT_OP_BODY_MEM) {
+ RETURN_IF_NULL_PARAM(pBuf);
+ err = ddocMemAppendData(pBuf, (const char*)p, n);
+ }
+ else {
+ n = fwrite(p, 1, n, *phFile);
+ ddocDebug(4, "ddocExtractProcessNode", "Wrote: %d bytes", n);
+ }
+ free(p);
+ }
+ } else {
+ // in memory we don't really want the escapes or do we ?
+ if(operation == EXTRACT_OP_BODY_MEM) {
+ RETURN_IF_NULL_PARAM(pBuf);
+ err = ddocMemAppendData(pBuf, (const char*)value, -1);
+ } else {
+ // convert xml special symbols to escapes on output
+ for(n = 0; value[n]; n++) {
+ switch(value[n]) {
+ case '<': fputs("&lt;", *phFile); break;
+ case '>': fputs("&gt;", *phFile); break;
+ case '&': fputs("&amp;", *phFile); break;
+ case '\'': fputs("&apos;", *phFile); break;
+ case '\"': fputs("&quot;", *phFile); break;
+ default: fputc(value[n], *phFile); break;
+ }
+ }
+ }
+ }
+ xmlFree(value);
+ }
+ }
+ break;
+ case XML_READER_TYPE_CDATA:
+ case XML_READER_TYPE_ENTITY_REFERENCE:
+ case XML_READER_TYPE_ENTITY:
+ case XML_READER_TYPE_PROCESSING_INSTRUCTION:
+ case XML_READER_TYPE_COMMENT:
+ case XML_READER_TYPE_DOCUMENT:
+ case XML_READER_TYPE_DOCUMENT_TYPE:
+ case XML_READER_TYPE_DOCUMENT_FRAGMENT:
+ case XML_READER_TYPE_NOTATION:
+ break;
+ }
+ ddocDebug(4, "ddocExtractProcessNode", "Err %d", err);
+ return err;
+}
+
+
+//--------------------------------------------------
+// Reads in signed XML document and extracts the desired data file
+// pSigDoc - signed document object if cached
+// szFileName - name of digidoc file
+// szDataFileName - name of new data file
+// szDocId - id if DataFile
+// szCharset - output charset
+//--------------------------------------------------
+EXP_OPTION int ddocXRdrExtractDataFile(SignedDoc* pSigDoc, const char* szFileName,
+ const char* szDataFileName, const char* szDocId, const char* szCharset)
+{
+ char szConvDigiDocName[MAX_FILENAME+1];
+ char szConvDataFileName[MAX_FILENAME+1];
+ char szContentType[MAX_CONTENT_TYPE+1];
+ xmlTextReaderPtr reader;
+ FILE* hFile = 0;
+ int ret;
+ long len;
+ void* pBuf;
+
+ // check input params
+ ddocDebug(3, "ddocXRdrExtractDataFile", "SigDoc: %s, digidoc: %s, datafile: %s, output file: %s, charset: %s",
+ (pSigDoc ? "OK" : "NULL"), szFileName, szDocId, szDataFileName, szCharset);
+ RETURN_IF_NULL_PARAM(szFileName);
+ RETURN_IF_NULL_PARAM(szDataFileName);
+ RETURN_IF_NULL_PARAM(szDocId);
+ RETURN_IF_NULL_PARAM(szCharset);
+ szContentType[0] = 0;
+ clearErrors();
+ // converts file names if necessary
+ ddocConvertFileName(szConvDataFileName, sizeof(szConvDataFileName), szDataFileName);
+ ddocConvertFileName(szConvDigiDocName, sizeof(szConvDigiDocName), szFileName);
+
+ // try reading from memory if already cached?
+ ret = ddocGetDataFileCachedData(pSigDoc, szDocId, &pBuf, &len);
+ if(pBuf) { // gotcha
+ ddocDebug(4, "ddocXRdrExtractDataFile", "Using cached data: %d bytes", len);
+ if((hFile = fopen(szConvDataFileName, "wb")) != NULL) {
+ fwrite(pBuf, 1, len, hFile);
+ fclose(hFile);
+ } else
+ SET_LAST_ERROR_RETURN_CODE(ERR_FILE_WRITE);
+ free(pBuf);
+ return ERR_OK;
+ }
+ // read digidoc
+ reader = xmlNewTextReaderFilename(szConvDigiDocName);
+ if(reader != NULL) {
+ ret = xmlTextReaderRead(reader);
+ // loop over all nodes...
+ while(ret == 1) {
+ ret = ddocExtractProcessNode(reader, &hFile, szDocId, szConvDataFileName,
+ EXTRACT_OP_BODY_ONLY, szContentType, 0);
+ if(ret == -1) { // found all what I need but no errs. Stop parsing
+ ret = 0;
+ break;
+ }
+ ret = xmlTextReaderRead(reader);
+ }
+ // cleanup
+ xmlFreeTextReader(reader);
+ if (ret != 0)
+ ddocDebug(1, "ddocXRdrExtractDataFile", "Error parsing file: %s parsing err: %d", szConvDigiDocName, ret);
+ return ret;
+ } else {
+ SET_LAST_ERROR_RETURN_CODE(ERR_FILE_READ);
+ ddocDebug(1, "ddocXRdrExtractDataFile", "Error reading file: %s", szConvDigiDocName);
+ }
+ return ERR_OK;
+}
+
+//--------------------------------------------------
+// Reads in signed XML document and returns the
+// desired DataFile-s content in a memory buffer.
+// caller is responsible for freeing the memory.
+// pSigDoc - digidoc object in case already read in
+// szFileName - name of digidoc file
+// szDocId - id if DataFile
+// pBuf - address of buffer pointer
+// returns error code or ERR_OK
+//--------------------------------------------------
+EXP_OPTION int ddocXRdrGetDataFile(SignedDoc* pSigDoc, const char* szFileName,
+ const char* szDocId, DigiDocMemBuf* pBuf)
+{
+ char szConvDigiDocName[MAX_FILENAME+1];
+ char szContentType[MAX_CONTENT_TYPE+1];
+ xmlTextReaderPtr reader;
+ FILE* hFile = 0;
+ int ret;
+
+ // check input params
+ ddocDebug(3, "ddocXRdrGetDataFile", "SigDoc: %s, digidoc: %s, docid: %s",
+ (pSigDoc ? "OK" : "NULL"), szFileName, szDocId);
+ RETURN_IF_NULL_PARAM(pBuf);
+ RETURN_IF_NULL_PARAM(szDocId);
+ memset(pBuf, 0, sizeof(DigiDocMemBuf));
+ clearErrors();
+ ret = ddocGetDataFileCachedData(pSigDoc, szDocId, &(pBuf->pMem), &pBuf->nLen);
+ if(pBuf->pMem){ // gotcha
+ ddocDebug(4, "ddocXRdrGetDataFile", "Using cached data: %d bytes", pBuf->nLen);
+ return ERR_OK;
+ }
+ RETURN_IF_NULL_PARAM(szFileName);
+ szContentType[0] = 0;
+ // converts file names if necessary
+ ddocConvertFileName(szConvDigiDocName, sizeof(szConvDigiDocName), szFileName);
+
+ // read digidoc
+ reader = xmlNewTextReaderFilename(szConvDigiDocName);
+ if(reader != NULL) {
+ ret = xmlTextReaderRead(reader);
+ // loop over all nodes...
+ while(ret == 1) {
+ ret = ddocExtractProcessNode(reader, &hFile, szDocId, 0,
+ EXTRACT_OP_BODY_MEM, szContentType, pBuf);
+ if(ret == -1) { // found all what I need but no errs. Stop parsing
+ ret = 0;
+ break;
+ }
+ ret = xmlTextReaderRead(reader);
+ }
+ // cleanup
+ xmlFreeTextReader(reader);
+ if (ret != 0)
+ ddocDebug(1, "ddocXRdrGetDataFile", "%s : failed to parse, err: %d", szConvDigiDocName, ret);
+ return ret;
+ } else {
+ SET_LAST_ERROR_RETURN_CODE(ERR_FILE_READ);
+ ddocDebug(1, "ddocXRdrGetDataFile", "Error reading file: %s", szConvDigiDocName);
+ }
+ return ERR_OK;
+}
+
+
+//--------------------------------------------------
+// Reads in signed XML document and extracts the desired data file
+// This function removes <DataFile> xml tags but doesn't
+// otherwise change or decode the data. It is used
+// internally to copy data content from an old digidoc file
+// to a temp file while saving a the file
+// szFileName - name of digidoc file
+// szDataFileName - name of new data file
+// szDocId - id if DataFile
+// szCharset - output charset
+//--------------------------------------------------
+int ddocXRdrCopyDataFile(SignedDoc* pSigDoc, const char* szFileName,
+ const char* szDataFileName, const char* szDocId, const char* szCharset)
+{
+ char szConvDigiDocName[MAX_FILENAME+1];
+ char szConvDataFileName[MAX_FILENAME+1];
+ char szContentType[MAX_CONTENT_TYPE+1];
+ xmlTextReaderPtr reader;
+ FILE* hFile = 0;
+ int ret;
+ long len;
+ void* pBuf = 0;
+
+ // check input params
+ ddocDebug(3, "ddocXRdrCopyDataFile", "SigDoc: %s, digidoc: %s, datafile: %s, output file: %s, charset: %s",
+ (pSigDoc ? "OK" : "NULL"), szFileName, szDocId, szDataFileName, szCharset);
+ RETURN_IF_NULL_PARAM(szFileName);
+ RETURN_IF_NULL_PARAM(szDataFileName);
+ RETURN_IF_NULL_PARAM(szDocId);
+ RETURN_IF_NULL_PARAM(szCharset);
+ szContentType[0] = 0;
+ clearErrors();
+ // converts file names if necessary
+ ddocConvertFileName(szConvDataFileName, sizeof(szConvDataFileName), szDataFileName);
+ ddocConvertFileName(szConvDigiDocName, sizeof(szConvDigiDocName), szFileName);
+
+ // try reading from memory if already cached?
+ ret = ddocGetDataFileCachedData(pSigDoc, szDocId, &pBuf, &len);
+ if(pBuf) { // gotcha
+ ddocDebug(4, "ddocXRdrCopyDataFile", "Using cached data: %d bytes", len);
+ if((hFile = fopen(szConvDataFileName, "wb")) != NULL) {
+ fwrite(pBuf, 1, len, hFile);
+ fclose(hFile);
+ } else
+ SET_LAST_ERROR(ERR_FILE_WRITE);
+ free(pBuf);
+ return ERR_OK;
+ }
+ // read digidoc
+ reader = xmlNewTextReaderFilename(szConvDigiDocName);
+ if(reader != NULL) {
+ ret = xmlTextReaderRead(reader);
+ // loop over all nodes...
+ while(ret == 1) {
+ ret = ddocExtractProcessNode(reader, &hFile, szDocId, szConvDataFileName,
+ EXTRACT_OP_NO_TAGS, szContentType, 0);
+ if(ret == -1) { // found all what I need but no errs. Stop parsing
+ ret = 0;
+ break;
+ }
+ ret = xmlTextReaderRead(reader);
+ }
+ // cleanup
+ xmlFreeTextReader(reader);
+ if (ret != 0)
+ ddocDebug(1, "ddocXRdrCopyDataFile", "Error parsing file: %s, err: %d", szConvDigiDocName, ret);
+ return ret;
+ } else {
+ SET_LAST_ERROR_RETURN_CODE(ERR_FILE_READ);
+ ddocDebug(1, "ddocXRdrCopyDataFile", "Error reading file: %s", szConvDigiDocName);
+ }
+ return ERR_OK;
+}
+
+
+//=====================< digidoc parsing function >=============================
+
+//--------------------------------------------------
+// Records elements start tag to given buffer
+// Used internally and not meant to be called directly
+// by the users of this library!
+// reader - XML reader cursor to current node
+// pCurrElem - current element stack entry
+// pBuf - address of buffer for collection certain portions of digidoc
+//--------------------------------------------------
+void ddocXRdrRecordElementStart(xmlTextReaderPtr reader, ElementEntry* pCurrElem, DigiDocMemBuf* pBuf)
+{
+ int n;
+ xmlChar *an, *av;
+
+ // if we are collecting some xml content
+ if(pBuf->pMem || pBuf->nLen) {
+ ddocMemAppendData(pBuf, "<", -1);
+ ddocMemAppendData(pBuf, (const char*)pCurrElem->tag, -1);
+ for(n = 0; xmlTextReaderMoveToAttributeNo(reader, n); n++) {
+ an = xmlTextReaderLocalName(reader);
+ av = xmlTextReaderValue(reader);
+ ddocMemAppendData(pBuf, " ", -1);
+ ddocMemAppendData(pBuf, (const char*)an, -1);
+ ddocMemAppendData(pBuf, "=\"", -1);
+ ddocMemAppendData(pBuf, (const char*)av, -1);
+ ddocMemAppendData(pBuf, "\"", -1);
+ xmlFree(an);
+ xmlFree(av);
+ }
+ xmlTextReaderMoveToElement(reader);
+ ddocMemAppendData(pBuf, ">", -1);
+ }
+}
+
+//--------------------------------------------------
+// Records elements end tag to given buffer
+// Used internally and not meant to be called directly
+// by the users of this library!
+// pCurrElem - current element stack entry
+// pBuf - address of buffer for collection certain portions of digidoc
+//--------------------------------------------------
+void ddocXRdrRecordElementEnd(ElementEntry* pCurrElem, DigiDocMemBuf* pBuf)
+{
+ // if we are collecting some xml content
+ if(pBuf->pMem || pBuf->nLen) {
+ ddocMemAppendData(pBuf, "</", -1);
+ ddocMemAppendData(pBuf, (const char*)pCurrElem->tag, -1);
+ ddocMemAppendData(pBuf, ">", -1);
+ }
+}
+
+//--------------------------------------------------
+// Records elements content to given buffer
+// Used internally and not meant to be called directly
+// by the users of this library!
+// value - element content
+// pBuf - address of buffer for collection certain portions of digidoc
+//--------------------------------------------------
+void ddocXRdrRecordElementContent(xmlChar* value, DigiDocMemBuf* pBuf)
+{
+ // if we are collecting some xml content
+ if(pBuf->pMem || pBuf->nLen)
+ ddocMemAppendData(pBuf, (const char*)value, -1);
+}
+
+//--------------------------------------------------
+// Starts recording xml content
+// Used internally and not meant to be called directly
+// by the users of this library!
+// pBuf - address of buffer for collection certain portions of digidoc
+// szTag - name of new tag thatwe start collecting for
+//--------------------------------------------------
+void ddocXRdrStartCollecting(DigiDocMemBuf* pBuf, const char* szTag)
+{
+ if(pBuf->pMem) {
+ ddocDebug(2, "ddocXRdrStartCollecting", "Warning: old buffer not released when starting collecting: %s", szTag);
+ free(pBuf->pMem);
+ }
+ ddocDebug(4, "ddocXRdrStartCollecting", "Starting collecting: %s", szTag);
+ pBuf->pMem = malloc(16); // dummy buf to start recording
+ pBuf->nLen = 0;
+}
+
+//--------------------------------------------------
+// Stops recording xml content, calculates digest and stores it
+// Used internally and not meant to be called directly
+// by the users of this library!
+// pBuf - address of buffer for collection certain portions of digidoc
+// szTag - name of new tag thatwe start collecting for
+// pDigestBuf - address of pointer receiving the digest value
+// pDigestLen - address of length variable for digest length
+//--------------------------------------------------
+int ddocXRdrStopCollectingAndCalcDigest(DigiDocMemBuf* pBuf, const char* szTag,
+ char** pDigestBuf, long* pDigestLen )
+{
+ char dig[DIGEST_LEN+2];
+ char *p;
+ SHA_CTX sctx;
+
+ ddocDebug(7, "ddocXRdrStopCollectingAndCalcDigest",
+ "Tag: %s Canonicalise:---------\n%s\n---------", szTag, pBuf->pMem);
+ p = canonicalizeXML((char*)pBuf->pMem, strlen((const char*)pBuf->pMem));
+ if(p) {
+ SHA1_Init(&sctx);
+ SHA1_Update(&sctx, p, strlen(p));
+ SHA1_Final((unsigned char*)dig, &sctx);
+ setString(pDigestBuf, dig, DIGEST_LEN);
+ (*pDigestLen) = DIGEST_LEN;
+ free(p);
+ p = 0;
+ }
+ // stop recording xml content
+ ddocDebug(4, "ddocParseProcessNode", "End recording: %s", szTag);
+ if(pBuf->pMem)
+ free(pBuf->pMem);
+ pBuf->pMem = 0;
+ pBuf->nLen = 0;
+ return ERR_OK;
+}
+
+//--------------------------------------------------
+// Stops recording xml content, calculates digest and stores it
+// Used internally and not meant to be called directly
+// by the users of this library!
+// pBuf - address of buffer for collection certain portions of digidoc
+// szTag - name of new tag thatwe start collecting for
+// pDigestValue - address of DigestValue structure
+// pDigestBuf - address of pointer receiving the digest value
+// pDigestLen - address of length variable for digest length
+//--------------------------------------------------
+int ddocXRdrStopCollectingAndAssignDigest(DigiDocMemBuf* pBuf, const char* szTag,
+ DigiDocMemBuf* pDigestBuf)
+{
+ int err = ERR_OK;
+ char dig[DIGEST_LEN+2];
+ char *p;
+ SHA_CTX sctx;
+
+ ddocDebug(7, "ddocXRdrStopCollectingAndCalcDigest",
+ "Tag: %s Canonicalise:---------\n%s\n---------", szTag, pBuf->pMem);
+ p = canonicalizeXML((char*)pBuf->pMem, strlen((const char*)pBuf->pMem));
+ if(p) {
+ SHA1_Init(&sctx);
+ SHA1_Update(&sctx, p, strlen(p));
+ SHA1_Final((unsigned char*)dig, &sctx);
+ err = ddocMemAssignData(pDigestBuf, dig, DIGEST_LEN);
+ free(p);
+ p = 0;
+ }
+ // stop recording xml content
+ ddocDebug(4, "ddocParseProcessNode", "End recording: %s", szTag);
+ if(pBuf->pMem)
+ free(pBuf->pMem);
+ pBuf->pMem = 0;
+ pBuf->nLen = 0;
+ return err;
+}
+
+
+//--------------------------------------------------
+// Processes node contents. This function is used
+// internally and not meant to be called directly
+// by the users of this library!
+// reader - XML reader cursor to current node
+// pSigDoc - address of signed doc pointer
+// pStack - element stack pointer used to keep track of parsing position
+// pBuf1 - address of first buffer for collection certain portions of digidoc
+// pBuf2 - address of second buffer for collection certain portions of digidoc
+// lMaxDFLen - maximum size of a cached DataFile
+//--------------------------------------------------
+int ddocParseProcessNode(xmlTextReaderPtr reader, SignedDoc **ppSigDoc,
+ ElementEntry* pStack, DigiDocMemBuf* pBuf1,
+ DigiDocMemBuf* pBuf2, long lMaxDFLen)
+{
+ int err = ERR_OK, n, l;
+ xmlChar *name = 0, *value = 0;
+ char* p;
+ ElementEntry* pCurrElem = 0;
+ DataFile *pDF = 0;
+ CertID* pCertID;
+ X509* pCert;
+ const DigiDocMemBuf *pMBuf;
+
+ RETURN_IF_NULL_PARAM(reader);
+ RETURN_IF_NULL_PARAM(ppSigDoc);
+ RETURN_IF_NULL_PARAM(pStack);
+ RETURN_IF_NULL_PARAM(pBuf1);
+ name = xmlTextReaderName(reader);
+ ddocDebug(7, "ddocParseProcessNode", "Node %d, name: %s depth: %d",
+ xmlTextReaderNodeType(reader), (name ? (char*)name : "-"), xmlTextReaderDepth(reader));
+ if(name) {
+ xmlFree(name);
+ name = 0;
+ }
+ switch(xmlTextReaderNodeType(reader)) {
+ case XML_READER_TYPE_ELEMENT:
+ err = ddocStackPushElement(pStack, reader,&pCurrElem);
+ if(pCurrElem) {
+ // not in recording mode
+ //if(!(*pBuf1)) {
+ ddocDebug(5, "ddocParseProcessNode", "Start element: %s", (const char*)pCurrElem->tag);
+ // start of <SignedDoc>
+ if(!xmlStrcmp(pCurrElem->tag, (xmlChar*)"SignedDoc")) {
+ xmlChar* format = xmlTextReaderGetAttribute(reader, (const xmlChar*)"format");
+ xmlChar* version = xmlTextReaderGetAttribute(reader, (const xmlChar*)"version");
+ if(ddocCheckFormatAndVer((const char*)format, (const char*)version))
+ SET_LAST_ERROR_RETURN(ERR_UNSUPPORTED_FORMAT, ERR_UNSUPPORTED_FORMAT);
+ err = SignedDoc_new(ppSigDoc, (const char*)format, (const char*)version);
+ ddocDebug(4, "ddocParseProcessNode", "Create SignedDoc format: %s ver: %s",
+ (const char*)format, (const char*)version);
+ xmlFree(format);
+ xmlFree(version);
+ }
+
+ // if not inside other <DataFile>
+ if(!ddocStackHasParentWithName(pStack, (xmlChar*)"DataFile", pCurrElem)) {
+ // start of <DataFile>
+ if(!xmlStrcmp(pCurrElem->tag, (xmlChar*)"DataFile")) {
+ xmlChar *an, *av;
+ DataFile *pDF = 0;
+ err = DataFile_new(&pDF, *ppSigDoc, NULL, NULL, NULL, NULL, 0,
+ NULL, 0, NULL, NULL);
+ for(n = 0; xmlTextReaderMoveToAttributeNo(reader, n); n++) {
+ an = xmlTextReaderLocalName(reader);
+ av = xmlTextReaderValue(reader);
+ ddocDebug(5, "ddocParseProcessNode", "DF attr: %s value: %s",
+ (const char*)an, (const char*)av);
+ if(!xmlStrcmp(an, (const xmlChar*)"Id"))
+ setString(&(pDF->szId), (const char*)av, -1);
+ else if(!xmlStrcmp(an, (const xmlChar*)"ContentType"))
+ setString(&(pDF->szContentType), (const char*)av, -1);
+ else if(!xmlStrcmp(an, (const xmlChar*)"MimeType"))
+ setString(&(pDF->szMimeType), (const char*)av, -1);
+ else if(!xmlStrcmp(an, (const xmlChar*)"Filename"))
+ setString(&(pDF->szFileName), (const char*)av, -1);
+ else if(!xmlStrcmp(an, (const xmlChar*)"DigestType"))
+ setString(&(pDF->szDigestType), (const char*)av, -1);
+ else if(!xmlStrcmp(an, (const xmlChar*)"DigestValue")) {
+ l = xmlStrlen(av) + 1;
+ p = (char*)malloc(l);
+ RETURN_IF_BAD_ALLOC(p);
+ decode((const byte*)av, strlen((const char*)av), (byte*)p, &l);
+ ddocDataFile_SetDigestValue(pDF, p, l); //??? set binary or base64 ???
+ }
+ else if(!xmlStrcmp(an, (const xmlChar*)"Size"))
+ pDF->nSize = atol((const char*)av);
+ else { // all other are optional atributes
+ err = addDataFileAttribute(pDF, (const char*)an, (const char*)av);
+ }
+ xmlFree(an);
+ xmlFree(av);
+ }
+ xmlTextReaderMoveToElement(reader);
+ ddocXRdrStartCollecting(pBuf1, "DataFile");
+ }
+ // start <Signature>
+ if(!xmlStrcmp(pCurrElem->tag, (xmlChar*)"Signature")) {
+ SignatureInfo *pSig = 0;
+ value = xmlTextReaderGetAttribute(reader, (const xmlChar*)"Id");
+ ddocDebug(4, "ddocParseProcessNode", "SIG:%s", (const char*)value);
+ err = SignatureInfo_new(&pSig, *ppSigDoc, (const char*)value);
+ xmlFree(value);
+ ddocXRdrStartCollecting(pBuf2, "Signature");
+ }
+ // start <Reference>
+ if(!xmlStrcmp(pCurrElem->tag, (xmlChar*)"Reference")) {
+ DocInfo *pDi = 0;
+ xmlChar *uri, *type;
+ SignatureInfo *pSig = ddocGetLastSignature(*ppSigDoc);
+ RETURN_IF_NULL(pSig);
+ uri = xmlTextReaderGetAttribute(reader, (const xmlChar*)"URI");
+ type = xmlTextReaderGetAttribute(reader, (const xmlChar*)"Type");
+ ddocDebug(4, "ddocParseProcessNode", "Reference URI: %s Type: %s",
+ (const char*)uri, (const char*)type);
+ // DataFile digest
+ if(uri[0] == '#' && uri[1] == 'D')
+ err = addDocInfo(&pDi, pSig, (const char*)(uri+1),
+ NULL, NULL, 0, NULL, 0); // TODO: ver 1.x mime digest handling
+ xmlFree(uri);
+ xmlFree(type);
+ }
+
+ // start <DigestMethod>
+ if(!xmlStrcmp(pCurrElem->tag, (xmlChar*)"DigestMethod")) {
+ ElementEntry* pParent = 0;
+ value = xmlTextReaderGetAttribute(reader, (const xmlChar*)"Algorithm");
+ // if inside <SignedInfo>
+ if((pParent = ddocStackGetParentWithName(pStack, (xmlChar*)"Reference", pCurrElem)) != NULL) {
+ SignatureInfo *pSig = ddocGetLastSignature(*ppSigDoc);
+ RETURN_IF_NULL(pSig);
+ // DataFile reference
+ if(pParent->uri && pParent->uri[1] == 'D') {
+ DocInfo *pDi = ddocGetLastDocInfo(pSig);
+ if(pDi && !xmlStrcmp(value, (xmlChar*)DIGEST_METHOD_SHA1))
+ setString((char**)&(pDi->szDigestType), DIGEST_SHA1_NAME, -1);
+ // what if something else ?
+ }
+ // SignedProperties reference
+
+ } // inside <Reference>
+
+ xmlFree(value);
+ }
+
+ // start of <SignedInfo>
+ if(!xmlStrcmp(pCurrElem->tag, (xmlChar*)"SignedInfo"))
+ ddocXRdrStartCollecting(pBuf1, "SignedInfo");
+
+ // start of <SignedProperties>
+ if(!xmlStrcmp(pCurrElem->tag, (xmlChar*)"SignedProperties"))
+ ddocXRdrStartCollecting(pBuf1, "SignedProperties");
+
+ // start of <UnsignedProperties>
+ if(!xmlStrcmp(pCurrElem->tag, (xmlChar*)"UnsignedProperties")) {
+ NotaryInfo* pNot = 0;
+ SignatureInfo *pSig = ddocGetLastSignature(*ppSigDoc);
+ RETURN_IF_NULL(pSig);
+ ddocDebug(4, "ddocParseProcessNode", "Start of UnsignedProperties");
+ err = NotaryInfo_new(&pNot, *ppSigDoc, pSig);
+ }
+
+
+ } // if not inside other <DataFile>
+
+ // if we are collecting some xml content (<DataFile>, <SignedInfo>, etc.)
+ ddocXRdrRecordElementStart(reader, pCurrElem, pBuf1);
+ // if we are collecting <Signature> xml content
+ ddocXRdrRecordElementStart(reader, pCurrElem, pBuf2);
+ }
+ break;
+ case XML_READER_TYPE_END_ELEMENT:
+ // get current element
+ pCurrElem = ddocStackFindEnd(pStack);
+ if(pCurrElem) {
+ ddocDebug(5, "ddocParseProcessNode", "End element: %s", pCurrElem->tag);
+ // if we are collecting some xml content (<DataFile>, <SignedInfo>, etc.)
+ ddocXRdrRecordElementEnd(pCurrElem, pBuf1);
+ // if we are collecting <Signature> xml content
+ ddocXRdrRecordElementEnd(pCurrElem, pBuf2);
+
+ // </DataFile>
+ if(!xmlStrcmp(pCurrElem->tag, (xmlChar*)"DataFile") &&
+ !ddocStackHasParentWithName(pStack, (xmlChar*)"DataFile", pCurrElem)) {
+ ddocDebug(4, "ddocParseProcessNode", "End recording DataFile");
+ pDF = ddocGetLastDataFile(*ppSigDoc);
+ if(pDF) {
+ err = ddocXRdrStopCollectingAndAssignDigest(pBuf1, "DataFile", &(pDF->mbufDigest));
+ setString((char**)&(pDF->szDigestType), DIGEST_SHA1_NAME, -1);
+ // TODO: Version 1.0 buggy digest calculation...
+ }
+ } // </DataFile>
+
+ // </SignedInfo>
+ if(!xmlStrcmp(pCurrElem->tag, (xmlChar*)"SignedInfo") &&
+ !ddocStackHasParentWithName(pStack, (xmlChar*)"DataFile", pCurrElem)) {
+ SignatureInfo *pSig = ddocGetLastSignature(*ppSigDoc);
+ RETURN_IF_NULL(pSig);
+ if(!pSig->pSigInfoRealDigest)
+ ddocDigestValue_new(&(pSig->pSigInfoRealDigest), 0, 0, 0);
+ err = ddocXRdrStopCollectingAndAssignDigest(pBuf1, "SignedInfo",
+ &(pSig->pSigInfoRealDigest->mbufDigestValue));
+ } // </SignedInfo>
+
+ // </SignedProperties>
+ if(!xmlStrcmp(pCurrElem->tag, (xmlChar*)"SignedProperties") &&
+ !ddocStackHasParentWithName(pStack, (xmlChar*)"DataFile", pCurrElem)) {
+ SignatureInfo *pSig = ddocGetLastSignature(*ppSigDoc);
+ RETURN_IF_NULL(pSig);
+ if(!pSig->pSigPropRealDigest)
+ ddocDigestValue_new(&(pSig->pSigPropRealDigest), 0, 0, 0);
+ ddocXRdrStopCollectingAndAssignDigest(pBuf1, "SignedProperties",
+ &(pSig->pSigPropRealDigest->mbufDigestValue));
+ } // </SignedProperties>
+
+ // </Signature>
+ if(!xmlStrcmp(pCurrElem->tag, (xmlChar*)"Signature") &&
+ !ddocStackHasParentWithName(pStack, (xmlChar*)"DataFile", pCurrElem)) {
+ SignatureInfo *pSig = ddocGetLastSignature(*ppSigDoc);
+ RETURN_IF_NULL(pSig);
+ ddocDebug(4, "ddocParseProcessNode", "End recording Signature");
+ // DO NOT FREE THE MEM! Just take ownership
+ ddocMemBuf_free(&(pSig->mbufOrigContent));
+ pSig->mbufOrigContent.pMem = (byte*)pBuf2->pMem;
+ pSig->mbufOrigContent.nLen = pBuf2->nLen;
+ pBuf2->pMem = 0;
+ pBuf2->nLen = 0;
+ } // </Signature>
+
+ } // if(pCurrElem)
+ err = ddocStackPopElement(pStack, 0, NULL);
+ break;
+ case XML_READER_TYPE_ATTRIBUTE:
+ break;
+ case XML_READER_TYPE_TEXT:
+ value = xmlTextReaderValue(reader);
+ if(value) {
+ ddocDebug(8, "ddocParseProcessNode", "TEXT:\'%s\'", (const char*)value, -1);
+ // if we are collecting some xml content (<DataFile>, <SignedInfo>, etc.)
+ ddocXRdrRecordElementContent(value, pBuf1);
+ // if we are collecting <Signature> xml content
+ ddocXRdrRecordElementContent(value, pBuf2);
+
+ // get current tag
+ pCurrElem = ddocStackFindEnd(pStack);
+
+ // content of <DataFile>
+ if(pCurrElem && !xmlStrcmp(pCurrElem->tag, (xmlChar*)"DataFile") &&
+ !ddocStackHasParentWithName(pStack, (xmlChar*)"DataFile", pCurrElem)) {
+ DataFile *pDF = ddocGetLastDataFile(*ppSigDoc);
+ // collect <DataFile> contents
+ ddocAppendDataFileData(pDF, lMaxDFLen, (void*)value, strlen((const char*)value), !strcmp(pDF->szContentType, CONTENT_EMBEDDED_BASE64));
+ }
+
+ // content of <DigestValue>
+ if(!xmlStrcmp(pCurrElem->tag, (xmlChar*)"DigestValue")) {
+ ElementEntry* pParent = 0;
+ ddocDebug(4, "ddocParseProcessNode", "DigestValue: %s", (const char*)value);
+ l = strlen((const char*)value);
+ p = (char*)malloc(l+1);
+ RETURN_IF_BAD_ALLOC(p);
+ memset(p, 0, l+1);
+ decode((const byte*)value, l, (byte*)p, &l);
+
+ // if inside <Reference>
+ if((pParent = ddocStackGetParentWithName(pStack,
+ (xmlChar*)"Reference", pCurrElem)) != NULL) {
+ SignatureInfo *pSig = ddocGetLastSignature(*ppSigDoc);
+ RETURN_IF_NULL(pSig);
+ // DataFile digest value
+ if(pParent->uri && pParent->uri[1] == 'D') {
+ DocInfo *pDi = ddocGetLastDocInfo(pSig);
+ if(pDi) {
+ ddocDebug(4, "ddocParseProcessNode", "SIG: %s DocInfo: %s digest", pSig->szId, pDi->szDocId);
+ setString((char**)&(pDi->szDigest), p, l);
+ pDi->nDigestLen = l;
+ }
+ }
+ // SignedProperties digest value
+ if(pParent->uri && pParent->uri[1] == 'S') {
+ ddocDebug(4, "ddocParseProcessNode", "SIG: %s SignedProperties digest", pSig->szId);
+ ddocSigInfo_SetSigPropDigest(pSig, p, l);
+ }
+
+ } // inside <Reference>
+
+ // if inside <SigningCertificate>
+ if((pParent = ddocStackGetParentWithName(pStack, (xmlChar*)"SigningCertificate", pCurrElem)) != NULL) {
+ SignatureInfo *pSig = ddocGetLastSignature(*ppSigDoc);
+ RETURN_IF_NULL(pSig);
+ pCertID = ddocSigInfo_GetOrCreateCertIDOfType(pSig, CERTID_TYPE_SIGNERS_CERTID);
+ RETURN_IF_NULL(pCertID);
+ // Certificate digest value
+ ddocDebug(4, "ddocParseProcessNode", "SIG: %s signers certificate digest", pSig->szId);
+ ddocCertID_SetDigestValue(pCertID, p, l);
+ } // inside <SigningCertificate>
+
+ // if inside <CompleteCertificateRefs>
+ if((pParent = ddocStackGetParentWithName(pStack, (xmlChar*)"CompleteCertificateRefs", pCurrElem)) != NULL) {
+ SignatureInfo *pSig = ddocGetLastSignature(*ppSigDoc);
+ RETURN_IF_NULL(pSig);
+ pCertID = ddocSigInfo_GetOrCreateCertIDOfType(pSig, CERTID_TYPE_RESPONDERS_CERTID);
+ RETURN_IF_NULL(pCertID);
+ // Certificate digest value
+ ddocDebug(4, "ddocParseProcessNode", "Sig: %s responders certificate digest", pSig->szId);
+ ddocCertID_SetDigestValue(pCertID, p, l);
+ } // inside <CompleteCertificateRefs>
+
+ // if inside <CompleteRevocationRefs>
+ if((pParent = ddocStackGetParentWithName(pStack, (xmlChar*)"CompleteRevocationRefs", pCurrElem)) != NULL) {
+ NotaryInfo* pNot = ddocGetLastNotaryInfo(*ppSigDoc);
+ RETURN_IF_NULL(pNot);
+ // Certificate digest value
+ ddocDebug(4, "ddocParseProcessNode", "NOT: %s OCSP digest", pNot->szId);
+ ddocNotInfo_SetOcspDigest(pNot, p, l);
+ } // inside <CompleteRevocationRefs>
+
+
+ free(p);
+ } // DigestVlue
+
+ // content of <SignatureValue>
+ if(!xmlStrcmp(pCurrElem->tag, (xmlChar*)"SignatureValue")) {
+ SignatureInfo *pSig = ddocGetLastSignature(*ppSigDoc);
+ ddocDebug(4, "ddocParseProcessNode", "SignatureValue: %s", (const char*)value);
+ RETURN_IF_NULL(pSig);
+ l = strlen((const char*)value);
+ p = (char*)malloc(l+1);
+ RETURN_IF_BAD_ALLOC(p);
+ memset(p, 0, l+1);
+ decode((const byte*)value, l, (byte*)p, &l);
+ ddocSigInfo_SetSignatureValue(pSig, p, l);
+ free(p);
+ } // SignatureValue
+
+ // content of <IssuerSerial> or <X509SerialNumber>
+ if((!xmlStrcmp(pCurrElem->tag, (xmlChar*)"IssuerSerial") &&
+ strcmp((*ppSigDoc)->szFormatVer, DIGIDOC_XML_1_3_VER)) ||
+ !xmlStrcmp(pCurrElem->tag, (xmlChar*)"X509SerialNumber")) {
+ if(ddocStackHasParentWithName(pStack, (xmlChar*)"SigningCertificate", pCurrElem)) {
+ SignatureInfo *pSig = ddocGetLastSignature(*ppSigDoc);
+ ddocDebug(4, "ddocParseProcessNode", "X509IssuerSerial: %s", (const char*)value);
+ pCertID = ddocSigInfo_GetOrCreateCertIDOfType(pSig, CERTID_TYPE_SIGNERS_CERTID);
+ RETURN_IF_NULL(pCertID);
+ ddocCertID_SetIssuerSerial(pCertID, (const char*)value);
+ }
+ if(ddocStackHasParentWithName(pStack, (xmlChar*)"CompleteCertificateRefs", pCurrElem)) {
+ SignatureInfo *pSig = ddocGetLastSignature(*ppSigDoc);
+ RETURN_IF_NULL(pSig);
+ ddocDebug(4, "ddocParseProcessNode", "X509IssuerSerial: %s", (const char*)value);
+ pCertID = ddocSigInfo_GetOrCreateCertIDOfType(pSig, CERTID_TYPE_RESPONDERS_CERTID);
+ RETURN_IF_NULL(pCertID);
+ ddocCertID_SetIssuerSerial(pCertID, (const char*)value);
+ }
+
+ } // IssuerSerial
+
+ // content of <X509IssuerName>
+ if(!strcmp((*ppSigDoc)->szFormatVer, DIGIDOC_XML_1_3_VER) &&
+ !xmlStrcmp(pCurrElem->tag, (xmlChar*)"X509IssuerName")) {
+ if(ddocStackHasParentWithName(pStack, (xmlChar*)"SigningCertificate", pCurrElem)) {
+ SignatureInfo *pSig = ddocGetLastSignature(*ppSigDoc);
+ ddocDebug(4, "ddocParseProcessNode", "X509IssuerName: %s", (const char*)value);
+ pCertID = ddocSigInfo_GetOrCreateCertIDOfType(pSig, CERTID_TYPE_SIGNERS_CERTID);
+ RETURN_IF_NULL(pCertID);
+ ddocCertID_SetIssuerName(pCertID, (const char*)value);
+ }
+ if(ddocStackHasParentWithName(pStack, (xmlChar*)"CompleteCertificateRefs", pCurrElem)) {
+ SignatureInfo *pSig = ddocGetLastSignature(*ppSigDoc);
+ RETURN_IF_NULL(pSig);
+ ddocDebug(4, "ddocParseProcessNode", "X509IssuerName: %s", (const char*)value);
+ pCertID = ddocSigInfo_GetOrCreateCertIDOfType(pSig, CERTID_TYPE_RESPONDERS_CERTID);
+ RETURN_IF_NULL(pCertID);
+ ddocCertID_SetIssuerName(pCertID, (const char*)value);
+ }
+
+ } // IssuerSerial
+
+
+ // content of <X509Certificate>
+ if(!xmlStrcmp(pCurrElem->tag, (xmlChar*)"X509Certificate")) {
+ SignatureInfo *pSig = ddocGetLastSignature(*ppSigDoc);
+ l = strlen((const char*)value);
+ ddocDebug(4, "ddocParseProcessNode", "X509Certificate: %s len: %d", (const char*)value, l);
+ RETURN_IF_NULL(pSig);
+
+ ddocDecodeX509PEMData((X509**)&pCert, (const char*)value, l);
+ ddocSigInfo_SetSignersCert(pSig, pCert);
+ } // X509Certificate
+
+ // content of <SigningTime>
+ if(!xmlStrcmp(pCurrElem->tag, (xmlChar*)"SigningTime")) {
+ SignatureInfo *pSig = ddocGetLastSignature(*ppSigDoc);
+ ddocDebug(4, "ddocParseProcessNode", "SigningTime: %s", (const char*)value);
+ RETURN_IF_NULL(pSig);
+ setString((char**)&(pSig->szTimeStamp), (const char*)value, -1);
+ } // SigningTime
+
+ // content of <ClaimedRole>
+ if(!xmlStrcmp(pCurrElem->tag, (xmlChar*)"ClaimedRole")) {
+ SignatureInfo *pSig = ddocGetLastSignature(*ppSigDoc);
+ ddocDebug(4, "ddocParseProcessNode", "ClaimedRole: %s", (const char*)value);
+ RETURN_IF_NULL(pSig);
+ addSignerRole(pSig, 0, (const char*)value, strlen((const char*)value), 0);
+ } // ClaimedRole
+
+ // content of <ResponderID>
+ if(!xmlStrcmp(pCurrElem->tag, (xmlChar*)"ResponderID")) {
+ NotaryInfo* pNot = ddocGetLastNotaryInfo(*ppSigDoc);
+ RETURN_IF_NULL(pNot);
+ ddocDebug(4, "ddocParseProcessNode", "ResponderID: %s", (const char*)value);
+ ddocNotInfo_SetResponderId(pNot, (const char*)value, -1);
+ } // ResponderID
+
+ // content of <ProducedAt>
+ if(!xmlStrcmp(pCurrElem->tag, (xmlChar*)"ProducedAt")) {
+ NotaryInfo* pNot = ddocGetLastNotaryInfo(*ppSigDoc);
+ RETURN_IF_NULL(pNot);
+ ddocDebug(4, "ddocParseProcessNode", "ProducedAt: %s", (const char*)value);
+ setString((char**)&(pNot->timeProduced), (const char*)value, -1);
+ } // ProducedAt
+
+ // content of <EncapsulatedX509Certificate>
+ if(!xmlStrcmp(pCurrElem->tag, (xmlChar*)"EncapsulatedX509Certificate")) {
+ SignatureInfo *pSig = ddocGetLastSignature(*ppSigDoc);
+ RETURN_IF_NULL(pSig);
+ ddocDebug(4, "ddocParseProcessNode", "EncapsulatedX509Certificate: %s", (const char*)value);
+ l = strlen((const char*)value);
+ ddocDecodeX509PEMData((X509**)&pCert, (const char*)value, l);
+ ddocSigInfo_SetOCSPRespondersCert(pSig, pCert);
+ } // EncapsulatedX509Certificate
+
+ // content of <EncapsulatedOCSPValue>
+ if(!xmlStrcmp(pCurrElem->tag, (xmlChar*)"EncapsulatedOCSPValue")) {
+ OCSP_RESPONSE* pResp = 0;
+ byte buf1[DIGEST_LEN+2];
+ int len1;
+ NotaryInfo* pNot;
+ SignatureInfo *pSig;
+
+ pNot = ddocGetLastNotaryInfo(*ppSigDoc);
+ RETURN_IF_NULL(pNot);
+ pSig = ddocGetLastSignature(*ppSigDoc);
+ RETURN_IF_NULL(pSig);
+ ddocDebug(4, "ddocParseProcessNode", "EncapsulatedOCSPValue: %s", (const char*)value);
+ err = ddocDecodeOCSPResponsePEMData(&pResp, (const byte*)value, strlen((const char*)value));
+ if(pResp) {
+ // in ver 1.2 we have correct OCP digest
+ // VS 1.76 - add 1.3 version too
+ if(!strcmp((*ppSigDoc)->szFormatVer, DIGIDOC_XML_1_2_VER) ||
+ !strcmp((*ppSigDoc)->szFormatVer, DIGIDOC_XML_1_3_VER))
+ err = initializeNotaryInfoWithOCSP(*ppSigDoc, pNot, pResp, ddocSigInfo_GetOCSPRespondersCert(pSig), 0);
+ else // in older versions the digest was incorrect
+ err = initializeNotaryInfoWithOCSP(*ppSigDoc, pNot, pResp, ddocSigInfo_GetOCSPRespondersCert(pSig), 1);
+ } else
+ ddocDebug(1, "ddocParseProcessNode", "error decoding OCSP response");
+ // check OCSP digest
+ len1 = sizeof(buf1);
+ err = calculateNotaryInfoDigest(*ppSigDoc, pNot, buf1, &len1);
+ pMBuf = ddocNotInfo_GetOcspDigest(pNot);
+ RETURN_IF_NULL(pMBuf);
+ if(err || compareByteArrays(buf1, len1, (byte*)pMBuf->pMem, pMBuf->nLen)) {
+ SET_LAST_ERROR(ERR_BAD_OCSP_RESPONSE_DIGEST);
+ err = ERR_BAD_OCSP_RESPONSE_DIGEST;
+ ddocDebug(1, "ddocParseProcessNode", "Incorrect OCSP digest, len1: %d, len2: %d",
+ len1, pMBuf->nLen);
+ }
+
+ } // EncapsulatedOCSPValue
+
+ xmlFree(value);
+ value = 0;
+ }
+ break;
+ case XML_READER_TYPE_WHITESPACE:
+ case XML_READER_TYPE_SIGNIFICANT_WHITESPACE:
+ case XML_READER_TYPE_CDATA:
+ value = xmlTextReaderValue(reader);
+ if(value) {
+ // if we are collecting some xml content (<DataFile>, <SignedInfo>, etc.)
+ ddocXRdrRecordElementContent(value, pBuf1);
+ // if we are collecting <Signature> xml content
+ ddocXRdrRecordElementContent(value, pBuf2);
+ xmlFree(value);
+ value = 0;
+ }
+ break;
+
+ case XML_READER_TYPE_ENTITY_REFERENCE:
+ case XML_READER_TYPE_ENTITY:
+ case XML_READER_TYPE_PROCESSING_INSTRUCTION:
+ case XML_READER_TYPE_COMMENT:
+ case XML_READER_TYPE_DOCUMENT:
+ case XML_READER_TYPE_DOCUMENT_TYPE:
+ case XML_READER_TYPE_DOCUMENT_FRAGMENT:
+ case XML_READER_TYPE_NOTATION:
+ break;
+ }
+ //ddocDebug(4, "ddocParseProcessNode", "Err %d", err);
+ return err;
+}
+
+
+//--------------------------------------------------
+// Reads in signed XML document
+// szFileName - name of digidoc file
+// ppSigDoc - address of new signed doc pointer
+// lMaxDFLen - maximum size of a cached DataFile
+//--------------------------------------------------
+EXP_OPTION int ddocXRdrReadSignedDocFromFile(const char* szFileName,
+ SignedDoc** pSigDoc, long lMaxDFLen)
+{
+ char szConvDigiDocName[MAX_FILENAME+1];
+ xmlTextReaderPtr reader;
+ ElementEntry stack;
+ DigiDocMemBuf memBuf1, memBuf2;
+ int ret;
+
+ ddocDebug(3, "ddocXRdrReadSignedDocFromFile", "digidoc: %s, filename charset %s, max df: %ld",
+ szFileName, lMaxDFLen);
+ // check input params
+ RETURN_IF_NULL_PARAM(szFileName);
+ RETURN_IF_NULL_PARAM(pSigDoc);
+ memset(&stack, 0, sizeof(ElementEntry));
+ *pSigDoc = NULL; // mark as not read in
+ ddocDebug(3, "ddocXRdrReadSignedDocFromFile", "digidoc: %s", szFileName);
+ clearErrors();
+ memBuf1.pMem = 0;
+ memBuf1.nLen = 0;
+ memBuf2.pMem = 0;
+ memBuf2.nLen = 0;
+ // converts file names if necessary
+ ddocConvertFileName(szConvDigiDocName, sizeof(szConvDigiDocName), szFileName);
+
+ // read digidoc
+ reader = xmlNewTextReaderFilename(szConvDigiDocName);
+ if(reader != NULL) {
+ ret = xmlTextReaderRead(reader);
+ // loop over all nodes...
+ while(ret == 1) {
+ ret = ddocParseProcessNode(reader, pSigDoc, &stack,
+ &memBuf1, &memBuf2, lMaxDFLen);
+ if(ret == ERR_OK)
+ ret = 1;
+ ret = xmlTextReaderRead(reader);
+ }
+ // cleanup
+ ret = ddocStackPopElement(&stack, 1, NULL);
+ if(memBuf1.pMem)
+ free(memBuf1.pMem);
+ if(memBuf2.pMem)
+ free(memBuf2.pMem);
+ xmlFreeTextReader(reader);
+ if (ret != 0)
+ ddocDebug(1, "ddocXRdrReadSignedDocFromFile", "%s : failed to parse: %d", szConvDigiDocName, ret);
+ return ret;
+ } else {
+ SET_LAST_ERROR_RETURN_CODE(ERR_FILE_READ);
+ ddocDebug(1, "ddocXRdrReadSignedDocFromFile", "Error reading file: %s", szConvDigiDocName);
+ }
+ return ERR_OK;
+}
+
+//--------------------------------------------------
+// Reads in signed XML document from memory buffer
+// szXml - memory buffer that contains digidoc data
+// xmlLen - length of the input data
+// szFileNameCharset - digidoc filename charset
+// ppSigDoc - address of new signed doc pointer
+// lMaxDFLen - maximum size of a cached DataFile
+//--------------------------------------------------
+EXP_OPTION int ddocXRdrReadSignedDocFromMemory(const char* szXml, int xmlLen,
+ SignedDoc** pSigDoc, long lMaxDFLen)
+{
+ xmlTextReaderPtr reader;
+ ElementEntry stack;
+ DigiDocMemBuf memBuf1, memBuf2;
+ int ret;
+
+ ddocDebug(3, "ddocXRdrReadSignedDocFromMemory", "data len: %d, max df: %ld", xmlLen, lMaxDFLen);
+ // check input params
+ RETURN_IF_NULL_PARAM(szXml);
+ RETURN_IF_NULL_PARAM(pSigDoc);
+ memset(&stack, 0, sizeof(ElementEntry));
+ *pSigDoc = NULL; // mark as not read in
+ clearErrors();
+ memBuf1.pMem = 0;
+ memBuf1.nLen = 0;
+ memBuf2.pMem = 0;
+ memBuf2.nLen = 0;
+ // read digidoc
+ reader = xmlReaderForMemory(szXml, xmlLen, "http://www.sk.ee/DigiDoc/", "UTF-8", 0);
+ if(reader != NULL) {
+ ret = xmlTextReaderRead(reader);
+ // loop over all nodes...
+ while(ret == 1) {
+ ret = ddocParseProcessNode(reader, pSigDoc, &stack,
+ &memBuf1, &memBuf2, lMaxDFLen);
+ if(ret == ERR_OK)
+ ret = 1;
+ ret = xmlTextReaderRead(reader);
+ }
+ // cleanup
+ ret = ddocStackPopElement(&stack, 1, NULL);
+ if(memBuf1.pMem)
+ free(memBuf1.pMem);
+ if(memBuf2.pMem)
+ free(memBuf2.pMem);
+ xmlFreeTextReader(reader);
+ if (ret != 0)
+ ddocDebug(1, "ddocXRdrReadSignedDocFromMemory", "failed to parse: %d", ret);
+ return ret;
+ } else {
+ SET_LAST_ERROR_RETURN_CODE(ERR_FILE_READ);
+ ddocDebug(1, "ddocXRdrReadSignedDocFromMemory", "Error parsing digidoc");
+ }
+ return ERR_OK;
+}
+
diff --git a/libdigidoc/DigiDocParser.h b/libdigidoc/DigiDocParser.h
new file mode 100644
index 0000000..107c819
--- /dev/null
+++ b/libdigidoc/DigiDocParser.h
@@ -0,0 +1,107 @@
+#ifndef __DIGIDOC_PARSER_H__
+#define __DIGIDOC_PARSER_H__
+//==================================================
+// FILE: DigiDocParser.h
+// PROJECT: Digi Doc
+// DESCRIPTION: Digi Doc functions for xml parsing
+// AUTHOR: Veiko Sinivee, S|E|B IT Partner Estonia
+//==================================================
+// Copyright (C) AS Sertifitseerimiskeskus
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+// GNU Lesser General Public Licence is available at
+// http://www.gnu.org/copyleft/lesser.html
+//==========< HISTORY >=============================
+// 10.07.2004 Veiko Sinivee
+// Creation
+// 22.08.2004 Veiko Sinivee
+// Renamed ddocExtractDataFile to ddocXRdrExtractDataFile
+// Renamed ddocGetDataFile to ddocXRdrGetDataFile
+// Renamed ddocCopyDataFile to ddocXRdrCopyDataFile
+// introduced ddocXRdrReadSignedDocFromFile()
+//==================================================
+
+#include <libdigidoc/DigiDocDefs.h>
+#include <libdigidoc/DigiDocLib.h>
+#include <libdigidoc/DigiDocMem.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+
+ //--------------------------------------------------
+ // Reads in signed XML document and extracts the desired data file
+ // pSigDoc - signed document object if cached
+ // szFileName - name of digidoc file
+ // szDataFileName - name of new data file
+ // szDocId - id if DataFile
+ // szCharset - output charset
+ // szFileNameCharset - digidoc filename charset
+ //--------------------------------------------------
+ EXP_OPTION int ddocXRdrExtractDataFile(SignedDoc* pSigDoc, const char* szFileName,
+ const char* szDataFileName,
+ const char* szDocId, const char* szCharset);
+
+ //--------------------------------------------------
+ // Reads in signed XML document and returns the
+ // desired DataFile-s content in a memory buffer.
+ // caller is responsible for freeing the memory.
+ // pSigDoc - signed document object if cached
+ // szFileName - name of digidoc file
+ // szDocId - id if DataFile
+ // pBuf - address of buffer pointer
+ // returns error code or ERR_OK
+ //--------------------------------------------------
+ EXP_OPTION int ddocXRdrGetDataFile(SignedDoc* pSigDoc, const char* szFileName,
+ const char* szDocId, DigiDocMemBuf* pBuf);
+
+ //--------------------------------------------------
+ // Reads in signed XML document and extracts the desired data file
+ // This function keeps also <DataFile> xml tags. It is used
+ // internally to copy data content from an old digidoc file
+ // to a temp file while saving a the file
+ // pSigDoc - signed document object if cached
+ // szFileName - name of digidoc file
+ // szDataFileName - name of new data file
+ // szDocId - id if DataFile
+ // szCharset - output charset
+ //--------------------------------------------------
+ int ddocXRdrCopyDataFile(SignedDoc* pSigDoc, const char* szFileName, const char* szDataFileName,
+ const char* szDocId, const char* szCharset);
+
+ //--------------------------------------------------
+ // Reads in signed XML document
+ // szFileName - name of digidoc file
+ // ppSigDoc - address of new signed doc pointer
+ // lMaxDFLen - maximum size of a cached DataFile
+ //--------------------------------------------------
+ EXP_OPTION int ddocXRdrReadSignedDocFromFile(const char* szFileName,
+ SignedDoc** pSigDoc, long lMaxDFLen);
+
+
+ //--------------------------------------------------
+ // Reads in signed XML document from memory buffer
+ // szXml - memory buffer that contains digidoc data
+ // xmlLen - length of the input data
+ // szFileNameCharset - digidoc filename charset
+ // ppSigDoc - address of new signed doc pointer
+ // lMaxDFLen - maximum size of a cached DataFile
+ //--------------------------------------------------
+ EXP_OPTION int ddocXRdrReadSignedDocFromMemory(const char* szXml, int xmlLen,
+ SignedDoc** pSigDoc, long lMaxDFLen);
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif // __DIGIDOC_PARSER_H__
+
diff --git a/libdigidoc/DigiDocSAXParser.c b/libdigidoc/DigiDocSAXParser.c
new file mode 100644
index 0000000..0bebe63
--- /dev/null
+++ b/libdigidoc/DigiDocSAXParser.c
@@ -0,0 +1,3237 @@
+//==================================================
+// FILE: DigiDocSAXParser.c
+// PROJECT: Digi Doc
+// DESCRIPTION: Digi Doc functions for xml parsing using SAX interface
+// AUTHOR: Veiko Sinivee, S|E|B IT Partner Estonia
+//==================================================
+// Copyright (C) AS Sertifitseerimiskeskus
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+// GNU Lesser General Public Licence is available at
+// http://www.gnu.org/copyleft/lesser.html
+//==========< HISTORY >=============================
+// 12.08.2004 Veiko Sinivee
+// Creation
+//==================================================
+
+#include <libdigidoc/DigiDocDefs.h>
+#include <libdigidoc/DigiDocSAXParser.h>
+#include <libdigidoc/DigiDocError.h>
+#include <libdigidoc/DigiDocDebug.h>
+#include <libdigidoc/DigiDocConvert.h>
+#include <libdigidoc/DigiDocMem.h>
+#include <libdigidoc/DigiDocLib.h>
+#include <libdigidoc/DigiDocCert.h>
+#include <libdigidoc/DigiDocConfig.h>
+#include <libdigidoc/DigiDocOCSP.h>
+#include <libdigidoc/DigiDocDfExtract.h>
+#include <libdigidoc/DigiDocVerify.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <memory.h>
+#include <string.h>
+#include <ctype.h>
+
+#include <libxml/globals.h>
+#include <libxml/xmlerror.h>
+#include <libxml/parser.h>
+#include <libxml/parserInternals.h> /* only for xmlNewInputFromFile() */
+#include <libxml/tree.h>
+#include <libxml/debugXML.h>
+#include <libxml/xmlmemory.h>
+#include <libxml/c14n.h>
+
+// string used to force parser to flush it's buffers
+static char g_szDataFileFlush1[] = "</DataFile>";
+static char g_szDataFileFlush2[] = "<DataFile Id=\"%s\" ContentType=\"%s\">";
+
+#ifdef WIN32
+ #define snprintf _snprintf
+ #include <wchar.h>
+#endif
+
+extern int ddocCheckFormatAndVer(const char* format, const char* version);
+extern char* canonicalizeXML(char* source, int len);
+extern int escapeXMLSymbols(const char* src, int srclen, char** dest);
+
+#define FLAG_XML_ELEM 1
+#define FLAG_SIGNATURE 2
+#define FLAG_SIG_PART 3
+#define FLAG_TS_INP 4
+
+//===============< SAX handlers >==============================
+
+/*
+* Working area for XML parsing with SAX
+*/
+typedef struct SigDocParse_st {
+ SignedDoc* pSigDoc; // document file to be filled with data
+ char tag[300]; // current tag
+ char ctx1[300]; // context1
+ char ctx2[300]; // context2
+ char ctx3[300]; // context3
+ char ctx4[300];
+ char ctx5[300];
+ BIO* bDataFile;
+ EVP_ENCODE_CTX ectx;
+ SHA_CTX sctx, sctx2; // sha1 digest context and alternat dig context
+ int errcode;
+ char* szInputFileName;
+ int checkFileDigest;
+ int nIgnoreDataFile; // incremented each time when EMBEDDED XML content is found.
+ // used to ignore such content
+ DigiDocMemBuf mbufElemData;
+ char bCollectElemData;
+ char bNoXMLElemData;
+ int checkUTF8;
+ DigiDocMemBuf mbufSigData; // <Signature>
+ char bCollectSigData;
+ DigiDocMemBuf mbufSigPartData; // <SignedInfo> and <SignedProperties>
+ char bCollectSigPartData;
+ long lMaxDFLen;
+ time_t tStartParse;
+ long lSize;
+ char bCollectDFData;
+ DigiDocMemBuf *pMemBufDF;
+ int bKeepBase64;
+ char b64line[66];
+ int b64pos;
+ DigiDocMemBuf mbufTags;
+ XmlElemInfo *eRoot, *eCurr;
+} SigDocParse;
+
+//--------------------------------------------------
+// Releases memory that might have been allocated during
+// the parsing process.
+// pctx - pointer to parsing context
+//--------------------------------------------------
+void ddocSAXCleanup(SigDocParse* pctx)
+{
+ // field: szInputFileName is not allocated in parser!
+ ddocMemBuf_free(&(pctx->mbufElemData));
+ ddocMemBuf_free(&(pctx->mbufSigData));
+ ddocMemBuf_free(&(pctx->mbufSigPartData));
+ ddocMemBuf_free(&(pctx->mbufTags));
+ if(pctx->pMemBufDF)
+ ddocMemBuf_free(pctx->pMemBufDF);
+ if(pctx->bDataFile)
+ BIO_free(pctx->bDataFile);
+ if(pctx->eRoot)
+ XmlElemInfo_free(pctx->eRoot);
+ memset(pctx, 0, sizeof(SigDocParse));
+}
+
+//--------------------------------------------------
+// Starts collecting some element data.
+// pctx - pointer to parsing context
+// nFlag - 1=element, 2=signature, 3=sigprop, 4=ts-input
+// bNoXml - no-xml flag
+//--------------------------------------------------
+int ddocSaxParseStartCollecting(SigDocParse* pctx, int nFlag, int bNoXml)
+{
+ RETURN_IF_NULL_PARAM(pctx);
+ switch(nFlag) {
+ case FLAG_XML_ELEM:
+ pctx->bCollectElemData = 1;
+ pctx->errcode = ddocMemBuf_free(&(pctx->mbufElemData));
+ break;
+ case FLAG_SIGNATURE:
+ pctx->bCollectSigData = 1;
+ pctx->errcode = ddocMemBuf_free(&(pctx->mbufSigData));
+ break;
+ case FLAG_SIG_PART:
+ pctx->bCollectSigPartData = 1;
+ pctx->errcode = ddocMemBuf_free(&(pctx->mbufSigPartData));
+ break;
+ }
+ pctx->bNoXMLElemData = bNoXml;
+ return pctx->errcode;
+}
+
+//--------------------------------------------------
+// Ends collecting some element data.
+// pctx - pointer to parsing context
+// nFlag - 1=element, 2=signature, 3=sigprop, 4=ts-input
+// bNoXml - no-xml flag
+//--------------------------------------------------
+int ddocSaxParseEndCollecting(SigDocParse* pctx, int nFlag, int bNoXml)
+{
+ RETURN_IF_NULL_PARAM(pctx);
+ switch(nFlag) {
+ case FLAG_XML_ELEM:
+ pctx->bCollectElemData = 0;
+ pctx->errcode = ddocMemBuf_free(&(pctx->mbufElemData));
+ break;
+ case FLAG_SIGNATURE:
+ pctx->bCollectSigData = 0;
+ pctx->errcode = ddocMemBuf_free(&(pctx->mbufSigData));
+ break;
+ case FLAG_SIG_PART:
+ pctx->bCollectSigPartData = 0;
+ pctx->errcode = ddocMemBuf_free(&(pctx->mbufSigPartData));
+ break;
+ }
+ pctx->bNoXMLElemData = bNoXml;
+ return pctx->errcode;
+}
+
+//--------------------------------------------------
+// Finds the desired atribute value.
+// atts - attributes array
+// name - name of searched atribute
+// defval - default value if not found
+//--------------------------------------------------
+const char* ddocSaxParseFindAttrib(const xmlChar **atts,
+ const char* name, const char* defval)
+{
+ int i;
+
+ for (i = 0; (atts != NULL) && (atts[i] != NULL); i += 2) {
+ if(!strcmp((const char*)atts[i], name))
+ return (const char*)atts[i+1];
+ }
+ return defval;
+}
+
+
+//--------------------------------------------------
+// Decodes a URI value in form #<id>-<type> or #<id>@<type>
+// into its components
+// uri - URI value
+// id - buffer for id
+// nIdLen - id buffer length
+// adr - buffer for adr
+// nAdrLen - adr buffer length
+//--------------------------------------------------
+void decodeURI(const char* uri, char* id, int nIdLen, char* adr, int nAdrLen)
+{
+ int j, b, i, a;
+
+ RETURN_VOID_IF_NULL(uri);
+ RETURN_VOID_IF_NULL(id);
+ RETURN_VOID_IF_NULL(adr);
+
+ id[0] = adr[0] = 0;
+ for(i = j = a = b = 0; uri[j] && (a < nAdrLen-1) && (i < nIdLen-1); j++) {
+ switch(uri[j]) {
+ case '#': continue;
+ case '@': // same as the next
+ case '-': b = 1; continue;
+ default:
+ if(b)
+ adr[a++] = uri[j];
+ else
+ id[i++] = uri[j];
+ }
+ }
+ adr[a] = 0;
+ id[i] = 0;
+}
+
+
+//--------------------------------------------------
+// handles the start of a <SignedDoc> element.
+// Creates SignedDoc structure to read in the info.
+// pctx - pointer to XML parsing work-area
+// name - tag name
+// atts - attributes
+//--------------------------------------------------
+void handleStartSignedDoc(SigDocParse* pctx, const xmlChar *name, const xmlChar **atts)
+{
+ int i;
+ const char *key = NULL, *value = NULL;
+
+ //RETURN_VOID_IF_NULL(pctx);
+ //RETURN_VOID_IF_NULL(name);
+ //RETURN_VOID_IF_NULL(atts);
+
+ strncpy(pctx->ctx1, (const char*)name, sizeof(pctx->ctx1)-1);
+ for (i = 0; (atts != NULL) && (atts[i] != NULL); i += 2) {
+ key = (const char*)atts[i];
+ value = (const char*)atts[i+1];
+ if(!strcmp(key, "format"))
+ setString(&(pctx->pSigDoc->szFormat), value, -1);
+ if(!strcmp(key, "version"))
+ setString(&(pctx->pSigDoc->szFormatVer), value, -1);
+ }
+ if(ddocCheckFormatAndVer(pctx->pSigDoc->szFormat,
+ pctx->pSigDoc->szFormatVer))
+ SET_LAST_ERROR(ERR_UNSUPPORTED_FORMAT);
+}
+
+void unescapeFilename(char** szFileName, const char* str1, const char* str2)
+{
+ DigiDocMemBuf mbuf1, mbuf2;
+ mbuf1.pMem = 0;
+ mbuf1.nLen = 0;
+ mbuf2.pMem = 0;
+ mbuf2.nLen = 0;
+ ddocDebug(4, "unescapeFilename", "In: %s replace: %s with: %s", *szFileName, str1, str2);
+ if(szFileName && strstr((const char*)(*szFileName), str1)) {
+ mbuf1.pMem = *szFileName; mbuf1.nLen = strlen(*szFileName);
+ ddocMemReplaceSubstr(&mbuf1, &mbuf2, str1, str2);
+ setString(szFileName, (const char*)mbuf2.pMem, -1);
+ ddocMemBuf_free(&mbuf2);
+ ddocDebug(4, "unescapeFilename", "Escaped: %s", *szFileName);
+ }
+}
+
+int utf8strlen(const char* src)
+{
+ int i, j;
+ unsigned char uc;
+ for(i = 0, j = 0; src && src[i]; i++) {
+ uc = (unsigned char)(0x000000FF & src[i]);
+ if(uc <= 0x7F || uc >= 0xC0)
+ j++;
+ }
+ ddocDebug(4, "utf8strlen", "Str: %s, len: %d", src, j);
+ return j;
+}
+
+//--------------------------------------------------
+// handles the start of a <DataFile> element.
+// Reads in id, filename, mime_type and embedded attributes
+// pctx - pointer to XML parsing work-area
+// name - tag name
+// atts - attributes
+//--------------------------------------------------
+void handleStartDataFile(SigDocParse* pctx, const xmlChar *name, const xmlChar **atts)
+{
+ int i, err = ERR_OK, j;
+ long size = -1;
+ const char *id = 0, *mime = 0, *dtype = 0, *dvalue = 0, *ctype = 0;
+ char *p = 0;
+ DigiDocMemBuf mbuf1, mbuf2;
+ DataFile* pDataFile = NULL;
+
+ mbuf1.pMem = 0;
+ mbuf1.nLen = 0;
+ mbuf2.pMem = 0;
+ mbuf2.nLen = 0;
+ ddocDebug(4, "handleStartDataFile", "Ignore: %d", pctx->nIgnoreDataFile);
+ strncpy(pctx->ctx1, (const char*)name, sizeof(pctx->ctx1));
+ id = mime = dtype = dvalue = 0;
+ size = 0;
+ // allocate mem dynamically and calculate required size as necessary
+ if(!pctx->nIgnoreDataFile) {
+ pctx->bCollectElemData = 1;
+ }
+ for (i = 0; (atts != NULL) && (atts[i] != NULL); i += 2) {
+ if(!strcmp((const char*)atts[i], "Id"))
+ id = (const char*)atts[i+1];
+ if(!strcmp((const char*)atts[i], "Filename")) {
+ escapeXMLSymbols((const char*)atts[i+1], -1, &p);
+ if(p)
+ err = ddocMemAppendData(&mbuf1, p, -1);
+ free(p); p = 0;
+ ddocDebug(4, "handleStartDataFile", "Filename in: \'%s\' out: \'%s\'",
+ atts[i+1], (char*)mbuf1.pMem);
+ if(strchr((char*)mbuf1.pMem, '/') || strchr((char*)mbuf1.pMem, '\\')) {
+ ddocDebug(1, "handleStartDataFile", "Invalid filename: \'%s\'", (char*)mbuf1.pMem);
+ SET_LAST_ERROR(ERR_DF_NAME);
+ return;
+ }
+ }
+ if(!strcmp((const char*)atts[i], "MimeType"))
+ mime = (const char*)atts[i+1];
+ if(!strcmp((const char*)atts[i], "ContentType"))
+ ctype = (const char*)atts[i+1];
+ if(!strcmp((const char*)atts[i], "DigestType"))
+ dtype = (const char*)atts[i+1];
+ if(!strcmp((const char*)atts[i], "DigestValue"))
+ dvalue = (const char*)atts[i+1];
+ if(!strcmp((const char*)atts[i], "Size"))
+ size = atol((const char*)atts[i+1]);
+ }
+ if (!id || (strlen(id) > 21)) {
+ SET_LAST_ERROR(ERR_DIGIDOC_PARSE);
+ ddocDebug(1, "handleStartDataFile", "Arr err id: %s", id);
+ return;
+ }
+ // VS: check id uniqueness
+ for(j = 0; j < getCountOfDataFiles(pctx->pSigDoc); j++) {
+ pDataFile = getDataFile(pctx->pSigDoc, j);
+ if(pDataFile && pDataFile->szId && !strcmp(pDataFile->szId, id)) {
+ ddocDebug(1, "handleStartDataFile", "DF %d has same id: %s", j, id);
+ SET_LAST_ERROR(ERR_DIGIDOC_PARSE);
+ return;
+ }
+ }
+ if (!mime || (strlen(mime) > 255)) {
+ SET_LAST_ERROR(ERR_DIGIDOC_PARSE);
+ ddocDebug(1, "handleStartDataFile", "Arr err mime: %s", mime);
+ return;
+ }
+ if (!mbuf1.pMem || (utf8strlen(mbuf1.pMem) > 255)) {
+ SET_LAST_ERROR(ERR_DIGIDOC_PARSE);
+ return;
+ }
+ if (size < 0) {
+ SET_LAST_ERROR(ERR_DIGIDOC_PARSE);
+ ddocDebug(1, "handleStartDataFile", "Arr err size: %d", size);
+ return;
+ }
+ if (!ctype || (strlen(ctype) > 40)) {
+ SET_LAST_ERROR(ERR_DIGIDOC_PARSE);
+ ddocDebug(1, "handleStartDataFile", "Arr err ctype: %s", ctype);
+ return;
+ }
+ if (!pctx->pSigDoc->szFormatVer) {
+ SET_LAST_ERROR(ERR_DIGIDOC_PARSE);
+ ddocDebug(1, "handleStartDataFile", "Arr err sigdoc missing");
+ return;
+ }
+ if ((dtype && (strlen(dtype) > 10)) ||
+ (dvalue && (strlen(dvalue) > 100))) {
+ SET_LAST_ERROR(ERR_DIGIDOC_PARSE);
+ ddocDebug(1, "handleStartDataFile", "Arr err - dtype: %s dvalue: %s", dtype, dvalue);
+ return;
+ }
+ if((!ctype || strcmp(ctype, CONTENT_EMBEDDED_BASE64))
+ && !ConfigItem_lookup_bool("EMBEDDED_XML_SUPPORT", 0)) {
+ SET_LAST_ERROR(ERR_BAD_DATAFILE_CONTENT_TYPE);
+ return;
+ }
+ ddocDebug(4, "handleStartDataFile", "Check ignore");
+ // if not in ignore mode / level
+ if(!pctx->nIgnoreDataFile) {
+ strncpy(pctx->ctx2, id, sizeof(pctx->ctx2)-1);
+ ddocDebug(4, "handleStartDataFile", "Start DF: %s", id);
+ if(ctype && !strcmp(ctype, CONTENT_EMBEDDED_BASE64)) {
+ EVP_DecodeInit(&(pctx->ectx));
+ ddocDebug(3, "handleStartDataFile", "Init sha1");
+ SHA1_Init(&(pctx->sctx));
+ SHA1_Init(&(pctx->sctx2));
+ }
+ if(pctx->bDataFile)
+ pctx->bDataFile = BIO_new_file((char*)mbuf1.pMem, "w");
+ strncpy(pctx->ctx3, ctype, sizeof(pctx->ctx3)-1);
+ if(strcmp(pctx->pSigDoc->szFormatVer, DIGIDOC_XML_1_3_VER)) {
+ // copy value first
+ err = ddocMemAssignData(&mbuf2, (const char*)mbuf1.pMem, mbuf1.nLen+1);
+ // apply conversion - no length change
+ convWinToFName((const char*)mbuf1.pMem, (char*)mbuf2.pMem, mbuf2.nLen);
+ err = DataFile_new(&pDataFile, pctx->pSigDoc, id, (char*)mbuf2.pMem, ctype,
+ mime, size, NULL, 0, dtype, CHARSET_UTF_8);
+ }
+ else
+ err = DataFile_new(&pDataFile, pctx->pSigDoc, id, (char*)mbuf1.pMem, ctype,
+ mime, size, NULL, 0, dtype, CHARSET_UTF_8);
+ // RETURN_IF_NULL(pDataFile);
+ ddocDebug(4, "handleStartDataFile", "Create DF: \'%s\' - err: %d", id, err);
+ if(dvalue) {
+ err = ddocMemBuf_free(&mbuf2);
+ err = ddocDecodeBase64Data((void*)dvalue, -1, &mbuf2);
+ ddocDataFile_SetDetachedDigestValue(pDataFile, (const char*)mbuf2.pMem, mbuf2.nLen);
+ }
+ // add other attributes
+ for (i = 0; (atts != NULL) && (atts[i] != NULL); i += 2) {
+ if(strcmp((const char*)atts[i], "Id") && strcmp((const char*)atts[i], "Filename") &&
+ strcmp((const char*)atts[i], "MimeType") && strcmp((const char*)atts[i], "DigestValue") &&
+ strcmp((const char*)atts[i], "Size") && strcmp((const char*)atts[i], "ContentType") &&
+ strcmp((const char*)atts[i], "DigestType") && strcmp((const char*)atts[i], "xmlns"))
+ err = addDataFileAttribute(pDataFile, (const char*)atts[i], (const char*)atts[i+1]);
+ }
+ }
+ // is it pure XML ?
+ if(!strcmp(ctype, CONTENT_EMBEDDED) || pctx->nIgnoreDataFile)
+ pctx->nIgnoreDataFile++;
+ // cleanup
+ err = ddocMemBuf_free(&mbuf2);
+ err = ddocMemBuf_free(&mbuf1);
+ // replace &amp; with & if necessary
+ unescapeFilename(&(pDataFile->szFileName), "&amp;", "&");
+ unescapeFilename(&(pDataFile->szFileName), "&apos;", "'");
+ unescapeFilename(&(pDataFile->szFileName), "&quot;", "\"");
+ ddocDebug(4, "handleStartDataFile", "Final filename: \'%s\'", pDataFile->szFileName);
+}
+
+
+//--------------------------------------------------
+// handles the content of a <DataFile> element.
+// Reads in data file (Base64) data, decodes it
+// and writes to a file
+// pctx - pointer to XML parsing work-area
+// value - character values read from file
+// len - length of chars ???
+//--------------------------------------------------
+void handleDataFile(SigDocParse* pctx, const xmlChar *value, int len)
+{
+ int l, i, j;
+ char buf[1024], ch;
+ DataFile* pDf = 0;
+ DigiDocMemBuf mbuf1;
+ // decode the content data
+ ddocDebug(4, "handleDataFile", "DF: %s, append len: %d", pctx->ctx2, len);
+ pDf = getDataFileWithId(pctx->pSigDoc, pctx->ctx2);
+ RETURN_VOID_IF_NULL(pDf);
+ ddocAppendDataFileData(pDf, pctx->lMaxDFLen, (void*)value, len, !strcmp(pDf->szContentType, CONTENT_EMBEDDED_BASE64));
+ if(!strcmp(pctx->ctx3, CONTENT_EMBEDDED_BASE64)) {
+ // if using DataFile Base64 hack
+#ifdef WITH_BASE64_HASHING_HACK
+ if(pctx->pSigDoc->szFormatVer && strcmp(pctx->pSigDoc->szFormatVer, SK_XML_1_VER) &&
+ pctx->pSigDoc->szFormat && strcmp(pctx->pSigDoc->szFormat, SK_XML_1_NAME)) {
+ ch = ((char*)value)[len];
+ ((char*)value)[len] = 0;
+ ddocDebug(4, "handleDataFile", "sha1 update: \'%s\' len: %d", value, len);
+ mbuf1.pMem = (char*)value;
+ mbuf1.nLen = len;
+ ddocDebugWriteFile(4, "df-data.txt", &mbuf1);
+ ((char*)value)[len] = ch;
+ SHA1_Update(&(pctx->sctx), (char*)value, len);
+ SHA1_Update(&(pctx->sctx2), (char*)value, len);
+ ddocMemBuf_free(&(pctx->mbufElemData));
+ if(pctx->bDataFile) {
+ i = j = 0;
+ while(i < len) {
+ i = (i + 512 > len) ? len : i + 512;
+ l = sizeof(buf);
+ memset(buf, 0, sizeof(buf));
+ EVP_DecodeUpdate(&(pctx->ectx), (unsigned char*)buf, &l, (unsigned char*)value + j, i - j);
+ BIO_write(pctx->bDataFile, buf, l);
+ j = i;
+ }
+ }
+ } else {
+#endif
+ i = j = 0;
+ while(i < len) {
+ i = (i + 512 > len) ? len : i + 512;
+ l = sizeof(buf);
+ memset(buf, 0, sizeof(buf));
+ EVP_DecodeUpdate(&(pctx->ectx), (unsigned char*)buf, &l, (unsigned char*)value + j, i - j);
+ if(pctx->bDataFile)
+ BIO_write(pctx->bDataFile, buf, l);
+ buf[l] = 0;
+ ddocDebug(4, "handleDataFile", "update sha1: %s", buf);
+ SHA1_Update(&(pctx->sctx), buf, l);
+ SHA1_Update(&(pctx->sctx2), buf, l);
+ j = i;
+ }
+#ifdef WITH_BASE64_HASHING_HACK
+ }
+#endif
+ } else if(!strcmp(pctx->ctx3, CONTENT_EMBEDDED)) {
+ if(pctx->bDataFile)
+ BIO_write(pctx->bDataFile, value, len);
+ }
+}
+
+
+//--------------------------------------------------
+// handles the end of a <DataFile> element.
+// Finishes writing file data
+// pctx - pointer to XML parsing work-area
+// name - tag name
+//--------------------------------------------------
+void handleEndDataFile(SigDocParse* pctx, const xmlChar *name)
+{
+ int l1, err;
+ long l;
+ char buf[1024], *pTmp1 = 0, *pTmp2 = 0;
+ DataFile* pDf = 0;
+ time_t t1, t2;
+ DigiDocMemBuf mbuf1;
+
+ ddocDebug(4, "handleEndDataFile", "DF: %s", pctx->ctx2);
+ if(pctx->nIgnoreDataFile > 0 && !strcmp(pctx->ctx3, CONTENT_EMBEDDED))
+ pctx->nIgnoreDataFile--;
+ if(pctx->nIgnoreDataFile)
+ return;
+ pDf = getDataFileWithId(pctx->pSigDoc, pctx->ctx2);
+ RETURN_VOID_IF_NULL(pDf);
+ RETURN_VOID_IF_NULL(pDf->szContentType);
+
+ // if store file data
+ if(pctx->bDataFile &&
+ !strcmp(pDf->szContentType, CONTENT_EMBEDDED_BASE64)) {
+ l1 = sizeof(buf);
+ EVP_DecodeFinal(&(pctx->ectx), (unsigned char*)buf, &l1);
+ BIO_write(pctx->bDataFile, buf, l1);
+ BIO_free(pctx->bDataFile);
+ pctx->bDataFile = NULL;
+ }
+ // in version 1.0 we calculate digest over original data
+ if(pctx->pSigDoc->szFormat && !strcmp(pctx->pSigDoc->szFormat, SK_XML_1_NAME)) {
+ if(!strcmp(pDf->szContentType, CONTENT_EMBEDDED_BASE64)) {
+ ddocDebug(3, "handleEndDataFile", "final sha1");
+ SHA1_Final((unsigned char*)buf, &(pctx->sctx));
+ checkErrors();
+ ddocDataFile_SetDigestValue(pDf, buf, DIGEST_LEN);
+ SHA1_Final((unsigned char*)buf, &(pctx->sctx2));
+ ddocDataFile_SetWrongDigestValue(pDf, buf, DIGEST_LEN);
+ // debug
+ l1 = sizeof(buf);
+ bin2hex(pDf->mbufDigest.pMem, pDf->mbufDigest.nLen, buf, &l1);
+ ddocDebug(3, "handleEndDataFile", "DF: %s calc digest: %s len: %d",
+ pDf->szId, buf, l1);
+ } else if(!strcmp(pDf->szContentType, CONTENT_EMBEDDED)) {
+ if(pctx->mbufElemData.pMem) {
+ l1 = sizeof(buf);
+ // remove the tag end marker
+ pTmp2 = (char*)(pctx->mbufElemData.pMem) + pctx->mbufElemData.nLen - 1;
+ while(*pTmp2 != '<' && pTmp2 > (char*)pctx->mbufElemData.pMem)
+ pTmp2--;
+ if(*pTmp2 == '<')
+ *pTmp2 = 0;
+ //skip leading newlines
+ pTmp1 = (char*)pctx->mbufElemData.pMem;
+ while(*pTmp1 && *pTmp1 != '<') pTmp1++;
+ if(pctx->bDataFile) {
+ BIO_write(pctx->bDataFile, pTmp1, strlen(pTmp1));
+ BIO_free(pctx->bDataFile);
+ pctx->bDataFile = 0;
+ }
+ err = calculateDigest((const byte*)pTmp1, strlen(pTmp1),
+ DIGEST_SHA1, (byte*)buf, &l1);
+ if(!err)
+ ddocDataFile_SetDigestValue(pDf, buf, DIGEST_LEN);
+ // free collected data
+ // and mark the end of data collecting mode
+ ddocMemBuf_free(&(pctx->mbufElemData));
+ pctx->bCollectElemData = 0;
+ }
+ } else if(pctx->checkFileDigest) {
+ l1 = sizeof(buf);
+ err = calculateFileDigest(pDf->szFileName,
+ DIGEST_SHA1, (byte*)buf, &l1, &l);
+ if(!err)
+ ddocDataFile_SetDigestValue(pDf, buf, DIGEST_LEN);
+ else
+ ddocMemBuf_free(&(pDf->mbufDigest));
+ }
+ }
+ // in version 1.1 we calculate digest over the whole <DataFile>
+ // in canonicalized form
+ else {
+ // if use base64 hack of datafile
+#ifdef WITH_BASE64_HASHING_HACK
+ if(!strcmp(pDf->szContentType, CONTENT_EMBEDDED_BASE64)) {
+ strncpy(buf, "</DataFile>", sizeof(buf));
+ ddocDebug(3, "handleEndDataFile", "final sha1 update: \'%s\'", buf);
+ mbuf1.pMem = "</DataFile>";
+ mbuf1.nLen = strlen("</DataFile>");
+ ddocDebugWriteFile(4, "df-data.txt", &mbuf1);
+ SHA1_Update(&(pctx->sctx), buf, strlen(buf));
+ SHA1_Update(&(pctx->sctx2), buf, strlen(buf));
+ memset(buf, 0, sizeof(buf));
+ SHA1_Final((unsigned char*)buf, &(pctx->sctx));
+ ddocDataFile_SetDigestValue(pDf, buf, DIGEST_LEN);
+ SHA1_Final((unsigned char*)buf, &(pctx->sctx2));
+ ddocDataFile_SetWrongDigestValue(pDf, buf, DIGEST_LEN);
+ setString((char**)&(pDf->szDigestType), DIGEST_SHA1_NAME, -1);
+ // debug
+ l1 = sizeof(buf);
+ encode((const byte*)pDf->mbufDigest.pMem, pDf->mbufDigest.nLen, (byte*)buf, &l1);
+ ddocDebug(3, "handleEndDataFile", "DF: %s calc digest: %s len: %d", pDf->szId, buf, l1);
+ ddocMemBuf_free(&(pctx->mbufElemData));
+ pctx->bCollectElemData = 0;
+ // wrong digest
+ l1 = sizeof(buf);
+ encode((const byte*)pDf->mbufWrongDigest.pMem, pDf->mbufWrongDigest.nLen, (byte*)buf, &l1);
+ ddocDebug(3, "handleEndDataFile", "DF: %s alt calc digest: %s len: %d", pDf->szId, buf, l1);
+
+ } else {
+#endif
+ // debug
+ time(&t1);
+ ddocDebug(4, "handleEndDataFile", "DF: %s data-len: %ld, parsing time: %d [sek]",
+ (const char*)name, pctx->mbufElemData.nLen, (t1 - pctx->tStartParse));
+ ddocDebug(8, "handleEndDataFile", "DF: %s data:\n%s", (const char*)name, pctx->mbufElemData.pMem);
+ if(pctx->mbufElemData.pMem) {
+ pTmp2 = canonicalizeXML((char*)pctx->mbufElemData.pMem, pctx->mbufElemData.nLen);
+ time(&t2);
+ ddocDebug(4, "handleEndDataFile", "Canonicalizing: %s, time: %d [sek]",
+ (pTmp2 ? "OK" : "ERROR"), (t2 - t1));
+ if(pTmp2) {
+ SHA1_Init(&(pctx->sctx));
+ SHA1_Update(&(pctx->sctx), pTmp2, strlen(pTmp2));
+ SHA1_Final((unsigned char*)buf,&(pctx->sctx));
+ ddocDataFile_SetDigestValue(pDf, buf, DIGEST_LEN);
+ setString((char**)&(pDf->szDigestType), DIGEST_SHA1_NAME, -1);
+ ddocDebug(4, "handleEndDataFile", "DF: %s digest updated", pDf->szId);
+ l1 = sizeof(buf);
+ encode((byte*)pDf->mbufDigest.pMem, pDf->mbufDigest.nLen, (byte*)buf, &l1);
+ ddocDebug(4, "handleEndDataFile", "DF: %s calc digest: %s len: %d", pDf->szId, buf, l1);
+ // P.R ends
+ ddocDebug(4, "handleEndDataFile", "DF: %s canonical XML: \'%s\'", pDf->szId, pTmp2);
+
+ ddocDebug(4, "handleEndDataFile", "DF: %s calc digest: %s len: %d",
+ pDf->szId, buf, l1);
+ ddocDebug(4, "handleEndDataFile", "DF: %s canonical XML: \'%s\'",
+ pDf->szId, pTmp2);
+ free(pTmp2);
+ } // if(pTmp2)
+ ddocMemBuf_free(&(pctx->mbufElemData));
+ pctx->bCollectElemData = 0;
+ } // if(pctx->mbufElemData.pMem)
+#ifdef WITH_BASE64_HASHING_HACK
+ } // else not base64 hack
+#endif
+ } // else
+}
+
+
+//--------------------------------------------------
+// handles the start of a <Signature> element.
+// Adds a SignatureInfo struct to SignedDoc structure.
+// pctx - pointer to XML parsing work-area
+// name - tag name
+// atts - attributes
+//--------------------------------------------------
+void handleStartSignature(SigDocParse* pctx, const xmlChar **atts)
+{
+ int i, j;
+ SignatureInfo *pSignatureInfo;
+
+ if(!pctx->pSigDoc || !pctx->pSigDoc->szFormat) {
+ pctx->errcode = ERR_DIGIDOC_PARSE;
+ addError(pctx->errcode, __FILE__, __LINE__, "Signature not in ddoc container!");
+ // ddocDebug(1, "handleStartSignature", "Signature has no ddoc container");
+ // SET_LAST_ERROR(ERR_DIGIDOC_PARSE);
+ return;
+ }
+ for (i = 0; (atts != NULL) && (atts[i] != NULL); i += 2) {
+ if(!strcmp((const char*)atts[i], "Id")) {
+ memset(pctx->ctx1, 0, sizeof(pctx->ctx1));
+ memset(pctx->ctx2, 0, sizeof(pctx->ctx2));
+ memset(pctx->ctx3, 0, sizeof(pctx->ctx3));
+ strncpy(pctx->ctx1, (const char*)atts[i+1], /*sizeof(pctx->ctx1)-*/50);
+ // check id uniqueness
+ for(j = 0; j < getCountOfSignatures(pctx->pSigDoc); j++) {
+ pSignatureInfo = getSignature(pctx->pSigDoc, j);
+ if(pSignatureInfo && pSignatureInfo->szId && !strcmp(pSignatureInfo->szId, (const char*)atts[i+1])) {
+ ddocDebug(1, "handleStartSignature", "Signature: %d has same id: %s", j, (const char*)atts[i+1]);
+ SET_LAST_ERROR(ERR_DIGIDOC_PARSE);
+ return;
+ }
+ }
+ SignatureInfo_new(&pSignatureInfo, pctx->pSigDoc, (const char*)atts[i+1]); // MEMLEAK: ???
+ }
+ }
+}
+
+
+
+//--------------------------------------------------
+// handles the start of a <Reference> element.
+// Records the reference URI attribute
+// pctx - pointer to XML parsing work-area
+// atts - attributes
+//--------------------------------------------------
+void handleStartReference(SigDocParse* pctx, const xmlChar **atts)
+{
+ strncpy(pctx->ctx2, ddocSaxParseFindAttrib(atts, "URI", ""), sizeof(pctx->ctx2)-1);
+}
+
+//--------------------------------------------------
+// handles the start of a <SignatureMethod> element.
+// Records the signature method
+// pctx - pointer to XML parsing work-area
+// atts - attributes
+//--------------------------------------------------
+void handleStartSignatureMethod(SigDocParse* pctx, const xmlChar **atts)
+{
+ SignatureInfo *pSigInfo;
+ const char *alg;
+
+ alg = ddocSaxParseFindAttrib(atts, "Algorithm", NULL);
+ pSigInfo = ddocGetLastSignature(pctx->pSigDoc);
+ if((alg != NULL) && (pSigInfo != NULL) &&
+ !strcmp(alg+strlen(alg)-8, "rsa-sha1") &&
+ (pctx->ctx1[0] == 'S')) {
+ ddocSignatureValue_new(&(pSigInfo->pSigValue), 0, SIGN_RSA_NAME, 0, 0);
+ }
+#ifdef WITH_ECDSA
+ else if((alg != NULL) && (pSigInfo != NULL) &&
+ !strcmp(alg+strlen(alg)-10, "ecdsa-sha1") &&
+ (pctx->ctx1[0] == 'S')) {
+ ddocSignatureValue_new(&(pSigInfo->pSigValue), 0, SIGN_ECDSA_NAME, 0, 0);
+ }
+#endif
+}
+
+
+//--------------------------------------------------
+// handles the start of a <DigestMethod> element.
+// Records the digest method
+// pctx - pointer to XML parsing work-area
+// name - tag name
+// atts - attributes
+//--------------------------------------------------
+void handleStartDigestMethod(SigDocParse* pctx, const xmlChar **atts)
+{
+ SignatureInfo *pSigInfo;
+ const char *alg;
+
+ alg = ddocSaxParseFindAttrib(atts, "Algorithm", NULL);
+ pSigInfo = ddocGetLastSignature(pctx->pSigDoc);
+ if((alg != NULL) && (pSigInfo != NULL) &&
+ !strcmp(alg+strlen(alg)-4, "sha1"))
+ strncpy(pctx->ctx3, DIGEST_SHA1_NAME, sizeof(pctx->ctx3));
+ else
+ pctx->ctx3[0] = 0;
+}
+
+//--------------------------------------------------
+// This function should be called at the end of
+// </EncapsulatedOCSPValue> to determine the correct
+// types of CertID and CertValue objects.
+// pSigInfo - signature object
+//--------------------------------------------------
+int selectCertIdAndValueTypes(SignatureInfo* pSigInfo)
+{
+ int err = ERR_OK, i, j, l1;
+ CertID* cid;
+ CertValue *cval1, *cval2;
+ X509* pCert;
+ char buf1[300];
+ DigiDocMemBuf mbuf1, mbuf2;
+ const DigiDocMemBuf *pMBuf = 0;
+
+ RETURN_IF_NULL_PARAM(pSigInfo);
+ mbuf1.pMem = 0;
+ mbuf1.nLen = 0;
+ mbuf2.pMem = 0;
+ mbuf2.nLen = 0;
+ for(i = 0; pSigInfo->pCertIDs &&
+ i < ddocCertIDList_GetCertIDsCount(pSigInfo->pCertIDs); i++) {
+ cid = ddocCertIDList_GetCertID(pSigInfo->pCertIDs, i);
+ ddocDebug(3, "selectCertIdAndValueTypes", "CID type: %d serial %s - %s", cid->nType, cid->szIssuerSerial, cid->szIssuerName);
+ if(cid && cid->nType == CERTID_TYPE_UNKNOWN) {
+ ddocDebug(3, "selectCertIdAndValueTypes", "Find type for cid: %s - %s", cid->szIssuerSerial, cid->szIssuerName);
+ // find corresponding CertValue
+ cval1 = NULL;
+ for(j = 0; pSigInfo->pCertValues &&
+ (j < ddocCertValueList_GetCertValuesCount(pSigInfo->pCertValues)); j++) {
+ cval2 = ddocCertValueList_GetCertValue(pSigInfo->pCertValues, j);
+ if(cval2) {
+ pCert = ddocCertValue_GetCert(cval2);
+ l1 = sizeof(buf1);
+ memset(buf1, 0, l1);
+ ReadCertSerialNumber(buf1, l1, pCert);
+ //AM 19.09.08
+ if(cid->szIssuerSerial){
+ if(!strcmp(cid->szIssuerSerial, buf1)) {
+ cval1 = cval2;
+ break; // found it
+ }
+ }
+ // should I check also hash value?
+ }
+ } // for certValues
+ // if found matching CertID and CertValue
+ if(cval1) {
+ ddocDebug(3, "selectCertIdAndValueTypes", "CertID: %s - %s -> CertValue: %s",
+ cid->szIssuerSerial, cid->szIssuerName, cval1->szId);
+ // Test1: is this an OCSP responders cert?
+ if(pSigInfo->pNotary)
+ pMBuf = (DigiDocMemBuf*)ddocNotInfo_GetResponderId(pSigInfo->pNotary);
+ if(pMBuf) {
+ if(pSigInfo->pNotary->nRespIdType == RESPID_NAME_TYPE) {
+ err = ddocCertGetSubjectCN(ddocCertValue_GetCert(cval1), &mbuf1);
+ memset(buf1, 0, sizeof(buf1));
+ findCN((char*)pMBuf->pMem, buf1, sizeof(buf1)); // defined in DigiDocConfig.c
+ if(!strcmp(buf1, (const char*)mbuf1.pMem)) {
+ // yes this is a responders cert
+ ddocDebug(3, "selectCertIdAndValueTypes", "cert: %s responder %s -> RESPONDER",
+ (const char*)mbuf1.pMem, buf1);
+ cid->nType = CERTID_TYPE_RESPONDERS_CERTID;
+ cval1->nType = CERTID_VALUE_RESPONDERS_CERT;
+ snprintf(buf1, sizeof(buf1), "%s-RESPONDERS_CERTINFO", pSigInfo->szId);
+ ddocCertID_SetId(cid, buf1);
+ }
+ ddocMemBuf_free(&mbuf1);
+ } // ByName
+ if(pSigInfo->pNotary->nRespIdType == RESPID_KEY_TYPE) {
+ err = ddocCertGetPubkeyDigest(ddocCertValue_GetCert(cval1), &mbuf1);
+ l1 = sizeof(buf1);
+ memset(buf1, 0, l1);
+ bin2hex((const byte*)mbuf1.pMem, mbuf1.nLen, buf1, &l1);
+ ddocDebug(3, "selectCertIdAndValueTypes", "cert hash: %s", buf1);
+ l1 = sizeof(buf1);
+ memset(buf1, 0, l1);
+ bin2hex((const byte*)pMBuf->pMem, pMBuf->nLen, buf1, &l1);
+ ddocDebug(3, "selectCertIdAndValueTypes", "respid: %s", buf1);
+
+ ddocEncodeBase64(&mbuf1, &mbuf2);
+ ddocMemBuf_free(&mbuf1);
+ ddocEncodeBase64(pMBuf, &mbuf1);
+ ddocDebug(3, "selectCertIdAndValueTypes", "cert: %s responder %s",
+ (const char*)mbuf2.pMem, (const char*)mbuf1.pMem);
+ if(!strcmp((const char*)mbuf2.pMem, (const char*)mbuf1.pMem)) {
+ // yes this is a responders cert
+ ddocDebug(3, "selectCertIdAndValueTypes", "cert: %s responder %s -> RESPONDER",
+ (const char*)mbuf2.pMem, (const char*)mbuf1.pMem);
+ cid->nType = CERTID_TYPE_RESPONDERS_CERTID;
+ cval1->nType = CERTID_VALUE_RESPONDERS_CERT;
+ snprintf(buf1, sizeof(buf1), "%s-RESPONDERS_CERTINFO", pSigInfo->szId);
+ ddocCertID_SetId(cid, buf1);
+ }
+ ddocMemBuf_free(&mbuf1);
+ ddocMemBuf_free(&mbuf2);
+ } // ByKey
+ } // if pMBuf
+ }
+ } // for certids
+ }
+ return err;
+}
+
+
+//--------------------------------------------------
+// handles the start of a <EncapsulatedOCSPValue> element.
+// Records the OCSP response data
+// pctx - pointer to XML parsing work-area
+// name - tag name
+//--------------------------------------------------
+// FIXME : error handling
+void handleEndEncapsulatedOCSPValue(SigDocParse* pctx)
+{
+ OCSP_RESPONSE* pResp;
+ NotaryInfo* pNotInfo = 0;
+ SignatureInfo* pSig = 0;
+
+ // convert the X509 cert data to
+ // cert and replace the pointer value
+ RETURN_VOID_IF_NULL(pctx->pSigDoc->szFormatVer);
+ pNotInfo = ddocGetLastNotaryInfo(pctx->pSigDoc);
+ RETURN_VOID_IF_NULL(pNotInfo); // VS: 1.76 correct the check
+ pSig = ddocGetLastSignature(pctx->pSigDoc);
+ RETURN_VOID_IF_NULL(pSig);
+ /*pctx->errcode =*/ ddocDecodeOCSPResponsePEMData(&pResp,
+ (const byte*)pctx->mbufElemData.pMem, (int)pctx->mbufElemData.nLen);
+ // cleanup
+ ddocSaxParseEndCollecting(pctx, FLAG_XML_ELEM, 0);
+ if(pResp) {
+ // in ver 1.2 we have correct OCSP digest
+ // VS 1.76 - add 1.3 version too
+ if(!strcmp(pctx->pSigDoc->szFormatVer, DIGIDOC_XML_1_2_VER) ||
+ !strcmp(pctx->pSigDoc->szFormatVer, DIGIDOC_XML_1_3_VER))
+ pctx->errcode = initializeNotaryInfoWithOCSP(pctx->pSigDoc, pNotInfo, pResp, ddocSigInfo_GetOCSPRespondersCert(pSig), 0);
+ else // in older versions the digest was incorrect
+ /*pctx->errcode =*/ initializeNotaryInfoWithOCSP(pctx->pSigDoc, pNotInfo, pResp, ddocSigInfo_GetOCSPRespondersCert(pSig), 1);
+ OCSP_RESPONSE_free(pResp);
+ } /*else
+ checkErrors();*/
+ ddocDebug(3, "handleEndEncapsulatedOCSPValue", "RC: %d", pctx->errcode);
+ if(pctx->errcode)
+ return;
+ // now we have OCSP value too
+ // determine the correct types of certid and certvalue objects now
+ /*pctx->errcode =*/ selectCertIdAndValueTypes(pSig);
+}
+
+
+//--------------------------------------------------
+// handles the start of a <SignedProperties> element.
+// Records the id and target attributes
+// pctx - pointer to XML parsing work-area
+// name - tag name
+// atts - attributes
+//--------------------------------------------------
+void handleStartSignedProperties(SigDocParse* pctx, const xmlChar **atts)
+{
+ if(!pctx->nIgnoreDataFile)
+ ddocSaxParseStartCollecting(pctx, FLAG_SIG_PART, 0);
+ strncpy(pctx->ctx2, ddocSaxParseFindAttrib(atts, "Id", ""), sizeof(pctx->ctx2)-1);
+ strncpy(pctx->ctx3, ddocSaxParseFindAttrib(atts, "Target", ""), sizeof(pctx->ctx3)-1);
+}
+
+//--------------------------------------------------
+// handles the end of a <SignedProperties> element.
+// Records the digest of this element
+// pctx - pointer to XML parsing work-area
+// name - tag name
+//--------------------------------------------------
+void handleEndSignedProperties(SigDocParse* pctx)
+{
+ char* pTmp2;
+ char buf[DIGEST_LEN+3], buf2[40];
+ int l2;
+ SignatureInfo* pSigInfo;
+ DigiDocMemBuf mbuf1;
+
+ pSigInfo = ddocGetLastSignature(pctx->pSigDoc);
+ if(pctx->mbufSigPartData.pMem && pSigInfo) {
+ ddocDebug(5, "handleEndSignedProperties", "DATA: %d ->%s",
+ pctx->mbufSigPartData.nLen, (char*)pctx->mbufSigPartData.pMem);
+ ddocDebugWriteFile(4, "sigprop-can1.txt", &(pctx->mbufSigPartData));
+ pTmp2 = canonicalizeXML((char*)pctx->mbufSigPartData.pMem, pctx->mbufSigPartData.nLen);
+
+ //dumpInFile("sigprop-can2.txt", pTmp2);
+ if(pTmp2) {
+ mbuf1.pMem = pTmp2;
+ mbuf1.nLen = strlen(pTmp2);
+ ddocDebugWriteFile(4, "sigprop-can2.txt", &mbuf1);
+ ddocDebug(5, "handleEndSignedProperties", "HASH over: \n---\n%s\n---\n",
+ pTmp2);
+ SHA1_Init(&(pctx->sctx));
+ SHA1_Update(&(pctx->sctx), pTmp2, strlen(pTmp2));
+ SHA1_Final((unsigned char*)buf,&(pctx->sctx));
+ ddocSigInfo_SetSigPropRealDigest(pSigInfo, buf, DIGEST_LEN);
+ l2 = 40;
+ encode((const byte*)buf, DIGEST_LEN, (byte*)buf2, &l2);
+ ddocDebug(5, "handleEndSignedProperties", "SigProp hash: %s", buf2);
+ free(pTmp2);
+ }
+ ddocSaxParseEndCollecting(pctx, FLAG_SIG_PART, 0);
+ pctx->checkUTF8 = 0;
+ }
+}
+
+
+//--------------------------------------------------
+// handles the start of a <SignedInfo> element.
+// Starts recording data for digest calculation
+// pctx - pointer to XML parsing work-area
+// name - tag name
+// atts - attributes
+//--------------------------------------------------
+void handleStartSignedInfo(SigDocParse* pctx)
+{
+ if(!pctx->nIgnoreDataFile) {
+ // mark the start of data collect mode
+ pctx->errcode = ddocSaxParseStartCollecting(pctx, FLAG_SIG_PART, 0);
+ pctx->checkUTF8 = 1;
+ }
+}
+
+//--------------------------------------------------
+// handles the end of a <SignedInfo> element.
+// Records the digest of this element
+// pctx - pointer to XML parsing work-area
+// name - tag name
+//--------------------------------------------------
+void handleEndSignedInfo(SigDocParse* pctx)
+{
+ char* pTmp;
+ char buf[DIGEST_LEN+3];
+ SignatureInfo* pSigInfo;
+ pSigInfo = ddocGetLastSignature(pctx->pSigDoc);
+ if(pctx->mbufSigPartData.pMem && pSigInfo) {
+ ddocDebug(5, "handleEndSignedInfo", "DATA: %d ->%s",
+ pctx->mbufSigPartData.nLen, (char*)pctx->mbufSigPartData.pMem);
+ pTmp = canonicalizeXML((char*)pctx->mbufSigPartData.pMem, pctx->mbufSigPartData.nLen);
+ ddocDebug(5, "handleEndSignedInfo", "CANONICALIZED: %d ->%s", strlen(pTmp), (char*)pTmp);
+ if(pTmp) {
+ SHA1_Init(&(pctx->sctx));
+ SHA1_Update(&(pctx->sctx), pTmp, strlen(pTmp));
+ SHA1_Final((unsigned char*)buf,&(pctx->sctx));
+ ddocSigInfo_SetSigInfoRealDigest(pSigInfo, buf, DIGEST_LEN);
+ free(pTmp);
+ }
+ pctx->errcode = ddocSaxParseEndCollecting(pctx, FLAG_SIG_PART, 0);
+ pctx->checkUTF8 = 0;
+ }
+}
+
+
+//--------------------------------------------------
+// handles the start of a <Cert> element.
+// Records the id attribute
+// pctx - pointer to XML parsing work-area
+// name - tag name
+// atts - attributes
+//--------------------------------------------------
+void handleStartCert(SigDocParse* pctx, const xmlChar **atts)
+{
+ char *p = 0, buf1[50];
+ SignatureInfo* pSigInfo = NULL;
+ CertID *pCertID = NULL;
+
+ // used in old formats
+ p = (char*)ddocSaxParseFindAttrib(atts, "Id", NULL);
+ if(p)
+ strncpy(pctx->ctx2, p, sizeof(pctx->ctx2)-1);
+ pSigInfo = ddocGetLastSignature(pctx->pSigDoc);
+ ddocDebug(3, "handleStartCert", "Sig: %s", (pSigInfo ? pSigInfo->szId : "NULL"));
+ RETURN_VOID_IF_NULL(pSigInfo);
+ // only if we are in Notary since signers cert-id is handled by <SigningCertificate>
+ if(pSigInfo->pNotary) {
+ // don't know what cert-id it's going to be
+ ddocCertID_new(&pCertID, CERTID_TYPE_UNKNOWN, 0, 0, 0, 0, 0);
+ if(!pSigInfo->pCertIDs)
+ ddocCertIDList_new(&(pSigInfo->pCertIDs));
+ ddocCertIDList_addCertID(pSigInfo->pCertIDs, pCertID);
+ snprintf(buf1, sizeof(buf1), "%s-UNKNOWN_CERTINFO", pSigInfo->szId);
+ strncpy(pctx->ctx2, buf1, sizeof(pctx->ctx2)-1);
+ }
+}
+
+
+//--------------------------------------------------
+// handles the start of a <SigningCertificate> element.
+// pctx - pointer to XML parsing work-area
+// name - tag name
+// atts - attributes
+//--------------------------------------------------
+void handleStartSigningCertificate(SigDocParse* pctx)
+{
+ SignatureInfo* pSigInfo = NULL;
+ CertID *pCertID = NULL;
+ X509* x509 = NULL;
+ int ret = 0;
+ DigiDocMemBuf mbuf1, mbuf2;
+
+ mbuf1.pMem = 0;
+ mbuf1.nLen = 0;
+ mbuf2.pMem = 0;
+ mbuf2.nLen = 0;
+ pSigInfo = ddocGetLastSignature(pctx->pSigDoc);
+ ddocDebug(3, "handleStartSigningCertificate", "Sig: %s",
+ (pSigInfo ? pSigInfo->szId : "NULL"));
+ RETURN_VOID_IF_NULL(pSigInfo);
+ pCertID = ddocSigInfo_GetOrCreateCertIDOfType(pSigInfo, CERTID_TYPE_SIGNERS_CERTID);
+ snprintf(pctx->ctx2, sizeof(pctx->ctx2)-1, "%s-CERTINFO", pSigInfo->szId);
+ x509 = ddocSigInfo_GetSignersCert(pSigInfo);
+ if(x509){
+ ret = ddocCertGetIssuerDN(x509, &mbuf1);
+ if(ret == 0) {
+ if(pCertID && mbuf1.pMem)
+ ddocCertID_SetIssuerName(pCertID, (char*)mbuf1.pMem);
+ }
+ }
+}
+
+
+//--------------------------------------------------
+// handles the start of a <UnsignedSignatureProperties> element.
+// pctx - pointer to XML parsing work-area
+// name - tag name
+// atts - attributes
+//--------------------------------------------------
+void handleStartUnsignedSignatureProperties(SigDocParse* pctx)
+{
+ SignatureInfo* pSigInfo = NULL;
+ NotaryInfo *pNotaryInfo;
+
+ pSigInfo = ddocGetLastSignature(pctx->pSigDoc);
+ ddocDebug(3, "handleStartUnsignedSignatureProperties", "Sig: %s",
+ (pSigInfo ? pSigInfo->szId : "NULL"));
+ RETURN_VOID_IF_NULL(pSigInfo);
+ (void)NotaryInfo_new(&pNotaryInfo, pctx->pSigDoc, pSigInfo);
+}
+
+
+//--------------------------------------------------
+// handles the start of a <CompleteCertificateRefs> element.
+// Records the signature id so that we can later
+// capture responders cert digest
+// pctx - pointer to XML parsing work-area
+// name - tag name
+// atts - attributes
+//--------------------------------------------------
+void handleStartCompleteCertificateRefs(SigDocParse* pctx)
+{
+ SignatureInfo* pSigInfo = 0;
+
+ pSigInfo = ddocGetLastSignature(pctx->pSigDoc);
+ ddocDebug(3, "handleStartCompleteCertificateRefs", "Sig: %s", (pSigInfo ? pSigInfo->szId : "NULL"));
+ RETURN_VOID_IF_NULL(pSigInfo);
+ snprintf(pctx->ctx2, sizeof(pctx->ctx2)-1, "%s-RESPONDER_CERTINFO", pSigInfo->szId);
+}
+
+
+//--------------------------------------------------
+// handles the start of a <OCSPIdentifier> element.
+// Records the id attribute
+// pctx - pointer to XML parsing work-area
+// name - tag name
+// atts - attributes
+//--------------------------------------------------
+void handleStartOCSPIdentifier(SigDocParse* pctx, const xmlChar **atts)
+{
+ strncpy(pctx->ctx2, ddocSaxParseFindAttrib(atts, "URI", ""), sizeof(pctx->ctx2)-1);
+}
+
+//--------------------------------------------------
+// handles the start of a <X509Certificate> element.
+// Records the digest method
+// pctx - pointer to XML parsing work-area
+// name - tag name
+//--------------------------------------------------
+void handleEndX509Certificate(SigDocParse* pctx)
+{
+ X509* x509 = 0;
+ SignatureInfo* pSigInfo = 0;
+
+ pSigInfo = ddocGetLastSignature(pctx->pSigDoc);
+ // convert the X509 cert data to
+ // cert and replace the pointer value
+ if(pSigInfo && pctx->mbufElemData.pMem) {
+ pctx->errcode = ddocDecodeX509PEMData(&x509,
+ (const char*)pctx->mbufElemData.pMem, (int)pctx->mbufElemData.nLen);
+ if(x509)
+ ddocSigInfo_SetSignersCert(pSigInfo, x509);
+ // cleanup
+ pctx->errcode = ddocSaxParseEndCollecting(pctx, FLAG_XML_ELEM, 0);
+ }
+}
+
+//--------------------------------------------------
+// handles the start of a <EncapsulatedX509Certificate> element.
+// Records the signature id so that we can later
+// capture responders cert digest
+// pctx - pointer to XML parsing work-area
+// name - tag name
+// atts - attributes
+//--------------------------------------------------
+void handleStartEncapsulatedX509Certificate(SigDocParse* pctx, const xmlChar **atts)
+{
+ SignatureInfo* pSigInfo = 0;
+ const char *p1 = 0;
+ CertValue *pCertValue;
+
+ pSigInfo = ddocGetLastSignature(pctx->pSigDoc);
+ p1 = ddocSaxParseFindAttrib(atts, "Id", NULL);
+
+ ddocDebug(3, "handleStartEncapsulatedX509Certificate", "Sig: %s, type: %s",
+ (pSigInfo ? pSigInfo->szId : "NULL"), (p1 ? p1 : "NULL"));
+ RETURN_VOID_IF_NULL(pSigInfo);
+ if(p1) {
+ if(strstr(p1, "TSA_CERT"))
+ pCertValue = ddocSigInfo_GetOrCreateCertValueOfType(pSigInfo, CERTID_VALUE_TSA_CERT);
+ if(strstr(p1, "RESPONDER_CERT"))
+ pCertValue = ddocSigInfo_GetOrCreateCertValueOfType(pSigInfo, CERTID_VALUE_RESPONDERS_CERT);
+ }
+ snprintf(pctx->ctx2, sizeof(pctx->ctx2)-1, "%s-RESPONDER_CERTINFO", pSigInfo->szId);
+ pctx->errcode = ddocSaxParseStartCollecting(pctx, FLAG_XML_ELEM, 1);
+}
+
+//--------------------------------------------------
+// handles the end of a <EncapsulatedX509Certificate> element.
+// Records the digest method
+// pctx - pointer to XML parsing work-area
+// name - tag name
+//--------------------------------------------------
+void handleEndEncapsulatedX509Certificate(SigDocParse* pctx)
+{
+ X509* x509 = 0;
+ NotaryInfo* pNotInf = 0;
+ SignatureInfo* pSigInfo = 0;
+ CertValue* pCertValue = 0;
+
+ // convert the X509 cert data to cert<
+ pNotInf = ddocGetLastNotaryInfo(pctx->pSigDoc);
+ pSigInfo = ddocGetLastSignature(pctx->pSigDoc);
+ pctx->errcode = ddocDecodeX509PEMData(&x509,
+ (const char*)pctx->mbufElemData.pMem, (int)pctx->mbufElemData.nLen);
+ if(x509 && pSigInfo) {
+ pCertValue = ddocSigInfo_GetLastCertValue(pSigInfo);
+ if(pCertValue)
+ ddocCertValue_SetCert(pCertValue, x509);
+ else
+ X509_free(x509); // not found, free it
+ }
+ // cleanup
+ ddocSaxParseEndCollecting(pctx, FLAG_XML_ELEM, 0);
+}
+
+char* PATH_DIGEST_VALUE_SIGNED_INFO = "/SignedDoc/Signature/SignedInfo/Reference";
+char* PATH_DIGEST_VALUE_SIG_CERT = "/SignedDoc/Signature/Object/QualifyingProperties/SignedProperties/SignedSignatureProperties/SigningCertificate/Cert/CertDigest";
+char* PATH_DIGEST_VALUE_CERT_REF = "/SignedDoc/Signature/Object/QualifyingProperties/UnsignedProperties/UnsignedSignatureProperties/CompleteCertificateRefs/CertRefs/Cert/CertDigest";
+char* PATH_DIGEST_VALUE_CERT_REF_1_0 = "/SignedDoc/Signature/Object/QualifyingProperties/UnsignedProperties/UnsignedSignatureProperties/CompleteCertificateRefs/Cert/CertDigest";
+char* PATH_DIGEST_VALUE_RVOK_REFS = "/SignedDoc/Signature/Object/QualifyingProperties/UnsignedProperties/UnsignedSignatureProperties/CompleteRevocationRefs/OCSPRefs/OCSPRef/DigestAlgAndValue";
+
+int checkValidDigestValPath(SigDocParse* pctx, SignatureInfo* pSigInfo)
+{
+ if(pctx && pctx->mbufTags.pMem) {
+ if(!strcmp((const char*)pctx->mbufTags.pMem, PATH_DIGEST_VALUE_CERT_REF_1_0)) {
+ pSigInfo->nErr1 = ERR_VER_1_0;
+ ddocDebug(1, "VER 1.0", "Ver 1.0 signature! Found element DigestValue in path: %s format: %s ver: %s", (const char*)pctx->mbufTags.pMem, pctx->pSigDoc->szFormat, pctx->pSigDoc->szFormatVer);
+ if(strcmp(pctx->pSigDoc->szFormat, SK_XML_1_NAME) &&
+ (strcmp(pctx->pSigDoc->szFormat, DIGIDOC_XML_1_1_NAME) ||
+ !strcmp(pctx->pSigDoc->szFormatVer, DIGIDOC_XML_1_3_VER))) {
+ ddocDebug(1, "checkValidDigestValPath10-12", "Invalid XML! Found element DigestValue in path: %s format: %s ver: %s", (const char*)pctx->mbufTags.pMem, pctx->pSigDoc->szFormat, pctx->pSigDoc->szFormatVer);
+ SET_LAST_ERROR(ERR_DIGIDOC_PARSE);
+ if(pSigInfo && !pSigInfo->nErr1)
+ pSigInfo->nErr1 = ERR_DIGIDOC_PARSE;
+ return ERR_DIGIDOC_PARSE;
+ }
+
+ } else {
+ if(strcmp((const char*)pctx->mbufTags.pMem, PATH_DIGEST_VALUE_SIGNED_INFO) &&
+ strcmp((const char*)pctx->mbufTags.pMem, PATH_DIGEST_VALUE_SIG_CERT) &&
+ strcmp((const char*)pctx->mbufTags.pMem, PATH_DIGEST_VALUE_CERT_REF) &&
+ strcmp((const char*)pctx->mbufTags.pMem, PATH_DIGEST_VALUE_RVOK_REFS)) {
+ ddocDebug(1, "checkValidDigestValPath", "Invalid XML! Found element DigestValue in path: %s format: %s ver: %s", (const char*)pctx->mbufTags.pMem, pctx->pSigDoc->szFormat, pctx->pSigDoc->szFormatVer);
+ SET_LAST_ERROR(ERR_DIGIDOC_PARSE);
+ if(pSigInfo && !pSigInfo->nErr1)
+ pSigInfo->nErr1 = ERR_DIGIDOC_PARSE;
+ return ERR_DIGIDOC_PARSE;
+ }
+ }
+ }
+ return 0;
+}
+
+char* PATH_CLAIMED_ROLE = "/SignedDoc/Signature/Object/QualifyingProperties/SignedProperties/SignedSignatureProperties/SignerRole/ClaimedRoles";
+
+int checkValidClaimedRolePath(SigDocParse* pctx, SignatureInfo* pSigInfo)
+{
+ if(pctx && pctx->mbufTags.pMem) {
+ if(strcmp((const char*)pctx->mbufTags.pMem, PATH_CLAIMED_ROLE)) {
+ ddocDebug(1, "checkValidClaimedRolePath", "Invalid XML! Found element ClaimedRole in path: %s", (const char*)pctx->mbufTags.pMem);
+ SET_LAST_ERROR(ERR_DIGIDOC_PARSE);
+ if(pSigInfo && !pSigInfo->nErr1)
+ pSigInfo->nErr1 = ERR_DIGIDOC_PARSE;
+ return ERR_DIGIDOC_PARSE;
+ }
+ }
+ return 0;
+}
+
+//--------------------------------------------------
+// handles the content of a <DigestValue> element.
+// Decodes and reads in digest value
+// pctx - pointer to XML parsing work-area
+// name - tag name
+// atts - attributes
+//--------------------------------------------------
+void handleEndDigestValue(SigDocParse* pctx)
+{
+ char id[100], type[100];
+ SignatureInfo* pSigInfo = NULL;
+ NotaryInfo* pNotInfo = NULL;
+ DocInfo* pDocInfo = NULL;
+ CertID* pCertID = NULL;
+ DigiDocMemBuf mbuf1;
+
+ mbuf1.pMem = 0;
+ mbuf1.nLen = 0;
+ pSigInfo = ddocGetLastSignature(pctx->pSigDoc);
+ ddocDebug(4, "handleDigestValue", "DF: %s value: %s len: %d",
+ pctx->ctx2, (char*)pctx->mbufElemData.pMem, pctx->mbufElemData.nLen);
+ // decode digest value
+ ddocDecodeBase64(&(pctx->mbufElemData), &mbuf1);
+ ddocDebug(4, "handleDigestValue", "decoded len: %ld", mbuf1.nLen);
+ // cleanup
+ ddocSaxParseEndCollecting(pctx, FLAG_XML_ELEM, 0);
+ // find current signature
+ pSigInfo = ddocGetLastSignature(pctx->pSigDoc);
+ RETURN_VOID_IF_NULL(pSigInfo);
+ if(checkValidDigestValPath(pctx, pSigInfo))
+ return;
+
+ decodeURI(pctx->ctx2, id, sizeof(id), type, sizeof(type));
+ ddocDebug(4, "handleDigestValue", "ctx2: %s id: %s type: %s", pctx->ctx2, id, type);
+ if(id[0] == 'D' || !strcmp(id, "null")) {
+ RETURN_VOID_IF_NULL(pSigInfo);
+ pDocInfo = getDocInfoWithId(pSigInfo, id);
+ if(!strcmp(type, "MimeType") ||
+ !strcmp(type, "MIME")) {
+ if(pDocInfo == NULL) {
+ addDocInfo(&pDocInfo, pSigInfo, id, pctx->ctx3,
+ NULL, 0, (const byte*)mbuf1.pMem, mbuf1.nLen);
+ } else
+ setDocInfoMimeDigest(pDocInfo, (const byte*)mbuf1.pMem, mbuf1.nLen);
+ }
+ else {
+ if(pDocInfo == NULL) {
+ addDocInfo(&pDocInfo, pSigInfo, id, pctx->ctx3,
+ (const byte*)mbuf1.pMem, mbuf1.nLen, NULL, 0); // MEMLEAK: ???
+ } else
+ setDocInfoDigest(pDocInfo, (const byte*)mbuf1.pMem, mbuf1.nLen, pctx->ctx3);
+ }
+ }
+ if(id[0] == 'S') {
+ if(!strcmp(type, "SignedProperties")) {
+ RETURN_VOID_IF_NULL(pSigInfo);
+ ddocSigInfo_SetSigPropDigest(pSigInfo, (const char*)mbuf1.pMem, mbuf1.nLen);
+ }
+ if(!strcmp(type, "CERTINFO")) {
+ RETURN_VOID_IF_NULL(pSigInfo);
+ pCertID = ddocSigInfo_GetOrCreateCertIDOfType(pSigInfo, CERTID_TYPE_SIGNERS_CERTID);
+ RETURN_VOID_IF_NULL(pCertID);
+ ddocCertID_SetDigestValue(pCertID, (const char*)mbuf1.pMem, mbuf1.nLen);
+ }
+ if(!strcmp(type, "UNKNOWN_CERTINFO")) {
+ pCertID = ddocCertIDList_GetLastCertID(pSigInfo->pCertIDs);
+ RETURN_VOID_IF_NULL(pCertID);
+ ddocCertID_SetDigestValue(pCertID, (const char*)mbuf1.pMem, mbuf1.nLen);
+ }
+ }
+ if(id[0] == 'N') {
+ pNotInfo = getNotaryWithId(pctx->pSigDoc, id);
+ SET_LAST_ERROR_RETURN_VOID_IF_NOT(pNotInfo, ERR_OCSP_WRONG_RESPID);
+ ddocNotInfo_SetOcspDigest(pNotInfo, (const char*)mbuf1.pMem, mbuf1.nLen);
+ }
+ ddocMemBuf_free(&mbuf1);
+}
+
+
+//--------------------------------------------------
+// handles the content of a <SigningTime> element.
+// Reads in timestamp data
+// pctx - pointer to XML parsing work-area
+// value - character values read from file
+// len - length of chars ???
+//--------------------------------------------------
+void handleEndSigningTime(SigDocParse* pctx)
+{
+ SignatureInfo *pSigInfo;
+
+ pSigInfo = ddocGetLastSignature(pctx->pSigDoc);
+ RETURN_VOID_IF_NULL(pSigInfo);
+ if(pctx->mbufElemData.pMem) {
+ setString(&(pSigInfo->szTimeStamp), (char*)pctx->mbufElemData.pMem, -1);
+ ddocSaxParseEndCollecting(pctx, FLAG_XML_ELEM, 0);
+ }
+}
+
+#define ADR_ENTRY_CITY 1
+#define ADR_ENTRY_STATE 2
+#define ADR_ENTRY_COUNTRY 3
+#define ADR_ENTRY_ZIP 4
+
+//--------------------------------------------------
+// Handles address entry
+// pctx - pointer to XML parsing work-area
+//
+// value - character values read from file
+// len - length of chars ???
+//--------------------------------------------------
+void handleAdrEntry(SigDocParse* pctx, int nAdr)
+{
+ SignatureInfo* pSigInfo;
+
+ pSigInfo = ddocGetLastSignature(pctx->pSigDoc);
+ if(pSigInfo && pctx->mbufElemData.pMem) {
+ switch(nAdr) {
+ case ADR_ENTRY_CITY:
+ setString(&(pSigInfo->sigProdPlace.szCity), (const char*)pctx->mbufElemData.pMem, -1);
+ break;
+ case ADR_ENTRY_STATE:
+ setString(&(pSigInfo->sigProdPlace.szStateOrProvince), (const char*)pctx->mbufElemData.pMem, -1);
+ break;
+ case ADR_ENTRY_COUNTRY:
+ setString(&(pSigInfo->sigProdPlace.szCountryName), (const char*)pctx->mbufElemData.pMem, -1);
+ break;
+ case ADR_ENTRY_ZIP:
+ setString(&(pSigInfo->sigProdPlace.szPostalCode), (const char*)pctx->mbufElemData.pMem, -1);
+ break;
+ }
+ }
+ ddocSaxParseEndCollecting(pctx, FLAG_XML_ELEM, 0);
+}
+
+//--------------------------------------------------
+// handles the start of a <ClaimedRole> element.
+// Stores the collected claimed role
+// pctx - pointer to XML parsing work-area
+// name - tag name
+//--------------------------------------------------
+void handleEndClaimedRole(SigDocParse* pctx)
+{
+ SignatureInfo* pSigInfo;
+
+ if(pctx->mbufElemData.pMem) {
+ pSigInfo = ddocGetLastSignature(pctx->pSigDoc);
+ if(checkValidClaimedRolePath(pctx, pSigInfo)) return;
+ RETURN_VOID_IF_NULL(pSigInfo);
+ addSignerRole(pSigInfo, 0, (const char*)pctx->mbufElemData.pMem, -1, 0);
+ ddocSaxParseEndCollecting(pctx, FLAG_XML_ELEM, 0);
+ pctx->bNoXMLElemData = 0;
+ }
+}
+
+//--------------------------------------------------
+// handles the start of a <CertifiedRole> element.
+// Stores the collected certified role
+// pctx - pointer to XML parsing work-area
+// name - tag name
+//--------------------------------------------------
+void handleEndCertifiedRole(SigDocParse* pctx)
+{
+ SignatureInfo* pSigInfo;
+
+ if(pctx->mbufElemData.pMem) {
+ pSigInfo = ddocGetLastSignature(pctx->pSigDoc);
+ RETURN_VOID_IF_NULL(pSigInfo);
+ addSignerRole(pSigInfo, 1, (const char*)pctx->mbufElemData.pMem, -1, 0);
+ ddocSaxParseEndCollecting(pctx, FLAG_XML_ELEM, 0);
+ }
+}
+
+//--------------------------------------------------
+// handles the end of a <IssuerSerial> element.
+// Reads in cert isseur serial number
+// pctx - pointer to XML parsing work-area
+// value - character values read from file
+// len - length of chars ???
+//--------------------------------------------------
+void handleEndIssuerSerial(SigDocParse* pctx)
+{
+ SignatureInfo* pSigInfo;
+ char id[20], type[20];
+ CertID* pCertID;
+
+ decodeURI(pctx->ctx2, id, sizeof(id), type, sizeof(type));
+ if(!strcmp(type, "CERTINFO")) {
+ pSigInfo = ddocGetLastSignature(pctx->pSigDoc);
+ pCertID = ddocSigInfo_GetCertIDOfType(pSigInfo, CERTID_TYPE_SIGNERS_CERTID);
+ if(pCertID && pctx->mbufElemData.pMem)
+ ddocCertID_SetIssuerSerial(pCertID, (char*)pctx->mbufElemData.pMem);
+ }
+ if(!strcmp(type, "UNKNOWN_CERTINFO")) {
+ pSigInfo = ddocGetLastSignature(pctx->pSigDoc);
+ pCertID = ddocCertIDList_GetLastCertID(pSigInfo->pCertIDs);
+ if(pCertID && pctx->mbufElemData.pMem)
+ ddocCertID_SetIssuerSerial(pCertID, (char*)pctx->mbufElemData.pMem);
+ }
+ ddocSaxParseEndCollecting(pctx, FLAG_XML_ELEM, 0);
+}
+
+//--------------------------------------------------
+// handles the end of a <IssuerName> element.
+// Reads in cert isseur serial number
+// pctx - pointer to XML parsing work-area
+// value - character values read from file
+// len - length of chars ???
+//--------------------------------------------------
+void handleEndIssuerName(SigDocParse* pctx)
+{
+ SignatureInfo* pSigInfo;
+ char id[20], type[20];
+ CertID* pCertID;
+
+ decodeURI(pctx->ctx2, id, sizeof(id), type, sizeof(type));
+ if(!strcmp(type, "CERTINFO")) {
+ pSigInfo = ddocGetLastSignature(pctx->pSigDoc);
+ pCertID = ddocSigInfo_GetCertIDOfType(pSigInfo, CERTID_TYPE_SIGNERS_CERTID);
+ ddocDebug(3, "handleEndIssuerName", "Issuer name: %s", pctx->mbufElemData.pMem);
+ if(pCertID && pctx->mbufElemData.pMem)
+ ddocCertID_SetIssuerName(pCertID, (char*)pctx->mbufElemData.pMem);
+ }
+ if(!strcmp(type, "UNKNOWN_CERTINFO")) {
+ pSigInfo = ddocGetLastSignature(pctx->pSigDoc);
+ pCertID = ddocCertIDList_GetLastCertID(pSigInfo->pCertIDs);
+ if(pCertID && pctx->mbufElemData.pMem)
+ ddocCertID_SetIssuerName(pCertID, (char*)pctx->mbufElemData.pMem);
+ }
+ ddocSaxParseEndCollecting(pctx, FLAG_XML_ELEM, 0);
+}
+
+//--------------------------------------------------
+// tests if this is a textform responder id
+// we base the test on existence of certain
+// key elements in a DN.
+// return 1 if it is text form
+//--------------------------------------------------
+int isTextResponderId(const char* szRespId)
+{
+ return strstr(szRespId, "CN=") && strstr(szRespId, "C=");
+}
+
+//--------------------------------------------------
+// handles the end of a </ResponderId> or <ByName> element.
+// Reads in ResponderId data
+// pctx - pointer to XML parsing work-area
+// value - character values read from file
+// len - length of chars ???
+//--------------------------------------------------
+void handleEndResponderID(SigDocParse* pctx)
+{
+ NotaryInfo* pNotInf;
+ DigiDocMemBuf mbuf1;
+
+ mbuf1.pMem = 0;
+ mbuf1.nLen = 0;
+ RETURN_VOID_IF_NULL(pctx->pSigDoc->szFormatVer);
+ pNotInf = ddocGetLastNotaryInfo(pctx->pSigDoc);
+ ddocDebug(3, "handleEndResponderId", "notary: %s id: %s, len: %d",
+ (pNotInf ? pNotInf->szId : "NULL"), (const char*)pctx->mbufElemData.pMem, pctx->mbufElemData.nLen);
+ if(pNotInf && pctx->mbufElemData.pMem) {
+ // in earlier format we din't have <ByName> and <ByKey>
+ // so we must detect if this is text or base64
+ if(isTextResponderId((const char*)pctx->mbufElemData.pMem)) {
+ pctx->errcode = ddocNotInfo_SetResponderId(pNotInf, (const char*)pctx->mbufElemData.pMem, pctx->mbufElemData.nLen);
+ pNotInf->nRespIdType = RESPID_NAME_TYPE;
+ } else {
+ ddocDecodeBase64Data(pctx->mbufElemData.pMem, pctx->mbufElemData.nLen, &mbuf1);
+ pctx->errcode = ddocNotInfo_SetResponderId(pNotInf, (const char*)mbuf1.pMem, mbuf1.nLen);
+ pNotInf->nRespIdType = RESPID_KEY_TYPE;
+ }
+ pctx->errcode = ddocSaxParseEndCollecting(pctx, FLAG_XML_ELEM, 0);
+ }
+}
+
+//--------------------------------------------------
+// handles the end of a </ProducedAt>
+// Reads in OCSP ProducedAt timestamp
+// pctx - pointer to XML parsing work-area
+// value - character values read from file
+// len - length of chars ???
+//--------------------------------------------------
+void handleEndProducedAt(SigDocParse* pctx)
+{
+ NotaryInfo* pNotInf = NULL;
+
+ RETURN_VOID_IF_NULL(pctx->pSigDoc);
+ pNotInf = ddocGetLastNotaryInfo(pctx->pSigDoc);
+ RETURN_VOID_IF_NULL(pNotInf);
+ ddocDebug(3, "handleEndProducedAt", "notary: %s produced at: %s len: %d",
+ (pNotInf ? pNotInf->szId : "NULL"), (const char*)pctx->mbufElemData.pMem, pctx->mbufElemData.nLen);
+ if(pNotInf && pctx->mbufElemData.pMem) {
+ setString(&(pNotInf->szProducedAt), (const char*)pctx->mbufElemData.pMem, -1 /* pctx->mbufElemData.nLen*/);
+ pctx->errcode = ddocSaxParseEndCollecting(pctx, FLAG_XML_ELEM, 0);
+ }
+}
+
+//--------------------------------------------------
+// handles the end of a <ByKey> element.
+// Reads in ResponderId data
+// pctx - pointer to XML parsing work-area
+// value - character values read from file
+// len - length of chars ???
+//--------------------------------------------------
+void handleEndByKey(SigDocParse* pctx)
+{
+ NotaryInfo* pNotInf;
+ DigiDocMemBuf mbuf1;
+
+ mbuf1.pMem = 0;
+ mbuf1.nLen = 0;
+ pNotInf = ddocGetLastNotaryInfo(pctx->pSigDoc);
+ ddocDebug(3, "handleEndByKey", "notary: %s id: %s, len: %d",
+ (pNotInf ? pNotInf->szId : "NULL"), (const char*)pctx->mbufElemData.pMem, pctx->mbufElemData.nLen);
+ if(pNotInf && pctx->mbufElemData.pMem) {
+ ddocDecodeBase64Data(pctx->mbufElemData.pMem, pctx->mbufElemData.nLen, &mbuf1);
+ pctx->errcode = ddocNotInfo_SetResponderId(pNotInf, (const char*)mbuf1.pMem, mbuf1.nLen);
+ pctx->errcode = ddocSaxParseEndCollecting(pctx, FLAG_XML_ELEM, 0);
+ pNotInf->nRespIdType = RESPID_KEY_TYPE;
+ }
+ ddocMemBuf_free(&mbuf1);
+}
+
+//--------------------------------------------------
+// handles the end of a <SignatureValue> element.<
+// Decodes the base64 data in a buffer and assigns
+// to signature value
+// pctx - pointer to XML parsing work-area
+// name - tag name
+//--------------------------------------------------
+void handleEndSignatureValue(SigDocParse* pctx)
+{
+ SignatureInfo* pSigInfo;
+ DigiDocMemBuf mbuf1, mbuf2;
+ char *p1 = 0, *p2 = 0;
+ int l1;
+
+ mbuf1.pMem = 0;
+ mbuf1.nLen = 0;
+ mbuf2.pMem = 0;
+ mbuf2.nLen = 0;
+ RETURN_VOID_IF_NULL(pctx->pSigDoc->szFormatVer);
+ pSigInfo = ddocGetLastSignature(pctx->pSigDoc);
+ // decode signature value
+ p1 = strchr((const char*)pctx->mbufElemData.pMem, '>');
+ if(p1)
+ p2 = strchr((const char*)p1, '<');
+ if(p1 && p2) {
+ p1++;
+ *p2 = 0;
+ l1 = strlen(p1) + 10;
+ ddocMemSetLength(&mbuf1, l1);
+ decode((const byte*)p1, strlen(p1), (byte*)mbuf1.pMem, &l1);
+ mbuf1.nLen = l1;
+ if(pSigInfo && mbuf1.nLen > 0)
+ ddocSigInfo_SetSignatureValue(pSigInfo, (char*)mbuf1.pMem, mbuf1.nLen);
+ ddocMemBuf_free(&mbuf1);
+ }
+ // cleanup
+ ddocSaxParseEndCollecting(pctx, FLAG_TS_INP, 0);
+}
+
+//--------------------------------------------------
+// Collects elements start-tag
+// pctx - pointer to XML parsing work-area
+// name - xml element tag name
+// atts - xml atributes
+// pcFlag - pointer to flag governing collection of this element
+// pMBuf - DigiDocMemBuf to collect it in
+//--------------------------------------------------
+int ddocSaxParseCollectStartTag(SigDocParse* pctx, const xmlChar *name, const xmlChar **atts,
+ char *pcFlag, DigiDocMemBuf* pMBuf)
+{
+ int i, addXmlns = 0, addXmlns3 = 0;
+ char *p = 0;
+ // if we are in collect data mode then
+ // record this tag data
+ if(*pcFlag) {
+ // don't use this attribute for 1.0 format
+ if(pctx->pSigDoc->szFormatVer && (!strcmp(pctx->pSigDoc->szFormatVer, DIGIDOC_XML_1_1_VER) ||
+ !strcmp(pctx->pSigDoc->szFormatVer, DIGIDOC_XML_1_2_VER)) &&
+ (!strcmp((const char*)name, "SignedProperties") ||
+ !strcmp((const char*)name, "SignedInfo"))) // must have this attribute
+ addXmlns = 1;
+ else
+ addXmlns = 0; // don't need this atribute
+ ddocDebug(3, "ddocSaxParseCollectStartTag", "Format: %s name: %s", pctx->pSigDoc->szFormatVer, (const char*)name);
+ if(pctx->pSigDoc->szFormatVer && !strcmp((const char*)name, "DataFile")) {
+ if(!strcmp(pctx->pSigDoc->szFormatVer, DIGIDOC_XML_1_3_VER)) // must have this attribute
+ addXmlns3 = 1;
+ }
+ pctx->errcode = ddocMemAppendData(pMBuf, "<", -1);
+ if(!pctx->errcode)
+ pctx->errcode = ddocMemAppendData(pMBuf, (const char*)name, -1);
+ for (i = 0; !pctx->errcode && (atts != NULL) && (atts[i] != NULL); i += 2) {
+ pctx->errcode = ddocMemAppendData(pMBuf, " ", -1);
+ if(!pctx->errcode)
+ pctx->errcode = ddocMemAppendData(pMBuf, (const char*)atts[i], -1);
+ if(!pctx->errcode)
+ pctx->errcode = ddocMemAppendData(pMBuf, "=\"", -1);
+ if(!pctx->errcode) {
+ escapeXMLSymbols((const char*)atts[i+1], -1, &p);
+ if(p) {
+ pctx->errcode = ddocMemAppendData(pMBuf, p, -1);
+ free(p);
+ }
+ }
+ if(!pctx->errcode)
+ pctx->errcode = ddocMemAppendData(pMBuf, "\"", -1);
+ if(!strcmp((const char*)atts[i], "xmlns")) {
+ addXmlns = 0; // already has this atribute
+ addXmlns3 = 0;
+ }
+ } // for
+ if(addXmlns && !pctx->errcode)
+ pctx->errcode = ddocMemAppendData(pMBuf, " xmlns=\"http://www.w3.org/2000/09/xmldsig#\"", -1);
+ if(addXmlns3 && !pctx->errcode)
+ pctx->errcode = ddocMemAppendData(pMBuf, " xmlns=\"http://www.sk.ee/DigiDoc/v1.3.0#\"", -1);
+ if(!pctx->errcode)
+ pctx->errcode = ddocMemAppendData(pMBuf, ">", -1);
+ ddocDebug(3, "ddocSaxParseCollectStartTag", "Element tag collected: %d - %s", pMBuf->nLen, (char*)pMBuf->pMem);
+ }
+ return pctx->errcode;
+}
+
+//--------------------------------------------------
+// Collects elements start-tag. Used for ddoc 1.3 alternate DataFile hash calc
+// pctx - pointer to XML parsing work-area
+// name - xml element tag name
+// atts - xml atributes
+// pMBuf - DigiDocMemBuf to collect it in
+//--------------------------------------------------
+int ddocSaxParseCollectDf3AltStartTag(SigDocParse* pctx, const xmlChar *name, const xmlChar **atts, DigiDocMemBuf* pMBuf)
+{
+ int i;
+ char *p = 0;
+ // if we are in collect data mode then
+ // record this tag data
+ pctx->errcode = ddocMemAppendData(pMBuf, "<", -1);
+ if(!pctx->errcode)
+ pctx->errcode = ddocMemAppendData(pMBuf, (const char*)name, -1);
+ for (i = 0; !pctx->errcode && (atts != NULL) && (atts[i] != NULL); i += 2) {
+ pctx->errcode = ddocMemAppendData(pMBuf, " ", -1);
+ if(!pctx->errcode)
+ pctx->errcode = ddocMemAppendData(pMBuf, (const char*)atts[i], -1);
+ if(!pctx->errcode)
+ pctx->errcode = ddocMemAppendData(pMBuf, "=\"", -1);
+ if(!pctx->errcode) {
+ escapeXMLSymbols((const char*)atts[i+1], -1, &p);
+ if(p) {
+ pctx->errcode = ddocMemAppendData(pMBuf, p, -1);
+ free(p);
+ }
+ }
+ if(!pctx->errcode)
+ pctx->errcode = ddocMemAppendData(pMBuf, "\"", -1);
+ } // for
+ if(!pctx->errcode)
+ pctx->errcode = ddocMemAppendData(pMBuf, ">", -1);
+ ddocDebug(3, "ddocSaxParseCollectDf3AltStartTag", "Element tag collected: %d - %s", pMBuf->nLen, (char*)pMBuf->pMem);
+ return pctx->errcode;
+}
+
+
+/**
+ * startElementHandler:
+ * @ctxt: An XML parser context
+ * @name: The element name
+ *
+ * called when an opening tag has been processed.
+ */
+static void startElementHandler(void *ctx, const xmlChar *name, const xmlChar **atts)
+{
+ SigDocParse* pctx = (SigDocParse*)ctx;
+ char *pTmp1 = NULL;
+ const char *sXmlns;
+ DigiDocMemBuf mbuf1, mbuf2;
+ SignatureInfo* pSig;
+ XmlElemInfo* eEl = NULL;
+
+ mbuf2.pMem = 0;
+ mbuf2.nLen = 0;
+ strncpy(pctx->tag, (const char*)name, sizeof(pctx->tag));
+ XmlElemInfo_new(&eEl, NULL, (const char*)name);
+ if(!pctx->eRoot)
+ pctx->eRoot = eEl;
+ if(pctx->eCurr) {
+ XmlElemInfo_addChild(pctx->eCurr, eEl);
+ }
+ pctx->eCurr = eEl;
+ pctx->errcode = validateElementPath(pctx->eCurr);
+ // do nothing if error has ocurred
+ if(pctx->errcode) return;
+ ddocMemPush(&(pctx->mbufTags), (const char*)name);
+ ddocDebug(4, "startElementHandler", "<%s> path: %s", (const char*)name, (const char*)pctx->mbufTags.pMem);
+
+ //printf("<%s>\n", (const char*)name);
+ if(!strcmp((const char*)name, "DataFile")) {
+ pctx->bCollectDFData++; // increment bypass mode
+ if(pctx->bCollectDFData == 1) // only the first time
+ handleStartDataFile(pctx, name, atts);
+ // collect wrong/alternate digest for ddoc 1.3
+ ddocSaxParseCollectDf3AltStartTag(pctx, name, atts, &mbuf2);
+ }
+ if(!strcmp((const char*)name, "SignedProperties"))
+ handleStartSignedProperties(pctx, atts);
+ if(!strcmp((const char*)name, "SignedInfo"))
+ handleStartSignedInfo(pctx);
+ // if we are not in a <DataFile> and we encounter
+ // the <Signature> tag then start collecting original content
+ if(!pctx->nIgnoreDataFile &&
+ (!strcmp((const char*)name, "Signature") || pctx->bCollectSigData)) {
+ if(!strcmp((const char*)name, "Signature"))
+ pctx->errcode = ddocSaxParseStartCollecting(pctx, FLAG_SIGNATURE, 0);
+ // collect general <Signature> data<
+ ddocSaxParseCollectStartTag(pctx, name, atts, &(pctx->bCollectSigData), &(pctx->mbufSigData));
+ }
+ // we need the tags here because of hash value calculation
+ // collect general tag data
+ if(!strcmp((const char*)name, "SignatureValue"))
+ pctx->errcode = ddocSaxParseStartCollecting(pctx, FLAG_XML_ELEM, 0);
+ ddocSaxParseCollectStartTag(pctx, name, atts, &(pctx->bCollectElemData), &(pctx->mbufElemData));
+ // use base64 DataFile parsing optimization
+ // only possible if: a) not 1.0 format b) base64 content c) check config settings
+#ifdef WITH_BASE64_HASHING_HACK
+ if((pctx->bCollectDFData == 1) && pctx->pSigDoc->szFormatVer && pctx->pSigDoc->szFormat &&
+ (strcmp(pctx->pSigDoc->szFormatVer, SK_XML_1_VER) && strcmp(pctx->pSigDoc->szFormat, SK_XML_1_NAME))&&
+ !strcmp(pctx->ctx3, CONTENT_EMBEDDED_BASE64) ) {
+ // append end tag
+ ddocMemAppendData(&(pctx->mbufElemData), "</DataFile>", -1);
+ pTmp1 = canonicalizeXML((char*)pctx->mbufElemData.pMem, pctx->mbufElemData.nLen);
+ if(pTmp1) {
+ // remove end tag again after canonicalization
+ pTmp1[strlen(pTmp1) - 11] = 0;
+ ddocDebug(4, "startElementHandler", "Initial sha1 update: \'%s\'", pTmp1);
+ mbuf1.pMem = pTmp1;
+ mbuf1.nLen = strlen(pTmp1);
+ ddocDebugWriteFile(4, "df-data.txt", &mbuf1);
+ SHA1_Update(&(pctx->sctx), pTmp1, strlen(pTmp1));
+ free(pTmp1);
+ pTmp1 = NULL;
+ }
+ // handle alternate digest
+ ddocMemAppendData(&mbuf2, "</DataFile>", -1);
+ pTmp1 = canonicalizeXML((char*)mbuf2.pMem, mbuf2.nLen);
+ if(pTmp1) {
+ // remove end tag again after canonicalization
+ pTmp1[strlen(pTmp1) - 11] = 0;
+ ddocDebug(4, "startElementHandler", "Initial alt sha1 update: \'%s\'", pTmp1);
+ SHA1_Update(&(pctx->sctx2), pTmp1, strlen(pTmp1));
+ free(pTmp1);
+ }
+ ddocMemBuf_free(&(pctx->mbufElemData));
+ }
+#endif
+ if(mbuf2.pMem)
+ ddocMemBuf_free(&mbuf2);
+ // collect general <SignedProperties> data
+ ddocSaxParseCollectStartTag(pctx, name, atts, &(pctx->bCollectSigPartData), &(pctx->mbufSigPartData));
+ // check other start-tag-actions
+ if(!pctx->nIgnoreDataFile) {
+ if(!strcmp((const char*)name, "SignedDoc"))
+ handleStartSignedDoc(pctx, name, atts);
+ if(!strcmp((const char*)name, "Signature"))
+ handleStartSignature(pctx, atts);
+ if(!strcmp((const char*)name, "Reference"))
+ handleStartReference(pctx, atts);
+ if(!strcmp((const char*)name, "SignatureMethod"))
+ handleStartSignatureMethod(pctx, atts);
+ if(!strcmp((const char*)name, "DigestMethod"))
+ handleStartDigestMethod(pctx, atts);
+ if(!strcmp((const char*)name, "Cert"))
+ handleStartCert(pctx, atts);
+ /*if(!strcmp((const char*)name, "ResponderID")) // TODO: do we need it ???
+ handleStartResponderId(pctx, name, atts);*/
+ /* if(!strcmp((const char*)name, "Certificate")) // TODO: do we need it ???
+ handleStartCertificate(pctx, name, atts);*/
+ if(!strcmp((const char*)name, "UnsignedSignatureProperties"))
+ handleStartUnsignedSignatureProperties(pctx);
+ if(!strcmp((const char*)name, "OCSPIdentifier"))
+ handleStartOCSPIdentifier(pctx, atts);
+ if(!strcmp((const char*)name, "SigningCertificate"))
+ handleStartSigningCertificate(pctx);
+ if(!strcmp((const char*)name, "CompleteCertificateRefs"))
+ handleStartCompleteCertificateRefs(pctx);
+ if(!strcmp((const char*)name, "EncapsulatedX509Certificate"))
+ handleStartEncapsulatedX509Certificate(pctx, atts);
+ // start collecting but release old if exists
+ if(!strcmp((const char*)name, "X509SerialNumber") ||
+ !strcmp((const char*)name, "X509IssuerName")) {
+ // check xmlns
+ sXmlns = ddocSaxParseFindAttrib(atts, "xmlns", NULL);
+ if(sXmlns == NULL || strcmp(sXmlns, NAMESPACE_XML_DSIG)) {
+ ddocDebug(1, "startElementHandler", "Invalid namespace %s for element: %s", sXmlns, name);
+ SET_LAST_ERROR(ERR_ISSUER_XMLNS);
+ //pctx->errcode = ERR_ISSUER_XMLNS;
+ pSig = ddocGetLastSignature(pctx->pSigDoc);
+ if(pSig && !pSig->nErr1)
+ pSig->nErr1 = ERR_ISSUER_XMLNS; // store this erro code by signature because it can't be found after parsing
+ }
+ ddocSaxParseEndCollecting(pctx, FLAG_XML_ELEM, 0);
+ pctx->errcode = ddocSaxParseStartCollecting(pctx, FLAG_XML_ELEM, 1);
+
+ }
+ // start collecting but release old if exists
+ if((!strcmp((const char*)name, "Transform") ||
+ !strcmp((const char*)name, "Transforms")) &&
+ pctx->pSigDoc->szFormat && !strcmp(pctx->pSigDoc->szFormat, DIGIDOC_XML_1_1_NAME)) {
+ SET_LAST_ERROR(ERR_TRANSFORM_UNSUPPORTED);
+ pSig = ddocGetLastSignature(pctx->pSigDoc);
+ if(pSig && !pSig->nErr1)
+ pSig->nErr1 = ERR_TRANSFORM_UNSUPPORTED; // store this erro code
+ }
+ // start collecting data of these elements
+ if(!strcmp((const char*)name, "CertifiedRole") ||
+ !strcmp((const char*)name, "ClaimedRole") ||
+ !strcmp((const char*)name, "DigestValue") ||
+ !strcmp((const char*)name, "EncapsulatedOCSPValue") ||
+ !strcmp((const char*)name, "EncapsulatedTimeStamp") ||
+ !strcmp((const char*)name, "X509Certificate") ||
+ !strcmp((const char*)name, "SigningTime") ||
+ !strcmp((const char*)name, "ResponderID") ||
+ !strcmp((const char*)name, "ProducedAt") ||
+ !strcmp((const char*)name, "ByName") ||
+ !strcmp((const char*)name, "ByKey") ||
+ !strcmp((const char*)name, "City") ||
+ !strcmp((const char*)name, "StateOrProvince") ||
+ !strcmp((const char*)name, "PostalCode") ||
+ !strcmp((const char*)name, "CountryName") ||
+ !strcmp((const char*)name, "IssuerSerial")
+ )
+ pctx->errcode = ddocSaxParseStartCollecting(pctx, FLAG_XML_ELEM, 1);
+ }
+}
+
+//--------------------------------------------------
+// Collects elements end-tag
+// pctx - pointer to XML parsing work-area
+// name - xml element tag name
+// pcFlag - pointer to flag governing collection of this element
+// pMBuf - DigiDocMemBuf to collect it in
+//--------------------------------------------------
+int ddocSaxParseCollectEndElement(SigDocParse* pctx, const xmlChar *name,
+ char* pcFlag, DigiDocMemBuf* pMBuf)
+{
+ if(*pcFlag) {
+ if(!pctx->errcode)
+ pctx->errcode = ddocMemAppendData(pMBuf, "</", -1);
+ if(!pctx->errcode)
+ pctx->errcode = ddocMemAppendData(pMBuf, (const char*)name, -1);
+ if(!pctx->errcode)
+ pctx->errcode = ddocMemAppendData(pMBuf, ">", -1);
+ }
+ return pctx->errcode;
+}
+
+/**
+ * endElementHandler:
+ * @ctxt: An XML parser context
+ * @name: The element name
+ *
+ * called when the end of an element has been detected.
+ */
+static void endElementHandler(void *ctx, const xmlChar *name)
+{
+ SignatureInfo* pSigInfo = NULL;
+ SigDocParse* pctx = (SigDocParse*)ctx;
+ const char* pTag = 0;
+
+ // do nothing if error has ocurred
+ if(pctx->errcode) return;
+ pTag = ddocMemPop(&(pctx->mbufTags));
+ if(pctx->eCurr)
+ pctx->eCurr =pctx->eCurr->pParent;
+ ddocDebug(4, "endElementHandler", "</%s>, popped: %s path: %s", (const char*)name, pTag, (const char*)pctx->mbufTags.pMem);
+ // if we are in collect data mode then
+ // collect the tag end
+ if(!pctx->bNoXMLElemData)
+ ddocSaxParseCollectEndElement(pctx, name, &(pctx->bCollectElemData), &(pctx->mbufElemData));
+
+ if(!strcmp((const char*)name, "DataFile")) {
+ pctx->bCollectDFData--; // decrement bypass mode
+ if(pctx->bCollectDFData == 0)
+ handleEndDataFile(pctx, name);
+ }
+ // collect separately <Signature> and <SignedProperties> data
+ ddocSaxParseCollectEndElement(pctx, name, &(pctx->bCollectSigData), &(pctx->mbufSigData));
+ ddocSaxParseCollectEndElement(pctx, name, &(pctx->bCollectSigPartData), &(pctx->mbufSigPartData));
+ if(pctx->mbufSigData.pMem && !strcmp((const char*)name, "Signature")) {
+ pSigInfo = ddocGetLastSignature(pctx->pSigDoc);
+ if(pSigInfo) {
+ // MEMLEAK: possible memleak if old content would not be released ???
+ ddocDebug(3, "endElementHandler", "Set orig-content %s old-mem-used: %s new-content: %d",
+ pSigInfo->szId, (pSigInfo->mbufOrigContent.pMem ? "TRUE" : "FALSE"), pctx->mbufSigData.nLen);
+ ddocMemBuf_free(&(pSigInfo->mbufOrigContent));
+ pSigInfo->mbufOrigContent.pMem = (byte*)pctx->mbufSigData.pMem;
+ pSigInfo->mbufOrigContent.nLen = pctx->mbufSigData.nLen;
+ pctx->mbufSigData.pMem = 0;
+ pctx->mbufSigData.nLen = 0;
+ }
+ }
+ if(!pctx->nIgnoreDataFile) {
+ if(!strcmp((const char*)name, "EncapsulatedX509Certificate"))
+ handleEndEncapsulatedX509Certificate(pctx);
+ if(!strcmp((const char*)name, "EncapsulatedOCSPValue"))
+ handleEndEncapsulatedOCSPValue(pctx);
+ if(!strcmp((const char*)name, "ClaimedRole"))
+ handleEndClaimedRole(pctx);
+ if(!strcmp((const char*)name, "CertifiedRole"))
+ handleEndCertifiedRole(pctx);
+ if(!strcmp((const char*)name, "X509Certificate"))
+ handleEndX509Certificate(pctx);
+ if(!strcmp((const char*)name, "SignedProperties"))
+ handleEndSignedProperties(pctx);
+ if(!strcmp((const char*)name, "SignedInfo"))
+ handleEndSignedInfo(pctx);
+ if(!strcmp((const char*)name, "SignatureValue"))
+ handleEndSignatureValue(pctx);
+ if(!strcmp((const char*)name, "ResponderID"))
+ handleEndResponderID(pctx);
+ if(!strcmp((const char*)name, "ProducedAt"))
+ handleEndProducedAt(pctx);
+ if(!strcmp((const char*)name, "ByName"))
+ handleEndResponderID(pctx);
+ if(!strcmp((const char*)name, "ByKey"))
+ handleEndByKey(pctx);
+ if(!strcmp((const char*)name, "DigestValue"))
+ handleEndDigestValue(pctx);
+ if(!strcmp((const char*)name, "SigningTime"))
+ handleEndSigningTime(pctx);
+ if(!strcmp((const char*)name, "IssuerSerial"))
+ handleEndIssuerSerial(pctx);
+ if(!strcmp((const char*)name, "X509SerialNumber"))
+ handleEndIssuerSerial(pctx);
+ if(!strcmp((const char*)name, "X509IssuerName"))
+ handleEndIssuerName(pctx);
+ //if(!strcmp((const char*)name, "Cert"))
+ // handleEndCert(pctx, name);
+ if(!strcmp((const char*)name, "City"))
+ handleAdrEntry(pctx, ADR_ENTRY_CITY);
+ if(!strcmp((const char*)name, "StateOrProvince"))
+ handleAdrEntry(pctx, ADR_ENTRY_STATE);
+ if(!strcmp((const char*)name, "PostalCode"))
+ handleAdrEntry(pctx, ADR_ENTRY_ZIP);
+ if(!strcmp((const char*)name, "CountryName"))
+ handleAdrEntry(pctx, ADR_ENTRY_COUNTRY);
+
+ }
+ // reset tag, but not the context because used
+ pctx->tag[0] = 0;
+}
+
+/**
+ * charactersHandler:
+ * @ctxt: An XML parser context
+ * @ch: a xmlChar string
+ * @len: the number of xmlChar
+ *
+ * receiving some chars from the parser.
+ * Question: how much at a time ???
+ */
+static void charactersHandler(void *ctx, const xmlChar *ch, int len)
+{
+ SigDocParse* pctx = (SigDocParse*)ctx;
+ char *p = 0;
+
+ // do nothing if error has ocurred
+ if(pctx->errcode) return;
+ // if we are in collect data mode then
+ // collect this data
+ ddocDebug(4, "charactersHandler", "tag: %s len: %d, elem-data: %s, sig-data: %s, collected: %d",
+ pctx->tag, len, (pctx->mbufElemData.pMem ? "Y" : "N"),
+ (pctx->mbufSigData.pMem ? "Y" : "N"), pctx->mbufElemData.nLen);
+//#ifndef WITH_BASE64_HASHING_HACK
+ if(pctx->bCollectElemData) {
+ if(!pctx->errcode) {
+ if(pctx->bNoXMLElemData) {
+ pctx->errcode = ddocMemAppendData(&(pctx->mbufElemData), (const char*)ch, len);
+ } else {
+ pctx->errcode = escapeXMLSymbols((const char*)ch, len, &p);
+ pctx->errcode = ddocMemAppendData(&(pctx->mbufElemData), (const char*)p, -1);
+ free(p);
+ }
+ }
+ }
+//#endif
+ if(pctx->bCollectSigData) {
+ if(!pctx->errcode) {
+ p = 0;
+ pctx->errcode = escapeTextNode((const char*)ch, len, &p);
+ pctx->errcode = ddocMemAppendData(&(pctx->mbufSigData), p, -1);
+ free(p);
+ }
+ }
+ if(pctx->bCollectSigPartData) {
+ if(!pctx->errcode) {
+ p = 0;
+ pctx->errcode = escapeXMLSymbols((const char*)ch, len, &p);
+ pctx->errcode = ddocMemAppendData(&(pctx->mbufSigPartData), p, -1);
+ free(p);
+ }
+ }
+
+ ddocDebug(5, "charactersHandler", "End collecting");
+ if(!strcmp(pctx->tag, "DataFile"))
+ handleDataFile(pctx, ch, len);
+ //else printf("Ignoring: (%s, %d)\n", ch, len);
+ ddocDebug(5, "charactersHandler", "End");
+}
+
+/**
+ * startElementHandler:
+ * @ctxt: An XML parser context
+ * @name: The element name
+ *
+ * called when an opening tag has been processed.
+ */
+static void extractStartElementHandler(void *ctx, const xmlChar *name, const xmlChar **atts)
+{
+ const char* id = 0, *ctype = 0;
+ int i, l1;
+ char *p1 = 0;
+
+ SigDocParse* pctx = (SigDocParse*)ctx;
+ strncpy(pctx->tag, (const char*)name, sizeof(pctx->tag));
+ ddocDebug(5, "extractStartElementHandler", "tag: %s", pctx->tag);
+ // do nothing if error has ocurred
+ if(pctx->errcode) return;
+ if(!strcmp((const char*)name, "DataFile")) {
+ for (i = 0; (atts != NULL) && (atts[i] != NULL); i += 2) {
+ if(!strcmp((const char*)atts[i], "Id"))
+ id = (const char*)atts[i+1];
+ if(!strcmp((const char*)atts[i], "ContentType"))
+ ctype = (const char*)atts[i+1];
+ }
+ if(!pctx->nIgnoreDataFile) {
+ strncpy(pctx->ctx2, id, sizeof(pctx->ctx2));
+ strncpy(pctx->ctx4, ctype, sizeof(pctx->ctx4));
+ if(!strcmp(pctx->ctx2, pctx->ctx3)) {
+ pctx->bCollectDFData++; // increment bypass mode
+ ddocDebug(4, "extractStartElementHandler", "Start DF: %s mode: %s skip: %d",
+ pctx->ctx3, pctx->ctx1, pctx->bCollectDFData);
+ if(pctx->bCollectDFData == 1) { // only the first time
+ ddocDebug(4, "extractStartElementHandler", "Init collecting DF: %s mode: %s",
+ pctx->ctx3, pctx->ctx1);
+ if(!strcmp(pctx->ctx4, CONTENT_EMBEDDED_BASE64) && !pctx->bKeepBase64) {
+ EVP_DecodeInit(&(pctx->ectx));
+ pctx->b64pos = 0;
+ pctx->lSize = 0;
+ }
+ // open output file if necessary
+ if(!pctx->bDataFile && !pctx->pMemBufDF) {
+ pctx->bDataFile = BIO_new_file(pctx->ctx5, "w");
+ ddocDebug(4, "extractStartElementHandler", "Opening file: %s", pctx->ctx5);
+ if(!pctx->bDataFile)
+ SET_LAST_ERROR(ERR_FILE_WRITE);
+ }
+ }
+ }
+ }
+ if(!strcmp(ctype, CONTENT_EMBEDDED) || pctx->nIgnoreDataFile)
+ pctx->nIgnoreDataFile++;
+ }
+ if(!strcmp(pctx->ctx2, pctx->ctx3) &&
+ !strcmp(pctx->ctx4, CONTENT_EMBEDDED) &&
+ strcmp((const char*)name, "DataFile")) {
+ if(!strcmp(pctx->ctx1, CHARSET_ISO_8859_1)) { // if must convert
+ // begining of the tag
+ l1 = strlen((char*)name) + 10;
+ p1 = (char*)malloc(l1);
+ RETURN_VOID_IF_BAD_ALLOC(p1);
+ if(pctx->pMemBufDF) {
+ ddocMemAppendData(pctx->pMemBufDF, "<", -1);
+ ddocMemAppendData(pctx->pMemBufDF, utf82ascii((const char*)name, p1, &l1), -1);
+ }
+ else
+ BIO_printf(pctx->bDataFile, "<%s", utf82ascii((const char*)name, p1, &l1));
+ free(p1);
+ p1 = 0;
+ for (i = 0; (atts != NULL) && (atts[i] != NULL); i += 2) {
+ l1 = strlen((char*)atts[i]) + 10;
+ p1 = (char*)malloc(l1);
+ RETURN_VOID_IF_BAD_ALLOC(p1);
+ if(pctx->pMemBufDF) {
+ ddocMemAppendData(pctx->pMemBufDF, " ", -1);
+ ddocMemAppendData(pctx->pMemBufDF, utf82ascii((const char*)atts[i], p1, &l1), -1);
+ ddocMemAppendData(pctx->pMemBufDF, "=", -1);
+ }
+ else
+ BIO_printf(pctx->bDataFile, " %s=", utf82ascii((const char*)atts[i], p1, &l1));
+ free(p1);
+ p1 = 0;
+ l1 = strlen((char*)atts[i+1]) + 10;
+ p1 = (char*)malloc(l1);
+ RETURN_VOID_IF_BAD_ALLOC(p1);
+ if(pctx->pMemBufDF) {
+ ddocMemAppendData(pctx->pMemBufDF, "\"", -1);
+ ddocMemAppendData(pctx->pMemBufDF, utf82ascii((const char*)atts[i+1], p1, &l1), -1);
+ ddocMemAppendData(pctx->pMemBufDF, "\"", -1);
+ }
+ else
+ BIO_printf(pctx->bDataFile, "\"%s\"", utf82ascii((const char*)atts[i+1], p1, &l1));
+ free(p1);
+ p1 = 0;
+ } // for - atributes
+ if(pctx->pMemBufDF)
+ ddocMemAppendData(pctx->pMemBufDF, ">", -1);
+ else
+ BIO_puts(pctx->bDataFile, ">");
+ } // if - must convert
+ else { // no need to convert
+ if(pctx->pMemBufDF) {
+ ddocMemAppendData(pctx->pMemBufDF, "<", -1);
+ ddocMemAppendData(pctx->pMemBufDF, (const char*)name, -1);
+ for (i = 0; (atts != NULL) && (atts[i] != NULL); i += 2) {
+ ddocMemAppendData(pctx->pMemBufDF, " ", -1);
+ ddocMemAppendData(pctx->pMemBufDF, (const char*)atts[i], -1);
+ p1 = 0;
+ ddocMemAppendData(pctx->pMemBufDF, "=\"", -1);
+ pctx->errcode = escapeXMLSymbols((const char*)atts[i+1],
+ strlen((const char*)atts[i+1]), &p1);
+ ddocMemAppendData(pctx->pMemBufDF, p1, -1);
+ free(p1);
+ ddocMemAppendData(pctx->pMemBufDF, "\"", -1);
+ }
+ ddocMemAppendData(pctx->pMemBufDF, ">", -1);
+ } else {
+ BIO_printf(pctx->bDataFile, "<%s", name);
+ for (i = 0; (atts != NULL) && (atts[i] != NULL); i += 2) {
+ BIO_printf(pctx->bDataFile, " %s=\"%s\"",
+ (const char*)atts[i], (const char*)atts[i+1]);
+ }
+ BIO_puts(pctx->bDataFile, ">");
+ }
+ } // else no conversion
+ } // if strcmp(DataFile)
+}
+
+
+//--------------------------------------------------
+// handles decoding base64 content. Removes all
+// whitespace and breaks the data in 64 symbol lines
+// to ensure correct decoding
+// pctx - pointer to XML parsing work-area
+// ch - input data
+// len - length of input data
+// lastBlock - 1=last base64 block
+//--------------------------------------------------
+void extractDecodeB64(SigDocParse* pctx, const char* ch, int len, int lastBlock)
+{
+ int l = 0, j;
+ char decData[70];
+
+ ddocDebug(4, "extractDecodeB64", "line: %d last: %d", len, lastBlock);
+ do {
+ // compose a 64 char base64 line for OpenSSL's decoder
+ while(pctx->b64pos < 64 && l < len) {
+ if(!isspace(ch[l])) {
+ pctx->b64line[pctx->b64pos] = ch[l];
+ pctx->b64pos++;
+ }
+ l++;
+ }
+ // if line is ready then terminate and use it
+ if(pctx->b64pos == 64 || (l == len && lastBlock)) {
+ pctx->b64line[pctx->b64pos] = '\n';
+ pctx->b64line[pctx->b64pos + 1] = 0;
+ j = sizeof(decData);
+ memset(decData, 0, j);
+ ddocDebug(5, "extractDecodeB64", "decoding: %s", pctx->b64line);
+ EVP_DecodeUpdate(&(pctx->ectx), (unsigned char*)decData, &j,
+ (unsigned char*)pctx->b64line, pctx->b64pos + 1);
+ ddocDebug(4, "extractDecodeB64", "decoding: %d -> got: %d", pctx->b64pos, j);
+ if(pctx->pMemBufDF)
+ ddocMemAppendData(pctx->pMemBufDF, decData, j);
+ else {
+ if(!pctx->pMemBufDF)
+ SET_LAST_ERROR_RETURN_VOID_IF_NOT(pctx->bDataFile, ERR_FILE_WRITE);
+ BIO_write(pctx->bDataFile, decData, j);
+ }
+ pctx->lSize += j;
+ if(l == len && lastBlock) {
+ j = sizeof(decData);
+ memset(decData, 0, j);
+ EVP_DecodeFinal(&(pctx->ectx), (unsigned char*)decData, &j);
+ ddocDebug(4, "extractDecodeB64", "decoding final got: %d", j);
+ if(j > 0) {
+ if(pctx->pMemBufDF)
+ ddocMemAppendData(pctx->pMemBufDF, decData, j);
+ else {
+ if(!pctx->pMemBufDF)
+ SET_LAST_ERROR_RETURN_VOID_IF_NOT(pctx->bDataFile, ERR_FILE_WRITE);
+ BIO_write(pctx->bDataFile, decData, j);
+ }
+ pctx->lSize += j;
+ }
+ }
+ // ready for next line
+ pctx->b64pos = 0;
+ //memset(&(pctx->b64line), 0, sizeof(pctx->b64line));
+ }
+ } while(l < len);
+}
+
+
+/**
+ * extractBodyHandler:
+ * @ctxt: An XML parser context
+ * @name: The element name
+ *
+ * called when bypassing xml parser for base64 data and extracting to file
+ */
+void extractBodyHandler(SigDocParse* pctx, const char* ch, int len)
+{
+ ddocDebug(4, "extractBodyHandler", "DF: %s data: %d", pctx->ctx2, len);
+ if(!pctx->pMemBufDF)
+ SET_LAST_ERROR_RETURN_VOID_IF_NOT(pctx->bDataFile, ERR_FILE_WRITE);
+ if(!pctx->bKeepBase64) {
+ extractDecodeB64(pctx, ch, len, 0);
+ } else {
+ if(pctx->pMemBufDF) {
+ ddocMemAppendData(pctx->pMemBufDF, ch, len);
+ }else {
+ ddocDebug(4, "extractBodyHandler", "Writing: %s len: %d", ch, len);
+ BIO_write(pctx->bDataFile, ch, len);
+ }
+ pctx->lSize += len;
+ }
+}
+
+/**
+ * extractBodyHandler:
+ * @ctxt: An XML parser context
+ * @name: The element name
+ *
+ * called when bypassing xml parser for bas64 data and extracting to file
+ */
+void extractNoChangeHandler(SigDocParse* pctx, const char* ch, int len)
+{
+ int l;
+ char *p = 0;
+
+ ddocDebug(4, "extractNoChangeHandler", "DF: %s data: %d", pctx->ctx2, len);
+ if(pctx->errcode) { return; }
+ if(!pctx->pMemBufDF)
+ SET_LAST_ERROR_RETURN_VOID_IF_NOT(pctx->bDataFile, ERR_FILE_WRITE);
+ if(!strcmp(pctx->ctx4, CONTENT_EMBEDDED_BASE64)) {
+ BIO_write(pctx->bDataFile, ch, len);
+ pctx->lSize += len;
+ } else {
+ pctx->errcode = escapeXMLSymbols((const char*)ch, len, &p);
+ l = strlen(p);
+ pctx->lSize += l;
+ if(pctx->pMemBufDF) {
+ ddocMemAppendData(pctx->pMemBufDF,p, l);
+ } else {
+ ddocDebug(5, "extractNoChangeHandler", "Writing: %s len: %d", p, l);
+ BIO_write(pctx->bDataFile, p, l);
+ }
+ free(p);
+ p = 0;
+ }
+}
+
+/**
+ * charactersHandler:
+ * @ctxt: An XML parser context
+ * @ch: a xmlChar string
+ * @len: the number of xmlChar
+ *
+ * receiving some chars from the parser.
+ * Question: how much at a time ???
+ */
+static void extractCharactersHandler(void *ctx, const xmlChar *ch, int len)
+{
+ int l;
+ char *p = 0, *p2 = 0;
+ SigDocParse* pctx = (SigDocParse*)ctx;
+
+ ddocDebug(5, "extractCharactersHandler", "tag: %s, data: %d - \'%s\'", pctx->tag, len, (char*)ch);
+ // do nothing if error has ocurred
+ if(pctx->errcode) { return; }
+ if(!strcmp(pctx->ctx2, pctx->ctx3)) {
+ if(!strcmp(pctx->ctx1, "NO-CHANGE")) { // NO-CHANGE
+ extractNoChangeHandler(pctx, (const char*)ch, len);
+ }
+ else { // NOT NO-CHANGE
+ if(!strcmp(pctx->ctx4, CONTENT_EMBEDDED_BASE64)) {
+ extractBodyHandler(pctx, (const char*)ch, len);
+ }
+ if(!strcmp(pctx->ctx4, CONTENT_EMBEDDED)) {
+ if(!strcmp(pctx->ctx1, CHARSET_ISO_8859_1)) {
+ l = len + 10;
+ p = (char*)malloc(l);
+ RETURN_VOID_IF_BAD_ALLOC(p);
+ memset(p, 0, l);
+ UTF8Toisolat1((unsigned char*)p, &l,
+ (const unsigned char*)ch, &len);
+ escapeXMLSymbols((const char*)p, l, &p2);
+ free(p);
+ p = 0;
+ l = strlen(p2);
+ if(pctx->pMemBufDF)
+ ddocMemAppendData(pctx->pMemBufDF, p, l);
+ else
+ BIO_write(pctx->bDataFile, (unsigned char*)p, l);
+ free(p2);
+ p2 = 0;
+ } else {
+ escapeXMLSymbols((const char*)ch, len, &p);
+ l = strlen(p);
+ if(pctx->pMemBufDF)
+ ddocMemAppendData(pctx->pMemBufDF, p, l);
+ else
+ BIO_write(pctx->bDataFile, (unsigned char*)p, l);
+ free(p);
+ }
+ }
+ } // NOT NO-CHANGE
+ }
+ ddocDebug(5, "extractCharactersHandler", "done, errs: %d", pctx->errcode);
+}
+
+/**
+ * extractEndElementHandler:
+ * @ctxt: An XML parser context
+ * @name: The element name
+ *
+ * called when the end of an element has been detected.
+ */
+static void extractEndElementHandler(void *ctx, const xmlChar *name)
+{
+ time_t t1;
+ SigDocParse* pctx = (SigDocParse*)ctx;
+
+ ddocDebug(5, "extractEndElementHandler", "tag: %s", (char*)name);
+ // do nothing if error has ocurred
+ if(pctx->errcode) { return; }
+ if(!strcmp((const char*)name, "DataFile")) {
+ if(pctx->nIgnoreDataFile > 0)
+ pctx->nIgnoreDataFile--;
+ ddocDebug(3, "extractEndElementHandler", "DF: %s end ignore: %d skip: %d",
+ pctx->ctx2, pctx->nIgnoreDataFile, pctx->bCollectDFData);
+ if(!strcmp(pctx->ctx2, pctx->ctx3) &&
+ !pctx->nIgnoreDataFile) {
+ pctx->bCollectDFData--;
+ if(!pctx->bCollectDFData) {
+ if(!strcmp(pctx->ctx4, CONTENT_EMBEDDED_BASE64) &&
+ strcmp(pctx->ctx1, "NO-CHANGE")) {
+ if(!pctx->bKeepBase64)
+ extractDecodeB64(pctx, NULL, 0, 1);
+ }
+ if(!strcmp(pctx->ctx1, "NO-CHANGE")) {
+ // todo ?
+ }
+ time(&t1);
+ ddocDebug(3, "extractEndElementHandler", "DF: %s mode: %s, time: %d [sek] total: %ld bytes",
+ pctx->ctx3, pctx->ctx1, (t1 - pctx->tStartParse), pctx->lSize);
+ // mark the end of data collecting
+ pctx->ctx3[0] = 0;
+ pctx->lSize = 0;
+ } // if bCollectDFData == 0
+ } // if not ignore DataFile
+ } // if "DataFile"
+ if(pctx->ctx3[0] && !strcmp(pctx->ctx4, CONTENT_EMBEDDED)) {
+ if(pctx->pMemBufDF) {
+ ddocDebug(5, "extractEndElementHandler", "Last name: %s collected: \'%s\'",
+ (char*)name, (char*)pctx->pMemBufDF->pMem);
+ ddocMemAppendData(pctx->pMemBufDF, "</", -1);
+ ddocMemAppendData(pctx->pMemBufDF, (char*)name, -1);
+ ddocMemAppendData(pctx->pMemBufDF, ">", -1);
+ ddocDebug(5, "extractEndElementHandler", "Result: \'%s\'",
+ (char*)pctx->pMemBufDF->pMem);
+
+ } else {
+ BIO_printf(pctx->bDataFile, "</%s>", name);
+ }
+ }
+ // reset tag
+ pctx->tag[0] = 0;
+}
+
+
+/**
+ * cdataBlockHandler:
+ * @ctx: the user data (XML parser context)
+ * @value: The pcdata content
+ * @len: the block length
+ *
+ * called when a pcdata block has been parsed
+ */
+static void cdataBlockHandler(void * ctx, const xmlChar *value, int len)
+{
+ fprintf(stdout, "SAX.pcdata(%.20s, %d)\n", (char *) value, len);
+}
+
+
+/**
+ * warningHandler:
+ * @ctxt: An XML parser context
+ * @msg: the message to display/transmit
+ * @...: extra parameters for the message display
+ *
+ * Display and format a warning messages, gives file, line, position and
+ * extra parameters.
+ */
+static void warningHandler(void * ctx, const char *msg, ...)
+{
+ va_list args;
+
+ va_start(args, msg);
+ ddocDebugVaArgs(2, "warningHandler", msg, args);
+ va_end(args);
+}
+
+/**
+ * errorHandler:
+ * @ctxt: An XML parser context
+ * @msg: the message to display/transmit
+ * @...: extra parameters for the message display
+ *
+ * Display and format a error messages, gives file, line, position and
+ * extra parameters.
+ */
+static void errorHandler(void *ctx, const char *msg, ...)
+{
+ va_list args;
+ SigDocParse* pctx = (SigDocParse*)ctx;
+
+ va_start(args, msg);
+ pctx->errcode = ERR_DIGIDOC_PARSE;
+ ddocDebugVaArgs(1, "errorHandler", msg, args);
+ addError(pctx->errcode, __FILE__, __LINE__, "XML parsing error");
+ va_end(args);
+}
+
+/**
+ * fatalErrorHandler:
+ * @ctxt: An XML parser context
+ * @msg: the message to display/transmit
+ * @...: extra parameters for the message display
+ *
+ * Display and format a fatalError messages, gives file, line, position and
+ * extra parameters.
+ */
+static void fatalErrorHandler(void *ctx, const char *msg, ...)
+{
+ va_list args;
+ SigDocParse* pctx = (SigDocParse*)ctx;
+
+ va_start(args, msg);
+ pctx->errcode = ERR_DIGIDOC_PARSE;
+ ddocDebugVaArgs(1, "fatalErrorHandler", msg, args);
+ addError(pctx->errcode, __FILE__, __LINE__, "XML parsing error");
+ va_end(args);
+}
+
+
+xmlSAXHandler debugSAXHandlerStruct = {
+ NULL, //internalSubsetHandler,
+ NULL, //isStandaloneHandler,
+ NULL, //hasInternalSubsetHandler,
+ NULL, //hasExternalSubsetHandler,
+ NULL, //resolveEntityHandler,
+ NULL, //getEntityHandler,
+ NULL, //entityDeclHandler,
+ NULL, //notationDeclHandler,
+ NULL, //attributeDeclHandler,
+ NULL, //elementDeclHandler,
+ NULL, //unparsedEntityDeclHandler,
+ NULL, //setDocumentLocatorHandler,
+ NULL, //startDocumentHandler,
+ NULL, //endDocumentHandler,
+ startElementHandler,
+ endElementHandler,
+ NULL, //referenceHandler,
+ charactersHandler,
+ NULL, //ignorableWhitespaceHandler,
+ NULL, //processingInstructionHandler,
+ NULL, //commentHandler,
+ warningHandler,
+ errorHandler,
+ fatalErrorHandler,
+ NULL, //getParameterEntityHandler,
+ cdataBlockHandler,
+ NULL, //externalSubsetHandler,
+ 1
+};
+
+
+xmlSAXHandlerPtr debugSAXHandler = &debugSAXHandlerStruct;
+
+
+xmlSAXHandler extractSAXHandlerStruct = {
+ NULL, //internalSubsetHandler,
+ NULL, //isStandaloneHandler,
+ NULL, //hasInternalSubsetHandler,
+ NULL, //hasExternalSubsetHandler,
+ NULL, //resolveEntityHandler,
+ NULL, //getEntityHandler,
+ NULL, //entityDeclHandler,
+ NULL, //notationDeclHandler,
+ NULL, //attributeDeclHandler,
+ NULL, //elementDeclHandler,
+ NULL, //unparsedEntityDeclHandler,
+ NULL, //setDocumentLocatorHandler,
+ NULL, //startDocumentHandler,
+ NULL, //endDocumentHandler,
+ extractStartElementHandler,
+ extractEndElementHandler,
+ NULL, //referenceHandler,
+ extractCharactersHandler,
+ NULL, //ignorableWhitespaceHandler,
+ NULL, //processingInstructionHandler,
+ NULL, //commentHandler,
+ warningHandler,
+ errorHandler,
+ fatalErrorHandler,
+ NULL, //getParameterEntityHandler,
+ NULL, //cdataBlockHandler,
+ NULL, //externalSubsetHandler,
+ 1
+};
+
+xmlSAXHandlerPtr extractSAXHandler = &extractSAXHandlerStruct;
+
+
+
+
+//--------------------------------------------------
+// Reads in signed XML document info from digidoc file
+// ppSigDoc - pointer to the buffer of newly read info pointer
+// szFileName - documents filename
+// checkFileDigest - indicates if digests of datafiles referred by the document must be checked
+// lMaxDFLen - maximum size for a DataFile whose contents will be
+// kept in memory
+//--------------------------------------------------
+EXP_OPTION int ddocSaxReadSignedDocFromFile(SignedDoc** ppSigDoc, const char* szFileName,
+ int checkFileDigest, long lMaxDFLen)
+{
+ int err = ERR_OK, ret, n;
+ FILE *f;
+ char chars[1028], *p, buf1[16385];
+ xmlParserCtxtPtr ctxt;
+ SigDocParse pctx;
+ DigiDocMemBuf mbuf1;
+#ifdef WIN32
+ wchar_t *convFileName = 0;
+ err = utf82unicode((const char*)szFileName, (char**)&convFileName, &ret);
+ ddocDebug(3, "ddocSaxReadSignedDocFromFile", "file: %s, conv-file: %s", szFileName, convFileName);
+#endif
+
+ ddocDebug(3, "ddocSaxReadSignedDocFromFile", "digidoc: %s, checkDig: %d, maxDF: %ld",
+ szFileName, checkFileDigest, lMaxDFLen);
+ RETURN_IF_NULL_PARAM(ppSigDoc);
+ RETURN_IF_NULL_PARAM(szFileName);
+ clearErrors();
+ memset(&pctx, 0, sizeof(pctx));
+ pctx.pSigDoc = (SignedDoc*)malloc(sizeof(SignedDoc));
+ RETURN_IF_BAD_ALLOC(pctx.pSigDoc);
+ memset(pctx.pSigDoc, 0, sizeof(SignedDoc));
+#ifdef WIN32
+ ddocDebug(3, "ddocSaxReadSignedDocFromFile", "Opening file: %s", convFileName);
+ if(!err && ((f = _wfopen(convFileName, L"rb")) != NULL)) {
+#else
+ ddocDebug(3, "ddocSaxReadSignedDocFromFile", "Opening file: %s", szFileName);
+ if(!err && ((f = fopen(szFileName, "rb")) != NULL)) {
+#endif
+ ddocDebug(4, "ddocSaxReadSignedDocFromFile", "file opened");
+ n=0;
+ if(ftell(f) > 0) {
+ ddocDebug(5, "ddocSaxReadSignedDocFromFile", "File position after open is: %d err: %d eof: %d, move to begin!", ftell(f), ferror(f), feof(f));
+ fseek(f, 0, SEEK_SET);
+ }
+ //memset(chars,0,sizeof(chars));
+ ret = fread(chars, 1, 100, f);
+ if (ret > 0) {
+ chars[ret] = 0; // zero terminate block data
+ p = strstr(chars, "<?xml");
+ if(!p)
+ p = chars;
+ n++;
+ //pctx.bDataFile = (BIO*)1;
+ pctx.szInputFileName = (char*)szFileName;
+ pctx.checkFileDigest = checkFileDigest;
+ pctx.lMaxDFLen = lMaxDFLen;
+ time(&(pctx.tStartParse));
+ ddocDebug(5, "ddocSaxReadSignedDocFromFile", "parse block: %d len: %d fpos: %d \n---\n%s\n---\n", n, ret, ftell(f), p);
+
+ ctxt = xmlCreatePushParserCtxt(debugSAXHandler, &pctx,
+ p, strlen(p), szFileName);
+ do {
+ //memset(chars, 0, sizeof(chars)); // no longer necessary as zero terminated later here
+ ret = fread(chars, 1, 1024, f);
+ ddocDebug(5, "ddocSaxReadSignedDocFromFile", "read block: %d got: %d fpos: %d err: %d eof: %d", n, ret, ftell(f), ferror(f), feof(f));
+ if((ferror(f) && ret <= 0) && !feof(f)) {
+ ddocDebug(1, "ddocSaxReadSignedDocFromFile", "Error %d reading file: %s", ferror(f), szFileName);
+ SET_LAST_ERROR_RETURN_CODE(ERR_FILE_READ);
+ }
+ if(ret >= 0) {
+ chars[ret] = 0; // zero terminate block data
+ } else {
+ ddocDebug(1, "ddocSaxReadSignedDocFromFile", "No data could be read from: %s pos: %d", szFileName, ftell(f));
+ break;
+ }
+ n++;
+ ddocDebug(5, "ddocSaxReadSignedDocFromFile", "parse block: %d len: %d fpos: %d \n---\n%s\n---\n", n, ret, ftell(f), chars);
+
+ if(pctx.bCollectDFData > 0 && !strcmp(pctx.ctx4, CONTENT_EMBEDDED_BASE64)) { // bypass mode
+ // look for new element start "<"
+ p = strchr(chars, '<');
+ // if we just enetered the bypass mode then send flush command
+ // but increment bypass mode in order not to fall out of it
+ if(pctx.bCollectDFData == 1 && !p) { // start bypass mode
+ pctx.bCollectDFData += 2; // increment with 2 so we dont return to flushing
+ ddocDebug(4, "ddocSaxReadSignedDocFromFile", "Starting bypass mode, skip: %d",
+ pctx.bCollectDFData);
+ // force the parser to release element content
+ // before entering into bypass mode
+ ddocDebug(5, "ddocSaxReadSignedDocFromFile", "parse bypass data %s", g_szDataFileFlush1);
+ xmlParseChunk(ctxt, g_szDataFileFlush1, strlen(g_szDataFileFlush1), 0);
+ ddocDebug(4, "ddocSaxReadSignedDocFromFile", "Entering bypass mode, skip: %d",
+ pctx.bCollectDFData);
+ }
+ if(pctx.bCollectDFData >=2 && !p /*pctx.bCollectElemData*/) { // parse in bypass mode
+ ddocDebug(4, "ddocSaxReadSignedDocFromFile", "Parsing in bypass mode, skip: %d len: %d",
+ pctx.bCollectDFData, ret);
+#ifdef WITH_BASE64_HASHING_HACK
+ ddocDebug(4, "ddocSaxReadSignedDocFromFile", "update sha1: %d - %s", ret, chars);
+ SHA1_Update(&(pctx.sctx), chars, ret);
+ mbuf1.pMem = chars;
+ mbuf1.nLen = ret;
+ ddocDebugWriteFile(4, "df-data.txt", &mbuf1);
+#else
+ pctx.errcode = ddocMemAppendData(&(pctx.mbufElemData), chars, ret);
+ // update sha1
+ l1 = sizeof(buf1);
+ EVP_DecodeUpdate(&(pctx.ectx), (unsigned char*)buf1, &l1, (unsigned char*)chars, ret);
+ ddocDebug(4, "ddocSaxReadSignedDocFromFile", "update sha1: %d - %s", l1, buf1);
+ SHA1_Update(&(pctx.sctx), buf1, l1);
+#endif
+ }
+ if(p) { // finish bypass mode
+ ddocDebug(4, "ddocSaxReadSignedDocFromFile", "Ending bypass mode len: %d, skip: %d",
+ ret, pctx.bCollectDFData);
+ snprintf(buf1, sizeof(buf1), g_szDataFileFlush2, pctx.ctx3, pctx.ctx4);
+ // send finish command
+ ddocDebug(5, "ddocSaxReadSignedDocFromFile", "parse finish data %s", buf1);
+ xmlParseChunk(ctxt, buf1, strlen(buf1), 0);
+ pctx.bCollectDFData = 1;
+ // parse the normal chunk that caused end
+ xmlParseChunk(ctxt, chars, ret, 0);
+ }
+ } else { // normal mode
+ ddocDebug(4, "ddocSaxReadSignedDocFromFile", "parsing normal chunk");
+ xmlParseChunk(ctxt, chars, ret, 0);
+ }
+
+ } while(ret > 0/* && pctx.ctx3[0]*/);
+ ddocDebug(5, "ddocSaxReadSignedDocFromFile", "parse end0 \n---\n%s\n---\n", chars);
+ xmlParseChunk(ctxt, chars, 0, 1);
+ xmlFreeParserCtxt(ctxt);
+ }
+ *ppSigDoc = pctx.pSigDoc;
+ fclose(f);
+ }
+ else {
+ err = ERR_FILE_READ;
+ ddocDebug(1, "ddocSaxReadSignedDocFromFile", "error reading file: %s, err: %d", szFileName, err);
+ }
+ if (err != ERR_OK) SET_LAST_ERROR(err);
+ if(!err)
+ err = getLastError();
+ ddocDebug(3, "ddocSaxReadSignedDocFromFile", "success reading file: %s, err: %d", szFileName, err);
+ // cleanup parser context
+ ddocSAXCleanup(&pctx);
+ // check ddoc xmlns problem
+ checkDdocWrongDigests(*ppSigDoc);
+#ifdef WIN32
+ free(convFileName);
+#endif
+ return checkUnknownErr();
+}
+
+
+//--------------------------------------------------
+// Reads in signed XML document info
+// ppSigDoc - pointer to the buffer of newly read info pointer
+// szFileName - documents filename
+// checkFileDigest - indicates if digests of datafiles referred by the document must be checked
+// lMaxDFLen - maximum size for a DataFile whose contents will be
+// kept in memory
+//--------------------------------------------------
+EXP_OPTION int ddocSaxReadSignedDocFromMemory(SignedDoc** ppSigDoc, const void* pData,
+ int len, long lMaxDFLen)
+{
+ int err = ERR_OK;
+ int ret, l2;
+ SigDocParse pctx;
+ char * p = 0;
+
+ ddocDebug(3, "ddocSaxReadSignedDocFromMemory", "data len: %d, maxDF: %ld", len, lMaxDFLen);
+ RETURN_IF_NULL_PARAM(ppSigDoc);
+ RETURN_IF_NULL_PARAM(pData);
+
+ clearErrors();
+ memset(&pctx, 0, sizeof(pctx));
+ pctx.pSigDoc = (SignedDoc*)malloc(sizeof(SignedDoc));
+ RETURN_IF_BAD_ALLOC(pctx.pSigDoc);
+ memset(pctx.pSigDoc, 0, sizeof(SignedDoc));
+ //pctx.bDataFile = (BIO*)1;
+ pctx.szInputFileName = 0;
+ pctx.checkFileDigest = 0;
+ pctx.lMaxDFLen = lMaxDFLen;
+ // skip any BOM marks or other non-xml chars at the beginning
+ if(pData)
+ p = strstr((const char*)pData, "<?xml");
+ if(p) {
+ l2 = strlen(p);
+ } else {
+ p = (char*)pData;
+ l2 = len;
+ }
+ ret = xmlSAXUserParseMemory(debugSAXHandler, &pctx, (const char*)p, l2);
+ *ppSigDoc = pctx.pSigDoc;
+ if (err != ERR_OK) {
+ SET_LAST_ERROR(err);
+ ddocDebug(1, "ddocSaxReadSignedDocFromMemory", "parsing error: %d", err);
+ }
+ if(!err)
+ err = getLastError();
+ // cleanup parser context
+ ddocSAXCleanup(&pctx);
+ return err;
+}
+
+
+//--------------------------------------------------
+// Reads in signed XML document and extracts the desired data file
+// pSigDoc - signed document object if exists. Can be NULL
+// szFileName - digidoc filename
+// szDataFileName - name of the file where to store embedded data.
+// szDocId - DataFile Id atribute value
+// szCharset - convert DataFile content to charset
+//--------------------------------------------------
+EXP_OPTION int ddocSaxExtractDataFile(SignedDoc* pSigDoc, const char* szFileName,
+ const char* szDataFileName, const char* szDocId,
+ const char* szCharset)
+{
+ FILE *f;
+ int ret, err = ERR_OK;
+ long len;
+ char chars[1050], convFileName[1024],
+ convDataFileName[1024], *p;
+ xmlParserCtxtPtr ctxt;
+ SigDocParse pctx;
+ void* pBuf;
+ // test
+ ddocDebug(3, "ddocSaxExtractDataFile", "SigDoc: %s, docid: %s, digidoc: %s, file: %s, charset: %s", (pSigDoc ? "OK" : "NULL"), szDocId, szFileName, szDataFileName, szCharset);
+ return ddocExtractDataFile(pSigDoc, szFileName, szDataFileName, szDocId, szCharset);
+ RETURN_IF_NULL_PARAM(szFileName);
+ RETURN_IF_NULL_PARAM(szDataFileName);
+ RETURN_IF_NULL_PARAM(szDocId);
+ RETURN_IF_NULL_PARAM(szCharset);
+
+ clearErrors();
+ memset(&pctx, 0, sizeof(pctx));
+ memset(convFileName, 0, sizeof(convFileName));
+ memset(convDataFileName, 0, sizeof(convDataFileName));
+ ddocConvertFileName(convDataFileName, sizeof(convDataFileName), szDataFileName);
+ ddocConvertFileName(convFileName, sizeof(convFileName), szFileName);
+
+ // test
+ return ddocExtractDataFile(pSigDoc, szFileName, szDataFileName, szDocId, szCharset);
+
+ // try reading from memory if already cached?
+ ret = ddocGetDataFileCachedData(pSigDoc, szDocId, &pBuf, &len);
+ if(pBuf) { // gotcha
+ ddocDebug(3, "ddocSaxExtractDataFile", "Using cached data: %d bytes", len);
+ if((f = fopen(convDataFileName, "wb")) != NULL) {
+ fwrite(pBuf, 1, len, f);
+ fclose(f);
+ } else {
+ ddocDebug(1, "ddocSaxExtractDataFile", "Error writing file: %s", convDataFileName);
+ SET_LAST_ERROR_RETURN_CODE(ERR_FILE_WRITE);
+ }
+ free(pBuf);
+ return ret;
+ }
+ strncpy(pctx.ctx5, convDataFileName, sizeof(pctx.ctx5));
+ if ((f = fopen(convFileName, "r")) != NULL) {
+ pctx.pSigDoc = NULL;
+ pctx.bDataFile = NULL;
+ pctx.ctx1[0] = pctx.ctx2[0] = pctx.ctx3[0] = pctx.tag[0] = pctx.ctx4[0] = 0;
+ pctx.errcode = ERR_OK;
+ time(&(pctx.tStartParse));
+ pctx.bDataFile = NULL; //BIO_new_file(szDataFileName, "w");
+ strncpy(pctx.ctx1, szCharset, sizeof(pctx.ctx1));
+ pctx.szInputFileName = (char*)szFileName;
+ strncpy(pctx.ctx3, szDocId, sizeof(pctx.ctx3));
+ memset(chars, 0, sizeof(chars));
+ ret = fread(chars, 1, 10, f);
+ if (ret > 0) {
+ p = strstr(chars, "<?xml");
+ if(!p)
+ p = chars;
+ ctxt = xmlCreatePushParserCtxt(extractSAXHandler, &pctx,
+ p, strlen(p), szFileName);
+ do {
+ memset(chars, 0, sizeof(chars));
+ ret = fread(chars, 1, 1024, f);
+ ddocDebug(6, "ddocSaxExtractDataFile", "Parsing %d bytes: \n%s\n", ret, chars);
+ if(ret <= 0) break;
+ if(pctx.bCollectDFData > 0 &&
+ !strcmp(pctx.ctx4, CONTENT_EMBEDDED_BASE64)) { // bypass mode
+ // look for new element start "<"
+ p = strchr(chars, '<');
+ // if we just entered the bypass mode then send flush command
+ // but increment bypass mode in order not to fall out of it
+ if(pctx.bCollectDFData == 1 && !p) { // start bypass mode
+ pctx.bCollectDFData += 2; // increment with 2 so we dont return to flushing
+ ddocDebug(4, "ddocSaxExtractDataFile", "Starting bypass mode, skip: %d",
+ pctx.bCollectDFData);
+ // force the parser to release element content
+ // before entering into bypass mode
+ xmlParseChunk(ctxt, g_szDataFileFlush1, strlen(g_szDataFileFlush1), 0);
+ ddocDebug(4, "ddocSaxExtractDataFile", "Entering bypass mode, skip: %d",
+ pctx.bCollectDFData);
+ }
+ if(pctx.bCollectDFData >=2 && !p) { // parse in bypass mode
+ ddocDebug(4, "ddocSaxExtractDataFile",
+ "Parsing in bypass mode, skip: %d len: %d",
+ pctx.bCollectDFData, ret);
+ if(!strcmp(pctx.ctx1, "NO-CHANGE")) { // NO-CHANGE
+ extractNoChangeHandler(&pctx, (const char*)chars, ret);
+ } else {
+ extractBodyHandler(&pctx, (const char*)chars, ret);
+ }
+ }
+ if(p) { // finish bypass mode
+ *p = 0;
+ ddocDebug(3, "ddocSaxExtractDataFile", "Last block %d bytes: \n%s\n", ret, chars);
+ pctx.bCollectDFData = 1;
+ //xmlParseChunk(ctxt, chars, strlen((const char*)chars), 0);
+ if(!strcmp(pctx.ctx1, "NO-CHANGE")) { // NO-CHANGE
+ extractNoChangeHandler(&pctx, (const char*)chars, strlen(chars));
+ } else {
+ extractBodyHandler(&pctx, (const char*)chars, strlen(chars));
+ extractDecodeB64(&pctx, NULL, 0, 1);
+ }
+ pctx.bCollectDFData = 0; // stopp bypass attempts
+ memset(chars, 0, sizeof(chars));
+ ret = 0; // stop parsing
+ }
+ } else { // normal mode
+ ddocDebug(3, "ddocSaxExtractDataFile", "parsing normal chunk \n%s\n", chars);
+ xmlParseChunk(ctxt, chars, ret, 0);
+ memset(chars, 0, sizeof(chars));
+ }
+
+ } while(ret > 0 && pctx.ctx3[0]);
+ ddocDebug(3, "ddocSaxExtractDataFile", "parsing last chunk\n---%s\n---", chars);
+ if(strlen(chars))
+ xmlParseChunk(ctxt, chars, 0, 1);
+ xmlFreeParserCtxt(ctxt);
+ }
+ ddocDebug(5, "ddocSaxExtractDataFile", "parsing complete");
+ fclose(f);
+ } else {
+ ddocDebug(1, "ddocSaxExtractDataFile", "Error reading file: %s", szFileName);
+ SET_LAST_ERROR_RETURN_CODE(ERR_FILE_READ);
+ }
+ if(!err)
+ err = getLastError();
+ // cleanup parser context
+ ddocSAXCleanup(&pctx);
+ return err;
+}
+
+//--------------------------------------------------
+// Reads in signed XML document and returns the
+// desired DataFile-s content in a memory buffer.
+// caller is responsible for freeing the memory.
+// pSigDoc - signed document object if cached
+// szFileName - name of digidoc file
+// szDocId - id if DataFile
+// pOutBuf - address of buffer pointer
+// bKeepBase64 - 1=don't decode base64, 0=decode base64
+// returns error code or ERR_OK
+//--------------------------------------------------
+EXP_OPTION int ddocSAXGetDataFile(SignedDoc* pSigDoc, const char* szFileName,
+ const char* szDocId, DigiDocMemBuf* pOutBuf,
+ int bKeepBase64)
+{
+ FILE *f;
+ int ret, err = ERR_OK;
+ char chars[1025], convFileName[1024], *p, buf1[200];
+ xmlParserCtxtPtr ctxt;
+ SigDocParse pctx;
+
+ RETURN_IF_NULL_PARAM(szFileName);
+ RETURN_IF_NULL_PARAM(szDocId);
+ clearErrors();
+ ddocDebug(3, "ddocSAXGetDataFile", "SigDoc: %s, docid: %s, digidoc: %s, keepb64: %d",
+ (pSigDoc ? "OK" : "NULL"), szDocId, szFileName, bKeepBase64);
+ // try reading from memory if already cached?
+ pOutBuf->pMem = 0;
+ pOutBuf->nLen = 0;
+ ret = ddocGetDataFileCachedData(pSigDoc, szDocId, &(pOutBuf->pMem), &pOutBuf->nLen);
+ if(pOutBuf->pMem) { // gotcha
+ ddocDebug(3, "ddocSAXGetDataFile", "Using cached data: %d bytes", pOutBuf->nLen);
+ return ret;
+ }
+ memset(&pctx, 0, sizeof(pctx));
+ ddocConvertFileName( convFileName, sizeof(convFileName), szFileName );
+ if ((f = fopen(convFileName, "r")) != NULL) {
+ pctx.pSigDoc = NULL;
+ pctx.bDataFile = NULL;
+ pctx.ctx1[0] = pctx.ctx2[0] = pctx.ctx3[0] = pctx.tag[0] = pctx.ctx4[0] = 0;
+ pctx.errcode = ERR_OK;
+ pctx.bKeepBase64 = bKeepBase64;
+ pOutBuf->pMem = 0;
+ pOutBuf->nLen = 0;
+ pctx.pMemBufDF = pOutBuf;
+ time(&(pctx.tStartParse));
+ pctx.bDataFile = NULL; //BIO_new_file(szDataFileName, "w");
+ //strcpy(pctx.ctx1, szCharset);
+ pctx.szInputFileName = (char*)szFileName;
+ strncpy(pctx.ctx3, szDocId, sizeof(pctx.ctx3));
+ memset(chars, 0, sizeof(chars));
+ ret = fread(chars, 1, 100, f);
+ if (ret > 0) {
+ p = strstr(chars, "<?xml");
+ if(!p)
+ p = chars;
+ ctxt = xmlCreatePushParserCtxt(extractSAXHandler, &pctx,
+ p, strlen(p), szFileName);
+ do {
+ memset(chars, 0, sizeof(chars));
+ ret = fread(chars, 1, sizeof(chars)-1, f);
+ if(ret <= 0) break;
+ if(ret > 0 && ret < sizeof(chars)) chars[ret] = 0;
+ if(pctx.bCollectDFData > 0) { // bypass mode
+ // look for new element start "<"
+ p = strchr(chars, '<');
+ // if we just enetered the bypass mode then send flush command
+ // but increment bypass mode in order not to fall out of it
+ if(pctx.bCollectDFData == 1 && !p) { // start bypass mode
+ pctx.bCollectDFData += 2; // increment with 2 so we dont return to flushing
+ ddocDebug(4, "ddocSAXGetDataFile", "Starting bypass mode, skip: %d",
+ pctx.bCollectDFData);
+ // force the parser to release element content
+ // before entering into bypass mode
+ xmlParseChunk(ctxt, g_szDataFileFlush1, strlen(g_szDataFileFlush1), 0);
+ ddocDebug(4, "ddocSAXGetDataFile", "Entering bypass mode, skip: %d",
+ pctx.bCollectDFData);
+ }
+ if(pctx.bCollectDFData >=2 && !p) { // parse in bypass mode
+ ddocDebug(4, "ddocSAXGetDataFile", "Parsing in bypass mode, skip: %d len: %d",
+ pctx.bCollectDFData, ret);
+ extractBodyHandler(&pctx, (const char*)chars, ret);
+ }
+ if(p) { // finish bypass mode
+ ddocDebug(4, "ddocSAXGetDataFile", "Ending bypass mode len: %d, skip: %d",
+ ret, pctx.bCollectDFData);
+ snprintf(buf1, sizeof(buf1), g_szDataFileFlush2, pctx.ctx3, pctx.ctx4);
+ // send finish command
+ xmlParseChunk(ctxt, buf1, strlen(buf1), 0);
+ pctx.bCollectDFData = 1;
+ // parse the normal chunk that caused end
+ xmlParseChunk(ctxt, chars, ret, 0);
+ }
+ } else { // normal mode
+ ddocDebug(4, "ddocSAXGetDataFile", "parsing normal chunk");
+ xmlParseChunk(ctxt, chars, ret, 0);
+ }
+
+ } while(ret > 0);
+ xmlParseChunk(ctxt, chars, 0, 1);
+ xmlFreeParserCtxt(ctxt);
+ }
+ fclose(f);
+ } else {
+ ddocDebug(1, "ddocSAXGetDataFile", "Error reading file: %s", szFileName);
+ SET_LAST_ERROR_RETURN_CODE(ERR_FILE_READ);
+ }
+ if(!err)
+ err = getLastError();
+ // cleanup parser context
+ ddocSAXCleanup(&pctx);
+ return err;
+}
+
+
+//--------------------------------------------------
+// Reads new signatures from another digidoc file
+// and adds to existing digidoc. Adds only those
+// signatures that don't exist in old digidoc.
+// pSigDoc - signed document object
+// szFileName - name of digidoc file
+// returns error code or ERR_OK
+//--------------------------------------------------
+EXP_OPTION int ddocReadNewSignaturesFromDdoc(SignedDoc* pSigDoc, const char* szFileName)
+{
+ SignedDoc *pSigDoc2 = 0;
+ int err = ERR_OK, n1 = 0, n2 = 0, i;
+ SignatureInfo** pSignatures = NULL;
+
+ RETURN_IF_NULL_PARAM(pSigDoc);
+ RETURN_IF_NULL_PARAM(szFileName);
+ // read in digidoc file
+ err = ddocSaxReadSignedDocFromFile(&pSigDoc2, szFileName, 0, 0);
+ if(err) {
+ if(pSigDoc2)
+ SignedDoc_free(pSigDoc2);
+ return err;
+ }
+ // copy new signatures from digidoc just read in
+ // assumes that new signatures are at the end
+ n1 = getCountOfSignatures(pSigDoc);
+ n2 = getCountOfSignatures(pSigDoc2);
+ if(n2 > n1) {
+ pSignatures = (SignatureInfo**)realloc(pSigDoc->pSignatures, n2 * sizeof(void *));
+ if(!pSignatures) {
+ if(pSigDoc2)
+ SignedDoc_free(pSigDoc2);
+ RETURN_IF_BAD_ALLOC(pSignatures);
+ }
+ pSigDoc->pSignatures = pSignatures;
+ for(i = n1; i < n2; i++) {
+ pSigDoc->pSignatures[i] = pSigDoc2->pSignatures[i]; // take ownership
+ pSigDoc2->pSignatures[i] = 0; // set to NULL to prevent deallocation
+ // VS destroy hash - debug
+ ((char*)pSigDoc->pSignatures[i]->pDocs[0]->szDigest)[0] = 0x0A;
+ }
+ pSigDoc->nSignatures = n2;
+ pSigDoc2->nSignatures = n1;
+ }
+ // delete new digidoc object no longer necessary
+ SignedDoc_free(pSigDoc2);
+
+ return err;
+}
+
+char* pHdr1 = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\" ?>\n";
+char* pHdr2 = "<SignedDoc format=\"DIGIDOC-XML\" version=\"1.3\" xmlns=\"http://www.sk.ee/DigiDoc/v1.3.0#\">\n";
+char* pHdr3 = "\n</SignedDoc>";
+
+//--------------------------------------------------
+// Adds new signature to existing ddoc
+// szFileName - ddoc file name
+// pSigBuf - buffer with new signature data
+// nSigLen - new signature data length
+//--------------------------------------------------
+EXP_OPTION int ddocAddSignatureFromMemory(SignedDoc* pSigDoc, const char* szFileName, const void* pSigBuf, int nSigLen)
+{
+ int err = ERR_OK, n1 = 0, n2 = 0, i;
+ SignatureInfo** pSignatures = NULL;
+ SignedDoc *pSigDoc2 = 0;
+ char buf1[102], *p1;
+ FILE* f;
+ DigiDocMemBuf mbuf1;
+#ifdef WIN32
+ wchar_t *convFileName = 0;
+ int ret = 0;
+#endif
+
+ RETURN_IF_NULL_PARAM(pSigDoc);
+ //RETURN_IF_NULL_PARAM(szFileName && strlen(szFileName));
+ RETURN_IF_NULL_PARAM(pSigBuf);
+ mbuf1.pMem = 0;
+ mbuf1.nLen = 0;
+ clearErrors();
+ ddocDebug(3, "ddocAddSignatureFromMemory", "SigDoc: %s, file: %s, sig: %s, slen: %d",
+ (pSigDoc ? "OK" : "NULL"), szFileName, (pSigBuf ? "OK" : "NULL"), nSigLen);
+
+ // read in digidoc buffer
+ ddocMemAssignData(&mbuf1, pHdr1, -1);
+ ddocMemAppendData(&mbuf1, pHdr2, -1);
+ ddocMemAppendData(&mbuf1, pSigBuf, nSigLen);
+ ddocMemAppendData(&mbuf1, pHdr3, -1);
+ err = ddocSaxReadSignedDocFromMemory(&pSigDoc2, mbuf1.pMem, mbuf1.nLen, mbuf1.nLen);
+ ddocMemBuf_free(&mbuf1);
+ if(err) {
+ ddocDebug(1, "ddocAddSignatureFromMemory", "Error: %d reading signature", err);
+ if(pSigDoc2)
+ SignedDoc_free(pSigDoc2);
+ return err;
+ }
+ // copy new signatures from digidoc just read in
+ // assumes that new signatures are at the end
+ n1 = getCountOfSignatures(pSigDoc);
+ n2 = getCountOfSignatures(pSigDoc2);
+ if(n2 > n1) {
+ pSignatures = (SignatureInfo**)realloc(pSigDoc->pSignatures, n2 * sizeof(void *));
+ if(!pSignatures) {
+ if(pSigDoc2)
+ SignedDoc_free(pSigDoc2);
+ RETURN_IF_BAD_ALLOC(pSignatures);
+ }
+ pSigDoc->pSignatures = pSignatures;
+ for(i = n1; i < n2; i++) {
+ pSigDoc->pSignatures[i] = pSigDoc2->pSignatures[i]; // take ownership
+ pSigDoc2->pSignatures[i] = 0; // set to NULL to prevent deallocation
+ }
+ pSigDoc->nSignatures = n2;
+ pSigDoc2->nSignatures = n1;
+ }
+ // delete new digidoc object no longer necessary
+ SignedDoc_free(pSigDoc2);
+ ddocDebug(3, "ddocAddSignatureFromMemory", "RC: %d adding signature", err);
+ // now append new signature to existing ddoc file
+ if(szFileName && strlen(szFileName)) { // if we have to update ddoc on disc
+#ifdef WIN32
+ err = utf82unicode((const char*)szFileName, (char**)&convFileName, &ret);
+ ddocDebug(3, "ddocAddSignatureFromMemory", "file: %s, conv-file: %s", szFileName, convFileName);
+ ddocDebug(3, "ddocSaxReadSignedDocFromFile", "Opening file: %s", convFileName);
+ if(!err && ((f = _wfopen(convFileName, L"r+b")) != NULL)) {
+#else
+ ddocDebug(3, "ddocSaxReadSignedDocFromFile", "Opening file: %s", szFileName);
+ if(!err && ((f = fopen(szFileName, "r+b")) != NULL)) {
+#endif
+ ddocDebug(3, "ddocSaxReadSignedDocFromFile", "file opened, pos: %d", ftell(f));
+ // seek to file end -100 bytes anf find ddoc end tag
+ err = fseek(f, -30, SEEK_END);
+ ddocDebug(3, "ddocSaxReadSignedDocFromFile", "seek: %d new pos: %d", err, ftell(f));
+ memset(buf1, 0, sizeof(buf1));
+ n1 = fread(buf1, 1, 30, f);
+ ddocDebug(3, "ddocSaxReadSignedDocFromFile", "read: %d data: %s", n1, buf1);
+ p1 = strstr(buf1, "</SignedDoc>");
+ if(p1) {
+ *p1 = 0;
+ n2 = strlen(buf1);
+ ddocDebug(3, "ddocSaxReadSignedDocFromFile", "distance: %d", n2);
+ err = fseek(f, -1 * (30 - n2), SEEK_END);
+ ddocDebug(3, "ddocSaxReadSignedDocFromFile", "seek: %d new pos: %d", err, ftell(f));
+ n1 = fwrite(pSigBuf, 1, nSigLen, f);
+ ddocDebug(3, "ddocSaxReadSignedDocFromFile", "wrote: %d", n1);
+ fputs("</SignedDoc>", f);
+ }
+ fclose(f);
+ }
+ } // if szFileName
+ return err;
+}
+
diff --git a/libdigidoc/DigiDocSAXParser.h b/libdigidoc/DigiDocSAXParser.h
new file mode 100644
index 0000000..aad2fc6
--- /dev/null
+++ b/libdigidoc/DigiDocSAXParser.h
@@ -0,0 +1,105 @@
+#ifndef __DIGIDOC_SAX_PARSER_H__
+#define __DIGIDOC_SAX_PARSER_H__
+//==================================================
+// FILE: DigiDocSAXParser.h
+// PROJECT: Digi Doc
+// DESCRIPTION: Digi Doc functions for xml parsing using SAX interface
+// This is the older parser and will probably
+// be removed in new versions
+// AUTHOR: Veiko Sinivee, S|E|B IT Partner Estonia
+//==================================================
+// Copyright (C) AS Sertifitseerimiskeskus
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+// GNU Lesser General Public Licence is available at
+// http://www.gnu.org/copyleft/lesser.html
+//==========< HISTORY >=============================
+// 12.08.2004 Veiko Sinivee
+// Creation
+// 22.08.2004 Veiko Sinivee
+// Renamed readSignedDoc() to ddocSaxReadSignedDocFromFile(). Params changed.
+// Renamed extractDataFile() to ddocSaxExtractDataFile(). Uses chached content.
+//==================================================
+
+#include <libdigidoc/DigiDocDefs.h>
+#include <libdigidoc/DigiDocLib.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+//--------------------------------------------------
+// Reads in signed XML document info from digidoc file
+// ppSigDoc - pointer to the buffer of newly read info pointer
+// szFileName - documents filename
+// checkFileDigest - indicates if digests of datafiles referred by the document must be checked
+// lMaxDFLen - maximum size for a DataFile whose contents will be
+// kept in memory
+//--------------------------------------------------
+EXP_OPTION int ddocSaxReadSignedDocFromFile(SignedDoc** ppSigDoc, const char* szFileName,
+ int checkFileDigest, long lMaxDFLen);
+
+//--------------------------------------------------
+// Reads in signed XML document and extracts the desired data file
+// pSigDoc - signed document object if exists. Can be NULL
+// szFileName - digidoc filename
+// szDataFileName - name of the file where to store embedded data.
+// szDocId - DataFile Id atribute value
+// szCharset - convert DataFile content to charset
+//--------------------------------------------------
+EXP_OPTION int ddocSaxExtractDataFile(SignedDoc* pSigDoc, const char* szFileName, const char* szDataFileName,
+ const char* szDocId, const char* szCharset);
+
+//--------------------------------------------------
+// Reads in signed XML document and returns the
+// desired DataFile-s content in a memory buffer.
+// caller is responsible for freeing the memory.
+// pSigDoc - signed document object if cached
+// szFileName - name of digidoc file
+// szDocId - id if DataFile
+// pBuf - address of buffer pointer
+// bKeepBase64 - 1=don't decode base64, 0=decode base64
+// returns error code or ERR_OK
+//--------------------------------------------------
+EXP_OPTION int ddocSAXGetDataFile(SignedDoc* pSigDoc, const char* szFileName,
+ const char* szDocId, DigiDocMemBuf* pBuf,
+ int bKeepBase64);
+
+//--------------------------------------------------
+// Reads in signed XML document info from memory buffer
+// ppSigDoc - pointer to the buffer of newly read info pointer
+// szFileName - documents filename
+// checkFileDigest - indicates if digests of datafiles referred by the document must be checked
+// lMaxDFLen - maximum size for a DataFile whose contents will be
+// kept in memory
+//--------------------------------------------------
+EXP_OPTION int ddocSaxReadSignedDocFromMemory(SignedDoc** ppSigDoc, const void* pData,
+ int len, long lMaxDFLen);
+
+//--------------------------------------------------
+// Reads new signatures from another digidoc file
+// and adds to existing digidoc. Adds only those
+// signatures that don't exist in old digidoc.
+// pSigDoc - signed document object
+// szFileName - name of digidoc file
+// returns error code or ERR_OK
+//--------------------------------------------------
+EXP_OPTION int ddocReadNewSignaturesFromDdoc(SignedDoc* pSigDoc, const char* szFileName);
+//AM 13.03.2008
+void decodeURI(const char* uri, char* id, int nIdLen, char* adr, int nAdrLen);
+
+
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif // __DIGIDOC_SAX_PARSER_H__
+
diff --git a/libdigidoc/DigiDocService.c b/libdigidoc/DigiDocService.c
new file mode 100644
index 0000000..ce471a3
--- /dev/null
+++ b/libdigidoc/DigiDocService.c
@@ -0,0 +1,341 @@
+//==================================================
+// FILE: DigiDocService.c
+// PROJECT: Digi Doc
+// DESCRIPTION: Digi Doc functions for DigiDocService access
+// AUTHOR: Veiko Sinivee, Sunset Software O
+//==================================================
+// Copyright (C) AS Sertifitseerimiskeskus
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+// GNU Lesser General Public Licence is available at
+// http://www.gnu.org/copyleft/lesser.html
+//==================================================
+
+// config data comes from there
+#include <config.h>
+#include <libdigidoc/DigiDocConfig.h>
+#include <libdigidoc/DigiDocService.h>
+#include <libdigidoc/DigiDocDebug.h>
+#include <libdigidoc/DigiDocMem.h>
+#include <libdigidoc/DigiDocObj.h>
+#include <libdigidoc/DigiDocConvert.h>
+#include <libdigidoc/DigiDocGen.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <memory.h>
+#include <string.h>
+
+char* g_xmlHdr1 = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<SOAP-ENV:Envelope xmlns:SOAP-ENV=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:SOAP-ENC=\"http://schemas.xmlsoap.org/soap/encoding/\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:d=\"http://www.sk.ee/DigiDocService/DigiDocService_2_3.wsdl\"><SOAP-ENV:Body SOAP-ENV:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\"><d:MobileCreateSignature>";
+char* g_xmlEnd1 = "</d:MobileCreateSignature></SOAP-ENV:Body></SOAP-ENV:Envelope>";
+char* g_xmlHdr2 = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<SOAP-ENV:Envelope xmlns:SOAP-ENV=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:SOAP-ENC=\"http://schemas.xmlsoap.org/soap/encoding/\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:d=\"http://www.sk.ee/DigiDocService/DigiDocService_2_3.wsdl\"><SOAP-ENV:Body SOAP-ENV:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\"><d:GetMobileCreateSignatureStatus>";
+char* g_xmlEnd2 = "</d:GetMobileCreateSignatureStatus></SOAP-ENV:Body></SOAP-ENV:Envelope>";
+
+char* g_ddsUrl = "https://digidocservice.sk.ee/DigiDocService";
+
+int ddocXmlElem(DigiDocMemBuf* pMbuf, const char* szElem, const char* szValue)
+{
+ int err = ERR_OK;
+ if(szValue) {
+ err = ddocGen_startElem(pMbuf, szElem);
+ if(!err)
+ err = ddocMemAppendData(pMbuf, szValue, -1);
+ if(!err)
+ err = ddocGen_endElem(pMbuf, szElem);
+ }
+ return err;
+}
+
+int findXmlElemValue(DigiDocMemBuf* pMbMsg, const char* szTag, DigiDocMemBuf* pMbValue)
+{
+ char *p1, *p2;
+ char tag[50];
+
+ p1 = (char*)pMbMsg->pMem;
+ if(p1) {
+ snprintf(tag, sizeof(tag), "<%s", szTag);
+ p1 = strstr(p1, tag);
+ if(p1) {
+ while(*p1 && *p1 != '>') p1++;
+ if(*p1 && *p1 == '>') p1++;
+ snprintf(tag, sizeof(tag), "</%s", szTag);
+ p2 = strstr(p1, tag);
+ if(p2 && p1 && (long)p2 > (long)p1) {
+ ddocMemAssignData(pMbValue, p1, (int)(p2 - p1));
+ return 0;
+ }
+ }
+ }
+ return -1;
+}
+
+
+//--------------------------------------------------
+// Signs the document and gets return status back
+// pSigDoc - signed document object
+// szIdCode - personal id code
+// szPhoneNo - users phone number
+// szLang - language code
+// manifest - manifest or role
+// city - signers address , city
+// state - signers address , state or province
+// zip - signers address , postal code
+// country - signers address , country name
+// pSesscode - pointer to long int buffer for returning session code
+// szChallenge - buffer for returning challenge code (char 4)
+// nChalLen - length of challenge buffer
+// return error code or ERR_OK
+//--------------------------------------------------
+EXP_OPTION int ddsSign(SignedDoc* pSigDoc,
+ const char* szIdCode, const char* szPhoneNo,
+ const char* szLang, const char* szServiceName,
+ const char* manifest, const char* city,
+ const char* state, const char* zip,
+ const char* country,
+ char* url, char* proxyHost, char* proxyPort,
+ long* pSesscode, char* szChallenge, int nChalLen)
+{
+ int err = ERR_OK, i, l1;
+ char *p1 = 0;
+ DataFile *pDf = 0;
+ DigiDocMemBuf mbuf1, mbuf2, mbuf3;
+ char buf1[40];
+
+ mbuf1.pMem = 0;
+ mbuf1.nLen = 0;
+ mbuf2.pMem = 0;
+ mbuf2.nLen = 0;
+ mbuf3.pMem = 0;
+ mbuf3.nLen = 0;
+ ddocDebug(3, "ddsSign", "Creating M-ID signature using: %s", szPhoneNo);
+ RETURN_IF_NULL_PARAM(pSigDoc);
+ RETURN_IF_NULL_PARAM(szIdCode);
+ RETURN_IF_NULL_PARAM(country);
+ RETURN_IF_NULL_PARAM(szPhoneNo);
+ //RETURN_IF_NULL_PARAM(url);
+ if(url == NULL)
+ url = g_ddsUrl;
+ RETURN_IF_NULL_PARAM(pSesscode);
+ RETURN_IF_NULL_PARAM(szChallenge);
+ ddocMemAssignData(&mbuf2, g_xmlHdr1, -1);
+ // create xml request
+ err = ddocXmlElem(&mbuf2, "IDCode", szIdCode);
+ err = ddocXmlElem(&mbuf2, "SignersCountry", country);
+ err = ddocXmlElem(&mbuf2, "PhoneNo", szPhoneNo);
+ err = ddocXmlElem(&mbuf2, "Language", szLang);
+ err = ddocXmlElem(&mbuf2, "ServiceName", szServiceName);
+ err = ddocXmlElem(&mbuf2, "Role", manifest);
+ err = ddocXmlElem(&mbuf2, "City", city);
+ err = ddocXmlElem(&mbuf2, "StateOrProvince", state);
+ err = ddocXmlElem(&mbuf2, "PostalCode", zip);
+ err = ddocXmlElem(&mbuf2, "CountryName", country);
+ err = ddocGen_startElem(&mbuf2, "DataFiles");
+ for(i = 0; i < getCountOfDataFiles(pSigDoc); i++) {
+ pDf = getDataFile(pSigDoc, i);
+ err = ddocGen_startElem(&mbuf2, "DataFileDigest");
+ err = ddocXmlElem(&mbuf2, "Id", pDf->szId);
+ err = ddocXmlElem(&mbuf2, "DigestType", pDf->szDigestType);
+ l1 = sizeof(buf1);
+ memset(buf1, 0, l1);
+ encode((const byte*)pDf->mbufDigest.pMem, pDf->mbufDigest.nLen, (byte*)buf1, &l1);
+ err = ddocXmlElem(&mbuf2, "DigestValue", buf1);
+ err = ddocGen_endElem(&mbuf2, "DataFileDigest");
+ }
+ err = ddocGen_endElem(&mbuf2, "DataFiles");
+ err = ddocXmlElem(&mbuf2, "Format", pSigDoc->szFormat);
+ err = ddocXmlElem(&mbuf2, "Version", pSigDoc->szFormatVer);
+ sprintf(buf1, "S%d", getNextSignatureId(pSigDoc));
+ err = ddocXmlElem(&mbuf2, "SignatureID", buf1);
+ err = ddocXmlElem(&mbuf2, "MessagingMode", "asynchClientServer");
+ err = ddocXmlElem(&mbuf2, "AsyncConfiguration", "0");
+ ddocMemAppendData(&mbuf2, g_xmlEnd1, -1);
+
+ // create http req
+ ddocMemAssignData(&mbuf1, "POST ", -1);
+ if(proxyHost || (proxyPort && atoi(proxyPort) > 0)) {
+ ddocMemAppendData(&mbuf1, url, -1);
+ } else {
+ p1 = strstr(url, "://");
+ if(p1) p1 += 3;
+ if(p1) p1 = strchr(p1, '/');
+ if(p1)
+ ddocMemAppendData(&mbuf1, p1, -1);
+ else
+ ddocMemAppendData(&mbuf1, "/", -1);
+ }
+ ddocMemAppendData(&mbuf1, " HTTP/1.0\r\n", -1);
+ ddocMemAppendData(&mbuf1, "User-Agent: DigiDocLib\r\n", -1);
+ ddocMemAppendData(&mbuf1, "Content-Type: text/xml; charset=utf-8\r\n", -1);
+ snprintf(buf1, sizeof(buf1), "Content-Length: %d\r\n", (int)mbuf2.nLen);
+ ddocMemAppendData(&mbuf1, buf1, -1);
+ ddocMemAppendData(&mbuf1, "Connection: Close\r\n", -1);
+ if(proxyHost || (proxyPort && atoi(proxyPort) > 0)) // if we use proxy then send also Proxy-Connection
+ ddocMemAppendData(&mbuf1, "Proxy-Connection: Close\r\n", -1);
+ ddocMemAppendData(&mbuf1, "SOAPAction: \"\"\r\n", -1);
+ ddocMemAppendData(&mbuf1, "\r\n", -1);
+ ddocMemAppendData(&mbuf1, mbuf2.pMem, mbuf2.nLen);
+ ddocDebug(4, "ddsSign", "Send to host: %s request len: %d", url, mbuf1.nLen);
+ ddocDebug(4, "ddsSign", "Sending: \n---\n%s\n---\n", mbuf1.pMem);
+ ddocMemBuf_free(&mbuf2);
+ err = ddocPullUrl(url, &mbuf1, &mbuf2, proxyHost, proxyPort);
+ ddocDebug(4, "ddsSign", "Recevied len: %d RC: %d", mbuf2.nLen, err);
+ //ddocDebug(3, "ddsSign", "Received: \n---\n%s\n---\n", mbuf2.pMem);
+ if(!err && ((l1 = ddocGetHttpResponseCode(&mbuf2)) == 200)) {
+ err = ddocGetHttpPayload(&mbuf2, &mbuf3);
+ ddocMemBuf_free(&mbuf2);
+ ddocDebug(4, "ddsSign", "SOAP: \n---\n%s\n---\n", mbuf3.pMem);
+ err = findXmlElemValue(&mbuf3, "Sesscode", &mbuf2);
+ if(!err)
+ (*pSesscode) = atol((char*)mbuf2.pMem);
+ //ddocDebug(3, "ddsSign", "Sesscode: %ld", (*pSesscode));
+ ddocMemBuf_free(&mbuf2);
+ err = findXmlElemValue(&mbuf3, "ChallengeID", &mbuf2);
+ //ddocDebug(3, "ddsSign", "Challenge id %s", mbuf2.pMem);
+ if(!err && mbuf2.pMem && mbuf2.nLen) {
+ memset(szChallenge, 0, nChalLen);
+ strncpy(szChallenge, mbuf2.pMem, mbuf2.nLen);
+ }
+ ddocDebug(3, "ddsSign", "Sesscode: %ld Challenge id %s RC: %d", (*pSesscode), szChallenge, err);
+ ddocMemBuf_free(&mbuf2);
+ }
+
+ ddocMemBuf_free(&mbuf1);
+ ddocMemBuf_free(&mbuf2);
+ ddocMemBuf_free(&mbuf3);
+ RETURN_IF_NOT(err == ERR_OK, err);
+ return err;
+}
+
+//------------------------------------------
+// Gets DigiDocService session status and returns status code
+// If session is ready then signature will be returned
+// pSigDoc - signed document object to be modified
+// lSesscode - session code
+// url - dds service url
+// proxyHost - proxy hostname
+// proxyPort -proxy port
+// pStatus - buffer for returning status
+// pMBufSig - buffer for returning signature
+// returns DigiDocService session status code
+// deprecated use ddsGetStatus(pSigDoc, lSesscode, url, proxyHost, proxyPort, pStatus, szFileName)
+//------------------------------------------
+DIGIDOC_DEPRECATED EXP_OPTION int ddsGetStatus(SignedDoc* pSigDoc, long lSesscode,
+ char* url, char* proxyHost, char* proxyPort,
+ int* pStatus)
+{
+ return ddsGetStatusWithFile(pSigDoc, lSesscode, url, proxyHost, proxyPort, pStatus, NULL);
+}
+
+//------------------------------------------
+// Gets DigiDocService session status and returns status code
+// If session is ready then signature will be returned
+// pSigDoc - signed document object to be modified
+// lSesscode - session code
+// url - dds service url
+// proxyHost - proxy hostname
+// proxyPort -proxy port
+// pStatus - buffer for returning status
+// szFileName - ddoc filename to add signature from dds (optional)
+// pMBufSig - buffer for returning signature
+// returns DigiDocService session status code
+//------------------------------------------
+EXP_OPTION int ddsGetStatusWithFile(SignedDoc* pSigDoc, long lSesscode,
+ char* url, char* proxyHost, char* proxyPort,
+ int* pStatus, const char* szFileName)
+{
+ int err = ERR_OK, l1;
+ SignatureInfo *pSigInfo = 0;
+ DigiDocMemBuf mbuf1, mbuf2, mbuf3;
+ char buf1[40], *p1;
+
+ mbuf1.pMem = 0;
+ mbuf1.nLen = 0;
+ mbuf2.pMem = 0;
+ mbuf2.nLen = 0;
+ mbuf3.pMem = 0;
+ mbuf3.nLen = 0;
+ ddocDebug(3, "ddsGetStatus", "Get Status for sess: %ld", lSesscode);
+ RETURN_IF_NULL_PARAM(pSigDoc);
+ //RETURN_IF_NULL_PARAM(url);
+ if(url == NULL)
+ url = g_ddsUrl;
+ RETURN_IF_NULL_PARAM(pStatus);
+ *pStatus = 0;
+ ddocMemAssignData(&mbuf2, g_xmlHdr2, -1);
+ // create xml request
+ sprintf(buf1, "%ld", lSesscode);
+ err = ddocXmlElem(&mbuf2, "Sesscode", buf1);
+ err = ddocXmlElem(&mbuf2, "WaitSignature", "false");
+ ddocMemAppendData(&mbuf2, g_xmlEnd2, -1);
+
+ // create http req
+ ddocMemAssignData(&mbuf1, "POST ", -1);
+ if(proxyHost || (proxyPort && atoi(proxyPort) > 0)) {
+ ddocMemAppendData(&mbuf1, url, -1);
+ } else {
+ p1 = strstr(url, "://");
+ if(p1) p1 += 3;
+ if(p1) p1 = strchr(p1, '/');
+ if(p1)
+ ddocMemAppendData(&mbuf1, p1, -1);
+ else
+ ddocMemAppendData(&mbuf1, "/", -1);
+ }
+ ddocMemAppendData(&mbuf1, " HTTP/1.0\r\n", -1);
+ ddocMemAppendData(&mbuf1, "User-Agent: DigiDocLib\r\n", -1);
+ ddocMemAppendData(&mbuf1, "Content-Type: text/xml; charset=utf-8\r\n", -1);
+ snprintf(buf1, sizeof(buf1), "Content-Length: %d\r\n", (int)mbuf2.nLen);
+ ddocMemAppendData(&mbuf1, buf1, -1);
+ ddocMemAppendData(&mbuf1, "Connection: Close\r\n", -1);
+ if(proxyHost || (proxyPort && atoi(proxyPort) > 0)) // if we use proxy then send also Proxy-Connection
+ ddocMemAppendData(&mbuf1, "Proxy-Connection: Close\r\n", -1);
+ ddocMemAppendData(&mbuf1, "SOAPAction: \"\"\r\n", -1);
+ ddocMemAppendData(&mbuf1, "\r\n", -1);
+ ddocMemAppendData(&mbuf1, mbuf2.pMem, mbuf2.nLen);
+ ddocDebug(4, "ddsGetStatus", "Send to host: %s request len: %d", url, mbuf1.nLen);
+ ddocDebug(4, "ddsGetStatus", "Sending: \n---\n%s\n---\n", mbuf1.pMem);
+ ddocMemBuf_free(&mbuf2);
+ err = ddocPullUrl(url, &mbuf1, &mbuf2, proxyHost, proxyPort);
+ ddocDebug(4, "ddsGetStatus", "Recevied len: %d RC: %d", mbuf2.nLen, err);
+ //ddocDebug(3, "ddsSign", "Received: \n---\n%s\n---\n", mbuf2.pMem);
+ if(!err && ((l1 = ddocGetHttpResponseCode(&mbuf2)) == 200)) {
+ err = ddocGetHttpPayload(&mbuf2, &mbuf3);
+ ddocMemBuf_free(&mbuf2);
+ ddocDebug(4, "ddsGetStatus", "SOAP: \n---\n%s\n---\n", mbuf3.pMem);
+ err = findXmlElemValue(&mbuf3, "Status", &mbuf2);
+ if(!err && mbuf2.pMem) {
+ if(!strcmp((char*)mbuf2.pMem, "OUTSTANDING_TRANSACTION"))
+ (*pStatus) = STATUS_OUTSTANDING_TRANSACTION;
+ if(!strcmp((char*)mbuf2.pMem, "SIGNATURE"))
+ (*pStatus) = STATUS_SIGNATURE;
+ if(!strcmp((char*)mbuf2.pMem, "ERROR"))
+ (*pStatus) = STATUS_ERROR;
+
+ }
+ ddocDebug(3, "ddsGetStatus", "Sesscode: %ld Status: %d RC: %d", lSesscode, (*pStatus), err);
+ ddocMemBuf_free(&mbuf2);
+ if((*pStatus) == STATUS_SIGNATURE) {
+ err = findXmlElemValue(&mbuf3, "Signature", &mbuf2);
+ ddocDebug(4, "ddsGetStatus", "Sig-esacped: \n---\n%s\n---\n", mbuf2.pMem);
+ p1 = escape2xmlsym((char*)mbuf2.pMem);
+ ddocDebug(4, "ddsGetStatus", "Signature: \n---\n%s\n---\n", p1);
+ err = ddocAddSignatureFromMemory(pSigDoc, szFileName, (const void*)p1, strlen(p1));
+ /*sprintf(buf1, "S%d", getNextSignatureId(pSigDoc));
+ SignatureInfo_new(&pSigInfo, pSigDoc, buf1);
+ ddocMemAssignData(&(pSigInfo->mbufOrigContent), p1, -1);*/
+ free(p1);
+ }
+ }
+
+ ddocMemBuf_free(&mbuf1);
+ ddocMemBuf_free(&mbuf2);
+ ddocMemBuf_free(&mbuf3);
+ RETURN_IF_NOT(err == ERR_OK, err);
+ return err;
+}
+
diff --git a/libdigidoc/DigiDocService.h b/libdigidoc/DigiDocService.h
new file mode 100644
index 0000000..8cce6f5
--- /dev/null
+++ b/libdigidoc/DigiDocService.h
@@ -0,0 +1,102 @@
+#ifndef __DIGI_DOC_SRV_H__
+#define __DIGI_DOC_SRV_H__
+//==================================================
+// FILE: DigiDocService.h
+// PROJECT: Digi Doc
+// DESCRIPTION: Digi Doc functions for DigiDocService access
+// AUTHOR: Veiko Sinivee, Sunset Software O
+//==================================================
+// Copyright (C) AS Sertifitseerimiskeskus
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+// GNU Lesser General Public Licence is available at
+// http://www.gnu.org/copyleft/lesser.html
+//==================================================
+
+#include <libdigidoc/DigiDocDefs.h>
+#include <libdigidoc/DigiDocHTTP.h>
+#include <libdigidoc/DigiDocMem.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define STATUS_UNKNOWN 0
+#define STATUS_OUTSTANDING_TRANSACTION 1
+#define STATUS_SIGNATURE 2
+#define STATUS_ERROR 3
+
+
+ //------------------------------------------
+ // Gets DigiDocService session status and returns status code
+ // If session is ready then signature will be returned
+ // pSigDoc - signed document object to be modified
+ // lSesscode - session code
+ // url - dds service url
+ // proxyHost - proxy hostname
+ // proxyPort -proxy port
+ // pStatus - buffer for returning status
+ // pMBufSig - buffer for returning signature
+ // returns DigiDocService session status code
+ // deprecated use ddsGetStatus(pSigDoc, lSesscode, url, proxyHost, proxyPort, pStatus, szFileName)
+ //------------------------------------------
+ DIGIDOC_DEPRECATED EXP_OPTION int ddsGetStatus(SignedDoc* pSigDoc, long lSesscode,
+ char* url, char* proxyHost, char* proxyPort,
+ int* pStatus);
+
+ //------------------------------------------
+ // Gets DigiDocService session status and returns status code
+ // If session is ready then signature will be returned
+ // pSigDoc - signed document object to be modified
+ // lSesscode - session code
+ // url - dds service url
+ // proxyHost - proxy hostname
+ // proxyPort -proxy port
+ // pStatus - buffer for returning status
+ // szFileName - ddoc filename to add signature from dds (optional)
+ // pMBufSig - buffer for returning signature
+ // returns DigiDocService session status code
+ //------------------------------------------
+ EXP_OPTION int ddsGetStatusWithFile(SignedDoc* pSigDoc, long lSesscode,
+ char* url, char* proxyHost, char* proxyPort,
+ int* pStatus, const char* szFileName);
+
+ //--------------------------------------------------
+ // Signs the document and gets return status back
+ // pSigDoc - signed document object
+ // szIdCode - personal id code
+ // szPhoneNo - users phone number
+ // szLang - language code
+ // manifest - manifest or role
+ // city - signers address , city
+ // state - signers address , state or province
+ // zip - signers address , postal code
+ // country - signers address , country name
+ // pSesscode - pointer to long int buffer for returning session code
+ // szChallenge - buffer for returning challenge code (char 4)
+ // nChalLen - length of challenge buffer
+ // return error code or ERR_OK
+ //--------------------------------------------------
+ EXP_OPTION int ddsSign(SignedDoc* pSigDoc,
+ const char* szIdCode, const char* szPhoneNo,
+ const char* szLang, const char* szServiceName,
+ const char* manifest, const char* city,
+ const char* state, const char* zip,
+ const char* country,
+ char* url, char* proxyHost, char* proxyPort,
+ long* pSesscode, char* szChallenge, int nChalLen);
+
+
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif // __DIGI_DOC_CFG_H__
diff --git a/libdigidoc/DigiDocStack.c b/libdigidoc/DigiDocStack.c
new file mode 100644
index 0000000..9ea32e7
--- /dev/null
+++ b/libdigidoc/DigiDocStack.c
@@ -0,0 +1,315 @@
+//==================================================
+// FILE: DigiDocStack.c
+// PROJECT: Digi Doc
+// DESCRIPTION: Digi Doc functions for simple stack
+// to keep track of xml parsing
+// AUTHOR: Veiko Sinivee, S|E|B IT Partner Estonia
+//==================================================
+// Copyright (C) AS Sertifitseerimiskeskus
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+// GNU Lesser General Public Licence is available at
+// http://www.gnu.org/copyleft/lesser.html
+//==========< HISTORY >=============================
+// 09.09.2004 Veiko Sinivee
+// Creation
+//==================================================
+
+#include <libdigidoc/DigiDocStack.h>
+#include <libdigidoc/DigiDocLib.h>
+#include <libdigidoc/DigiDocError.h>
+#include <libdigidoc/DigiDocDebug.h>
+#include <string.h>
+
+//--------------------------------------------------
+// Finds the last element on stack
+// reader - XML reader cursor to current node
+// pStack - address of stack begin. This one elemnt
+// must exist, but might be initially empty
+// return error code or ERR_OK
+//--------------------------------------------------
+ElementEntry* ddocStackFindEnd(ElementEntry* pStack)
+{
+ ElementEntry* pElem = pStack;
+ while(pElem->pNext)
+ pElem = (ElementEntry*)pElem->pNext;
+ return pElem;
+}
+
+//--------------------------------------------------
+// Push a new element info onto stack
+// reader - XML reader cursor to current node
+// pStack - address of stack begin. This one elemnt
+// must exist, but might be initially empty
+// pLastElem - address for new elements pointer.
+// If not NULL then will be used to return the
+// newly allocated elemnt, so you don't have to
+// do a new search.
+// return error code or ERR_OK
+//--------------------------------------------------
+int ddocStackPushElement(ElementEntry* pStack, xmlTextReaderPtr reader,
+ ElementEntry** pLastElem)
+{
+ ElementEntry* pElem;
+
+ RETURN_IF_NULL_PARAM(reader);
+ RETURN_IF_NULL_PARAM(pStack);
+ pElem = ddocStackFindEnd(pStack);
+ if(pElem->tag && !pElem->pNext) { // check if this entry is used
+ pElem->pNext = (ElementEntry*)malloc(sizeof(ElementEntry));
+ if(!pElem)
+ SET_LAST_ERROR_RETURN_CODE(ERR_BAD_ALLOC);
+ memset(pElem->pNext, 0, sizeof(ElementEntry));
+ pElem = (ElementEntry*)pElem->pNext;
+ }
+ if(!pElem)
+ return ERR_NULL_POINTER;
+ pElem->tag = xmlTextReaderLocalName(reader);
+ pElem->prefix = xmlTextReaderPrefix(reader);
+ pElem->nsUri = xmlTextReaderNamespaceUri(reader);
+ // atributes
+ pElem->id = xmlTextReaderGetAttribute(reader, (const xmlChar*)"Id");
+ pElem->uri = xmlTextReaderGetAttribute(reader, (const xmlChar*)"URI");
+ pElem->content = xmlTextReaderGetAttribute(reader, (const xmlChar*)"ContentType");
+ if(pLastElem) // this may be NULL if users doesn't want the last elem.
+ *pLastElem = pElem;
+ return ERR_OK;
+}
+
+//--------------------------------------------------
+// Push a new element info onto stack
+// tagName - elements tag name, Possibly with ns-prefix
+// atts - array of atributa names and values
+// pStack - address of stack begin. This one elemnt
+// must exist, but might be initially empty
+// pLastElem - address for new elements pointer.
+// If not NULL then will be used to return the
+// newly allocated elemnt, so you don't have to
+// do a new search.
+// return error code or ERR_OK
+//--------------------------------------------------
+int ddocStackPushElementSAX(ElementEntry* pStack, const xmlChar* tagName,
+ const xmlChar** atts, ElementEntry** pLastElem)
+{
+ ElementEntry* pElem;
+ char *p1, *p2;
+ xmlChar *n, *v;
+ int i;
+
+ ddocDebug(5, "ddocStackPushElementSAX", "tag: %s", (char*)tagName);
+ RETURN_IF_NULL_PARAM(tagName)
+ RETURN_IF_NULL_PARAM(pStack)
+ pElem = ddocStackFindEnd(pStack);
+ if(pElem->tag && !pElem->pNext) { // check if this entry is used
+ pElem->pNext = (ElementEntry*)malloc(sizeof(ElementEntry));
+ if(!pElem)
+ SET_LAST_ERROR_RETURN_CODE(ERR_BAD_ALLOC);
+ memset(pElem->pNext, 0, sizeof(ElementEntry));
+ pElem = (ElementEntry*)pElem->pNext;
+ }
+ if(!pElem)
+ return ERR_NULL_POINTER;
+ p1 = (char*)strdup((char*)tagName);
+ if(!p1)
+ SET_LAST_ERROR_RETURN_CODE(ERR_BAD_ALLOC)
+ // check for ns-prefix
+ p2 = strchr(p1, ':');
+ if(p2) {
+ *p2 = 0;
+ p2++;
+ pElem->prefix = xmlStrdup((xmlChar*)p1);
+ if(!pElem->prefix) {
+ free(p1);
+ SET_LAST_ERROR_RETURN_CODE(ERR_BAD_ALLOC);
+ }
+ pElem->tag = xmlStrdup((const xmlChar*)p2);
+ }
+ else
+ pElem->tag = xmlStrdup((const xmlChar*)p1);
+ free(p1);
+ if(!pElem->tag)
+ SET_LAST_ERROR_RETURN_CODE(ERR_BAD_ALLOC);
+ for (i = 0; (atts != NULL) && (atts[i] != NULL); i += 2) {
+ n = (xmlChar*)atts[i];
+ v = (xmlChar*)atts[i+1];
+ if(n && !strncmp((char*)n, "xmlns", 5) && v)
+ pElem->nsUri = xmlStrdup((xmlChar*)v);
+ if(n && !strncmp((char*)n, "Id", 2) && v)
+ pElem->id = xmlStrdup((xmlChar*)v);
+ if(n && !strncmp((char*)n, "URI", 3) && v)
+ pElem->uri = xmlStrdup((xmlChar*)v);
+ if(n && !strncmp((char*)n, "ContentType", 11) && v)
+ pElem->content = xmlStrdup((xmlChar*)v);
+ }
+ if(pLastElem) // this may be NULL if users doesn't want the last elem.
+ *pLastElem = pElem;
+ return ERR_OK;
+}
+
+//--------------------------------------------------
+// Pop the last element from the stack
+// pStack - address of stack begin. This one elemnt
+// must exist, and will never be deleted.
+// bCleanup - flag: 1=cleanup the whole stack, 0=just the last element
+// return error code or ERR_OK
+// pLastElem - address for new elements pointer.
+// If not NULL then will be used to return the
+// last element on stack.
+//--------------------------------------------------
+int ddocStackPopElement(ElementEntry* pStack, int bCleanup,
+ ElementEntry** pLastElem)
+{
+ ElementEntry *pElem = 0, *pOldElem = 0;
+
+ RETURN_IF_NULL_PARAM(pStack);
+ do {
+ pOldElem = pElem = pStack;
+ while(pElem->pNext) {
+ pOldElem = pElem;
+ pElem = (ElementEntry *)pElem->pNext;
+ }
+ if(pElem && pElem != pStack) {
+ ddocDebug(5, "ddocStackPopElement", "Pop: %s, cleanup: %d", pElem->tag, bCleanup);
+ xmlFree(pElem->tag);
+ pElem->tag = 0;
+ xmlFree(pElem->prefix);
+ pElem->prefix = 0;
+ xmlFree(pElem->nsUri);
+ pElem->nsUri = 0;
+ xmlFree(pElem->id);
+ pElem->id = 0;
+ xmlFree(pElem->uri);
+ pElem->uri = 0;
+ xmlFree(pElem->content);
+ pElem->content = 0;
+ free(pElem);
+ pElem = 0; // mark freed
+ pOldElem->pNext = 0;
+ if(!bCleanup)
+ break; // remove just the last one?
+ }
+ } while(pElem && pElem != pStack);
+ if(bCleanup) {
+ // now free up also the final first elements
+ // dynamically allocated part
+ xmlFree(pStack->tag);
+ pStack->tag = 0;
+ xmlFree(pStack->prefix);
+ pStack->prefix = 0;
+ xmlFree(pStack->nsUri);
+ pStack->nsUri = 0;
+ xmlFree(pStack->id);
+ pStack->id = 0;
+ xmlFree(pStack->uri);
+ pStack->uri = 0;
+ xmlFree(pStack->content);
+ pStack->content = 0;
+ pStack->pNext = 0;
+ }
+ if(pLastElem && pElem) // this may be NULL if users doesn't want the last elem.
+ *pLastElem = pElem;
+ return ERR_OK;
+}
+
+
+//--------------------------------------------------
+// Retrieve the current/last/stack top elements tag (localname)
+// pStack - address of stack begin.
+//--------------------------------------------------
+const xmlChar* ddocStackCurrentTag(ElementEntry* pStack)
+{
+ ElementEntry* pElem = 0;
+ const xmlChar* pTag = 0;
+
+ if(pStack) {
+ pElem = ddocStackFindEnd(pStack);
+ if(pElem)
+ pTag = (const xmlChar*)pElem->tag;
+ }
+ return pTag;
+}
+
+//--------------------------------------------------
+// Retrieve the current/last/stack top elements ns prefix
+// pStack - address of stack begin.
+//--------------------------------------------------
+const xmlChar* ddocStackCurrentNsPrefix(ElementEntry* pStack)
+{
+ ElementEntry* pElem = 0;
+ const xmlChar* pPrefix = 0;
+
+ if(pStack) {
+ pElem = ddocStackFindEnd(pStack);
+ if(pElem)
+ pPrefix = (const xmlChar*)pElem->prefix;
+ }
+ return pPrefix;
+}
+
+
+//--------------------------------------------------
+// Retrieve the current/last/stack top elements ns prefix
+// pStack - address of stack begin.
+//--------------------------------------------------
+const xmlChar* ddocStackCurrentNsUri(ElementEntry* pStack)
+{
+ ElementEntry* pElem = 0;
+ const xmlChar* pUri = 0;
+
+ if(pStack) {
+ pElem = ddocStackFindEnd(pStack);
+ if(pElem)
+ pUri = (const xmlChar*)pElem->nsUri;
+ }
+ return pUri;
+}
+
+//--------------------------------------------------
+// Checks if there is a parent element with the given
+// localname on the stack.
+// pStack - address of stack begin.
+// return 1 if there is such a parent elem or 0 if not.
+//--------------------------------------------------
+int ddocStackHasParentWithName(ElementEntry* pStack,
+ const xmlChar* parentsName, ElementEntry* pCurrElem)
+{
+ int bFound = 0;
+ ElementEntry *pElem = pStack;
+
+ while(pElem && pElem != pCurrElem) {
+ if(pElem->tag && !xmlStrcmp(pElem->tag, parentsName)) {
+ bFound = 1;
+ break;
+ } else
+ pElem = (ElementEntry *)pElem->pNext;
+ }
+ return bFound;
+}
+
+//--------------------------------------------------
+// Checks if there is a parent element with the given
+// localname on the stack.
+// pStack - address of stack begin.
+// return 1 if there is such a parent elem or 0 if not.
+//--------------------------------------------------
+ElementEntry* ddocStackGetParentWithName(ElementEntry* pStack,
+ const xmlChar* parentsName, ElementEntry* pCurrElem)
+{
+ ElementEntry *pParent = 0;
+ ElementEntry *pElem = pStack;
+
+ while(pElem && pElem != pCurrElem) {
+ if(pElem->tag && !xmlStrcmp(pElem->tag, parentsName)) {
+ pParent = pElem;
+ break;
+ } else
+ pElem = (ElementEntry *)pElem->pNext;
+ }
+ return pParent;
+}
diff --git a/libdigidoc/DigiDocStack.h b/libdigidoc/DigiDocStack.h
new file mode 100644
index 0000000..89d573f
--- /dev/null
+++ b/libdigidoc/DigiDocStack.h
@@ -0,0 +1,137 @@
+#ifndef __DIGIDOC_STACK_H__
+#define __DIGIDOC_STACK_H__
+//==================================================
+// FILE: DigiDocStack.h
+// PROJECT: Digi Doc
+// DESCRIPTION: Digi Doc functions for simple stack
+// to keep track of xml parsing
+// AUTHOR: Veiko Sinivee, S|E|B IT Partner Estonia
+//==================================================
+// Copyright (C) AS Sertifitseerimiskeskus
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+// GNU Lesser General Public Licence is available at
+// http://www.gnu.org/copyleft/lesser.html
+//==========< HISTORY >=============================
+// 09.09.2004 Veiko Sinivee
+// Creation
+//==================================================
+
+#include <libxml/xmlreader.h>
+#include <libdigidoc/DigiDocDefs.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct ElementEntry_st {
+ xmlChar* tag; // xml elements tag
+ xmlChar* prefix; // namespace local prefix
+ xmlChar* nsUri; // namespace URI
+ // some important atributes
+ xmlChar* id; // attribute "Id"
+ xmlChar* uri; // attribute "URI"
+ xmlChar* content; // attribute "ContentType"
+ void* pNext; // next element in list/stack
+} ElementEntry;
+
+//--------------------------------------------------
+// Finds the last element on stack
+// reader - XML reader cursor to current node
+// pStack - address of stack begin. This one elemnt
+// must exist, but might be initially empty
+// return error code or ERR_OK
+//--------------------------------------------------
+ElementEntry* ddocStackFindEnd(ElementEntry* pStack);
+
+//--------------------------------------------------
+// Push a new element info onto stack
+// reader - XML reader cursor to current node
+// pStack - address of stack begin. This one elemnt
+// must exist, but might be initially empty
+// pLastElem - address for new elements pointer.
+// If not NULL then will be used to return the
+// newly allocated elemnt, so you don't have to
+// do a new search.
+// return error code or ERR_OK
+//--------------------------------------------------
+int ddocStackPushElement(ElementEntry* pStack, xmlTextReaderPtr reader,
+ ElementEntry** pLastElem);
+
+//--------------------------------------------------
+// Push a new element info onto stack
+// tagName - elements tag name, Possibly with ns-prefix
+// atts - array of atributa names and values
+// pStack - address of stack begin. This one elemnt
+// must exist, but might be initially empty
+// pLastElem - address for new elements pointer.
+// If not NULL then will be used to return the
+// newly allocated elemnt, so you don't have to
+// do a new search.
+// return error code or ERR_OK
+//--------------------------------------------------
+int ddocStackPushElementSAX(ElementEntry* pStack, const xmlChar* tagName,
+ const xmlChar** atts, ElementEntry** pLastElem);
+
+//--------------------------------------------------
+// Pop the last element from the stack
+// pStack - address of stack begin. This one elemnt
+// must exist, and will never be deleted.
+// bCleanup - flag: 1=cleanup the whole stack, 0=just the last element
+// return error code or ERR_OK
+// pLastElem - address for new elements pointer.
+// If not NULL then will be used to return the
+// last element on stack.
+//--------------------------------------------------
+int ddocStackPopElement(ElementEntry* pStack, int bCleanup,
+ ElementEntry** pLastElem);
+
+//--------------------------------------------------
+// Retrieve the current/last/stack top elements tag (localname)
+// pStack - address of stack begin.
+//--------------------------------------------------
+const xmlChar* ddocStackCurrentTag(ElementEntry* pStack);
+
+//--------------------------------------------------
+// Retrieve the current/last/stack top elements ns prefix
+// pStack - address of stack begin.
+//--------------------------------------------------
+const xmlChar* ddocStackCurrentNsPrefix(ElementEntry* pStack);
+
+//--------------------------------------------------
+// Retrieve the current/last/stack top elements ns prefix
+// pStack - address of stack begin.
+//--------------------------------------------------
+const xmlChar* ddocStackCurrentNsUri(ElementEntry* pStack);
+
+//--------------------------------------------------
+// Checks if there is a parent element with the given
+// localname on the stack.
+// pStack - address of stack begin.
+// return 1 if there is such a parent elem or 0 if not.
+//--------------------------------------------------
+int ddocStackHasParentWithName(ElementEntry* pStack,
+ const xmlChar* parentsName, ElementEntry* pCurrElem);
+
+//--------------------------------------------------
+// Checks if there is a parent element with the given
+// localname on the stack.
+// pStack - address of stack begin.
+// return 1 if there is such a parent elem or 0 if not.
+//--------------------------------------------------
+ElementEntry* ddocStackGetParentWithName(ElementEntry* pStack,
+ const xmlChar* parentsName, ElementEntry* pCurrElem);
+
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // __DIGIDOC_STACK_H__
diff --git a/libdigidoc/DigiDocVerify.c b/libdigidoc/DigiDocVerify.c
new file mode 100644
index 0000000..237e285
--- /dev/null
+++ b/libdigidoc/DigiDocVerify.c
@@ -0,0 +1,1972 @@
+//==================================================
+// FILE: DigiDocVerify.c
+// PROJECT: Digi Doc
+// DESCRIPTION: DigiDoc verification routines
+// AUTHOR: Veiko Sinivee, S|E|B IT Partner Estonia
+//==================================================
+// Copyright (C) AS Sertifitseerimiskeskus
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+// GNU Lesser General Public Licence is available at
+// http://www.gnu.org/copyleft/lesser.html
+//==========< HISTORY >=============================
+// 26.04.2006 Veiko Sinivee
+// Creation
+//==================================================
+
+#include "DigiDocVerify.h"
+#include "DigiDocError.h"
+#include "DigiDocLib.h"
+#include "DigiDocDebug.h"
+#include "DigiDocConvert.h"
+#include "DigiDocError.h"
+#include "DigiDocCert.h"
+#include "DigiDocGen.h"
+#include "DigiDocObj.h"
+
+
+#include <openssl/sha.h>
+#ifdef WITH_ECDSA
+ #include <openssl/ecdsa.h>
+#endif
+#include <openssl/rsa.h>
+#include <openssl/evp.h>
+#include <openssl/objects.h>
+#include <openssl/x509.h>
+#include <openssl/x509v3.h>
+#include <openssl/err.h>
+#include <openssl/pem.h>
+#include <openssl/ssl.h>
+#include <openssl/ocsp.h>
+#include <openssl/pkcs12.h>
+#include <openssl/rand.h>
+
+//--------------------< ddoc structure def >-----------------------
+
+const XmlElemDef eTransform = {"Transform", 'Y', NULL}; /* 1.0 */
+const XmlElemDef* eTransformsCh[] = {&eTransform, NULL}; /* 1.0 */
+const XmlElemDef eTransforms = {"Transforms", 'Y', (void**)&eTransformsCh}; /* 1.0 */
+
+const XmlElemDef eDigestMethod = {"DigestMethod", 'N', NULL};
+const XmlElemDef eDigestValue = {"DigestValue", 'N', NULL};
+const XmlElemDef* eRefCh[] = {&eDigestMethod, &eDigestValue, &eTransforms, NULL};
+const XmlElemDef eReference = {"Reference", 'Y', (void**)&eRefCh};
+const XmlElemDef eSignatureMethod = {"SignatureMethod", 'N', NULL};
+const XmlElemDef eCanonicalizationMethod = {"CanonicalizationMethod", 'N', NULL};
+const XmlElemDef* eSigInfoCh[] = {&eCanonicalizationMethod, &eSignatureMethod, &eReference, NULL};
+const XmlElemDef eSigInfo = {"SignedInfo", 'N', (void**)&eSigInfoCh};
+const XmlElemDef eSigVal = {"SignatureValue", 'N', NULL};
+const XmlElemDef eModulus = {"Modulus", 'N', NULL};
+const XmlElemDef eExponent = {"Exponent", 'N', NULL};
+const XmlElemDef* eRSAKeyValueCh[] = {&eModulus, &eExponent, NULL};
+const XmlElemDef eRSAKeyValue = {"RSAKeyValue", 'N', (void**)&eRSAKeyValueCh};
+const XmlElemDef* eKeyValueCh[] = {&eRSAKeyValue};
+const XmlElemDef eKeyValue = {"KeyValue", 'N', (void**)&eKeyValueCh};
+const XmlElemDef eX509Certificate = {"X509Certificate", 'N', NULL};
+const XmlElemDef* eX509DataCh[] = {&eX509Certificate, NULL};
+const XmlElemDef eX509Data = {"X509Data", 'N', (void**)&eX509DataCh};
+const XmlElemDef* eKeyInfoCh[] = {&eKeyValue,&eX509Data, NULL};
+const XmlElemDef eKeyInfo = {"KeyInfo", 'N', (void**)&eKeyInfoCh};
+
+
+const XmlElemDef eEncapsulatedOCSPValue = {"EncapsulatedOCSPValue", 'Y', NULL};
+const XmlElemDef* eOCSPValuesCh[] = {&eEncapsulatedOCSPValue, NULL};
+const XmlElemDef eOCSPValues = {"OCSPValues", 'N', (void**)&eOCSPValuesCh};
+const XmlElemDef* eRevocationValuesCh[] = {&eOCSPValues, &eEncapsulatedOCSPValue, NULL};
+const XmlElemDef eRevocationValues = {"RevocationValues", 'N', (void**)&eRevocationValuesCh};
+const XmlElemDef eEncapsulatedX509Certificate = {"EncapsulatedX509Certificate", 'Y', NULL};
+const XmlElemDef* eCertificateValuesCh[] = {&eEncapsulatedX509Certificate, NULL};
+const XmlElemDef eCertificateValues = {"CertificateValues", 'N', (void**)&eCertificateValuesCh};
+const XmlElemDef eResponderID = {"ResponderID", 'N', NULL};
+const XmlElemDef eProducedAt = {"ProducedAt", 'N', NULL};
+const XmlElemDef* eOCSPIdentifierCh[] = {&eResponderID,&eProducedAt, NULL};
+const XmlElemDef eOCSPIdentifier = {"OCSPIdentifier", 'N', (void**)&eOCSPIdentifierCh};
+const XmlElemDef* eDigestAlgAndValueCh[] = {&eDigestMethod,&eDigestValue, NULL};
+const XmlElemDef eDigestAlgAndValue = {"DigestAlgAndValue", 'N', (void**)&eDigestAlgAndValueCh};
+const XmlElemDef* eOCSPRefCh[] = {&eOCSPIdentifier,&eDigestAlgAndValue, NULL};
+const XmlElemDef eOCSPRef = {"OCSPRef", 'Y', (void**)&eOCSPRefCh};
+const XmlElemDef* eOCSPRefsCh[] = {&eOCSPRef, NULL};
+const XmlElemDef eOCSPRefs = {"OCSPRefs", 'N', (void**)&eOCSPRefsCh};
+const XmlElemDef* eCompleteRevocationRefsCh[] = {&eOCSPRefs, NULL};
+const XmlElemDef eCompleteRevocationRefs = {"CompleteRevocationRefs", 'N', (void**)&eCompleteRevocationRefsCh};
+//
+const XmlElemDef eX509IssuerName = {"X509IssuerName", 'N', NULL};
+const XmlElemDef eX509SerialNumber = {"X509SerialNumber", 'N', NULL};
+const XmlElemDef* eIssuerSerialCh[] = {&eX509IssuerName,&eX509SerialNumber, NULL};
+const XmlElemDef eIssuerSerial = {"IssuerSerial", 'N', (void**)&eIssuerSerialCh};
+const XmlElemDef* eCertDigestCh[] = {&eDigestMethod,&eDigestValue, NULL};
+const XmlElemDef eCertDigest = {"CertDigest", 'N', (void**)&eCertDigestCh};
+const XmlElemDef* eCertCh[] = {&eCertDigest,&eIssuerSerial, NULL};
+const XmlElemDef eCert = {"Cert", 'Y', (void**)&eCertCh};
+const XmlElemDef* eCertRefsCh[] = {&eCert, NULL};
+const XmlElemDef eCertRefs = {"CertRefs", 'N', (void**)&eCertRefsCh};
+const XmlElemDef* eCompleteCertificateRefsCh[] = {&eCertRefs, &eCert, NULL };// 1.0
+const XmlElemDef eCompleteCertificateRefs = {"CompleteCertificateRefs", 'N', (void**)&eCompleteCertificateRefsCh};
+const XmlElemDef* eUnsignedSignaturePropertiesCh[] = {&eCompleteCertificateRefs,&eCompleteRevocationRefs,&eCertificateValues,&eRevocationValues, NULL};
+const XmlElemDef eUnsignedSignatureProperties = {"UnsignedSignatureProperties", 'N', (void**)&eUnsignedSignaturePropertiesCh};
+const XmlElemDef* eUnsignedPropertiesCh[] = {&eUnsignedSignatureProperties, NULL};
+const XmlElemDef eUnsignedProperties = {"UnsignedProperties", 'N', (void**)&eUnsignedPropertiesCh};
+
+
+const XmlElemDef* eSigningCertificateCh[] = {&eCert, NULL};
+const XmlElemDef eSigningCertificate = {"SigningCertificate", 'N', (void**)&eSigningCertificateCh};
+const XmlElemDef eSigningTime = {"SigningTime", 'N', NULL};
+const XmlElemDef eSignaturePolicyImplied = {"SignaturePolicyImplied", 'N', NULL};
+const XmlElemDef eCity = {"City", 'N', NULL};
+const XmlElemDef eStateOrProvince = {"StateOrProvince", 'N', NULL};
+const XmlElemDef ePostalCode = {"PostalCode", 'N', NULL};
+const XmlElemDef eCountryName = {"CountryName", 'N', NULL};
+const XmlElemDef* eSignatureProductionPlaceCh[] = {&eCity,&eStateOrProvince,&ePostalCode,&eCountryName, NULL};
+const XmlElemDef eSignatureProductionPlace = {"SignatureProductionPlace", 'N', (void**)&eSignatureProductionPlaceCh};
+const XmlElemDef eClaimedRole = {"ClaimedRole", 'Y', NULL};
+const XmlElemDef* eClaimedRolesCh[] = {&eClaimedRole, NULL};
+const XmlElemDef eClaimedRoles = {"ClaimedRoles", 'N', (void**)&eClaimedRolesCh};
+const XmlElemDef* eSignerRoleCh[] = {&eClaimedRoles, NULL};
+const XmlElemDef eSignerRole = {"SignerRole", 'N', (void**)&eSignerRoleCh};
+
+const XmlElemDef* eSignaturePolicyIdentifierCh[] = {&eSignaturePolicyImplied, NULL};
+const XmlElemDef eSignaturePolicyIdentifier = {"SignaturePolicyIdentifier", 'N', (void**)&eSignaturePolicyIdentifierCh};
+
+
+const XmlElemDef* eSignedSignaturePropertiesCh[] = {&eSigningTime,&eSigningCertificate,&eSignaturePolicyIdentifier,&eSignatureProductionPlace,&eSignerRole, NULL};
+const XmlElemDef eSignedSignatureProperties = {"SignedSignatureProperties", 'N', (void**)&eSignedSignaturePropertiesCh};
+const XmlElemDef eSignedDataObjectProperties = {"SignedDataObjectProperties", 'N', NULL};
+const XmlElemDef* eSignedPropertiesCh[] = {&eSignedSignatureProperties,&eSignedDataObjectProperties, NULL};
+const XmlElemDef eSignedProperties = {"SignedProperties", 'N', (void**)&eSignedPropertiesCh};
+
+const XmlElemDef* eQualifyingPropertiesCh[] = {&eSignedProperties,&eUnsignedProperties, NULL};
+const XmlElemDef eQualifyingProperties = {"QualifyingProperties", 'N', (void**)&eQualifyingPropertiesCh};
+
+const XmlElemDef* eObjectCh[] = {&eQualifyingProperties, NULL};
+const XmlElemDef eObject = {"Object", 'N', (void**)&eObjectCh};
+const XmlElemDef* eSignatureCh[] = {&eSigInfo,&eSigVal,&eKeyInfo,&eObject, NULL};
+const XmlElemDef eSignature = {"Signature", 'Y', (void**)&eSignatureCh};
+const XmlElemDef eDataFile = {"DataFile", 'Y', NULL};
+const XmlElemDef* eSigDocCh[] = {&eDataFile, &eSignature, NULL};
+const XmlElemDef eSignedDoc = {"SignedDoc", 'N', (void**)& eSigDocCh };
+
+//--------------------------------------------------
+
+int XmlElemInfo_new(XmlElemInfo **ppXi, const char* id, const char* tag)
+{
+ XmlElemInfo* pXi = NULL;
+
+ //RETURN_IF_NULL_PARAM(id);
+ RETURN_IF_NULL_PARAM(tag);
+ ddocDebug(5, "XmlElemInfo_new", "tag: %s id: %s", (tag ? tag : "NULL"), (id ? id : "NULL"));
+ pXi = (XmlElemInfo*)malloc(sizeof(XmlElemInfo));
+ RETURN_IF_BAD_ALLOC(pXi);
+ memset(pXi, 0, sizeof(XmlElemInfo));
+ if(id)
+ setString(&(pXi->szId), id, -1);
+ if(tag)
+ setString(&(pXi->szTag), tag, -1);
+ *ppXi = pXi;
+ return ERR_OK;
+}
+
+
+void XmlElemInfo_free(XmlElemInfo* pXi)
+{
+ XmlElemInfo** p = NULL;
+
+ RETURN_VOID_IF_NULL(pXi);
+ ddocDebug(5, "XmlElemInfo_free", "tag: %s id: %s children: %s", (pXi->szTag ? pXi->szTag : "NULL"), (pXi->szId ? pXi->szId : "NULL"), (pXi->pChildren ? "Y" : "N"));
+ for(p = (XmlElemInfo**)pXi->pChildren; p && *p; p++)
+ XmlElemInfo_free(*p);
+ if(pXi->pChildren)
+ free(pXi->pChildren);
+ if(pXi->szId)
+ free(pXi->szId);
+ if(pXi->szTag)
+ free(pXi->szTag);
+ if(pXi)
+ free(pXi);
+}
+
+int XmlElemInfo_countChildren(XmlElemInfo* pXi)
+{
+ XmlElemInfo** p = NULL;
+ int n = 0;
+
+ if(pXi && pXi->pChildren) {
+ for(p = (XmlElemInfo**)pXi->pChildren; p && *p; p++)
+ n++;
+ }
+ return n;
+}
+
+int XmlElemInfo_addChild(XmlElemInfo* pParent, XmlElemInfo* pChild)
+{
+ int n = 0;
+
+ RETURN_IF_NULL(pParent);
+ RETURN_IF_NULL(pChild);
+ n = XmlElemInfo_countChildren(pParent);
+ pParent->pChildren = (void**)realloc(pParent->pChildren, sizeof(XmlElemInfo*) * (n + 2));
+ ((XmlElemInfo**)pParent->pChildren)[n] = pChild;
+ pChild->pParent = pParent;
+ ((XmlElemInfo**)pParent->pChildren)[n+1] = NULL;
+ return ERR_OK;
+}
+
+XmlElemInfo* XmlElemInfo_getRootElem(XmlElemInfo* pElem)
+{
+ if(pElem) {
+ if(!pElem->pParent)
+ return pElem;
+ else
+ return XmlElemInfo_getRootElem(pElem->pParent);
+ }
+ return NULL;
+}
+
+int XmlElemInfo_getLevel(XmlElemInfo* pElem)
+{
+ int n = 0;
+ XmlElemInfo* p = pElem;
+ while(p) {
+ n++;
+ p = p->pParent;
+ }
+ return n;
+}
+
+XmlElemInfo** XmlElemInfo_getPathElements(XmlElemInfo* pElem)
+{
+ XmlElemInfo *p = 0, **pp = 0;
+ int n = XmlElemInfo_getLevel(pElem);
+ if(n > 0) {
+ pp = (XmlElemInfo **)malloc(sizeof(XmlElemInfo *) * (n+1));
+ pp[n] = 0;
+ p = pElem;
+ while(p && n > 0) {
+ pp[n-1] = p;
+ n--;
+ p = p->pParent;
+ }
+ }
+ return pp;
+}
+
+
+int XmlElemInfo_getPath(XmlElemInfo* pElem, DigiDocMemBuf* pMbuf)
+{
+ int err = ERR_OK;
+ XmlElemInfo **pp1 = 0, **pp2 = 0;
+
+ RETURN_IF_NULL(pElem);
+ RETURN_IF_NULL(pMbuf);
+ pp2 = XmlElemInfo_getPathElements(pElem);
+ for(pp1 = pp2; pp1 && *pp1; pp1++) {
+ err = ddocMemAppendData(pMbuf, "/", -1);
+ err = ddocMemAppendData(pMbuf, (*pp1)->szTag, -1);
+ }
+ free(pp2);
+ return err;
+}
+
+XmlElemDef* XmlElemDef_findChildByTag(XmlElemDef* pElem, const char* tag)
+{
+ XmlElemDef **p = NULL, *pe = NULL;
+ if(pElem && pElem->szTag && tag && !strcmp(pElem->szTag, tag))
+ return pElem;
+ if(pElem && pElem->pChildren) {
+ for(p = (XmlElemDef**)pElem->pChildren; p && *p; p++) {
+ pe = XmlElemDef_findChildByTag(*p, tag);
+ if(pe) return pe;
+ }
+ }
+ return NULL;
+}
+
+XmlElemDef* XmlElemDef_findElemOrDirectChildByTag(XmlElemDef* pElem, const char* tag)
+{
+ XmlElemDef **p = NULL;
+ if(pElem && pElem->szTag && tag && !strcmp(pElem->szTag, tag))
+ return pElem;
+ if(pElem && pElem->pChildren) {
+ for(p = (XmlElemDef**)pElem->pChildren; p && *p; p++) {
+ if(p && (*p)->szTag && tag && !strcmp((*p)->szTag, tag))
+ return *p;
+ }
+ }
+ return NULL;
+}
+
+int XmlElemInfo_countChildrenWithTag(XmlElemInfo* pElem, const char* tag)
+{
+ int n = 0;
+ XmlElemInfo **p = NULL;
+ if(pElem && pElem->pChildren) {
+ for(p = (XmlElemInfo**)pElem->pChildren; p && *p; p++) {
+ if(p && (*p)->szTag && tag && !strcmp((*p)->szTag, tag))
+ n++;
+ }
+ }
+ return n;
+}
+
+int XmlElemDef_checkPath(XmlElemDef* pRoot, XmlElemInfo* pElem)
+{
+ DigiDocMemBuf mbuf;
+ XmlElemDef *p1 = pRoot, *p2 = 0;
+ XmlElemInfo **pp1 = 0, **pp2 = 0;
+ int err = ERR_OK;
+
+ mbuf.pMem = 0;
+ mbuf.nLen = 0;
+ XmlElemInfo_getPath(pElem, &mbuf);
+ ddocDebug(4, "XmlElemDef_checkPath", "Validate elem: %s path: %s", (pElem->szTag ? pElem->szTag : "NULL"), mbuf.pMem);
+ ddocMemBuf_free(&mbuf);
+ pp2 = XmlElemInfo_getPathElements(pElem);
+ for(pp1 = pp2; pp1 && *pp1 && p1; pp1++) {
+ p2 = XmlElemDef_findElemOrDirectChildByTag(p1, (*pp1)->szTag);
+ ddocDebug(4, "XmlElemDef_checkPath", "Current: %s find: %s found: %s", (p1->szTag ? p1->szTag : "NULL"), ((*pp1)->szTag ? (*pp1)->szTag : "NULL"), (p2 ? "OK" : "NULL"));
+ if(!p2) {
+ ddocDebug(1, "XmlElemDef_checkPath", "Did not find: %s under %s", ((*pp1)->szTag ? (*pp1)->szTag : "NULL"), (p1->szTag ? p1->szTag : "NULL"));
+ err = ERR_XML_VALIDATION;
+ }
+ p1 = p2;
+ }
+ free(pp2);
+
+ return err;
+}
+
+int validateElementPath(XmlElemInfo* pElem)
+{
+ XmlElemDef* pRoot = &eSignedDoc;
+ XmlElemDef* pCurr = NULL;
+ int err = ERR_OK, n;
+
+ ddocDebug(3, "validateElementPath", "Validate elem: %s root: %s",
+ (pElem->szTag ? pElem->szTag : "NULL"), (pRoot->szTag ? pRoot->szTag : "NULL"));
+ pCurr = XmlElemDef_findChildByTag(pRoot, pElem->szTag);
+ if(pCurr) {
+ ddocDebug(3, "validateElementPath", "Elem: %s exists", (pElem->szTag ? pElem->szTag : "NULL"));
+ err = XmlElemDef_checkPath(pRoot, pElem);
+ ddocDebug(3, "validateElementPath", "Elem: %s path rc: %d", (pElem->szTag ? pElem->szTag : "NULL"), err);
+ if(err) SET_LAST_ERROR(err);
+ if(!err && pElem->pParent) {
+ XmlElemInfo* pParent = (XmlElemInfo*)pElem->pParent;
+ n = XmlElemInfo_countChildrenWithTag(pParent, pElem->szTag);
+ ddocDebug(3, "validateElementPath", "Parent: %s elems: %s count: %d multiple: %c",
+ (pParent->szTag ? pParent->szTag : "NULL"), (pElem->szTag ? pElem->szTag : "NULL"), n, pCurr->bMultiple);
+ if(n > 1 && pCurr->bMultiple != 'Y') {
+ ddocDebug(3, "validateElementPath", "Found: %d elems: %s under: %s but multiple not allowed",
+ n, (pElem->szTag ? pElem->szTag : "NULL"), (pParent->szTag ? pParent->szTag : "NULL"));
+ err = ERR_XML_VALIDATION;
+ SET_LAST_ERROR(err);
+ }
+ }
+ } else {
+ ddocDebug(1, "validateElementPath", "Elem: %s does not exist", (pElem->szTag ? pElem->szTag : "NULL"));
+ err = ERR_DIGIDOC_PARSE;
+ }
+
+ return err;
+}
+
+
+//--------------------------------------------------
+
+
+//--------------------------------------------------
+// Verifies files SHA1-RSA signature
+// szFileName - file name
+// nDigestType - digest type. Supports only SHA1 (0)
+// pSigBuf - buffer to store the signature
+// nSigLen - buffer size, must be at least 128
+// will be updated by actual signature length
+// certfile - name of the certificate file
+// returns error code or ERR_OK for success
+//--------------------------------------------------
+EXP_OPTION int verifyFileSignature(const char* szFileName, int nDigestType,
+ byte* pSigBuf, int nSigLen,
+ const char *certfile)
+{
+ int err = ERR_OK;
+ EVP_MD_CTX ctx;
+ unsigned char buf[FILE_BUFSIZE];
+ int i;
+ FILE *f;
+ EVP_PKEY* pkey = NULL;
+
+ RETURN_IF_NULL_PARAM(szFileName);
+ RETURN_IF_NULL_PARAM(pSigBuf);
+ RETURN_IF_NULL_PARAM(certfile);
+
+ if(nDigestType == DIGEST_SHA1) {
+ if((err = ReadPublicKey(&pkey, certfile)) == ERR_OK) {
+ if((f = fopen(szFileName,"rb")) != NULL) {
+ EVP_VerifyInit(&ctx, EVP_sha1());
+ for (;;) {
+ i = fread(buf, sizeof(char), FILE_BUFSIZE, f);
+ if (i <= 0) break;
+ EVP_VerifyUpdate (&ctx, buf, (unsigned long)i);
+ }
+ err = EVP_VerifyFinal(&ctx, pSigBuf, nSigLen, pkey);
+ if(err == ERR_LIB_NONE)
+ err = ERR_OK;
+ fclose(f);
+ EVP_PKEY_free(pkey);
+ } // if - fopen
+ else
+ err = ERR_FILE_READ;
+ }
+ else
+ err = ERR_CERT_READ;
+ }
+ else
+ err = ERR_UNSUPPORTED_DIGEST;
+
+ if (err != ERR_OK) SET_LAST_ERROR(err);
+ return err;
+}
+
+
+//--------------------------------------------------
+// Verifies files SHA1-RSA signature
+// szData - input data
+// dataLen - input data length
+// nDigestType - digest type
+// pSigBuf - buffer to store the signature
+// nSigLen - buffer size, must be at least 128
+// will be updated by actual signature length
+// cert - certificate data
+// returns error code or ERR_OK for success
+//--------------------------------------------------
+EXP_OPTION int verifySignature(const char* szData, unsigned long dataLen, int nDigestType,
+ byte* pSigBuf, int nSigLen, X509* cert)
+{
+ int err = ERR_OK;
+ EVP_MD_CTX ctx;
+ EVP_PKEY* pkey = NULL;
+
+ RETURN_IF_NULL_PARAM(szData);
+ RETURN_IF_NULL_PARAM(pSigBuf);
+ RETURN_IF_NULL_PARAM(cert);
+
+ if(nDigestType == DIGEST_SHA1) {
+ if((err = GetPublicKey(&pkey, cert)) == ERR_OK) {
+ checkErrors();
+ EVP_VerifyInit(&ctx, EVP_sha1());
+ checkErrors();
+ EVP_VerifyUpdate (&ctx, szData, dataLen);
+ checkErrors();
+ err = EVP_VerifyFinal(&ctx, pSigBuf, nSigLen, pkey);
+ if(err == ERR_LIB_NONE)
+ err = ERR_OK;
+ checkErrors();
+ EVP_PKEY_free(pkey);
+ checkErrors();
+ }
+ else
+ err = ERR_CERT_READ;
+ }
+ else
+ err = ERR_UNSUPPORTED_DIGEST;
+
+ if (err != ERR_OK) SET_LAST_ERROR(err);
+ return err;
+}
+
+//============================================================
+// Compares two byte arrays and returns 0 for OK.
+// doesn't record an error on error stack
+// dig1 - byte array 1
+// len1 - byte array 1 length
+// dig2 - byte array 2
+// len2 - byte array 2 length
+//============================================================
+EXP_OPTION int compareByteArraysNoErr(const byte* dig1, int len1, const byte* dig2, int len2)
+{
+ int i;
+
+ if(!dig1 || !dig2 || len1 != len2)
+ return -1;
+ for(i = 0; i < len1; i++) {
+ if(dig1[i] != dig2[i])
+ return -2;
+ }
+ return 0;
+}
+
+//byte sigvalasn1[] = { 48, 33, 48, 9, 6, 5, 43, 14, 3, 2, 26, 5, 0, 4, 20 };
+byte sigvalasn1[] = {
+ 0x30, 0x1f, 0x30, 0x07, 0x06,
+ 0x05, 0x2b, 0x0e, 0x03, 0x02,
+ 0x1a, 0x04, 0x14 };
+byte sigvalasn2[] = {
+ 0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2b,
+ 0x0e, 0x03, 0x02, 0x1a, 0x05, 0x00, 0x04, 0x14 };
+
+int verifySigValAsn1(byte* sigval, int len)
+{
+ if(!sigval ||
+ (compareByteArraysNoErr(sigval, len, sigvalasn1, sizeof(sigvalasn1)) &&
+ compareByteArraysNoErr(sigval, len, sigvalasn2, sizeof(sigvalasn2)))) {
+ ddocDebug(1, "verifySigValAsn1", "Invalid signature value asn.1 len: ", len);
+ SET_LAST_ERROR(ERR_SIGVAL_ASN1);
+ return ERR_SIGVAL_ASN1;
+ }
+ return ERR_OK;
+}
+
+//--------------------------------------------------
+// Verifies files SHA1-RSA signature (EstID specific!!!)
+// digest - digest data
+// dataLen - digest data length
+// nDigestType - digest type
+// pSigBuf - buffer to store the signature
+// nSigLen - buffer size, must be at least 128
+// will be updated by actual signature length
+// cert - certificate data
+// returns error code or ERR_OK for success
+//--------------------------------------------------
+EXP_OPTION int verifyEstIDSignature(const byte* digest, int digestLen, int nDigestType,
+ byte* pSigBuf, int nSigLen, X509* cert)
+{
+ int err = ERR_OK, nCheckSigValAsn1 = 1;
+ EVP_PKEY* pkey = 0;
+ byte buf2[DIGEST_LEN+2], buf3[500], buf4[200], buf5[200],buf256[DIGEST_LEN256+2];
+ int l2 = 0, l1;
+ //AM 11.02.09 ecdsa-sha1 support for LI
+#ifdef WITH_ECDSA
+ ECDSA_SIG *ecsig;
+#endif
+ RETURN_IF_NULL_PARAM(digest);
+ RETURN_IF_NULL_PARAM(pSigBuf);
+ RETURN_IF_NULL_PARAM(cert);
+ ddocDebug(3, "verifyEstIDSignature", "start");
+ if(nDigestType == DIGEST_SHA1) {
+ if((err = GetPublicKey(&pkey, cert)) == ERR_OK) {
+ l2 = sizeof(buf3);
+ memset(buf3, 0, sizeof(buf3));
+ ERR_clear_error();
+ //swapBytes(pSigBuf, nSigLen);
+#ifdef WITH_ECDSA
+ if(pkey->type==NID_X9_62_id_ecPublicKey){
+ ecsig = ECDSA_SIG_new();
+ ecsig->r = BN_new();
+ ecsig->s = BN_new();
+ if (!BN_bin2bn(pSigBuf, nSigLen/2,ecsig->r) || !BN_bin2bn(pSigBuf + nSigLen/2, nSigLen/2, ecsig->s)){
+ ECDSA_SIG_free(ecsig);
+ EVP_PKEY_free(pkey);
+ return ERR_COMPARE;
+ }
+ l2 = ECDSA_do_verify(digest, digestLen, ecsig, pkey->pkey.ec);
+ ECDSA_SIG_free(ecsig);
+ if (l2 == -1){
+ /* error */
+ err = ERR_COMPARE;
+ }
+ else if (l2 == 0){
+ /* incorrect signature */
+ err = ERR_COMPARE;
+ }
+ else { /* ret == 1 */
+ /* signature ok */
+ err = ERR_OK;
+ }
+ }else
+#endif
+ if(pkey->type==NID_rsaEncryption){
+ //clearErrors();
+ l2 = RSA_public_decrypt(nSigLen, pSigBuf, buf3, pkey->pkey.rsa, RSA_PKCS1_PADDING); //RSA_PKCS1_PADDING); //RSA_NO_PADDING);
+ checkErrors();
+ ddocDebug(3, "verifyEstIDSignature", "decryted sig-hash len: %d", l2);
+ // debug info
+ l1 = sizeof(buf4);
+ if(digestLen > 0) {
+ memset(buf4, 0, sizeof(buf4));
+ encode((const byte*)digest, digestLen, (byte*)buf4, &l1);
+ ddocDebug(3, "verifyEstIDSignature", "calculated hash: %s len: %d", buf4, digestLen);
+ }
+ l1 = sizeof(buf4);
+ if(l2 > 0) { // TODO: lisa asn.1 prefixi kontroll
+ memset(buf4, 0, sizeof(buf4));
+ encode((const byte*)buf3, l2, (byte*)buf4, &l1);
+ ddocDebug(3, "verifyEstIDSignature", "decrypted hash: %s len: %d", buf4, l2);
+ }
+ memset(buf2, 0, DIGEST_LEN);
+ checkErrors();
+ if(l2 > DIGEST_LEN) {
+ err = verifySigValAsn1(buf3, l2 - DIGEST_LEN);
+ memcpy(buf2, buf3 + l2 - DIGEST_LEN, DIGEST_LEN);
+ } else {
+ memcpy(buf2, buf3, DIGEST_LEN);
+ err = ERR_SIGVAL_ASN1;
+ SET_LAST_ERROR(err);
+ ddocDebug(1, "verifyEstIDSignature", "Invalid rsa-sha1 siganture length: %d", l2);
+ }
+ if(!err)
+ err = compareByteArrays(digest, digestLen, buf2, DIGEST_LEN);
+ //debug
+ l1 = sizeof(buf4);
+ encode((const byte*)digest, digestLen, (byte*)buf4, &l1);
+ l1 = sizeof(buf5);
+ encode((const byte*)buf2, DIGEST_LEN, (byte*)buf5, &l1);
+ ddocDebug(3, "verifyEstIDSignature", "comp-hash: %s sig-hash: %s, err: %d", buf4, buf5, err);
+ } else
+ err = ERR_UNSUPPORTED_SIGNATURE;
+
+ EVP_PKEY_free(pkey);
+ checkErrors();
+ }
+ //AM 23.04.08
+ } else if(nDigestType == DIGEST_SHA256) {
+ if((err = GetPublicKey(&pkey, cert)) == ERR_OK) {
+ l2 = sizeof(buf3);
+ memset(buf3, 0, sizeof(buf3));
+ ERR_clear_error();
+ //swapBytes(pSigBuf, nSigLen);
+ l2 = RSA_public_decrypt(nSigLen, pSigBuf, buf3, pkey->pkey.rsa, RSA_PKCS1_PADDING); //RSA_PKCS1_PADDING); //RSA_NO_PADDING);
+ checkErrors();
+ ddocDebug(3, "verifyEstIDSignature", "decryted sig-hash len: %d", l2);
+ // debug info
+ l1 = sizeof(buf4);
+ if(digestLen > 0) {
+ memset(buf4, 0, sizeof(buf4));
+ encode((const byte*)digest, digestLen, (byte*)buf4, &l1);
+ ddocDebug(3, "verifyEstIDSignature", "calculated hash: %s len: %d", buf4, digestLen);
+ }
+ l1 = sizeof(buf4);
+ if(l2 > 0) {
+ memset(buf4, 0, sizeof(buf4));
+ encode((const byte*)buf3, l2, (byte*)buf4, &l1);
+ ddocDebug(3, "verifyEstIDSignature", "decrypted hash: %s len: %d", buf4, l2);
+ }
+ memset(buf256, 0, DIGEST_LEN);
+ if(l2 > DIGEST_LEN)
+ memcpy(buf256, buf3 + l2 - DIGEST_LEN, DIGEST_LEN);
+ else
+ memcpy(buf256, buf3, DIGEST_LEN);
+ checkErrors();
+ //err = compareByteArrays(digest, digestLen, buf256, DIGEST_LEN256);
+ err = compareByteArrays(digest, DIGEST_LEN, buf256, DIGEST_LEN);
+ //debug
+ l1 = sizeof(buf4);
+ encode((const byte*)digest, digestLen, (byte*)buf4, &l1);
+ l1 = sizeof(buf5);
+ encode((const byte*)buf256, DIGEST_LEN256, (byte*)buf5, &l1);
+ ddocDebug(3, "verifyEstIDSignature", "comp-hash: %s sig-hash: %s, err: %d", buf4, buf5, err);
+
+ EVP_PKEY_free(pkey);
+ checkErrors();
+ }
+ else
+ err = ERR_CERT_READ;
+ }
+ else
+ err = ERR_UNSUPPORTED_DIGEST;
+
+ if (err != ERR_OK) SET_LAST_ERROR(err);
+ ddocDebug(3, "verifyEstIDSignature", "end");
+ return err;
+}
+
+
+//============================================================
+// Compares two byte arrays and returns 0 for OK
+// dig1 - byte array 1
+// len1 - byte array 1 length
+// dig2 - byte array 2
+// len2 - byte array 2 length
+//============================================================
+EXP_OPTION int compareByteArrays(const byte* dig1, int len1, const byte* dig2, int len2)
+{
+ int err = ERR_OK, i;
+
+ RETURN_IF_NULL_PARAM(dig1);
+ RETURN_IF_NULL_PARAM(dig2);
+ RETURN_IF_NOT(len1 == len2, ERR_COMPARE);
+ for(i = 0; i < len1; i++) {
+ if(dig1[i] != dig2[i]) {
+ err = ERR_COMPARE;
+ break;
+ }
+ }
+ return err;
+}
+
+//============================================================
+// Checks and records the knowledge if one signature had
+// missing xmlns problem
+// pSigDoc - signed doc data
+// returns 1 if at least one signature had this problem
+//============================================================
+EXP_OPTION int checkDdocWrongDigests(const SignedDoc* pSigDoc)
+{
+ int i, d, j, l, m, k, err = 0, e = 0;
+ SignatureInfo *pSigInfo = 0;
+ DocInfo *pDi = NULL;
+ DataFile *pDf = NULL;
+
+ RETURN_IF_NULL_PARAM(pSigDoc);
+ d = getCountOfSignatures(pSigDoc);
+ m = getCountOfDataFiles(pSigDoc);
+ //printf("checkDdocWrongDigests\n");
+ for(i = 0; i < d; i++) {
+ pSigInfo = getSignature(pSigDoc, i);
+ l = getCountOfDocInfos(pSigInfo);
+ for(j = 0; j < l; j++) {
+ pDi = getDocInfo(pSigInfo, j);
+ for(k = 0; k < m; k++) {
+ pDf = getDataFile(pSigDoc, k);
+ //printf("DI: %s DF: %s content: %s\n", pDi->szDocId, pDf->szId, pDf->szContentType);
+ if(!strcmp(pDi->szDocId, pDf->szId) &&
+ (!strcmp(pDf->szContentType, CONTENT_EMBEDDED) ||
+ !strcmp(pDf->szContentType, CONTENT_EMBEDDED_BASE64))) {
+ err = compareByteArrays(pDi->szDigest, pDi->nDigestLen,
+ (byte*)pDf->mbufDigest.pMem, pDf->mbufDigest.nLen);
+ if(err) { // check also the wrong digest
+ err = compareByteArrays(pDi->szDigest, pDi->nDigestLen,
+ (byte*)pDf->mbufWrongDigest.pMem, pDf->mbufWrongDigest.nLen);
+ if(!err) {
+ setString((char**)&(pDi->szDigestType), DIGEST_SHA1_WRONG, -1);
+ e = 1;
+ }
+ }
+ }
+ }
+ }
+ }
+ return e;
+}
+
+//============================================================
+// Verifies the digest of the given doc in this signature
+// pSigDoc - signed doc data
+// pSigInfo - signature info object
+// filename - file name for not embedded files
+// szDataFile - name of the digidoc file
+//============================================================
+// FIXME : Hard to understand the logic
+EXP_OPTION int verifySigDocDigest(const SignedDoc* pSigDoc, const SignatureInfo* pSigInfo,
+ const DocInfo* pDocInfo, const char* szDataFile)
+{
+ int err = ERR_OK;
+ int l1 = 0, l2 = 0;
+ DataFile *pDf = NULL ;
+ byte buf1[DIGEST_LEN+2], buf2[100], buf3[100], buf4[100];
+ char *attNames = NULL, *attValues = NULL, *pTmp1 = NULL, *pTmp2 = NULL;
+ //FILE *hFile;
+
+ RETURN_IF_NULL_PARAM(pSigInfo);
+ RETURN_IF_NULL_PARAM(pSigDoc);
+ RETURN_IF_NULL_PARAM(pDocInfo);
+ pDf = getDataFileWithId(pSigDoc, pDocInfo->szDocId);
+ RETURN_IF_NULL(pDf);
+ RETURN_IF_NULL(pDf->szContentType);
+ RETURN_IF_NULL(pDf->szDigestType);
+ RETURN_IF_NULL(pDocInfo->szDigestType);
+ // verify detached file signature
+ ddocDebug(3, "verifySigDocDigest", "SigDoc: %s DF: %s len1: %d len2: %d, ctype: %s",
+ pSigDoc->szFormatVer, pDf->szId, pDf->mbufDigest.nLen,
+ pDocInfo->nDigestLen, pDf->szContentType);
+ // the new digest calculation on the fly doesn't
+ // work for old 1.0 files
+ //AM 29.10.09
+ if(!strcmp(pDf->szContentType, CONTENT_EMBEDDED) &&
+ (!strcmp(pSigDoc->szFormatVer, SK_XML_1_VER) && !strcmp(pSigDoc->szFormat, SK_XML_1_NAME))) {
+ attNames = "Id";
+ attValues = pDf->szId;
+ err = readTagContents(&pTmp2, szDataFile, "DataFile", 1,
+ (const char**)&attNames, (const char**)&attValues, 0);
+ if(err == ERR_OK) {
+ pTmp1 = pTmp2;
+ //skip leading newlines
+ while(*pTmp1 && *pTmp1 != '<') pTmp1++;
+ l1 = sizeof(buf1);
+ err = calculateDigest((const byte*)pTmp1, strlen(pTmp1),
+ DIGEST_SHA1, (byte*)buf1, &l1);
+ if(err == ERR_OK) {
+ err = ddocDataFile_SetDigestValue(pDf, (const char*)buf1, DIGEST_LEN);
+ encode((const byte*)pDf->mbufDigest.pMem, pDf->mbufDigest.nLen, (byte*)buf3, &l2);
+ ddocDebug(3, "verifySigDocDigest", "DF: %s calculated digest: %s",
+ pDf->szId, buf3);
+ }
+ free(pTmp2);
+ }
+ }
+ if(!strcmp(pDf->szContentType, CONTENT_EMBEDDED) ||
+ !strcmp(pDf->szContentType, CONTENT_EMBEDDED_BASE64)){
+ buf2[0] = buf3[0] = buf4[0] = 0;
+ l2 = sizeof(buf2);
+ if(pDocInfo->szDigest)
+ bin2hex((const byte*)pDocInfo->szDigest, pDocInfo->nDigestLen, (char*)buf2, &l2);
+ l2 = sizeof(buf3);
+ if(pDf->mbufDigest.pMem)
+ bin2hex((const byte*)pDf->mbufDigest.pMem, pDf->mbufDigest.nLen, (char*)buf3, &l2);
+ l2 = sizeof(buf4);
+ if(pDf->mbufWrongDigest.pMem)
+ bin2hex((const byte*)pDf->mbufWrongDigest.pMem, pDf->mbufWrongDigest.nLen, (char*)buf4, &l2);
+
+ ddocDebug(3, "verifySigDocDigest", "DF: %s len1: %d len2: %d, type1: %s type2: %s, digest1: %s digest2: %s digest3: %s",
+ pDf->szId, pDf->mbufDigest.nLen, pDocInfo->nDigestLen, pDocInfo->szDigestType, pDf->szDigestType, buf2, buf3, buf4);
+ if(strcmp(pDocInfo->szDigestType, pDf->szDigestType))
+ err = ERR_DOC_DIGEST;
+ else
+ err = compareByteArrays(pDocInfo->szDigest, pDocInfo->nDigestLen,
+ (byte*)pDf->mbufDigest.pMem, pDf->mbufDigest.nLen);
+ if(err) { // check also the wrong digest
+ err = compareByteArrays(pDocInfo->szDigest, pDocInfo->nDigestLen,
+ (byte*)pDf->mbufWrongDigest.pMem, pDf->mbufWrongDigest.nLen);
+ ddocDebug(3, "verifySigDocDigest", "wrong doc dig verify: %d", err);
+ if(!err) {
+ setString((char**)&(pDocInfo->szDigestType), DIGEST_SHA1_WRONG, -1);
+ err = ERR_DF_WRONG_DIG;
+ }
+ }
+ if(err != ERR_OK && err != ERR_DF_WRONG_DIG)
+ err = ERR_DOC_DIGEST;
+ }
+
+ if (err != ERR_OK) SET_LAST_ERROR(err);
+ ddocDebug(3, "verifySigDocDigest", "SigDoc DF: %s err: %d",
+ pDf->szId, err);
+
+ return err;
+}
+
+//============================================================
+// Verifies the mime digest of the given doc in this signature
+// pSigDoc - signed doc data
+// pSigInfo - signature info object
+// filename - file name for not embedded files
+//============================================================
+EXP_OPTION int verifySigDocMimeDigest(const SignedDoc* pSigDoc, const SignatureInfo* pSigInfo,
+ const DocInfo* pDocInfo, const char* szFileName)
+{
+ int err = ERR_OK;
+ int l1;
+ DataFile* pDf;
+ byte buf1[DIGEST_LEN+2];
+
+ RETURN_IF_NULL_PARAM(pSigInfo);
+ RETURN_IF_NULL_PARAM(pSigDoc);
+ RETURN_IF_NULL_PARAM(pDocInfo);
+ pDf = getDataFileWithId(pSigDoc, pDocInfo->szDocId);
+ RETURN_IF_NULL(pDf);
+ // we check mime digest only in ver 1.0
+ if(!strcmp(pSigDoc->szFormatVer, SK_XML_1_VER) && !strcmp(pSigDoc->szFormat, SK_XML_1_NAME)) {
+ l1 = sizeof(buf1);
+ err = calculateDigest((const byte*)pDf->szMimeType, strlen(pDf->szMimeType),
+ DIGEST_SHA1, buf1, &l1);
+ RETURN_IF_NOT(err == ERR_OK, err);
+ err = compareByteArrays(pDocInfo->szMimeDigest, pDocInfo->nMimeDigestLen,
+ buf1, l1);
+ if(err != ERR_OK)
+ err = ERR_MIME_DIGEST;
+ }
+ if (err != ERR_OK) SET_LAST_ERROR(err);
+ return err;
+}
+
+
+//============================================================
+// Verifies the SignedProperties digest
+// pSigInfo - signature info object
+// from original file and use it for hash function.
+// This is usefull if the file has been generated by
+// another library and possibly formats these elements
+// differently.
+//============================================================
+EXP_OPTION int verifySigDocSigPropDigest(const SignatureInfo* pSigInfo)
+{
+ int err = ERR_OK;
+
+ RETURN_IF_NULL_PARAM(pSigInfo);
+ err = ddocCompareDigestValues(pSigInfo->pSigPropDigest, pSigInfo->pSigPropRealDigest);
+ RETURN_IF_NOT(err == ERR_OK, ERR_SIGPROP_DIGEST);
+ return err;
+}
+
+int verifyCertDnPart(const char* sDN, const char* sId, const X509* pCert, int nNid)
+{
+ int err = ERR_OK;
+ DigiDocMemBuf mbuf1, mbuf2;
+
+ mbuf1.pMem = 0; mbuf1.nLen = 0;
+ mbuf2.pMem = 0; mbuf2.nLen = 0;
+ err = ddocCertGetDNPart(pCert, &mbuf1, nNid, 1);
+ err = ddocGetDNPartFromString(sDN, sId, &mbuf2);
+ ddocDebug(3, "verifyCertDnPart", "Search: %s from: %s got: %s cmp: %s", sId, sDN,
+ (const char*)mbuf2.pMem, (const char*)mbuf1.pMem);
+ if(mbuf1.pMem && mbuf2.pMem && strcmp((const char*)mbuf2.pMem, (const char*)mbuf1.pMem)) {
+ ddocDebug(3, "verifyCertDnPart", "Not matching entry: %s cert: %s signed: %s", sId, (const char*)mbuf1.pMem, (const char*)mbuf2.pMem);
+ err = ERR_WRONG_CERT;
+ SET_LAST_ERROR(err);
+ }
+ ddocMemBuf_free(&mbuf1);
+ ddocMemBuf_free(&mbuf2);
+ return err;
+}
+
+
+//============================================================
+// Verifies the certificates signed attributes
+// pSigInfo - signature info object
+//============================================================
+EXP_OPTION int verifySigCert(const SignatureInfo* pSigInfo)
+{
+ int err = ERR_OK, e1;
+ int l1, l2;
+ char szOtherSerial[100];
+ byte buf1[DIGEST_LEN256+2], buf2[DIGEST_LEN256*2], buf3[DIGEST_LEN256*2];
+ DigiDocMemBuf* pMBuf;
+ CertID* pCertID = 0;
+ X509* pCert;
+
+ RETURN_IF_NULL_PARAM(pSigInfo);
+ RETURN_IF_NULL_PARAM(ddocSigInfo_GetSignersCert(pSigInfo));
+ l1 = sizeof(buf1);
+ pCertID = ddocCertIDList_GetCertIDOfType(pSigInfo->pCertIDs, CERTID_TYPE_SIGNERS_CERTID);
+ if(pCertID->szDigestType){
+ if(!strcmp(pCertID->szDigestType,DIGEST_SHA256_NAME)){
+ RETURN_IF_NOT(X509_digest(ddocSigInfo_GetSignersCert(pSigInfo),
+ EVP_sha256(), buf1, (unsigned int*)&l1), ERR_X509_DIGEST); }
+ else{
+ RETURN_IF_NOT(X509_digest(ddocSigInfo_GetSignersCert(pSigInfo),
+ EVP_sha1(), buf1, (unsigned int*)&l1), ERR_X509_DIGEST); }
+ }else{
+ RETURN_IF_NOT(X509_digest(ddocSigInfo_GetSignersCert(pSigInfo),
+ EVP_sha1(), buf1, (unsigned int*)&l1), ERR_X509_DIGEST);
+ }
+ // debug
+ memset(buf2, 0, sizeof(buf2));
+ memset(buf3, 0, sizeof(buf3));
+ pMBuf = ddocSigInfo_GetSignersCert_DigestValue(pSigInfo);
+ RETURN_IF_NULL_PARAM(pMBuf);
+ l2 = sizeof(buf2)-1;
+ encode((const byte*)pMBuf->pMem, ((pMBuf->nLen < l2/2) ? pMBuf->nLen : l2/2), (byte*)buf2, &l2);
+ l2 = sizeof(buf3)-1;
+ encode((const byte*)buf1, l1, (byte*)buf3, &l2);
+ ddocDebug(3, "verifySigCert", "SIG: %s cdig1: %d - %s cdig2: %d - %s - %d",
+ pSigInfo->szId, pMBuf->nLen, buf2, l1, buf3, l2);
+ err = compareByteArrays((const byte*)pMBuf->pMem, pMBuf->nLen, buf1, l1);
+ RETURN_IF_NOT(err == ERR_OK, ERR_WRONG_CERT);
+ err = ReadCertSerialNumber(szOtherSerial, sizeof(szOtherSerial), ddocSigInfo_GetSignersCert(pSigInfo));
+ ddocDebug(3, "verifySigCert", "SIG: %s signer-cert-serial: %s cert-serial2: %s",
+ pSigInfo->szId, ddocSigInfo_GetSignersCert_IssuerSerial(pSigInfo), szOtherSerial);
+ RETURN_IF_NOT(((err == ERR_OK) &&
+ !strcmp(ddocSigInfo_GetSignersCert_IssuerSerial(pSigInfo), szOtherSerial)), ERR_WRONG_CERT);
+ // check key usage
+ pCert = ddocSigInfo_GetSignersCert(pSigInfo);
+ if(!ddocCertCheckKeyUsage(pCert, KUIDX_NON_REPUDIATION)) {
+ ddocDebug(1, "verifySigCert", "SIG: %s cert has no non-repudiation key usage", pSigInfo->szId);
+ SET_LAST_ERROR(ERR_SIGNERS_CERT_NON_REPU);
+ return ERR_SIGNERS_CERT_NON_REPU;
+ } else
+ ddocDebug(3, "verifySigCert", "SIG: %s cert has non-repudiation key usage", pSigInfo->szId);
+ // check cert parts
+ if(pCertID && pCert) {
+ e1 = verifyCertDnPart(pCertID->szIssuerName, "CN", pCert, NID_commonName);
+ if(!err && e1) err = e1;
+ e1 = verifyCertDnPart(pCertID->szIssuerName, "C", pCert, NID_countryName);
+ if(!err && e1) err = e1;
+ e1 = verifyCertDnPart(pCertID->szIssuerName, "O", pCert, NID_organization);
+ if(!err && e1) err = e1;
+ e1 = verifyCertDnPart(pCertID->szIssuerName, "OU", pCert, NID_organizationUnit);
+ if(!err && e1) err = e1;
+ }
+ return err;
+}
+
+
+//============================================================
+// Verifies this signature
+// pSigDoc - signed doc data
+// pSigInfo - signature info object
+// signerCA - direct signer CA certs filename
+// szDateFile - name of the digidoc file
+// bUseCA - use CA certs or not 1/0
+// from original file and use it for hash function.
+// This is usefull if the file has been generated by
+// another library and possibly formats these elements
+// differently.
+//============================================================
+EXP_OPTION int verifySignatureInfo(const SignedDoc* pSigDoc, const SignatureInfo* pSigInfo,
+ const char* signerCA, const char* szDataFile, int bUseCA)
+{
+ int err = ERR_OK;
+ int j, k;
+ X509* cert = NULL;
+ DocInfo* pDocInfo = NULL;
+ DataFile* pDf = NULL;
+ DigiDocMemBuf *pMBuf1 = 0, *pMBuf2 = 0;
+
+ RETURN_IF_NULL_PARAM(pSigInfo);
+ clearErrors();
+ pMBuf1 = ddocDigestValue_GetDigestValue(pSigInfo->pSigInfoRealDigest);
+ RETURN_IF_NULL_PARAM(pMBuf1);
+ pMBuf2 = ddocSigInfo_GetSignatureValue_Value((SignatureInfo*)pSigInfo);
+ RETURN_IF_NULL_PARAM(pMBuf2);
+ err = verifyEstIDSignature((const byte*)pMBuf1->pMem, pMBuf1->nLen, DIGEST_SHA1,
+ (byte*)pMBuf2->pMem, pMBuf2->nLen, ddocSigInfo_GetSignersCert(pSigInfo));
+ if(err != ERR_OK)
+ err = ERR_SIGNATURE;
+ if(err == ERR_OK) {
+ k = getCountOfDocInfos(pSigInfo);
+ ddocDebug(4, "verifySignatureInfo", "DFs: %d", k);
+ for(j = 0; (err == ERR_OK) && (j < k); j++) {
+ pDocInfo = getDocInfo(pSigInfo, j);
+ RETURN_IF_NULL(pDocInfo);
+ ddocDebug(4, "verifySignatureInfo", "DocInfo: %s", pDocInfo->szDocId);
+ pDf = getDataFileWithId(pSigDoc, pDocInfo->szDocId);
+ RETURN_IF_NULL(pDf);
+ ddocDebug(4, "verifySignatureInfo", "DF: %s", pDf->szId);
+ err = verifySigDocDigest(pSigDoc, pSigInfo, pDocInfo, szDataFile);
+ ddocDebug(4, "verifySignatureInfo", "DF: %s verify: %d", pDf->szId, err);
+ if(err == ERR_OK)
+ err = verifySigDocMimeDigest(pSigDoc, pSigInfo, pDocInfo, NULL);
+ }
+ }
+ if(err == ERR_OK)
+ err = verifySigDocSigPropDigest(pSigInfo);
+ if(err == ERR_OK) {
+ err = verifySigCert(pSigInfo);
+ }
+ if(err == ERR_OK) {
+ cert = getSignCertData(pSigInfo);
+ // VS: ver 2.2.4 - removed this check as OCSP check is sufficient
+ //if(err == ERR_OK)
+ // err = isCertValid(cert, convertStringToTimeT(pSigDoc, pSigInfo->szTimeStamp));
+ if(bUseCA && (err == ERR_OK))
+ err = isCertSignedBy(cert, signerCA);
+ }
+ if ( err != ERR_OK) SET_LAST_ERROR(err);
+ return err;
+}
+
+
+//============================================================
+// Verifies the whole document, but returns on first error
+// Use the functions defined earlier to verify all contents
+// step by step.
+// pSigDoc - signed doc data
+//
+//============================================================
+EXP_OPTION int verifySigDoc(const SignedDoc* pSigDoc, const char* signerCA,
+ const char** caFiles, const char* caPath, const char* notCert,
+ const char* szDataFile, int bUseCA)
+
+{
+ SignatureInfo* pSigInfo;
+ int i, d, err = ERR_OK;
+
+ RETURN_IF_NULL_PARAM(pSigDoc);
+ d = getCountOfSignatures(pSigDoc);
+ for(i = 0; i < d; i++) {
+ pSigInfo = getSignature(pSigDoc, i);
+ err = verifySignatureInfo(pSigDoc, pSigInfo, signerCA,
+ szDataFile, bUseCA);
+ RETURN_IF_NOT(err == ERR_OK, err);
+ err = verifyNotaryInfo(pSigDoc, pSigInfo, pSigInfo->pNotary, caFiles, caPath, notCert);
+ RETURN_IF_NOT(err == ERR_OK, err);
+ }
+ return err;
+}
+
+//============================================================
+// Verifies the certificates signed attributes
+// pNotInfo - notary info object
+//============================================================
+EXP_OPTION int verifyNotCert(const SignatureInfo* pSigInfo, const NotaryInfo* pNotInfo)
+{
+ int err = ERR_OK;
+ int l1;
+ char szOtherSerial[100];
+ byte buf1[DIGEST_LEN+2];
+ CertID* pCertID;
+ DigiDocMemBuf* pMBuf;
+ X509* pCert = 0;
+
+ RETURN_IF_NULL_PARAM(pSigInfo);
+ RETURN_IF_NULL_PARAM(pNotInfo);
+ pCertID = ddocSigInfo_GetCertIDOfType((SignatureInfo*)pSigInfo, CERTID_TYPE_RESPONDERS_CERTID);
+ RETURN_IF_NOT(pCertID, ERR_WRONG_CERT);
+ pMBuf = ddocCertID_GetDigestValue(pCertID);
+ RETURN_IF_NULL(pMBuf);
+
+ l1 = sizeof(buf1);
+ ddocDebug(9, "verifyNotCert", "ddocSigInfo_GetOCSPRespondersCert start");
+ pCert = ddocSigInfo_GetOCSPRespondersCert(pSigInfo);
+ RETURN_IF_NOT(pCert, ERR_WRONG_CERT);
+ if(pNotInfo->szDigestType!=NULL){
+ if(!strcmp(pNotInfo->szDigestType,DIGEST_SHA256_NAME)){
+ RETURN_IF_NOT(X509_digest(pCert, EVP_sha256(), buf1, (unsigned int*)&l1), ERR_X509_DIGEST); }
+ else {
+ RETURN_IF_NOT(X509_digest(pCert, EVP_sha1(), buf1, (unsigned int*)&l1), ERR_X509_DIGEST); }
+ }else{
+ RETURN_IF_NOT(X509_digest(pCert, EVP_sha1(), buf1, (unsigned int*)&l1), ERR_X509_DIGEST); }
+ err = compareByteArrays((const byte*)pMBuf->pMem, pMBuf->nLen, buf1, l1);
+ RETURN_IF_NOT(err == ERR_OK, ERR_WRONG_CERT);
+ err = ReadCertSerialNumber(szOtherSerial, sizeof(szOtherSerial), ddocSigInfo_GetOCSPRespondersCert(pSigInfo));
+ RETURN_IF_NOT(err == ERR_OK, err);
+ RETURN_IF_NOT(!strcmp(ddocCertID_GetIssuerSerial(pCertID), szOtherSerial), ERR_WRONG_CERT);
+ return ERR_OK;
+}
+
+//--------------------------------------------------
+// Sets digest algorithm type object
+// type - SHA1
+//--------------------------------------------------
+X509_ALGOR* setCIDAlgorithm(const EVP_MD * type)
+{
+ X509_ALGOR* alg = NULL;
+ int nid;
+
+ alg = X509_ALGOR_new();
+ RETURN_OBJ_IF_NULL(alg, 0);
+ if((alg->parameter == NULL) ||
+ (alg->parameter->type != V_ASN1_NULL)) {
+ ASN1_TYPE_free(alg->parameter);
+ alg->parameter=ASN1_TYPE_new();
+ RETURN_OBJ_IF_NULL(alg->parameter, NULL);
+ alg->parameter->type=V_ASN1_NULL;
+ }
+ ASN1_OBJECT_free(alg->algorithm);
+ if ((nid = EVP_MD_type(type)) != NID_undef) {
+ alg->algorithm=OBJ_nid2obj(nid);
+ }
+ return alg;
+}
+
+//--------------------------------------------------
+// Sets signature algorithm type object
+// type - RSA+SHA1
+//--------------------------------------------------
+X509_ALGOR* setSignAlgorithm(const EVP_MD * type)
+{
+ X509_ALGOR* alg;
+ //int nid;
+
+ alg = X509_ALGOR_new();
+ RETURN_OBJ_IF_NULL(alg, NULL);
+ if((alg->parameter == NULL) ||
+ (alg->parameter->type != V_ASN1_NULL)) {
+ ASN1_TYPE_free(alg->parameter);
+ alg->parameter=ASN1_TYPE_new();
+ RETURN_OBJ_IF_NULL(alg->parameter, 0);
+ alg->parameter->type=V_ASN1_NULL;
+ }
+ ASN1_OBJECT_free(alg->algorithm);
+ /*if ((nid = EVP_MD_type(type)) != NID_undef) {
+ alg->algorithm=OBJ_nid2obj(nid);
+ }*/
+ alg->algorithm = OBJ_nid2obj(type->pkey_type);
+ return alg;
+}
+
+//--------------------------------------------------
+// Helper function. Converts Notary info to an OCSP
+// response structure. Used in verify and file writing
+// functions
+// pNotInfo - NotaryInfo object
+// notCert - OCSP responder certificate
+// pBasResp - pointer to a pointer of the new response structure
+//--------------------------------------------------
+int notary2ocspBasResp(const SignedDoc* pSigDoc, const NotaryInfo* pNotInfo, X509* notCert, OCSP_BASICRESP** pBasResp)
+{
+ OCSP_SINGLERESP * single = 0;
+ SignatureInfo* pSigInfo;
+ CertID* pCertID;
+ CertValue* pCertVal;
+ // ASN1_GENERALIZEDTIME *tp = NULL;
+ int err = ERR_OK;
+ const DigiDocMemBuf *pMBuf;
+ DigiDocMemBuf mbuf1;
+ const char *p1 = NULL;
+
+ mbuf1.pMem = 0;
+ mbuf1.nLen = 0;
+ RETURN_IF_NULL_PARAM(notCert);
+ // new basic response
+ *pBasResp = OCSP_BASICRESP_new();
+ RETURN_IF_NULL(*pBasResp);
+ str2asn1time(pSigDoc, pNotInfo->timeProduced, (*pBasResp)->tbsResponseData->producedAt);
+ p1 = ddocNotInfo_GetResponderId_Type(pNotInfo);
+ RETURN_IF_NULL(p1);
+ if(!strcmp(p1, RESPID_NAME_VALUE)) {
+ (*pBasResp)->tbsResponseData->responderId->type = V_OCSP_RESPID_NAME;
+ (*pBasResp)->tbsResponseData->responderId->value.byName =
+ X509_NAME_dup(X509_get_subject_name(notCert));
+ } else {
+ (*pBasResp)->tbsResponseData->responderId->type = V_OCSP_RESPID_KEY;
+ (*pBasResp)->tbsResponseData->responderId->value.byKey =
+ ASN1_OCTET_STRING_new();
+ pMBuf = ddocNotInfo_GetResponderId(pNotInfo);
+ RETURN_IF_NULL(pMBuf);
+ ASN1_OCTET_STRING_set((*pBasResp)->tbsResponseData->responderId->value.byKey,
+ (unsigned char*)pMBuf->pMem, pMBuf->nLen);
+ }
+ // new single response
+ single = OCSP_SINGLERESP_new();
+ single->certStatus->type = V_OCSP_CERTSTATUS_GOOD;
+ single->certStatus->value.good = ASN1_NULL_new();
+ single->certId->hashAlgorithm = setCIDAlgorithm(EVP_sha1());
+ err = ddocNotInfo_GetIssuerNameHash(pNotInfo, &mbuf1);
+ ASN1_OCTET_STRING_set(single->certId->issuerNameHash, (unsigned char*)mbuf1.pMem, mbuf1.nLen);
+ ddocMemBuf_free(&mbuf1);
+ err = ddocNotInfo_GetIssuerKeyHash(pNotInfo, &mbuf1);
+ ASN1_OCTET_STRING_set(single->certId->issuerKeyHash, (unsigned char*)mbuf1.pMem, mbuf1.nLen);
+ ddocMemBuf_free(&mbuf1);
+ pSigInfo = ddocGetSignatureForNotary(pSigDoc, pNotInfo);
+ RETURN_IF_NULL(pSigInfo);
+ pCertID = ddocSigInfo_GetCertIDOfType(pSigInfo, CERTID_TYPE_RESPONDERS_CERTID);
+ if(pCertID) {
+ ddocDebug(9, "notary2ocspBasResp", "pCertID");
+ ddocMemAppendData(&mbuf1, ddocCertID_GetIssuerSerial(pCertID), -1);
+ } else {
+ ddocDebug(9, "notary2ocspBasResp", "no pCertID");
+ pCertVal = ddocCertValueList_GetCertValueOfType(pSigInfo->pCertValues, CERTID_VALUE_RESPONDERS_CERT);
+ ddocDebug(9, "notary2ocspBasResp", "ddocCertValueList_GetCertValueOfType");
+ if(pCertVal) {
+ ddocMemSetLength(&mbuf1, 100);
+ ReadCertSerialNumber((char*)mbuf1.pMem, mbuf1.nLen-1, pCertVal->pCert);
+ }
+ }
+ ASN1_INTEGER_set(single->certId->serialNumber, atol((const char*)mbuf1.pMem));
+ ddocMemBuf_free(&mbuf1);
+ err = ddocNotInfo_GetThisUpdate(pNotInfo, &mbuf1);
+ if(mbuf1.pMem && strlen((char*)mbuf1.pMem))
+ str2asn1time(pSigDoc, (char*)mbuf1.pMem, single->thisUpdate);
+ ddocMemBuf_free(&mbuf1);
+ err = ddocNotInfo_GetNextUpdate(pNotInfo, &mbuf1);
+ if(mbuf1.pMem && strlen((char*)mbuf1.pMem))
+ str2asn1time(pSigDoc, (char*)mbuf1.pMem, single->nextUpdate);
+ ddocMemBuf_free(&mbuf1);
+ sk_OCSP_SINGLERESP_push((*pBasResp)->tbsResponseData->responses, single);
+ // add nonce
+ err = ddocNotInfo_GetOcspRealDigest(pSigDoc, pNotInfo, &mbuf1);
+ if(!err)
+ err = OCSP_basic_add1_nonce((*pBasResp), (unsigned char*)mbuf1.pMem, mbuf1.nLen);
+ ddocMemBuf_free(&mbuf1);
+ if (err == ERR_LIB_NONE){
+ err = ERR_OK;
+ // set signature
+ (*pBasResp)->signatureAlgorithm = setSignAlgorithm(EVP_sha1());
+ err = ddocNotInfo_GetOcspSignatureValue(pNotInfo, &mbuf1);
+ ASN1_OCTET_STRING_set((*pBasResp)->signature, (byte*)mbuf1.pMem, mbuf1.nLen);
+ ddocMemBuf_free(&mbuf1);
+ } else {
+ OCSP_BASICRESP_free(*pBasResp);
+ // PR. avoid double free
+ *pBasResp = 0;
+ SET_LAST_ERROR_RETURN_CODE(ERR_OCSP_NO_NONCE);
+ }
+ ddocDebug(9, "notary2ocspBasResp", "end");
+ // checkErrors();
+ return ERR_OK;
+}
+
+//--------------------------------------------------
+// Verfies NotaryInfo signature
+// pSigDoc - signed doc object
+// pNotInfo - NotaryInfo object
+// caFiles - array of CA file names terminated with NULL
+// CApath - path to (directory) all certs
+// notCertFile - Notary (e.g. OCSP responder) cert file
+//--------------------------------------------------
+EXP_OPTION int verifyNotaryInfo(const SignedDoc* pSigDoc,
+ const SignatureInfo* pSigInfo,
+ const NotaryInfo* pNotInfo,
+ const char** caFiles, const char *CApath,
+ const char* notCertFile)
+{
+ X509** caCerts;
+ X509* notCert = NULL;
+ int err = ERR_OK, l1, i;
+
+ RETURN_IF_NULL_PARAM(caFiles);
+ RETURN_IF_NULL_PARAM(CApath);
+ RETURN_IF_NULL_PARAM(notCertFile);
+ // find the chain length
+ // VS - ver 1.67
+ for(l1 = 0; caFiles && caFiles[l1]; l1++);
+ caCerts = (X509**)malloc(sizeof(void*) * (l1 + 1));
+ RETURN_IF_BAD_ALLOC(caCerts);
+ memset(caCerts, 0, sizeof(void*) * (l1 + 1));
+ for(i = 0; i < l1; i++) {
+ err = ReadCertificate(&(caCerts[i]),caFiles[i]);
+ if (err != ERR_OK) {
+ err = ERR_CERT_READ;
+ goto cleanup;
+ }
+ }
+ err = ReadCertificate(&notCert, notCertFile);
+ if (err != ERR_OK) {
+ err = ERR_CERT_READ;
+ goto cleanup;
+ }
+ err = verifyNotaryInfoCERT(pSigDoc, pSigInfo, pNotInfo,
+ (const X509**)caCerts, CApath, notCert);
+ if (err != ERR_OK) SET_LAST_ERROR(err);
+ // cleanup
+cleanup:
+ if(notCert)
+ X509_free(notCert);
+ for(i = 0; i < l1; i++)
+ if(caCerts[i])
+ X509_free(caCerts[i]);
+ free(caCerts);
+ return err;
+}
+
+//--------------------------------------------------
+// Setup X509 store for verification purposes
+// CApath - directory of all certs
+// CA1file - highest root cert
+// CA2file - actual parent cert
+//--------------------------------------------------
+int setup_verifyCERT(X509_STORE **newX509_STORE,
+ const char *CApath, const X509** certs)
+{
+ X509_STORE *store;
+ X509_LOOKUP *lookup;
+ int i;
+ DigiDocMemBuf mbuf1;
+
+ mbuf1.pMem = 0;
+ mbuf1.nLen = 0;
+ if((store = X509_STORE_new()) == NULL) goto end;
+ lookup = X509_STORE_add_lookup(store,X509_LOOKUP_file());
+ if (lookup == NULL) goto end;
+ for(i = 0; certs && certs[i]; i++) {
+ ddocDebug(3, "setup_verifyCERT", "add cert: %d cert: %s", i, (certs[i] ? "OK" : "NULL"));
+ ddocCertGetSubjectDN((X509*)certs[i], &mbuf1);
+ ddocDebug(3, "setup_verifyCERT", "add cert: %d cert: %s", i, (char*)mbuf1.pMem);
+ X509_STORE_add_cert(store, (X509*)certs[i]);
+ ddocMemBuf_free(&mbuf1);
+ }
+ ddocDebug(3, "setup_verifyCERT", "certs added");
+ lookup=X509_STORE_add_lookup(store,X509_LOOKUP_hash_dir());
+ if (lookup == NULL) goto end;
+ if (CApath) {
+ ddocDebug(3, "setup_verifyCERT", "lookup dir: %s", CApath);
+ if(!X509_LOOKUP_add_dir(lookup,CApath,X509_FILETYPE_PEM)) {
+ //BIO_printf(bp, "Error loading directory %s\n", CApath);
+ goto end;
+ }
+ } else X509_LOOKUP_add_dir(lookup,NULL,X509_FILETYPE_DEFAULT);
+ *newX509_STORE = store;
+ ERR_clear_error();
+ return ERR_OK;
+end:
+ if (store) X509_STORE_free(store);
+ SET_LAST_ERROR_RETURN_CODE(ERR_CERT_STORE_READ);
+}
+
+int verifyOcspCertId(OCSP_RESPONSE* pResp, X509* pCert, X509* pCaCert)
+{
+ OCSP_RESPBYTES *rb = NULL;
+ OCSP_BASICRESP *br = NULL;
+ OCSP_RESPDATA *rd = NULL;
+ OCSP_SINGLERESP *single = NULL;
+ OCSP_CERTID *cid = NULL;
+ int err = ERR_OK;
+ DigiDocMemBuf mbuf1, mbuf2, mbuf3;
+
+ RETURN_IF_NULL_PARAM(pResp);
+ RETURN_IF_NULL_PARAM(pCert);
+ RETURN_IF_NULL_PARAM(pCaCert);
+ RETURN_IF_NULL_PARAM(pResp->responseBytes);
+ mbuf1.pMem = 0;
+ mbuf1.nLen = 0;
+ mbuf2.pMem = 0;
+ mbuf2.nLen = 0;
+ mbuf3.pMem = 0;
+ mbuf3.nLen = 0;
+ rb = pResp->responseBytes;
+ if(OBJ_obj2nid(rb->responseType) != NID_id_pkix_OCSP_basic)
+ SET_LAST_ERROR_RETURN_CODE(ERR_OCSP_UNKNOWN_TYPE);
+ if((br = OCSP_response_get1_basic(pResp)) == NULL)
+ SET_LAST_ERROR_RETURN_CODE(ERR_OCSP_NO_BASIC_RESP);
+ ddocCertGetSubjectDN(pCert, &mbuf2);
+ ddocCertGetSubjectDN(pCaCert, &mbuf3);
+ ddocDebug(4, "verifyOcspCertId", "for cert: %ld, cn: %s, ca: %s", X509_get_serialNumber(pCert), mbuf2.pMem, mbuf3.pMem);
+ ddocMemBuf_free(&mbuf2);
+ ddocMemBuf_free(&mbuf3);
+ rd = br->tbsResponseData;
+ if(ASN1_INTEGER_get(rd->version) != 0)
+ SET_LAST_ERROR_RETURN_CODE(ERR_OCSP_WRONG_VERSION);
+ if(sk_OCSP_SINGLERESP_num(rd->responses) != 1)
+ SET_LAST_ERROR_RETURN_CODE(ERR_OCSP_ONE_RESPONSE);
+ single = sk_OCSP_SINGLERESP_value(rd->responses, 0);
+ RETURN_IF_NULL(single);
+ cid = single->certId;
+ RETURN_IF_NULL(cid);
+ // check serial number
+ if(ASN1_INTEGER_cmp(cid->serialNumber, X509_get_serialNumber(pCert)) != 0) {
+ ddocDebug(4, "verifyOcspCertId", "Looking for cert-nr: %ld buf found %ld",
+ X509_get_serialNumber(pCert), ASN1_INTEGER_get(cid->serialNumber));
+ return ERR_WRONG_CERT;
+ }
+ // check issuer name hash
+ err = ddocCertGetIssuerNameDigest(pCert, &mbuf1);
+ RETURN_IF_NOT(err == ERR_OK, err);
+ err = compareByteArrays((byte*)mbuf1.pMem, (unsigned int)mbuf1.nLen,
+ cid->issuerNameHash->data, cid->issuerNameHash->length);
+ mbuf2.pMem = cid->issuerNameHash->data;
+ mbuf2.nLen = cid->issuerNameHash->length;
+ ddocBin2Hex(&mbuf2, &mbuf3);
+ mbuf2.pMem = 0;
+ mbuf2.nLen = 0;
+ ddocBin2Hex(&mbuf1, &mbuf2);
+ ddocDebug(4, "verifyOcspCertId", "Looking for name-hash: %s found %s RC: %d",
+ (char*)mbuf2.pMem, (char*)mbuf3.pMem, err);
+ ddocMemBuf_free(&mbuf1);
+ ddocMemBuf_free(&mbuf2);
+ ddocMemBuf_free(&mbuf3);
+ RETURN_IF_NOT(err == ERR_OK, ERR_WRONG_CERT);
+ // check issuer key hash
+ err = ddocCertGetPubkeyDigest(pCaCert, &mbuf1);
+ RETURN_IF_NOT(err == ERR_OK, err);
+ err = compareByteArrays((byte*)mbuf1.pMem, (unsigned int)mbuf1.nLen,
+ cid->issuerKeyHash->data, cid->issuerKeyHash->length);
+ mbuf2.pMem = cid->issuerKeyHash->data;
+ mbuf2.nLen = cid->issuerKeyHash->length;
+ ddocBin2Hex(&mbuf2, &mbuf3);
+ mbuf2.pMem = 0;
+ mbuf2.nLen = 0;
+ ddocBin2Hex(&mbuf1, &mbuf2);
+ ddocDebug(4, "verifyOcspCertId", "Looking for key-hash: %s found %s RC: %d",
+ (char*)mbuf2.pMem, (char*)mbuf3.pMem, err);
+ ddocMemBuf_free(&mbuf1);
+ ddocMemBuf_free(&mbuf2);
+ ddocMemBuf_free(&mbuf3);
+ return err;
+}
+
+//--------------------------------------------------
+// Verfies NotaryInfo signature
+// pSigDoc - signed doc object
+// pNotInfo - NotaryInfo object
+// caCerts - CA certificate pointer array terminated with NULL
+// CApath - path to (directory) all certs
+// notCertFile - Notary (e.g. OCSP responder) cert file
+//--------------------------------------------------
+EXP_OPTION int verifyNotaryInfoCERT(const SignedDoc* pSigDoc,
+ const SignatureInfo* pSigInfo,
+ const NotaryInfo* pNotInfo,
+ const X509** caCerts, const char *CApath,
+ const X509* notCert)
+{
+ return verifyNotaryInfoCERT2(pSigDoc, pSigInfo, pNotInfo, caCerts, CApath, notCert, NULL);
+}
+
+//--------------------------------------------------
+// Verfies NotaryInfo signature
+// pSigDoc - signed doc object
+// pNotInfo - NotaryInfo object
+// caCerts - CA certificate pointer array terminated with NULL
+// CApath - path to (directory) all certs
+// notCertFile - Notary (e.g. OCSP responder) cert file
+// pSigCa - signers ca cert
+//--------------------------------------------------
+EXP_OPTION int verifyNotaryInfoCERT2(const SignedDoc* pSigDoc,
+ const SignatureInfo* pSigInfo,
+ const NotaryInfo* pNotInfo,
+ const X509** caCerts, const char *CApath,
+ const X509* notCert, const X509* pSigCa)
+{
+ X509_STORE *store;
+ OCSP_RESPONSE* pResp = NULL;
+ OCSP_BASICRESP* bs = NULL;
+ STACK_OF(X509)* ver_certs = NULL;
+ int err = ERR_OK, l1;
+ X509 *certNotaryDirectCA = 0, *pCert = 0, *pCaCert = 0;
+ DigiDocMemBuf mbuf1;
+ char buf1[100], buf3[500];
+ time_t tProdAt;
+
+ mbuf1.pMem = 0;
+ mbuf1.nLen = 0;
+ RETURN_IF_NULL_PARAM(pSigDoc);
+ RETURN_IF_NULL_PARAM(pSigInfo);
+ RETURN_IF_NULL_PARAM(pNotInfo);
+ RETURN_IF_NULL_PARAM(notCert);
+ RETURN_IF_NULL_PARAM(caCerts);
+
+ // find the chain length
+ for(l1 = 0; caCerts && caCerts[l1]; l1++);
+ if(l1 < 1)
+ SET_LAST_ERROR_RETURN_CODE(ERR_CERT_INVALID);
+ certNotaryDirectCA = (X509*)caCerts[l1-1];
+ // do the signature values match?
+ // not to be checked in format 1.4
+ if(err) return err;
+ // now create an OCSP object and check its validity
+ // VS - ver 1.66
+ pResp = ddocNotInfo_GetOCSPResponse_Value(pNotInfo);
+ if(!pResp) {
+ ddocDebug(3, "verifyNotaryInfoCERT", "OCSP missing");
+ SET_LAST_ERROR_RETURN_CODE(ERR_NO_OCSP);
+ }
+ // debug
+ //WriteOCSPResponse("test2.resp", pResp);
+ if((setup_verifyCERT(&store, CApath, caCerts)) == ERR_OK) {
+ ddocNotInfo_GetProducedAt_timet(pNotInfo, &tProdAt);
+ X509_VERIFY_PARAM_set_time(store->param, tProdAt);
+ X509_STORE_set_flags(store, X509_V_FLAG_USE_CHECK_TIME);
+ // new basic response
+ // create OCSP basic response
+ // in version 1.0 we calculated digest over tbsResponseData
+ bs = OCSP_response_get1_basic(pResp);
+ if (!bs) err = ERR_OCSP_WRONG_RESPID;
+ if (err == ERR_OK) {
+ ver_certs = sk_X509_new_null();
+ if (ver_certs) {
+ ReadCertSerialNumber(buf1, sizeof(buf1), (X509*)notCert);
+ ddocCertGetSubjectDN((X509*)notCert, &mbuf1);
+ sk_X509_push(ver_certs, notCert);
+ ddocDebug(3, "verifyNotaryInfoCERT", "OCSP verify err: %d, err1: %d format: %s", err, pSigInfo->nErr1, pSigDoc->szFormatVer);
+ // fix invalid padding flag on ddoc 1.0 signatures
+ if((!strcmp(pSigDoc->szFormatVer, SK_XML_1_VER) && !strcmp(pSigDoc->szFormat, SK_XML_1_NAME))
+ || (bs->signature->flags & 0x07)) {
+ ddocDebug(3, "verifyNotaryInfoCERT", "Reset ocsp flag %d", bs->signature->flags);
+ bs->signature->flags &= ~(ASN1_STRING_FLAG_BITS_LEFT|0x07);
+ }
+ err = OCSP_basic_verify(bs, ver_certs, store, OCSP_NOCHECKS);
+ ddocDebug(3, "verifyNotaryInfoCERT", "OCSP verify: %d, not cet: %s cn: %s", err, buf1, mbuf1.pMem);
+ if(err == ERR_LIB_NONE) {
+ err = ERR_OK;
+ } else {
+ err = ERR_NOTARY_SIG_MATCH;
+ SET_LAST_ERROR(err);
+ }
+ // cleanup
+ sk_X509_free(ver_certs);
+ }
+ if(bs) OCSP_BASICRESP_free(bs);
+ }
+ X509_STORE_free(store);
+ } else {
+ err = ERR_CERT_STORE_READ;
+ SET_LAST_ERROR(err);
+ }
+ if(pSigInfo->nErr1 == ERR_VER_1_0)
+ ((SignatureInfo*)pSigInfo)->nErr1 = 0;
+ ddocDebug(3, "verifyNotaryInfoCERT", "OCSP verify final: %d, not cet: %s cn: %s", err, buf1, mbuf1.pMem);
+ ddocMemBuf_free(&mbuf1);
+ if(err == ERR_OK) {
+ ddocDebug(9, "verifyNotaryInfoCERT", "ddocSigInfo_GetOCSPRespondersCert start");
+ //if(!notCert) // ???
+ notCert = ddocSigInfo_GetOCSPRespondersCert(pSigInfo);
+ ddocDebug(9, "verifyNotaryInfoCERT", "ddocSigInfo_GetOCSPRespondersCert end");
+ if(notCert && pNotInfo->timeProduced) { // VS: ver 1.66
+ ddocDebug(9, "verifyNotaryInfoCERT", "notCert exists");
+ err = isCertValid((X509*)notCert, convertStringToTimeT(pSigDoc, pNotInfo->timeProduced)); //crash?
+ if (err != ERR_OK)
+ SET_LAST_ERROR(err);
+ } else {
+ ddocDebug(9, "verifyNotaryInfoCERT", "notCert invalid");
+ err = ERR_CERT_INVALID;
+ SET_LAST_ERROR(err);
+ }
+ if(err == ERR_OK) {
+ err = isCertSignedByCERT(notCert, certNotaryDirectCA);
+ if (err != ERR_OK)
+ SET_LAST_ERROR(err);
+ }
+ if(err == ERR_OK) {
+ err = verifyNotCert(pSigInfo, pNotInfo);
+ if (err != ERR_OK)
+ SET_LAST_ERROR(err);
+ }
+ if(err == ERR_OK) {
+ err = verifyNotaryDigest(pSigDoc, pNotInfo);
+ if (err != ERR_OK && err != ERR_OCSP_NONCE_SIGVAL_NOMATCH)
+ SET_LAST_ERROR(ERR_NOTARY_SIG_MATCH);
+ }
+ if(err == ERR_OK) {
+ pCert = ddocSigInfo_GetSignersCert(pSigInfo);
+ pCaCert = (pSigCa != NULL) ? (X509*)pSigCa : certNotaryDirectCA;
+ err = verifyOcspCertId(pResp, pCert, pCaCert);
+ if (err != ERR_OK)
+ SET_LAST_ERROR(err);
+ }
+ if(err == ERR_OK) {
+ ddocDebug(3, "verifyNotaryInfoCERT", "Not: %s time-ocsp: %s time-xml: %s",
+ pNotInfo->szId, (pNotInfo->timeProduced ? pNotInfo->timeProduced : ""),
+ (pNotInfo->szProducedAt ? pNotInfo->szProducedAt : ""));
+ if(pNotInfo->timeProduced && pNotInfo->szProducedAt &&
+ strcmp(pNotInfo->timeProduced, pNotInfo->szProducedAt) &&
+ strcmp(pSigDoc->szFormat, SK_XML_1_NAME)) {
+ err = ERR_OCSP_MALFORMED;
+ SET_LAST_ERROR(err);
+ }
+ }
+ }
+ if(pResp)
+ OCSP_RESPONSE_free(pResp);
+ ddocDebug(3, "verifyNotaryInfoCERT", "Ocsp verify: %d", err);
+ return err;
+}
+
+
+//--------------------------------------------------
+// Verfies NotaryInfo digest
+// pNotInfo - NotaryInfo object
+//--------------------------------------------------
+EXP_OPTION int verifyNotaryDigest(const SignedDoc* pSigDoc, const NotaryInfo* pNotInfo)
+{
+ int err, l1, l2, l3;
+ byte buf1[DIGEST_LEN256+2], buf2[40], buf3[40];
+ const DigiDocMemBuf *pMBuf;
+ DigiDocMemBuf mbuf2;
+ SignatureInfo* pSigInf = 0;
+
+ mbuf2.pMem = 0;
+ mbuf2.nLen = 0;
+ l1 = sizeof(buf1);
+ err = calculateNotaryInfoDigest(pSigDoc, pNotInfo, buf1, &l1);
+ RETURN_IF_NOT(err == ERR_OK, err);
+ pMBuf = ddocNotInfo_GetOcspDigest(pNotInfo);
+ RETURN_IF_NULL(pMBuf);
+ err = compareByteArrays(buf1, l1, (byte*)pMBuf->pMem, pMBuf->nLen);
+ RETURN_IF_NOT(err == ERR_OK, err);
+ // verify ocsp nonce = signature value digest
+ pSigInf = ddocGetSignatureForNotary(pSigDoc, pNotInfo);
+ RETURN_IF_NULL(pSigInf);
+ pMBuf = ddocSigInfo_GetSignatureValue_Value(pSigInf);
+ RETURN_IF_NULL(pMBuf);
+ l1 = sizeof(buf1);
+ err = calculateDigest((const byte*)pMBuf->pMem, pMBuf->nLen,
+ DIGEST_SHA1, (byte*)buf1, &l1);
+ RETURN_IF_NOT(err == ERR_OK, err);
+ err = ddocNotInfo_GetOcspRealDigest(pSigDoc, pNotInfo, &mbuf2);
+ RETURN_IF_NOT(err == ERR_OK, err);
+ err = compareByteArrays(buf1, l1, (byte*)mbuf2.pMem, mbuf2.nLen);
+ // debug output
+ l2 = sizeof(buf2);
+ l3 = sizeof(buf3);
+ encode((const byte*)buf1, l1, (byte*)buf2, &l2);
+ encode((const byte*)mbuf2.pMem, mbuf2.nLen, (byte*)buf3, &l3);
+ ddocDebug(3, "verifyNotaryDigest", "Signature: %s Notary: %s sig-val-dig: %s nonce: %s verify: %d",
+ pSigInf->szId, pNotInfo->szId, buf2, buf3, err);
+ RETURN_IF_NOT(err == ERR_OK, ERR_OCSP_NONCE_SIGVAL_NOMATCH);
+
+ return ERR_OK;
+}
+
+
+//============================================================
+// Verifies the whole document, but returns on first error
+// Use the functions defined earlier to verify all contents
+// step by step.
+// pSigDoc - signed doc data
+// signerCA - direct signer CA certs filename
+// szDateFile - name of the digidoc file
+// bUseCA - use CA certs or not 1/0
+//============================================================
+EXP_OPTION int verifySigDocCERT(const SignedDoc* pSigDoc,
+ const void* signerCA, const X509** caCerts,
+ const char* caPath, const X509* notCert,
+ const char* szDataFile, int bUseCA)
+{
+ SignatureInfo* pSigInfo;
+ int i, d, err = ERR_OK;
+
+ RETURN_IF_NULL_PARAM(pSigDoc);
+ //assert(pSigDoc);
+ d = getCountOfSignatures(pSigDoc);
+ for(i = 0; i < d; i++) {
+ pSigInfo = getSignature(pSigDoc, i);
+ err = verifySignatureInfoCERT(pSigDoc, pSigInfo, signerCA,
+ szDataFile, bUseCA);
+ //RETURN_IF_NOT(err == ERR_OK, err);
+ err = verifyNotaryInfoCERT(pSigDoc, pSigInfo, pSigInfo->pNotary, caCerts, caPath, notCert);
+ //RETURN_IF_NOT(err == ERR_OK, err);
+ }
+ return err;
+}
+
+//============================================================
+// Verifies this signature
+// pSigDoc - signed doc data
+// pSigInfo - signature info object
+// signerCA - direct signer CA certs filename
+// szDataFile - provide to read <SignedInfo> and <SignedProperties>
+// from original file and use it for hash function.
+// This is usefull if the file has been generated by
+// another library and possibly formats these elements
+// differently.
+// bUseCA - use CA certs or not 1/0
+//============================================================
+EXP_OPTION int verifySignatureInfoCERT(const SignedDoc* pSigDoc, const SignatureInfo* pSigInfo,
+ const void* signerCACert, const char* szDataFile, int bUseCA)
+{
+ int err = ERR_OK, err2 = ERR_OK;
+ int j, k, i;
+ X509* cert;
+ DocInfo* pDocInfo = NULL;
+ DataFile* pDf = NULL;
+ DigiDocMemBuf *pMBuf1, *pMBuf2;
+ NotaryInfo* pNot = NULL;
+
+ RETURN_IF_NULL_PARAM(pSigInfo);
+ pMBuf1 = ddocSigInfo_GetSigInfoRealDigest((SignatureInfo*)pSigInfo);
+ RETURN_IF_NULL_PARAM(pMBuf1);
+ pMBuf2 = ddocSigInfo_GetSignatureValue_Value((SignatureInfo*)pSigInfo);
+ RETURN_IF_NULL_PARAM(pMBuf2);
+ ddocDebug(3, "verifySignatureInfoCERT", "Sig: %s, CA: %s",
+ ((pSigInfo && pSigInfo->szId) ? pSigInfo->szId : "NULL"),
+ (signerCACert ? "OK" : "NULL"));
+ if(pSigInfo->szDigestType){
+ if(!strcmp(pSigInfo->szDigestType,DIGEST_SHA256_NAME))
+ err = verifyEstIDSignature((const byte*)pMBuf1->pMem, pMBuf1->nLen, DIGEST_SHA256,
+ (byte*)pMBuf2->pMem, pMBuf2->nLen, ddocSigInfo_GetSignersCert(pSigInfo));
+ else
+ err = verifyEstIDSignature((const byte*)pMBuf1->pMem, pMBuf1->nLen, DIGEST_SHA1,
+ (byte*)pMBuf2->pMem, pMBuf2->nLen, ddocSigInfo_GetSignersCert(pSigInfo));
+ }else{
+ err = verifyEstIDSignature((const byte*)pMBuf1->pMem, pMBuf1->nLen, DIGEST_SHA1,
+ (byte*)pMBuf2->pMem, pMBuf2->nLen, ddocSigInfo_GetSignersCert(pSigInfo));}
+ //RETURN_IF_NOT(err == ERR_OK, ERR_SIGNATURE);
+ // check that this signature signs all DataFiles
+ for(i = 0; i < getCountOfDataFiles(pSigDoc); i++) {
+ pDf = getDataFile(pSigDoc, i);
+ k = 0; // not found yet
+ for(j = 0; j < getCountOfDocInfos(pSigInfo); j++) {
+ pDocInfo = getDocInfo(pSigInfo, j);
+ ddocDebug(4, "verifySignatureInfoCERT", "Check sig \'%s\' of doc: \'%s\'", pSigInfo->szId, pDocInfo->szDocId);
+ if(!strcmp(pDocInfo->szDocId, pDf->szId)) {
+ k = 1; // found
+ break;
+ }
+ }
+ if(!k) {
+ //ddocDebug(1, "verifySignatureInfoCERT", "Signature \'%s\' does not sign doc: \'%s\'", pSigInfo->szId, pDocInfo->szDocId);
+ err = ERR_DOC_DIGEST;
+ SET_LAST_ERROR(err);
+ //return err;
+ }
+ }
+ // verify DataFile hashes
+ k = getCountOfDocInfos(pSigInfo);
+ ddocDebug(4, "verifySignatureInfoCERT", "DFs: %d", k);
+ for(j = 0; (err == ERR_OK) && (j < k); j++) {
+ pDocInfo = getDocInfo(pSigInfo, j);
+ ddocDebug(4, "verifySignatureInfoCERT", "Verify doc: %d - \'%s\'", j, pDocInfo->szDocId);
+ RETURN_IF_NULL(pDocInfo);
+ pDf = getDataFileWithId(pSigDoc, pDocInfo->szDocId);
+ SET_LAST_ERROR_RETURN_IF_NOT(pDf, ERR_BAD_DATAFILE_COUNT, ERR_BAD_DATAFILE_COUNT);
+ //RETURN_IF_NULL(pDf);
+ err = verifySigDocDigest(pSigDoc, pSigInfo, pDocInfo, szDataFile);
+ //ddocDebug(4, "verifySignatureInfoCERT", "Verify doc: %s - %d", pDocInfo->szDocId, err);
+ //RETURN_IF_NOT(err == ERR_OK, err);
+ if(!err)
+ err = verifySigDocMimeDigest(pSigDoc, pSigInfo, pDocInfo, NULL);
+ //RETURN_IF_NOT(err == ERR_OK, err);
+ }
+ err2 = verifySigDocSigPropDigest(pSigInfo);
+ if(!err) err = err2;
+ err2 = verifySigCert(pSigInfo);
+ if(!err) err = err2;
+ cert = getSignCertData(pSigInfo);
+ //#23789 - kontrollida allkirjastaja kehtivust OCSP producedAt ajal
+ pNot = getNotaryWithSigId(pSigDoc, pSigInfo->szId);
+ if(pNot && pNot->timeProduced) {
+ err = isCertValid(cert, convertStringToTimeT(pSigDoc, pNot->timeProduced));
+ }
+ if(bUseCA)
+ err2 = isCertSignedByCERT((const X509*)cert, (const X509*)signerCACert);
+ if(!err) err = err2;
+ return err;
+}
+
+//--------------------------------------------------
+// Checks if this element tag contains the
+// required attributes with the given values
+// data - input data, XML tags data (not content but the attributes)
+// nAttrs - number of attributes to check
+// attNames - array of attribute names
+// attValues - array of attribute values
+// returns 0 if OK (all atributes found or none desired)
+//--------------------------------------------------
+int checkAttrs(const char* data, int nAttrs,
+ const char** attNames, const char** attValues)
+{
+ int remains = 0, i;
+ char *pTmp1 = 0, *pTmp2 = 0;
+
+ RETURN_IF_NULL_PARAM(data);
+
+ if(nAttrs) {
+ RETURN_IF_NULL_PARAM(attNames);
+ RETURN_IF_NULL_PARAM(attValues);
+ remains = nAttrs; // must find nAttrs values
+ for(i = 0; i < nAttrs; i++) {
+ RETURN_IF_NULL(attNames[i]);
+ RETURN_IF_NULL(attValues[i]);
+ if((pTmp1 = strstr(data, attNames[i])) != 0) {
+ if((pTmp2 = strstr(pTmp1, "\"")) != 0) {
+ if(!strncmp(pTmp2+1, attValues[i], strlen(attValues[i])))
+ remains--; // found one
+ }
+ }
+ }
+ }
+ if (remains == 0)
+ return ERR_OK;
+ else
+ return remains;
+}
+
+char* findString(char* mainBuf, char* search)
+{
+ char* pTmp = NULL;
+ // first find in the latest 2KB
+ pTmp = strstr(mainBuf+2048, search);
+ // if not found check the previous buffer
+ // as well because the tag could have been broken
+ // between two buffer borders
+ if(!pTmp)
+ pTmp = strstr(mainBuf, search);
+ return pTmp;
+}
+
+//--------------------------------------------------
+// Finds the contents of a given XML tag
+// in the given file.
+// data - buffer for tag content data (caller must deallocate)
+// tagName - tag name to search
+// nAttrs - number of attributes to check
+// attNames - array of attribute names
+// attValues - array of attribute values
+// withTags - 1 if include tags themselves, else 0
+// returns 0 if tag was found and data read.
+//--------------------------------------------------
+int readTagContents(char** data, const char* fileName,
+ const char* tagName, int nAttrs,
+ const char** attNames, const char** attValues,
+ int withTags)
+{
+ int err = ERR_OK, status, len, level;
+ FILE *hFile = 0;
+ char *pTmp1 = 0, *pTmp2 = 0, *pTmp3 = 0, *pBegin = 0, *pData = NULL;
+ char buf1[4097], buf2[100];
+
+ RETURN_IF_NULL_PARAM(data);
+ RETURN_IF_NULL_PARAM(fileName);
+ RETURN_IF_NULL_PARAM(tagName);
+ RETURN_IF_NULL_PARAM(attNames);
+ RETURN_IF_NULL_PARAM(attValues);
+
+ if((hFile = fopen(fileName, "rb")) != 0) {
+ status = 0; // nothing found yet
+ level = 0;
+ memset(buf1, 0, sizeof(buf1));
+ // allways load the second half of the buffer
+ // warning - assignment in conditional expression -> yes but the code seems clearer this way!
+ while((len = fread(buf1+2048, 1, 2048, hFile)) && status < 2) {
+ switch(status) {
+ case 0:
+ // find <tagName
+ snprintf(buf2, sizeof(buf2), "<%s ", tagName);
+ pTmp1 = findString(buf1, buf2);
+ while(pTmp1 && (status == 0) && ((int)(pTmp1-buf1) < (int)sizeof(buf1))) {
+ pTmp2 = strstr(pTmp1, ">");
+ if(pTmp2) {
+ *pTmp2 = 0;
+ err = checkAttrs(pTmp1, nAttrs, attNames, attValues);
+ *pTmp2 = '>';
+ if(!err) {
+ // mark the found tag
+ // in order not to later mistake this
+ // for a new level. Take also buffer moving
+ // in account
+ pBegin = pTmp1-2048;
+ status = 1; // now search for...
+ if(withTags) {
+ snprintf(buf2, sizeof(buf2), "</%s>", tagName);
+ if((pTmp3 = strstr(pTmp1, buf2)) != 0)
+ *(pTmp3+strlen(buf2)) = 0;
+ len = strlen(pTmp1)+1;
+ pData = (char*)malloc(len);
+ memset(pData, 0, len);
+ RETURN_IF_BAD_ALLOC(pData);
+ strncpy(pData, pTmp1, len);
+ if(pTmp3) {
+ *data = pData;
+ status = 2;
+ }
+ } else {
+ pTmp2++; // first byte of content data
+ // find </tagName>
+ snprintf(buf2, sizeof(buf2), "</%s>", tagName);
+ if((pTmp3 = strstr(pTmp1, buf2)) != 0)
+ *pTmp3 = 0;
+ len = strlen(pTmp2);
+ pData = (char*)malloc(len+1);
+ RETURN_IF_BAD_ALLOC(pData);
+ strncpy(pData, pTmp2, len);
+ if(pTmp3) {
+ *data = pData;
+ status = 2;
+ }
+ } // else
+ } // if(!err)
+ else
+ pTmp1 = strstr(pTmp2, buf2);
+ } // if(pTmp2)
+ else
+ pTmp1++;
+ } // if(pTmp1)
+ break;
+ case 1:
+ snprintf(buf2, sizeof(buf2), "</%s>", tagName);
+ pTmp3 = findString(buf1, buf2);
+ // if the found end-tag is fully in the
+ // previous buffer then if cannot be the right
+ // one because I would have noticed it in
+ // the last step
+ if((pTmp3+strlen(buf2)) < (buf1+2048))
+ pTmp3 = NULL;
+ snprintf(buf2, sizeof(buf2), "<%s ", tagName);
+ pTmp1 = findString(buf1, buf2);
+ if(pTmp1 && pTmp1 > pBegin && !pTmp3)
+ level++;
+ if(pTmp3 && !level) {
+ if(withTags) {
+ snprintf(buf2, sizeof(buf2), "</%s>", tagName);
+ *(pTmp3 + strlen(buf2)) = 0;
+ } else
+ *pTmp3 = 0;
+ *data = pData;
+ status = 2;
+ }
+ if(pTmp3 && level > 0)
+ level--;
+ len = strlen(buf1+2048);
+ if(len) {
+ RETURN_IF_NULL(pData);
+ pData = (char*)realloc(pData, strlen(pData)+len+1);
+ strncpy(strchr(pData, 0), buf1+2048, strlen(pData)+len+1);
+ *data = pData;
+ }
+ break;
+
+ default:
+ break;
+ }
+ memcpy(buf1, buf1+2048, 2048);
+ memset(buf1+2048, 0, 2049);
+ } // while
+ fclose(hFile);
+ } // if(hFile
+ else
+ err = ERR_FILE_READ;
+ return (pData == NULL);
+}
+
diff --git a/libdigidoc/DigiDocVerify.h b/libdigidoc/DigiDocVerify.h
new file mode 100644
index 0000000..891e2b7
--- /dev/null
+++ b/libdigidoc/DigiDocVerify.h
@@ -0,0 +1,178 @@
+#ifndef __DIGIDOC_VERIFY_H__
+#define __DIGIDOC_VERIFY_H__
+//==================================================
+// FILE: DigiDocVerify.h
+// PROJECT: Digi Doc
+// DESCRIPTION: DigiDoc verification routines
+// AUTHOR: Veiko Sinivee, S|E|B IT Partner Estonia
+//==================================================
+// Copyright (C) AS Sertifitseerimiskeskus
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+// GNU Lesser General Public Licence is available at
+// http://www.gnu.org/copyleft/lesser.html
+//==========< HISTORY >=============================
+// 26.04.2006 Veiko Sinivee
+// Creation
+//==================================================
+
+#include "DigiDocDefs.h"
+#include "DigiDocObj.h"
+#include "DigiDocMem.h"
+#include <openssl/x509.h>
+#include <openssl/ocsp.h>
+
+//==========< XML generation routines >========================
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// Holds info of an xml element used in signature format
+typedef struct XmlElemDef_st {
+ char* szTag; // element tag
+ char bMultiple; // 'Y' if multiple elements allowed, 'N' if not
+ void** pChildren; // list of children terminated by NULL
+} XmlElemDef;
+
+// Holds info of an xml element used in signature format
+typedef struct XmlElemInfo_st {
+ char* szId; // element tag
+ char* szTag; // element tag
+ void* pParent; // parent emenent info if exists
+ void** pChildren; // list of children terminated by NULL
+} XmlElemInfo;
+
+int XmlElemInfo_new(XmlElemInfo **ppXi, const char* id, const char* tag);
+
+void XmlElemInfo_free(XmlElemInfo* pXi);
+
+int XmlElemInfo_countChildren(XmlElemInfo* pXi);
+
+int XmlElemInfo_addChild(XmlElemInfo* pParent, XmlElemInfo* pChild);
+
+XmlElemInfo* XmlElemInfo_getRootElem(XmlElemInfo* pElem);
+
+// verifies files signature
+EXP_OPTION int verifyFileSignature(const char* szFileName, int nDigestType,
+ byte* pSigBuf, int nSigLen,
+ const char *certfile);
+
+
+// Compares two byte arrays and returns 0 for OK
+EXP_OPTION int compareByteArrays(const byte* dig1, int len1, const byte* dig2, int len2);
+
+// verifies one doc's check digests in this signature
+EXP_OPTION int verifySigDocDigest(const SignedDoc* pSigDoc, const SignatureInfo* pSigInfo,
+ const DocInfo* pDocInfo, const char* szDataFile);
+// verifies the mime digest of this doc in this signature
+EXP_OPTION int verifySigDocMimeDigest(const SignedDoc* pSigDoc, const SignatureInfo* pSigInfo,
+ const DocInfo* pDocInfo, const char* szFileName);
+
+// verifies this one signature
+EXP_OPTION int verifySignatureInfo(const SignedDoc* pSigDoc, const SignatureInfo* pSigInfo,
+ const char* signerCA, const char* szDataFile, int bUseCA);
+
+// verifies the whole document (returns on first err)
+EXP_OPTION int verifySigDoc(const SignedDoc* pSigDoc, const char* signerCA,
+ const char** caFiles, const char* caPath, const char* notCert,
+ const char* szDataFile, int bUseCA);
+
+
+// Verifies the certificates signed attributes
+EXP_OPTION int verifySigCert(const SignatureInfo* pSigInfo);
+
+
+// Verfies NotaryInfo signature
+EXP_OPTION int verifyNotaryInfo(const SignedDoc* pSigDoc, const SignatureInfo* pSigInfo,
+ const NotaryInfo* pNotInfo,
+ const char ** caFiles, const char *CApath, const char* notCertFile);
+
+// Verifies the certificates signed attributes
+EXP_OPTION int verifyNotCert(const SignatureInfo* pSigInfo, const NotaryInfo* pNotInfo);
+
+// Verfies NotaryInfo digest
+EXP_OPTION int verifyNotaryDigest(const SignedDoc* pSigDoc, const NotaryInfo* pNotInfo);
+
+// verifies signed doc
+EXP_OPTION int verifySigDocCERT(const SignedDoc* pSigDoc, const void* signerCA,
+ const X509** caCerts,
+ const char* caPath, const X509* notCert,
+ const char* szDataFile, int bUseCA);
+
+
+// Verifies this signature
+ EXP_OPTION int verifySignatureInfoCERT(const SignedDoc* pSigDoc,
+ const SignatureInfo* pSigInfo,
+ const void* signerCACert, const char* szDataFile, int bUseCA);
+
+// Checks if the cert has been signed by this CA-cert
+EXP_OPTION int isCertSignedByCERT(const X509* cert, const X509* caCert);
+
+
+// Verfies NotaryInfo signature
+EXP_OPTION int verifyNotaryInfoCERT(const SignedDoc* pSigDoc,
+ const SignatureInfo* pSigInfo,
+ const NotaryInfo* pNotInfo,
+ const X509** caCerts,
+ const char *CApath, const X509* notCert);
+
+//--------------------------------------------------
+// Verfies NotaryInfo signature
+// pSigDoc - signed doc object
+// pNotInfo - NotaryInfo object
+// caCerts - CA certificate pointer array terminated with NULL
+// CApath - path to (directory) all certs
+// notCertFile - Notary (e.g. OCSP responder) cert file
+// pSigCa - signers ca cert
+//--------------------------------------------------
+EXP_OPTION int verifyNotaryInfoCERT2(const SignedDoc* pSigDoc,
+ const SignatureInfo* pSigInfo,
+ const NotaryInfo* pNotInfo,
+ const X509** caCerts, const char *CApath,
+ const X509* notCert, const X509* pSigCa);
+
+EXP_OPTION int verifySigDocSigPropDigest(const SignatureInfo* pSigInfo);
+
+// Calculates the digest of NotaryInfo
+EXP_OPTION int calculateNotaryInfoDigest(const SignedDoc* pSigDoc,
+ const NotaryInfo* pNotInfo, byte* digBuf, int* digLen);
+
+int readTagContents(char** data, const char* fileName,
+ const char* tagName, int nAttrs,
+ const char** attNames, const char** attValues,
+ int withTags);
+
+ X509_ALGOR* setSignAlgorithm(const EVP_MD * type);
+
+int setup_verifyCERT(X509_STORE **newX509_STORE,
+ const char *CApath,
+ const X509** certs);
+
+EXP_OPTION int verifyEstIDSignature(const byte* digest, int digestLen, int nDigestType,
+ byte* pSigBuf, int nSigLen, X509* cert);
+EXP_OPTION int verifyEstIDSignature2(const byte* digest, int digestLen, int nDigestType,
+ byte* pSigBuf, int nSigLen, X509* cert);
+
+//===========================================================
+// Checks and records the knowledge if one signature had
+// missing xmlns problem
+// pSigDoc - signed doc data
+// returns 1 if at least one signature had this problem
+//============================================================
+EXP_OPTION int checkDdocWrongDigests(const SignedDoc* pSigDoc);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // __DIGIDOC_VERIFY_H__
+
+
diff --git a/libdigidoc/DlgUnit.c b/libdigidoc/DlgUnit.c
new file mode 100644
index 0000000..65a62fe
--- /dev/null
+++ b/libdigidoc/DlgUnit.c
@@ -0,0 +1,688 @@
+//==================================================
+// FILE: DlgUnit.c
+// PROJECT: Digi Doc
+// DESCRIPTION: Low-level built dialog with list selection capability
+// UPDATES:
+//
+// Created by Aare Amenberg 06/10/2003
+//==================================================
+// Copyright (C) AS Sertifitseerimiskeskus
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+// GNU Lesser General Public Licence is available at
+// http://www.gnu.org/copyleft/lesser.html
+//==================================================
+
+#include <libdigidoc/DigiDocDefs.h>
+#include <stdio.h>
+#include <windows.h>
+#include <commctrl.h>
+#include "DlgUnit.h"
+
+HINSTANCE hInstanceCOM = NULL;
+extern int RunDialogUnitSimple(char *psList[], char *psCaption, char *psHeader, char *psOkButton, char *psCancelButton, int iWinWidth, int iWinHeight);
+EXTERN_C IMAGE_DOS_HEADER __ImageBase;
+
+#define HINST_THISCOMPONENT ((HINSTANCE)&__ImageBase)
+//min and max sizes for dialog window
+#define dDLGWIN_MINWIDTH 170
+#define dDLGWIN_MAXWIDTH 800
+#define dDLGWIN_MINHEIGHT 150
+#define dDLGWIN_MAXHEIGHT 600
+
+//maximum items in the listbox
+//Developer can change the value
+#define dDLGMAXLISTBOXSIZE 1024
+//maximum item length
+//Developer can change the value
+#define dDLGMAXITEMSIZE 512
+
+//temporary messagebox buffer len
+#define dDLGTEMPBUFLEN 64
+
+//internal errors
+#define dDLGNOERRORS 0
+#define dDLGERROR -1
+#define dDLGNOSELECTION -9
+//output error
+#define dDLGERROR_OUT -2 //can't initiate dialog
+#define dDLGNOSELECTION_OUT -1 //no selection, cancel
+//if output result >= 0, then item is selected
+
+//User texts max length (headers,title,tooltips,etc.)
+#define dDLGUSERTEXTMAXLEN 128
+
+//Dialog functions
+static BOOL CALLBACK WndDlgUnitProc(HWND, UINT, WPARAM, LPARAM);
+static void CalculateDialogSize(HWND hDlg);
+static void SetDialogItemSize(HWND hWnd, int iWOffs, int iHOffs);
+static void SetDialogItemPosition(HWND hWnd, int iWOffs, int iHOffs);
+static void CenterDialogOnScreen(HWND hDlg, HWND hMain);
+static void Dialog_End(HWND hDlg, BOOL fCancel);
+static int Dialog_Init(HWND hDlg);
+static void DispError(char *psError);
+//ListView functions
+static BOOL ListViewSetHeaderColumn(HWND hWndList, int iIndex, int iSize, char *psHeader);
+static int ListViewCalcColumnSize(HWND hWndList, int iIndex, int iSizePercent);
+static BOOL ListViewInserRow(HWND hWndList, int iIndex, char *psVal1, char *psVal2, char *psVal3, char *psVal4, char *psVal5);
+static BOOL ListViewInsertItem(HWND hWndListView, int iIndex, char *psData);
+
+//Tooltip functions
+static void ToolTipInitiate(HWND hWndDlg);
+static HWND ToolTipCreate (HWND hParent);
+static void ToolTipForItem (HWND hwnd,char *psText,HWND hTip);
+
+//User defined texts
+static char sDlgCaption[dDLGUSERTEXTMAXLEN+1] ="DigiDoc";
+static char sGrpHeader[dDLGUSERTEXTMAXLEN+1] ="Select certificate:";
+static char sOkButtonText[dDLGUSERTEXTMAXLEN+1] ="&Ok";
+static char sCancelButtonText[dDLGUSERTEXTMAXLEN+1] ="&Cancel";
+//ListView headers
+static char sListColumn1[dDLGUSERTEXTMAXLEN+1] ="Issuer";
+static char sListColumn2[dDLGUSERTEXTMAXLEN+1] ="Friendly name";
+static char sListColumn3[dDLGUSERTEXTMAXLEN+1] ="Valid from";
+static char sListColumn4[dDLGUSERTEXTMAXLEN+1] ="Valid to";
+static char sListColumn5[dDLGUSERTEXTMAXLEN+1] ="CSP";
+//User defined tooltips
+static char sDlgToolTip[dDLGUSERTEXTMAXLEN+1] ="Certificate selection";
+static char sListToolTip[dDLGUSERTEXTMAXLEN+1] ="Selecting certificate press <Enter>\nor click <Ok> button\nor mouse double-click";
+static char sOkButtonToolTip[dDLGUSERTEXTMAXLEN+1] ="Select and close dialog";
+static char sCancelButtonToolTip[dDLGUSERTEXTMAXLEN+1]="Cancel selection";
+
+static char **psListItems=NULL; //Listbox items
+static HWND hToolTipWnd=NULL; //ToolTip window
+static int iDlgWidth = 800;
+static int iDlgHeight = 170;
+//
+//Set texts
+//
+//psCaption - dialog caption/title
+// if NULL, then no caption
+//psHeader - listbox header
+// if NULL, then no header
+//psOkButton - Ok button label
+// if NULL or zero length string, then "&Ok"
+//psCancelButton - Cancel button label
+// if NULL or zero length string, then "&Cancel"
+EXP_OPTION int DialogUnitSetTexts(char *psCaption, char *psHeader, char *psOkButton, char *psCancelButton)
+{
+if (psCaption != NULL)
+ lstrcpyn(sDlgCaption,psCaption,dDLGUSERTEXTMAXLEN);
+if (psHeader != NULL)
+ lstrcpyn(sGrpHeader,psHeader,dDLGUSERTEXTMAXLEN);
+if (psOkButton != NULL)
+ lstrcpyn(sOkButtonText,psOkButton,dDLGUSERTEXTMAXLEN);
+if (psCancelButton != NULL)
+ lstrcpyn(sCancelButtonText,psCancelButton,dDLGUSERTEXTMAXLEN);
+//if not specified, then Ok string
+if (lstrlen(sOkButtonText) == 0)
+ lstrcpy(sOkButtonText,"&Ok");
+//if not specified, then Ok string
+if (lstrlen(sCancelButtonText) == 0)
+ lstrcpy(sCancelButtonText,"&Cancel");
+return(0);
+}
+
+EXP_OPTION int DialogUnitSetHeaders(char *psCol1, char *psCol2, char *psCol3, char *psCol4, char *psCol5)
+{
+if (psCol1 != NULL)
+ lstrcpyn(sListColumn1,psCol1,dDLGUSERTEXTMAXLEN);
+if (psCol2 != NULL)
+ lstrcpyn(sListColumn2,psCol2,dDLGUSERTEXTMAXLEN);
+if (psCol3 != NULL)
+ lstrcpyn(sListColumn3,psCol3,dDLGUSERTEXTMAXLEN);
+if (psCol4 != NULL)
+ lstrcpyn(sListColumn4,psCol4,dDLGUSERTEXTMAXLEN);
+if (psCol5 != NULL)
+ lstrcpyn(sListColumn5,psCol5,dDLGUSERTEXTMAXLEN);
+return(0);
+}
+
+EXP_OPTION int DialogUnitSetToolTips(char *psCommon, char *psListView, char *psOkButton, char *psCancelButton)
+{
+if (psCommon != NULL)
+ lstrcpyn(sDlgToolTip,psCommon,dDLGUSERTEXTMAXLEN);
+else
+ sDlgToolTip[0] = 0;
+if (psListView != NULL)
+ lstrcpyn(sListToolTip,psListView,dDLGUSERTEXTMAXLEN);
+else
+ sListToolTip[0] = 0;
+if (psOkButton != NULL)
+ lstrcpyn(sOkButtonToolTip,psOkButton,dDLGUSERTEXTMAXLEN);
+else
+ sOkButtonToolTip[0] = 0;
+if (psCancelButton != NULL)
+ lstrcpyn(sCancelButtonToolTip,psCancelButton,dDLGUSERTEXTMAXLEN);
+else
+ sCancelButtonToolTip[0] = 0;
+return(0);
+}
+
+//
+//Dialog main function
+//
+//Limitations:
+// Max. items in the listbox dDLGMAXLISTBOXSIZE
+// Max. item size in the listbox dDLGMAXITEMSIZE
+// Dialogbox sizes dDLGWIN_* values
+//
+//No dynamic memory allocation
+//
+//Selection is accepted if, list item is selected and
+// - user pressed "Ok" button
+// - user double-clicks on the listbox item
+// - user pressed <Enter> key
+//
+//If no items in the psList or psList is NULL,
+//then Ok button is disabled
+//
+//psList - pointer arrays of listbox elements
+// last item must be NULL
+//psCaption - dialog caption/title
+// if NULL, then no caption
+//psHeader - listbox header
+// if NULL, then no header
+//psOkButton - Ok button label
+// if NULL or zero length string, then "&Ok"
+//psCancelButton - Cancel button label
+// if NULL or zero length string, then "&Cancel"
+
+//iWinWidth - dialogbox width, if 0 then default size
+//
+//iWinHeight - dialogbox height, if 0 then default size
+//
+//returns -2 (dDLGERROR_OUT) if dialog error
+//returns -1 (dDLGNOSELECTION_OUT) if listbox item not selected (Cancel button)
+// >=0 selected item index in the psList array
+//
+//
+int RunDialogUnit(char *psList[], int iWinWidth, int iWinHeight)
+{
+char sTemp[dDLGTEMPBUFLEN];
+DWORD dwRes;
+int iRes = dDLGERROR_OUT;
+INITCOMMONCONTROLSEX iccex;
+//LPTSTR lpName;
+//HRSRC hRes;
+//HGLOBAL hGlobal;
+iDlgWidth = iWinWidth;
+iDlgHeight = iWinHeight;
+//if not allowed value, then default size
+if (iDlgWidth < dDLGWIN_MINWIDTH || iDlgWidth > dDLGWIN_MAXWIDTH)
+ iDlgWidth = 0;
+//if not allowed value, then default size
+if (iDlgHeight < dDLGWIN_MINHEIGHT || iDlgHeight > dDLGWIN_MAXHEIGHT)
+ iDlgHeight = 0;
+//set items
+psListItems = psList;
+//Init common control
+iccex.dwICC = ICC_WIN95_CLASSES;
+iccex.dwSize = sizeof(INITCOMMONCONTROLSEX);
+if (InitCommonControlsEx(&iccex) == TRUE)
+//InitCommonControls();
+ {
+ //Starts dialog, return value from function Dialog_End
+ //hRes = FindResource(NULL,"#220", RT_DIALOG);
+ //hRes = FindResource(NULL,MAKEINTRESOURCE(IDD_DLG_UNIT), RT_DIALOG);
+ //hGlobal = LoadResource(NULL,hRes);
+ //dwRes = IDD_DLG_UNIT;
+ //lpName = MAKEINTRESOURCE(IDD_DLG_UNIT);
+
+ iRes = DialogBox(HINST_THISCOMPONENT, MAKEINTRESOURCE(IDD_DLG_UNIT), NULL, (DLGPROC)WndDlgUnitProc);
+ //iRes = DialogBox(hInstanceCOM, MAKEINTRESOURCE(IDD_DLG_UNIT), NULL, (DLGPROC)WndDlgUnitProc);
+
+ if (iRes == dDLGERROR)
+ iRes = dDLGERROR_OUT;
+ }
+
+//if GetLastError returns nonzero, then dialog opening error
+if (iRes == dDLGERROR_OUT)
+ {
+ dwRes = GetLastError();
+ if (dwRes != 0)
+ {
+ //prints Windows errorcode
+ snprintf(sTemp, sizeof(sTemp), "DigiDoc Dialog Error=%d",dwRes);
+ //DispError(sTemp);
+ }
+ #ifdef WIN32_CSP
+ iRes = RunDialogUnitSimple(psList, sDlgCaption, sGrpHeader, sOkButtonText, sCancelButtonText, iDlgWidth, iDlgHeight);
+ #endif
+ }
+if (iRes == dDLGNOSELECTION)
+ iRes = dDLGNOSELECTION_OUT;
+return(iRes);
+}
+
+
+//Dialog callback functions
+static BOOL CALLBACK WndDlgUnitProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
+{
+BOOL fRes = FALSE;
+DWORD dwNotifyCode;
+LPNMHDR pnmh;
+switch (message)
+ {
+ case WM_INITDIALOG:
+ //dialog init
+ Dialog_Init(hDlg);
+ fRes = TRUE;
+ break;
+ case WM_CLOSE:
+ //user closes dialog from the system menu
+ Dialog_End(hDlg, TRUE);
+ fRes = TRUE;
+ break;
+ case WM_NOTIFY:
+ pnmh = (LPNMHDR)lParam;
+ if (pnmh != NULL && pnmh->code == NM_DBLCLK)
+ {
+ Dialog_End(hDlg,FALSE);
+ fRes = TRUE;
+ }
+ break;
+ case WM_COMMAND:
+ {
+ dwNotifyCode = HIWORD(wParam);
+ //user presses dblclick in the listbox
+ if (dwNotifyCode == LBN_DBLCLK)
+ {
+ Dialog_End(hDlg,FALSE);
+ fRes = TRUE;
+ break;
+ }
+ switch (wParam)
+ {
+ case IDOK:
+ //user pressed OK button
+ Dialog_End(hDlg,FALSE);
+ fRes = TRUE;
+ break;
+ case IDCANCEL:
+ //user pressed Cancel button
+ Dialog_End(hDlg, TRUE);
+ fRes = TRUE;
+ break;
+ }
+ }
+ }
+return(fRes);
+}
+
+//Dialog end function
+//fCancel - TRUE, if user pressed Cancel button
+//
+static void Dialog_End(HWND hDlg, BOOL fCancel)
+{
+int iRes = dDLGNOSELECTION;
+//if TRUE, then always (dDLGNOSELECTION)
+if (fCancel == FALSE)
+ {
+ //if listbox item selected, then retuns selected item index
+ iRes = ListView_GetSelectionMark(GetDlgItem(hDlg,IDC_LISTVIEW));
+ }
+if (hToolTipWnd != NULL)
+ {
+ DestroyWindow(hToolTipWnd);
+ hToolTipWnd = NULL;
+ }
+EndDialog(hDlg, iRes);
+}
+
+
+//Dialog init
+//
+static int Dialog_Init(HWND hDlg)
+{
+int iRes = dDLGNOERRORS;
+UINT iState;
+UINT iMask;
+DWORD dwStyle;
+int iItems = 0;
+HWND hWndListView;
+//Set dialog caption
+SetWindowText(hDlg, (LPTSTR)sDlgCaption);
+//Set listbox header
+SetDlgItemText(hDlg,IDC_GROUPBOX,(LPTSTR)sGrpHeader);
+//Set Ok button label
+SetDlgItemText(hDlg,IDOK,(LPTSTR)sOkButtonText);
+//Set Cancel button label
+SetDlgItemText(hDlg,IDCANCEL,(LPTSTR)sCancelButtonText);
+//Calculate dialog size
+CalculateDialogSize(hDlg);
+//Center dialog
+CenterDialogOnScreen(hDlg,NULL);
+//Set topmost
+SetWindowPos(hDlg,HWND_TOPMOST,0,0,0,0,SWP_NOSIZE|SWP_NOMOVE);
+//Set ListView params
+hWndListView = GetDlgItem(hDlg,IDC_LISTVIEW);
+dwStyle = (LVS_EX_FULLROWSELECT | LVS_EX_HEADERDRAGDROP);
+SendMessage(hWndListView,LVM_SETEXTENDEDLISTVIEWSTYLE,0,dwStyle);
+//
+ToolTipInitiate(hDlg);
+ToolTipForItem (GetDlgItem(hDlg,IDOK), sOkButtonToolTip, hToolTipWnd);
+ToolTipForItem (GetDlgItem(hDlg,IDCANCEL), sCancelButtonToolTip, hToolTipWnd);
+ToolTipForItem (hWndListView, sListToolTip, hToolTipWnd);
+ToolTipForItem (hDlg, sDlgToolTip, hToolTipWnd);
+ToolTipForItem (ListView_GetHeader(hWndListView), sDlgToolTip, hToolTipWnd);
+//
+//Set ListView headers
+ListViewSetHeaderColumn(hWndListView, 0, 25, sListColumn1);
+ListViewSetHeaderColumn(hWndListView, 1, 25, sListColumn2);
+ListViewSetHeaderColumn(hWndListView, 2, 15, sListColumn3);
+ListViewSetHeaderColumn(hWndListView, 3, 15, sListColumn4);
+ListViewSetHeaderColumn(hWndListView, 4, 20, sListColumn5);
+//Set ListView rows
+while (psListItems != NULL && *psListItems != NULL && iItems < dDLGMAXLISTBOXSIZE)
+ {
+ if (lstrlen(*psListItems) < dDLGMAXITEMSIZE)
+ {
+ ListViewInsertItem(hWndListView,iItems,*psListItems);
+ ++iItems;
+ }
+ else
+ iRes = dDLGERROR;
+ ++psListItems;
+ }
+if (iRes != dDLGNOERRORS)
+ DispError("DigiDoc Dialog data error");
+if (iItems > 0)
+ {
+ EnableWindow(GetDlgItem(hDlg, IDOK),TRUE);
+ iState = LVIS_FOCUSED | LVIS_SELECTED;
+ iMask = LVIS_FOCUSED | LVIS_SELECTED;
+ ListView_SetItemCount(hWndListView,iItems);
+ ListView_SetItemState(hWndListView, 0, iState, iMask);
+ //iState = ListView_GetItemCount(hWndListView);
+ //iMask = ListView_GetNextItem(hWndListView,-1,LVNI_FOCUSED);
+ //SetFocus(hWndList);
+ }
+else
+ EnableWindow(GetDlgItem(hDlg, IDOK),FALSE);
+return(iRes);
+}
+
+//Parse \t separated texts and add to the ListView
+static BOOL ListViewInsertItem(HWND hWndListView, int iIndex, char *psData)
+{
+BOOL fRes = TRUE;
+int iI=0;
+char sVal[5][dDLGMAXITEMSIZE+1];
+char *psBeg;
+char *psEnd;
+sVal[0][0] = 0;
+sVal[1][0] = 0;
+sVal[2][0] = 0;
+sVal[3][0] = 0;
+sVal[4][0] = 0;
+psBeg = psData;
+while (psBeg != NULL && *psBeg != 0)
+ {
+ psEnd = strchr(psBeg,'\t');
+ if (psEnd != NULL)
+ {
+ lstrcpyn(sVal[iI],psBeg,(psEnd-psBeg)+1);
+ psBeg=psEnd+1;
+ }
+ else
+ {
+ lstrcpyn(sVal[iI],psBeg,dDLGMAXITEMSIZE);
+ break;
+ }
+ ++iI;
+ }
+//
+ListViewInserRow(hWndListView, iIndex, sVal[0], sVal[1], sVal[2], sVal[3], sVal[4]);
+return(fRes);
+}
+
+//Calculate dialog size
+//
+static void CalculateDialogSize(HWND hDlg)
+{
+RECT rcDlg; // Dialog window rect
+int iWOffs;
+int iHOffs;
+if (iDlgWidth > 0 && iDlgHeight > 0)
+ {
+ GetWindowRect(hDlg,&rcDlg);
+ iWOffs = iDlgWidth - (rcDlg.right - rcDlg.left);
+ iHOffs = iDlgHeight - (rcDlg.bottom - rcDlg.top);
+ SetDialogItemSize(hDlg,iWOffs,iHOffs);
+ SetDialogItemSize(GetDlgItem(hDlg,IDC_LISTVIEW),iWOffs,iHOffs);
+ SetDialogItemSize(GetDlgItem(hDlg,IDC_GROUPBOX),iWOffs,iHOffs);
+ SetDialogItemPosition(GetDlgItem(hDlg,IDOK),iWOffs,iHOffs);
+ SetDialogItemPosition(GetDlgItem(hDlg,IDCANCEL),iWOffs,iHOffs);
+ }
+}
+
+//Set dialog item size
+//
+static void SetDialogItemSize(HWND hWnd, int iWOffs, int iHOffs)
+{
+RECT rcItm; // Dialog window rect
+int iWidth, iHeight; // Width and height
+GetWindowRect(hWnd, &rcItm);
+iWidth = rcItm.right - rcItm.left;
+iHeight = rcItm.bottom - rcItm.top;
+SetWindowPos(hWnd,NULL,0,0,iWidth+iWOffs, iHeight+iHOffs,SWP_NOMOVE|SWP_NOZORDER);
+}
+
+//Set dialog item pos
+//
+static void SetDialogItemPosition(HWND hWnd, int iWOffs, int iHOffs)
+{
+RECT rcCln;
+RECT rcItm; // Dialog item rect
+RECT rcParent; // Parent item rect
+int iLeft;
+int iTop;
+int iTitleW;
+// GetWindowRect retrieves screen coordinates
+GetWindowRect(hWnd, &rcItm);
+//GetClientRect(hWnd, &rcItm);
+//Changed by A.Amenberg 27.06.2003
+//GetAncestor supported from Win98 and WinNT SP4
+//GetWindowRect(GetAncestor(hWnd, GA_PARENT), &rcParent);
+GetWindowRect(GetParent(hWnd), &rcParent);
+GetClientRect(GetParent(hWnd), &rcCln);
+iTitleW = rcParent.bottom - rcCln.bottom;
+// for SetWindowPos we need left and right on PARENT.
+iLeft = (rcItm.left - rcParent.left) + iWOffs;
+iTop = (rcItm.top - rcParent.top) + iHOffs - iTitleW;
+// move, don't resize
+SetWindowPos(hWnd, NULL, iLeft, iTop, 0, 0, SWP_NOSIZE|SWP_NOZORDER);
+}
+
+//Center dialog
+//hMain - parent window, if NULL, then center in desktop
+//
+static void CenterDialogOnScreen(HWND hDlg, HWND hMain)
+{
+RECT rcParent; // Parent window client rect
+RECT rcDlg; // Dialog window rect
+int iLeft, iTop; // Top-left coordinates
+int iWidth, iHeight; // Width and height
+HWND hwnd;
+// Get frame window client rect in screen coordinates
+if (hMain == NULL)
+ hwnd = GetDesktopWindow();
+else
+ hwnd = hMain;
+GetWindowRect(hwnd, &rcParent);
+// Determine the top-left point for the dialog to be centered
+GetWindowRect(hDlg, &rcDlg);
+iWidth = rcDlg.right - rcDlg.left;
+iHeight = rcDlg.bottom - rcDlg.top;
+iLeft = rcParent.left + (((rcParent.right - rcParent.left) - iWidth ) / 2);
+iTop = rcParent.top + (((rcParent.bottom - rcParent.top ) - iHeight) / 2);
+if (iLeft < 0)
+ iLeft = 0;
+if (iTop < 0)
+ iTop = 0;
+// Place the dialog
+MoveWindow(hDlg, iLeft, iTop, iWidth, iHeight, TRUE);
+}
+
+//Error messagebox
+//
+static void DispError(char *psError)
+{
+MessageBox(NULL,psError, "Dialog Unit Error",MB_OK|MB_SYSTEMMODAL|MB_ICONERROR);
+}
+
+
+static BOOL ListViewSetHeaderColumn(HWND hWndList, int iIndex, int iSize, char *psHeader)
+{
+BOOL fRes = TRUE;
+LV_COLUMN lvC;
+lvC.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM;
+lvC.fmt = LVCFMT_LEFT; //LVCFMT_CENTER;
+lvC.cx = ListViewCalcColumnSize(hWndList,iIndex,iSize);
+lvC.pszText = psHeader;
+lvC.iSubItem = iIndex;
+if (ListView_InsertColumn (hWndList, iIndex, &lvC) == -1)
+ fRes = FALSE;
+return(fRes);
+}
+
+static int ListViewCalcColumnSize(HWND hWndList, int iIndex, int iSizePercent)
+{
+RECT rcRec;
+int iListSize;
+int iUsedSize=0;
+int iRes;
+int iI;
+double dPercUnit;
+GetClientRect(hWndList, &rcRec);
+iListSize = rcRec.right;
+for(iI=0; iI < iIndex;++iI)
+ iUsedSize+=ListView_GetColumnWidth(hWndList,iI);
+if (iIndex < 4)
+ {
+ dPercUnit = (double)iListSize/(double)100;
+ iRes = (int)((double)iSizePercent*dPercUnit);
+ }
+else
+ iRes = iListSize-iUsedSize;
+return(iRes);
+}
+
+static BOOL ListViewInserRow(HWND hWndList, int iIndex, char *psVal1, char *psVal2, char *psVal3, char *psVal4, char *psVal5)
+{
+BOOL fRes = TRUE;
+LV_ITEM lvI;
+lvI.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_PARAM | LVIF_STATE;
+lvI.state = 0;
+lvI.stateMask = 0;
+lvI.iItem = iIndex;
+lvI.iSubItem = 0;
+lvI.pszText = "";
+lvI.cchTextMax = 200;
+if (ListView_InsertItem (hWndList, &lvI) == -1)
+ fRes = FALSE;
+ListView_SetItemText (hWndList, iIndex, 0, psVal1);
+ListView_SetItemText (hWndList, iIndex, 1, psVal2);
+ListView_SetItemText (hWndList, iIndex, 2, psVal3);
+ListView_SetItemText (hWndList, iIndex, 3, psVal4);
+ListView_SetItemText (hWndList, iIndex, 4, psVal5);
+return(fRes);
+}
+
+static void ToolTipInitiate(HWND hWndDlg)
+{
+if (hToolTipWnd == NULL)
+ {
+ hToolTipWnd = ToolTipCreate(hWndDlg);
+ SendMessage(hToolTipWnd,TTM_SETMAXTIPWIDTH,0,300);
+ }
+}
+
+static HWND ToolTipCreate (HWND hParent)
+{
+HWND hWnd = CreateWindowEx(WS_EX_TOPMOST,
+ TOOLTIPS_CLASS,
+ NULL,
+ WS_POPUP | TTS_NOPREFIX | TTS_ALWAYSTIP,
+ CW_USEDEFAULT,
+ CW_USEDEFAULT,
+ CW_USEDEFAULT,
+ CW_USEDEFAULT,
+ hParent,
+ NULL,
+ NULL, //oPrm.hAppInstance,
+ NULL
+ );
+
+ SetWindowPos(hWnd,
+ HWND_TOPMOST,
+ 0,
+ 0,
+ 0,
+ 0,
+ SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
+SendMessage(hWnd,TTM_SETMAXTIPWIDTH,0,300);
+return(hWnd);
+}
+
+static void ToolTipForItem (HWND hwnd, char *psText, HWND hTip)
+{
+HWND hWnd = hTip;
+ // struct specifying info about tool in ToolTip control
+ TOOLINFO ti;
+ unsigned int uid = 0; // for ti initialization
+ LPTSTR lptstr = (LPTSTR)psText;
+ RECT rect; // for client area coordinates
+
+ /* GET COORDINATES OF THE MAIN CLIENT AREA */
+ GetClientRect (hwnd, &rect);
+
+ /* INITIALIZE MEMBERS OF THE TOOLINFO STRUCTURE */
+ ti.cbSize = sizeof(TOOLINFO);
+ ti.uFlags = TTF_SUBCLASS;
+ //ti.uFlags = 0;
+ ti.hwnd = hwnd;
+ ti.hinst = NULL; //oPrm.hAppInstance;
+ ti.uId = uid;
+ ti.lpszText = lptstr;
+ // ToolTip control will cover the whole window
+ ti.rect.left = rect.left;
+ ti.rect.top = rect.top;
+ ti.rect.right = rect.right;
+ ti.rect.bottom = rect.bottom;
+if (hWnd == NULL)
+ hWnd = hToolTipWnd;
+ /* SEND AN ADDTOOL MESSAGE TO THE TOOLTIP CONTROL WINDOW */
+SendMessage(hWnd, TTM_ADDTOOL, 0, (LPARAM) (LPTOOLINFO) &ti);
+}
+
+
+EXP_OPTION int RunDialogTestLow(void)
+{
+int iRes = 0;
+/*
+int iI;
+int iT = 0;
+char *psTemp;
+char sTemp[5000];
+char sVal[128];
+*/
+char sTest[] = {'\x8E','\x9e','\x8A','\x9A','\x00'};
+char *aCertList[] =
+{
+NULL,
+"11111111111111111111111111111111111111111\t222\t333\t4444\t5555",
+"11111111111111111111111111111111111111111\t222\t333\t4444\t5555",
+"11111111111111111111111111111111111111111\t222\t333\t4444\t5555",
+NULL};
+aCertList[0]=sTest;
+iRes = RunDialogUnit(aCertList, 500, 300);
+return(iRes);
+}
diff --git a/libdigidoc/DlgUnit.h b/libdigidoc/DlgUnit.h
new file mode 100644
index 0000000..47a589e
--- /dev/null
+++ b/libdigidoc/DlgUnit.h
@@ -0,0 +1,3 @@
+#define IDD_DLG_UNIT 220
+#define IDC_GROUPBOX 201
+#define IDC_LISTVIEW 202
diff --git a/libdigidoc/DlgUnit.manifest b/libdigidoc/DlgUnit.manifest
new file mode 100644
index 0000000..dde17d8
--- /dev/null
+++ b/libdigidoc/DlgUnit.manifest
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
+<assemblyIdentity
+ version="1.0.0.0"
+ processorArchitecture="X86"
+ name="TestDlg.exe"
+ type="win32"
+/>
+<description>TestDlg</description>
+<dependency>
+ <dependentAssembly>
+ <assemblyIdentity
+ type="win32"
+ name="Microsoft.Windows.Common-Controls"
+ version="6.0.0.0"
+ processorArchitecture="X86"
+ publicKeyToken="6595b64144ccf1df"
+ language="*"
+ />
+ </dependentAssembly>
+</dependency>
+</assembly>
+
diff --git a/libdigidoc/DlgUnit.rc b/libdigidoc/DlgUnit.rc
new file mode 100644
index 0000000..97dd01e
--- /dev/null
+++ b/libdigidoc/DlgUnit.rc
@@ -0,0 +1,134 @@
+//Microsoft Developer Studio generated resource script.
+//
+#include "resource.h"
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+#define APSTUDIO_HIDDEN_SYMBOLS
+#include "windows.h"
+#undef APSTUDIO_HIDDEN_SYMBOLS
+#include "dlgunit.h"
+
+/////////////////////////////////////////////////////////////////////////////
+#undef APSTUDIO_READONLY_SYMBOLS
+
+/////////////////////////////////////////////////////////////////////////////
+// Unknown language: 0x25, 0x1 resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ETI)
+#ifdef _WIN32
+LANGUAGE 0x25, 0x1
+#pragma code_page(1257)
+#endif //_WIN32
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Dialog
+//
+
+IDD_DLG_UNIT DIALOGEX 0, 0, 300, 155
+STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "DigiDoc"
+FONT 8, "MS Sans Serif", 0, 0, 0x1
+BEGIN
+ DEFPUSHBUTTON "&OK",IDOK,240,136,50,14
+ GROUPBOX "Downloads:",IDC_GROUPBOX,2,2,296,126
+ PUSHBUTTON "&Cancel",IDCANCEL,180,136,50,14
+ CONTROL "List1",IDC_LISTVIEW,"SysListView32",LVS_REPORT |
+ LVS_SINGLESEL | LVS_SHOWSELALWAYS | LVS_AUTOARRANGE |
+ WS_BORDER | WS_TABSTOP,6,12,288,110,WS_EX_CLIENTEDGE
+END
+
+
+#ifdef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// TEXTINCLUDE
+//
+
+1 TEXTINCLUDE DISCARDABLE
+BEGIN
+ "resource.h\0"
+END
+
+2 TEXTINCLUDE DISCARDABLE
+BEGIN
+ "#define APSTUDIO_HIDDEN_SYMBOLS\r\n"
+ "#include ""windows.h""\r\n"
+ "#undef APSTUDIO_HIDDEN_SYMBOLS\r\n"
+ "#include ""dlgunit.h""\r\n"
+ "\0"
+END
+
+3 TEXTINCLUDE DISCARDABLE
+BEGIN
+ "\r\n"
+ "\0"
+END
+
+#endif // APSTUDIO_INVOKED
+
+
+#ifndef _MAC
+/////////////////////////////////////////////////////////////////////////////
+//
+// Version
+//
+
+VS_VERSION_INFO VERSIONINFO
+ FILEVERSION 2,7,1,56
+ PRODUCTVERSION 2,7,1,56
+ FILEFLAGSMASK 0x3fL
+#ifdef _DEBUG
+ FILEFLAGS 0x1L
+#else
+ FILEFLAGS 0x0L
+#endif
+ FILEOS 0x40004L
+ FILETYPE 0x2L
+ FILESUBTYPE 0x0L
+BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+ BLOCK "042504b0"
+ BEGIN
+ VALUE "Comments", "\0"
+ VALUE "CompanyName", "AS Sertifitseerimiskeskus\0"
+ VALUE "FileDescription", "DigiDocLib\0"
+ VALUE "FileVersion", "2.7.1.56\0"
+ VALUE "InternalName", "DigiDocLib\0"
+ VALUE "LegalCopyright", "Copyright 2010\0"
+ VALUE "LegalTrademarks", "\0"
+ VALUE "OriginalFilename", "DigiDocLib.dll\0"
+ VALUE "PrivateBuild", "\0"
+ VALUE "ProductName", "AS Sertifitseerimiskeskus DigiDocLib\0"
+ VALUE "ProductVersion", "2.7.1.56\0"
+ VALUE "SpecialBuild", "\0"
+ END
+ END
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation", 0x425, 1200
+ END
+END
+
+#endif // !_MAC
+
+#endif // Unknown language: 0x25, 0x1 resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+
+
+/////////////////////////////////////////////////////////////////////////////
+#endif // not APSTUDIO_INVOKED
+
diff --git a/libdigidoc/DlgUnitS.c b/libdigidoc/DlgUnitS.c
new file mode 100644
index 0000000..ec585ec
--- /dev/null
+++ b/libdigidoc/DlgUnitS.c
@@ -0,0 +1,476 @@
+//==================================================
+// FILE: DlgUnitS.c
+// PROJECT: Digi Doc
+// DESCRIPTION: Low-level built dialog with list selection capability
+// Simple dialog
+// 09/10/2003 Changed by AA
+//==================================================
+// Copyright (C) AS Sertifitseerimiskeskus
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+// GNU Lesser General Public Licence is available at
+// http://www.gnu.org/copyleft/lesser.html
+//==================================================
+
+#include <stdio.h>
+#include <windows.h>
+//#include <libdigidoc/DigiDocDefs.h>
+//Control ID's
+#define IDD_DLG_UNIT 1000
+#define IDC_GROUPBOX 1001
+#define IDC_LISTVIEW 1002
+
+//min and max sizes for dialog window
+#define dDLGWIN_MINWIDTH 170
+#define dDLGWIN_MAXWIDTH 800
+#define dDLGWIN_MINHEIGHT 150
+#define dDLGWIN_MAXHEIGHT 600
+
+//maximum items in the listbox
+//Developer can change the value
+#define dDLGMAXLISTBOXSIZE 1024
+//maximum item length
+//Developer can change the value
+#define dDLGMAXITEMSIZE 512
+
+//temporary messagebox buffer len
+#define dDLGTEMPBUFLEN 64
+#define dDLGNOSELECTION -2
+#define dDLGERROR -1
+
+static BOOL CALLBACK WndDlgUnitProc(HWND, UINT, WPARAM, LPARAM);
+static void CalculateDialogSize(HWND hDlg);
+static void SetDialogItemSize(HWND hWnd, int iWOffs, int iHOffs);
+static void SetDialogItemPosition(HWND hWnd, int iWOffs, int iHOffs);
+static void SetDialogItemPosition_Old(HWND hWnd, int iWOffs, int iHOffs);
+static void CenterDialogOnScreen(HWND hDlg, HWND hMain);
+static void Dialog_End(HWND hDlg, BOOL fCancel);
+static void Dialog_Init(HWND hDlg);
+static void DispError(char *psError);
+static LPWORD lpwAlign (LPWORD lpIn);
+static BOOL Dialog_Create(void);
+
+
+static HGLOBAL hgbl; //Dialog template
+static char *psDlgCaption=NULL; //Dialog Title
+static char *psGrpHeader=NULL; //Groupbox Header
+static char *psOkButtonText=NULL; //Ok button label
+static char *psCancelButtonText=NULL; //Cancel button label
+static char **psListItems=NULL; //Listbox items
+static int iDlgWidth = 800;
+static int iDlgHeight = 170;
+//
+//Dialog main function
+//
+//Limitations:
+// Max. items in the listbox dDLGMAXLISTBOXSIZE
+// Max. item size in the listbox dDLGMAXITEMSIZE
+// Dialogbox sizes dDLGWIN_* values
+//
+//No dynamic memory allocation
+//
+//Selection is accepted if, list item is selected and
+// - user pressed "Ok" button
+// - user double-clicks on the listbox item
+// - user pressed <Enter> key
+//
+//If no items in the psList or psList is NULL,
+//then Ok button is disabled
+//
+//psList - pointer arrays of listbox elements
+// last item must be NULL
+//psCaption - dialog caption/title
+// if NULL, then no caption
+//psHeader - listbox header
+// if NULL, then no header
+//psOkButton - Ok button label
+// if NULL or zero length string, then "&Ok"
+//psCancelButton - Cancel button label
+// if NULL or zero length string, then "&Cancel"
+//iWinWidth - dialogbox width, if 0 then default size
+//
+//iWinHeight - dialogbox height, if 0 then default size
+//
+//returns -1 (dDLGNOSELECTION) if listbox item not selected (Cancel button)
+// >=0 selected item index in the psList array
+//
+//
+int RunDialogUnitSimple(char *psList[], char *psCaption, char *psHeader, char *psOkButton, char *psCancelButton, int iWinWidth, int iWinHeight)
+{
+char sTemp[dDLGTEMPBUFLEN];
+DWORD dwRes;
+int iRes = dDLGNOSELECTION;
+//Set global data
+psDlgCaption = psCaption;
+psGrpHeader = psHeader;
+psOkButtonText = psOkButton;
+psCancelButtonText = psCancelButton;
+iDlgWidth = iWinWidth;
+iDlgHeight = iWinHeight;
+//if not allowed value, then default size
+if (iDlgWidth < dDLGWIN_MINWIDTH || iDlgWidth > dDLGWIN_MAXWIDTH)
+ iDlgWidth = 0;
+//if not allowed value, then default size
+if (iDlgHeight < dDLGWIN_MINHEIGHT || iDlgHeight > dDLGWIN_MAXHEIGHT)
+ iDlgHeight = 0;
+//if not specified, then empty string
+if (psDlgCaption == NULL)
+ psDlgCaption = "";
+//if not specified, then empty string
+if (psGrpHeader == NULL)
+ psGrpHeader = "";
+//if not specified, then Ok string
+if (psOkButtonText == NULL || lstrlen(psOkButtonText) == 0)
+ psOkButtonText = "&Ok";
+//if not specified, then Ok string
+if (psCancelButtonText == NULL || lstrlen(psCancelButtonText) == 0)
+ psCancelButtonText = "&Cancel";
+//set items
+psListItems = psList;
+//Starts dialog, return value from function Dialog_End
+
+if (Dialog_Create() == TRUE)
+ iRes = DialogBoxIndirect(NULL, (LPDLGTEMPLATE) hgbl, GetActiveWindow(), (DLGPROC) WndDlgUnitProc);
+else
+ iRes = dDLGERROR;
+//iRes = DialogBox(NULL, MAKEINTRESOURCE(IDD_DLG_UNIT), NULL,(DLGPROC)WndDlgUnitProc);
+//if GetLastError returns nonzero, then dialog opening error
+if (iRes == dDLGERROR)
+ {
+ dwRes = GetLastError();
+ if (dwRes != 0)
+ {
+ //prints Windows errorcode
+ _snprintf(sTemp, sizeof(sTemp), "Windows Error=%d",dwRes);
+ DispError(sTemp);
+ }
+ }
+if (iRes == dDLGNOSELECTION)
+ iRes = dDLGERROR;
+if (hgbl != NULL)
+ GlobalFree(hgbl);
+return(iRes);
+}
+
+
+//Dialog callback functions
+static BOOL CALLBACK WndDlgUnitProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
+{
+BOOL fRes = FALSE;
+DWORD dwNotifyCode;
+switch (message)
+ {
+ case WM_INITDIALOG:
+ //dialog init
+ Dialog_Init(hDlg);
+ fRes = TRUE;
+ break;
+ case WM_CLOSE:
+ //user closes dialog from the system menu
+ Dialog_End(hDlg, TRUE);
+ fRes = TRUE;
+ break;
+ case WM_COMMAND:
+ {
+ dwNotifyCode = HIWORD(wParam);
+ //user presses dblclick in the listbox
+ if (dwNotifyCode == LBN_DBLCLK)
+ {
+ Dialog_End(hDlg,FALSE);
+ fRes = TRUE;
+ break;
+ }
+ switch (wParam)
+ {
+ case IDOK:
+ //user pressed OK button
+ Dialog_End(hDlg,FALSE);
+ fRes = TRUE;
+ break;
+ case IDCANCEL:
+ //user pressed Cancel button
+ Dialog_End(hDlg, TRUE);
+ fRes = TRUE;
+ break;
+ }
+ }
+ }
+return(fRes);
+}
+
+//Dialog end function
+//fCancel - TRUE, if user pressed Cancel button
+//
+static void Dialog_End(HWND hDlg, BOOL fCancel)
+{
+int iRes = dDLGNOSELECTION;
+int iSelection;
+//if TRUE, then always returns -1 (dDLGNOSELECTION)
+if (fCancel == FALSE)
+ {
+ //if listbox item selected, then retuns selected item index
+ iSelection = SendMessage(GetDlgItem(hDlg,IDC_LISTVIEW), LB_GETCURSEL,0,0);
+ if (iSelection != LB_ERR)
+ iRes = iSelection;
+ }
+EndDialog(hDlg, iRes);
+}
+
+
+//Dialog init
+//
+static void Dialog_Init(HWND hDlg)
+{
+int iItems = 0;
+BOOL fError = FALSE;
+HWND hWndLst = GetDlgItem(hDlg,IDC_LISTVIEW);
+//Set dialog caption
+SetWindowText(hDlg, (LPTSTR)psDlgCaption);
+//Set listbox header
+SetDlgItemText(hDlg,IDC_GROUPBOX,(LPTSTR)psGrpHeader);
+//Set Ok button label
+SetDlgItemText(hDlg,IDOK,(LPTSTR)psOkButtonText);
+//Set Cancel button label
+SetDlgItemText(hDlg,IDCANCEL,(LPTSTR)psCancelButtonText);
+//Calculate dialog size
+CalculateDialogSize(hDlg);
+//Center dialog
+CenterDialogOnScreen(hDlg,NULL);
+//Deletes listbox
+SendMessage(hWndLst, LB_RESETCONTENT, 0, 0);
+//Set hor scrollbar
+SendMessage(hWndLst, LB_SETHORIZONTALEXTENT, 1200,0);
+//Add items to the listbox
+while (psListItems != NULL && *psListItems != NULL && iItems < dDLGMAXLISTBOXSIZE)
+ {
+ if (lstrlen(*psListItems) < dDLGMAXITEMSIZE)
+ {
+ SendMessage(hWndLst, LB_ADDSTRING, 0, (LONG) (LPTSTR)*psListItems);
+ ++iItems;
+ }
+ else
+ fError = TRUE;
+ ++psListItems;
+ }
+if (fError == TRUE)
+ DispError("Listbox item error");
+//if at least one item, then select first item
+if (iItems > 0)
+ {
+ EnableWindow(GetDlgItem(hDlg, IDOK),TRUE);
+ SendMessage(hWndLst, LB_SETCURSEL, 0, (LONG) 0);
+ }
+else
+ EnableWindow(GetDlgItem(hDlg, IDOK),FALSE);
+}
+
+//Calculate dialog size
+//
+static void CalculateDialogSize(HWND hDlg)
+{
+
+RECT rcDlg; // Dialog window rect
+int iWOffs, iHOffs; // Offsets
+if (iDlgWidth > 0 && iDlgHeight > 0)
+ {
+ GetWindowRect(hDlg, &rcDlg);
+ iWOffs = iDlgWidth - (rcDlg.right - rcDlg.left);
+ iHOffs = iDlgHeight - (rcDlg.bottom - rcDlg.top);
+ SetDialogItemSize(hDlg,iWOffs,iHOffs);
+ SetDialogItemSize(GetDlgItem(hDlg,IDC_LISTVIEW),iWOffs,iHOffs);
+ SetDialogItemSize(GetDlgItem(hDlg,IDC_GROUPBOX),iWOffs,iHOffs);
+ SetDialogItemPosition(GetDlgItem(hDlg,IDOK),iWOffs,iHOffs);
+ SetDialogItemPosition(GetDlgItem(hDlg,IDCANCEL),iWOffs,iHOffs);
+ }
+}
+
+//Set dialog item size
+//
+static void SetDialogItemSize(HWND hWnd, int iWOffs, int iHOffs)
+{
+RECT rcItm; // Dialog window rect
+int iWidth, iHeight; // Width and height
+GetWindowRect(hWnd, &rcItm);
+iWidth = rcItm.right - rcItm.left;
+iHeight = rcItm.bottom - rcItm.top;
+SetWindowPos(hWnd,NULL,0,0,iWidth+iWOffs, iHeight+iHOffs,SWP_NOMOVE|SWP_NOZORDER);
+}
+
+//Set dialog item pos
+//Not in use
+static void SetDialogItemPosition_Old(HWND hWnd, int iWOffs, int iHOffs)
+{
+RECT rcItm; // Dialog window rect
+int iLeft, iTop; // Left and top
+int iWidth, iHeight; // Width and height
+GetWindowRect(hWnd, &rcItm);
+iWidth = rcItm.right - rcItm.left;
+iHeight= rcItm.bottom - rcItm.top;
+iLeft = rcItm.left+iWOffs;
+iTop = rcItm.top+iHOffs-20;
+SetWindowPos(hWnd,NULL,iLeft,iTop,iWidth,iHeight,SWP_NOZORDER);
+}
+
+//Set dialog item pos
+//
+static void SetDialogItemPosition(HWND hWnd, int iWOffs, int iHOffs)
+{
+RECT rcItm; // Dialog item rect
+RECT rcParent; // Parent item rect
+int iLeft, iTop; // Left and top
+// GetWindowRect retrieves screen coordinates
+GetWindowRect(hWnd, &rcItm);
+//Changed by A.Amenberg 27.06.2003
+//GetAncestor supported from Win98 and WinNT SP4
+//GetWindowRect(GetAncestor(hWnd, GA_PARENT), &rcParent);
+GetWindowRect(GetParent(hWnd), &rcParent);
+// for SetWindowPos we need left and right on PARENT.
+iLeft = (rcItm.left - rcParent.left) + iWOffs;
+iTop = (rcItm.top - rcParent.top) + iHOffs - 20; // subtract titlebar height
+// move, don't resize
+SetWindowPos(hWnd, NULL, iLeft, iTop, 0, 0, SWP_NOSIZE|SWP_NOZORDER);
+}
+
+//Center dialog
+//hMain - parent window, if NULL, then center in desktop
+//
+static void CenterDialogOnScreen(HWND hDlg, HWND hMain)
+{
+RECT rcParent; // Parent window client rect
+RECT rcDlg; // Dialog window rect
+int iLeft, iTop; // Top-left coordinates
+int iWidth, iHeight; // Width and height
+HWND hwnd;
+// Get frame window client rect in screen coordinates
+if (hMain == NULL)
+ hwnd = GetDesktopWindow();
+else
+ hwnd = hMain;
+GetWindowRect(hwnd, &rcParent);
+// Determine the top-left point for the dialog to be centered
+GetWindowRect(hDlg, &rcDlg);
+iWidth = rcDlg.right - rcDlg.left;
+iHeight = rcDlg.bottom - rcDlg.top;
+iLeft = rcParent.left + (((rcParent.right - rcParent.left) - iWidth ) / 2);
+iTop = rcParent.top + (((rcParent.bottom - rcParent.top ) - iHeight) / 2);
+if (iLeft < 0)
+ iLeft = 0;
+if (iTop < 0)
+ iTop = 0;
+// Place the dialog
+MoveWindow(hDlg, iLeft, iTop, iWidth, iHeight, TRUE);
+}
+
+//Error messagebox
+//
+static void DispError(char *psError)
+{
+MessageBox(NULL,psError, "Dialog Unit Error",MB_OK|MB_SYSTEMMODAL|MB_ICONERROR);
+}
+
+
+
+//Helper routine. Take an input pointer, return closest
+//pointer that is aligned on a DWORD (4 byte) boundary.
+//
+static LPWORD lpwAlign (LPWORD lpIn)
+{
+ULONG ul;
+ul = (ULONG) lpIn;
+ul +=3;
+ul >>=2;
+ul <<=2;
+return((LPWORD)ul);
+}
+
+
+static BOOL Dialog_Create(void)
+{
+BOOL fRes = FALSE;
+LPDLGTEMPLATE lpdt;
+LPDLGITEMTEMPLATE lpdit;
+LPWORD lpw;
+LPWSTR lpwsz;
+int nchar;
+hgbl = GlobalAlloc(GMEM_ZEROINIT, 1024);
+if (hgbl == NULL)
+ return(fRes);
+lpdt = (LPDLGTEMPLATE)GlobalLock(hgbl);
+// Define a dialog box.
+lpdt->style = WS_POPUP | WS_BORDER | WS_SYSMENU | DS_MODALFRAME | WS_CAPTION | DS_SETFONT;
+lpdt->cdit = 4; // number of controls
+lpdt->x = 0; lpdt->y = 0;
+lpdt->cx = 205; lpdt->cy = 204;
+lpw = (LPWORD) (lpdt + 1);
+*lpw++ = 0; // no menu
+*lpw++ = 0; // predefined dialog box class (by default)
+*lpw++ = 0; // no caption text
+*lpw++ = 0x0008; // font size
+lpwsz = (LPWSTR) lpw;
+nchar = 1+ MultiByteToWideChar (CP_ACP, 0, "MS Sans Serif", -1, lpwsz, 50);
+lpw += nchar;
+
+// Define an OK button.
+lpw = lpwAlign (lpw);
+lpdit = (LPDLGITEMTEMPLATE) lpw;
+lpdit->x = 152; lpdit->y = 182;
+lpdit->cx = 50; lpdit->cy = 14;
+lpdit->id = IDOK; // OK button identifier
+lpdit->style = WS_CHILD | WS_VISIBLE | BS_DEFPUSHBUTTON | WS_TABSTOP;
+lpw = (LPWORD) (lpdit + 1);
+*lpw++ = 0xFFFF;
+*lpw++ = 0x0080; // button class
+*lpw++ = 0x0000; // no caption
+*lpw++ = 0; // no creation data
+// Define a Cancel button.
+lpw = lpwAlign (lpw);
+lpdit = (LPDLGITEMTEMPLATE) lpw;
+lpdit->x = 97; lpdit->y = 182;
+lpdit->cx = 50; lpdit->cy = 14;
+lpdit->id = IDCANCEL; //Cancel button identifier
+lpdit->style = WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON | WS_TABSTOP;
+lpw = (LPWORD) (lpdit + 1);
+*lpw++ = 0xFFFF;
+*lpw++ = 0x0080; // button class atom
+*lpw++ = 0x0000; // no caption
+*lpw++ = 0; // no creation data
+// Define a groupbox control.
+lpw = lpwAlign (lpw);
+lpdit = (LPDLGITEMTEMPLATE) lpw;
+lpdit->x = 0; lpdit->y = 2;
+lpdit->cx = 205; lpdit->cy = 173;
+lpdit->id = IDC_GROUPBOX; // groupbox identifier
+lpdit->style = BS_GROUPBOX | WS_VISIBLE;
+lpw = (LPWORD) (lpdit + 1);
+*lpw++ = 0xFFFF;
+*lpw++ = 0x0080; // listbox
+*lpw++ = 0x0000; // no caption
+*lpw++ = 0; // no creation data
+// Define a listbox control.
+lpw = lpwAlign (lpw);
+lpdit = (LPDLGITEMTEMPLATE) lpw;
+lpdit->x = 4; lpdit->y = 12;
+lpdit->cx = 197; lpdit->cy = 158;
+lpdit->id = IDC_LISTVIEW; // listbox identifier
+lpdit->style = LBS_USETABSTOPS | LBS_NOTIFY | WS_CHILD | WS_VISIBLE | WS_VSCROLL | WS_HSCROLL | WS_TABSTOP | LBS_NOINTEGRALHEIGHT | WS_BORDER;
+lpw = (LPWORD) (lpdit + 1);
+*lpw++ = 0xFFFF;
+*lpw++ = 0x0083; // listbox
+*lpw++ = 0x0000; // no caption
+//if caption exist, delete previous line and remove next 3 lines comments
+//lpwsz = (LPWSTR) lpw;
+//nchar = 1+MultiByteToWideChar (CP_ACP, 0, "", -1, lpwsz, 50);
+//lpw += nchar;
+*lpw++ = 0; // no creation data
+GlobalUnlock(hgbl);
+fRes = TRUE;
+return(fRes);
+}
+
+
diff --git a/libdigidoc/cdigidoc.1.cmake b/libdigidoc/cdigidoc.1.cmake
new file mode 100644
index 0000000..effe492
--- /dev/null
+++ b/libdigidoc/cdigidoc.1.cmake
@@ -0,0 +1,244 @@
+.TH CDIGIDOC 1 "${BUILD_DATE}" "${VERSION}" "cdigidoc man page"
+.SH NAME
+cdigidoc \- read, digitally sign, verify files in XAdES format and encrypt, decrypt files in XMLENC format
+.SH SYNOPSIS
+.B cdigidoc <command(s)> [
+.I -in <input-file>
+.B ] [
+.I -out <output-file>
+.B ] [
+.I -config <config-file>
+.B ]
+.SH DESCRIPTION
+.B cdigidoc
+is an utility which provides a command line interface to the CDigiDoc library, which is a library in C programming language offering the the functionality to create files in supported DigiDoc formats, sigitally sign the DigiDoc files using smart cards or other supported cryptographic tokens, add time marks and validity confirmations to digital signatures using OCSP protocol, verify the digital signatures, and digitally encrypt and decrypt the DigiDoc files. It is also possible to use cdigidoc utility as a CGI program in web applications created in environments that cannot easily use the JDigiDoc library or call the DigiDocService webservice for digital signature functionality.
+.PP
+For full documentation, see
+.nf
+https://svn.eesti.ee/projektid/idkaart_public/branches/3.6/libdigidoc/doc/SK-CDD-PRG-GUIDE.pdf
+.PP
+XAdES format
+.nf
+http://www.w3.org/TR/XAdES
+.PP
+XML-ENC format
+http://www.w3.org/TR/xmlenc-core
+.SH OPTIONS
+.IP "-?, -help"
+Displays help about command syntax.
+.IP "-in <input-file>"
+Specifies the input file name. It is recommended to pass the full path to the file in this parameter.
+.IP "-out <output-file>"
+Stores the newly created or modified document in a file.
+.IP "-config <configuration-file>"
+Specifies the CDigiDoc configuration file name. If left unspecified, then the configuration file is looked up from default locations.
+.IP "-check-cert <certificate-file-in-pem-format>"
+Checks the certificate validity status. Used for checking the chosen certificate’s validity; returns an OCSP response from the certificate’s CA’s OCSP responder. Note that the command is currently not being tested. If the certificate is valid, then the return code’s (RC) value is 0.
+.IP "-new [format] [version]"
+Creates a new digidoc container with the specified format and version. The current digidoc format in CDigiDoc library is DIGIDOC-XML, default version is 1.3 (newest). By using the optional parameter - version - with this command, you can specify an alternative version to be created. Note: the older SK-XML format is supported only for backward compatibility.
+.IP "-add <input-file> <mime-type> [<content-type>] [<charset>]"
+Adds a new data file to a digidoc document. If digidoc doesn't exist then creates one in the default format.
+.RS
+.TP
+Input file (required)
+Specifies the name of the data file (it is recommended to include full path in this parameter; the path is removed when writing to DigiDoc container file).
+.TP
+Mime type (required)
+Represents the MIME type of the original file like "text/plain" or "application/msword".
+.TP
+Content type
+Reflects how the original files are embedded in the container EMBEDDED_BASE64 (used by default).
+In previous versions cdigidoc allowed content type EMBEDDED to sign pure xml or text.
+.TP
+Charset
+UTF-8 encoding is supported and used by default.
+.RE
+.IP "-sign <pin-code> [[[manifest] [[city] [state] [zip] [country]] [slot(0)] [ocsp(1)] [token-type(PKCS11)] [pkcs12-file-name]]"
+Adds a digital signature to the digidoc document. You can use it with following parameters:
+.RS
+.TP
+pin code
+In case of Estonian ID cards, pin code2 is used for digital signing. If signing with a software token (PKCS#12 file), then the password of PKCS#12 file should be entered here.
+.TP
+manifest
+Role or resolution of the signer
+.TP
+city
+City where the signature is created
+.TP
+state
+State or province where the signature is created
+.TP
+zip
+Postal code of the place where the signature is created
+.TP
+country
+Country of origin. ISO 3166-type 2-character country codes are used (e.g. EE)
+.TP
+slot
+Identifier of the signer’s private key’s slot on a smartcard. When operating for example with a single Estonian ID card, its signature key can be found in slot 1 - which is used by default.
+The library makes some assumptions about PKCS#11 drivers and card layouts:
+ - you have signature and/or authentication keys on the card
+ - both key and certificate are in one slot
+ - if you have many keys like 1 signature and 1 authentication key then they are in different slots
+ - you can sign with signature key that has a corresponding certificate with "NonRepudiation" bit set.
+You may need to specify a different slot to be used when for example operating with multiple smart cards on the same system.
+If the slot needs to be specified during signing, then the 5 previous optional parameters (manifest, city, state, zip, country) should be filled first (either with the appropriate data or as "" for no value).
+.TP
+ocsp
+Specifies whether an OCSP confirmation is added to the signature that is being created. Possible values are 0 - confirmation is not added; 1 - confirmation is added. By default, the value is set to 1.
+Parameter value 0 can be used when creating a technical signature. Technical signature is a signature with no OCSP confirmation and no timestamp value.
+.TP
+token type
+Speciafies type of signature token to be use.
+ - PKCS11 default value. Signs with a smart-card or software pkcs11 token
+ - CNG on windows platforms uses CSP/CNG for signing
+ - PKCS12 signs with a PKCS#12 key container that must be entered in the next parameter
+. TP
+pkcs12 file name
+Name of the PKCS#12 key container file to be used for signing.
+.RE
+.IP "-mid-sign <phone-no> <per-code> [[<country>(EE)] [<lang>(EST)] [<service>(Testing)] [<manifest>] [<city> <state> <zip>]]"
+Invokes mobile signing of a ddoc file using Mobile-ID and DigiDocService.
+Mobile-ID is a service based on Wireless PKI providing for mobile authentication and digital signing, currently supported by all Estonian and some Lithuanian mobile operators.
+The Mobile-ID user gets a special SIM card with private keys on it. Hash to be signed is sent over the GSM network to the phone and the user shall enter PIN code to sign. The signed result is sent back over the air.
+DigiDocService is a SOAP-based web service, access to the service is IP-based and requires a written contract with provider of DigiDocService.
+You can use Mobile-ID signing with the following parameters:
+.RS
+.TP
+phone-no
+Phone number of the signer with the country code in format +xxxxxxxxx (for example +3706234566)
+.TP
+per-code
+Identification number of the signer (personal national ID number).
+.TP
+country
+Country of origin. ISO 3166-type 2-character country codes are used (e.g. default is EE)
+.TP
+lang
+Language for user dialog in mobile phone. 3-character capitalized acronyms are used (e.g. default is EST)
+.TP
+service
+Name of the service – previously agreed with Application Provider and DigiDocService operator. Maximum length – 20 chars. (e.g. default is Testing)
+.TP
+manifest
+Role or resolution of the signer
+.TP
+city
+City where the signature is created
+.TP
+state
+State or province where the signature is created
+.TP
+zip
+Postal code of the place where the signature is created
+.RE
+.IP "-list"
+Displays the data file and signature info of a DigiDoc document just read in; verifies all signatures.
+.RS
+.HP
+Returns Digidoc container data, in format: SignedDoc | <format-identifier> | <version>
+.HP
+List of all data files, in format: DataFile | <file identifier> | <file name> | <file size in bytes> | <mime type> | <data file embedding option>
+.HP
+List of all signatures (if existing), in format: Signature | <signature identifier> | <signer’s key info: last name, first name, personal code> | <verification return code> | <verification result>
+.HP
+Signer’s certificate information.
+.HP
+OCSP responder certificate information
+.RE
+.IP "-verify"
+Returns signature verification results (if signatures exist):
+.RS
+.HP
+Signature | <signature identifier> | <signer’s key info: last name, first name, personal code> | <verification return code> | <verification result>
+.HP
+Returns signer’s certificate and OCSP Responder certificate information.
+.RE
+.IP "-extract <data-file-id> <output-file>"
+Extracts the selected data file from the DigiDoc container and stores it in a file.
+Data file id represents the ID for data file to be extracted from inside the DigiDoc container (e.g. D0, D1…). Output file represents the name of the output file.
+
+.IP "-denc-list <input-encrypted-file>"
+Displays the encrypted data and recipient’s info of an encrypted document just read in.
+.IP "-encrecv <certificate-file> [recipient] [KeyName] [CarriedKeyName]"
+Adds a new recipient certificate and other metadata to an encrypted document. Certificate file (required) specifies the file from which the public key component is fetched for encrypting the data. The decryption can be performed only by using private key corresponding to that certificate. The input certificate files for encryption must come from the file system (PEM encodings are supported). Possible sources where the certificate files can be obtained from include: Windows Certificate Store ("Other Persons"), LDAP directories, ID-card in smart-card reader. For example the certificate files for Estonian ID card owners can be retrieved from a LDAP directory at ldap://ldap.sk.ee. The query can be made in following format through the web browser (IE): ldap://ldap.sk.ee:389/c=EE??sub?(serialNumber= xxxxxxxxxxx) where serial Number is the recipient’s personal identification number, e,g.38307240240).
+Other parameters include:
+.RS
+.TP
+recipient
+If left unspecified, then the program assigns the CN value of the certificate passwed as first parameter.
+This is later used as a command line option to identify the recipient whose key and smart card is used to decrypt the data.
+Note:
+Although this parameter is optional, it is recommended to pass on the entire CN value from the recipient’s certificate as the recipient identifier here, especially when dealing with multiple recipients.
+.TP
+KeyName
+Sub-element <KeyName> can be added to better identify the key object. Optional, but can be used to search for the right recipient’s key or display its data in an application.
+.TP
+CarriedKeyName
+Sub-element <CarriedKeyName> can be added to better identify the key object. Optional, but can be used to search for the right recipient’s key or display its data in an application.
+.RE
+
+.IP "-encrypt-sk <input-file>"
+Encrypts the data from the given input file and writes the completed encrypted document in a file. Recommended for providing cross-usability with other DigiDoc software components.
+This command places the data file to be encrypted in a new DigiDoc container. Therefore handling such encrypted documents later with other DigiDoc applications is fully supported (e.g. DigiDoc3 client).
+Input file (required) specifies the original data file to be encrypted.
+Note: There are also alternative encryption commands which are however not recommended for providing cross-usability with other DigiDoc software components:
+.RS
+.TP
+.I "-encrypt <input-file>"
+Encrypts the data from the given input file and writes the completed encrypted document in a file. Should be used only for encrypting small documents, already in DIGIDOC-XML format.
+Input file (required) specifies the original data file to be encrypted.
+.TP
+.I "-encrypt-file <input-file> <output-file>"
+Encrypts the input file and writes to output file. Should be used only for encrypting large documents, already in DIGIDOC-XML format. Note that the command in not currently tested.
+Input file (required) specifies the original data file to be encrypted.
+Output file (required) specifies the name of the output file which will be created in the current encrypted document format (ENCDOC-XML ver 1.0), with file extension .cdoc.
+.RE
+.IP "-decrypt-sk <input-file> <pin> [pkcs12-file] [slot(0)]"
+Decrypts and possibly decompresses the encrypted file just read in and writes to output file. Expects the encrypted file to be inside a DigiDoc container.
+Input file (required) specifies the input file’s name.
+Pin (required) represents the recipient’s pin1 (in context of Estonian ID cards).
+pkcs12-file (optional) specifies the PKCS#12 file if decrypting is done with a software token.
+slot default is slot 0 containing Estonian ID cards authentication keypair. This parameter can be used to decrypt with a key from the second id card attached to the computer etc.
+Note: There are also alternative commands for decryption, depending on the encrypted file’s format, size and the certificate type used for decrypting it.
+.RS
+.TP
+.I "-decrypt <input-file> <pin> [pkcs12-file] [slot(0)]"
+Offers same functionality as -decrypt-sk, should be used for decrypting small files (which do not need to be inside a DigiDoc container).
+Input file (required) specifies the input file’s name.
+Pin (required) represents the recipient’s pin1 (in contexts of Estonian ID cards).
+pkcs12-file (optional) specifies the PKCS#12 file if decrypting is done with a software token.
+slot default is slot 0 containing Estonian ID cards authentication keypair. This parameter can be used to decrypt with a key from the second id card attached to the computer etc.
+.TP
+.I "-decrypt-file <input-file> <output-file> <pin> [pkcs12-file]"
+Offers same functionality as -decrypt for decrypting documents, should be used for decrypting large files (which do not need to be inside a DigiDoc container). Expects the encrypted data not to be compressed. Note that the command is not currently tested.
+Input file (required) specifies the encrypted file to be decrypted.
+Output file (required) specifies the output file name.
+Pin (required) represents the recipient’s pin1 (in contexts of Estonian ID cards).
+pkcs12-file (optional) specifies the PKCS#12 file if decrypting is done with a software token.
+.RE
+.IP "-calc-sign <cert-file> [<manifest>] [<city> <state> <zip> <country>]"
+Offers an alternative to \-sign command to be used in CGI pograms. Adds signers certificate in pem format and optionally manifest and signers address and calculates the final hash value to be signed. This value is hex-encoded and can now be sent to users computer to be signed using a web plugin. This command creates an incomplete signature that lacks the actual RSA signature value. It must be stored in a temporary file and later completed using the \-add-sign-value command.
+-IP "-add-sign-value <sign-value-file> <sign-id>"
+Offers an alternative to \-sign command to be used in CGI pograms. Adds an RSA signature hex-encoded value to an incomplete signature created using the \-calc-sign command. This signature is still lacking the ocsp timemark, that can now be obtained using the \-get-confirmation command producing a complete XAdES signature.
+.IP "-get-confirmation <signature-id>"
+Adds an OCSP confirmation to a DigiDoc file’s signature.
+.SH EXAMPLES
+.IP "cdigidoc -new DIGIDOC-XML 1.3 -add <input-file> <mime> -sign <pin2> -out <output-file>
+Creates a new signed document in DIGIDOC-XML 1.3 format, adds one input file, signs with smartcard using the default signature slot and writes to a signed document file.
+.IP "cdigidoc -in <signed-input-file> -list"
+Reads in a signed document, verifies signatures and prints the results to console.
+.IP "cdigidoc -in <signed-input-file> -extract D0 <output-file>"
+Reads in a signed document, finds the first signed document and writes it to output file.
+.IP "cdigidoc -encrecv <recipient1.pem> -encrecv <recipient2.pem> -encrypt-sk <file-to-encrypt> -out <output-file.cdoc>"
+Creates a new encypted file by encrypting input file that is encrypted using AES-128 and encrypts the generated randome transport key using RSA for two possible recipients identified by their certificates. Transport key is encrypted using RSA1.5.
+.IP "cdigidoc -decrypt-sk <input-file.cdoc> <pin1> -out <output-file>"
+Reads in encrypted file and decrypts it with smartcards first keypair (Estonian ID cards authentication key) and writes decrypted data to given putput file.
+.IP "cdigidoc -decrypt-sk <input-file.cdoc> <password> <keyfile.p12d> -out <output-file>"
+Reads in encrypted file and decrypts it with a PKCS#12 key-container and writes decrypted data to given putput file.
+
+.SH AUTHORS
+.B AS Sertifitseerimiskeskus (Certification Centre Ltd.)
+.SH "SEE ALSO"
+digidoc-tool(1), qesteidutil(1), qdigidocclient(1), qdigidoccrypto(1)
diff --git a/libdigidoc/cdigidoc.c b/libdigidoc/cdigidoc.c
new file mode 100644
index 0000000..49e0988
--- /dev/null
+++ b/libdigidoc/cdigidoc.c
@@ -0,0 +1,2559 @@
+//==================================================
+// FILE: digidoc.c
+// PROJECT: Digi Doc
+// DESCRIPTION: Utility program to demonstrate the
+// functionality of DigiDocLib
+// AUTHOR: Veiko Sinivee, S|E|B IT Partner Estonia
+//==================================================
+// Copyright (C) AS Sertifitseerimiskeskus
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+// GNU Lesser General Public Licence is available at
+// http://www.gnu.org/copyleft/lesser.html
+//==========< HISTORY >=============================
+// 12.01.2004 Veiko Sinivee
+// Creation
+//==================================================
+
+#include "config.h"
+#include <libdigidoc/DigiDocDefs.h>
+#include <libdigidoc/DigiDocLib.h>
+#include <libdigidoc/DigiDocConfig.h>
+#include <libdigidoc/DigiDocPKCS11.h>
+#include <libdigidoc/DigiDocSAXParser.h>
+#include <libdigidoc/DigiDocParser.h>
+#include <libdigidoc/DigiDocEncSAXParser.h>
+#include <libdigidoc/DigiDocEnc.h>
+#include <libdigidoc/DigiDocEncGen.h>
+#include <libdigidoc/DigiDocConvert.h>
+#include <libdigidoc/DigiDocDebug.h>
+#include <libdigidoc/DigiDocCert.h>
+#include <libdigidoc/DigiDocObj.h>
+#include <libdigidoc/DigiDocGen.h>
+#include <libdigidoc/DigiDocService.h>
+#include <libdigidoc/DigiDocDfExtract.h>
+
+#ifdef WIN32
+ #define snprintf _snprintf
+ #include <wchar.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <openssl/objects.h>
+#include <sys/stat.h>
+#include <time.h>
+
+//==========< global constants >====================
+
+// programm arguments
+char* p_szInFile = 0;
+char* p_szInEncFile = 0;
+char* p_szInDecFile = 0;
+char* p_szOutFile = 0;
+char* p_szConfigFile = 0;
+int p_parseMode = 1, g_nLibErrors = 0;
+
+int g_cgiMode = 1; // 1=output in CGI mode, 0=normal e.g. human readable mode
+char* g_szOutputSeparator = 0;
+char *errorClass[] = {"NO_ERRORS", "TECHNICAL", "USER", "LIBRARY"};
+char* g_szProgNameVer = "cdigidoc/"DIGIDOC_VERSION;
+
+//==========< forward defs >========================
+
+void printErrorsAndWarnings(SignedDoc* pSigDoc);
+
+//==========< helper functions for argument handling >====================
+
+
+
+//--------------------------------------------------
+// Handles one argument
+//--------------------------------------------------
+int checkArguments(int argc, char** argv, int* pCounter, char** dest)
+{
+ int nLen = 0;
+
+ if(argc > (*pCounter)+1 && argv[(*pCounter)+1][0] != '-') {
+ nLen = strlen(argv[(*pCounter)+1]) * 2;
+ ddocConvertInput((const char*)argv[(*pCounter)+1], dest);
+ (*pCounter)++;
+ }
+ return nLen;
+}
+
+//--------------------------------------------------
+// checks the existence of one command line argument
+//--------------------------------------------------
+int hasCmdLineArg(int argc, char** argv, const char* argName)
+{
+ int i;
+
+ for(i = 1; i < argc; i++) {
+ if(argv[i] != NULL && argv[i][0] == '-' &&
+ !strcmp(argv[i], argName)) {
+ return i;
+ }
+ }
+ return 0;
+}
+
+//--------------------------------------------------
+// Returns the value of one command line argument
+//--------------------------------------------------
+int checkCmdLineArg(int argc, char** argv, const char* argName, char** dest)
+{
+ int i;
+
+ *dest = 0; // mark as not found
+ for(i = 1; i < argc; i++) {
+ if(argv[i] != NULL && argv[i][0] == '-' &&
+ !strcmp(argv[i], argName)) {
+ if((i + 1 < argc) && (argv[i+1][0] != '-')) {
+ ddocConvertInput((const char*)argv[i+1], dest);
+ return 0;
+ }
+ else
+ return ERR_BAD_PARAM;
+ }
+ }
+ return 0; // not found but no error
+}
+
+//--------------------------------------------------
+// prints usage statement
+//--------------------------------------------------
+void printUsage()
+{
+ fprintf(stderr, "USAGE: cdigidoc <command(s)> [-in <input-file>] [-out <output-file>] [-config <config-file>]\n");
+ fprintf(stderr, "COMMANDS:\n");
+ fprintf(stderr, "\t[-new] \n");
+ fprintf(stderr, "\t-check-cert <-cerificate-file-name (PEM format)>\n");
+ fprintf(stderr, "\t-add <file-name> <mime-type> [<content-type>] [<charset>]\n");
+ fprintf(stderr, "\t-verify \n");
+ fprintf(stderr, "\t-sign <pin> [[[<manifest>] [<city> <state> <zip> <country>]] [slot(0)] [ocsp(1)] [PKCS11/CNG/PKCS12] [pkcs12-file-name]]\n");
+ fprintf(stderr, "\t-extract <doc-id> <file-name> [<charset>] [<file-name-charset>]\n");
+ fprintf(stderr, "\t-encrypt <file-name>\n");
+ fprintf(stderr, "\t-encrypt-sk <file-name>\n");
+ fprintf(stderr, "\t-encrecv <cert-file> [<recipient>] [<keyname>] [<carried-key-name>]\n");
+ fprintf(stderr, "\t-decrypt <file-name> <pin1> [pkcs12-file] [slot(0)]\n");
+ fprintf(stderr, "\t-decrypt-sk <file-name> <pin1> [pkcs12-file] [slot(0)]\n");
+ fprintf(stderr, "\t-denc-list <file-name>\n");
+ fprintf(stderr, "\t-encrypt-file <in-file-name> <out-file-name> [<in-file-mime-type>]\n");
+ fprintf(stderr, "\t-decrypt-file <in-file-name> <out-file-name> <pin1> [pkcs12-file]\n");
+
+ fprintf(stderr, "\t-calc-sign <cert-file> [<manifest>] [<city> <state> <zip> <country>]\n");
+ fprintf(stderr, "\t-add-sign-value <sign-value-file> <sign-id>\n");
+ fprintf(stderr, "\t-del-sign <sign-id>\n");
+ fprintf(stderr, "\t-get-confirmation <sign-id>\n");
+
+ fprintf(stderr, "\t-mid-sign <phone-no> <per-code> [[<country>(EE)] [<lang>(EST)] [<service>(Testing)] [<manifest>] [<city> <state> <zip>]]\n");
+ fprintf(stderr, "\t-mid-test <input-data-file> <input-mime-type> <output-ddoc> <phone-no> <per-code> [<service> (Testimine)]\n");
+
+ fprintf(stderr, "\t-in-mem <file-name>\n");
+ fprintf(stderr, "\t-add-mem <file-name> <mime-type> [<content-type>]\n");
+ fprintf(stderr, "\t-out-mem <file-name>\n");
+ fprintf(stderr, "\t-extract-mem <doc-id> <file-name>\n");
+
+ fprintf(stderr, "OPTIONS:\n");
+ fprintf(stderr, "\t-cgimode [<ouput-separator] - output in CGI mode\n");
+ fprintf(stderr, "\t-consolemode - output in console (not cgi) mode\n");
+ fprintf(stderr, "\t-SAX - use SAX parser\n");
+ fprintf(stderr, "\t-libraryerrors - show all errors sent by library\n");
+ fprintf(stderr, "\t-XRDR - use XmlReader parser\n");
+}
+
+//--------------------------------------------------
+// Checks program runtime arguments
+//--------------------------------------------------
+int checkProgArguments(int argc, char** argv)
+{
+ int err = ERR_OK;
+
+ // -?, -help -> print usage
+ if(!err && (hasCmdLineArg(argc, argv, "-?") ||
+ hasCmdLineArg(argc, argv, "-help")))
+ printUsage();
+ // -in <input-file>
+ if(!err)
+ if((err = checkCmdLineArg(argc, argv, "-in", &p_szInFile)) != ERR_OK)
+ addError(err, __FILE__, __LINE__, "Missing or invalid input file name");
+ // -in-mem <input-file>
+ if(!err && hasCmdLineArg(argc, argv, "-in-mem")) {
+ if((err = checkCmdLineArg(argc, argv, "-in-mem", &p_szInFile)) != ERR_OK)
+ addError(err, __FILE__, __LINE__, "Missing or invalid input file name");
+ p_parseMode = 3;
+ }
+ // -SAX -> use Sax parser (default)
+ if(!err)
+ if(hasCmdLineArg(argc, argv, "-SAX"))
+ p_parseMode = 1;
+ // -SAX -> use Sax parser (default)
+ if(!err)
+ if(hasCmdLineArg(argc, argv, "-XRDR"))
+ p_parseMode = 2;
+ // -libraryerrors
+ if(!err)
+ if(hasCmdLineArg(argc, argv, "-libraryerrors"))
+ g_nLibErrors = 1;
+ // -out <out-file>
+ if(!err)
+ if((err = checkCmdLineArg(argc, argv, "-out", &p_szOutFile)) != ERR_OK)
+ addError(err, __FILE__, __LINE__, "Missing or invalid output file name");
+ if(!err && hasCmdLineArg(argc, argv, "-out-mem")) {
+ if((err = checkCmdLineArg(argc, argv, "-out-mem", &p_szOutFile)) != ERR_OK)
+ addError(err, __FILE__, __LINE__, "Missing or invalid output file name");
+ p_parseMode = 3;
+ }
+ // -encrypt <encryption-input-file>
+ if(!err && hasCmdLineArg(argc, argv, "-encrypt"))
+ if((err = checkCmdLineArg(argc, argv, "-encrypt", &p_szInEncFile)) != ERR_OK)
+ addError(err, __FILE__, __LINE__, "Missing or invalid encrypt input file name");
+ // -encrypt-sk <encryption-input-file>
+ if(!err && hasCmdLineArg(argc, argv, "-encrypt-sk"))
+ if((err = checkCmdLineArg(argc, argv, "-encrypt-sk", &p_szInEncFile)) != ERR_OK)
+ addError(err, __FILE__, __LINE__, "Missing or invalid encrypt input file name");
+ // -config <config-file>
+ if(!err)
+ if((err = checkCmdLineArg(argc, argv, "-config", &p_szConfigFile)) != ERR_OK)
+ addError(err, __FILE__, __LINE__, "Missing or invalid configuration file name");
+ // -CGI -> use CGI output mode
+ if(!err)
+ if(hasCmdLineArg(argc, argv, "-cgimode")) {
+ g_cgiMode = 1;
+ if((err = checkCmdLineArg(argc, argv, "-cgimode", &g_szOutputSeparator)) != ERR_OK)
+ addError(err, __FILE__, __LINE__, "Missing or invalid cgi output separator");
+ if(!g_szOutputSeparator || !g_szOutputSeparator[0] || err) {
+ g_szOutputSeparator = strdup("|");
+ err = ERR_OK;
+ }
+ }
+ if(hasCmdLineArg(argc, argv, "-consolemode")) {
+ g_cgiMode = 0;
+ }
+ return err;
+}
+
+//--------------------------------------------------
+// reads various statusflags from config file
+//--------------------------------------------------
+void readConfigParams()
+{
+ int n = 0;
+ const char* s = 0;
+
+ // check if we are in CGI mode
+ n = ConfigItem_lookup_bool("DIGIDOC_CGI_MODE", 0);
+ if(!g_cgiMode && n)
+ g_cgiMode = n;
+
+ s = ConfigItem_lookup("DIGIDOC_CGI_SEPARATOR");
+ if(!g_szOutputSeparator && s)
+ g_szOutputSeparator = (char*)strdup(s);
+ if(!g_szOutputSeparator || !g_szOutputSeparator[0]) {
+ if(g_szOutputSeparator) free(g_szOutputSeparator);
+ g_szOutputSeparator = strdup("|");
+ }
+}
+
+
+//==========< command handlers >====================
+
+//--------------------------------------------------
+// Creates a new signed doc
+//--------------------------------------------------
+int cmdNew(SignedDoc** ppSigDoc, const char* pFormat, const char* pVersion)
+{
+ int err = ERR_OK;
+ const char* format = pFormat, *version = pVersion;
+
+ if(!p_szOutFile) {
+ err = ERR_BAD_PARAM;
+ addError(err, __FILE__, __LINE__, "No output file specified");
+ return err;
+ }
+ if(!format)
+ format = "DIGIDOC-XML";
+ if(!version)
+ version = "1.3";
+ if(format && version) {
+ err = SignedDoc_new(ppSigDoc, format, version);
+ RETURN_IF_NOT(err == ERR_OK, err);
+ } else {
+ err = ERR_UNSUPPORTED_FORMAT;
+ addError(err, __FILE__, __LINE__, "Error finding new document format or version");
+ }
+ return err;
+}
+
+
+
+//--------------------------------------------------
+// Adds a DataFile to signed doc
+//--------------------------------------------------
+int cmdAddDataFile(SignedDoc** ppSigDoc, const char* file,
+ const char* mime, const char* content, const char* charset)
+{
+ int err = ERR_OK, l1;
+ DataFile *pDataFile;
+ char *p = 0, buf1[300];
+
+ // if there was no new command then implicitly create a new document
+ if(!(*ppSigDoc)) {
+ err = cmdNew(ppSigDoc, NULL, NULL);
+ RETURN_IF_NOT(err == ERR_OK, err);
+ }
+ // convert to UTF-8
+ err = ddocConvertInput(file, &p);
+ l1 = sizeof(buf1);
+ getFullFileName(p, buf1, l1);
+ freeLibMem(p);
+ // add a file
+ err = DataFile_new(&pDataFile, *ppSigDoc, NULL, buf1,
+ content, mime, 0, NULL, 0, NULL, charset);
+ if(!err)
+ err = calculateDataFileSizeAndDigest(*ppSigDoc, pDataFile->szId, buf1, DIGEST_SHA1);
+
+ RETURN_IF_NOT(err == ERR_OK, err);
+ return err;
+}
+
+//--------------------------------------------------
+// Create digidoc and adds datafiles
+//--------------------------------------------------
+int runAddCmds(int argc, char** argv, SignedDoc** ppSigDoc)
+{
+ int err = ERR_OK, i;
+
+ for(i = 1; (err == ERR_OK) && (i < argc); i++) {
+ if(argv[i][0] == '-') { // all commands and options must start with -
+ // create new digidoc
+ if(!strcmp(argv[i], "-new")) {
+ char* format = NULL;
+ char* version = NULL;
+ // optional content and charset
+ checkArguments(argc, argv, &i, &format);
+ checkArguments(argc, argv, &i, &version);
+ //printf("format: %s version: %s\n", format, version);
+ err = cmdNew(ppSigDoc, format, version);
+ freeLibMem(format);
+ freeLibMem(version);
+ RETURN_IF_NOT(err == ERR_OK, err);
+ }
+ // add a DataFile
+ if(!strcmp(argv[i], "-add")) {
+ if(argc > i+2 && argv[i+1][0] != '-' && argv[i+2][0] != '-') {
+ char* file = argv[i+1];
+ char* mime = argv[i+2];
+ char* content = NULL;
+ char* charset = NULL;
+ i += 2;
+ // optional content and charset
+ checkArguments(argc, argv, &i, &content);
+ checkArguments(argc, argv, &i, &charset);
+ err = cmdAddDataFile(ppSigDoc, (const char*)file, (const char*)mime,
+ (const char*)(content ? content : CONTENT_EMBEDDED_BASE64),
+ (const char*)(charset ? charset : CHARSET_UTF_8));
+ freeLibMem(content);
+ freeLibMem(charset);
+ } else {
+ err = ERR_BAD_PARAM;
+ addError(err, __FILE__, __LINE__, "Missing <file> and <mime-type> arguments of -add command");
+ }
+ }
+
+ }
+ }
+ return err;
+}
+
+//--------------------------------------------------
+// Adds a DataFile to signed doc
+//--------------------------------------------------
+int cmdAddDataFileFromMem(SignedDoc** ppSigDoc, const char* file,
+ const char* mime, const char* content)
+{
+ int err = ERR_OK;
+ DataFile *pDf = NULL;
+ DigiDocMemBuf mbuf1;
+
+ mbuf1.pMem = 0;
+ mbuf1.nLen = 0;
+
+ // if there was no new command then implicitly create a new document
+ if(!(*ppSigDoc)) {
+ err = cmdNew(ppSigDoc, NULL, NULL);
+ RETURN_IF_NOT(err == ERR_OK, err);
+ }
+ err = ddocReadFile(file, &mbuf1);
+ if(!err)
+ err = createDataFileInMemory(&pDf, *ppSigDoc, NULL, file, content, mime, mbuf1.pMem, mbuf1.nLen);
+ ddocMemBuf_free(&mbuf1);
+ return err;
+}
+
+//--------------------------------------------------
+// Create digidoc and adds datafiles
+//--------------------------------------------------
+int runAddMemCmds(int argc, char** argv, SignedDoc** ppSigDoc)
+{
+ int err = ERR_OK, i;
+
+ for(i = 1; (err == ERR_OK) && (i < argc); i++) {
+ if(argv[i][0] == '-') { // all commands and options must start with -
+ // add a DataFile
+ if(!strcmp(argv[i], "-add-mem")) {
+ if(argc > i+2 && argv[i+1][0] != '-' && argv[i+2][0] != '-') {
+ char* file = argv[i+1];
+ char* mime = argv[i+2];
+ char* content = NULL;
+ i += 2;
+ // optional content and charset
+ checkArguments(argc, argv, &i, &content);
+ err = cmdAddDataFileFromMem(ppSigDoc, (const char*)file, (const char*)mime,
+ (const char*)(content ? content : CONTENT_EMBEDDED_BASE64));
+ freeLibMem(content);
+ } else {
+ err = ERR_BAD_PARAM;
+ addError(err, __FILE__, __LINE__, "Missing <file> and <mime-type> arguments of -add-mem command");
+ }
+ }
+
+ }
+ }
+ return err;
+}
+
+//--------------------------------------------------
+// Create digidoc and adds datafiles
+//--------------------------------------------------
+/*int runAddSignValue(int argc, char** argv, SignedDoc** ppSigDoc)
+{
+ int err = ERR_OK, i;
+
+ for(i = 1; (err == ERR_OK) && (i < argc); i++) {
+ if(argv[i][0] == '-') { // all commands and options must start with -
+ // create new digidoc
+ if(!strcmp(argv[i], "-addsignvalue")) {
+ char* infile = NULL;
+ char* sigid = NULL;
+ char* sigvalf = NULL;
+ checkArguments(argc, argv, &i, &infile);
+ checkArguments(argc, argv, &i, &sigid);
+ checkArguments(argc, argv, &i, &sigvalf);
+ err = cmdReadDigiDoc(ppSigDoc, 0, 1);
+
+ }
+ // add a DataFile
+ if(!strcmp(argv[i], "-addsignvalue")) {
+ if(argc > i+2 && argv[i+1][0] != '-' && argv[i+2][0] != '-') {
+ char* file = argv[i+1];
+ char* mime = argv[i+2];
+ char* content = CONTENT_EMBEDDED_BASE64;
+ char* charset = CHARSET_UTF_8;
+ i += 2;
+ // optional content and charset
+ checkArguments(argc, argv, &i, &content);
+ checkArguments(argc, argv, &i, &charset);
+ err = cmdAddDataFile(ppSigDoc, (const char*)file, (const char*)mime,
+ (const char*)content, (const char*)charset);
+ } else {
+ err = ERR_BAD_PARAM;
+ addError(err, __FILE__, __LINE__, "Missing <in-digidoc> and <sig-id> or <sign-value-file> arguments of -addsignvalue command");
+ }
+
+ }
+ }
+ return err;
+}*/
+
+//--------------------------------------------------
+// Add ecryption recipients
+//--------------------------------------------------
+int runRecipientCmds(int argc, char** argv, DEncEncryptedData** ppEncData)
+{
+ int err = ERR_OK, i, rb = 0;
+ DEncEncryptedKey* pEncKey = 0;
+ X509* pCert = 0;
+ DigiDocMemBuf mbuf1;
+
+ mbuf1.pMem = 0;
+ mbuf1.nLen = 0;
+ for(i = 1; (err == ERR_OK) && (i < argc); i++) {
+ if(argv[i][0] == '-') { // all commands and options must start with -
+ // add a recipients key
+ if(!strcmp(argv[i], "-encrecv")) {
+ if(argc > i+1 && argv[i+1][0] != '-') {
+ char* certfile = argv[i+1];
+ char* recipient = NULL;
+ char* keyname = NULL;
+ char* carriedkeyname = NULL;
+ char* id = NULL;
+ i++;
+ if(!(*ppEncData))
+ err = dencEncryptedData_new(ppEncData, DENC_XMLNS_XMLENC, DENC_ENC_METHOD_AES128, 0, 0, 0);
+ if(!err) {
+ err = dencMetaInfo_SetLibVersion(*ppEncData);
+ if(!err) {
+ err = dencMetaInfo_SetFormatVersion(*ppEncData);
+ if(!err) {
+ // optional arguments
+ checkArguments(argc, argv, &i, &recipient);
+ checkArguments(argc, argv, &i, &keyname);
+ checkArguments(argc, argv, &i, &carriedkeyname);
+ err = ReadCertificate(&pCert, certfile);
+ if(!err) {
+ if(!recipient) {
+ ddocCertGetSubjectCN(pCert, &mbuf1);
+ recipient = (char*)mbuf1.pMem;
+ rb = 1;
+ }
+ err = dencEncryptedKey_new(*ppEncData, &pEncKey, pCert,
+ DENC_ENC_METHOD_RSA1_5,
+ id, recipient, keyname, carriedkeyname);
+ if(rb) recipient = NULL; // was not malloc separately from mbuf1
+ }
+ }
+ }
+ }
+ ddocMemBuf_free(&mbuf1);
+ freeLibMem(recipient);
+ freeLibMem(keyname);
+ freeLibMem(carriedkeyname);
+ } else {
+ err = ERR_BAD_PARAM;
+ addError(err, __FILE__, __LINE__, "Missing <cert-file> argument of -encrecv command");
+ }
+ }
+ }
+ }
+ return err;
+}
+
+
+unsigned char* findFileExt(unsigned char* szFileName)
+{
+ int i = 0;
+
+ if(szFileName && strlen(szFileName) > 0) {
+ for(i = strlen(szFileName)-1; (i > 0) && (szFileName[i] != '.'); i--);
+ if(szFileName[i] == '.')
+ return szFileName + i + 1;
+ }
+ return 0;
+}
+
+int checkOldFormatVer(SignedDoc* pSigDoc)
+{
+ if(!pSigDoc || !pSigDoc->szFormat || !pSigDoc->szFormatVer) {
+ addError(ERR_BAD_PARAM, __FILE__, __LINE__, "Format or version not specified");
+ return ERR_BAD_PARAM;
+ }
+ if(!strcmp(pSigDoc->szFormat, SK_XML_1_NAME) ||
+ (!strcmp(pSigDoc->szFormat, DIGIDOC_XML_1_1_NAME) &&
+ (!strcmp(pSigDoc->szFormatVer, DIGIDOC_XML_1_1_VER) ||
+ !strcmp(pSigDoc->szFormatVer, DIGIDOC_XML_1_2_VER)))) {
+ SET_LAST_ERROR(ERR_OLD_VERSION);
+ return ERR_OLD_VERSION;
+ }
+ return ERR_OK;
+}
+
+//--------------------------------------------------
+// reads in a signed doc
+//--------------------------------------------------
+int cmdReadDigiDoc(SignedDoc** ppSigDoc, DEncEncryptedData** ppEncData, int nMode)
+{
+ int err = ERR_OK, e;
+ int nMaxDfLen;
+ unsigned char* pExt = 0;
+ if(!p_szInFile) {
+ err = ERR_BAD_PARAM;
+ addError(err, __FILE__, __LINE__, "No input file specified");
+ return err;
+ }
+ nMaxDfLen = ConfigItem_lookup_int("DATAFILE_MAX_CACHE", 0);
+ pExt = findFileExt(p_szInFile);
+ //printf("Read file: %s - ext: %s", p_szInFile, pExt);
+ if(pExt && strcmp(pExt, "cdoc") == 0) {
+ err = dencSaxReadEncryptedData(ppEncData, p_szInFile);
+ } else if(pExt && strcmp(pExt, "ddoc") == 0) {
+ switch(nMode) {
+ case 2: // new XMLReader interface
+ //err = ddocXRdrReadSignedDocFromFile(p_szInFile, CHARSET_ISO_8859_1, ppSigDoc, nMaxDfLen);
+ break;
+ case 1:
+ default:
+ err = ddocSaxReadSignedDocFromFile(ppSigDoc, p_szInFile, 0, nMaxDfLen);
+ }
+ } else {
+ err = ERR_FILE_READ;
+ }
+ e = checkOldFormatVer(*ppSigDoc);
+ if(!err && e) err = e;
+ printErrorsAndWarnings(*ppSigDoc);
+ return err;
+}
+
+//--------------------------------------------------
+// reads in a signed doc
+//--------------------------------------------------
+int cmdReadDigiDocFromMem(SignedDoc** ppSigDoc, DEncEncryptedData** ppEncData)
+{
+ int err = ERR_OK, e;
+ DigiDocMemBuf mbuf1;
+
+ mbuf1.pMem = 0;
+ mbuf1.nLen = 0;
+ if(!p_szInFile) {
+ err = ERR_BAD_PARAM;
+ addError(err, __FILE__, __LINE__, "No input file specified");
+ return err;
+ }
+ //nMaxDfLen = ConfigItem_lookup_int("DATAFILE_MAX_CACHE", 0);
+
+ if(strstr(p_szInFile, ".cdoc")) {
+ err = ddocReadFile(p_szInFile, &mbuf1);
+ if(!err)
+ err = dencSaxReadEncryptedDataFromMemory(ppEncData, &mbuf1);
+ } else {
+ err = ddocReadFile(p_szInFile, &mbuf1);
+ if(!err)
+ err = ddocSaxReadSignedDocFromMemory(ppSigDoc, mbuf1.pMem, mbuf1.nLen, mbuf1.nLen + 1);
+ }
+ ddocMemBuf_free(&mbuf1);
+ e = checkOldFormatVer(*ppSigDoc);
+ printErrorsAndWarnings(*ppSigDoc);
+ if(!err && e) err = e;
+ return err;
+}
+
+//--------------------------------------------------
+// writes a digidoc in file
+//--------------------------------------------------
+int cmdWrite(SignedDoc* pSigDoc, DEncEncryptedData* pEncData)
+{
+ int err = ERR_OK;
+ FILE* hFile;
+#ifdef WIN32
+ wchar_t *convFileName = 0;
+ int l1 = 0;
+#endif
+
+ if(!p_szOutFile) {
+ err = ERR_BAD_PARAM;
+ addError(err, __FILE__, __LINE__, "No output file specified");
+ return err;
+ }
+ if(pSigDoc)
+ err = createSignedDoc(pSigDoc, p_szInFile, p_szOutFile);
+ if(pEncData) {
+ if(pEncData->nDataStatus == DENC_DATA_STATUS_ENCRYPTED_AND_NOT_COMPRESSED ||
+ pEncData->nDataStatus == DENC_DATA_STATUS_ENCRYPTED_AND_COMPRESSED) {
+ err = dencGenEncryptedData_writeToFile(pEncData, p_szOutFile);
+ } else {
+#ifdef WIN32
+ err = utf82unicode((const char*)p_szOutFile, (char**)&convFileName, &l1);
+ ddocDebug(3, "cmdWrite", "Writing file: %s, conv-file: %s len: %d", p_szOutFile, convFileName, l1);
+ if((hFile = _wfopen(convFileName, L"wb")) != NULL) {
+#else
+ if((hFile = fopen(p_szOutFile, "wb")) != NULL) {
+#endif
+ fwrite((pEncData)->mbufEncryptedData.pMem, 1,
+ (pEncData)->mbufEncryptedData.nLen, hFile);
+ fclose(hFile);
+ }
+ else
+ err = ERR_FILE_WRITE;
+ }
+ }
+ if (err)
+ addError(err, __FILE__, __LINE__, "Error writing file\n");
+ return err;
+}
+
+//--------------------------------------------------
+// writes a digidoc in file
+//--------------------------------------------------
+int cmdWriteMem(SignedDoc* pSigDoc, DEncEncryptedData* pEncData)
+{
+ int err = ERR_OK;
+ DigiDocMemBuf mbuf1;
+
+ mbuf1.pMem = 0;
+ mbuf1.nLen = 0;
+ if(!p_szOutFile) {
+ err = ERR_BAD_PARAM;
+ addError(err, __FILE__, __LINE__, "No output file specified");
+ return err;
+ }
+ if(pSigDoc) {
+ err = createSignedDocInMemory(pSigDoc, NULL, &mbuf1);
+ if(!err)
+ err = ddocWriteFile(p_szOutFile, &mbuf1);
+ }
+ if(pEncData) {
+ if(pEncData->nDataStatus == DENC_DATA_STATUS_ENCRYPTED_AND_NOT_COMPRESSED ||
+ pEncData->nDataStatus == DENC_DATA_STATUS_ENCRYPTED_AND_COMPRESSED) {
+ err = dencGenEncryptedData_toXML(pEncData, &mbuf1);
+ if(!err)
+ err = ddocWriteFile(p_szOutFile, &mbuf1);
+ } else {
+ err = ddocWriteFile(p_szOutFile, &(pEncData->mbufEncryptedData));
+ }
+ }
+ ddocMemBuf_free(&mbuf1);
+ if (err)
+ addError(err, __FILE__, __LINE__, "Error writing file\n");
+ return err;
+}
+
+
+//-----------------------------------------
+// prints certificate info
+//-----------------------------------------
+void printCertificateInfo(SignedDoc* pSigDoc, X509* pCert)
+{
+ int err, p;
+ char buf1[500];
+ PolicyIdentifier* pPolicies;
+ DigiDocMemBuf mbuf;
+ int nPols;
+
+ mbuf.pMem = 0;
+ mbuf.nLen = 0;
+ // serial number
+ err = ReadCertSerialNumber(buf1, sizeof(buf1), pCert);
+ if(g_cgiMode)
+ fprintf(stdout, "\nX509Certificate%s%s", g_szOutputSeparator, buf1);
+ else
+ fprintf(stdout, "\nX509Certificate nr: %s", buf1);
+ // issuer
+ err = ddocCertGetIssuerDN(pCert, &mbuf);
+ if(g_cgiMode)
+ fprintf(stdout, "%s%s", g_szOutputSeparator, (char*)mbuf.pMem);
+ else
+ fprintf(stdout, "\n\tIssuer: %s", (char*)mbuf.pMem);
+ ddocMemBuf_free(&mbuf);
+ // subject
+ err = ddocCertGetSubjectDN(pCert, &mbuf);
+ if(g_cgiMode)
+ fprintf(stdout, "%s%s", g_szOutputSeparator, (char*)mbuf.pMem);
+ else
+ fprintf(stdout, "\n\tSubject: %s", (char*)mbuf.pMem);
+ ddocMemBuf_free(&mbuf);
+ // ValidFrom
+ memset(buf1, 0, sizeof(buf1));
+ err = getCertNotBefore(pSigDoc, pCert, buf1, sizeof(buf1));
+ if(g_cgiMode)
+ fprintf(stdout, "%s%s", g_szOutputSeparator, buf1);
+ else
+ fprintf(stdout, "\n\tNotBefore: %s", buf1);
+ // ValidTo
+ memset(buf1, 0, sizeof(buf1));
+ err = getCertNotAfter(pSigDoc, pCert, buf1, sizeof(buf1));
+ if(g_cgiMode)
+ fprintf(stdout, "%s%s", g_szOutputSeparator, buf1);
+ else
+ fprintf(stdout, "\n\tNotAfter: %s", buf1);
+ // policy URL
+ err = readCertPolicies(pCert, &pPolicies, &nPols);
+ if(nPols) {
+ for(p = 0; p < nPols; p++) {
+ if(g_cgiMode)
+ fprintf(stdout, "\nSignaturePolicy%s%s%s%s%s%s",
+ g_szOutputSeparator, pPolicies[p].szOID,
+ g_szOutputSeparator, pPolicies[p].szCPS,
+ g_szOutputSeparator, pPolicies[p].szUserNotice);
+ else
+ fprintf(stdout, "\n\tnSignaturePolicy oid: %s cps: %s desc: %s", pPolicies[p].szOID,
+ pPolicies[p].szCPS, pPolicies[p].szUserNotice);
+ } // for p < nPols
+ }
+ PolicyIdentifiers_free(pPolicies, nPols);
+
+}
+
+char* TEST_OIDS_PREFS[] = {
+ "1.3.6.1.4.1.10015.3.7", "1.3.6.1.4.1.10015.7", // tempel test
+ "1.3.6.1.4.1.10015.3.3", "1.3.6.1.4.1.10015.3.11", // mid test
+ "1.3.6.1.4.1.10015.3.2", // digi-id test
+ "1.3.6.1.4.1.10015.3.1" // est-eid test
+};
+
+int checkTestCert(X509* pCert)
+{
+ int err = ERR_OK, i, p;
+ PolicyIdentifier* pPolicies = NULL;
+ DigiDocMemBuf mbuf;
+ int nPols = 0;
+
+ mbuf.pMem = 0;
+ mbuf.nLen = 0;
+ ddocCertGetSubjectCN(pCert, &mbuf);
+ /*if(mbuf.pMem && strstr(mbuf.pMem, "TEST")) {
+ printf("\n Test CN: %s", (char*)(mbuf.pMem));
+ err = ERR_TEST_SIGNATURE;
+ }*/
+ err = readCertPolicies(pCert, &pPolicies, &nPols);
+ if(!err && nPols && !err) {
+ for(p = 0; p < nPols; p++) {
+ //printf("\nOID: %s", pPolicies[p].szOID);
+ for(i = 0; i < 6 && !err; i++) {
+ if(i == 1 && // tempel - test
+ strstr(pPolicies[p].szOID, TEST_OIDS_PREFS[1]) &&
+ strstr(mbuf.pMem, "TEST")) {
+ //printf("\nTempel-Test OID: %s", TEST_OIDS_PREFS[i]);
+ err = ERR_TEST_SIGNATURE;
+ } else if(i != 1) {
+ if(strstr(pPolicies[p].szOID, TEST_OIDS_PREFS[i])) {
+ //printf("\nTest OID: %s", TEST_OIDS_PREFS[i]);
+ err = ERR_TEST_SIGNATURE;
+ }
+ }
+ }
+ }
+ }
+ ddocMemBuf_free(&mbuf);
+ PolicyIdentifiers_free(pPolicies, nPols);
+ if(err == ERR_TEST_SIGNATURE)
+ SET_LAST_ERROR(ERR_TEST_SIGNATURE);
+ return err;
+}
+
+
+int isError(SignedDoc* pSigDoc, int nErrCd)
+{
+ return (nErrCd != ERR_OK && !isWarning(pSigDoc, nErrCd));
+}
+
+int isWarning(SignedDoc* pSigDoc, int nErrCd)
+{
+ if(pSigDoc && pSigDoc->szFormat && !strcmp(pSigDoc->szFormat, SK_XML_1_NAME)) {
+ // currently no warnings for ddoc 1.0
+ return (nErrCd == ERR_OLD_VERSION) || (nErrCd == ERR_TEST_SIGNATURE);
+ } else {
+ return ((nErrCd == ERR_ISSUER_XMLNS) ||
+ (nErrCd == ERR_OLD_VERSION) ||
+ (nErrCd == ERR_TEST_SIGNATURE) ||
+ (nErrCd == ERR_DF_WRONG_DIG)
+ );
+ }
+}
+
+int isLibraryError(int nErrCd)
+{
+ return (nErrCd != ERR_OK &&
+ nErrCd != ERR_OLD_VERSION &&
+ nErrCd != ERR_TEST_SIGNATURE &&
+ nErrCd != ERR_UNSUPPORTED_FORMAT);
+}
+
+int hasWarnings(SignedDoc* pSigDoc)
+{
+ int n;
+ ErrorInfo* pErr;
+
+ for(n = getLastErrorsIdx(); n >= 0; n--) {
+ pErr = getErrorsInfo(n);
+ if(isWarning(pSigDoc, pErr->code))
+ return pErr->code;
+ }
+ return ERR_OK;
+}
+
+int hasErrors(SignedDoc* pSigDoc)
+{
+ int n;
+ ErrorInfo* pErr;
+
+ for(n = getLastErrorsIdx(); n >= 0; n--) {
+ pErr = getErrorsInfo(n);
+ if(isError(pSigDoc, pErr->code))
+ return pErr->code;
+ }
+ return ERR_OK;
+}
+
+void printErrorsAndWarnings(SignedDoc* pSigDoc)
+{
+ int n, m = getLastErrorsIdx();
+ ErrorInfo* pErr;
+ char* pErrStr;
+
+ // list all errors
+ if(g_cgiMode) {
+ /*for(n = 0; n < m; n++) {
+ pErr = getErrorsInfo(n);
+ pErrStr = getErrorString(pErr->code);
+ printf("\nErr: %d cd: %d msg: %s", n, pErr->code, pErrStr);
+ }*/
+ for(n = m; n >= 0; n--) {
+ pErr = getErrorsInfo(n);
+ pErrStr = getErrorString(pErr->code);
+ if(isError(pSigDoc, pErr->code))
+ fprintf(stdout, "\nERROR%s%d%s%s%s%s%s%d%s%s%s%s",
+ g_szOutputSeparator, pErr->code,
+ g_szOutputSeparator, pErrStr,
+ g_szOutputSeparator, pErr->fileName,
+ g_szOutputSeparator, pErr->line,
+ g_szOutputSeparator, pErr->assertion,
+ g_szOutputSeparator, errorClass[getErrorClass(pErr->code)]);
+ }
+ for(n = m; n >= 0; n--) {
+ pErr = getErrorsInfo(n);
+ pErrStr = getErrorString(pErr->code);
+ if(isWarning(pSigDoc, pErr->code))
+ fprintf(stdout, "\nWARNING%s%d%s%s%s%s%s%d%s%s%s%s",
+ g_szOutputSeparator, pErr->code,
+ g_szOutputSeparator, pErrStr,
+ g_szOutputSeparator, pErr->fileName,
+ g_szOutputSeparator, pErr->line,
+ g_szOutputSeparator, pErr->assertion,
+ g_szOutputSeparator, errorClass[getErrorClass(pErr->code)]);
+ }
+ if(g_nLibErrors) {
+ for(n = m; n >= 0; n--) {
+ pErr = getErrorsInfo(n);
+ if(isLibraryError(pErr->code)) {
+ pErrStr = getErrorString(pErr->code);
+ fprintf(stdout, "\nLIBRARY-ERROR%s%d%s%s%s%s%s%d%s%s%s%s",
+ g_szOutputSeparator, pErr->code,
+ g_szOutputSeparator, pErrStr,
+ g_szOutputSeparator, pErr->fileName,
+ g_szOutputSeparator, pErr->line,
+ g_szOutputSeparator, pErr->assertion,
+ g_szOutputSeparator, errorClass[getErrorClass(pErr->code)]);
+ }
+ }
+ }
+ } else {
+ for(n = m; n >= 0; n--) {
+ pErr = getErrorsInfo(n);
+ pErrStr = getErrorString(pErr->code);
+ if(isError(pSigDoc, pErr->code))
+ fprintf(stdout, "\nERROR: %d - %s - %s",
+ pErr->code, pErrStr, pErr->assertion);
+ if(isWarning(pSigDoc, pErr->code))
+ fprintf(stdout, "\nWARNING: %d - %s - %s",
+ pErr->code, pErrStr, pErr->assertion);
+ }
+ }
+}
+
+
+//--------------------------------------------------
+// Verifys sigantures and notaries
+//--------------------------------------------------
+int cmdVerify(SignedDoc* pSigDoc)
+{
+ int err = ERR_OK, s, d, l, m, l1, e, e2, n1, e3;
+ SignatureInfo* pSigInfo = 0;
+ NotaryInfo* pNot;
+ DataFile *pDf = 0;
+ DigiDocMemBuf mbuf;
+ X509* pRcert = 0;
+ const DigiDocMemBuf* pMBuf = 0;
+ char buf1[100], *p1 = 0;
+
+ mbuf.pMem = 0;
+ mbuf.nLen = 0;
+ if(!pSigDoc) {
+ SET_LAST_ERROR(ERR_UNSUPPORTED_FORMAT);
+ return ERR_UNSUPPORTED_FORMAT;
+ }
+ // print signed doc format and version
+ if(g_cgiMode) {
+ fprintf(stdout, "\nSignedDoc%s%s%s%s",
+ g_szOutputSeparator,
+ pSigDoc->szFormat, g_szOutputSeparator,
+ pSigDoc->szFormatVer);
+ } else {
+ fprintf(stdout, "\nSignedDoc format: %s version: %s\n",
+ pSigDoc->szFormat, pSigDoc->szFormatVer);
+ }
+ // display DataFile-s
+ d = getCountOfDataFiles(pSigDoc);
+ for(l = 0; l < d; l++) {
+ pDf = getDataFile(pSigDoc, l);
+ ddocGetDataFileFilename(pSigDoc, pDf->szId, (void**)&p1, &n1);
+ if(g_cgiMode)
+ fprintf(stdout, "\n\nDataFile%s%s%s%s%s%ld%s%s%s%s",
+ g_szOutputSeparator, pDf->szId, g_szOutputSeparator,
+ p1, g_szOutputSeparator,
+ pDf->nSize, g_szOutputSeparator,
+ pDf->szMimeType, g_szOutputSeparator,
+ pDf->szContentType);
+ else
+ fprintf(stdout, "\n\nDataFile: %s, file: %s, size: %ld, mime-type: %s content-type: %s",
+ pDf->szId, p1, pDf->nSize, pDf->szMimeType, pDf->szContentType);
+ if(p1)
+ freeLibMem(p1);
+ }
+
+
+ // verify signatures
+ d = getCountOfSignatures(pSigDoc);
+ for(s = 0; s < d; s++) {
+ pSigInfo = getSignature(pSigDoc, s);
+ e = ddocCertGetSubjectCN(ddocSigInfo_GetSignersCert(pSigInfo), &mbuf);
+ clearErrors();
+ e = verifySignatureAndNotary(pSigDoc, pSigInfo, p_szInFile);
+ if(!e)
+ e = hasErrors(pSigDoc);
+ if(!err && e) err = e;
+ e2 = checkTestCert(ddocSigInfo_GetSignersCert(pSigInfo));
+ if(!err && e2) err = e2;
+ if(!e && e2) e = e2;
+ if(g_cgiMode) {
+ fprintf(stdout, "\n\nSignature%s%s%s%s%s%d%s%s",
+ g_szOutputSeparator,
+ pSigInfo->szId,
+ g_szOutputSeparator,
+ (const char*)mbuf.pMem,
+ g_szOutputSeparator,
+ e,
+ g_szOutputSeparator,
+ (e ? getErrorString(e) : ""));
+ } else {
+ fprintf(stdout, "\n\nSignature: %s - %s - %s", pSigInfo->szId,
+ (const char*)mbuf.pMem, ((!e) ? "OK" : "ERROR"));
+ }
+ ddocMemBuf_free(&mbuf);
+ // print signers roles / manifests
+ m = getCountOfSignerRoles(pSigInfo, 0);
+ for(l = 0; l < m; l++) {
+ if(g_cgiMode)
+ fprintf(stdout, "\nClaimedRole%s%s", g_szOutputSeparator, getSignerRole(pSigInfo, 0, l));
+ else
+ fprintf(stdout, "\n\tClaimedRole: %s", getSignerRole(pSigInfo, 0, l));
+ }
+ if(pSigInfo->sigProdPlace.szCity || pSigInfo->sigProdPlace.szStateOrProvince ||
+ pSigInfo->sigProdPlace.szPostalCode || pSigInfo->sigProdPlace.szCountryName) {
+ if(g_cgiMode) {
+ fprintf(stdout, "\nSignatureProductionPlace%s%s%s%s%s%s%s%s", g_szOutputSeparator,
+ (pSigInfo->sigProdPlace.szCountryName ? pSigInfo->sigProdPlace.szCountryName : ""),
+ g_szOutputSeparator,
+ (pSigInfo->sigProdPlace.szStateOrProvince ? pSigInfo->sigProdPlace.szStateOrProvince : ""),
+ g_szOutputSeparator,
+ (pSigInfo->sigProdPlace.szCity ? pSigInfo->sigProdPlace.szCity : ""),
+ g_szOutputSeparator,
+ (pSigInfo->sigProdPlace.szPostalCode ? pSigInfo->sigProdPlace.szPostalCode : ""));
+ } else {
+ fprintf(stdout, "\n\tnSignatureProductionPlace - Country: %s, State: %s, City: %s, Postal code: %s",
+ (pSigInfo->sigProdPlace.szCountryName ? pSigInfo->sigProdPlace.szCountryName : ""),
+ (pSigInfo->sigProdPlace.szStateOrProvince ? pSigInfo->sigProdPlace.szStateOrProvince : ""),
+ (pSigInfo->sigProdPlace.szCity ? pSigInfo->sigProdPlace.szCity : ""),
+ (pSigInfo->sigProdPlace.szPostalCode ? pSigInfo->sigProdPlace.szPostalCode : ""));
+ }
+ }
+ // signers certificate
+ if(ddocSigInfo_GetSignersCert(pSigInfo))
+ printCertificateInfo(pSigDoc, ddocSigInfo_GetSignersCert(pSigInfo));
+ // confirmation
+ if(pSigDoc && pSigInfo) {
+ pNot = getNotaryWithSigId(pSigDoc, pSigInfo->szId);
+ if(pNot) {
+ pMBuf = ddocNotInfo_GetResponderId(pNot);
+ buf1[0] = 0;
+ l1 = sizeof(buf1);
+ if(pNot->nRespIdType == RESPID_NAME_TYPE) {
+ strncpy(buf1, (const char*)pMBuf->pMem, l1);
+ }
+ if(pNot->nRespIdType == RESPID_KEY_TYPE) {
+ encode((const byte*)pMBuf->pMem, pMBuf->nLen, (byte*)buf1, &l1);
+ }
+ }
+ if(pNot && pMBuf) {
+ if(g_cgiMode)
+ fprintf(stdout, "\nRevocationValues%s%s%s%s",
+ g_szOutputSeparator,
+ buf1,
+ g_szOutputSeparator,
+ pNot->timeProduced);
+ else
+ fprintf(stdout, "\n\tRevocationValues responder: %s produced-at: %s",
+ buf1, pNot->timeProduced);
+ // certificate
+ pRcert = ddocSigInfo_GetOCSPRespondersCert(pSigInfo);
+ e3 = checkTestCert(pRcert);
+ if(!e2 && e3) { // live allkirjastaja sert aga test ocsp
+ fprintf(stdout, "\n\tSigner from LIVE CA-chain but OCSP from TEST CA-chain!");
+ err = e3;
+ SET_LAST_ERROR(e3);
+ }
+ printCertificateInfo(pSigDoc, pRcert);
+ }
+ }
+ printErrorsAndWarnings(pSigDoc);
+ }
+ return err;
+}
+
+
+//--------------------------------------------------
+// Signs the document and gets configrmation
+//--------------------------------------------------
+int cmdSign(SignedDoc* pSigDoc, const char* pin, const char* manifest,
+ const char* city, const char* state, const char* zip, const char* country,
+ int nSlot, int nOcsp, int nSigner, const char* szPkcs12File)
+{
+ int err = ERR_OK;
+ SignatureInfo* pSigInfo = NULL;
+
+ ddocDebug(3, "cmdSign", "Creating new digital signature");
+ err = signDocumentWithSlotAndSigner(pSigDoc, &pSigInfo, pin, manifest,
+ city, state, zip, country, nSlot, nOcsp, nSigner, szPkcs12File);
+ ddocDebug(3, "cmdSign", "End creating new digital signature");
+ RETURN_IF_NOT(err == ERR_OK, err);
+ return ERR_OK;
+}
+
+
+
+
+
+
+//#ifdef WITH_DEPRECATED_FUNCTIONS
+//--------------------------------------------------
+// Runs some test. This is used simply to test
+// new features of the library and the functionality
+// may change.
+//--------------------------------------------------
+void cmdTest2(const char* infile)
+{
+ X509* pCert = 0;
+ //char buf1[X509_NAME_LEN + 10];
+ int err = ERR_OK, nPols = 0;
+ PolicyIdentifier *pPolicies = 0;
+
+ ddocDebug(3, "cmdTest2", "Reading cert: %s", infile);
+ err = ReadCertificate(&pCert, infile);
+ if(!err && pCert) {
+ err = readCertPolicies(pCert, &pPolicies, &nPols);
+ printf("Read pols rc: %d pols: %d\n", err, nPols);
+
+ /*
+ l1 = sizeof(buf1);
+ memset(buf1, 0, sizeof(buf1));
+ err = getCertSubjectName(pCert, buf1, &l1);
+ if(g_cgiMode)
+ fprintf(stdout, "\nDN%s%s%s%d",
+ g_szOutputSeparator, buf1,
+ g_szOutputSeparator, l1);
+ else
+ fprintf(stdout, "\nDN: %s len: %d", buf1, l1);
+ */
+ }
+ if(pCert)
+ X509_free(pCert);
+ if(pPolicies)
+ PolicyIdentifiers_free(pPolicies, nPols);
+}
+//#endif
+
+//--------------------------------------------------
+// Encrypts a file
+//--------------------------------------------------
+int cmdEncrypt(DEncEncryptedData** ppEncData, const char* szFileName)
+{
+ FILE* hFile;
+ SignedDoc *pSigDoc = 0;
+ DEncEncryptionProperty* pEncProperty = 0;
+ int len, err = ERR_OK, i = 0;
+ long lFileLen;
+ char buf[2048], *p = 0;
+#ifdef WIN32
+ wchar_t *convFileName = 0;
+ err = utf82unicode((const char*)szFileName, (char**)&convFileName, &i);
+#endif
+
+ ddocDebug(3, "cmdEncrypt", "Encrypting %s rc: %d", szFileName, err);
+ err = dencEncryptedData_new(ppEncData, DENC_XMLNS_XMLENC, DENC_ENC_METHOD_AES128, 0, 0, 0);
+ if(!err) {
+ err = dencMetaInfo_SetLibVersion(*ppEncData);
+ if(!err) {
+ err = dencMetaInfo_SetFormatVersion(*ppEncData);
+ if(!err) {
+ err = ddocConvertInput(szFileName, &p);
+ if(!err) {
+ err = dencEncryptionProperty_new(*ppEncData, &pEncProperty,
+ 0, 0, ENCPROP_FILENAME, getSimpleFileName(p));
+ if(strstr(p, ".bdoc") || strstr(p, ".asice"))
+ err = dencEncryptedData_SetMimeType(*ppEncData, "application/vnd.etsi.asic-e+zip");
+ err = calculateFileSize(szFileName, &lFileLen);
+ sprintf(buf, "%ld", lFileLen);
+ err = dencEncryptionProperty_new(*ppEncData, &pEncProperty,
+ 0, 0, ENCPROP_ORIG_SIZE, buf);
+ freeLibMem(p);
+ if(!err) {
+ ddocDebug(3, "cmdEncrypt", "Opening %s rc: %d", szFileName, err);
+#ifdef WIN32
+ if((hFile = _wfopen(convFileName, L"rb")) != NULL) {
+#else
+ if((hFile = fopen(szFileName, "rb")) != NULL) {
+#endif
+ do {
+ memset(buf,0,sizeof(buf));
+ len = fread(buf, 1, sizeof(buf), hFile);
+ if(len)
+ err = dencEncryptedData_AppendData(*ppEncData, buf, len);
+ } while(len && !err);
+ fclose(hFile);
+ } // if fopen/wfopen
+ ddocDebug(3, "cmdEncrypt", "Enc data-len: %d rc: %d", (*ppEncData)->mbufEncryptedData.nLen, err);
+ if(!err)
+ err = dencEncryptedData_encryptData(*ppEncData, DENC_COMPRESS_NEVER);
+ } // err - endProp_new
+ } // err - conver filename
+ } // err - serFormatVer
+ } // err - setLibVer
+ } // err - dencEncData_new
+ return err;
+}
+
+
+//--------------------------------------------------
+// Encrypts a file and uses SK specific method of
+// putting the file first in a ddoc container and then into
+// cdoc
+//--------------------------------------------------
+int cmdEncryptSk(DEncEncryptedData** ppEncData, const char* szFileName)
+{
+ SignedDoc *pSigDoc = 0;
+ DEncEncryptionProperty* pEncProperty = 0;
+ DataFile *pDf = 0;
+ int err = ERR_OK;
+ long lSize;
+ char buf[256], *p = 0;
+ DigiDocMemBuf mbuf1;
+
+ mbuf1.pMem = 0;
+ mbuf1.nLen = 0;
+ err = dencEncryptedData_new(ppEncData, DENC_XMLNS_XMLENC, DENC_ENC_METHOD_AES128, 0, 0, 0);
+ if(!err) {
+ err = dencMetaInfo_SetLibVersion(*ppEncData);
+ if(!err) {
+ err = dencMetaInfo_SetFormatVersion(*ppEncData);
+ if(!err) {
+ err = ddocConvertInput(szFileName, &p);
+ if(!err) {
+ err = dencEncryptionProperty_new(*ppEncData, &pEncProperty,
+ 0, 0, ENCPROP_FILENAME, getSimpleFileName(p));
+ if(!err) {
+ err = SignedDoc_new(&pSigDoc, "DIGIDOC-XML", "1.3");
+ if(!err) {
+ calculateFileSize(szFileName, &lSize);
+ err = DataFile_new(&pDf, pSigDoc, NULL, szFileName,
+ "EMBEDDED_BASE64", "application/file", lSize, NULL, 0, NULL, NULL);
+ sprintf(buf, "%ld", lSize);
+ err = dencEncryptionProperty_new(*ppEncData, &pEncProperty,
+ 0, 0, ENCPROP_ORIG_SIZE, buf);
+ if(!err) {
+ err = dencOrigContent_registerDigiDoc(*ppEncData, pSigDoc);
+ if(!err) {
+ sprintf(buf, "%s.ddoc", szFileName);
+ err = createSignedDoc(pSigDoc, NULL, buf);
+ if(!err) {
+ err = ddocReadFile(buf, &mbuf1);
+ if(!err) {
+ err = dencEncryptedData_AppendData(*ppEncData, mbuf1.pMem, mbuf1.nLen);
+ //ddocDebug(3, "EncTest", "Enc data: \"%s\"", mbuf1.pMem);
+ remove(buf);
+ ddocMemBuf_free(&mbuf1);
+ if(!err)
+ err = dencEncryptedData_encryptData(*ppEncData, DENC_COMPRESS_NEVER);
+ } // err - ddocReadFile
+ } // err - createSignedDoc
+ } // err - origContent_register
+ } // err - sigDoc_new
+ } // err - sigDoc_new
+ SignedDoc_free(pSigDoc);
+ } // err - encProp_new
+ freeLibMem(p);
+ } // err - convert filename
+ } // err - setFormatVer
+ } // err - setLibVer
+ } // err - endData_new
+ return err;
+}
+
+
+//--------------------------------------------------
+// Runs various tests. Just for trying out new features
+//--------------------------------------------------
+int runTestCmds(int argc, char** argv)
+{
+ int err = ERR_OK, i;
+ char* infile = NULL;
+
+ for(i = 1; (err == ERR_OK) && (i < argc); i++) {
+ if(argv[i][0] == '-') { // all commands and options must start with -
+ if(!strcmp(argv[i], "-test")) {
+ // add a recipients key
+
+ }
+//#ifdef WITH_DEPRECATED_FUNCTIONS
+ if(!strcmp(argv[i], "-test2")) {
+ ddocConvertInput((const char*)argv[i+1], &infile);
+ cmdTest2(argv[i+1]);
+ }
+//#endif
+ }
+ }
+ return err;
+}
+
+//--------------------------------------------------
+// Encrypts whole files
+//--------------------------------------------------
+int runEncryptFileCmds(int argc, char** argv, DEncEncryptedData* pEncData)
+{
+ int err = ERR_OK, i;
+
+ for(i = 1; (err == ERR_OK) && (i < argc); i++) {
+ if(argv[i][0] == '-') { // all commands and options must start with -
+ // add a recipients key
+ if(!strcmp(argv[i], "-encrypt-file")) {
+ if(argc > i+2 && argv[i+1][0] != '-' && argv[i+2][0] != '-') {
+ char* infile = NULL;
+ char* outfile = NULL;
+ char* mime = NULL;
+ ddocConvertInput((const char*)argv[i+1], &infile);
+ ddocConvertInput((const char*)argv[i+2], &outfile);
+ ddocConvertInput((const char*)argv[i+3], &mime);
+ i += 3;
+ // optional arguments
+ checkArguments(argc, argv, &i, &mime);
+ // encrypt the file
+ err = dencEncryptFile(pEncData, infile, outfile, mime);
+ if(infile) freeLibMem(infile);
+ if(outfile) freeLibMem(outfile);
+ if(mime) freeLibMem(mime);
+ if(err) return err;
+ } else {
+ err = ERR_BAD_PARAM;
+ addError(err, __FILE__, __LINE__, "Missing <in-file> or <out-file> argument of -encrypt-file command");
+ }
+ }
+ }
+ }
+ return err;
+}
+
+
+//--------------------------------------------------
+// Decrypts whole files
+//--------------------------------------------------
+int runDecryptFileCmds(int argc, char** argv)
+{
+ int err = ERR_OK, i;
+
+ for(i = 1; (err == ERR_OK) && (i < argc); i++) {
+ if(argv[i][0] == '-') { // all commands and options must start with -
+ // decrypt a file
+ if(!strcmp(argv[i], "-decrypt-file")) {
+ if(argc > i+2 && argv[i+1][0] != '-' &&
+ argv[i+2][0] != '-' && argv[i+3][0] != '-') {
+ char* infile = NULL;
+ char* outfile = NULL;
+ char* pin = NULL;
+ char* pkcs12file = NULL;
+ ddocConvertInput((const char*)argv[i+1], &infile);
+ ddocConvertInput((const char*)argv[i+2], &outfile);
+ ddocConvertInput((const char*)argv[i+3], &pin);
+ i += 3;
+ // optional arguments
+ checkArguments(argc, argv, &i, &pkcs12file);
+ // decrypt the file
+ err = dencSaxReadDecryptFile(infile, outfile, pin, pkcs12file);
+ if(infile) freeLibMem(infile);
+ if(outfile) freeLibMem(outfile);
+ if(pin) freeLibMem(pin);
+ if(pkcs12file) freeLibMem(pkcs12file);
+ if(err) return err;
+ } else {
+ err = ERR_BAD_PARAM;
+ addError(err, __FILE__, __LINE__, "Missing <in-file>, <out-file> or <pin> argument of -decrypt-file command");
+ }
+ }
+ }
+ }
+ return err;
+}
+
+//--------------------------------------------------
+// Generates and encrypts a block of data with specific
+// length
+//--------------------------------------------------
+int cmdEncryptTestSet(DEncEncryptedData** ppEncData, int nSize, char* dir, int nDdoc, int nDel)
+{
+ DEncEncryptionProperty* pEncProperty = 0;
+ int err = ERR_OK, i, nCompress, l2;
+ char *p = 0, fname1[256], fname2[256], c, *p2;
+ SignedDoc* pSigDoc = 0;
+ DataFile *pDf = 0;
+ FILE* hFile;
+ DigiDocMemBuf mbuf1;
+
+ mbuf1.pMem = 0;
+ mbuf1.nLen = 0;
+ nCompress = ConfigItem_lookup_int("DENC_COMPRESS_MODE", DENC_COMPRESS_ALLWAYS);
+ ddocDebug(3, "EncTest", "Test: %d", nSize);
+ err = dencEncryptedData_new(ppEncData, DENC_XMLNS_XMLENC, DENC_ENC_METHOD_AES128, 0, 0, 0);
+ if(err) return err;
+ err = dencMetaInfo_SetLibVersion(*ppEncData);
+ if(err) return err;
+ err = dencMetaInfo_SetFormatVersion(*ppEncData);
+ if(err) return err;
+ sprintf(fname1, "%stest-%d.dat", dir, nSize);
+ err = dencEncryptionProperty_new(*ppEncData, &pEncProperty, 0, 0, ENCPROP_FILENAME, fname1);
+ if(err) return err;
+ p = (char*)malloc(nSize+1);
+ if(!p) return ERR_BAD_ALLOC;
+ memset(p, 0, nSize+1);
+ for(i = 0, c = 'A'; i < nSize; i++, c++) {
+ p[i] = c;
+ if(c >= 'z') c = 'A';
+ }
+ // append x.923 padding if last block is full
+ if(nSize % 16 == 0) {
+ ddocDebug(3, "EncTest", "Full size: %d. Change last 8 bytes to X.923 padding", nSize);
+ p[nSize-1] = 8;
+ for(i = nSize -2; i > nSize - 9; i--)
+ p[i] = 0;
+ }
+ l2 = nSize * 2 + 1;
+ p2 = (char*)malloc(l2);
+ if(!p2) return ERR_BAD_ALLOC;
+ memset(p2, 0, l2);
+ bin2hex((const byte*)p, nSize, (byte*)p2, &l2);
+ ddocDebug(3, "EncTest", "Fil data hex: \"%s\" len: %d", p2, l2);
+ if((hFile = fopen(fname1, "w")) != NULL) {
+ fwrite(p, nSize, 1, hFile);
+ fclose(hFile);
+ }
+ free(p); p = 0;
+ fname2[0] = 0;
+ if(nDdoc) {
+ err = dencEncryptionProperty_new(*ppEncData, &pEncProperty, 0, 0, ENCPROP_ORIG_MIME, DENC_ENCDATA_TYPE_DDOC);
+ err = SignedDoc_new(&pSigDoc, "DIGIDOC-XML", "1.3");
+ if(!err) {
+ err = DataFile_new(&pDf, pSigDoc, NULL, fname1, "EMBEDDED_BASE64", "text/txt", nSize, NULL, 0, NULL, NULL);
+ if(!err) {
+ err = dencOrigContent_registerDigiDoc(*ppEncData, pSigDoc);
+ if(!err) {
+ sprintf(fname2, "%stest-%d.ddoc", dir, nSize);
+ err = createSignedDoc(pSigDoc, NULL, fname2);
+ if(!err) {
+ err = ddocReadFile(fname2, &mbuf1);
+ if(!err)
+ err = dencEncryptedData_AppendData(*ppEncData, mbuf1.pMem, mbuf1.nLen);
+ }
+ }
+ }
+ }
+ //ddocDebug(3, "EncTest", "Enc data: \"%s\"", mbuf1.pMem);
+ if(nDel && fname2[0])
+ remove(fname2);
+ ddocMemBuf_free(&mbuf1);
+ } else {
+ err = dencEncryptedData_AppendData(*ppEncData, p, nSize);
+ }
+ if(nDel && fname1[0])
+ remove(fname1);
+
+ if(!err)
+ err = dencEncryptedData_encryptData(*ppEncData, nCompress);
+ if(pSigDoc)
+ SignedDoc_free(pSigDoc);
+ return err;
+}
+
+//--------------------------------------------------
+// Encrypts generated test files
+//--------------------------------------------------
+int runEncryptTestSetCmds(int argc, char** argv)
+{
+ int err = ERR_OK, i, j;
+ DEncEncryptedData* pEncData = 0;
+ DEncEncryptedKey* pEncKey = 0;
+ X509* pCert = 0;
+ char fname[128];
+
+ for(i = 1; (err == ERR_OK) && (i < argc); i++) {
+ if(argv[i][0] == '-') { // all commands and options must start with -
+ // add a recipients key
+ if(!strcmp(argv[i], "-encrypt-test-set")) {
+ if(argc > i+2 && argv[i+1][0] != '-' && argv[i+2][0] != '-') {
+ char* certfile = argv[i+1];
+ char* recipient = argv[i+2];
+ char* outdir = argv[i+3];
+ int nStart = atoi(argv[i+4]);
+ int nEnd = atoi(argv[i+5]);
+ int nDdoc = atoi(argv[i+6]);
+ int nDel = atoi(argv[i+7]);
+
+ for(j = nStart; j < nEnd; j++) {
+ err = ReadCertificate(&pCert, certfile);
+ if(err) return err;
+ pEncData = 0;
+ err = cmdEncryptTestSet(&pEncData, j, outdir, nDdoc, nDel);
+ if(err) return err;
+ err = dencEncryptedKey_new(pEncData, &pEncKey, pCert,
+ DENC_ENC_METHOD_RSA1_5,
+ NULL, recipient, NULL, NULL);
+ sprintf(fname, "%stest-%d.cdoc", outdir, j);
+ err = dencGenEncryptedData_writeToFile(pEncData, fname);
+ dencEncryptedData_free(pEncData);
+ pEncKey = 0;
+ pEncData = 0;
+ }
+ } else {
+ err = ERR_BAD_PARAM;
+ addError(err, __FILE__, __LINE__, "Invalid parameters for -encrypt-test-set command");
+ }
+ }
+ }
+ }
+ return err;
+}
+
+
+//--------------------------------------------------
+// Lists EncryptedData objects
+//--------------------------------------------------
+int cmdListEncryptedData(DEncEncryptedData* pEncData)
+{
+ int err = ERR_OK, k;
+ char buf1[50], buf2[50];
+
+ if(g_cgiMode) {
+ fprintf(stdout, "\nEncryptedData%s%s%s%s%s%s%s%s",
+ g_szOutputSeparator, (pEncData->szId ? pEncData->szId : ""),
+ g_szOutputSeparator, (pEncData->szType ? pEncData->szType : ""),
+ g_szOutputSeparator, (pEncData->szMimeType ? pEncData->szMimeType : ""),
+ g_szOutputSeparator, (pEncData->szEncryptionMethod ? pEncData->szEncryptionMethod : ""));
+ err = dencMetaInfo_GetLibVersion(pEncData, buf1, sizeof(buf1), buf2, sizeof(buf2));
+ fprintf(stdout, "\nLIBRARY%s%s%s%s", g_szOutputSeparator, buf1, g_szOutputSeparator, buf2);
+ err = dencMetaInfo_GetFormatVersion(pEncData, buf1, sizeof(buf1), buf2, sizeof(buf2));
+ fprintf(stdout, "\nFORMAT%s%s%s%s", g_szOutputSeparator, buf1, g_szOutputSeparator, buf2);
+ } else {
+ fprintf(stdout, "\nEncryptedData - Id=%s Type=%s MimeType=%s EncryptionMethod=%s",
+ (pEncData->szId ? pEncData->szId : ""),
+ (pEncData->szType ? pEncData->szType : ""),
+ (pEncData->szMimeType ? pEncData->szMimeType : ""),
+ (pEncData->szEncryptionMethod ? pEncData->szEncryptionMethod : ""));
+ err = dencMetaInfo_GetLibVersion(pEncData, buf1, sizeof(buf1), buf2, sizeof(buf2));
+ fprintf(stdout, "\n\tLIBRARY: %s VERSION: %s", buf1, buf2);
+ err = dencMetaInfo_GetFormatVersion(pEncData, buf1, sizeof(buf1), buf2, sizeof(buf2));
+ fprintf(stdout, "\n\tFORMAT: %s VERSION: %s", buf1, buf2);
+ }
+ for(k = 0; k < pEncData->nEncryptedKeys; k++) {
+ DEncEncryptedKey *pEncKey = pEncData->arrEncryptedKeys[k];
+ if(g_cgiMode)
+ fprintf(stdout, "\nEncryptedKey%s%s%s%s%s%s%s%s%s%s%s%s",
+ g_szOutputSeparator, (pEncKey->szId ? pEncKey->szId : ""),
+ g_szOutputSeparator, (pEncKey->szRecipient ? pEncKey->szRecipient : ""),
+ g_szOutputSeparator, (pEncKey->szKeyName ? pEncKey->szKeyName : ""),
+ g_szOutputSeparator, (pEncKey->szCarriedKeyName ? pEncKey->szCarriedKeyName : ""),
+ g_szOutputSeparator, (pEncKey->szEncryptionMethod ? pEncKey->szEncryptionMethod : ""),
+ g_szOutputSeparator, (pEncKey->pCert ? "OK" : "NULL"));
+ else
+ fprintf(stdout, "\nEncryptedKey: Id=%s Recipient=%s KeyName=%s CarriedKeyName=%s EncryptionMethod=%s Cert: %s",
+ (pEncKey->szId ? pEncKey->szId : ""),
+ (pEncKey->szRecipient ? pEncKey->szRecipient : ""),
+ (pEncKey->szKeyName ? pEncKey->szKeyName : ""),
+ (pEncKey->szCarriedKeyName ? pEncKey->szCarriedKeyName : ""),
+ (pEncKey->szEncryptionMethod ? pEncKey->szEncryptionMethod : ""),
+ (pEncKey->pCert ? "OK" : "NULL"));
+ }
+ if(pEncData->encProperties.nEncryptionProperties > 0) {
+ if(g_cgiMode)
+ fprintf(stdout, "\nEncryptionProperties%s%s",
+ g_szOutputSeparator, (pEncData->encProperties.szId ? pEncData->encProperties.szId : ""));
+ else
+ fprintf(stdout, "\nEncryptionProperties: %s",
+ (pEncData->encProperties.szId ? pEncData->encProperties.szId : ""));
+ for(k = 0; k < pEncData->encProperties.nEncryptionProperties; k++) {
+ DEncEncryptionProperty *pEncProp = pEncData->encProperties.arrEncryptionProperties[k];
+ if(g_cgiMode)
+ fprintf(stdout, "\nEncryptionProperty%s%s%s%s%s%s%s%s\n",
+ g_szOutputSeparator, (pEncProp->szId ? pEncProp->szId : ""),
+ g_szOutputSeparator, (pEncProp->szTarget ? pEncProp->szTarget : ""),
+ g_szOutputSeparator, (pEncProp->szName ? pEncProp->szName : ""),
+ g_szOutputSeparator, (pEncProp->szContent ? pEncProp->szContent : ""));
+ else
+ fprintf(stdout, "\nEncryptionProperty Id=%s Target=%s Name=%s Content=%s\n",
+ (pEncProp->szId ? pEncProp->szId : ""),
+ (pEncProp->szTarget ? pEncProp->szTarget : ""),
+ (pEncProp->szName ? pEncProp->szName : ""),
+ (pEncProp->szContent ? pEncProp->szContent : ""));
+ }
+ }
+ return err;
+}
+
+//--------------------------------------------------
+// Add ecryption recipients
+//--------------------------------------------------
+int runDEncListCmds(int argc, char** argv)
+{
+ int err = ERR_OK, i;
+ DEncEncryptedData* pEncData = 0;
+
+ for(i = 1; (err == ERR_OK) && (i < argc); i++) {
+ if(argv[i][0] == '-') { // all commands and options must start with -
+ // add a recipients key
+ if(!strcmp(argv[i], "-denc-list")) {
+ if(argc > i+1 && argv[i+1][0] != '-') {
+ char* file = argv[i+1];
+ err = dencSaxReadEncryptedData(&pEncData, file);
+ if(!err)
+ err = cmdListEncryptedData(pEncData);
+ if(pEncData && !err)
+ dencEncryptedData_free(pEncData);
+ } else {
+ err = ERR_BAD_PARAM;
+ addError(err, __FILE__, __LINE__, "Missing <file> argument of -denc-list command");
+ }
+ }
+ }
+ }
+ return err;
+}
+
+//--------------------------------------------------
+// decryption file
+//--------------------------------------------------
+int runDecryptCmds(int argc, char** argv, DEncEncryptedData** ppEncData)
+{
+ int err = ERR_OK, i, bDecSk = 0, nSlot = 0, nKey = 0;
+ DEncEncryptedKey* pEncKey = 0;
+ FILE *hFile = 0;
+ SignedDoc *pSigDoc = 0;
+ DataFile *pDf = 0;
+ char fname1[256], *pkcs12file = 0, *infile = 0, *pin = 0, key[300];
+ EVP_PKEY *pkey;
+#ifdef WIN32
+ wchar_t *convFileName = 0;
+ int l1 = 0;
+#endif
+
+ for(i = 1; (err == ERR_OK) && (i < argc); i++) {
+ if(argv[i][0] == '-') { // all commands and options must start with -
+ // decrypt file
+ if(!strcmp(argv[i], "-decrypt") ||
+ !strcmp(argv[i], "-decrypt-hex") ||
+ !strcmp(argv[i], "-decrypt-sk")) {
+ if(!strcmp(argv[i], "-decrypt-sk")) bDecSk = 1;
+ if(argc > i+3 &&
+ argv[i+1][0] != '-' &&
+ argv[i+2][0] != '-') {
+ ddocConvertInput(argv[i+1], &infile);
+ ddocConvertInput(argv[i+2], &pin);
+ nKey = 0;
+ memset(key, 0, sizeof(key));
+ if(!strcmp(argv[i], "-decrypt-hex")) {
+ nKey = sizeof(key);
+ hex2bin(pin, (byte*)key, &nKey);
+ }
+ i += 2;
+ if(argc > i+1 && argv[i+1][0] != '-') {
+ ddocConvertInput(argv[i+1], &pkcs12file);
+ i++;
+ }
+ if(argc > i+2 && argv[i+2][0] != '-') {
+ nSlot = atoi(argv[i+2]);
+ i++;
+ }
+ ddocDebug(3, "runDecryptCmds", "Decrypt file: %s pin: %s pkcs12: %s slot: %d", infile, pin, pkcs12file, nSlot);
+ err = dencSaxReadEncryptedData(ppEncData, infile);
+ if(err) return err;
+ // if using hex key
+ if(nKey > 0) {
+ ddocDebug(3, "runDecryptCmds", "Decrypt with key: %s len: %d", pin, nKey);
+ err = dencEncryptedData_decrypt_withKey(*ppEncData, key, nKey);
+ }
+ // if using pkcs12
+ else if(pkcs12file != NULL && strlen(pkcs12file) > 0) {
+ ddocDebug(3, "runDecryptCmds", "Opening pkcs12 file: %s", pkcs12file);
+ err = dencEncryptedData_findEncryptedKeyByPKCS12(*ppEncData, &pEncKey, &pkey, pkcs12file, pin);
+ } else {
+ ddocDebug(3, "runDecryptCmds", "Connecting to pkcs11, slot: %d", nSlot);
+ err = dencEncryptedData_findEncryptedKeyByPKCS11UsingSlot(*ppEncData, &pEncKey, nSlot);
+ }
+ if(!nKey) {
+ if(pEncKey) {
+ if(pkcs12file != NULL && strlen(pkcs12file) > 0)
+ err = dencEncryptedData_decryptWithKey(*ppEncData, pEncKey, pkey);
+ else
+ err = dencEncryptedData_decryptUsingSlot(*ppEncData, pEncKey, pin, nSlot);
+ if(err) return err;
+ } else {
+ err = ERR_DENC_DECRYPT;
+ addError(err, __FILE__, __LINE__, "No transport key found for your smartcard");
+ }
+ }
+ // read in ddoc if necessary
+ if(bDecSk && p_szOutFile) {
+ sprintf(fname1, "%s.ddoc", p_szOutFile);
+ ddocDebug(3, "runDecryptCmds", "writing ddoc to: %s", fname1);
+#ifdef WIN32
+ err = utf82unicode((const char*)fname1, (char**)&convFileName, &l1);
+ ddocDebug(3, "ddocReadFile", "file: %s, conv-file: %s len: %d", fname1, convFileName, i);
+ if((hFile = _wfopen(convFileName, L"wb")) != NULL) {
+#else
+ if((hFile = fopen(fname1, "wb")) != NULL) {
+#endif
+ fwrite((*ppEncData)->mbufEncryptedData.pMem, (*ppEncData)->mbufEncryptedData.nLen, 1, hFile);
+ fclose(hFile);
+ ddocDebug(3, "runDecryptCmds", "Reading ddoc: %s", fname1);
+ err = ddocSaxReadSignedDocFromFile(&pSigDoc, fname1, 0, 0);
+ if(!err && getCountOfDataFiles(pSigDoc) > 0) {
+ pDf = getDataFile(pSigDoc, 0);
+ ddocDebug(3, "runDecryptCmds", "writing DF: %s to: %s", pDf->szId, p_szOutFile);
+ err = ddocExtractDataFile(pSigDoc, fname1, p_szOutFile, pDf->szId, "UTF-8");
+ dencEncryptedData_free(*ppEncData);
+ *ppEncData = NULL;
+ p_szOutFile = NULL;
+ }
+ SignedDoc_free(pSigDoc);
+ if(fname1[0] && !remove(fname1))
+ ddocDebug(3, "runDecryptCmds", "error deleting file: %", fname1);
+ }
+ }
+ // p_szOutFile
+ } else {
+ err = ERR_BAD_PARAM;
+ addError(err, __FILE__, __LINE__, "Missing <file> or <pin> argument of -decrypt command");
+ }
+ }
+ }
+ }
+ return err;
+}
+
+//--------------------------------------------------
+// Create digidoc and adds datafiles
+//--------------------------------------------------
+int runExtractCmds(int argc, char** argv, SignedDoc** ppSigDoc)
+{
+ int err = ERR_OK, i;
+
+ for(i = 1; (err == ERR_OK) && (i < argc); i++) {
+ if(argv[i][0] == '-') { // all commands and options must start with -
+ // add a DataFile
+ if(!strcmp(argv[i], "-extract")) {
+ if(argc > i+2 && argv[i+1][0] != '-' && argv[i+2][0] != '-') {
+ char* id = NULL;
+ char* file = NULL;
+ char* charset = CHARSET_UTF_8;
+ checkArguments(argc, argv, &i, &id);
+ checkArguments(argc, argv, &i, &file);
+ // optional charset & filenamecharset
+ //checkArguments(argc, argv, &i, &charset);
+ err = ddocExtractDataFile(*ppSigDoc, (const char*)p_szInFile, (const char*)file,
+ (const char*)id, (const char*)charset);
+ // report success
+ if(g_cgiMode)
+ fprintf(stdout, "\nDataFile%s%s%s%s%s%d", g_szOutputSeparator, id,
+ g_szOutputSeparator, file, g_szOutputSeparator, err);
+ else
+ fprintf(stdout, "\nDataFile id: %s path: %s rc: %d", id, file, err);
+
+ if(id) freeLibMem(id);
+ if(file) freeLibMem(file);
+
+ } else {
+ err = ERR_BAD_PARAM;
+ addError(err, __FILE__, __LINE__, "Missing <file> argument of -extract command");
+ }
+ }
+ }
+ }
+ return err;
+}
+
+//--------------------------------------------------
+// Create digidoc and adds datafiles
+//--------------------------------------------------
+int runExtractMemCmds(int argc, char** argv, SignedDoc** ppSigDoc)
+{
+ int err = ERR_OK, i;
+ char* pBuf = 0;
+ long nLen = 0;
+ FILE* hFile = 0;
+
+ for(i = 1; (err == ERR_OK) && (i < argc); i++) {
+ if(argv[i][0] == '-') { // all commands and options must start with -
+ // extract DataFile
+ if(!strcmp(argv[i], "-extract-mem")) {
+ if(argc > i+2 && argv[i+1][0] != '-' && argv[i+2][0] != '-') {
+ char* id = NULL;
+ char* file = NULL;
+ checkArguments(argc, argv, &i, &id);
+ checkArguments(argc, argv, &i, &file);
+ err = ddocGetDataFileCachedData(*ppSigDoc, id, (void**)&pBuf, &nLen);
+ printf("\nExtract DF: %s, err: %d data: %ld", id, err, nLen);
+ if(file && (hFile = fopen(file, "wb")) != NULL && pBuf && nLen)
+ fwrite(pBuf, nLen, 1, hFile);
+ if(id) freeLibMem(id);
+ if(file) freeLibMem(file);
+ if(hFile) fclose(hFile);
+ } else {
+ err = ERR_BAD_PARAM;
+ addError(err, __FILE__, __LINE__, "Missing <file> argument of -extract command");
+ }
+ }
+ }
+ }
+ if(pBuf)
+ freeLibMem(pBuf);
+ if(hFile)
+ fclose(hFile);
+ return err;
+}
+
+
+//--------------------------------------------------
+// Verfys sigantures and notaries
+//--------------------------------------------------
+int runVerifyCmds(int argc, char** argv, SignedDoc* pSigDoc, DEncEncryptedData* pEncData)
+{
+ int err = ERR_OK, i;
+
+ for(i = 1; !err && (i < argc); i++) {
+ if(argv[i][0] == '-') { // all commands and options must start with -
+ // create new digidoc
+ if(!strcmp(argv[i], "-verify")) {
+ if(pSigDoc) {
+ err = cmdVerify(pSigDoc);
+ }
+ if(pEncData)
+ err = dencValidate(pEncData);
+ }
+ }
+ }
+ return err;
+}
+
+
+//--------------------------------------------------
+// Handles signature commands
+//--------------------------------------------------
+int runSignCmds(int argc, char** argv, SignedDoc** ppSigDoc)
+{
+ int err = ERR_OK, i, nManif, nSlot = 0, nOcsp = 1, nSigner = 1;
+
+ for(i = 1; !err && (i < argc); i++) {
+ if(argv[i][0] == '-') { // all commands and options must start with -
+ // create new digidoc
+ if(!strcmp(argv[i], "-sign")) {
+ char* pin = NULL;
+ char* manifest = NULL;
+ char* city = NULL;
+ char* state = NULL;
+ char* zip = NULL;
+ char* country = NULL;
+ char* sSlot = NULL;
+ char* sOcsp = NULL;
+ char* sSigner = NULL;
+ char* szPkcs12File = NULL;
+ checkArguments(argc, argv, &i, &pin);
+ // if pin is NULL check for autosign pin
+ if(!pin)
+ pin = (char*)ConfigItem_lookup("AUTOSIGN_PIN");
+ if(!pin) {
+ err = ERR_BAD_PARAM;
+ addError(err, __FILE__, __LINE__, "Missing <pin> argument of -sign command");
+ return err;
+ }
+ // check config file
+ nManif = ConfigItem_lookup_int("MANIFEST_MODE", 0);
+ if(nManif == 2) {
+ manifest = (char*)ConfigItem_lookup("DIGIDOC_ROLE_MANIFEST");
+ country = (char*)ConfigItem_lookup("DIGIDOC_ADR_COUNTRY");
+ state = (char*)ConfigItem_lookup("DIGIDOC_ADR_STATE");
+ city = (char*)ConfigItem_lookup("DIGIDOC_ADR_CITY");
+ zip = (char*)ConfigItem_lookup("DIGIDOC_ADR_ZIP");
+ }
+ // optional mainfest argument
+ checkArguments(argc, argv, &i, &manifest);
+ // optional address
+ checkArguments(argc, argv, &i, &city);
+ checkArguments(argc, argv, &i, &state);
+ checkArguments(argc, argv, &i, &zip);
+ checkArguments(argc, argv, &i, &country);
+ checkArguments(argc, argv, &i, &sSlot);
+ checkArguments(argc, argv, &i, &sOcsp);
+ checkArguments(argc, argv, &i, &sSigner);
+ if(sSlot)
+ nSlot = atoi(sSlot);
+ if(sOcsp)
+ nOcsp = atoi(sOcsp);
+ if(sSigner) {
+ if(!strcmp(sSigner, "PKCS11")) nSigner = 1;
+ if(!strcmp(sSigner, "PKCS12")) nSigner = 3;
+#ifdef WIN32
+ if(!strcmp(sSigner, "CNG")) nSigner = 2;
+#endif
+ }
+ checkArguments(argc, argv, &i, &szPkcs12File);
+ err = cmdSign(*ppSigDoc, (const char*)pin, (const char*)manifest,
+ (const char*)city, (const char*)state, (const char*)zip,
+ (const char*)country, nSlot, nOcsp, nSigner, szPkcs12File);
+ if(manifest) freeLibMem(manifest);
+ if(city) freeLibMem(city);
+ if(state) freeLibMem(state);
+ if(zip) freeLibMem(zip);
+ if(country) freeLibMem(country);
+ if(sSlot) freeLibMem(sSlot);
+ if(sOcsp) freeLibMem(sOcsp);
+ if(sSigner) freeLibMem(sSigner);
+ if(szPkcs12File) freeLibMem(szPkcs12File);
+ }
+ }
+ }
+ return err;
+}
+
+
+//--------------------------------------------------
+// Handles commands related to checking certificates
+//--------------------------------------------------
+int runCheckCertCmds(int argc, char** argv)
+{
+ int err = ERR_OK, i;
+ char* szCertFile = 0;
+ X509* pCert = 0;
+ DigiDocMemBuf mbuf;
+
+ mbuf.pMem = 0;
+ mbuf.nLen = 0;
+ for(i = 1; !err && (i < argc); i++) {
+ if(!strcmp(argv[i], "-check-cert") &&
+ argv[i+1][0] != '-') {
+ szCertFile = argv[i+1];
+ i++;
+ if(szCertFile) {
+ err = ReadCertificate(&pCert, szCertFile);
+ if(!err && pCert) {
+ err = ddocVerifyCertByOCSP(pCert, NULL);
+ err = ddocCertGetSubjectCN(pCert, &mbuf);
+ printf("Verifying cert: %s --> RC :%d\n", (const char*)mbuf.pMem, err);
+ ddocMemBuf_free(&mbuf);
+ }
+ if(pCert) {
+ X509_free(pCert);
+ pCert = 0;
+ }
+ }
+ }
+ }
+ return err;
+}
+
+//--------------------------------------------------
+// Handles commands related to adding signature value
+// from a file containging base64 encoded RSA-SHA1 signature value
+//--------------------------------------------------
+int runAddSignValueCmds(int argc, char** argv, SignedDoc* pSigDoc)
+{
+ int err = ERR_OK, i;
+ char *szSignFile = 0, *szSignId = 0;
+ SignatureInfo* pSignInfo = 0;
+
+ for(i = 1; !err && (i < argc); i++) {
+ if(!strcmp(argv[i], "-add-sign-value") && i < argc - 2 &&
+ argv[i+1][0] != '-' && argv[i+2][0] != '-') {
+ checkArguments(argc, argv, &i, &szSignFile);
+ checkArguments(argc, argv, &i, &szSignId);
+ if(!pSigDoc) {
+ err = ERR_BAD_PARAM;
+ addError(err, __FILE__, __LINE__, "No digidoc document read in yet!");
+ return err;
+ }
+ if(szSignFile && szSignId) {
+ pSignInfo = getSignatureWithId(pSigDoc, szSignId);
+ if(pSignInfo) {
+ // read the file
+ err = setSignatureValueFromFile(pSignInfo, szSignFile);
+ } else {
+ err = ERR_BAD_PARAM;
+ addError(err, __FILE__, __LINE__, "Wrong signature id");
+ }
+ // report on success
+ if(g_cgiMode)
+ fprintf(stdout, "\nAddSignValue%s%s%s%s%s%d", g_szOutputSeparator, szSignId,
+ g_szOutputSeparator, szSignFile, g_szOutputSeparator, err);
+ else
+ fprintf(stdout, "\nAddSignValue id: %s path: %s rc: %d", szSignId, szSignFile, err);
+ } else {
+ err = ERR_BAD_PARAM;
+ addError(err, __FILE__, __LINE__, "Missing <sign-value-file> or <sign-id> argument of -add-sign-value command");
+ }
+ }
+ }
+ if(szSignFile) freeLibMem(szSignFile);
+ if(szSignId) freeLibMem(szSignId);
+ return err;
+}
+
+
+//--------------------------------------------------
+// Handles commands related to deleting signatures
+//--------------------------------------------------
+int runDelSignCmds(int argc, char** argv, SignedDoc* pSigDoc)
+{
+ int err = ERR_OK, i;
+ char *szSignId = 0;
+ SignatureInfo* pSignInfo = 0;
+
+ for(i = 1; !err && (i < argc); i++) {
+ if(!strcmp(argv[i], "-del-sign") && i < argc - 1 &&
+ argv[i+1][0] != '-') {
+ checkArguments(argc, argv, &i, &szSignId);
+ if(!pSigDoc) {
+ err = ERR_BAD_PARAM;
+ addError(err, __FILE__, __LINE__, "No digidoc document read in yet!");
+ return err;
+ }
+ if(szSignId) {
+ pSignInfo = getSignatureWithId(pSigDoc, szSignId);
+ if(pSignInfo) {
+ err = SignatureInfo_delete(pSigDoc, szSignId);
+ // report on success
+ if(g_cgiMode)
+ fprintf(stdout, "\nDelSign%s%s%s%d", g_szOutputSeparator, szSignId,
+ g_szOutputSeparator, err);
+ else
+ fprintf(stdout, "\nDelSign id: %s rc: %d", szSignId, err);
+
+ } else {
+ err = ERR_BAD_PARAM;
+ addError(err, __FILE__, __LINE__, "wrong signature id!");
+ }
+ } else {
+ err = ERR_BAD_PARAM;
+ addError(err, __FILE__, __LINE__, "Missing <sign-id> argument of -del-sign command");
+ }
+ }
+ }
+ if(szSignId) freeLibMem(szSignId);
+ return err;
+}
+
+
+//--------------------------------------------------
+// Handles commands related to notarizing signatures
+//--------------------------------------------------
+int runGetConfirmationCmds(int argc, char** argv, SignedDoc* pSigDoc)
+{
+ int err = ERR_OK, i;
+ char *szSignId = 0;
+ SignatureInfo* pSignInfo = 0;
+
+ for(i = 1; !err && (i < argc); i++) {
+ if(!strcmp(argv[i], "-get-confirmation") && i < argc - 1 &&
+ argv[i+1][0] != '-') {
+ checkArguments(argc, argv, &i, &szSignId);
+ if(!pSigDoc) {
+ err = ERR_BAD_PARAM;
+ addError(err, __FILE__, __LINE__, "No digidoc document read in yet!");
+ return err;
+ }
+ if(szSignId) {
+ pSignInfo = getSignatureWithId(pSigDoc, szSignId);
+ if(pSignInfo) {
+ err = notarizeSignature(pSigDoc, pSignInfo);
+ // report on success
+ if(g_cgiMode)
+ fprintf(stdout, "\nNotarizeSignature%s%s%s%d", g_szOutputSeparator, szSignId,
+ g_szOutputSeparator, err);
+ else
+ fprintf(stdout, "\nNotarizeSignature id: %s rc: %d", szSignId, err);
+
+ } else {
+ err = ERR_BAD_PARAM;
+ addError(err, __FILE__, __LINE__, "wrong signature id!");
+ }
+ if(szSignId) freeLibMem(szSignId);
+ } else {
+ err = ERR_BAD_PARAM;
+ addError(err, __FILE__, __LINE__, "Missing <sign-id> argument of -get-confirmation command");
+ }
+ }
+ }
+ return err;
+}
+
+
+//--------------------------------------------------
+// Signs the document and gets configrmation
+//--------------------------------------------------
+int cmdCalcSign(SignedDoc* pSigDoc, const char* manifest,
+ const char* city, const char* state, const char* zip,
+ const char* country, const char* certFile)
+{
+ int err = ERR_OK, l1;
+ SignatureInfo* pSigInfo = NULL;
+ X509* pCert = NULL;
+ char buf1[50];
+
+ ddocDebug(3, "cmdCalcSign", "Creating new digital signature");
+ RETURN_IF_NULL_PARAM(pSigDoc);
+ RETURN_IF_NULL_PARAM(certFile);
+ // read certificate
+ // this certificate will nto be released since new signature takes ownership!
+ err = ReadCertificate(&pCert, certFile);
+ RETURN_IF_NOT(err == ERR_OK, err);
+ // prepare signature
+ err = ddocPrepareSignature(pSigDoc, &pSigInfo,
+ manifest, city, state, zip, country, pCert, NULL);
+ // base64 encode final hash
+ l1 = sizeof(buf1);
+ err = ddocGetSignedHash(pSigInfo, buf1, &l1, 2, 0);
+ RETURN_IF_NOT(err == ERR_OK, err);
+ // report on success
+ if(g_cgiMode)
+ fprintf(stdout, "\nSignatureHash%s%s%s%s%s%d", g_szOutputSeparator, pSigInfo->szId,
+ g_szOutputSeparator, buf1, g_szOutputSeparator, err);
+ else
+ fprintf(stdout, "\nSignatureHash id: %s hash: %s rc: %d", pSigInfo->szId, buf1, err);
+
+
+ RETURN_IF_NOT(err == ERR_OK, err);
+ return ERR_OK;
+}
+
+//--------------------------------------------------
+// Handles signature commands
+//--------------------------------------------------
+int runCalcSignCmds(int argc, char** argv, SignedDoc* pSigDoc)
+{
+ int err = ERR_OK, i, nManif;
+
+ for(i = 1; !err && (i < argc); i++) {
+ if(argv[i][0] == '-') { // all commands and options must start with -
+ // create new digidoc
+ if(!strcmp(argv[i], "-calc-sign")) {
+ char* certFile = NULL;
+ char* manifest = NULL;
+ char* city = NULL;
+ char* state = NULL;
+ char* zip = NULL;
+ char* country = NULL;
+ checkArguments(argc, argv, &i, &certFile);
+ // check config file
+ nManif = ConfigItem_lookup_int("MANIFEST_MODE", 0);
+ if(nManif == 2) {
+ manifest = (char*)ConfigItem_lookup("DIGIDOC_ROLE_MANIFEST");
+ country = (char*)ConfigItem_lookup("DIGIDOC_ADR_COUNTRY");
+ state = (char*)ConfigItem_lookup("DIGIDOC_ADR_STATE");
+ city = (char*)ConfigItem_lookup("DIGIDOC_ADR_CITY");
+ zip = (char*)ConfigItem_lookup("DIGIDOC_ADR_ZIP");
+ }
+ // optional mainfest argument
+ checkArguments(argc, argv, &i, &manifest);
+ // optional address
+ checkArguments(argc, argv, &i, &city);
+ checkArguments(argc, argv, &i, &state);
+ checkArguments(argc, argv, &i, &zip);
+ checkArguments(argc, argv, &i, &country);
+ if(!certFile) {
+ err = ERR_BAD_PARAM;
+ addError(err, __FILE__, __LINE__, "Missing <cert-file> argument of -calc-sign command");
+ }
+ else
+ err = cmdCalcSign(pSigDoc, (const char*)manifest,
+ (const char*)city, (const char*)state, (const char*)zip,
+ (const char*)country, (const char*)certFile);
+ if(manifest) freeLibMem(manifest);
+ if(city) freeLibMem(city);
+ if(state) freeLibMem(state);
+ if(zip) freeLibMem(zip);
+ if(country) freeLibMem(country);
+ if(certFile) freeLibMem(certFile);
+ }
+ }
+ }
+ return err;
+}
+
+
+//--------------------------------------------------
+// Signs the document and gets configrmation
+//--------------------------------------------------
+int cmdMidSign(SignedDoc* pSigDoc, const char* szPhoneNo,
+ const char* szIdCode, const char* szLang,
+ const char* szService,
+ const char* manifest, const char* city,
+ const char* state, const char* zip,
+ const char* country)
+{
+ int err = ERR_OK, nPollFreq = 0, l1, nStatus = 0;
+ char* szUrl = 0, *szProxyHost = 0, *szProxyPort = 0;
+ long lSesscode = 0;
+ char buf1[10];
+ DigiDocMemBuf mbuf1;
+#ifdef WIN32
+ time_t tNew, tOld;
+#endif
+
+ mbuf1.pMem = 0;
+ mbuf1.nLen = 0;
+ nPollFreq = ConfigItem_lookup_int("DDS_POLLFREQ", 0);
+ szUrl = (char*)ConfigItem_lookup("DDS_URL");
+ szProxyHost = (char*)ConfigItem_lookup("DDS_PROXY_HOST");
+ szProxyPort = (char*)ConfigItem_lookup("DDS_PROXY_PORT");
+ ddocDebug(3, "cmdMidSign", "Creating MID signature using: %s poll freq: %d", szPhoneNo, nPollFreq);
+ // send signature req
+ l1 = sizeof(buf1);
+ ddsSign(pSigDoc, szIdCode, szPhoneNo, szLang, szService,
+ manifest, city, state, zip, country, szUrl, szProxyHost, szProxyPort,
+ &lSesscode, buf1, l1);
+
+ // report on success
+ if(g_cgiMode)
+ fprintf(stdout, "\nMIDSinatureReq%s%ld%s%d",
+ g_szOutputSeparator, lSesscode,
+ g_szOutputSeparator, err);
+ else
+ fprintf(stdout, "\nMIDSignatureReq session: %ld rc: %d", lSesscode, err);
+ // if we should keep on polling
+ if(!err && nPollFreq) {
+ // now check status
+ do {
+#ifdef WIN32
+ time(&tOld);
+ do {
+ time(&tNew);
+ } while(tNew - tOld < nPollFreq);
+#else
+ ddocDebug(3, "cmdMidSign", "Sleep: %d", nPollFreq);
+ sleep(nPollFreq);
+#endif
+ err = ddsGetStatusWithFile(pSigDoc, lSesscode, szUrl, szProxyHost, szProxyPort, &nStatus, p_szInFile);
+ ddocDebug(3, "cmdMidSign", "Txn: %ld status: %d err: %d", lSesscode, nStatus, err);
+ } while(!err && nStatus == 1);
+ }
+ if(g_cgiMode)
+ fprintf(stdout, "\nMID session %s%ld%s%d",
+ g_szOutputSeparator, lSesscode,
+ g_szOutputSeparator, nStatus);
+ else
+ fprintf(stdout, "\nMID session %ld complete status: %d", lSesscode, nStatus);
+
+ RETURN_IF_NOT(err == ERR_OK, err);
+ return ERR_OK;
+}
+
+
+//--------------------------------------------------
+// Handles MID signature commands
+//--------------------------------------------------
+int runMidSignCmds(int argc, char** argv, SignedDoc* pSigDoc)
+{
+ int err = ERR_OK, i, nManif = 0;
+
+ for(i = 1; !err && (i < argc); i++) {
+ if(argv[i][0] == '-') { // all commands and options must start with -
+ // create new digidoc
+ if(!strcmp(argv[i], "-mid-sign")) {
+ char* phoneNo = NULL;
+ char* idcode = NULL;
+ char* service = NULL;
+ char* lang = NULL;
+ char* manifest = NULL;
+ char* city = NULL;
+ char* state = NULL;
+ char* zip = NULL;
+ char* country = NULL;
+ checkArguments(argc, argv, &i, &phoneNo);
+ // check config file
+ nManif = ConfigItem_lookup_int("MANIFEST_MODE", 0);
+ if(nManif == 2) {
+ manifest = (char*)ConfigItem_lookup("DIGIDOC_ROLE_MANIFEST");
+ country = (char*)ConfigItem_lookup("DIGIDOC_ADR_COUNTRY");
+ state = (char*)ConfigItem_lookup("DIGIDOC_ADR_STATE");
+ city = (char*)ConfigItem_lookup("DIGIDOC_ADR_CITY");
+ zip = (char*)ConfigItem_lookup("DIGIDOC_ADR_ZIP");
+ }
+ // optional mainfest argument
+ checkArguments(argc, argv, &i, &idcode);
+ checkArguments(argc, argv, &i, &country);
+ checkArguments(argc, argv, &i, &lang);
+ checkArguments(argc, argv, &i, &service);
+ checkArguments(argc, argv, &i, &manifest);
+ checkArguments(argc, argv, &i, &city);
+ checkArguments(argc, argv, &i, &state);
+ checkArguments(argc, argv, &i, &zip);
+ if(!phoneNo) {
+ err = ERR_BAD_PARAM;
+ addError(err, __FILE__, __LINE__, "Missing <phone-no> argument of -mid-sign command");
+ }
+ else
+ cmdMidSign(pSigDoc, (const char*)phoneNo, (const char*)idcode,
+ (const char*)(lang ? lang : "EST"),
+ (const char*)(service ? service : "Testimine"), (const char*)manifest,
+ (const char*)city, (const char*)state, (const char*)zip,
+ (const char*)(country ? country : "EE"));
+ if(manifest) freeLibMem(manifest);
+ if(city) freeLibMem(city);
+ if(state) freeLibMem(state);
+ if(zip) freeLibMem(zip);
+ if(country) freeLibMem(country);
+ if(phoneNo) freeLibMem(phoneNo);
+ }
+ }
+ }
+ return err;
+}
+
+
+//--------------------------------------------------
+// Handles MID signature commands
+//--------------------------------------------------
+int runMidTestCmds(int argc, char** argv, SignedDoc* pSigDoc)
+{
+ int err = ERR_OK, i, e1;
+ SignedDoc *pSdoc = NULL;
+ DataFile *pDf = NULL;
+ long lSize1, lSize2, lSize3;
+
+ for(i = 1; !err && (i < argc); i++) {
+ if(argv[i][0] == '-') { // all commands and options must start with -
+ // create new digidoc
+ if(!strcmp(argv[i], "-mid-test")) {
+ char* infile = NULL;
+ char* inmime = NULL;
+ char* outddoc = NULL;
+ char* phoneNo = NULL;
+ char* idcode = NULL;
+ char* service = NULL;
+ checkArguments(argc, argv, &i, &infile);
+ checkArguments(argc, argv, &i, &inmime);
+ checkArguments(argc, argv, &i, &outddoc);
+ checkArguments(argc, argv, &i, &phoneNo);
+ checkArguments(argc, argv, &i, &idcode);
+ checkArguments(argc, argv, &i, &service);
+ if(!phoneNo || !idcode || !infile || !inmime || !outddoc) {
+ err = ERR_BAD_PARAM;
+ addError(err, __FILE__, __LINE__, "Missing <phone-no> <idcode> <infile> <inmime> or <outddoc> argument of -mid-test command");
+ } else {
+ p_szInFile = outddoc;
+ printf("Creating ddoc: %s of file: %s mime: %s\n", outddoc, infile, inmime);
+ err = SignedDoc_new(&pSdoc, "DIGIDOC-XML", "1.3");
+ printf("Creating ddoc: %s rc: %d\n", outddoc, err);
+ RETURN_IF_NOT(err == ERR_OK, err);
+ err = calculateFileSize(infile, &lSize1);
+ err = DataFile_new(&pDf, pSdoc, NULL, infile, "EMBEDDED_BASE64", inmime, 0, NULL, 0, NULL, NULL);
+ err = createSignedDoc(pSdoc, NULL, outddoc);
+ if(pDf->nSize == 0 && lSize1 > 0)
+ pDf->nSize = lSize1;
+ err = calculateFileSize(outddoc, &lSize2);
+ printf("Add data-file: %s rc: %d d-size: %ld ddoc-size: %ld\n", infile, err, lSize1, lSize2);
+ err = ddocExtractDataFile(pSdoc, outddoc, "D0.dat", "D0", "UTF-8");
+ err = calculateFileSize("D0.dat", &lSize3);
+ printf("Extract before signing rc: %d size: %ld\n", err, lSize3);
+ printf("MID signing phone: %s id-code: %s\n", phoneNo, idcode);
+ err = cmdMidSign(pSdoc, (const char*)phoneNo, (const char*)idcode,
+ "EST", (service ? service : "Testimine"), NULL, NULL, NULL, NULL, "EE");
+ err = calculateFileSize(outddoc, &lSize2);
+ printf("MID signed phone: %s id-code: %s ddoc-size: %ld rc: %d\n", phoneNo, idcode, lSize2, err);
+ err = cmdVerify(pSdoc);
+ printf("\nVerify after signing rc: %d\n", err);
+ lSize3 = 0;
+ err = ddocExtractDataFile(pSdoc, outddoc, "D0.dat", "D0", "UTF-8");
+ err = calculateFileSize("D0.dat", &lSize3);
+ printf("Extract after signing rc: %d size: %ld\n", err, lSize3);
+ }
+ SignedDoc_free(pSdoc);
+ if(infile) freeLibMem(infile);
+ if(inmime) freeLibMem(inmime);
+ if(outddoc) freeLibMem(outddoc);
+ if(phoneNo) freeLibMem(phoneNo);
+ if(idcode) freeLibMem(idcode);
+ if(service) freeLibMem(service);
+ }
+ }
+ }
+ return err;
+}
+
+
+
+
+//--------------------------------------------------
+// Program main function
+//--------------------------------------------------
+int main(int argc, char** argv)
+{
+ int err = ERR_OK, e = 0;
+ SignedDoc* pSigDoc = 0;
+ DEncEncryptedData* pEncData = 0;
+ time_t t1, t2;
+#ifdef WIN32
+ char buf1[250];
+#endif
+
+ if(argc <= 1) {
+ printUsage();
+ exit(0);
+ }
+ // init DigiDoc library
+ initDigiDocLib();
+#ifdef WIN32
+ // find out program home if invoked with a long command line
+ memset(buf1, 0, sizeof(buf1));
+ getFileNamePath(argv[0], buf1, sizeof(buf1));
+ if(strlen(buf1)) {
+ strncat(buf1, "digidoc.ini", sizeof(buf1));
+ err = initConfigStore(buf1);
+ } else
+ err = initConfigStore(NULL);
+#else
+ // read in config file
+ err = initConfigStore(NULL);
+#endif
+ // clear all errors that were encountered by not finding config files
+ err = checkProgArguments(argc, argv);
+ time(&t1);
+ // register program name and version
+ setGUIVersion(g_szProgNameVer);
+ ddocDebugTruncateLog();
+ // use command line argument if required
+ if(p_szConfigFile)
+ err = readConfigFile(p_szConfigFile, ITEM_TYPE_PRIVATE);
+ // read flags from config file
+ readConfigParams();
+
+ // display programm name and version
+ if(g_cgiMode) {
+ if(ConfigItem_lookup_bool("DIGIDOC_CGI_PRINT_HEADER", 1))
+ fprintf(stdout, "%s%s%s", getLibName(), g_szOutputSeparator, getLibVersion());
+ } else {
+ fprintf(stdout, "%s - %s", getLibName(), getLibVersion());
+ }
+
+ // execute the commands now
+ // check certificate status throught OCSP
+ if(!err)
+ err = runCheckCertCmds(argc, argv);
+ // read input file if necessary
+ if(p_szInFile && !err) {
+ if(p_parseMode != 3)
+ err = cmdReadDigiDoc(&pSigDoc, &pEncData, p_parseMode);
+ else
+ err = cmdReadDigiDocFromMem(&pSigDoc, &pEncData);
+ // if read error was warning then continue
+ if(pSigDoc && isWarning(pSigDoc, err))
+ err = ERR_OK;
+ if(err && pSigDoc)
+ printErrorsAndWarnings(pSigDoc);
+ }
+ // various tests
+ if(!err)
+ err = runTestCmds(argc, argv);
+ if(p_szInEncFile && !err) {
+ if(hasCmdLineArg(argc, argv, "-encrypt-sk"))
+ err = cmdEncryptSk(&pEncData, p_szInEncFile);
+ else
+ err = cmdEncrypt(&pEncData, p_szInEncFile);
+ }
+ // list encrypted files
+ if(!err)
+ err = runDEncListCmds(argc, argv);
+ // add data files
+ if(!err)
+ err = runAddCmds(argc, argv, &pSigDoc);
+ // add data files from mem
+ if(!err)
+ err = runAddMemCmds(argc, argv, &pSigDoc);
+ // add recipients
+ if(!err)
+ err = runRecipientCmds(argc, argv, &pEncData);
+ // encrypt whole files
+ if(!err)
+ err = runEncryptFileCmds(argc, argv, pEncData);
+ // decrypt whole files
+ if(!err)
+ err = runDecryptFileCmds(argc, argv);
+ // run signature commands
+ if(!err)
+ err = runSignCmds(argc, argv, &pSigDoc);
+ // calculate signature hash commands
+ if(!err)
+ err = runCalcSignCmds(argc, argv, pSigDoc);
+ if(!err)
+ err = runMidSignCmds(argc, argv, pSigDoc);
+ if(!err)
+ err = runMidTestCmds(argc, argv, pSigDoc);
+ // verify signatures
+ if(!err) {
+ e = runVerifyCmds(argc, argv, pSigDoc, pEncData);
+ if(!err && e) err = e;
+ }
+ // extract datafiles
+ if(!err)
+ err = runExtractCmds(argc, argv, &pSigDoc);
+ if(!err)
+ err = runExtractMemCmds(argc, argv, &pSigDoc);
+ // decrypt files
+ if(!err)
+ err = runDecryptCmds(argc, argv, &pEncData);
+ // add signature value from a file
+ if(!err)
+ err = runAddSignValueCmds(argc, argv, pSigDoc);
+ // delete signatures
+ if(!err)
+ err = runDelSignCmds(argc, argv, pSigDoc);
+ // notarize signatures
+ if(!err)
+ err = runGetConfirmationCmds(argc, argv, pSigDoc);
+ if(!err)
+ err = runEncryptTestSetCmds(argc, argv);
+ // write output file
+ if(p_szOutFile && !err)
+ if(p_parseMode != 3)
+ err = cmdWrite(pSigDoc, pEncData);
+ else
+ err = cmdWriteMem(pSigDoc, pEncData);
+ time(&t2);
+
+ printErrorsAndWarnings(pSigDoc);
+ if(pSigDoc && !isError(pSigDoc, err)) { // find correct error from list
+ e = hasErrors(pSigDoc);
+ if((!err || !isError(pSigDoc,err)) && e) err = e;
+ }
+ // display programm error code and elapsed time
+ if(g_cgiMode) {
+ if(ConfigItem_lookup_bool("DIGIDOC_CGI_PRINT_TRAILER", 1))
+ fprintf(stdout, "\n%s%s%d%s%ld", getLibName(), g_szOutputSeparator, (isError(pSigDoc,err) ? err : 0), g_szOutputSeparator, (long)(t2-t1));
+ } else {
+ fprintf(stdout, "\n%s - time: %ld sec result: %s", getLibName(), (long)(t2-t1), (isError(pSigDoc,err) ? "failure" : "success"));
+ }
+ fprintf(stdout, "\n");
+ // cleanup
+ if(pSigDoc)
+ SignedDoc_free(pSigDoc);
+ if(pEncData)
+ dencEncryptedData_free(pEncData);
+ if(g_szOutputSeparator)
+ free(g_szOutputSeparator);
+ // cleanup
+#ifndef WIN32 // TODO: somehow this free gives invalid heap error on win32
+ cleanupConfigStore(NULL);
+#endif
+ finalizeDigiDocLib();
+
+ return err;
+}
diff --git a/libdigidoc/cdigidoc.rc b/libdigidoc/cdigidoc.rc
new file mode 100644
index 0000000..3267c28
--- /dev/null
+++ b/libdigidoc/cdigidoc.rc
@@ -0,0 +1,43 @@
+#ifndef Q_CC_BOR
+# if defined(UNDER_CE) && UNDER_CE >= 400
+# include <winbase.h>
+# else
+# include <winver.h>
+# endif
+#endif
+
+#include <config.h>
+
+VS_VERSION_INFO VERSIONINFO
+ FILEVERSION VERSION_COMMA
+ PRODUCTVERSION VERSION_COMMA
+ FILEFLAGSMASK VS_FFI_FILEFLAGSMASK
+#ifdef _DEBUG
+ FILEFLAGS VS_FF_DEBUG
+#else
+ FILEFLAGS 0x0L
+#endif
+ FILEOS VOS_NT_WINDOWS32
+ FILETYPE VFT_APP
+ FILESUBTYPE VFT_UNKNOWN
+BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+ BLOCK "040904E4"
+ BEGIN
+ VALUE "CompanyName", "Estonian ID Card\0"
+ VALUE "FileDescription", "cdigidoc\0"
+ VALUE "FileVersion", VERSION "\0"
+ VALUE "InternalName", "cdigidoc\0"
+ VALUE "LegalCopyright", "Copyright (C) 2009-2012 Estonian ID Card"
+ VALUE "OriginalFilename", "cdigidoc.exe\0"
+ VALUE "ProductName", "cdigidoc\0"
+ VALUE "ProductVersion", VERSION "\0"
+ END
+ END
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation", 0x425, 1200
+ END
+END
+/* End of Version info */
diff --git a/libdigidoc/libdigidoc.pc.cmake b/libdigidoc/libdigidoc.pc.cmake
new file mode 100644
index 0000000..70d24fb
--- /dev/null
+++ b/libdigidoc/libdigidoc.pc.cmake
@@ -0,0 +1,10 @@
+prefix=@CMAKE_INSTALL_PREFIX@
+exec_prefix=@CMAKE_INSTALL_FULL_BINDIR@
+libdir=@CMAKE_INSTALL_FULL_LIBDIR@
+includedir=@CMAKE_INSTALL_FULL_INCLUDEDIR@
+
+Name: libdigidoc
+Description: Libdigidoc library for handling digitally signed documents
+Version: @VERSION@
+Libs: -L${libdir} -ldigidoc
+Cflags: -I${includedir}
diff --git a/libdigidoc/libdigidoc.rc b/libdigidoc/libdigidoc.rc
new file mode 100644
index 0000000..7338b52
--- /dev/null
+++ b/libdigidoc/libdigidoc.rc
@@ -0,0 +1,43 @@
+#ifndef Q_CC_BOR
+# if defined(UNDER_CE) && UNDER_CE >= 400
+# include <winbase.h>
+# else
+# include <winver.h>
+# endif
+#endif
+
+#include <config.h>
+
+VS_VERSION_INFO VERSIONINFO
+ FILEVERSION VERSION_COMMA
+ PRODUCTVERSION VERSION_COMMA
+ FILEFLAGSMASK VS_FFI_FILEFLAGSMASK
+#ifdef _DEBUG
+ FILEFLAGS VS_FF_DEBUG
+#else
+ FILEFLAGS 0x0L
+#endif
+ FILEOS VOS_NT_WINDOWS32
+ FILETYPE VFT_DLL
+ FILESUBTYPE VFT_UNKNOWN
+BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+ BLOCK "040904E4"
+ BEGIN
+ VALUE "CompanyName", "Estonian ID Card\0"
+ VALUE "FileDescription", "libdigidoc\0"
+ VALUE "FileVersion", VERSION "\0"
+ VALUE "InternalName", "libdigidoc\0"
+ VALUE "LegalCopyright", "Copyright (C) 2009-2012 Estonian ID Card"
+ VALUE "OriginalFilename", "libdigidoc.dll\0"
+ VALUE "ProductName", "libdigidoc\0"
+ VALUE "ProductVersion", VERSION "\0"
+ END
+ END
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation", 0x425, 1200
+ END
+END
+/* End of Version info */
diff --git a/libdigidoc/pkcs11/cryptoki.h b/libdigidoc/pkcs11/cryptoki.h
new file mode 100644
index 0000000..1c2b975
--- /dev/null
+++ b/libdigidoc/pkcs11/cryptoki.h
@@ -0,0 +1,96 @@
+/* cryptoki.h include file for PKCS #11. 2001 June 25 */
+
+
+
+/* This is a sample file containing the top level include directives
+
+ * for building Win32 Cryptoki libraries and applications.
+
+ */
+
+
+
+#ifndef ___CRYPTOKI_H_INC___
+
+#define ___CRYPTOKI_H_INC___
+
+
+
+#pragma pack(push, cryptoki, 1)
+
+
+
+/* Specifies that the function is a DLL entry point. */
+
+#define CK_IMPORT_SPEC __declspec(dllimport)
+
+
+
+/* Define CRYPTOKI_EXPORTS during the build of cryptoki libraries. Do
+
+ * not define it in applications.
+
+ */
+
+#ifdef CRYPTOKI_EXPORTS
+
+/* Specified that the function is an exported DLL entry point. */
+
+#define CK_EXPORT_SPEC __declspec(dllexport)
+
+#else
+
+#define CK_EXPORT_SPEC CK_IMPORT_SPEC
+
+#endif
+
+
+
+/* Ensures the calling convention for Win32 builds */
+
+#define CK_CALL_SPEC __cdecl
+
+
+
+#define CK_PTR *
+
+
+
+#define CK_DEFINE_FUNCTION(returnType, name) \
+ returnType CK_EXPORT_SPEC CK_CALL_SPEC name
+
+
+
+#define CK_DECLARE_FUNCTION(returnType, name) \
+ returnType CK_EXPORT_SPEC CK_CALL_SPEC name
+
+
+
+#define CK_DECLARE_FUNCTION_POINTER(returnType, name) \
+ returnType CK_IMPORT_SPEC (CK_CALL_SPEC CK_PTR name)
+
+
+
+#define CK_CALLBACK_FUNCTION(returnType, name) \
+ returnType (CK_CALL_SPEC CK_PTR name)
+
+
+
+#ifndef NULL_PTR
+
+#define NULL_PTR 0
+
+#endif
+
+
+
+#include "pkcs11.h"
+
+
+
+#pragma pack(pop, cryptoki)
+
+
+
+#endif /* ___CRYPTOKI_H_INC___ */
+
diff --git a/libdigidoc/pkcs11/pkcs11.h b/libdigidoc/pkcs11/pkcs11.h
new file mode 100644
index 0000000..e4cfa41
--- /dev/null
+++ b/libdigidoc/pkcs11/pkcs11.h
@@ -0,0 +1,288 @@
+/* pkcs11.h include file for PKCS #11. 2001 June 25 */
+
+#ifndef _PKCS11_H_
+#define _PKCS11_H_ 1
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Before including this file (pkcs11.h) (or pkcs11t.h by
+ * itself), 6 platform-specific macros must be defined. These
+ * macros are described below, and typical definitions for them
+ * are also given. Be advised that these definitions can depend
+ * on both the platform and the compiler used (and possibly also
+ * on whether a Cryptoki library is linked statically or
+ * dynamically).
+ *
+ * In addition to defining these 6 macros, the packing convention
+ * for Cryptoki structures should be set. The Cryptoki
+ * convention on packing is that structures should be 1-byte
+ * aligned.
+ *
+ * If you're using Microsoft Developer Studio 5.0 to produce
+ * Win32 stuff, this might be done by using the following
+ * preprocessor directive before including pkcs11.h or pkcs11t.h:
+ *
+ * #pragma pack(push, cryptoki, 1)
+ *
+ * and using the following preprocessor directive after including
+ * pkcs11.h or pkcs11t.h:
+ *
+ * #pragma pack(pop, cryptoki)
+ *
+ * If you're using an earlier version of Microsoft Developer
+ * Studio to produce Win16 stuff, this might be done by using
+ * the following preprocessor directive before including
+ * pkcs11.h or pkcs11t.h:
+ *
+ * #pragma pack(1)
+ *
+ * In a UNIX environment, you're on your own for this. You might
+ * not need to do (or be able to do!) anything.
+ *
+ *
+ * Now for the macros:
+ *
+ *
+ * 1. CK_PTR: The indirection string for making a pointer to an
+ * object. It can be used like this:
+ *
+ * typedef CK_BYTE CK_PTR CK_BYTE_PTR;
+ *
+ * If you're using Microsoft Developer Studio 5.0 to produce
+ * Win32 stuff, it might be defined by:
+ *
+ * #define CK_PTR *
+ *
+ * If you're using an earlier version of Microsoft Developer
+ * Studio to produce Win16 stuff, it might be defined by:
+ *
+ * #define CK_PTR far *
+ *
+ * In a typical UNIX environment, it might be defined by:
+ *
+ * #define CK_PTR *
+ *
+ *
+ * 2. CK_DEFINE_FUNCTION(returnType, name): A macro which makes
+ * an exportable Cryptoki library function definition out of a
+ * return type and a function name. It should be used in the
+ * following fashion to define the exposed Cryptoki functions in
+ * a Cryptoki library:
+ *
+ * CK_DEFINE_FUNCTION(CK_RV, C_Initialize)(
+ * CK_VOID_PTR pReserved
+ * )
+ * {
+ * ...
+ * }
+ *
+ * If you're using Microsoft Developer Studio 5.0 to define a
+ * function in a Win32 Cryptoki .dll, it might be defined by:
+ *
+ * #define CK_DEFINE_FUNCTION(returnType, name) \
+ * returnType __declspec(dllexport) name
+ *
+ * If you're using an earlier version of Microsoft Developer
+ * Studio to define a function in a Win16 Cryptoki .dll, it
+ * might be defined by:
+ *
+ * #define CK_DEFINE_FUNCTION(returnType, name) \
+ * returnType __export _far _pascal name
+ *
+ * In a UNIX environment, it might be defined by:
+ *
+ * #define CK_DEFINE_FUNCTION(returnType, name) \
+ * returnType name
+ *
+ *
+ * 3. CK_DECLARE_FUNCTION(returnType, name): A macro which makes
+ * an importable Cryptoki library function declaration out of a
+ * return type and a function name. It should be used in the
+ * following fashion:
+ *
+ * extern CK_DECLARE_FUNCTION(CK_RV, C_Initialize)(
+ * CK_VOID_PTR pReserved
+ * );
+ *
+ * If you're using Microsoft Developer Studio 5.0 to declare a
+ * function in a Win32 Cryptoki .dll, it might be defined by:
+ *
+ * #define CK_DECLARE_FUNCTION(returnType, name) \
+ * returnType __declspec(dllimport) name
+ *
+ * If you're using an earlier version of Microsoft Developer
+ * Studio to declare a function in a Win16 Cryptoki .dll, it
+ * might be defined by:
+ *
+ * #define CK_DECLARE_FUNCTION(returnType, name) \
+ * returnType __export _far _pascal name
+ *
+ * In a UNIX environment, it might be defined by:
+ *
+ * #define CK_DECLARE_FUNCTION(returnType, name) \
+ * returnType name
+ *
+ *
+ * 4. CK_DECLARE_FUNCTION_POINTER(returnType, name): A macro
+ * which makes a Cryptoki API function pointer declaration or
+ * function pointer type declaration out of a return type and a
+ * function name. It should be used in the following fashion:
+ *
+ * // Define funcPtr to be a pointer to a Cryptoki API function
+ * // taking arguments args and returning CK_RV.
+ * CK_DECLARE_FUNCTION_POINTER(CK_RV, funcPtr)(args);
+ *
+ * or
+ *
+ * // Define funcPtrType to be the type of a pointer to a
+ * // Cryptoki API function taking arguments args and returning
+ * // CK_RV, and then define funcPtr to be a variable of type
+ * // funcPtrType.
+ * typedef CK_DECLARE_FUNCTION_POINTER(CK_RV, funcPtrType)(args);
+ * funcPtrType funcPtr;
+ *
+ * If you're using Microsoft Developer Studio 5.0 to access
+ * functions in a Win32 Cryptoki .dll, in might be defined by:
+ *
+ * #define CK_DECLARE_FUNCTION_POINTER(returnType, name) \
+ * returnType __declspec(dllimport) (* name)
+ *
+ * If you're using an earlier version of Microsoft Developer
+ * Studio to access functions in a Win16 Cryptoki .dll, it might
+ * be defined by:
+ *
+ * #define CK_DECLARE_FUNCTION_POINTER(returnType, name) \
+ * returnType __export _far _pascal (* name)
+ *
+ * In a UNIX environment, it might be defined by:
+ *
+ * #define CK_DECLARE_FUNCTION_POINTER(returnType, name) \
+ * returnType (* name)
+ *
+ *
+ * 5. CK_CALLBACK_FUNCTION(returnType, name): A macro which makes
+ * a function pointer type for an application callback out of
+ * a return type for the callback and a name for the callback.
+ * It should be used in the following fashion:
+ *
+ * CK_CALLBACK_FUNCTION(CK_RV, myCallback)(args);
+ *
+ * to declare a function pointer, myCallback, to a callback
+ * which takes arguments args and returns a CK_RV. It can also
+ * be used like this:
+ *
+ * typedef CK_CALLBACK_FUNCTION(CK_RV, myCallbackType)(args);
+ * myCallbackType myCallback;
+ *
+ * If you're using Microsoft Developer Studio 5.0 to do Win32
+ * Cryptoki development, it might be defined by:
+ *
+ * #define CK_CALLBACK_FUNCTION(returnType, name) \
+ * returnType (* name)
+ *
+ * If you're using an earlier version of Microsoft Developer
+ * Studio to do Win16 development, it might be defined by:
+ *
+ * #define CK_CALLBACK_FUNCTION(returnType, name) \
+ * returnType _far _pascal (* name)
+ *
+ * In a UNIX environment, it might be defined by:
+ *
+ * #define CK_CALLBACK_FUNCTION(returnType, name) \
+ * returnType (* name)
+ *
+ *
+ * 6. NULL_PTR: This macro is the value of a NULL pointer.
+ *
+ * In any ANSI/ISO C environment (and in many others as well),
+ * this should best be defined by
+ *
+ * #ifndef NULL_PTR
+ * #define NULL_PTR 0
+ * #endif
+ */
+
+#ifndef WIN32
+ #include "unix.h"
+#else
+ #include "cryptoki.h"
+#endif
+
+/* All the various Cryptoki types and #define'd values are in the
+ * file pkcs11t.h. */
+#include "pkcs11t.h"
+
+#define __PASTE(x,y) x##y
+
+
+/* ==============================================================
+ * Define the "extern" form of all the entry points.
+ * ==============================================================
+ */
+
+#define CK_NEED_ARG_LIST 1
+#define CK_PKCS11_FUNCTION_INFO(name) \
+ extern CK_DECLARE_FUNCTION(CK_RV, name)
+
+/* pkcs11f.h has all the information about the Cryptoki
+ * function prototypes. */
+#include "pkcs11f.h"
+
+#undef CK_NEED_ARG_LIST
+#undef CK_PKCS11_FUNCTION_INFO
+
+
+/* ==============================================================
+ * Define the typedef form of all the entry points. That is, for
+ * each Cryptoki function C_XXX, define a type CK_C_XXX which is
+ * a pointer to that kind of function.
+ * ==============================================================
+ */
+
+#define CK_NEED_ARG_LIST 1
+#define CK_PKCS11_FUNCTION_INFO(name) \
+ typedef CK_DECLARE_FUNCTION_POINTER(CK_RV, __PASTE(CK_,name))
+
+/* pkcs11f.h has all the information about the Cryptoki
+ * function prototypes. */
+#include "pkcs11f.h"
+
+#undef CK_NEED_ARG_LIST
+#undef CK_PKCS11_FUNCTION_INFO
+
+
+/* ==============================================================
+ * Define structed vector of entry points. A CK_FUNCTION_LIST
+ * contains a CK_VERSION indicating a library's Cryptoki version
+ * and then a whole slew of function pointers to the routines in
+ * the library. This type was declared, but not defined, in
+ * pkcs11t.h.
+ * ==============================================================
+ */
+
+#define CK_PKCS11_FUNCTION_INFO(name) \
+ __PASTE(CK_,name) name;
+
+struct CK_FUNCTION_LIST {
+
+ CK_VERSION version; /* Cryptoki version */
+
+/* Pile all the function pointers into the CK_FUNCTION_LIST. */
+/* pkcs11f.h has all the information about the Cryptoki
+ * function prototypes. */
+#include "pkcs11f.h"
+
+};
+
+#undef CK_PKCS11_FUNCTION_INFO
+
+
+#undef __PASTE
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libdigidoc/pkcs11/pkcs11f.h b/libdigidoc/pkcs11/pkcs11f.h
new file mode 100644
index 0000000..8c3f826
--- /dev/null
+++ b/libdigidoc/pkcs11/pkcs11f.h
@@ -0,0 +1,898 @@
+/* pkcs11f.h include file for PKCS #11. 2001 June 25 */
+
+/* This function contains pretty much everything about all the */
+/* Cryptoki function prototypes. Because this information is */
+/* used for more than just declaring function prototypes, the */
+/* order of the functions appearing herein is important, and */
+/* should not be altered. */
+
+
+
+/* General-purpose */
+
+/* C_Initialize initializes the Cryptoki library. */
+CK_PKCS11_FUNCTION_INFO(C_Initialize)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_VOID_PTR pInitArgs /* if this is not NULL_PTR, it gets
+ * cast to CK_C_INITIALIZE_ARGS_PTR
+ * and dereferenced */
+);
+#endif
+
+
+/* C_Finalize indicates that an application is done with the
+ * Cryptoki library. */
+CK_PKCS11_FUNCTION_INFO(C_Finalize)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_VOID_PTR pReserved /* reserved. Should be NULL_PTR */
+);
+#endif
+
+
+/* C_GetInfo returns general information about Cryptoki. */
+CK_PKCS11_FUNCTION_INFO(C_GetInfo)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_INFO_PTR pInfo /* location that receives information */
+);
+#endif
+
+
+/* C_GetFunctionList returns the function list. */
+CK_PKCS11_FUNCTION_INFO(C_GetFunctionList)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_FUNCTION_LIST_PTR_PTR ppFunctionList /* receives pointer to
+ * function list */
+);
+#endif
+
+
+
+/* Slot and token management */
+
+/* C_GetSlotList obtains a list of slots in the system. */
+CK_PKCS11_FUNCTION_INFO(C_GetSlotList)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_BBOOL tokenPresent, /* only slots with tokens? */
+ CK_SLOT_ID_PTR pSlotList, /* receives array of slot IDs */
+ CK_ULONG_PTR pulCount /* receives number of slots */
+);
+#endif
+
+
+/* C_GetSlotInfo obtains information about a particular slot in
+ * the system. */
+CK_PKCS11_FUNCTION_INFO(C_GetSlotInfo)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SLOT_ID slotID, /* the ID of the slot */
+ CK_SLOT_INFO_PTR pInfo /* receives the slot information */
+);
+#endif
+
+
+/* C_GetTokenInfo obtains information about a particular token
+ * in the system. */
+CK_PKCS11_FUNCTION_INFO(C_GetTokenInfo)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SLOT_ID slotID, /* ID of the token's slot */
+ CK_TOKEN_INFO_PTR pInfo /* receives the token information */
+);
+#endif
+
+
+/* C_GetMechanismList obtains a list of mechanism types
+ * supported by a token. */
+CK_PKCS11_FUNCTION_INFO(C_GetMechanismList)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SLOT_ID slotID, /* ID of token's slot */
+ CK_MECHANISM_TYPE_PTR pMechanismList, /* gets mech. array */
+ CK_ULONG_PTR pulCount /* gets # of mechs. */
+);
+#endif
+
+
+/* C_GetMechanismInfo obtains information about a particular
+ * mechanism possibly supported by a token. */
+CK_PKCS11_FUNCTION_INFO(C_GetMechanismInfo)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SLOT_ID slotID, /* ID of the token's slot */
+ CK_MECHANISM_TYPE type, /* type of mechanism */
+ CK_MECHANISM_INFO_PTR pInfo /* receives mechanism info */
+);
+#endif
+
+
+/* C_InitToken initializes a token. */
+CK_PKCS11_FUNCTION_INFO(C_InitToken)
+#ifdef CK_NEED_ARG_LIST
+/* pLabel changed from CK_CHAR_PTR to CK_UTF8CHAR_PTR for v2.10 */
+(
+ CK_SLOT_ID slotID, /* ID of the token's slot */
+ CK_UTF8CHAR_PTR pPin, /* the SO's initial PIN */
+ CK_ULONG ulPinLen, /* length in bytes of the PIN */
+ CK_UTF8CHAR_PTR pLabel /* 32-byte token label (blank padded) */
+);
+#endif
+
+
+/* C_InitPIN initializes the normal user's PIN. */
+CK_PKCS11_FUNCTION_INFO(C_InitPIN)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_UTF8CHAR_PTR pPin, /* the normal user's PIN */
+ CK_ULONG ulPinLen /* length in bytes of the PIN */
+);
+#endif
+
+
+/* C_SetPIN modifies the PIN of the user who is logged in. */
+CK_PKCS11_FUNCTION_INFO(C_SetPIN)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_UTF8CHAR_PTR pOldPin, /* the old PIN */
+ CK_ULONG ulOldLen, /* length of the old PIN */
+ CK_UTF8CHAR_PTR pNewPin, /* the new PIN */
+ CK_ULONG ulNewLen /* length of the new PIN */
+);
+#endif
+
+
+
+/* Session management */
+
+/* C_OpenSession opens a session between an application and a
+ * token. */
+CK_PKCS11_FUNCTION_INFO(C_OpenSession)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SLOT_ID slotID, /* the slot's ID */
+ CK_FLAGS flags, /* from CK_SESSION_INFO */
+ CK_VOID_PTR pApplication, /* passed to callback */
+ CK_NOTIFY Notify, /* callback function */
+ CK_SESSION_HANDLE_PTR phSession /* gets session handle */
+);
+#endif
+
+
+/* C_CloseSession closes a session between an application and a
+ * token. */
+CK_PKCS11_FUNCTION_INFO(C_CloseSession)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession /* the session's handle */
+);
+#endif
+
+
+/* C_CloseAllSessions closes all sessions with a token. */
+CK_PKCS11_FUNCTION_INFO(C_CloseAllSessions)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SLOT_ID slotID /* the token's slot */
+);
+#endif
+
+
+/* C_GetSessionInfo obtains information about the session. */
+CK_PKCS11_FUNCTION_INFO(C_GetSessionInfo)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_SESSION_INFO_PTR pInfo /* receives session info */
+);
+#endif
+
+
+/* C_GetOperationState obtains the state of the cryptographic operation
+ * in a session. */
+CK_PKCS11_FUNCTION_INFO(C_GetOperationState)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* session's handle */
+ CK_BYTE_PTR pOperationState, /* gets state */
+ CK_ULONG_PTR pulOperationStateLen /* gets state length */
+);
+#endif
+
+
+/* C_SetOperationState restores the state of the cryptographic
+ * operation in a session. */
+CK_PKCS11_FUNCTION_INFO(C_SetOperationState)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* session's handle */
+ CK_BYTE_PTR pOperationState, /* holds state */
+ CK_ULONG ulOperationStateLen, /* holds state length */
+ CK_OBJECT_HANDLE hEncryptionKey, /* en/decryption key */
+ CK_OBJECT_HANDLE hAuthenticationKey /* sign/verify key */
+);
+#endif
+
+
+/* C_Login logs a user into a token. */
+CK_PKCS11_FUNCTION_INFO(C_Login)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_USER_TYPE userType, /* the user type */
+ CK_UTF8CHAR_PTR pPin, /* the user's PIN */
+ CK_ULONG ulPinLen /* the length of the PIN */
+);
+#endif
+
+
+/* C_Logout logs a user out from a token. */
+CK_PKCS11_FUNCTION_INFO(C_Logout)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession /* the session's handle */
+);
+#endif
+
+
+
+/* Object management */
+
+/* C_CreateObject creates a new object. */
+CK_PKCS11_FUNCTION_INFO(C_CreateObject)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_ATTRIBUTE_PTR pTemplate, /* the object's template */
+ CK_ULONG ulCount, /* attributes in template */
+ CK_OBJECT_HANDLE_PTR phObject /* gets new object's handle. */
+);
+#endif
+
+
+/* C_CopyObject copies an object, creating a new object for the
+ * copy. */
+CK_PKCS11_FUNCTION_INFO(C_CopyObject)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_OBJECT_HANDLE hObject, /* the object's handle */
+ CK_ATTRIBUTE_PTR pTemplate, /* template for new object */
+ CK_ULONG ulCount, /* attributes in template */
+ CK_OBJECT_HANDLE_PTR phNewObject /* receives handle of copy */
+);
+#endif
+
+
+/* C_DestroyObject destroys an object. */
+CK_PKCS11_FUNCTION_INFO(C_DestroyObject)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_OBJECT_HANDLE hObject /* the object's handle */
+);
+#endif
+
+
+/* C_GetObjectSize gets the size of an object in bytes. */
+CK_PKCS11_FUNCTION_INFO(C_GetObjectSize)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_OBJECT_HANDLE hObject, /* the object's handle */
+ CK_ULONG_PTR pulSize /* receives size of object */
+);
+#endif
+
+
+/* C_GetAttributeValue obtains the value of one or more object
+ * attributes. */
+CK_PKCS11_FUNCTION_INFO(C_GetAttributeValue)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_OBJECT_HANDLE hObject, /* the object's handle */
+ CK_ATTRIBUTE_PTR pTemplate, /* specifies attrs; gets vals */
+ CK_ULONG ulCount /* attributes in template */
+);
+#endif
+
+
+/* C_SetAttributeValue modifies the value of one or more object
+ * attributes */
+CK_PKCS11_FUNCTION_INFO(C_SetAttributeValue)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_OBJECT_HANDLE hObject, /* the object's handle */
+ CK_ATTRIBUTE_PTR pTemplate, /* specifies attrs and values */
+ CK_ULONG ulCount /* attributes in template */
+);
+#endif
+
+
+/* C_FindObjectsInit initializes a search for token and session
+ * objects that match a template. */
+CK_PKCS11_FUNCTION_INFO(C_FindObjectsInit)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_ATTRIBUTE_PTR pTemplate, /* attribute values to match */
+ CK_ULONG ulCount /* attrs in search template */
+);
+#endif
+
+
+/* C_FindObjects continues a search for token and session
+ * objects that match a template, obtaining additional object
+ * handles. */
+CK_PKCS11_FUNCTION_INFO(C_FindObjects)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* session's handle */
+ CK_OBJECT_HANDLE_PTR phObject, /* gets obj. handles */
+ CK_ULONG ulMaxObjectCount, /* max handles to get */
+ CK_ULONG_PTR pulObjectCount /* actual # returned */
+);
+#endif
+
+
+/* C_FindObjectsFinal finishes a search for token and session
+ * objects. */
+CK_PKCS11_FUNCTION_INFO(C_FindObjectsFinal)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession /* the session's handle */
+);
+#endif
+
+
+
+/* Encryption and decryption */
+
+/* C_EncryptInit initializes an encryption operation. */
+CK_PKCS11_FUNCTION_INFO(C_EncryptInit)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_MECHANISM_PTR pMechanism, /* the encryption mechanism */
+ CK_OBJECT_HANDLE hKey /* handle of encryption key */
+);
+#endif
+
+
+/* C_Encrypt encrypts single-part data. */
+CK_PKCS11_FUNCTION_INFO(C_Encrypt)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* session's handle */
+ CK_BYTE_PTR pData, /* the plaintext data */
+ CK_ULONG ulDataLen, /* bytes of plaintext */
+ CK_BYTE_PTR pEncryptedData, /* gets ciphertext */
+ CK_ULONG_PTR pulEncryptedDataLen /* gets c-text size */
+);
+#endif
+
+
+/* C_EncryptUpdate continues a multiple-part encryption
+ * operation. */
+CK_PKCS11_FUNCTION_INFO(C_EncryptUpdate)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* session's handle */
+ CK_BYTE_PTR pPart, /* the plaintext data */
+ CK_ULONG ulPartLen, /* plaintext data len */
+ CK_BYTE_PTR pEncryptedPart, /* gets ciphertext */
+ CK_ULONG_PTR pulEncryptedPartLen /* gets c-text size */
+);
+#endif
+
+
+/* C_EncryptFinal finishes a multiple-part encryption
+ * operation. */
+CK_PKCS11_FUNCTION_INFO(C_EncryptFinal)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* session handle */
+ CK_BYTE_PTR pLastEncryptedPart, /* last c-text */
+ CK_ULONG_PTR pulLastEncryptedPartLen /* gets last size */
+);
+#endif
+
+
+/* C_DecryptInit initializes a decryption operation. */
+CK_PKCS11_FUNCTION_INFO(C_DecryptInit)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_MECHANISM_PTR pMechanism, /* the decryption mechanism */
+ CK_OBJECT_HANDLE hKey /* handle of decryption key */
+);
+#endif
+
+
+/* C_Decrypt decrypts encrypted data in a single part. */
+CK_PKCS11_FUNCTION_INFO(C_Decrypt)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* session's handle */
+ CK_BYTE_PTR pEncryptedData, /* ciphertext */
+ CK_ULONG ulEncryptedDataLen, /* ciphertext length */
+ CK_BYTE_PTR pData, /* gets plaintext */
+ CK_ULONG_PTR pulDataLen /* gets p-text size */
+);
+#endif
+
+
+/* C_DecryptUpdate continues a multiple-part decryption
+ * operation. */
+CK_PKCS11_FUNCTION_INFO(C_DecryptUpdate)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* session's handle */
+ CK_BYTE_PTR pEncryptedPart, /* encrypted data */
+ CK_ULONG ulEncryptedPartLen, /* input length */
+ CK_BYTE_PTR pPart, /* gets plaintext */
+ CK_ULONG_PTR pulPartLen /* p-text size */
+);
+#endif
+
+
+/* C_DecryptFinal finishes a multiple-part decryption
+ * operation. */
+CK_PKCS11_FUNCTION_INFO(C_DecryptFinal)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_BYTE_PTR pLastPart, /* gets plaintext */
+ CK_ULONG_PTR pulLastPartLen /* p-text size */
+);
+#endif
+
+
+
+/* Message digesting */
+
+/* C_DigestInit initializes a message-digesting operation. */
+CK_PKCS11_FUNCTION_INFO(C_DigestInit)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_MECHANISM_PTR pMechanism /* the digesting mechanism */
+);
+#endif
+
+
+/* C_Digest digests data in a single part. */
+CK_PKCS11_FUNCTION_INFO(C_Digest)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_BYTE_PTR pData, /* data to be digested */
+ CK_ULONG ulDataLen, /* bytes of data to digest */
+ CK_BYTE_PTR pDigest, /* gets the message digest */
+ CK_ULONG_PTR pulDigestLen /* gets digest length */
+);
+#endif
+
+
+/* C_DigestUpdate continues a multiple-part message-digesting
+ * operation. */
+CK_PKCS11_FUNCTION_INFO(C_DigestUpdate)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_BYTE_PTR pPart, /* data to be digested */
+ CK_ULONG ulPartLen /* bytes of data to be digested */
+);
+#endif
+
+
+/* C_DigestKey continues a multi-part message-digesting
+ * operation, by digesting the value of a secret key as part of
+ * the data already digested. */
+CK_PKCS11_FUNCTION_INFO(C_DigestKey)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_OBJECT_HANDLE hKey /* secret key to digest */
+);
+#endif
+
+
+/* C_DigestFinal finishes a multiple-part message-digesting
+ * operation. */
+CK_PKCS11_FUNCTION_INFO(C_DigestFinal)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_BYTE_PTR pDigest, /* gets the message digest */
+ CK_ULONG_PTR pulDigestLen /* gets byte count of digest */
+);
+#endif
+
+
+
+/* Signing and MACing */
+
+/* C_SignInit initializes a signature (private key encryption)
+ * operation, where the signature is (will be) an appendix to
+ * the data, and plaintext cannot be recovered from the
+ *signature. */
+CK_PKCS11_FUNCTION_INFO(C_SignInit)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_MECHANISM_PTR pMechanism, /* the signature mechanism */
+ CK_OBJECT_HANDLE hKey /* handle of signature key */
+);
+#endif
+
+
+/* C_Sign signs (encrypts with private key) data in a single
+ * part, where the signature is (will be) an appendix to the
+ * data, and plaintext cannot be recovered from the signature. */
+CK_PKCS11_FUNCTION_INFO(C_Sign)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_BYTE_PTR pData, /* the data to sign */
+ CK_ULONG ulDataLen, /* count of bytes to sign */
+ CK_BYTE_PTR pSignature, /* gets the signature */
+ CK_ULONG_PTR pulSignatureLen /* gets signature length */
+);
+#endif
+
+
+/* C_SignUpdate continues a multiple-part signature operation,
+ * where the signature is (will be) an appendix to the data,
+ * and plaintext cannot be recovered from the signature. */
+CK_PKCS11_FUNCTION_INFO(C_SignUpdate)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_BYTE_PTR pPart, /* the data to sign */
+ CK_ULONG ulPartLen /* count of bytes to sign */
+);
+#endif
+
+
+/* C_SignFinal finishes a multiple-part signature operation,
+ * returning the signature. */
+CK_PKCS11_FUNCTION_INFO(C_SignFinal)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_BYTE_PTR pSignature, /* gets the signature */
+ CK_ULONG_PTR pulSignatureLen /* gets signature length */
+);
+#endif
+
+
+/* C_SignRecoverInit initializes a signature operation, where
+ * the data can be recovered from the signature. */
+CK_PKCS11_FUNCTION_INFO(C_SignRecoverInit)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_MECHANISM_PTR pMechanism, /* the signature mechanism */
+ CK_OBJECT_HANDLE hKey /* handle of the signature key */
+);
+#endif
+
+
+/* C_SignRecover signs data in a single operation, where the
+ * data can be recovered from the signature. */
+CK_PKCS11_FUNCTION_INFO(C_SignRecover)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_BYTE_PTR pData, /* the data to sign */
+ CK_ULONG ulDataLen, /* count of bytes to sign */
+ CK_BYTE_PTR pSignature, /* gets the signature */
+ CK_ULONG_PTR pulSignatureLen /* gets signature length */
+);
+#endif
+
+
+
+/* Verifying signatures and MACs */
+
+/* C_VerifyInit initializes a verification operation, where the
+ * signature is an appendix to the data, and plaintext cannot
+ * cannot be recovered from the signature (e.g. DSA). */
+CK_PKCS11_FUNCTION_INFO(C_VerifyInit)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_MECHANISM_PTR pMechanism, /* the verification mechanism */
+ CK_OBJECT_HANDLE hKey /* verification key */
+);
+#endif
+
+
+/* C_Verify verifies a signature in a single-part operation,
+ * where the signature is an appendix to the data, and plaintext
+ * cannot be recovered from the signature. */
+CK_PKCS11_FUNCTION_INFO(C_Verify)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_BYTE_PTR pData, /* signed data */
+ CK_ULONG ulDataLen, /* length of signed data */
+ CK_BYTE_PTR pSignature, /* signature */
+ CK_ULONG ulSignatureLen /* signature length*/
+);
+#endif
+
+
+/* C_VerifyUpdate continues a multiple-part verification
+ * operation, where the signature is an appendix to the data,
+ * and plaintext cannot be recovered from the signature. */
+CK_PKCS11_FUNCTION_INFO(C_VerifyUpdate)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_BYTE_PTR pPart, /* signed data */
+ CK_ULONG ulPartLen /* length of signed data */
+);
+#endif
+
+
+/* C_VerifyFinal finishes a multiple-part verification
+ * operation, checking the signature. */
+CK_PKCS11_FUNCTION_INFO(C_VerifyFinal)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_BYTE_PTR pSignature, /* signature to verify */
+ CK_ULONG ulSignatureLen /* signature length */
+);
+#endif
+
+
+/* C_VerifyRecoverInit initializes a signature verification
+ * operation, where the data is recovered from the signature. */
+CK_PKCS11_FUNCTION_INFO(C_VerifyRecoverInit)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_MECHANISM_PTR pMechanism, /* the verification mechanism */
+ CK_OBJECT_HANDLE hKey /* verification key */
+);
+#endif
+
+
+/* C_VerifyRecover verifies a signature in a single-part
+ * operation, where the data is recovered from the signature. */
+CK_PKCS11_FUNCTION_INFO(C_VerifyRecover)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_BYTE_PTR pSignature, /* signature to verify */
+ CK_ULONG ulSignatureLen, /* signature length */
+ CK_BYTE_PTR pData, /* gets signed data */
+ CK_ULONG_PTR pulDataLen /* gets signed data len */
+);
+#endif
+
+
+
+/* Dual-function cryptographic operations */
+
+/* C_DigestEncryptUpdate continues a multiple-part digesting
+ * and encryption operation. */
+CK_PKCS11_FUNCTION_INFO(C_DigestEncryptUpdate)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* session's handle */
+ CK_BYTE_PTR pPart, /* the plaintext data */
+ CK_ULONG ulPartLen, /* plaintext length */
+ CK_BYTE_PTR pEncryptedPart, /* gets ciphertext */
+ CK_ULONG_PTR pulEncryptedPartLen /* gets c-text length */
+);
+#endif
+
+
+/* C_DecryptDigestUpdate continues a multiple-part decryption and
+ * digesting operation. */
+CK_PKCS11_FUNCTION_INFO(C_DecryptDigestUpdate)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* session's handle */
+ CK_BYTE_PTR pEncryptedPart, /* ciphertext */
+ CK_ULONG ulEncryptedPartLen, /* ciphertext length */
+ CK_BYTE_PTR pPart, /* gets plaintext */
+ CK_ULONG_PTR pulPartLen /* gets plaintext len */
+);
+#endif
+
+
+/* C_SignEncryptUpdate continues a multiple-part signing and
+ * encryption operation. */
+CK_PKCS11_FUNCTION_INFO(C_SignEncryptUpdate)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* session's handle */
+ CK_BYTE_PTR pPart, /* the plaintext data */
+ CK_ULONG ulPartLen, /* plaintext length */
+ CK_BYTE_PTR pEncryptedPart, /* gets ciphertext */
+ CK_ULONG_PTR pulEncryptedPartLen /* gets c-text length */
+);
+#endif
+
+
+/* C_DecryptVerifyUpdate continues a multiple-part decryption and
+ * verify operation. */
+CK_PKCS11_FUNCTION_INFO(C_DecryptVerifyUpdate)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* session's handle */
+ CK_BYTE_PTR pEncryptedPart, /* ciphertext */
+ CK_ULONG ulEncryptedPartLen, /* ciphertext length */
+ CK_BYTE_PTR pPart, /* gets plaintext */
+ CK_ULONG_PTR pulPartLen /* gets p-text length */
+);
+#endif
+
+
+
+/* Key management */
+
+/* C_GenerateKey generates a secret key, creating a new key
+ * object. */
+CK_PKCS11_FUNCTION_INFO(C_GenerateKey)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_MECHANISM_PTR pMechanism, /* key generation mech. */
+ CK_ATTRIBUTE_PTR pTemplate, /* template for new key */
+ CK_ULONG ulCount, /* # of attrs in template */
+ CK_OBJECT_HANDLE_PTR phKey /* gets handle of new key */
+);
+#endif
+
+
+/* C_GenerateKeyPair generates a public-key/private-key pair,
+ * creating new key objects. */
+CK_PKCS11_FUNCTION_INFO(C_GenerateKeyPair)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* session
+ * handle */
+ CK_MECHANISM_PTR pMechanism, /* key-gen
+ * mech. */
+ CK_ATTRIBUTE_PTR pPublicKeyTemplate, /* template
+ * for pub.
+ * key */
+ CK_ULONG ulPublicKeyAttributeCount, /* # pub.
+ * attrs. */
+ CK_ATTRIBUTE_PTR pPrivateKeyTemplate, /* template
+ * for priv.
+ * key */
+ CK_ULONG ulPrivateKeyAttributeCount, /* # priv.
+ * attrs. */
+ CK_OBJECT_HANDLE_PTR phPublicKey, /* gets pub.
+ * key
+ * handle */
+ CK_OBJECT_HANDLE_PTR phPrivateKey /* gets
+ * priv. key
+ * handle */
+);
+#endif
+
+
+/* C_WrapKey wraps (i.e., encrypts) a key. */
+CK_PKCS11_FUNCTION_INFO(C_WrapKey)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_MECHANISM_PTR pMechanism, /* the wrapping mechanism */
+ CK_OBJECT_HANDLE hWrappingKey, /* wrapping key */
+ CK_OBJECT_HANDLE hKey, /* key to be wrapped */
+ CK_BYTE_PTR pWrappedKey, /* gets wrapped key */
+ CK_ULONG_PTR pulWrappedKeyLen /* gets wrapped key size */
+);
+#endif
+
+
+/* C_UnwrapKey unwraps (decrypts) a wrapped key, creating a new
+ * key object. */
+CK_PKCS11_FUNCTION_INFO(C_UnwrapKey)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* session's handle */
+ CK_MECHANISM_PTR pMechanism, /* unwrapping mech. */
+ CK_OBJECT_HANDLE hUnwrappingKey, /* unwrapping key */
+ CK_BYTE_PTR pWrappedKey, /* the wrapped key */
+ CK_ULONG ulWrappedKeyLen, /* wrapped key len */
+ CK_ATTRIBUTE_PTR pTemplate, /* new key template */
+ CK_ULONG ulAttributeCount, /* template length */
+ CK_OBJECT_HANDLE_PTR phKey /* gets new handle */
+);
+#endif
+
+
+/* C_DeriveKey derives a key from a base key, creating a new key
+ * object. */
+CK_PKCS11_FUNCTION_INFO(C_DeriveKey)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* session's handle */
+ CK_MECHANISM_PTR pMechanism, /* key deriv. mech. */
+ CK_OBJECT_HANDLE hBaseKey, /* base key */
+ CK_ATTRIBUTE_PTR pTemplate, /* new key template */
+ CK_ULONG ulAttributeCount, /* template length */
+ CK_OBJECT_HANDLE_PTR phKey /* gets new handle */
+);
+#endif
+
+
+
+/* Random number generation */
+
+/* C_SeedRandom mixes additional seed material into the token's
+ * random number generator. */
+CK_PKCS11_FUNCTION_INFO(C_SeedRandom)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_BYTE_PTR pSeed, /* the seed material */
+ CK_ULONG ulSeedLen /* length of seed material */
+);
+#endif
+
+
+/* C_GenerateRandom generates random data. */
+CK_PKCS11_FUNCTION_INFO(C_GenerateRandom)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_BYTE_PTR RandomData, /* receives the random data */
+ CK_ULONG ulRandomLen /* # of bytes to generate */
+);
+#endif
+
+
+
+/* Parallel function management */
+
+/* C_GetFunctionStatus is a legacy function; it obtains an
+ * updated status of a function running in parallel with an
+ * application. */
+CK_PKCS11_FUNCTION_INFO(C_GetFunctionStatus)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession /* the session's handle */
+);
+#endif
+
+
+/* C_CancelFunction is a legacy function; it cancels a function
+ * running in parallel. */
+CK_PKCS11_FUNCTION_INFO(C_CancelFunction)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE hSession /* the session's handle */
+);
+#endif
+
+
+
+/* Functions added in for Cryptoki Version 2.01 or later */
+
+/* C_WaitForSlotEvent waits for a slot event (token insertion,
+ * removal, etc.) to occur. */
+CK_PKCS11_FUNCTION_INFO(C_WaitForSlotEvent)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_FLAGS flags, /* blocking/nonblocking flag */
+ CK_SLOT_ID_PTR pSlot, /* location that receives the slot ID */
+ CK_VOID_PTR pRserved /* reserved. Should be NULL_PTR */
+);
+#endif
diff --git a/libdigidoc/pkcs11/pkcs11t.h b/libdigidoc/pkcs11/pkcs11t.h
new file mode 100644
index 0000000..bd44016
--- /dev/null
+++ b/libdigidoc/pkcs11/pkcs11t.h
@@ -0,0 +1,1334 @@
+/* pkcs11t.h include file for PKCS #11. 2001 June 25 */
+
+/* See top of pkcs11.h for information about the macros that
+ * must be defined and the structure-packing conventions that
+ * must be set before including this file. */
+
+#ifndef _PKCS11T_H_
+#define _PKCS11T_H_ 1
+
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+#ifndef TRUE
+#define TRUE (!FALSE)
+#endif
+
+
+/* an unsigned 8-bit value */
+typedef unsigned char CK_BYTE;
+
+/* an unsigned 8-bit character */
+typedef CK_BYTE CK_CHAR;
+
+/* an 8-bit UTF-8 character */
+typedef CK_BYTE CK_UTF8CHAR;
+
+/* a BYTE-sized Boolean flag */
+typedef CK_BYTE CK_BBOOL;
+
+/* an unsigned value, at least 32 bits long */
+typedef unsigned long int CK_ULONG;
+
+/* a signed value, the same size as a CK_ULONG */
+/* CK_LONG is new for v2.0 */
+typedef long int CK_LONG;
+
+/* at least 32 bits; each bit is a Boolean flag */
+typedef CK_ULONG CK_FLAGS;
+
+
+/* some special values for certain CK_ULONG variables */
+#define CK_UNAVAILABLE_INFORMATION (~0UL)
+#define CK_EFFECTIVELY_INFINITE 0
+
+
+typedef CK_BYTE CK_PTR CK_BYTE_PTR;
+typedef CK_CHAR CK_PTR CK_CHAR_PTR;
+typedef CK_UTF8CHAR CK_PTR CK_UTF8CHAR_PTR;
+typedef CK_ULONG CK_PTR CK_ULONG_PTR;
+typedef void CK_PTR CK_VOID_PTR;
+
+/* Pointer to a CK_VOID_PTR-- i.e., pointer to pointer to void */
+typedef CK_VOID_PTR CK_PTR CK_VOID_PTR_PTR;
+
+
+/* The following value is always invalid if used as a session */
+/* handle or object handle */
+#define CK_INVALID_HANDLE 0
+
+
+typedef struct CK_VERSION {
+ CK_BYTE major; /* integer portion of version number */
+ CK_BYTE minor; /* 1/100ths portion of version number */
+} CK_VERSION;
+
+typedef CK_VERSION CK_PTR CK_VERSION_PTR;
+
+
+typedef struct CK_INFO {
+ /* manufacturerID and libraryDecription have been changed from
+ * CK_CHAR to CK_UTF8CHAR for v2.10 */
+ CK_VERSION cryptokiVersion; /* Cryptoki interface ver */
+ CK_UTF8CHAR manufacturerID[32]; /* blank padded */
+ CK_FLAGS flags; /* must be zero */
+
+ /* libraryDescription and libraryVersion are new for v2.0 */
+ CK_UTF8CHAR libraryDescription[32]; /* blank padded */
+ CK_VERSION libraryVersion; /* version of library */
+} CK_INFO;
+
+typedef CK_INFO CK_PTR CK_INFO_PTR;
+
+
+/* CK_NOTIFICATION enumerates the types of notifications that
+ * Cryptoki provides to an application */
+/* CK_NOTIFICATION has been changed from an enum to a CK_ULONG
+ * for v2.0 */
+typedef CK_ULONG CK_NOTIFICATION;
+#define CKN_SURRENDER 0
+
+
+typedef CK_ULONG CK_SLOT_ID;
+
+typedef CK_SLOT_ID CK_PTR CK_SLOT_ID_PTR;
+
+
+/* CK_SLOT_INFO provides information about a slot */
+typedef struct CK_SLOT_INFO {
+ /* slotDescription and manufacturerID have been changed from
+ * CK_CHAR to CK_UTF8CHAR for v2.10 */
+ CK_UTF8CHAR slotDescription[64]; /* blank padded */
+ CK_UTF8CHAR manufacturerID[32]; /* blank padded */
+ CK_FLAGS flags;
+
+ /* hardwareVersion and firmwareVersion are new for v2.0 */
+ CK_VERSION hardwareVersion; /* version of hardware */
+ CK_VERSION firmwareVersion; /* version of firmware */
+} CK_SLOT_INFO;
+
+/* flags: bit flags that provide capabilities of the slot
+ * Bit Flag Mask Meaning
+ */
+#define CKF_TOKEN_PRESENT 0x00000001 /* a token is there */
+#define CKF_REMOVABLE_DEVICE 0x00000002 /* removable devices*/
+#define CKF_HW_SLOT 0x00000004 /* hardware slot */
+
+typedef CK_SLOT_INFO CK_PTR CK_SLOT_INFO_PTR;
+
+
+/* CK_TOKEN_INFO provides information about a token */
+typedef struct CK_TOKEN_INFO {
+ /* label, manufacturerID, and model have been changed from
+ * CK_CHAR to CK_UTF8CHAR for v2.10 */
+ CK_UTF8CHAR label[32]; /* blank padded */
+ CK_UTF8CHAR manufacturerID[32]; /* blank padded */
+ CK_UTF8CHAR model[16]; /* blank padded */
+ CK_CHAR serialNumber[16]; /* blank padded */
+ CK_FLAGS flags; /* see below */
+
+ /* ulMaxSessionCount, ulSessionCount, ulMaxRwSessionCount,
+ * ulRwSessionCount, ulMaxPinLen, and ulMinPinLen have all been
+ * changed from CK_USHORT to CK_ULONG for v2.0 */
+ CK_ULONG ulMaxSessionCount; /* max open sessions */
+ CK_ULONG ulSessionCount; /* sess. now open */
+ CK_ULONG ulMaxRwSessionCount; /* max R/W sessions */
+ CK_ULONG ulRwSessionCount; /* R/W sess. now open */
+ CK_ULONG ulMaxPinLen; /* in bytes */
+ CK_ULONG ulMinPinLen; /* in bytes */
+ CK_ULONG ulTotalPublicMemory; /* in bytes */
+ CK_ULONG ulFreePublicMemory; /* in bytes */
+ CK_ULONG ulTotalPrivateMemory; /* in bytes */
+ CK_ULONG ulFreePrivateMemory; /* in bytes */
+
+ /* hardwareVersion, firmwareVersion, and time are new for
+ * v2.0 */
+ CK_VERSION hardwareVersion; /* version of hardware */
+ CK_VERSION firmwareVersion; /* version of firmware */
+ CK_CHAR utcTime[16]; /* time */
+} CK_TOKEN_INFO;
+
+/* The flags parameter is defined as follows:
+ * Bit Flag Mask Meaning
+ */
+#define CKF_RNG 0x00000001 /* has random #
+ * generator */
+#define CKF_WRITE_PROTECTED 0x00000002 /* token is
+ * write-
+ * protected */
+#define CKF_LOGIN_REQUIRED 0x00000004 /* user must
+ * login */
+#define CKF_USER_PIN_INITIALIZED 0x00000008 /* normal user's
+ * PIN is set */
+
+/* CKF_RESTORE_KEY_NOT_NEEDED is new for v2.0. If it is set,
+ * that means that *every* time the state of cryptographic
+ * operations of a session is successfully saved, all keys
+ * needed to continue those operations are stored in the state */
+#define CKF_RESTORE_KEY_NOT_NEEDED 0x00000020
+
+/* CKF_CLOCK_ON_TOKEN is new for v2.0. If it is set, that means
+ * that the token has some sort of clock. The time on that
+ * clock is returned in the token info structure */
+#define CKF_CLOCK_ON_TOKEN 0x00000040
+
+/* CKF_PROTECTED_AUTHENTICATION_PATH is new for v2.0. If it is
+ * set, that means that there is some way for the user to login
+ * without sending a PIN through the Cryptoki library itself */
+#define CKF_PROTECTED_AUTHENTICATION_PATH 0x00000100
+
+/* CKF_DUAL_CRYPTO_OPERATIONS is new for v2.0. If it is true,
+ * that means that a single session with the token can perform
+ * dual simultaneous cryptographic operations (digest and
+ * encrypt; decrypt and digest; sign and encrypt; and decrypt
+ * and sign) */
+#define CKF_DUAL_CRYPTO_OPERATIONS 0x00000200
+
+/* CKF_TOKEN_INITIALIZED if new for v2.10. If it is true, the
+ * token has been initialized using C_InitializeToken or an
+ * equivalent mechanism outside the scope of PKCS #11.
+ * Calling C_InitializeToken when this flag is set will cause
+ * the token to be reinitialized. */
+#define CKF_TOKEN_INITIALIZED 0x00000400
+
+/* CKF_SECONDARY_AUTHENTICATION if new for v2.10. If it is
+ * true, the token supports secondary authentication for
+ * private key objects. */
+#define CKF_SECONDARY_AUTHENTICATION 0x00000800
+
+/* CKF_USER_PIN_COUNT_LOW if new for v2.10. If it is true, an
+ * incorrect user login PIN has been entered at least once
+ * since the last successful authentication. */
+#define CKF_USER_PIN_COUNT_LOW 0x00010000
+
+/* CKF_USER_PIN_FINAL_TRY if new for v2.10. If it is true,
+ * supplying an incorrect user PIN will it to become locked. */
+#define CKF_USER_PIN_FINAL_TRY 0x00020000
+
+/* CKF_USER_PIN_LOCKED if new for v2.10. If it is true, the
+ * user PIN has been locked. User login to the token is not
+ * possible. */
+#define CKF_USER_PIN_LOCKED 0x00040000
+
+/* CKF_USER_PIN_TO_BE_CHANGED if new for v2.10. If it is true,
+ * the user PIN value is the default value set by token
+ * initialization or manufacturing, or the PIN has been
+ * expired by the card. */
+#define CKF_USER_PIN_TO_BE_CHANGED 0x00080000
+
+/* CKF_SO_PIN_COUNT_LOW if new for v2.10. If it is true, an
+ * incorrect SO login PIN has been entered at least once since
+ * the last successful authentication. */
+#define CKF_SO_PIN_COUNT_LOW 0x00100000
+
+/* CKF_SO_PIN_FINAL_TRY if new for v2.10. If it is true,
+ * supplying an incorrect SO PIN will it to become locked. */
+#define CKF_SO_PIN_FINAL_TRY 0x00200000
+
+/* CKF_SO_PIN_LOCKED if new for v2.10. If it is true, the SO
+ * PIN has been locked. SO login to the token is not possible.
+ */
+#define CKF_SO_PIN_LOCKED 0x00400000
+
+/* CKF_SO_PIN_TO_BE_CHANGED if new for v2.10. If it is true,
+ * the SO PIN value is the default value set by token
+ * initialization or manufacturing, or the PIN has been
+ * expired by the card. */
+#define CKF_SO_PIN_TO_BE_CHANGED 0x00800000
+
+typedef CK_TOKEN_INFO CK_PTR CK_TOKEN_INFO_PTR;
+
+
+/* CK_SESSION_HANDLE is a Cryptoki-assigned value that
+ * identifies a session */
+typedef CK_ULONG CK_SESSION_HANDLE;
+
+typedef CK_SESSION_HANDLE CK_PTR CK_SESSION_HANDLE_PTR;
+
+
+/* CK_USER_TYPE enumerates the types of Cryptoki users */
+/* CK_USER_TYPE has been changed from an enum to a CK_ULONG for
+ * v2.0 */
+typedef CK_ULONG CK_USER_TYPE;
+/* Security Officer */
+#define CKU_SO 0
+/* Normal user */
+#define CKU_USER 1
+
+
+/* CK_STATE enumerates the session states */
+/* CK_STATE has been changed from an enum to a CK_ULONG for
+ * v2.0 */
+typedef CK_ULONG CK_STATE;
+#define CKS_RO_PUBLIC_SESSION 0
+#define CKS_RO_USER_FUNCTIONS 1
+#define CKS_RW_PUBLIC_SESSION 2
+#define CKS_RW_USER_FUNCTIONS 3
+#define CKS_RW_SO_FUNCTIONS 4
+
+
+/* CK_SESSION_INFO provides information about a session */
+typedef struct CK_SESSION_INFO {
+ CK_SLOT_ID slotID;
+ CK_STATE state;
+ CK_FLAGS flags; /* see below */
+
+ /* ulDeviceError was changed from CK_USHORT to CK_ULONG for
+ * v2.0 */
+ CK_ULONG ulDeviceError; /* device-dependent error code */
+} CK_SESSION_INFO;
+
+/* The flags are defined in the following table:
+ * Bit Flag Mask Meaning
+ */
+#define CKF_RW_SESSION 0x00000002 /* session is r/w */
+#define CKF_SERIAL_SESSION 0x00000004 /* no parallel */
+
+typedef CK_SESSION_INFO CK_PTR CK_SESSION_INFO_PTR;
+
+
+/* CK_OBJECT_HANDLE is a token-specific identifier for an
+ * object */
+typedef CK_ULONG CK_OBJECT_HANDLE;
+
+typedef CK_OBJECT_HANDLE CK_PTR CK_OBJECT_HANDLE_PTR;
+
+
+/* CK_OBJECT_CLASS is a value that identifies the classes (or
+ * types) of objects that Cryptoki recognizes. It is defined
+ * as follows: */
+/* CK_OBJECT_CLASS was changed from CK_USHORT to CK_ULONG for
+ * v2.0 */
+typedef CK_ULONG CK_OBJECT_CLASS;
+
+/* The following classes of objects are defined: */
+/* CKO_HW_FEATURE is new for v2.10 */
+/* CKO_DOMAIN_PARAMETERS is new for v2.11 */
+#define CKO_DATA 0x00000000
+#define CKO_CERTIFICATE 0x00000001
+#define CKO_PUBLIC_KEY 0x00000002
+#define CKO_PRIVATE_KEY 0x00000003
+#define CKO_SECRET_KEY 0x00000004
+#define CKO_HW_FEATURE 0x00000005
+#define CKO_DOMAIN_PARAMETERS 0x00000006
+#define CKO_VENDOR_DEFINED 0x80000000
+
+typedef CK_OBJECT_CLASS CK_PTR CK_OBJECT_CLASS_PTR;
+
+/* CK_HW_FEATURE_TYPE is new for v2.10. CK_HW_FEATURE_TYPE is a
+ * value that identifies the hardware feature type of an object
+ * with CK_OBJECT_CLASS equal to CKO_HW_FEATURE. */
+typedef CK_ULONG CK_HW_FEATURE_TYPE;
+
+/* The following hardware feature types are defined */
+#define CKH_MONOTONIC_COUNTER 0x00000001
+#define CKH_CLOCK 0x00000002
+#define CKH_VENDOR_DEFINED 0x80000000
+
+/* CK_KEY_TYPE is a value that identifies a key type */
+/* CK_KEY_TYPE was changed from CK_USHORT to CK_ULONG for v2.0 */
+typedef CK_ULONG CK_KEY_TYPE;
+
+/* the following key types are defined: */
+#define CKK_RSA 0x00000000
+#define CKK_DSA 0x00000001
+#define CKK_DH 0x00000002
+
+/* CKK_ECDSA and CKK_KEA are new for v2.0 */
+/* CKK_ECDSA is deprecated in v2.11, CKK_EC is preferred. */
+#define CKK_ECDSA 0x00000003
+#define CKK_EC 0x00000003
+#define CKK_X9_42_DH 0x00000004
+#define CKK_KEA 0x00000005
+
+#define CKK_GENERIC_SECRET 0x00000010
+#define CKK_RC2 0x00000011
+#define CKK_RC4 0x00000012
+#define CKK_DES 0x00000013
+#define CKK_DES2 0x00000014
+#define CKK_DES3 0x00000015
+
+/* all these key types are new for v2.0 */
+#define CKK_CAST 0x00000016
+#define CKK_CAST3 0x00000017
+/* CKK_CAST5 is deprecated in v2.11, CKK_CAST128 is preferred. */
+#define CKK_CAST5 0x00000018
+#define CKK_CAST128 0x00000018
+#define CKK_RC5 0x00000019
+#define CKK_IDEA 0x0000001A
+#define CKK_SKIPJACK 0x0000001B
+#define CKK_BATON 0x0000001C
+#define CKK_JUNIPER 0x0000001D
+#define CKK_CDMF 0x0000001E
+#define CKK_AES 0x0000001F
+
+#define CKK_VENDOR_DEFINED 0x80000000
+
+
+/* CK_CERTIFICATE_TYPE is a value that identifies a certificate
+ * type */
+/* CK_CERTIFICATE_TYPE was changed from CK_USHORT to CK_ULONG
+ * for v2.0 */
+typedef CK_ULONG CK_CERTIFICATE_TYPE;
+
+/* The following certificate types are defined: */
+/* CKC_X_509_ATTR_CERT is new for v2.10 */
+#define CKC_X_509 0x00000000
+#define CKC_X_509_ATTR_CERT 0x00000001
+#define CKC_VENDOR_DEFINED 0x80000000
+
+
+/* CK_ATTRIBUTE_TYPE is a value that identifies an attribute
+ * type */
+/* CK_ATTRIBUTE_TYPE was changed from CK_USHORT to CK_ULONG for
+ * v2.0 */
+typedef CK_ULONG CK_ATTRIBUTE_TYPE;
+
+/* The following attribute types are defined: */
+#define CKA_CLASS 0x00000000
+#define CKA_TOKEN 0x00000001
+#define CKA_PRIVATE 0x00000002
+#define CKA_LABEL 0x00000003
+#define CKA_APPLICATION 0x00000010
+#define CKA_VALUE 0x00000011
+
+/* CKA_OBJECT_ID is new for v2.10 */
+#define CKA_OBJECT_ID 0x00000012
+
+#define CKA_CERTIFICATE_TYPE 0x00000080
+#define CKA_ISSUER 0x00000081
+#define CKA_SERIAL_NUMBER 0x00000082
+
+/* CKA_AC_ISSUER, CKA_OWNER, and CKA_ATTR_TYPES are new
+ * for v2.10 */
+#define CKA_AC_ISSUER 0x00000083
+#define CKA_OWNER 0x00000084
+#define CKA_ATTR_TYPES 0x00000085
+
+/* CKA_TRUSTED is new for v2.11 */
+#define CKA_TRUSTED 0x00000086
+
+#define CKA_KEY_TYPE 0x00000100
+#define CKA_SUBJECT 0x00000101
+#define CKA_ID 0x00000102
+#define CKA_SENSITIVE 0x00000103
+#define CKA_ENCRYPT 0x00000104
+#define CKA_DECRYPT 0x00000105
+#define CKA_WRAP 0x00000106
+#define CKA_UNWRAP 0x00000107
+#define CKA_SIGN 0x00000108
+#define CKA_SIGN_RECOVER 0x00000109
+#define CKA_VERIFY 0x0000010A
+#define CKA_VERIFY_RECOVER 0x0000010B
+#define CKA_DERIVE 0x0000010C
+#define CKA_START_DATE 0x00000110
+#define CKA_END_DATE 0x00000111
+#define CKA_MODULUS 0x00000120
+#define CKA_MODULUS_BITS 0x00000121
+#define CKA_PUBLIC_EXPONENT 0x00000122
+#define CKA_PRIVATE_EXPONENT 0x00000123
+#define CKA_PRIME_1 0x00000124
+#define CKA_PRIME_2 0x00000125
+#define CKA_EXPONENT_1 0x00000126
+#define CKA_EXPONENT_2 0x00000127
+#define CKA_COEFFICIENT 0x00000128
+#define CKA_PRIME 0x00000130
+#define CKA_SUBPRIME 0x00000131
+#define CKA_BASE 0x00000132
+
+/* CKA_PRIME_BITS and CKA_SUB_PRIME_BITS are new for v2.11 */
+#define CKA_PRIME_BITS 0x00000133
+#define CKA_SUB_PRIME_BITS 0x00000134
+
+#define CKA_VALUE_BITS 0x00000160
+#define CKA_VALUE_LEN 0x00000161
+
+/* CKA_EXTRACTABLE, CKA_LOCAL, CKA_NEVER_EXTRACTABLE,
+ * CKA_ALWAYS_SENSITIVE, CKA_MODIFIABLE, CKA_ECDSA_PARAMS,
+ * and CKA_EC_POINT are new for v2.0 */
+#define CKA_EXTRACTABLE 0x00000162
+#define CKA_LOCAL 0x00000163
+#define CKA_NEVER_EXTRACTABLE 0x00000164
+#define CKA_ALWAYS_SENSITIVE 0x00000165
+
+/* CKA_KEY_GEN_MECHANISM is new for v2.11 */
+#define CKA_KEY_GEN_MECHANISM 0x00000166
+
+#define CKA_MODIFIABLE 0x00000170
+
+/* CKA_ECDSA_PARAMS is deprecated in v2.11,
+ * CKA_EC_PARAMS is preferred. */
+#define CKA_ECDSA_PARAMS 0x00000180
+#define CKA_EC_PARAMS 0x00000180
+
+#define CKA_EC_POINT 0x00000181
+
+/* CKA_SECONDARY_AUTH, CKA_AUTH_PIN_FLAGS,
+ * CKA_HW_FEATURE_TYPE, CKA_RESET_ON_INIT, and CKA_HAS_RESET
+ * are new for v2.10 */
+#define CKA_SECONDARY_AUTH 0x00000200
+#define CKA_AUTH_PIN_FLAGS 0x00000201
+#define CKA_HW_FEATURE_TYPE 0x00000300
+#define CKA_RESET_ON_INIT 0x00000301
+#define CKA_HAS_RESET 0x00000302
+
+#define CKA_VENDOR_DEFINED 0x80000000
+
+
+/* CK_ATTRIBUTE is a structure that includes the type, length
+ * and value of an attribute */
+typedef struct CK_ATTRIBUTE {
+ CK_ATTRIBUTE_TYPE type;
+ CK_VOID_PTR pValue;
+
+ /* ulValueLen went from CK_USHORT to CK_ULONG for v2.0 */
+ CK_ULONG ulValueLen; /* in bytes */
+} CK_ATTRIBUTE;
+
+typedef CK_ATTRIBUTE CK_PTR CK_ATTRIBUTE_PTR;
+
+
+/* CK_DATE is a structure that defines a date */
+typedef struct CK_DATE{
+ CK_CHAR year[4]; /* the year ("1900" - "9999") */
+ CK_CHAR month[2]; /* the month ("01" - "12") */
+ CK_CHAR day[2]; /* the day ("01" - "31") */
+} CK_DATE;
+
+
+/* CK_MECHANISM_TYPE is a value that identifies a mechanism
+ * type */
+/* CK_MECHANISM_TYPE was changed from CK_USHORT to CK_ULONG for
+ * v2.0 */
+typedef CK_ULONG CK_MECHANISM_TYPE;
+
+/* the following mechanism types are defined: */
+#define CKM_RSA_PKCS_KEY_PAIR_GEN 0x00000000
+#define CKM_RSA_PKCS 0x00000001
+#define CKM_RSA_9796 0x00000002
+#define CKM_RSA_X_509 0x00000003
+
+/* CKM_MD2_RSA_PKCS, CKM_MD5_RSA_PKCS, and CKM_SHA1_RSA_PKCS
+ * are new for v2.0. They are mechanisms which hash and sign */
+#define CKM_MD2_RSA_PKCS 0x00000004
+#define CKM_MD5_RSA_PKCS 0x00000005
+#define CKM_SHA1_RSA_PKCS 0x00000006
+
+/* CKM_RIPEMD128_RSA_PKCS, CKM_RIPEMD160_RSA_PKCS, and
+ * CKM_RSA_PKCS_OAEP are new for v2.10 */
+#define CKM_RIPEMD128_RSA_PKCS 0x00000007
+#define CKM_RIPEMD160_RSA_PKCS 0x00000008
+#define CKM_RSA_PKCS_OAEP 0x00000009
+
+/* CKM_RSA_X9_31_KEY_PAIR_GEN, CKM_RSA_X9_31, CKM_SHA1_RSA_X9_31,
+ * CKM_RSA_PKCS_PSS, and CKM_SHA1_RSA_PKCS_PSS are new for v2.11 */
+#define CKM_RSA_X9_31_KEY_PAIR_GEN 0x0000000A
+#define CKM_RSA_X9_31 0x0000000B
+#define CKM_SHA1_RSA_X9_31 0x0000000C
+#define CKM_RSA_PKCS_PSS 0x0000000D
+#define CKM_SHA1_RSA_PKCS_PSS 0x0000000E
+
+#define CKM_DSA_KEY_PAIR_GEN 0x00000010
+#define CKM_DSA 0x00000011
+#define CKM_DSA_SHA1 0x00000012
+#define CKM_DH_PKCS_KEY_PAIR_GEN 0x00000020
+#define CKM_DH_PKCS_DERIVE 0x00000021
+
+/* CKM_X9_42_DH_KEY_PAIR_GEN, CKM_X9_42_DH_DERIVE,
+ * CKM_X9_42_DH_HYBRID_DERIVE, and CKM_X9_42_MQV_DERIVE are new for
+ * v2.11 */
+#define CKM_X9_42_DH_KEY_PAIR_GEN 0x00000030
+#define CKM_X9_42_DH_DERIVE 0x00000031
+#define CKM_X9_42_DH_HYBRID_DERIVE 0x00000032
+#define CKM_X9_42_MQV_DERIVE 0x00000033
+
+#define CKM_RC2_KEY_GEN 0x00000100
+#define CKM_RC2_ECB 0x00000101
+#define CKM_RC2_CBC 0x00000102
+#define CKM_RC2_MAC 0x00000103
+
+/* CKM_RC2_MAC_GENERAL and CKM_RC2_CBC_PAD are new for v2.0 */
+#define CKM_RC2_MAC_GENERAL 0x00000104
+#define CKM_RC2_CBC_PAD 0x00000105
+
+#define CKM_RC4_KEY_GEN 0x00000110
+#define CKM_RC4 0x00000111
+#define CKM_DES_KEY_GEN 0x00000120
+#define CKM_DES_ECB 0x00000121
+#define CKM_DES_CBC 0x00000122
+#define CKM_DES_MAC 0x00000123
+
+/* CKM_DES_MAC_GENERAL and CKM_DES_CBC_PAD are new for v2.0 */
+#define CKM_DES_MAC_GENERAL 0x00000124
+#define CKM_DES_CBC_PAD 0x00000125
+
+#define CKM_DES2_KEY_GEN 0x00000130
+#define CKM_DES3_KEY_GEN 0x00000131
+#define CKM_DES3_ECB 0x00000132
+#define CKM_DES3_CBC 0x00000133
+#define CKM_DES3_MAC 0x00000134
+
+/* CKM_DES3_MAC_GENERAL, CKM_DES3_CBC_PAD, CKM_CDMF_KEY_GEN,
+ * CKM_CDMF_ECB, CKM_CDMF_CBC, CKM_CDMF_MAC,
+ * CKM_CDMF_MAC_GENERAL, and CKM_CDMF_CBC_PAD are new for v2.0 */
+#define CKM_DES3_MAC_GENERAL 0x00000135
+#define CKM_DES3_CBC_PAD 0x00000136
+#define CKM_CDMF_KEY_GEN 0x00000140
+#define CKM_CDMF_ECB 0x00000141
+#define CKM_CDMF_CBC 0x00000142
+#define CKM_CDMF_MAC 0x00000143
+#define CKM_CDMF_MAC_GENERAL 0x00000144
+#define CKM_CDMF_CBC_PAD 0x00000145
+
+#define CKM_MD2 0x00000200
+
+/* CKM_MD2_HMAC and CKM_MD2_HMAC_GENERAL are new for v2.0 */
+#define CKM_MD2_HMAC 0x00000201
+#define CKM_MD2_HMAC_GENERAL 0x00000202
+
+#define CKM_MD5 0x00000210
+
+/* CKM_MD5_HMAC and CKM_MD5_HMAC_GENERAL are new for v2.0 */
+#define CKM_MD5_HMAC 0x00000211
+#define CKM_MD5_HMAC_GENERAL 0x00000212
+
+#define CKM_SHA_1 0x00000220
+
+/* CKM_SHA_1_HMAC and CKM_SHA_1_HMAC_GENERAL are new for v2.0 */
+#define CKM_SHA_1_HMAC 0x00000221
+#define CKM_SHA_1_HMAC_GENERAL 0x00000222
+
+/* CKM_RIPEMD128, CKM_RIPEMD128_HMAC,
+ * CKM_RIPEMD128_HMAC_GENERAL, CKM_RIPEMD160, CKM_RIPEMD160_HMAC,
+ * and CKM_RIPEMD160_HMAC_GENERAL are new for v2.10 */
+#define CKM_RIPEMD128 0x00000230
+#define CKM_RIPEMD128_HMAC 0x00000231
+#define CKM_RIPEMD128_HMAC_GENERAL 0x00000232
+#define CKM_RIPEMD160 0x00000240
+#define CKM_RIPEMD160_HMAC 0x00000241
+#define CKM_RIPEMD160_HMAC_GENERAL 0x00000242
+
+/* All of the following mechanisms are new for v2.0 */
+/* Note that CAST128 and CAST5 are the same algorithm */
+#define CKM_CAST_KEY_GEN 0x00000300
+#define CKM_CAST_ECB 0x00000301
+#define CKM_CAST_CBC 0x00000302
+#define CKM_CAST_MAC 0x00000303
+#define CKM_CAST_MAC_GENERAL 0x00000304
+#define CKM_CAST_CBC_PAD 0x00000305
+#define CKM_CAST3_KEY_GEN 0x00000310
+#define CKM_CAST3_ECB 0x00000311
+#define CKM_CAST3_CBC 0x00000312
+#define CKM_CAST3_MAC 0x00000313
+#define CKM_CAST3_MAC_GENERAL 0x00000314
+#define CKM_CAST3_CBC_PAD 0x00000315
+#define CKM_CAST5_KEY_GEN 0x00000320
+#define CKM_CAST128_KEY_GEN 0x00000320
+#define CKM_CAST5_ECB 0x00000321
+#define CKM_CAST128_ECB 0x00000321
+#define CKM_CAST5_CBC 0x00000322
+#define CKM_CAST128_CBC 0x00000322
+#define CKM_CAST5_MAC 0x00000323
+#define CKM_CAST128_MAC 0x00000323
+#define CKM_CAST5_MAC_GENERAL 0x00000324
+#define CKM_CAST128_MAC_GENERAL 0x00000324
+#define CKM_CAST5_CBC_PAD 0x00000325
+#define CKM_CAST128_CBC_PAD 0x00000325
+#define CKM_RC5_KEY_GEN 0x00000330
+#define CKM_RC5_ECB 0x00000331
+#define CKM_RC5_CBC 0x00000332
+#define CKM_RC5_MAC 0x00000333
+#define CKM_RC5_MAC_GENERAL 0x00000334
+#define CKM_RC5_CBC_PAD 0x00000335
+#define CKM_IDEA_KEY_GEN 0x00000340
+#define CKM_IDEA_ECB 0x00000341
+#define CKM_IDEA_CBC 0x00000342
+#define CKM_IDEA_MAC 0x00000343
+#define CKM_IDEA_MAC_GENERAL 0x00000344
+#define CKM_IDEA_CBC_PAD 0x00000345
+#define CKM_GENERIC_SECRET_KEY_GEN 0x00000350
+#define CKM_CONCATENATE_BASE_AND_KEY 0x00000360
+#define CKM_CONCATENATE_BASE_AND_DATA 0x00000362
+#define CKM_CONCATENATE_DATA_AND_BASE 0x00000363
+#define CKM_XOR_BASE_AND_DATA 0x00000364
+#define CKM_EXTRACT_KEY_FROM_KEY 0x00000365
+#define CKM_SSL3_PRE_MASTER_KEY_GEN 0x00000370
+#define CKM_SSL3_MASTER_KEY_DERIVE 0x00000371
+#define CKM_SSL3_KEY_AND_MAC_DERIVE 0x00000372
+
+/* CKM_SSL3_MASTER_KEY_DERIVE_DH, CKM_TLS_PRE_MASTER_KEY_GEN,
+ * CKM_TLS_MASTER_KEY_DERIVE, CKM_TLS_KEY_AND_MAC_DERIVE, and
+ * CKM_TLS_MASTER_KEY_DERIVE_DH are new for v2.11 */
+#define CKM_SSL3_MASTER_KEY_DERIVE_DH 0x00000373
+#define CKM_TLS_PRE_MASTER_KEY_GEN 0x00000374
+#define CKM_TLS_MASTER_KEY_DERIVE 0x00000375
+#define CKM_TLS_KEY_AND_MAC_DERIVE 0x00000376
+#define CKM_TLS_MASTER_KEY_DERIVE_DH 0x00000377
+
+#define CKM_SSL3_MD5_MAC 0x00000380
+#define CKM_SSL3_SHA1_MAC 0x00000381
+#define CKM_MD5_KEY_DERIVATION 0x00000390
+#define CKM_MD2_KEY_DERIVATION 0x00000391
+#define CKM_SHA1_KEY_DERIVATION 0x00000392
+#define CKM_PBE_MD2_DES_CBC 0x000003A0
+#define CKM_PBE_MD5_DES_CBC 0x000003A1
+#define CKM_PBE_MD5_CAST_CBC 0x000003A2
+#define CKM_PBE_MD5_CAST3_CBC 0x000003A3
+#define CKM_PBE_MD5_CAST5_CBC 0x000003A4
+#define CKM_PBE_MD5_CAST128_CBC 0x000003A4
+#define CKM_PBE_SHA1_CAST5_CBC 0x000003A5
+#define CKM_PBE_SHA1_CAST128_CBC 0x000003A5
+#define CKM_PBE_SHA1_RC4_128 0x000003A6
+#define CKM_PBE_SHA1_RC4_40 0x000003A7
+#define CKM_PBE_SHA1_DES3_EDE_CBC 0x000003A8
+#define CKM_PBE_SHA1_DES2_EDE_CBC 0x000003A9
+#define CKM_PBE_SHA1_RC2_128_CBC 0x000003AA
+#define CKM_PBE_SHA1_RC2_40_CBC 0x000003AB
+
+/* CKM_PKCS5_PBKD2 is new for v2.10 */
+#define CKM_PKCS5_PBKD2 0x000003B0
+
+#define CKM_PBA_SHA1_WITH_SHA1_HMAC 0x000003C0
+#define CKM_KEY_WRAP_LYNKS 0x00000400
+#define CKM_KEY_WRAP_SET_OAEP 0x00000401
+
+/* Fortezza mechanisms */
+#define CKM_SKIPJACK_KEY_GEN 0x00001000
+#define CKM_SKIPJACK_ECB64 0x00001001
+#define CKM_SKIPJACK_CBC64 0x00001002
+#define CKM_SKIPJACK_OFB64 0x00001003
+#define CKM_SKIPJACK_CFB64 0x00001004
+#define CKM_SKIPJACK_CFB32 0x00001005
+#define CKM_SKIPJACK_CFB16 0x00001006
+#define CKM_SKIPJACK_CFB8 0x00001007
+#define CKM_SKIPJACK_WRAP 0x00001008
+#define CKM_SKIPJACK_PRIVATE_WRAP 0x00001009
+#define CKM_SKIPJACK_RELAYX 0x0000100a
+#define CKM_KEA_KEY_PAIR_GEN 0x00001010
+#define CKM_KEA_KEY_DERIVE 0x00001011
+#define CKM_FORTEZZA_TIMESTAMP 0x00001020
+#define CKM_BATON_KEY_GEN 0x00001030
+#define CKM_BATON_ECB128 0x00001031
+#define CKM_BATON_ECB96 0x00001032
+#define CKM_BATON_CBC128 0x00001033
+#define CKM_BATON_COUNTER 0x00001034
+#define CKM_BATON_SHUFFLE 0x00001035
+#define CKM_BATON_WRAP 0x00001036
+
+/* CKM_ECDSA_KEY_PAIR_GEN is deprecated in v2.11,
+ * CKM_EC_KEY_PAIR_GEN is preferred */
+#define CKM_ECDSA_KEY_PAIR_GEN 0x00001040
+#define CKM_EC_KEY_PAIR_GEN 0x00001040
+
+#define CKM_ECDSA 0x00001041
+#define CKM_ECDSA_SHA1 0x00001042
+
+/* CKM_ECDH1_DERIVE, CKM_ECDH1_COFACTOR_DERIVE, and CKM_ECMQV_DERIVE
+ * are new for v2.11 */
+#define CKM_ECDH1_DERIVE 0x00001050
+#define CKM_ECDH1_COFACTOR_DERIVE 0x00001051
+#define CKM_ECMQV_DERIVE 0x00001052
+
+#define CKM_JUNIPER_KEY_GEN 0x00001060
+#define CKM_JUNIPER_ECB128 0x00001061
+#define CKM_JUNIPER_CBC128 0x00001062
+#define CKM_JUNIPER_COUNTER 0x00001063
+#define CKM_JUNIPER_SHUFFLE 0x00001064
+#define CKM_JUNIPER_WRAP 0x00001065
+#define CKM_FASTHASH 0x00001070
+
+/* CKM_AES_KEY_GEN, CKM_AES_ECB, CKM_AES_CBC, CKM_AES_MAC,
+ * CKM_AES_MAC_GENERAL, CKM_AES_CBC_PAD, CKM_DSA_PARAMETER_GEN,
+ * CKM_DH_PKCS_PARAMETER_GEN, and CKM_X9_42_DH_PARAMETER_GEN are
+ * new for v2.11 */
+#define CKM_AES_KEY_GEN 0x00001080
+#define CKM_AES_ECB 0x00001081
+#define CKM_AES_CBC 0x00001082
+#define CKM_AES_MAC 0x00001083
+#define CKM_AES_MAC_GENERAL 0x00001084
+#define CKM_AES_CBC_PAD 0x00001085
+#define CKM_DSA_PARAMETER_GEN 0x00002000
+#define CKM_DH_PKCS_PARAMETER_GEN 0x00002001
+#define CKM_X9_42_DH_PARAMETER_GEN 0x00002002
+
+#define CKM_VENDOR_DEFINED 0x80000000
+
+typedef CK_MECHANISM_TYPE CK_PTR CK_MECHANISM_TYPE_PTR;
+
+
+/* CK_MECHANISM is a structure that specifies a particular
+ * mechanism */
+typedef struct CK_MECHANISM {
+ CK_MECHANISM_TYPE mechanism;
+ CK_VOID_PTR pParameter;
+
+ /* ulParameterLen was changed from CK_USHORT to CK_ULONG for
+ * v2.0 */
+ CK_ULONG ulParameterLen; /* in bytes */
+} CK_MECHANISM;
+
+typedef CK_MECHANISM CK_PTR CK_MECHANISM_PTR;
+
+
+/* CK_MECHANISM_INFO provides information about a particular
+ * mechanism */
+typedef struct CK_MECHANISM_INFO {
+ CK_ULONG ulMinKeySize;
+ CK_ULONG ulMaxKeySize;
+ CK_FLAGS flags;
+} CK_MECHANISM_INFO;
+
+/* The flags are defined as follows:
+ * Bit Flag Mask Meaning */
+#define CKF_HW 0x00000001 /* performed by HW */
+
+/* The flags CKF_ENCRYPT, CKF_DECRYPT, CKF_DIGEST, CKF_SIGN,
+ * CKG_SIGN_RECOVER, CKF_VERIFY, CKF_VERIFY_RECOVER,
+ * CKF_GENERATE, CKF_GENERATE_KEY_PAIR, CKF_WRAP, CKF_UNWRAP,
+ * and CKF_DERIVE are new for v2.0. They specify whether or not
+ * a mechanism can be used for a particular task */
+#define CKF_ENCRYPT 0x00000100
+#define CKF_DECRYPT 0x00000200
+#define CKF_DIGEST 0x00000400
+#define CKF_SIGN 0x00000800
+#define CKF_SIGN_RECOVER 0x00001000
+#define CKF_VERIFY 0x00002000
+#define CKF_VERIFY_RECOVER 0x00004000
+#define CKF_GENERATE 0x00008000
+#define CKF_GENERATE_KEY_PAIR 0x00010000
+#define CKF_WRAP 0x00020000
+#define CKF_UNWRAP 0x00040000
+#define CKF_DERIVE 0x00080000
+
+/* CKF_EC_F_P, CKF_EC_F_2M, CKF_EC_ECPARAMETERS, CKF_EC_NAMEDCURVE,
+ * CKF_EC_UNCOMPRESS, and CKF_EC_COMPRESS are new for v2.11. They
+ * describe a token's EC capabilities not available in mechanism
+ * information. */
+#define CKF_EC_F_P 0x00100000
+#define CKF_EC_F_2M 0x00200000
+#define CKF_EC_ECPARAMETERS 0x00400000
+#define CKF_EC_NAMEDCURVE 0x00800000
+#define CKF_EC_UNCOMPRESS 0x01000000
+#define CKF_EC_COMPRESS 0x02000000
+
+#define CKF_EXTENSION 0x80000000 /* FALSE for 2.01 */
+
+typedef CK_MECHANISM_INFO CK_PTR CK_MECHANISM_INFO_PTR;
+
+
+/* CK_RV is a value that identifies the return value of a
+ * Cryptoki function */
+/* CK_RV was changed from CK_USHORT to CK_ULONG for v2.0 */
+typedef CK_ULONG CK_RV;
+
+#define CKR_OK 0x00000000
+#define CKR_CANCEL 0x00000001
+#define CKR_HOST_MEMORY 0x00000002
+#define CKR_SLOT_ID_INVALID 0x00000003
+
+/* CKR_FLAGS_INVALID was removed for v2.0 */
+
+/* CKR_GENERAL_ERROR and CKR_FUNCTION_FAILED are new for v2.0 */
+#define CKR_GENERAL_ERROR 0x00000005
+#define CKR_FUNCTION_FAILED 0x00000006
+
+/* CKR_ARGUMENTS_BAD, CKR_NO_EVENT, CKR_NEED_TO_CREATE_THREADS,
+ * and CKR_CANT_LOCK are new for v2.01 */
+#define CKR_ARGUMENTS_BAD 0x00000007
+#define CKR_NO_EVENT 0x00000008
+#define CKR_NEED_TO_CREATE_THREADS 0x00000009
+#define CKR_CANT_LOCK 0x0000000A
+
+#define CKR_ATTRIBUTE_READ_ONLY 0x00000010
+#define CKR_ATTRIBUTE_SENSITIVE 0x00000011
+#define CKR_ATTRIBUTE_TYPE_INVALID 0x00000012
+#define CKR_ATTRIBUTE_VALUE_INVALID 0x00000013
+#define CKR_DATA_INVALID 0x00000020
+#define CKR_DATA_LEN_RANGE 0x00000021
+#define CKR_DEVICE_ERROR 0x00000030
+#define CKR_DEVICE_MEMORY 0x00000031
+#define CKR_DEVICE_REMOVED 0x00000032
+#define CKR_ENCRYPTED_DATA_INVALID 0x00000040
+#define CKR_ENCRYPTED_DATA_LEN_RANGE 0x00000041
+#define CKR_FUNCTION_CANCELED 0x00000050
+#define CKR_FUNCTION_NOT_PARALLEL 0x00000051
+
+/* CKR_FUNCTION_NOT_SUPPORTED is new for v2.0 */
+#define CKR_FUNCTION_NOT_SUPPORTED 0x00000054
+
+#define CKR_KEY_HANDLE_INVALID 0x00000060
+
+/* CKR_KEY_SENSITIVE was removed for v2.0 */
+
+#define CKR_KEY_SIZE_RANGE 0x00000062
+#define CKR_KEY_TYPE_INCONSISTENT 0x00000063
+
+/* CKR_KEY_NOT_NEEDED, CKR_KEY_CHANGED, CKR_KEY_NEEDED,
+ * CKR_KEY_INDIGESTIBLE, CKR_KEY_FUNCTION_NOT_PERMITTED,
+ * CKR_KEY_NOT_WRAPPABLE, and CKR_KEY_UNEXTRACTABLE are new for
+ * v2.0 */
+#define CKR_KEY_NOT_NEEDED 0x00000064
+#define CKR_KEY_CHANGED 0x00000065
+#define CKR_KEY_NEEDED 0x00000066
+#define CKR_KEY_INDIGESTIBLE 0x00000067
+#define CKR_KEY_FUNCTION_NOT_PERMITTED 0x00000068
+#define CKR_KEY_NOT_WRAPPABLE 0x00000069
+#define CKR_KEY_UNEXTRACTABLE 0x0000006A
+
+#define CKR_MECHANISM_INVALID 0x00000070
+#define CKR_MECHANISM_PARAM_INVALID 0x00000071
+
+/* CKR_OBJECT_CLASS_INCONSISTENT and CKR_OBJECT_CLASS_INVALID
+ * were removed for v2.0 */
+#define CKR_OBJECT_HANDLE_INVALID 0x00000082
+#define CKR_OPERATION_ACTIVE 0x00000090
+#define CKR_OPERATION_NOT_INITIALIZED 0x00000091
+#define CKR_PIN_INCORRECT 0x000000A0
+#define CKR_PIN_INVALID 0x000000A1
+#define CKR_PIN_LEN_RANGE 0x000000A2
+
+/* CKR_PIN_EXPIRED and CKR_PIN_LOCKED are new for v2.0 */
+#define CKR_PIN_EXPIRED 0x000000A3
+#define CKR_PIN_LOCKED 0x000000A4
+
+#define CKR_SESSION_CLOSED 0x000000B0
+#define CKR_SESSION_COUNT 0x000000B1
+#define CKR_SESSION_HANDLE_INVALID 0x000000B3
+#define CKR_SESSION_PARALLEL_NOT_SUPPORTED 0x000000B4
+#define CKR_SESSION_READ_ONLY 0x000000B5
+#define CKR_SESSION_EXISTS 0x000000B6
+
+/* CKR_SESSION_READ_ONLY_EXISTS and
+ * CKR_SESSION_READ_WRITE_SO_EXISTS are new for v2.0 */
+#define CKR_SESSION_READ_ONLY_EXISTS 0x000000B7
+#define CKR_SESSION_READ_WRITE_SO_EXISTS 0x000000B8
+
+#define CKR_SIGNATURE_INVALID 0x000000C0
+#define CKR_SIGNATURE_LEN_RANGE 0x000000C1
+#define CKR_TEMPLATE_INCOMPLETE 0x000000D0
+#define CKR_TEMPLATE_INCONSISTENT 0x000000D1
+#define CKR_TOKEN_NOT_PRESENT 0x000000E0
+#define CKR_TOKEN_NOT_RECOGNIZED 0x000000E1
+#define CKR_TOKEN_WRITE_PROTECTED 0x000000E2
+#define CKR_UNWRAPPING_KEY_HANDLE_INVALID 0x000000F0
+#define CKR_UNWRAPPING_KEY_SIZE_RANGE 0x000000F1
+#define CKR_UNWRAPPING_KEY_TYPE_INCONSISTENT 0x000000F2
+#define CKR_USER_ALREADY_LOGGED_IN 0x00000100
+#define CKR_USER_NOT_LOGGED_IN 0x00000101
+#define CKR_USER_PIN_NOT_INITIALIZED 0x00000102
+#define CKR_USER_TYPE_INVALID 0x00000103
+
+/* CKR_USER_ANOTHER_ALREADY_LOGGED_IN and CKR_USER_TOO_MANY_TYPES
+ * are new to v2.01 */
+#define CKR_USER_ANOTHER_ALREADY_LOGGED_IN 0x00000104
+#define CKR_USER_TOO_MANY_TYPES 0x00000105
+
+#define CKR_WRAPPED_KEY_INVALID 0x00000110
+#define CKR_WRAPPED_KEY_LEN_RANGE 0x00000112
+#define CKR_WRAPPING_KEY_HANDLE_INVALID 0x00000113
+#define CKR_WRAPPING_KEY_SIZE_RANGE 0x00000114
+#define CKR_WRAPPING_KEY_TYPE_INCONSISTENT 0x00000115
+#define CKR_RANDOM_SEED_NOT_SUPPORTED 0x00000120
+
+/* These are new to v2.0 */
+#define CKR_RANDOM_NO_RNG 0x00000121
+
+/* These are new to v2.11 */
+#define CKR_DOMAIN_PARAMS_INVALID 0x00000130
+
+/* These are new to v2.0 */
+#define CKR_BUFFER_TOO_SMALL 0x00000150
+#define CKR_SAVED_STATE_INVALID 0x00000160
+#define CKR_INFORMATION_SENSITIVE 0x00000170
+#define CKR_STATE_UNSAVEABLE 0x00000180
+
+/* These are new to v2.01 */
+#define CKR_CRYPTOKI_NOT_INITIALIZED 0x00000190
+#define CKR_CRYPTOKI_ALREADY_INITIALIZED 0x00000191
+#define CKR_MUTEX_BAD 0x000001A0
+#define CKR_MUTEX_NOT_LOCKED 0x000001A1
+
+#define CKR_VENDOR_DEFINED 0x80000000
+
+
+/* CK_NOTIFY is an application callback that processes events */
+typedef CK_CALLBACK_FUNCTION(CK_RV, CK_NOTIFY)(
+ CK_SESSION_HANDLE hSession, /* the session's handle */
+ CK_NOTIFICATION event,
+ CK_VOID_PTR pApplication /* passed to C_OpenSession */
+);
+
+
+/* CK_FUNCTION_LIST is a structure holding a Cryptoki spec
+ * version and pointers of appropriate types to all the
+ * Cryptoki functions */
+/* CK_FUNCTION_LIST is new for v2.0 */
+typedef struct CK_FUNCTION_LIST CK_FUNCTION_LIST;
+
+typedef CK_FUNCTION_LIST CK_PTR CK_FUNCTION_LIST_PTR;
+
+typedef CK_FUNCTION_LIST_PTR CK_PTR CK_FUNCTION_LIST_PTR_PTR;
+
+
+/* CK_CREATEMUTEX is an application callback for creating a
+ * mutex object */
+typedef CK_CALLBACK_FUNCTION(CK_RV, CK_CREATEMUTEX)(
+ CK_VOID_PTR_PTR ppMutex /* location to receive ptr to mutex */
+);
+
+
+/* CK_DESTROYMUTEX is an application callback for destroying a
+ * mutex object */
+typedef CK_CALLBACK_FUNCTION(CK_RV, CK_DESTROYMUTEX)(
+ CK_VOID_PTR pMutex /* pointer to mutex */
+);
+
+
+/* CK_LOCKMUTEX is an application callback for locking a mutex */
+typedef CK_CALLBACK_FUNCTION(CK_RV, CK_LOCKMUTEX)(
+ CK_VOID_PTR pMutex /* pointer to mutex */
+);
+
+
+/* CK_UNLOCKMUTEX is an application callback for unlocking a
+ * mutex */
+typedef CK_CALLBACK_FUNCTION(CK_RV, CK_UNLOCKMUTEX)(
+ CK_VOID_PTR pMutex /* pointer to mutex */
+);
+
+
+/* CK_C_INITIALIZE_ARGS provides the optional arguments to
+ * C_Initialize */
+typedef struct CK_C_INITIALIZE_ARGS {
+ CK_CREATEMUTEX CreateMutex;
+ CK_DESTROYMUTEX DestroyMutex;
+ CK_LOCKMUTEX LockMutex;
+ CK_UNLOCKMUTEX UnlockMutex;
+ CK_FLAGS flags;
+ CK_VOID_PTR pReserved;
+} CK_C_INITIALIZE_ARGS;
+
+/* flags: bit flags that provide capabilities of the slot
+ * Bit Flag Mask Meaning
+ */
+#define CKF_LIBRARY_CANT_CREATE_OS_THREADS 0x00000001
+#define CKF_OS_LOCKING_OK 0x00000002
+
+typedef CK_C_INITIALIZE_ARGS CK_PTR CK_C_INITIALIZE_ARGS_PTR;
+
+
+/* additional flags for parameters to functions */
+
+/* CKF_DONT_BLOCK is for the function C_WaitForSlotEvent */
+#define CKF_DONT_BLOCK 1
+
+/* CK_RSA_PKCS_OAEP_MGF_TYPE is new for v2.10.
+ * CK_RSA_PKCS_OAEP_MGF_TYPE is used to indicate the Message
+ * Generation Function (MGF) applied to a message block when
+ * formatting a message block for the PKCS #1 OAEP encryption
+ * scheme. */
+typedef CK_ULONG CK_RSA_PKCS_MGF_TYPE;
+
+typedef CK_RSA_PKCS_MGF_TYPE CK_PTR CK_RSA_PKCS_MGF_TYPE_PTR;
+
+/* The following MGFs are defined */
+#define CKG_MGF1_SHA1 0x00000001
+
+/* CK_RSA_PKCS_OAEP_SOURCE_TYPE is new for v2.10.
+ * CK_RSA_PKCS_OAEP_SOURCE_TYPE is used to indicate the source
+ * of the encoding parameter when formatting a message block
+ * for the PKCS #1 OAEP encryption scheme. */
+typedef CK_ULONG CK_RSA_PKCS_OAEP_SOURCE_TYPE;
+
+typedef CK_RSA_PKCS_OAEP_SOURCE_TYPE CK_PTR CK_RSA_PKCS_OAEP_SOURCE_TYPE_PTR;
+
+/* The following encoding parameter sources are defined */
+#define CKZ_DATA_SPECIFIED 0x00000001
+
+/* CK_RSA_PKCS_OAEP_PARAMS is new for v2.10.
+ * CK_RSA_PKCS_OAEP_PARAMS provides the parameters to the
+ * CKM_RSA_PKCS_OAEP mechanism. */
+typedef struct CK_RSA_PKCS_OAEP_PARAMS {
+ CK_MECHANISM_TYPE hashAlg;
+ CK_RSA_PKCS_MGF_TYPE mgf;
+ CK_RSA_PKCS_OAEP_SOURCE_TYPE source;
+ CK_VOID_PTR pSourceData;
+ CK_ULONG ulSourceDataLen;
+} CK_RSA_PKCS_OAEP_PARAMS;
+
+typedef CK_RSA_PKCS_OAEP_PARAMS CK_PTR CK_RSA_PKCS_OAEP_PARAMS_PTR;
+
+/* CK_RSA_PKCS_PSS_PARAMS is new for v2.11.
+ * CK_RSA_PKCS_PSS_PARAMS provides the parameters to the
+ * CKM_RSA_PKCS_PSS mechanism(s). */
+typedef struct CK_RSA_PKCS_PSS_PARAMS {
+ CK_MECHANISM_TYPE hashAlg;
+ CK_RSA_PKCS_MGF_TYPE mgf;
+ CK_ULONG sLen;
+} CK_RSA_PKCS_PSS_PARAMS;
+
+/* CK_KEA_DERIVE_PARAMS provides the parameters to the
+ * CKM_KEA_DERIVE mechanism */
+/* CK_KEA_DERIVE_PARAMS is new for v2.0 */
+typedef struct CK_KEA_DERIVE_PARAMS {
+ CK_BBOOL isSender;
+ CK_ULONG ulRandomLen;
+ CK_BYTE_PTR pRandomA;
+ CK_BYTE_PTR pRandomB;
+ CK_ULONG ulPublicDataLen;
+ CK_BYTE_PTR pPublicData;
+} CK_KEA_DERIVE_PARAMS;
+
+typedef CK_KEA_DERIVE_PARAMS CK_PTR CK_KEA_DERIVE_PARAMS_PTR;
+
+
+/* CK_RC2_PARAMS provides the parameters to the CKM_RC2_ECB and
+ * CKM_RC2_MAC mechanisms. An instance of CK_RC2_PARAMS just
+ * holds the effective keysize */
+typedef CK_ULONG CK_RC2_PARAMS;
+
+typedef CK_RC2_PARAMS CK_PTR CK_RC2_PARAMS_PTR;
+
+
+/* CK_RC2_CBC_PARAMS provides the parameters to the CKM_RC2_CBC
+ * mechanism */
+typedef struct CK_RC2_CBC_PARAMS {
+ /* ulEffectiveBits was changed from CK_USHORT to CK_ULONG for
+ * v2.0 */
+ CK_ULONG ulEffectiveBits; /* effective bits (1-1024) */
+
+ CK_BYTE iv[8]; /* IV for CBC mode */
+} CK_RC2_CBC_PARAMS;
+
+typedef CK_RC2_CBC_PARAMS CK_PTR CK_RC2_CBC_PARAMS_PTR;
+
+
+/* CK_RC2_MAC_GENERAL_PARAMS provides the parameters for the
+ * CKM_RC2_MAC_GENERAL mechanism */
+/* CK_RC2_MAC_GENERAL_PARAMS is new for v2.0 */
+typedef struct CK_RC2_MAC_GENERAL_PARAMS {
+ CK_ULONG ulEffectiveBits; /* effective bits (1-1024) */
+ CK_ULONG ulMacLength; /* Length of MAC in bytes */
+} CK_RC2_MAC_GENERAL_PARAMS;
+
+typedef CK_RC2_MAC_GENERAL_PARAMS CK_PTR \
+ CK_RC2_MAC_GENERAL_PARAMS_PTR;
+
+
+/* CK_RC5_PARAMS provides the parameters to the CKM_RC5_ECB and
+ * CKM_RC5_MAC mechanisms */
+/* CK_RC5_PARAMS is new for v2.0 */
+typedef struct CK_RC5_PARAMS {
+ CK_ULONG ulWordsize; /* wordsize in bits */
+ CK_ULONG ulRounds; /* number of rounds */
+} CK_RC5_PARAMS;
+
+typedef CK_RC5_PARAMS CK_PTR CK_RC5_PARAMS_PTR;
+
+
+/* CK_RC5_CBC_PARAMS provides the parameters to the CKM_RC5_CBC
+ * mechanism */
+/* CK_RC5_CBC_PARAMS is new for v2.0 */
+typedef struct CK_RC5_CBC_PARAMS {
+ CK_ULONG ulWordsize; /* wordsize in bits */
+ CK_ULONG ulRounds; /* number of rounds */
+ CK_BYTE_PTR pIv; /* pointer to IV */
+ CK_ULONG ulIvLen; /* length of IV in bytes */
+} CK_RC5_CBC_PARAMS;
+
+typedef CK_RC5_CBC_PARAMS CK_PTR CK_RC5_CBC_PARAMS_PTR;
+
+
+/* CK_RC5_MAC_GENERAL_PARAMS provides the parameters for the
+ * CKM_RC5_MAC_GENERAL mechanism */
+/* CK_RC5_MAC_GENERAL_PARAMS is new for v2.0 */
+typedef struct CK_RC5_MAC_GENERAL_PARAMS {
+ CK_ULONG ulWordsize; /* wordsize in bits */
+ CK_ULONG ulRounds; /* number of rounds */
+ CK_ULONG ulMacLength; /* Length of MAC in bytes */
+} CK_RC5_MAC_GENERAL_PARAMS;
+
+typedef CK_RC5_MAC_GENERAL_PARAMS CK_PTR \
+ CK_RC5_MAC_GENERAL_PARAMS_PTR;
+
+
+/* CK_MAC_GENERAL_PARAMS provides the parameters to most block
+ * ciphers' MAC_GENERAL mechanisms. Its value is the length of
+ * the MAC */
+/* CK_MAC_GENERAL_PARAMS is new for v2.0 */
+typedef CK_ULONG CK_MAC_GENERAL_PARAMS;
+
+typedef CK_MAC_GENERAL_PARAMS CK_PTR CK_MAC_GENERAL_PARAMS_PTR;
+
+
+/* CK_SKIPJACK_PRIVATE_WRAP_PARAMS provides the parameters to the
+ * CKM_SKIPJACK_PRIVATE_WRAP mechanism */
+/* CK_SKIPJACK_PRIVATE_WRAP_PARAMS is new for v2.0 */
+typedef struct CK_SKIPJACK_PRIVATE_WRAP_PARAMS {
+ CK_ULONG ulPasswordLen;
+ CK_BYTE_PTR pPassword;
+ CK_ULONG ulPublicDataLen;
+ CK_BYTE_PTR pPublicData;
+ CK_ULONG ulPAndGLen;
+ CK_ULONG ulQLen;
+ CK_ULONG ulRandomLen;
+ CK_BYTE_PTR pRandomA;
+ CK_BYTE_PTR pPrimeP;
+ CK_BYTE_PTR pBaseG;
+ CK_BYTE_PTR pSubprimeQ;
+} CK_SKIPJACK_PRIVATE_WRAP_PARAMS;
+
+typedef CK_SKIPJACK_PRIVATE_WRAP_PARAMS CK_PTR \
+ CK_SKIPJACK_PRIVATE_WRAP_PTR;
+
+
+/* CK_SKIPJACK_RELAYX_PARAMS provides the parameters to the
+ * CKM_SKIPJACK_RELAYX mechanism */
+/* CK_SKIPJACK_RELAYX_PARAMS is new for v2.0 */
+typedef struct CK_SKIPJACK_RELAYX_PARAMS {
+ CK_ULONG ulOldWrappedXLen;
+ CK_BYTE_PTR pOldWrappedX;
+ CK_ULONG ulOldPasswordLen;
+ CK_BYTE_PTR pOldPassword;
+ CK_ULONG ulOldPublicDataLen;
+ CK_BYTE_PTR pOldPublicData;
+ CK_ULONG ulOldRandomLen;
+ CK_BYTE_PTR pOldRandomA;
+ CK_ULONG ulNewPasswordLen;
+ CK_BYTE_PTR pNewPassword;
+ CK_ULONG ulNewPublicDataLen;
+ CK_BYTE_PTR pNewPublicData;
+ CK_ULONG ulNewRandomLen;
+ CK_BYTE_PTR pNewRandomA;
+} CK_SKIPJACK_RELAYX_PARAMS;
+
+typedef CK_SKIPJACK_RELAYX_PARAMS CK_PTR \
+ CK_SKIPJACK_RELAYX_PARAMS_PTR;
+
+
+typedef struct CK_PBE_PARAMS {
+ CK_BYTE_PTR pInitVector;
+ CK_UTF8CHAR_PTR pPassword;
+ CK_ULONG ulPasswordLen;
+ CK_BYTE_PTR pSalt;
+ CK_ULONG ulSaltLen;
+ CK_ULONG ulIteration;
+} CK_PBE_PARAMS;
+
+typedef CK_PBE_PARAMS CK_PTR CK_PBE_PARAMS_PTR;
+
+
+/* CK_KEY_WRAP_SET_OAEP_PARAMS provides the parameters to the
+ * CKM_KEY_WRAP_SET_OAEP mechanism */
+/* CK_KEY_WRAP_SET_OAEP_PARAMS is new for v2.0 */
+typedef struct CK_KEY_WRAP_SET_OAEP_PARAMS {
+ CK_BYTE bBC; /* block contents byte */
+ CK_BYTE_PTR pX; /* extra data */
+ CK_ULONG ulXLen; /* length of extra data in bytes */
+} CK_KEY_WRAP_SET_OAEP_PARAMS;
+
+typedef CK_KEY_WRAP_SET_OAEP_PARAMS CK_PTR \
+ CK_KEY_WRAP_SET_OAEP_PARAMS_PTR;
+
+
+typedef struct CK_SSL3_RANDOM_DATA {
+ CK_BYTE_PTR pClientRandom;
+ CK_ULONG ulClientRandomLen;
+ CK_BYTE_PTR pServerRandom;
+ CK_ULONG ulServerRandomLen;
+} CK_SSL3_RANDOM_DATA;
+
+
+typedef struct CK_SSL3_MASTER_KEY_DERIVE_PARAMS {
+ CK_SSL3_RANDOM_DATA RandomInfo;
+ CK_VERSION_PTR pVersion;
+} CK_SSL3_MASTER_KEY_DERIVE_PARAMS;
+
+typedef struct CK_SSL3_MASTER_KEY_DERIVE_PARAMS CK_PTR \
+ CK_SSL3_MASTER_KEY_DERIVE_PARAMS_PTR;
+
+
+typedef struct CK_SSL3_KEY_MAT_OUT {
+ CK_OBJECT_HANDLE hClientMacSecret;
+ CK_OBJECT_HANDLE hServerMacSecret;
+ CK_OBJECT_HANDLE hClientKey;
+ CK_OBJECT_HANDLE hServerKey;
+ CK_BYTE_PTR pIVClient;
+ CK_BYTE_PTR pIVServer;
+} CK_SSL3_KEY_MAT_OUT;
+
+typedef CK_SSL3_KEY_MAT_OUT CK_PTR CK_SSL3_KEY_MAT_OUT_PTR;
+
+
+typedef struct CK_SSL3_KEY_MAT_PARAMS {
+ CK_ULONG ulMacSizeInBits;
+ CK_ULONG ulKeySizeInBits;
+ CK_ULONG ulIVSizeInBits;
+ CK_BBOOL bIsExport;
+ CK_SSL3_RANDOM_DATA RandomInfo;
+ CK_SSL3_KEY_MAT_OUT_PTR pReturnedKeyMaterial;
+} CK_SSL3_KEY_MAT_PARAMS;
+
+typedef CK_SSL3_KEY_MAT_PARAMS CK_PTR CK_SSL3_KEY_MAT_PARAMS_PTR;
+
+
+typedef struct CK_KEY_DERIVATION_STRING_DATA {
+ CK_BYTE_PTR pData;
+ CK_ULONG ulLen;
+} CK_KEY_DERIVATION_STRING_DATA;
+
+typedef CK_KEY_DERIVATION_STRING_DATA CK_PTR \
+ CK_KEY_DERIVATION_STRING_DATA_PTR;
+
+
+/* The CK_EXTRACT_PARAMS is used for the
+ * CKM_EXTRACT_KEY_FROM_KEY mechanism. It specifies which bit
+ * of the base key should be used as the first bit of the
+ * derived key */
+/* CK_EXTRACT_PARAMS is new for v2.0 */
+typedef CK_ULONG CK_EXTRACT_PARAMS;
+
+typedef CK_EXTRACT_PARAMS CK_PTR CK_EXTRACT_PARAMS_PTR;
+
+/* CK_PKCS5_PBKD2_PSEUDO_RANDOM_FUNCTION_TYPE is new for v2.10.
+ * CK_PKCS5_PBKD2_PSEUDO_RANDOM_FUNCTION_TYPE is used to
+ * indicate the Pseudo-Random Function (PRF) used to generate
+ * key bits using PKCS #5 PBKDF2. */
+typedef CK_ULONG CK_PKCS5_PBKD2_PSEUDO_RANDOM_FUNCTION_TYPE;
+
+typedef CK_PKCS5_PBKD2_PSEUDO_RANDOM_FUNCTION_TYPE CK_PTR CK_PKCS5_PBKD2_PSEUDO_RANDOM_FUNCTION_TYPE_PTR;
+
+/* The following PRFs are defined in PKCS #5 v2.0. */
+#define CKP_PKCS5_PBKD2_HMAC_SHA1 0x00000001
+
+
+/* CK_PKCS5_PBKDF2_SALT_SOURCE_TYPE is new for v2.10.
+ * CK_PKCS5_PBKDF2_SALT_SOURCE_TYPE is used to indicate the
+ * source of the salt value when deriving a key using PKCS #5
+ * PBKDF2. */
+typedef CK_ULONG CK_PKCS5_PBKDF2_SALT_SOURCE_TYPE;
+
+typedef CK_PKCS5_PBKDF2_SALT_SOURCE_TYPE CK_PTR CK_PKCS5_PBKDF2_SALT_SOURCE_TYPE_PTR;
+
+/* The following salt value sources are defined in PKCS #5 v2.0. */
+#define CKZ_SALT_SPECIFIED 0x00000001
+
+/* CK_PKCS5_PBKD2_PARAMS is new for v2.10.
+ * CK_PKCS5_PBKD2_PARAMS is a structure that provides the
+ * parameters to the CKM_PKCS5_PBKD2 mechanism. */
+typedef struct CK_PKCS5_PBKD2_PARAMS {
+ CK_PKCS5_PBKDF2_SALT_SOURCE_TYPE saltSource;
+ CK_VOID_PTR pSaltSourceData;
+ CK_ULONG ulSaltSourceDataLen;
+ CK_ULONG iterations;
+ CK_PKCS5_PBKD2_PSEUDO_RANDOM_FUNCTION_TYPE prf;
+ CK_VOID_PTR pPrfData;
+ CK_ULONG ulPrfDataLen;
+ CK_UTF8CHAR_PTR pPassword;
+ CK_ULONG_PTR ulPasswordLen;
+} CK_PKCS5_PBKD2_PARAMS;
+
+typedef CK_PKCS5_PBKD2_PARAMS CK_PTR CK_PKCS5_PBKD2_PARAMS_PTR;
+
+#endif
diff --git a/libdigidoc/pkcs11/unix.h b/libdigidoc/pkcs11/unix.h
new file mode 100644
index 0000000..2e7eb66
--- /dev/null
+++ b/libdigidoc/pkcs11/unix.h
@@ -0,0 +1,24 @@
+
+
+#ifndef UNIX_H
+#define UNIX_H
+
+#define CK_PTR *
+
+#define CK_DEFINE_FUNCTION(returnType, name) \
+ returnType name
+
+#define CK_DECLARE_FUNCTION(returnType, name) \
+ returnType name
+
+#define CK_DECLARE_FUNCTION_POINTER(returnType, name) \
+ returnType (* name)
+
+#define CK_CALLBACK_FUNCTION(returnType, name) \
+ returnType (* name)
+
+#ifndef NULL_PTR
+#define NULL_PTR 0
+#endif
+
+#endif
diff --git a/libdigidoc/rc.rct b/libdigidoc/rc.rct
new file mode 100644
index 0000000..2f4d2e1
--- /dev/null
+++ b/libdigidoc/rc.rct
Binary files differ
diff --git a/libdigidoc/res.rc b/libdigidoc/res.rc
new file mode 100644
index 0000000..8b24240
--- /dev/null
+++ b/libdigidoc/res.rc
@@ -0,0 +1,94 @@
+//Microsoft Developer Studio generated resource script.
+//
+#include "resource.h"
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+#include "afxres.h"
+
+/////////////////////////////////////////////////////////////////////////////
+#undef APSTUDIO_READONLY_SYMBOLS
+
+/////////////////////////////////////////////////////////////////////////////
+// English (U.K.) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENG)
+#ifdef _WIN32
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_UK
+#pragma code_page(1252)
+#endif //_WIN32
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Dialog
+//
+
+IDD_DLG_UNIT34 DIALOGEX 0, 0, 300, 155
+STYLE DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "DigiDoc"
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ DEFPUSHBUTTON "&OK",IDOK,240,136,50,14
+ GROUPBOX "Select certificate:",IDC_GROUPBOX,2,2,296,126
+ PUSHBUTTON "&Cancel",IDCANCEL,180,136,50,14
+ CONTROL "List1",IDC_LISTVIEW,"SysListView32",LVS_REPORT |
+ LVS_SINGLESEL | LVS_SHOWSELALWAYS | LVS_AUTOARRANGE |
+ WS_BORDER | WS_TABSTOP,6,12,288,110,WS_EX_CLIENTEDGE
+END
+
+#endif // English (U.K.) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+/////////////////////////////////////////////////////////////////////////////
+// Unknown language: 0x25, 0x1 resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ETI)
+#ifdef _WIN32
+LANGUAGE 0x25, 0x1
+#pragma code_page(1257)
+#endif //_WIN32
+
+#ifdef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// TEXTINCLUDE
+//
+
+1 TEXTINCLUDE DISCARDABLE
+BEGIN
+ "resource.h\0"
+END
+
+2 TEXTINCLUDE DISCARDABLE
+BEGIN
+ "#include ""afxres.h""\r\n"
+ "\0"
+END
+
+3 TEXTINCLUDE DISCARDABLE
+BEGIN
+ "\r\n"
+ "\0"
+END
+
+#endif // APSTUDIO_INVOKED
+
+#endif // Unknown language: 0x25, 0x1 resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+
+
+/////////////////////////////////////////////////////////////////////////////
+#endif // not APSTUDIO_INVOKED
+
diff --git a/libdigidoc/resource.h b/libdigidoc/resource.h
new file mode 100644
index 0000000..7f2b28d
--- /dev/null
+++ b/libdigidoc/resource.h
@@ -0,0 +1,16 @@
+//{{NO_DEPENDENCIES}}
+// Microsoft Developer Studio generated include file.
+// Used by DlgUnit.rc
+//
+
+// Next default values for new objects
+//
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NO_MFC 1
+#define _APS_NEXT_RESOURCE_VALUE 101
+#define _APS_NEXT_COMMAND_VALUE 40001
+#define _APS_NEXT_CONTROL_VALUE 1000
+#define _APS_NEXT_SYMED_VALUE 101
+#endif
+#endif
diff --git a/libxml2-2.9.2-patches.zip b/libxml2-2.9.2-patches.zip
new file mode 100644
index 0000000..846a936
--- /dev/null
+++ b/libxml2-2.9.2-patches.zip
Binary files differ
diff --git a/prepare_win_build_environment.ps1 b/prepare_win_build_environment.ps1
new file mode 100644
index 0000000..40e2b60
--- /dev/null
+++ b/prepare_win_build_environment.ps1
@@ -0,0 +1,99 @@
+#powershell -ExecutionPolicy ByPass -File prepare_win_build_environment.ps1 [-openssl] [-libxml2] [-zlib]
+param(
+ [string]$target = "C:\build",
+ [string]$msbuild = "C:\Program Files (x86)\MSBuild\12.0\Bin\MSBuild.exe",
+ [string]$7zip = "C:\Program Files\7-Zip\7z.exe",
+ [string]$cmake = "C:\Program Files (x86)\CMake\bin\cmake.exe",
+ [string]$vcvars = "C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\vcvarsall.bat", #$env:VCINSTALLDIR
+ [string]$opensslver = "openssl-1.0.2d",
+ [string]$libxml2ver = "libxml2-2.9.2",
+ [string]$zlibver = "zlib-1.2.8",
+ [switch]$openssl = $false,
+ [switch]$libxml2 = $false,
+ [switch]$zlib = $false
+)
+
+$libdigidoc = split-path -parent $MyInvocation.MyCommand.Definition
+if(!(Test-Path -Path $target)){
+ New-Item -ItemType directory -Path $target
+}
+Push-Location -Path $target
+
+$shell = new-object -com shell.application
+$client = new-object System.Net.WebClient
+
+function openssl() {
+ $client.DownloadFile("https://www.openssl.org/source/$opensslver.tar.gz", "$target\$opensslver.tar.gz")
+ & $7zip x "$opensslver.tar.gz"
+ & $7zip x "$opensslver.tar"
+ Push-Location -Path $opensslver
+ & $vcvars x86 "&&" perl Configure VC-WIN32 no-asm "&&" ms\do_ms "&&" nmake -f ms\ntdll.mak install INSTALLTOP=\OpenSSL-Win32 OPENSSLDIR=\OpenSSL-Win32\bin
+ Pop-Location
+ Remove-Item $opensslver -Force -Recurse
+
+ & $7zip x "$opensslver.tar"
+ Push-Location -Path $opensslver
+ & $vcvars x86_amd64 "&&" perl Configure VC-WIN64A no-asm "&&" ms\do_win64a "&&" nmake -f ms\ntdll.mak install INSTALLTOP=\OpenSSL-Win64 OPENSSLDIR=\OpenSSL-Win64\bin
+ Pop-Location
+ Remove-Item $opensslver -Force -Recurse
+ Remove-Item "$opensslver.tar"
+}
+
+function libxml2() {
+ $client.DownloadFile("http://xmlsoft.org/sources/$libxml2ver.tar.gz", "$target\$libxml2ver.tar.gz")
+ & $7zip x "$libxml2ver.tar.gz"
+ & $7zip x "$libxml2ver.tar"
+ foreach($item in $shell.NameSpace("$libdigidoc\$libxml2ver-patches.zip").items()) {
+ $shell.Namespace($target).CopyHere($item,0x14)
+ }
+
+ Push-Location -Path "$libxml2ver\win32"
+ & cscript configure.js iconv=no iso8859x=yes "prefix=$target\libxml2\x86"
+ & $vcvars x86 "&&" nmake -f Makefile.msvc install
+ Pop-Location
+ Remove-Item $libxml2ver -Force -Recurse
+ & $7zip x "$libxml2ver.tar"
+ foreach($item in $shell.NameSpace("$libdigidoc\$libxml2ver-patches.zip").items()) {
+ $shell.Namespace($target).CopyHere($item,0x14)
+ }
+
+ Push-Location -Path "$libxml2ver\win32"
+ & cscript configure.js iconv=no iso8859x=yes "prefix=$target\libxml2\x64"
+ & $vcvars x86_amd64 "&&" nmake -f Makefile.msvc install
+ Pop-Location
+ Remove-Item $libxml2ver -Force -Recurse
+ Remove-Item "$libxml2ver.tar" -Force -Recurse
+}
+
+function zlib() {
+ $client.DownloadFile("http://zlib.net/$zlibver.tar.gz", "$target\$zlibver.tar.gz")
+ & $7zip x "$zlibver.tar.gz"
+ & $7zip x "$zlibver.tar"
+ Push-Location -Path $zlibver
+ & $vcvars x86 "&&" $cmake -DBUILD_SHARED_LIBS=YES -DCMAKE_BUILD_TYPE=Release "-DCMAKE_INSTALL_PREFIX=$target\zlib\x86" "-GNMake Makefiles" . "&&" nmake install
+ Pop-Location
+ Remove-Item $zlibver -Force -Recurse
+
+ & $7zip x "$zlibver.tar"
+ Push-Location -Path $zlibver
+ & $vcvars x86_amd64 "&&" $cmake -DBUILD_SHARED_LIBS=YES -DCMAKE_BUILD_TYPE=Release "-DCMAKE_INSTALL_PREFIX=$target\zlib\x64" "-GNMake Makefiles" . "&&" nmake install
+ Pop-Location
+ Remove-Item $zlibver -Force -Recurse
+ Remove-Item "$zlibver.tar"
+}
+
+if($openssl) {
+ openssl
+}
+if($libxml2) {
+ libxml2
+}
+if($zlib) {
+ zlib
+}
+if(!$openssl -and !$libxml2 -and !$zlib) {
+ openssl
+ libxml2
+ zlib
+}
+Pop-Location
diff --git a/vc2008/cdigidoc.vcproj b/vc2008/cdigidoc.vcproj
new file mode 100644
index 0000000..d1dffa1
--- /dev/null
+++ b/vc2008/cdigidoc.vcproj
@@ -0,0 +1,207 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="9,00"
+ Name="cdigidoc"
+ ProjectGUID="{53105BC1-6319-4A63-B412-99F3CC31640F}"
+ RootNamespace="cdigidoc"
+ Keyword="Win32Proj"
+ TargetFrameworkVersion="196613"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="1"
+ CharacterSet="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="&quot;C:\Program Files (x86)\Microsoft SDKs\Windows\v5.0\Include&quot;;&quot;$(ProjectDir)\..&quot;;c:\install;c:\install\zlib\include;c:\install\openssl_shared\include;c:\hudson\workspace\libdigidoc\label\Windows_trunk\idkaat\current\libdigidoc"
+ PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"
+ MinimalRebuild="true"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ UsePrecompiledHeader="0"
+ WarningLevel="1"
+ DebugInformationFormat="4"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ AdditionalIncludeDirectories="$(ProjectDir)\.."
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ UseLibraryDependencyInputs="true"
+ AdditionalDependencies="comctl32.lib odbc32.lib odbccp32.lib libxml2.lib crypt32.lib Shlwapi.lib libeay32.lib ssleay32.lib zlib.lib wsock32.lib digidoc.lib"
+ LinkIncremental="2"
+ AdditionalLibraryDirectories="&quot;C:\Program Files (x86)\Microsoft SDKs\Windows\v5.0\Lib&quot;;C:\install\libxml2;C:\install\openssl_shared\lib;C:\install\zlib\lib;&quot;$(ProjectDir)\Debug&quot;"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="1"
+ CharacterSet="1"
+ WholeProgramOptimization="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ EnableIntrinsicFunctions="true"
+ AdditionalIncludeDirectories="&quot;C:\Program Files (x86)\Microsoft SDKs\Windows\v5.0\Include&quot;;c:\install;c:\install\zlib\include;c:\install\openssl_shared\include;&quot;$(ProjectDir)\..&quot;"
+ PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
+ RuntimeLibrary="2"
+ EnableFunctionLevelLinking="true"
+ UsePrecompiledHeader="0"
+ WarningLevel="1"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ AdditionalIncludeDirectories="$(ProjectDir)\.."
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ UseLibraryDependencyInputs="true"
+ AdditionalDependencies="comctl32.lib odbc32.lib odbccp32.lib libxml2.lib crypt32.lib Shlwapi.lib libeay32.lib ssleay32.lib zlib.lib wsock32.lib digidoc.lib"
+ LinkIncremental="1"
+ AdditionalLibraryDirectories="&quot;C:\Program Files (x86)\Microsoft SDKs\Windows\v5.0\Lib&quot;;C:\install\libxml2;C:\install\openssl_shared\lib;C:\install\zlib\lib;&quot;$(ProjectDir)\Release&quot;"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+ UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+ >
+ <File
+ RelativePath="..\libdigidoc\cdigidoc.c"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hm;inl;inc;xsd"
+ UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+ >
+ </Filter>
+ <Filter
+ Name="Resource Files"
+ Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"
+ UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
+ >
+ <File
+ RelativePath="..\libdigidoc\cdigidoc.rc"
+ >
+ </File>
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/vc2008/libdigidoc.ncb b/vc2008/libdigidoc.ncb
new file mode 100644
index 0000000..f2ee18c
--- /dev/null
+++ b/vc2008/libdigidoc.ncb
Binary files differ
diff --git a/vc2008/libdigidoc.sln b/vc2008/libdigidoc.sln
new file mode 100644
index 0000000..d236541
--- /dev/null
+++ b/vc2008/libdigidoc.sln
@@ -0,0 +1,37 @@
+
+Microsoft Visual Studio Solution File, Format Version 9.00
+# Visual Studio 2008
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libdigidoc", "libdigidoc.vcproj", "{6DB238DD-6FC1-41AD-9317-1795EB40B32A}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "cdigidoc", "cdigidoc.vcproj", "{53105BC1-6319-4A63-B412-99F3CC31640F}"
+ ProjectSection(ProjectDependencies) = postProject
+ {6DB238DD-6FC1-41AD-9317-1795EB40B32A} = {6DB238DD-6FC1-41AD-9317-1795EB40B32A}
+ EndProjectSection
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Win32 = Debug|Win32
+ Release|Win32 = Release|Win32
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {6DB238DD-6FC1-41AD-9317-1795EB40B32A}.Debug|Win32.ActiveCfg = Debug|Win32
+ {6DB238DD-6FC1-41AD-9317-1795EB40B32A}.Debug|Win32.Build.0 = Debug|Win32
+ {6DB238DD-6FC1-41AD-9317-1795EB40B32A}.Release|Win32.ActiveCfg = Release|Win32
+ {6DB238DD-6FC1-41AD-9317-1795EB40B32A}.Release|Win32.Build.0 = Release|Win32
+ {39E94F79-A838-468B-B53A-EED12E16828D}.Debug|Win32.ActiveCfg = Debug|Win32
+ {39E94F79-A838-468B-B53A-EED12E16828D}.Debug|Win32.Build.0 = Debug|Win32
+ {39E94F79-A838-468B-B53A-EED12E16828D}.Release|Win32.ActiveCfg = Release|Win32
+ {39E94F79-A838-468B-B53A-EED12E16828D}.Release|Win32.Build.0 = Release|Win32
+ {7755CEE2-DDE2-417D-9AF9-8422C79F1C30}.Debug|Win32.ActiveCfg = Debug|Win32
+ {7755CEE2-DDE2-417D-9AF9-8422C79F1C30}.Debug|Win32.Build.0 = Debug|Win32
+ {7755CEE2-DDE2-417D-9AF9-8422C79F1C30}.Release|Win32.ActiveCfg = Release|Win32
+ {7755CEE2-DDE2-417D-9AF9-8422C79F1C30}.Release|Win32.Build.0 = Release|Win32
+ {53105BC1-6319-4A63-B412-99F3CC31640F}.Debug|Win32.ActiveCfg = Debug|Win32
+ {53105BC1-6319-4A63-B412-99F3CC31640F}.Debug|Win32.Build.0 = Debug|Win32
+ {53105BC1-6319-4A63-B412-99F3CC31640F}.Release|Win32.ActiveCfg = Release|Win32
+ {53105BC1-6319-4A63-B412-99F3CC31640F}.Release|Win32.Build.0 = Release|Win32
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal
diff --git a/vc2008/libdigidoc.suo b/vc2008/libdigidoc.suo
new file mode 100644
index 0000000..c32d2e2
--- /dev/null
+++ b/vc2008/libdigidoc.suo
Binary files differ
diff --git a/vc2008/libdigidoc.vcproj b/vc2008/libdigidoc.vcproj
new file mode 100644
index 0000000..f80d7d5
--- /dev/null
+++ b/vc2008/libdigidoc.vcproj
@@ -0,0 +1,406 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="9.00"
+ Name="libdigidoc"
+ ProjectGUID="{6DB238DD-6FC1-41AD-9317-1795EB40B32A}"
+ Keyword="Win32Proj"
+ TargetFrameworkVersion="0"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="Debug"
+ IntermediateDirectory="Debug"
+ ConfigurationType="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="&quot;C:\Program Files (x86)\Microsoft SDKs\Windows\v5.0\Include&quot;;&quot;$(ProjectDir)\..&quot;;c:\install;c:\install\zlib\include;c:\install\openssl_shared\include;c:\hudson\workspace\libdigidoc\label\Windows_trunk\idkaat\current\libdigidoc"
+ PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;LIBDIGIDOC_EXPORTS;digidoc_EXPORTS,WIN32"
+ MinimalRebuild="true"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ UsePrecompiledHeader="0"
+ WarningLevel="1"
+ Detect64BitPortabilityProblems="false"
+ DebugInformationFormat="4"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ AdditionalIncludeDirectories="$(ProjectDir)\.."
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="comctl32.lib odbc32.lib odbccp32.lib libxml2.lib crypt32.lib Shlwapi.lib libeay32.lib ssleay32.lib zlib.lib wsock32.lib"
+ OutputFile="$(OutDir)\digidoc.dll"
+ LinkIncremental="2"
+ AdditionalLibraryDirectories="&quot;C:\Program Files (x86)\Microsoft SDKs\Windows\v5.0\Lib&quot;;C:\install\libxml2;C:\install\openssl_shared\lib;C:\install\zlib\lib;&quot;$(ProjectDir)\..&quot;"
+ GenerateDebugInformation="true"
+ SubSystem="2"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="Release"
+ IntermediateDirectory="Release"
+ ConfigurationType="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="&quot;C:\Program Files (x86)\Microsoft SDKs\Windows\v5.0\Include&quot;;c:\install;c:\install\zlib\include;c:\install\openssl_shared\include;&quot;$(ProjectDir)\..&quot;;$(NOINHERIT)"
+ PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;LIBDIGIDOC_EXPORTS;digidoc_EXPORTS"
+ RuntimeLibrary="2"
+ UsePrecompiledHeader="0"
+ WarningLevel="1"
+ Detect64BitPortabilityProblems="false"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ AdditionalIncludeDirectories="$(ProjectDir)\.."
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="comctl32.lib odbc32.lib odbccp32.lib libxml2.lib crypt32.lib Shlwapi.lib libeay32.lib ssleay32.lib zlib.lib wsock32.lib"
+ OutputFile="$(OutDir)\digidoc.dll"
+ LinkIncremental="2"
+ AdditionalLibraryDirectories="&quot;C:\Program Files (x86)\Microsoft SDKs\Windows\v5.0\Lib&quot;;C:\install\libxml2;C:\install\openssl_shared\lib;C:\install\zlib\lib;&quot;$(ProjectDir)\..&quot;"
+ GenerateDebugInformation="true"
+ SubSystem="2"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hm;inl;inc;xsd"
+ UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+ >
+ <File
+ RelativePath="..\libdigidoc\DigiCrypt.h"
+ >
+ </File>
+ <File
+ RelativePath="..\libdigidoc\DigiDocCert.h"
+ >
+ </File>
+ <File
+ RelativePath="..\libdigidoc\DigiDocConfig.h"
+ >
+ </File>
+ <File
+ RelativePath="..\libdigidoc\DigiDocConvert.h"
+ >
+ </File>
+ <File
+ RelativePath="..\libdigidoc\DigiDocCsp.h"
+ >
+ </File>
+ <File
+ RelativePath="..\libdigidoc\DigiDocDebug.h"
+ >
+ </File>
+ <File
+ RelativePath="..\libdigidoc\DigiDocDefs.h"
+ >
+ </File>
+ <File
+ RelativePath="..\libdigidoc\DigiDocDfExtract.h"
+ >
+ </File>
+ <File
+ RelativePath="..\libdigidoc\DigiDocEnc.h"
+ >
+ </File>
+ <File
+ RelativePath="..\libdigidoc\DigiDocEncGen.h"
+ >
+ </File>
+ <File
+ RelativePath="..\libdigidoc\DigiDocEncSAXParser.h"
+ >
+ </File>
+ <File
+ RelativePath="..\libdigidoc\DigiDocError.h"
+ >
+ </File>
+ <File
+ RelativePath="..\libdigidoc\DigiDocGen.h"
+ >
+ </File>
+ <File
+ RelativePath="..\libdigidoc\DigiDocGlobals.h"
+ >
+ </File>
+ <File
+ RelativePath="..\libdigidoc\DigiDocHTTP.h"
+ >
+ </File>
+ <File
+ RelativePath="..\libdigidoc\DigiDocLib.h"
+ >
+ </File>
+ <File
+ RelativePath="..\libdigidoc\DigiDocMem.h"
+ >
+ </File>
+ <File
+ RelativePath="..\libdigidoc\DigiDocObj.h"
+ >
+ </File>
+ <File
+ RelativePath="..\libdigidoc\DigiDocOCSP.h"
+ >
+ </File>
+ <File
+ RelativePath="..\libdigidoc\DigiDocPKCS11.h"
+ >
+ </File>
+ <File
+ RelativePath="..\libdigidoc\DigiDocSAXParser.h"
+ >
+ </File>
+ <File
+ RelativePath="..\libdigidoc\DigiDocService.h"
+ >
+ </File>
+ <File
+ RelativePath="..\libdigidoc\DigiDocStack.h"
+ >
+ </File>
+ <File
+ RelativePath="..\libdigidoc\DigiDocVerify.h"
+ >
+ </File>
+ <File
+ RelativePath="..\libdigidoc\DlgUnit.h"
+ >
+ </File>
+ <File
+ RelativePath="..\libdigidoc\resource.h"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Resource Files"
+ Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx"
+ UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
+ >
+ <File
+ RelativePath="..\libdigidoc\DlgUnit.rc"
+ >
+ </File>
+ <File
+ RelativePath="..\libdigidoc\libdigidoc.rc"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+ UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+ >
+ <File
+ RelativePath="..\libdigidoc\DigiCrypt.c"
+ >
+ </File>
+ <File
+ RelativePath="..\libdigidoc\DigiDocCert.c"
+ >
+ </File>
+ <File
+ RelativePath="..\libdigidoc\DigiDocConfig.c"
+ >
+ </File>
+ <File
+ RelativePath="..\libdigidoc\DigiDocConvert.c"
+ >
+ </File>
+ <File
+ RelativePath="..\libdigidoc\DigiDocCsp.c"
+ >
+ </File>
+ <File
+ RelativePath="..\libdigidoc\DigiDocDebug.c"
+ >
+ </File>
+ <File
+ RelativePath="..\libdigidoc\DigiDocDfExtract.c"
+ >
+ </File>
+ <File
+ RelativePath="..\libdigidoc\DigiDocEnc.c"
+ >
+ </File>
+ <File
+ RelativePath="..\libdigidoc\DigiDocEncGen.c"
+ >
+ </File>
+ <File
+ RelativePath="..\libdigidoc\DigiDocEncSAXParser.c"
+ >
+ </File>
+ <File
+ RelativePath="..\libdigidoc\DigiDocError.c"
+ >
+ </File>
+ <File
+ RelativePath="..\libdigidoc\DigiDocGen.c"
+ >
+ </File>
+ <File
+ RelativePath="..\libdigidoc\DigiDocGlobals.c"
+ >
+ </File>
+ <File
+ RelativePath="..\libdigidoc\DigiDocHTTP.c"
+ >
+ </File>
+ <File
+ RelativePath="..\libdigidoc\DigiDocLib.c"
+ >
+ </File>
+ <File
+ RelativePath="..\libdigidoc\DigiDocMem.c"
+ >
+ </File>
+ <File
+ RelativePath="..\libdigidoc\DigiDocObj.c"
+ >
+ </File>
+ <File
+ RelativePath="..\libdigidoc\DigiDocOCSP.c"
+ >
+ </File>
+ <File
+ RelativePath="..\libdigidoc\DigiDocPKCS11.c"
+ >
+ </File>
+ <File
+ RelativePath="..\libdigidoc\DigiDocSAXParser.c"
+ >
+ </File>
+ <File
+ RelativePath="..\libdigidoc\DigiDocService.c"
+ >
+ </File>
+ <File
+ RelativePath="..\libdigidoc\DigiDocStack.c"
+ >
+ </File>
+ <File
+ RelativePath="..\libdigidoc\DigiDocVerify.c"
+ >
+ </File>
+ <File
+ RelativePath="..\libdigidoc\DlgUnit.c"
+ >
+ </File>
+ <File
+ RelativePath="..\libdigidoc\DlgUnitS.c"
+ >
+ </File>
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/vc2008/libdigidoc_vs.sln b/vc2008/libdigidoc_vs.sln
new file mode 100644
index 0000000..d236541
--- /dev/null
+++ b/vc2008/libdigidoc_vs.sln
@@ -0,0 +1,37 @@
+
+Microsoft Visual Studio Solution File, Format Version 9.00
+# Visual Studio 2008
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libdigidoc", "libdigidoc.vcproj", "{6DB238DD-6FC1-41AD-9317-1795EB40B32A}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "cdigidoc", "cdigidoc.vcproj", "{53105BC1-6319-4A63-B412-99F3CC31640F}"
+ ProjectSection(ProjectDependencies) = postProject
+ {6DB238DD-6FC1-41AD-9317-1795EB40B32A} = {6DB238DD-6FC1-41AD-9317-1795EB40B32A}
+ EndProjectSection
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Win32 = Debug|Win32
+ Release|Win32 = Release|Win32
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {6DB238DD-6FC1-41AD-9317-1795EB40B32A}.Debug|Win32.ActiveCfg = Debug|Win32
+ {6DB238DD-6FC1-41AD-9317-1795EB40B32A}.Debug|Win32.Build.0 = Debug|Win32
+ {6DB238DD-6FC1-41AD-9317-1795EB40B32A}.Release|Win32.ActiveCfg = Release|Win32
+ {6DB238DD-6FC1-41AD-9317-1795EB40B32A}.Release|Win32.Build.0 = Release|Win32
+ {39E94F79-A838-468B-B53A-EED12E16828D}.Debug|Win32.ActiveCfg = Debug|Win32
+ {39E94F79-A838-468B-B53A-EED12E16828D}.Debug|Win32.Build.0 = Debug|Win32
+ {39E94F79-A838-468B-B53A-EED12E16828D}.Release|Win32.ActiveCfg = Release|Win32
+ {39E94F79-A838-468B-B53A-EED12E16828D}.Release|Win32.Build.0 = Release|Win32
+ {7755CEE2-DDE2-417D-9AF9-8422C79F1C30}.Debug|Win32.ActiveCfg = Debug|Win32
+ {7755CEE2-DDE2-417D-9AF9-8422C79F1C30}.Debug|Win32.Build.0 = Debug|Win32
+ {7755CEE2-DDE2-417D-9AF9-8422C79F1C30}.Release|Win32.ActiveCfg = Release|Win32
+ {7755CEE2-DDE2-417D-9AF9-8422C79F1C30}.Release|Win32.Build.0 = Release|Win32
+ {53105BC1-6319-4A63-B412-99F3CC31640F}.Debug|Win32.ActiveCfg = Debug|Win32
+ {53105BC1-6319-4A63-B412-99F3CC31640F}.Debug|Win32.Build.0 = Debug|Win32
+ {53105BC1-6319-4A63-B412-99F3CC31640F}.Release|Win32.ActiveCfg = Release|Win32
+ {53105BC1-6319-4A63-B412-99F3CC31640F}.Release|Win32.Build.0 = Release|Win32
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal
diff --git a/vc2010/DigiDocLib.vcxproj b/vc2010/DigiDocLib.vcxproj
new file mode 100644
index 0000000..05b7274
--- /dev/null
+++ b/vc2010/DigiDocLib.vcxproj
@@ -0,0 +1,206 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup Label="ProjectConfigurations">
+ <ProjectConfiguration Include="Debug|Win32">
+ <Configuration>Debug</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|Win32">
+ <Configuration>Release</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="libdigidoc\DigiCrypt.c" />
+ <ClCompile Include="libdigidoc\DigiDocCert.c" />
+ <ClCompile Include="libdigidoc\DigiDocConfig.c" />
+ <ClCompile Include="libdigidoc\DigiDocConvert.c" />
+ <ClCompile Include="libdigidoc\DigiDocCsp.c" />
+ <ClCompile Include="libdigidoc\DigiDocDebug.c" />
+ <ClCompile Include="libdigidoc\DigiDocDfExtract.c" />
+ <ClCompile Include="libdigidoc\DigiDocEnc.c" />
+ <ClCompile Include="libdigidoc\DigiDocEncGen.c" />
+ <ClCompile Include="libdigidoc\DigiDocEncSAXParser.c" />
+ <ClCompile Include="libdigidoc\DigiDocError.c" />
+ <ClCompile Include="libdigidoc\DigiDocGen.c" />
+ <ClCompile Include="libdigidoc\DigiDocGlobals.c" />
+ <ClCompile Include="libdigidoc\DigiDocHTTP.c" />
+ <ClCompile Include="libdigidoc\DigiDocLib.c" />
+ <ClCompile Include="libdigidoc\DigiDocMem.c" />
+ <ClCompile Include="libdigidoc\DigiDocObj.c" />
+ <ClCompile Include="libdigidoc\DigiDocOCSP.c" />
+ <ClCompile Include="libdigidoc\DigiDocParser.c" />
+ <ClCompile Include="libdigidoc\DigiDocPKCS11.c" />
+ <ClCompile Include="libdigidoc\DigiDocSAXParser.c" />
+ <ClCompile Include="libdigidoc\DigiDocService.c" />
+ <ClCompile Include="libdigidoc\DigiDocStack.c" />
+ <ClCompile Include="libdigidoc\DigiDocVerify.c" />
+ <ClCompile Include="libdigidoc\DlgUnit.c" />
+ <ClCompile Include="libdigidoc\DlgUnitS.c" />
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="libdigidoc\DigiCrypt.h" />
+ <ClInclude Include="libdigidoc\DigiDocCert.h" />
+ <ClInclude Include="libdigidoc\DigiDocConfig.h" />
+ <ClInclude Include="libdigidoc\DigiDocConvert.h" />
+ <ClInclude Include="libdigidoc\DigiDocCsp.h" />
+ <ClInclude Include="libdigidoc\DigiDocDebug.h" />
+ <ClInclude Include="libdigidoc\DigiDocDefs.h" />
+ <ClInclude Include="libdigidoc\DigiDocDfExtract.h" />
+ <ClInclude Include="libdigidoc\DigiDocEnc.h" />
+ <ClInclude Include="libdigidoc\DigiDocEncGen.h" />
+ <ClInclude Include="libdigidoc\DigiDocEncSAXParser.h" />
+ <ClInclude Include="libdigidoc\DigiDocError.h" />
+ <ClInclude Include="libdigidoc\DigiDocGen.h" />
+ <ClInclude Include="libdigidoc\DigiDocGlobals.h" />
+ <ClInclude Include="libdigidoc\DigiDocHTTP.h" />
+ <ClInclude Include="libdigidoc\DigiDocLib.h" />
+ <ClInclude Include="libdigidoc\DigiDocMem.h" />
+ <ClInclude Include="libdigidoc\DigiDocObj.h" />
+ <ClInclude Include="libdigidoc\DigiDocOCSP.h" />
+ <ClInclude Include="libdigidoc\DigiDocParser.h" />
+ <ClInclude Include="libdigidoc\DigiDocPKCS11.h" />
+ <ClInclude Include="libdigidoc\DigiDocSAXParser.h" />
+ <ClInclude Include="libdigidoc\DigiDocService.h" />
+ <ClInclude Include="libdigidoc\DigiDocStack.h" />
+ <ClInclude Include="libdigidoc\DigiDocVerify.h" />
+ <ClInclude Include="libdigidoc\DlgUnit.h" />
+ <ClInclude Include="libdigidoc\resource.h" />
+ </ItemGroup>
+ <ItemGroup>
+ <ResourceCompile Include="libdigidoc\DlgUnit.rc" />
+ <ResourceCompile Include="libdigidoc\libdigidoc.rc" />
+ </ItemGroup>
+ <PropertyGroup Label="Globals">
+ <SccProjectName />
+ <SccLocalPath />
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ <UseOfMfc>false</UseOfMfc>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ <UseOfMfc>false</UseOfMfc>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <ImportGroup Label="ExtensionSettings">
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ <Import Project="$(VCTargetsPath)Microsoft.Cpp.UpgradeFromVC60.props" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ <Import Project="$(VCTargetsPath)Microsoft.Cpp.UpgradeFromVC60.props" />
+ </ImportGroup>
+ <PropertyGroup Label="UserMacros" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <OutDir>.\Debug\</OutDir>
+ <IntDir>.\Debug\</IntDir>
+ <LinkIncremental>true</LinkIncremental>
+ <TargetName>digidoc</TargetName>
+ <IncludePath>C:\install;C:\install\zlib\include;C:\install\openssl_shared\include;Z:\projects\libdigidoc\trunk;$(IncludePath)</IncludePath>
+ <LibraryPath>C:\install\libxml2;C:\install\openssl_shared\lib;C:\install\zlib\lib;$(LibraryPath)</LibraryPath>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <OutDir>.\Release\</OutDir>
+ <IntDir>.\Release\</IntDir>
+ <LinkIncremental>false</LinkIncremental>
+ <IncludePath>Z:\projects\libdigidoc\trunk;C:\install;C:\install\openssl_shared\include;C:\install\zlib\include;$(IncludePath)</IncludePath>
+ <LibraryPath>C:\install\libxml2;C:\install\openssl_shared\lib;C:\install\zlib\lib;$(LibraryPath)</LibraryPath>
+ </PropertyGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <ClCompile>
+ <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
+ <InlineFunctionExpansion>Default</InlineFunctionExpansion>
+ <FunctionLevelLinking>false</FunctionLevelLinking>
+ <Optimization>Disabled</Optimization>
+ <SuppressStartupBanner>true</SuppressStartupBanner>
+ <WarningLevel>Level3</WarningLevel>
+ <MinimalRebuild>true</MinimalRebuild>
+ <DebugInformationFormat>EditAndContinue</DebugInformationFormat>
+ <PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;BUILDINGDLL;WITH_SOAPDEFS_H;digidoc_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <AssemblerListingLocation>.\Debug\</AssemblerListingLocation>
+ <PrecompiledHeaderOutputFile>.\Debug\DigiDocLib.pch</PrecompiledHeaderOutputFile>
+ <ObjectFileName>.\Debug\</ObjectFileName>
+ <ProgramDataBaseFileName>.\Debug\</ProgramDataBaseFileName>
+ </ClCompile>
+ <Midl>
+ <SuppressStartupBanner>true</SuppressStartupBanner>
+ <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <TypeLibraryName>.\Debug\DigiDocLib.tlb</TypeLibraryName>
+ <MkTypLibCompatible>true</MkTypLibCompatible>
+ <RedirectOutputAndErrors>NUL</RedirectOutputAndErrors>
+ <TargetEnvironment>Win32</TargetEnvironment>
+ </Midl>
+ <ResourceCompile>
+ <Culture>0x041d</Culture>
+ <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ </ResourceCompile>
+ <Bscmake>
+ <SuppressStartupBanner>true</SuppressStartupBanner>
+ <OutputFile>.\Debug\DigiDocLib.bsc</OutputFile>
+ </Bscmake>
+ <Link>
+ <SuppressStartupBanner>true</SuppressStartupBanner>
+ <LinkDLL>true</LinkDLL>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <SubSystem>Windows</SubSystem>
+ <OutputFile>bin/digidoc.dll</OutputFile>
+ <ImportLibrary>bin\digidoc.lib</ImportLibrary>
+ <AdditionalDependencies>comctl32.lib;odbc32.lib;odbccp32.lib;libxml2.lib;crypt32.lib;Shlwapi.lib;libeay32.lib;ssleay32.lib;zlib.lib;wsock32.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ <IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries>
+ <IgnoreSpecificDefaultLibraries>LIBCMTD.LIB</IgnoreSpecificDefaultLibraries>
+ <ShowProgress>NotSet</ShowProgress>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <ClCompile>
+ <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
+ <InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>
+ <StringPooling>true</StringPooling>
+ <FunctionLevelLinking>true</FunctionLevelLinking>
+ <Optimization>MaxSpeed</Optimization>
+ <SuppressStartupBanner>true</SuppressStartupBanner>
+ <WarningLevel>Level3</WarningLevel>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;BUILDINGDLL;WITH_SOAPDEFS_H;digidoc_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <AssemblerListingLocation>.\Release\</AssemblerListingLocation>
+ <PrecompiledHeaderOutputFile>.\Release\DigiDocLib.pch</PrecompiledHeaderOutputFile>
+ <ObjectFileName>.\Release\</ObjectFileName>
+ <ProgramDataBaseFileName>.\Release\</ProgramDataBaseFileName>
+ </ClCompile>
+ <Midl>
+ <SuppressStartupBanner>true</SuppressStartupBanner>
+ <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <TypeLibraryName>.\Release\DigiDocLib.tlb</TypeLibraryName>
+ <MkTypLibCompatible>true</MkTypLibCompatible>
+ <RedirectOutputAndErrors>NUL</RedirectOutputAndErrors>
+ <TargetEnvironment>Win32</TargetEnvironment>
+ </Midl>
+ <ResourceCompile>
+ <Culture>0x041d</Culture>
+ <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ </ResourceCompile>
+ <Bscmake>
+ <SuppressStartupBanner>true</SuppressStartupBanner>
+ <OutputFile>.\Release\DigiDocLib.bsc</OutputFile>
+ </Bscmake>
+ <Link>
+ <SuppressStartupBanner>true</SuppressStartupBanner>
+ <LinkDLL>true</LinkDLL>
+ <SubSystem>Windows</SubSystem>
+ <IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries>
+ <OutputFile>bin\DigiDocLib.dll</OutputFile>
+ <ImportLibrary>.\Release\DigiDocLib.lib</ImportLibrary>
+ <AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
+ <AdditionalDependencies>comctl32.lib;odbc32.lib;odbccp32.lib;libxml2.lib;crypt32.lib;Shlwapi.lib;libeay32.lib;ssleay32.lib;zlib.lib;wsock32.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ <IgnoreSpecificDefaultLibraries>LIBCMT.lib</IgnoreSpecificDefaultLibraries>
+ </Link>
+ </ItemDefinitionGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+ <ImportGroup Label="ExtensionTargets">
+ </ImportGroup>
+</Project> \ No newline at end of file
diff --git a/vc2010/digidoc.vcxproj b/vc2010/digidoc.vcxproj
new file mode 100644
index 0000000..f066856
--- /dev/null
+++ b/vc2010/digidoc.vcxproj
@@ -0,0 +1,146 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup Label="ProjectConfigurations">
+ <ProjectConfiguration Include="Debug|Win32">
+ <Configuration>Debug</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|Win32">
+ <Configuration>Release</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Template|Win32">
+ <Configuration>Template</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="libdigidoc\cdigidoc.c" />
+ </ItemGroup>
+ <ItemGroup>
+ <ProjectReference Include="DigiDocLib.vcxproj">
+ <Project>{0ab62309-a060-0bd6-a056-1f774efb4d04}</Project>
+ <ReferenceOutputAssembly>false</ReferenceOutputAssembly>
+ </ProjectReference>
+ </ItemGroup>
+ <PropertyGroup Label="Globals">
+ <SccProjectName />
+ <SccLocalPath />
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Template|Win32'" Label="Configuration">
+ <ConfigurationType>Application</ConfigurationType>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+ <ConfigurationType>Application</ConfigurationType>
+ <UseOfMfc>false</UseOfMfc>
+ <CharacterSet>MultiByte</CharacterSet>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
+ <ConfigurationType>Application</ConfigurationType>
+ <UseOfMfc>false</UseOfMfc>
+ <CharacterSet>MultiByte</CharacterSet>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <ImportGroup Label="ExtensionSettings">
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Template|Win32'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ <Import Project="$(VCTargetsPath)Microsoft.Cpp.UpgradeFromVC60.props" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ <Import Project="$(VCTargetsPath)Microsoft.Cpp.UpgradeFromVC60.props" />
+ </ImportGroup>
+ <PropertyGroup Label="UserMacros" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <OutDir>bin\</OutDir>
+ <IntDir>.\Debug\</IntDir>
+ <LinkIncremental>true</LinkIncremental>
+ <ExecutablePath>$(ExecutablePath)</ExecutablePath>
+ <IncludePath>Z:\projects\libdigidoc\trunk;C:\install;C:\install\openssl_shared\include;C:\install\zlib\include;$(IncludePath)</IncludePath>
+ <LibraryPath>C:\install\libxml2;C:\install\openssl_shared\lib;C:\install\zlib\lib;Z:\projects\libdigidoc\trunk;$(LibraryPath)</LibraryPath>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <OutDir>.\Release\</OutDir>
+ <IntDir>.\Release\</IntDir>
+ <LinkIncremental>false</LinkIncremental>
+ <IncludePath>Z:\projects\libdigidoc\trunk;C:\install;C:\install\openssl_shared\include;C:\install\zlib\include;$(IncludePath)</IncludePath>
+ <LibraryPath>Z:\projects\libdigidoc\trunk\bin;Z:\projects\libdigidoc\trunk\Release;C:\install\libxml2;C:\install\openssl_static\lib;C:\install\zlib\lib;$(LibraryPath)</LibraryPath>
+ </PropertyGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <ClCompile>
+ <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
+ <InlineFunctionExpansion>Default</InlineFunctionExpansion>
+ <FunctionLevelLinking>false</FunctionLevelLinking>
+ <Optimization>Disabled</Optimization>
+ <SuppressStartupBanner>true</SuppressStartupBanner>
+ <WarningLevel>Level3</WarningLevel>
+ <MinimalRebuild>true</MinimalRebuild>
+ <DebugInformationFormat>EditAndContinue</DebugInformationFormat>
+ <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;WITH_SOAPDEFS_H;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <AssemblerListingLocation>.\Debug\</AssemblerListingLocation>
+ <PrecompiledHeaderOutputFile>.\Debug\digidoc.pch</PrecompiledHeaderOutputFile>
+ <ObjectFileName>.\Debug\</ObjectFileName>
+ <ProgramDataBaseFileName>.\Debug\</ProgramDataBaseFileName>
+ <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
+ </ClCompile>
+ <Midl>
+ <TypeLibraryName>.\Debug\digidoc.tlb</TypeLibraryName>
+ </Midl>
+ <ResourceCompile>
+ <Culture>0x0409</Culture>
+ <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ </ResourceCompile>
+ <Bscmake>
+ <SuppressStartupBanner>true</SuppressStartupBanner>
+ <OutputFile>.\Debug\digidoc.bsc</OutputFile>
+ </Bscmake>
+ <Link>
+ <SuppressStartupBanner>true</SuppressStartupBanner>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <SubSystem>Console</SubSystem>
+ <OutputFile>bin\digidoc.exe</OutputFile>
+ <AdditionalDependencies>odbc32.lib;odbccp32.lib;libxml2.lib;libeay32.lib;ssleay32.lib;bin\DigiDoc.lib;zlib.lib;wsock32.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <ClCompile>
+ <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
+ <InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>
+ <StringPooling>true</StringPooling>
+ <FunctionLevelLinking>true</FunctionLevelLinking>
+ <Optimization>MaxSpeed</Optimization>
+ <SuppressStartupBanner>true</SuppressStartupBanner>
+ <WarningLevel>Level4</WarningLevel>
+ <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;BUILDINGDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <AssemblerListingLocation>.\Release\</AssemblerListingLocation>
+ <PrecompiledHeaderOutputFile>.\Release\digidoc.pch</PrecompiledHeaderOutputFile>
+ <ObjectFileName>.\Release\</ObjectFileName>
+ <ProgramDataBaseFileName>.\Release\</ProgramDataBaseFileName>
+ </ClCompile>
+ <Midl>
+ <TypeLibraryName>.\Release\digidoc.tlb</TypeLibraryName>
+ </Midl>
+ <ResourceCompile>
+ <Culture>0x0409</Culture>
+ <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ </ResourceCompile>
+ <Bscmake>
+ <SuppressStartupBanner>true</SuppressStartupBanner>
+ <OutputFile>.\Release\digidoc.bsc</OutputFile>
+ </Bscmake>
+ <Link>
+ <SuppressStartupBanner>true</SuppressStartupBanner>
+ <SubSystem>Console</SubSystem>
+ <OutputFile>bin/cdigidoc.exe</OutputFile>
+ <AdditionalDependencies>odbc32.lib;odbccp32.lib;libeay32.lib;ssleay32.lib;libxml2.lib;zlib.lib;Release\DigiDocLib.lib;wsock32.lib;Shlwapi.lib;crypt32.lib;comctl32.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ </Link>
+ </ItemDefinitionGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+ <ImportGroup Label="ExtensionTargets">
+ </ImportGroup>
+</Project> \ No newline at end of file
diff --git a/vc2010/libdigidoc.sln b/vc2010/libdigidoc.sln
new file mode 100644
index 0000000..4c7fc05
--- /dev/null
+++ b/vc2010/libdigidoc.sln
@@ -0,0 +1,61 @@
+
+Microsoft Visual Studio Solution File, Format Version 11.00
+# Visual Studio 2010
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "DigiDocLib", "DigiDocLib.vcxproj", "{0AB62309-A060-0BD6-A056-1F774EFB4D04}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "digidoc", "digidoc.vcxproj", "{FEA32EF4-D9F2-F7AC-E6E9-153F371AEFDF}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug_2_rel|Win32 = Debug_2_rel|Win32
+ Debug|Win32 = Debug|Win32
+ Release MinDependency|Win32 = Release MinDependency|Win32
+ Release|Win32 = Release|Win32
+ Template|Win32 = Template|Win32
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {0AB62309-A060-0BD6-A056-1F774EFB4D04}.Debug_2_rel|Win32.ActiveCfg = Debug|Win32
+ {0AB62309-A060-0BD6-A056-1F774EFB4D04}.Debug_2_rel|Win32.Build.0 = Debug|Win32
+ {0AB62309-A060-0BD6-A056-1F774EFB4D04}.Debug|Win32.ActiveCfg = Debug|Win32
+ {0AB62309-A060-0BD6-A056-1F774EFB4D04}.Debug|Win32.Build.0 = Debug|Win32
+ {0AB62309-A060-0BD6-A056-1F774EFB4D04}.Release MinDependency|Win32.ActiveCfg = Release|Win32
+ {0AB62309-A060-0BD6-A056-1F774EFB4D04}.Release MinDependency|Win32.Build.0 = Release|Win32
+ {0AB62309-A060-0BD6-A056-1F774EFB4D04}.Release|Win32.ActiveCfg = Release|Win32
+ {0AB62309-A060-0BD6-A056-1F774EFB4D04}.Release|Win32.Build.0 = Release|Win32
+ {0AB62309-A060-0BD6-A056-1F774EFB4D04}.Template|Win32.ActiveCfg = Release|Win32
+ {0AB62309-A060-0BD6-A056-1F774EFB4D04}.Template|Win32.Build.0 = Release|Win32
+ {FEA32EF4-D9F2-F7AC-E6E9-153F371AEFDF}.Debug_2_rel|Win32.ActiveCfg = Debug|Win32
+ {FEA32EF4-D9F2-F7AC-E6E9-153F371AEFDF}.Debug_2_rel|Win32.Build.0 = Debug|Win32
+ {FEA32EF4-D9F2-F7AC-E6E9-153F371AEFDF}.Debug|Win32.ActiveCfg = Debug|Win32
+ {FEA32EF4-D9F2-F7AC-E6E9-153F371AEFDF}.Debug|Win32.Build.0 = Debug|Win32
+ {FEA32EF4-D9F2-F7AC-E6E9-153F371AEFDF}.Release MinDependency|Win32.ActiveCfg = Release|Win32
+ {FEA32EF4-D9F2-F7AC-E6E9-153F371AEFDF}.Release MinDependency|Win32.Build.0 = Release|Win32
+ {FEA32EF4-D9F2-F7AC-E6E9-153F371AEFDF}.Release|Win32.ActiveCfg = Release|Win32
+ {FEA32EF4-D9F2-F7AC-E6E9-153F371AEFDF}.Release|Win32.Build.0 = Release|Win32
+ {FEA32EF4-D9F2-F7AC-E6E9-153F371AEFDF}.Template|Win32.ActiveCfg = Template|Win32
+ {FEA32EF4-D9F2-F7AC-E6E9-153F371AEFDF}.Template|Win32.Build.0 = Template|Win32
+ {62BC5BB8-94BD-B9D5-D004-70B7671171D6}.Debug_2_rel|Win32.ActiveCfg = Debug_2_rel|Win32
+ {62BC5BB8-94BD-B9D5-D004-70B7671171D6}.Debug_2_rel|Win32.Build.0 = Debug_2_rel|Win32
+ {62BC5BB8-94BD-B9D5-D004-70B7671171D6}.Debug|Win32.ActiveCfg = Debug|Win32
+ {62BC5BB8-94BD-B9D5-D004-70B7671171D6}.Debug|Win32.Build.0 = Debug|Win32
+ {62BC5BB8-94BD-B9D5-D004-70B7671171D6}.Release MinDependency|Win32.ActiveCfg = Release MinDependency|Win32
+ {62BC5BB8-94BD-B9D5-D004-70B7671171D6}.Release MinDependency|Win32.Build.0 = Release MinDependency|Win32
+ {62BC5BB8-94BD-B9D5-D004-70B7671171D6}.Release|Win32.ActiveCfg = Release MinDependency|Win32
+ {62BC5BB8-94BD-B9D5-D004-70B7671171D6}.Release|Win32.Build.0 = Release MinDependency|Win32
+ {62BC5BB8-94BD-B9D5-D004-70B7671171D6}.Template|Win32.ActiveCfg = Release MinDependency|Win32
+ {62BC5BB8-94BD-B9D5-D004-70B7671171D6}.Template|Win32.Build.0 = Release MinDependency|Win32
+ {494A3DA8-A26C-41B2-A6EA-85BC57748152}.Debug_2_rel|Win32.ActiveCfg = Debug|Win32
+ {494A3DA8-A26C-41B2-A6EA-85BC57748152}.Debug_2_rel|Win32.Build.0 = Debug|Win32
+ {494A3DA8-A26C-41B2-A6EA-85BC57748152}.Debug|Win32.ActiveCfg = Debug|Win32
+ {494A3DA8-A26C-41B2-A6EA-85BC57748152}.Debug|Win32.Build.0 = Debug|Win32
+ {494A3DA8-A26C-41B2-A6EA-85BC57748152}.Release MinDependency|Win32.ActiveCfg = Release|Win32
+ {494A3DA8-A26C-41B2-A6EA-85BC57748152}.Release MinDependency|Win32.Build.0 = Release|Win32
+ {494A3DA8-A26C-41B2-A6EA-85BC57748152}.Release|Win32.ActiveCfg = Release|Win32
+ {494A3DA8-A26C-41B2-A6EA-85BC57748152}.Release|Win32.Build.0 = Release|Win32
+ {494A3DA8-A26C-41B2-A6EA-85BC57748152}.Template|Win32.ActiveCfg = Release|Win32
+ {494A3DA8-A26C-41B2-A6EA-85BC57748152}.Template|Win32.Build.0 = Release|Win32
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal