[pkg-opensc-commit] [pkcs11-helper] 01/60: Initial import

Eric Dorland eric at moszumanska.debian.org
Fri Jan 6 23:39:40 UTC 2017


This is an automated email from the git hooks/post-receive script.

eric pushed a commit to tag pkcs11-helper-1.02
in repository pkcs11-helper.

commit fe48b98c24bfa15b73baa63b9025c2b4bf97cc1e
Author: alonbl <alonbl at 485eb718-1723-0410-b8a9-88cf21a28c35>
Date:   Sun Nov 26 09:41:31 2006 +0000

    Initial import
---
 .svnignore                                         |   24 +
 COPYING.BSD                                        |   32 +
 COPYING.GPL                                        |  346 +++
 ChangeLog                                          |   42 +
 INSTALL                                            |   50 +
 Makefile.am                                        |   62 +
 README                                             |   26 +
 config-w32-vc.h.in                                 |  185 ++
 configure.ac                                       |  407 +++
 doc/Makefile.am                                    |   53 +
 doc/api/Doxyfile                                   | 1255 +++++++++
 doc/api/Doxyfile_footer.html                       |    2 +
 doc/api/Makefile.am                                |   68 +
 include/Makefile.am                                |   53 +
 include/pkcs11-helper-1.0/Makefile.am              |   95 +
 include/pkcs11-helper-1.0/cryptoki-win32.h         |   66 +
 include/pkcs11-helper-1.0/cryptoki.h               |   35 +
 .../pkcs11-helper-1.0/pkcs11-headers/Makefile.am   |   58 +
 include/pkcs11-helper-1.0/pkcs11-headers/pkcs11.h  |  299 ++
 include/pkcs11-helper-1.0/pkcs11-headers/pkcs11f.h |  912 ++++++
 include/pkcs11-helper-1.0/pkcs11-headers/pkcs11t.h | 1685 +++++++++++
 include/pkcs11-helper-1.0/pkcs11h-certificate.h    |  538 ++++
 include/pkcs11-helper-1.0/pkcs11h-core.h           |  539 ++++
 include/pkcs11-helper-1.0/pkcs11h-data.h           |  190 ++
 include/pkcs11-helper-1.0/pkcs11h-def.h            |   90 +
 include/pkcs11-helper-1.0/pkcs11h-engines.h        |  208 ++
 include/pkcs11-helper-1.0/pkcs11h-locate.h         |  128 +
 include/pkcs11-helper-1.0/pkcs11h-openssl.h        |  162 ++
 include/pkcs11-helper-1.0/pkcs11h-standalone.h     |  129 +
 include/pkcs11-helper-1.0/pkcs11h-token.h          |  205 ++
 lib/Makefile.am                                    |  157 ++
 lib/Makefile.w32-vc                                |  159 ++
 lib/_pkcs11h-certificate.h                         |   98 +
 lib/_pkcs11h-core.h                                |  238 ++
 lib/_pkcs11h-crypto.h                              |   63 +
 lib/_pkcs11h-mem.h                                 |   86 +
 lib/_pkcs11h-session.h                             |  143 +
 lib/_pkcs11h-slotevent.h                           |   74 +
 lib/_pkcs11h-sys.h                                 |   63 +
 lib/_pkcs11h-threading.h                           |  161 ++
 lib/_pkcs11h-token.h                               |   71 +
 lib/_pkcs11h-util.h                                |   98 +
 lib/certificate.exports                            |   27 +
 lib/common.h                                       |   76 +
 lib/core.exports                                   |   19 +
 lib/data.exports                                   |    5 +
 lib/libpkcs11-helper-1.pc.in                       |   11 +
 lib/locate.exports                                 |    2 +
 lib/openssl.exports                                |    7 +
 lib/pkcs11h-certificate.c                          | 2914 ++++++++++++++++++++
 lib/pkcs11h-core.c                                 | 1179 ++++++++
 lib/pkcs11h-crypto.c                               | 1280 +++++++++
 lib/pkcs11h-data.c                                 |  779 ++++++
 lib/pkcs11h-locate.c                               | 1163 ++++++++
 lib/pkcs11h-mem.c                                  |  141 +
 lib/pkcs11h-openssl.c                              |  784 ++++++
 lib/pkcs11h-serialization.c                        |  435 +++
 lib/pkcs11h-session.c                              | 1127 ++++++++
 lib/pkcs11h-slotevent.c                            |  485 ++++
 lib/pkcs11h-standalone.c                           |  857 ++++++
 lib/pkcs11h-sys.c                                  |  109 +
 lib/pkcs11h-threading.c                            |  570 ++++
 lib/pkcs11h-token.c                                |  669 +++++
 lib/pkcs11h-util.c                                 |  279 ++
 lib/slotevent.exports                              |    1 +
 lib/standalone.exports                             |    2 +
 lib/token.exports                                  |    9 +
 m4dir/Makefile.am                                  |   55 +
 m4dir/pkcs11-helper-1.m4                           |   70 +
 man/Makefile.am                                    |   72 +
 man/pkcs11-helper.8                                |   72 +
 tests/Makefile.am                                  |   53 +
 tests/basic/Makefile.am                            |   62 +
 tests/basic/basic.c                                |   69 +
 tests/certificate/Makefile.am                      |   62 +
 tests/certificate/certificate.c                    |  322 +++
 tests/slotevent/Makefile.am                        |   62 +
 tests/slotevent/slotevent.c                        |  141 +
 78 files changed, 23325 insertions(+)

diff --git a/.svnignore b/.svnignore
new file mode 100644
index 0000000..9ddf1b2
--- /dev/null
+++ b/.svnignore
@@ -0,0 +1,24 @@
+*.bz2
+*.gz
+*.o
+*.obj
+*.html
+*.exe
+.deps
+.libs
+configure
+Makefile.in
+config.log
+depcomp
+config.h
+Makefile
+config.status
+config.guess
+config.sub
+stamp-h1
+config.h.in
+autom4te.cache
+missing
+aclocal.m4
+install-sh
+
diff --git a/COPYING.BSD b/COPYING.BSD
new file mode 100644
index 0000000..f63088e
--- /dev/null
+++ b/COPYING.BSD
@@ -0,0 +1,32 @@
+Copyright (c) 2005-2006, Alon Bar-Lev <alon.barlev at gmail.com>
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright notice,
+    * this list of conditions and the following disclaimer.
+    * 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.
+    * Neither the name of the <ORGANIZATION> nor the names of its
+    * contributors may be used to endorse or promote products derived from
+    * this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER 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.
+
+RSA Security Inc. License
+-------------------------
+
+  This software is using RSA Security Inc. PKCS #11 Cryptographic Token Interface (Cryptoki).
+
diff --git a/COPYING.GPL b/COPYING.GPL
new file mode 100644
index 0000000..3b2c785
--- /dev/null
+++ b/COPYING.GPL
@@ -0,0 +1,346 @@
+		    GNU GENERAL PUBLIC LICENSE
+		       Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+                       51 Franklin St, 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.
+
+			    Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, 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 or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+

+		    GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+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 give any other recipients of the Program a copy of this License
+along with the Program.
+
+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 Program or any portion
+of it, thus forming a work based on the Program, 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) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+

+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+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 Program, 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 Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) 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; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, 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 executable.  However, as a
+special exception, the source code 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.
+
+If distribution of executable or 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 counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+

+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program 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.
+
+  5. 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 Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program 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 to
+this License.
+
+  7. 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 Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program 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 Program.
+
+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.
+

+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program 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.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the 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 Program
+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 Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, 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
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "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 PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. 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 PROGRAM 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 PROGRAM (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 PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), 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 Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  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 program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program 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 General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) year name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Library General
+Public License instead of this License.
+
+RSA Security Inc. License
+-------------------------
+
+  This software is using RSA Security Inc. PKCS #11 Cryptographic Token Interface (Cryptoki).
+
diff --git a/ChangeLog b/ChangeLog
new file mode 100644
index 0000000..6f4b7d9
--- /dev/null
+++ b/ChangeLog
@@ -0,0 +1,42 @@
+pkcs11-helper
+Copyright (c) 2006 Alon Bar-Lev <alon.barlev at gmail.com>
+
+$Id$
+
+2006-??-?? - Version 1.02
+
+* First standalone version.
+
+* Fix invalid certificate max size handling (Zeljko Vrba).
+
+* Added object serialization.
+
+* Added user data to hooks.
+
+* Added a force login method.
+
+* Added support for gnutls in addition to openssl.
+
+* Fixup threading lock issues.
+
+* Added support for duplicate serial tokens, based on label.
+
+* Added workaround for OpenSC cards, OpenSC bug#108, thanks to Kaupo Arulo.
+
+* Added a methods to lock session between two sign/decrypt operations.
+
+* Modified openssl interface.
+
+* Added engines for system and crypto to minimize dependencies.
+
+* Added win32 crypto engine.
+
+* Added decrypt option using C_UnwrapKey.
+
+2006-06-26 - Version 1.01
+
+* Fix handling mutiple providers.
+
+2006-05-14 - Version 1.00
+
+* First stable release.
diff --git a/INSTALL b/INSTALL
new file mode 100644
index 0000000..036f8d6
--- /dev/null
+++ b/INSTALL
@@ -0,0 +1,50 @@
+pkcs11-helper -- PKCS#11 simplification.
+
+Copyright (c) 2005-2006 Alon Bar-Lev <alon.barlev at gmail.com>
+
+POSIX
+	Dependencies:
+	        dl
+		threading: (Optional)
+			pthread (nptl)
+		engine-crypt: (Optional, usually must choose)
+			OpenSSL>=0.9.7 || GNUTLS>=1.4.4
+		openssl: (Optional)
+			OpenSSL>=0.9.7
+		doc: (Optional)
+			doxygen>=1.4
+
+	Build:
+		$ ./configure
+		$ make
+		$ make install
+
+Cross-MinGW32
+	Dependencies:
+		man2html
+		openssl: (Optional)
+			OpenSSL>=0.9.7
+		doc: (Optional)
+			doxygen>=1.4
+
+	Build:
+		w32root=/tmp/w32root
+		./configure --prefix=/ --host=mingw32 --disable-openssl
+		[[Add --with-cygwin-native if you use cygwin for native win32]]
+		make
+		make install DESTDIR=${w32root}
+
+	Create Microsoft LIB file (Optional):
+		[[Must use Microsoft lib utility]]
+		lib /def:libpkcs11-helper-1.dll.def \
+			/name:libpkcs11-helper-1.dll \
+			/out:libpkcs11-helper-1.lib
+
+Visual Studio
+	Dependencies:
+		None.
+
+	Build:
+		cd lib
+		nmake -f Makefile.w32-vc
+
diff --git a/Makefile.am b/Makefile.am
new file mode 100644
index 0000000..f531051
--- /dev/null
+++ b/Makefile.am
@@ -0,0 +1,62 @@
+#
+# Copyright (c) 2005-2006 Alon Bar-Lev <alon.barlev at gmail.com>
+# All rights reserved.
+#
+# This software is available to you under a choice of one of two
+# licenses.  You may choose to be licensed under the terms of the GNU
+# General Public License (GPL) Version 2, or the OpenIB.org BSD license.
+#
+# GNU General Public License (GPL) Version 2
+# ===========================================
+#  This program is free software; you can redistribute it and/or modify
+#  it under the terms of the GNU General Public License version 2
+#  as published by the Free Software Foundation.
+#
+#  This program 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 General Public License for more details.
+#
+#  You should have received a copy of the GNU General Public License
+#  along with this program (see the file COPYING[.GPL2] included with this
+#  distribution); if not, write to the Free Software Foundation, Inc.,
+#  59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+#
+# OpenIB.org BSD license
+# =======================
+# Redistribution and use in source and binary forms, with or without modifi-
+# cation, are permitted provided that the following conditions are met:
+#
+#   o  Redistributions of source code must retain the above copyright notice,
+#      this list of conditions and the following disclaimer.
+#
+#   o  Redistributions in binary form must reproduce the above copyright no-
+#      tice, this list of conditions and the following disclaimer in the do-
+#      cumentation and/or other materials provided with the distribution.
+#
+#   o  The names of the contributors may not be used to endorse or promote
+#      products derived from this software without specific prior written
+#      permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# ``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 REGENTS OR CONTRIBUTORS BE LI-
+# ABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUEN-
+# TIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEV-
+# ER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABI-
+# LITY, 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 option prevents autoreconf from overriding our COPYING and
+# INSTALL targets:
+AUTOMAKE_OPTIONS=foreign dist-bzip2
+
+SUBDIRS=man include lib m4dir doc tests
+
+dist_doc_DATA=README COPYING.GPL COPYING.BSD
+
+EXTRA_DIST=config-w32-vc.h
+
diff --git a/README b/README
new file mode 100644
index 0000000..b6a9717
--- /dev/null
+++ b/README
@@ -0,0 +1,26 @@
+pkcs11-helper -- PKCS#11 simplification.
+
+Copyright (c) 2005-2006 Alon Bar-Lev <alon.barlev at gmail.com>
+
+ABOUT
+	PKCS#11 is RSA Security published standard. PKCS#11 is the de-facto standard to access
+	cryptographic devices.
+
+	pkcs11-helper is a library that provides simplified interaction with PKCS#11
+	providers for user applications.
+
+	pkcs11-helper allows using multiple PKCS#11 providers at the same time, selecting 
+	keys by id, label or certificate subject, handling card removal and card insert
+	events, handling card re-insert to a different slot, supporting session expiration
+	serialization and much more, all using a simple API.
+
+	pkcs11-helper is not designed to manage card content, since object attributes
+	are usually vendor specific, and 99% of application need to access
+	existing objects in order to perform signature and decryption.
+
+AUTHORS
+	Alon Bar-Lev <alon.barlev at gmail.com>
+
+SUPPORT
+	http://????????????????
+
diff --git a/config-w32-vc.h.in b/config-w32-vc.h.in
new file mode 100644
index 0000000..fbeb414
--- /dev/null
+++ b/config-w32-vc.h.in
@@ -0,0 +1,185 @@
+/* config.h.  Generated from config.h.in by configure.  */
+/* config.h.in.  Generated from configure.ac by autoheader.  */
+
+/* Enable certificate interface */
+#define ENABLE_PKCS11H_CERTIFICATE 1
+
+/* Enable data interface */
+#define ENABLE_PKCS11H_DATA 1
+
+/* Enable debug support */
+#define ENABLE_PKCS11H_DEBUG 1
+
+/* Use GNUTLS cryto engine */
+/* #undef ENABLE_PKCS11H_ENGINE_GNUTLS */
+
+/* Use OpenSSL crypto engine */
+/* #undef ENABLE_PKCS11H_ENGINE_OPENSSL */
+
+/* Use win32 crypto engine */
+#define ENABLE_PKCS11H_ENGINE_WIN32 1
+
+/* Enable locate interface */
+#define ENABLE_PKCS11H_LOCATE 1
+
+/* Enable openssl interface */
+/* #undef ENABLE_PKCS11H_OPENSSL */
+
+/* Enable slotevent interface */
+#define ENABLE_PKCS11H_SLOTEVENT 1
+
+/* Enable standalone interface */
+#define ENABLE_PKCS11H_STANDALONE 1
+
+/* Enable threading */
+#define ENABLE_PKCS11H_THREADING 1
+
+/* Enable token interface */
+#define ENABLE_PKCS11H_TOKEN 1
+
+/* Define to 1 if you have the `alarm' function. */
+/* #undef HAVE_ALARM */
+
+/* Define to 1 if you have the <dlfcn.h> header file. */
+/* #undef HAVE_DLFCN_H */
+
+/* Define to 1 if you don't have `vprintf' but do have `_doprnt.' */
+/* #undef HAVE_DOPRNT */
+
+/* Define to 1 if you have the `gettimeofday' function. */
+/* #undef HAVE_GETTIMEOFDAY */
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#define HAVE_INTTYPES_H 1
+
+/* Define to 1 if you have the `dl' library (-ldl). */
+/* #undef HAVE_LIBDL */
+
+/* Define to 1 if you have the `pthread' library (-lpthread). */
+/* #undef HAVE_LIBPTHREAD */
+
+/* Define to 1 if you have the `memmove' function. */
+#define HAVE_MEMMOVE 1
+
+/* Define to 1 if you have the <memory.h> header file. */
+#define HAVE_MEMORY_H 1
+
+/* Define to 1 if you have the `memset' function. */
+#define HAVE_MEMSET 1
+
+/* Define to 1 if you have the <pthread.h> header file. */
+/* #undef HAVE_PTHREAD_H */
+
+/* Define to 1 if you have the <signal.h> header file. */
+/* #undef HAVE_SIGNAL_H */
+
+/* Define to 1 if you have the `snprintf' function. */
+#define HAVE_SNPRINTF 1
+
+/* Define to 1 if you have the `socket' function. */
+/* #undef HAVE_SOCKET */
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#define HAVE_STDINT_H 1
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#define HAVE_STDLIB_H 1
+
+/* Define to 1 if you have the `strchr' function. */
+#define HAVE_STRCHR 1
+
+/* Define to 1 if you have the `strdup' function. */
+#define HAVE_STRDUP 1
+
+/* Define to 1 if you have the `strerror' function. */
+#define HAVE_STRERROR 1
+
+/* Define to 1 if you have the <strings.h> header file. */
+#define HAVE_STRINGS_H 1
+
+/* Define to 1 if you have the <string.h> header file. */
+#define HAVE_STRING_H 1
+
+/* Define to 1 if you have the `strrchr' function. */
+#define HAVE_STRRCHR 1
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#define HAVE_SYS_STAT_H 1
+
+/* Define to 1 if you have the <sys/time.h> header file. */
+#define HAVE_SYS_TIME_H 1
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#define HAVE_SYS_TYPES_H 1
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#define HAVE_UNISTD_H 1
+
+/* Define to 1 if you have the `vprintf' function. */
+#define HAVE_VPRINTF 1
+
+/* Define to 1 if you have the <[], [stdio.h], [stdlib.h], [stdargs.h],
+   [malloc.h], [ctype.h], [string.h], [errno.h], [assert.h], [time.h], []>
+   header file. */
+/* #undef HAVE______STDIO_H____STDLIB_H____STDARGS_H____MALLOC_H____CTYPE_H____STRING_H____ERRNO_H____ASSERT_H____TIME_H_____ */
+
+/* Name of package */
+#define PACKAGE "@PACKAGE@"
+
+/* Define to the address where bug reports for this package should be sent. */
+#define PACKAGE_BUGREPORT "@PACKAGE_BUGREPORT@"
+
+/* Define to the full name of this package. */
+#define PACKAGE_NAME "@PACKAGE_NAME@"
+
+/* Define to the full name and version of this package. */
+#define PACKAGE_STRING "@PACKAGE_STRING@"
+
+/* Define to the one symbol short name of this package. */
+#define PACKAGE_TARNAME "@PACKAGE_TARNAME@"
+
+/* Define to the version of this package. */
+#define PACKAGE_VERSION "@PACKAGE_VERSION@"
+
+/* Define if you are on Cygwin */
+/* #undef PKCS11H_USE_CYGWIN */
+
+/* Define as the return type of signal handlers (`int' or `void'). */
+#define RETSIGTYPE void
+
+/* Define to 1 if you have the ANSI C header files. */
+#define STDC_HEADERS 1
+
+/* Test log level */
+#define TEST_LOG_LEVEL 3
+
+/* Test provider */
+#define TEST_PROVIDER "@TEST_PROVIDER@"
+
+/* Define to 1 if you can safely include both <sys/time.h> and <time.h>. */
+#define TIME_WITH_SYS_TIME 1
+
+/* Define to 1 if your <sys/time.h> declares `struct tm'. */
+/* #undef TM_IN_SYS_TIME */
+
+/* Use valgrind memory debugging library */
+/* #undef USE_VALGRIND */
+
+/* Version number of package */
+#define VERSION "@VERSION@"
+
+/* Define to empty if `const' does not conform to ANSI C. */
+/* #undef const */
+
+/* Define to `long int' if <sys/types.h> does not define. */
+/* #undef off_t */
+
+/* Define to `int' if <sys/types.h> does not define. */
+/* #undef pid_t */
+
+/* Define to `unsigned int' if <sys/types.h> does not define. */
+/* #undef size_t */
+
+/* Define to empty if the keyword `volatile' does not work. Warning: valid
+   code using `volatile' can become incorrect without. Disable with care. */
+/* #undef volatile */
diff --git a/configure.ac b/configure.ac
new file mode 100644
index 0000000..db318ef
--- /dev/null
+++ b/configure.ac
@@ -0,0 +1,407 @@
+#
+# Copyright (c) 2005-2006 Alon Bar-Lev <alon.barlev at gmail.com>
+# All rights reserved.
+#
+# This software is available to you under a choice of one of two
+# licenses.  You may choose to be licensed under the terms of the GNU
+# General Public License (GPL) Version 2, or the OpenIB.org BSD license.
+#
+# GNU General Public License (GPL) Version 2
+# ===========================================
+#  This program is free software; you can redistribute it and/or modify
+#  it under the terms of the GNU General Public License version 2
+#  as published by the Free Software Foundation.
+#
+#  This program 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 General Public License for more details.
+#
+#  You should have received a copy of the GNU General Public License
+#  along with this program (see the file COPYING[.GPL2] included with this
+#  distribution); if not, write to the Free Software Foundation, Inc.,
+#  59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+#
+# OpenIB.org BSD license
+# =======================
+# Redistribution and use in source and binary forms, with or without modifi-
+# cation, are permitted provided that the following conditions are met:
+#
+#   o  Redistributions of source code must retain the above copyright notice,
+#      this list of conditions and the following disclaimer.
+#
+#   o  Redistributions in binary form must reproduce the above copyright no-
+#      tice, this list of conditions and the following disclaimer in the do-
+#      cumentation and/or other materials provided with the distribution.
+#
+#   o  The names of the contributors may not be used to endorse or promote
+#      products derived from this software without specific prior written
+#      permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# ``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 REGENTS OR CONTRIBUTORS BE LI-
+# ABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUEN-
+# TIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEV-
+# ER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABI-
+# LITY, 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.
+#
+
+AC_PREREQ(2.60)
+AC_INIT(pkcs11-helper, 1.02)
+AM_INIT_AUTOMAKE(pkcs11-helper, [$PACKAGE_VERSION])
+AM_CONFIG_HEADER([config.h])
+AC_CONFIG_SRCDIR([lib/common.h])
+
+# Checks for programs.
+AC_CANONICAL_HOST
+
+LIBPKCS11_HELPER_LT_CURRENT="1"
+LIBPKCS11_HELPER_LT_REVISION="0"
+LIBPKCS11_HELPER_LT_AGE="0"
+AC_SUBST(LIBPKCS11_HELPER_LT_CURRENT)
+AC_SUBST(LIBPKCS11_HELPER_LT_REVISION)
+AC_SUBST(LIBPKCS11_HELPER_LT_AGE)
+
+AC_ARG_WITH(cygwin-native,
+	[  --with-cygwin-native              Compile native win32],
+	[CYGWIN_NATIVE="${withval}"],
+	[CYGWIN_NATIVE="no"]
+)
+
+WIN32="no"
+CYGWIN="no"
+case "${host}" in
+	*-mingw32*)
+		WIN32="yes"
+	;;
+	*-cygwin*)
+		AC_MSG_CHECKING([cygwin mode to use])
+		if test "${CYGWIN_NATIVE}" = "yes"; then
+			AC_MSG_RESULT([Using native win32])
+			CFLAGS="${CFLAGS} -mno-cygwin"
+			CYGWIN="yes"
+			WIN32="yes"
+		else
+			AC_MSG_RESULT([Using cygwin])
+			AC_DEFINE(PKCS11H_USE_CYGWIN, 1, [Define if you are on Cygwin])
+		fi
+	;;
+	*)
+	;;
+esac
+
+AC_ARG_ENABLE(doc,
+	[  --enable-doc                      Enable documantation],
+	[ENABLE_DOC="${enableval}"],
+	[ENABLE_DOC="no"]
+)
+
+AC_ARG_ENABLE(debug,
+	[  --disable-debug                   Disable debug support],
+	[ENABLE_PKCS11H_DEBUG="${enableval}"],
+	[ENABLE_PKCS11H_DEBUG="yes"]
+)
+
+AC_ARG_ENABLE(threading,
+	[  --disable-threading               Disable threading],
+	[ENABLE_PKCS11H_THREADING="${enableval}"],
+	[ENABLE_PKCS11H_THREADING="yes"]
+)
+
+AC_ARG_ENABLE(token,
+	[  --disable-token                   Disable token support],
+	[ENABLE_PKCS11H_TOKEN="${enableval}"],
+	[ENABLE_PKCS11H_TOKEN="yes"]
+)
+
+AC_ARG_ENABLE(data,
+	[  --disable-data                    Disable data objects support],
+	[ENABLE_PKCS11H_DATA="${enableval}"],
+	[ENABLE_PKCS11H_DATA="yes"]
+)
+
+AC_ARG_ENABLE(certificate,
+	[  --disable-certificate             Disable certificate support],
+	[ENABLE_PKCS11H_CERTIFICATE="${enableval}"],
+	[ENABLE_PKCS11H_CERTIFICATE="yes"]
+)
+
+AC_ARG_ENABLE(locate,
+	[  --disable-locate                  Disable locate support],
+	[ENABLE_PKCS11H_LOCATE="${enableval}"],
+	[ENABLE_PKCS11H_LOCATE="yes"]
+)
+
+AC_ARG_ENABLE(slotevent,
+	[  --disable-slotevent               Disable slotevent support],
+	[ENABLE_PKCS11H_SLOTEVENT="${enableval}"],
+	[ENABLE_PKCS11H_SLOTEVENT="yes"]
+)
+
+AC_ARG_ENABLE(openssl,
+	[  --disable-openssl                 Disable openssl interface],
+	[ENABLE_PKCS11H_OPENSSL="${enableval}"],
+	[ENABLE_PKCS11H_OPENSSL="yes"]
+)
+
+AC_ARG_ENABLE(standalone,
+	[  --disable-standalone              Disable standalone interface],
+	[ENABLE_PKCS11H_STANDALONE="${enableval}"],
+	[ENABLE_PKCS11H_STANDALONE="yes"]
+)
+
+AC_ARG_ENABLE(pedantic,
+	[  --enable-pedantic                 Enable pedantic compiler warnings, will not generate a working executable (debugging option)],
+	[PEDANTIC="${enableval}"],
+	[PEDANTIC="no"]
+)
+
+AC_ARG_WITH(crypto-engine-openssl,
+	[  --without-crypto-engine-openssl   Disable OpenSSL crypto engine],
+	[WITH_CRYPTO_ENGINE_OPENSSL="${withval}"],
+	[WITH_CRYPTO_ENGINE_OPENSSL="yes"]
+)
+
+AC_ARG_WITH(crypto-engine-gnutls,
+	[  --without-crypto-engine-gnutls    Disable GNUTLS crypto engine (OpenSSL will be used if both enabled)],
+	[WITH_CRYPTO_ENGINE_GNUTLS="${withval}"],
+	[WITH_CRYPTO_ENGINE_GNUTLS="yes"]
+)
+
+AC_ARG_WITH(crypto-engine-win32,
+	[  --without-crypto-engine-win32     Disable win32 native crypto engine on win32 systems],
+	[WITH_CRYPTO_ENGINE_WIN32="${withval}"],
+	[WITH_CRYPTO_ENGINE_WIN32="yes"]
+)
+
+AC_ARG_WITH(mem-check,
+	[  --with-mem-check=TYPE             Build with debug memory checking, TYPE = valgrind],
+	[MEMCHECK="$withval"]
+)
+
+AC_ARG_WITH(test-provider,
+	[  --with-test-provider=lib          Specify providers for test phase],
+	[
+		AC_DEFINE_UNQUOTED([TEST_PROVIDER], ["${withval}"], [Test provider])
+	],
+	[
+		AC_DEFINE_UNQUOTED([TEST_PROVIDER], ["/usr/lib/pkcs11/provider.so"], [Test provider])
+	]
+)
+
+AC_ARG_WITH(test-log-level,
+	[  --with-test-log-level=level       Specify log level for test phase],
+	[
+		AC_DEFINE_UNQUOTED([TEST_LOG_LEVEL], [${withval}], [Test log level])
+	],
+	[
+		AC_DEFINE_UNQUOTED([TEST_LOG_LEVEL], [3], [Test log level])
+	]
+)
+
+AC_PROG_CC
+AC_PROG_INSTALL
+AC_PROG_LIBTOOL
+PKG_PROG_PKG_CONFIG
+if test "${ENABLE_DOC}" = "yes"; then
+	AC_CHECK_PROGS([DOXYGEN], [doxygen])
+	test -z "${DOXYGEN}" && AC_MSG_ERROR([doxygen is required for docs])
+fi
+if test "${WIN32}" = "yes"; then
+	AC_CHECK_PROGS([MAN2HTML], [man2html])
+	test -z "${MAN2HTML}" && AC_MSG_ERROR([man2html is required for win32])
+fi
+
+AC_FUNC_MKTIME
+AC_TYPE_SIGNAL
+AC_FUNC_VPRINTF
+AC_CHECK_FUNCS([ \
+	gettimeofday memmove memset socket strchr strdup strerror strrchr \
+	snprintf \
+])
+
+# Checks for libraries.
+AC_CHECK_LIB([dl], [dlopen])
+
+if test "${ENABLE_PKCS11H_THREADING}" = "yes" -a "${WIN32}" != "yes"; then
+	AC_CHECK_LIB([pthread], [pthread_create])
+fi
+
+PKG_CHECK_MODULES([OPENSSL], [libcrypto >= 0.9.7], [HAVE_OPENSSL="yes"], [HAVE_OPENSSL="no"])
+if test "${HAVE_OPENSSL}" = "no"; then
+	PKG_CHECK_MODULES([OPENSSL], [openssl >= 0.9.7], [HAVE_OPENSSL="yes"], [HAVE_OPENSSL="no"])
+fi
+
+PKG_CHECK_MODULES([GNUTLS], [gnutls >= 1.4], [HAVE_GNUTLS="yes"], [HAVE_GNUTLS="no"])
+
+AC_MSG_CHECKING([cryptographic library to use])
+
+if test "${WITH_CRYPTO_ENGINE_OPENSSL}" = "yes" -a "${HAVE_OPENSSL}" != "yes"; then
+	WITH_CRYPTO_ENGINE_OPENSSL="no"
+fi
+
+if test "${WITH_CRYPTO_ENGINE_GNUTLS}" = "yes" -a "${HAVE_GNUTLS}" != "yes"; then
+	WITH_CRYPTO_ENGINE_GNUTLS="no"
+fi
+
+if test "${WIN32}" = "yes" -a "${WITH_CRYPTO_ENGINE_WIN32}" = "yes"; then
+	AC_MSG_RESULT([Using win32])
+	AC_DEFINE(ENABLE_PKCS11H_ENGINE_WIN32, 1, [Use win32 crypto engine])
+elif test "${WITH_CRYPTO_ENGINE_OPENSSL}" = "yes"; then
+	AC_MSG_RESULT([Using OpenSSL])
+	AC_DEFINE(ENABLE_PKCS11H_ENGINE_OPENSSL, 1, [Use OpenSSL crypto engine])
+	CFLAGS="${CFLAGS} ${OPENSSL_CFLAGS}"
+	LIBS="${LIBS} ${OPENSSL_LIBS}"
+elif test "${WITH_CRYPTO_ENGINE_GNUTLS}" = "yes"; then
+	AC_MSG_RESULT([Using GNUTLS])
+	AC_DEFINE(ENABLE_PKCS11H_ENGINE_GNUTLS, 1, [Use GNUTLS crypto engine])
+	CFLAGS="${CFLAGS} ${GNUTLS_CFLAGS}"
+	LIBS="${LIBS} ${GNUTLS_LIBS}"
+else
+	AC_MSG_RESULT([No engine selected.])
+fi
+
+# Checks for header files.
+AC_HEADER_STDC
+AC_C_CONST
+AC_C_VOLATILE
+AC_TYPE_OFF_T
+AC_TYPE_PID_T
+AC_TYPE_SIZE_T
+AC_HEADER_TIME
+AC_STRUCT_TM
+AC_CHECK_HEADERS([[ \
+	stdio.h \
+	stdlib.h \
+	stdargs.h \
+	malloc.h \
+	ctype.h \
+	string.h \
+	errno.h \
+	assert.h \
+	time.h \
+]])
+if test -z "${WIN32}"; then
+	AC_CHECK_HEADERS([ \
+		signal.h \
+		dlfcn.h \
+		unistd.h \
+		sys/time.h \
+		pthread.h \
+	])
+fi
+
+if test "$MEMCHECK" = "valgrind"; then
+	AC_CHECKING([for valgrind tool and Header files])
+	PKG_CHECK_MODULES([VALGRIND], [valgrind >= 3.0.0], [HAVE_VALGRIND=yes], [HAVE_VALGRIND=no])
+	if test "${HAVE_VALGRIND}" != "yes"; then
+		AC_MSG_ERROR([valgrind was not found])
+	fi
+	AC_DEFINE(USE_VALGRIND, 1, [Use valgrind memory debugging library])
+	CFLAGS="${CFLAGS} ${VALGRIND_CFLAGS} -g -fno-inline"
+#	LIBS="${VALGRIND_LIBS} ${LIBS}"
+fi
+
+CFLAGS="$CFLAGS -Wall -Wpointer-arith -Wsign-compare -Wno-unused-parameter -Wno-unused-function"
+
+if test "$PEDANTIC" = "yes"; then
+	CFLAGS="${CFLAGS} -ansi -pedantic -D__STRICT_ANSI__ -D_POSIX_SOURCE -D_POSIX_C_SOURCE -D_SVID_SOURCE"
+fi
+
+if test "${WIN32}" = "yes"; then
+	LIBS="${LIBS} -lkernel32 -lgdi32"
+fi
+
+if test "${ENABLE_PKCS11H_THREADING}" != "yes" -a "${ENABLE_PKCS11H_SLOTEVENT}" = "yes"; then
+	AC_MSG_ERROR([Threading must be enabled for slotevent to be enabled])
+fi
+
+if test "${ENABLE_PKCS11H_OPENSSL}" = "yes" -a "${WITH_CRYPTO_ENGINE_OPENSSL}" != "yes"; then
+	AC_MSG_ERROR([OpenSSL must be linked for OpenSSL interface to operate])
+fi
+
+if test "${ENABLE_PKCS11H_OPENSSL}" = "yes" -a "${ENABLE_PKCS11H_CERTIFICATE}" != "yes"; then
+	AC_MSG_ERROR([OpenSSL interface requires certificate interface])
+fi
+
+if test "${ENABLE_PKCS11H_DEBUG}" = "yes"; then
+	AC_DEFINE([ENABLE_PKCS11H_DEBUG], 1, [Enable debug support])
+	PKCS11H_FEATURES="${PKCS11H_FEATURES} debug"
+fi
+if test "${ENABLE_PKCS11H_THREADING}" = "yes"; then
+	AC_DEFINE([ENABLE_PKCS11H_THREADING], 1, [Enable threading])
+	PKCS11H_FEATURES="${PKCS11H_FEATURES} threading"
+fi
+if test "${ENABLE_PKCS11H_TOKEN}" = "yes"; then
+	AC_DEFINE([ENABLE_PKCS11H_TOKEN], 1, [Enable token interface])
+	PKCS11H_FEATURES="${PKCS11H_FEATURES} token"
+fi
+if test "${ENABLE_PKCS11H_DATA}" = "yes"; then
+	AC_DEFINE([ENABLE_PKCS11H_DATA], 1, [Enable data interface])
+	PKCS11H_FEATURES="${PKCS11H_FEATURES} data"
+fi
+if test "${ENABLE_PKCS11H_CERTIFICATE}" = "yes"; then
+	AC_DEFINE([ENABLE_PKCS11H_CERTIFICATE], 1, [Enable certificate interface])
+	PKCS11H_FEATURES="${PKCS11H_FEATURES} certificate"
+fi
+if test "${ENABLE_PKCS11H_LOCATE}" = "yes"; then
+	AC_DEFINE([ENABLE_PKCS11H_LOCATE], 1, [Enable locate interface])
+	PKCS11H_FEATURES="${PKCS11H_FEATURES} locate"
+fi
+if test "${ENABLE_PKCS11H_SLOTEVENT}" = "yes"; then
+	AC_DEFINE([ENABLE_PKCS11H_SLOTEVENT], 1, [Enable slotevent interface])
+	PKCS11H_FEATURES="${PKCS11H_FEATURES} slotevent"
+fi
+if test "${ENABLE_PKCS11H_OPENSSL}" = "yes"; then
+	AC_DEFINE([ENABLE_PKCS11H_OPENSSL], 1, [Enable openssl interface])
+	PKCS11H_FEATURES="${PKCS11H_FEATURES} openssl"
+fi
+if test "${ENABLE_PKCS11H_STANDALONE}" = "yes"; then
+	AC_DEFINE([ENABLE_PKCS11H_STANDALONE], 1, [Enable standalone interface])
+	PKCS11H_FEATURES="${PKCS11H_FEATURES} standalone"
+fi
+if test \
+	"${WITH_CRYPTO_ENGINE_OPENSSL}" = "yes" -o \
+	"${WITH_CRYPTO_ENGINE_GNUTLS}" = "yes" -o \
+	"${WITH_CRYPTO_ENGINE_WIN32}" = "yes"; then
+	PKCS11H_FEATURES="${PKCS11H_FEATURES} engine_crypto"
+fi
+
+docdir="${docdir}-${PACKAGE_VERSION}"
+pkgconfigdir="${libdir}/pkgconfig"
+AC_SUBST([pkgconfigdir])
+AC_SUBST([LIBS])
+AC_SUBST([PKCS11H_FEATURES])
+AM_CONDITIONAL(ENABLE_DOC, test "${ENABLE_DOC}" = "yes")
+AM_CONDITIONAL(WIN32, test "${WIN32}" = "yes")
+AM_CONDITIONAL(CYGWIN, test "${CYGWIN}" = "yes")
+AM_CONDITIONAL(ENABLE_PKCS11H_TOKEN, test "${ENABLE_PKCS11H_TOKEN}" = "yes")
+AM_CONDITIONAL(ENABLE_PKCS11H_DATA, test "${ENABLE_PKCS11H_DATA}" = "yes")
+AM_CONDITIONAL(ENABLE_PKCS11H_CERTIFICATE, test "${ENABLE_PKCS11H_CERTIFICATE}" = "yes")
+AM_CONDITIONAL(ENABLE_PKCS11H_LOCATE, test "${ENABLE_PKCS11H_LOCATE}" = "yes")
+AM_CONDITIONAL(ENABLE_PKCS11H_SLOTEVENT, test "${ENABLE_PKCS11H_SLOTEVENT}" = "yes")
+AM_CONDITIONAL(ENABLE_PKCS11H_OPENSSL, test "${ENABLE_PKCS11H_OPENSSL}" = "yes")
+AM_CONDITIONAL(ENABLE_PKCS11H_STANDALONE, test "${ENABLE_PKCS11H_STANDALONE}" = "yes")
+AC_CONFIG_FILES([
+	Makefile
+	config-w32-vc.h
+	include/Makefile
+	include/pkcs11-helper-1.0/Makefile
+	include/pkcs11-helper-1.0/pkcs11-headers/Makefile
+	man/Makefile
+	doc/Makefile
+	doc/api/Makefile
+	lib/Makefile
+	lib/libpkcs11-helper-1.pc
+	m4dir/Makefile
+	tests/Makefile
+	tests/basic/Makefile
+	tests/certificate/Makefile
+	tests/slotevent/Makefile
+])
+AC_OUTPUT
+
diff --git a/doc/Makefile.am b/doc/Makefile.am
new file mode 100644
index 0000000..858394a
--- /dev/null
+++ b/doc/Makefile.am
@@ -0,0 +1,53 @@
+#
+# Copyright (c) 2005-2006 Alon Bar-Lev <alon.barlev at gmail.com>
+# All rights reserved.
+#
+# This software is available to you under a choice of one of two
+# licenses.  You may choose to be licensed under the terms of the GNU
+# General Public License (GPL) Version 2, or the OpenIB.org BSD license.
+#
+# GNU General Public License (GPL) Version 2
+# ===========================================
+#  This program is free software; you can redistribute it and/or modify
+#  it under the terms of the GNU General Public License version 2
+#  as published by the Free Software Foundation.
+#
+#  This program 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 General Public License for more details.
+#
+#  You should have received a copy of the GNU General Public License
+#  along with this program (see the file COPYING[.GPL2] included with this
+#  distribution); if not, write to the Free Software Foundation, Inc.,
+#  59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+#
+# OpenIB.org BSD license
+# =======================
+# Redistribution and use in source and binary forms, with or without modifi-
+# cation, are permitted provided that the following conditions are met:
+#
+#   o  Redistributions of source code must retain the above copyright notice,
+#      this list of conditions and the following disclaimer.
+#
+#   o  Redistributions in binary form must reproduce the above copyright no-
+#      tice, this list of conditions and the following disclaimer in the do-
+#      cumentation and/or other materials provided with the distribution.
+#
+#   o  The names of the contributors may not be used to endorse or promote
+#      products derived from this software without specific prior written
+#      permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# ``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 REGENTS OR CONTRIBUTORS BE LI-
+# ABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUEN-
+# TIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEV-
+# ER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABI-
+# LITY, 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.
+#
+
+SUBDIRS=api
diff --git a/doc/api/Doxyfile b/doc/api/Doxyfile
new file mode 100644
index 0000000..b61d285
--- /dev/null
+++ b/doc/api/Doxyfile
@@ -0,0 +1,1255 @@
+# Doxyfile 1.4.7
+
+# 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
+#---------------------------------------------------------------------------
+
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded 
+# by quotes) that should identify the project.
+
+PROJECT_NAME           = pkcs11-helper
+
+# 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         = 
+
+# 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       = api
+
+# 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: 
+# Brazilian, Catalan, Chinese, Chinese-Traditional, Croatian, Czech, Danish, 
+# Dutch, Finnish, French, German, Greek, Hungarian, Italian, Japanese, 
+# Japanese-en (Japanese with English messages), Korean, Korean-en, Norwegian, 
+# Polish, Portuguese, Romanian, Russian, Serbian, Slovak, Slovene, Spanish, 
+# Swedish, and Ukrainian.
+
+OUTPUT_LANGUAGE        = English
+
+# This tag can be used to specify the encoding used in the generated output. 
+# The encoding is not always determined by the language that is chosen, 
+# but also whether or not the output is meant for Windows or non-Windows users. 
+# In case there is a difference, setting the USE_WINDOWS_ENCODING tag to YES 
+# forces the Windows encoding (this is the default for the Windows binary), 
+# whereas setting the tag to NO uses a Unix-style encoding (the default for 
+# all platforms other than Windows).
+
+USE_WINDOWS_ENCODING   = NO
+
+# 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       = 
+
+# 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        = YES
+
+# 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        = ../../include
+
+# 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 is your file systems 
+# 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 the Qt-style comments (thus requiring an 
+# explicit @brief command for a brief description.
+
+JAVADOC_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 DETAILS_AT_TOP tag is set to YES then Doxygen 
+# will output the detailed description near the top, like JavaDoc.
+# If set to NO, the detailed description appears after the member 
+# documentation.
+
+DETAILS_AT_TOP         = 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                = 
+
+# 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
+
+# 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 make the inheritance and collaboration 
+# diagrams that involve STL classes more complete and accurate.
+
+BUILTIN_STL_SUPPORT    = NO
+
+# 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
+
+#---------------------------------------------------------------------------
+# 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_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  = 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     = YES
+
+# 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     = YES
+
+# 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       = YES
+
+# 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     = 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_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
+
+# 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 define 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 defines 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
+
+# If the sources in your project are distributed over multiple directories 
+# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy 
+# in the documentation. The default is NO.
+
+SHOW_DIRECTORIES       = NO
+
+# 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    = 
+
+#---------------------------------------------------------------------------
+# 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
+
+# This WARN_NO_PARAMDOC option can be abled 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                  = ../../include
+
+# 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++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx 
+# *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py
+
+FILE_PATTERNS          = 
+
+# 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 
+# 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.
+
+EXCLUDE                = \
+	../../include/pkcs11-helper-1.0/cryptoki.h \
+	../../include/pkcs11-helper-1.0/cryptoki-win32.h \
+	../../include/pkcs11-helper-1.0/pkcs11-headers
+
+# The EXCLUDE_SYMLINKS tag can be used select whether or not files or 
+# directories that are symbolic links (a Unix filesystem 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 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, INPUT_FILTER 
+# is applied to all files.
+
+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
+
+#---------------------------------------------------------------------------
+# 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 and C++ comments will always remain visible.
+
+STRIP_CODE_COMMENTS    = YES
+
+# If the REFERENCED_BY_RELATION tag is set to YES (the default) 
+# then for each documented function all documented 
+# functions referencing it will be listed.
+
+REFERENCED_BY_RELATION = YES
+
+# If the REFERENCES_RELATION tag is set to YES (the default) 
+# then for each documented function all documented entities 
+# called/used by that function will be listed.
+
+REFERENCES_RELATION    = YES
+
+# 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 documentstion.
+
+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     = NO
+
+# 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.
+
+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            = Doxyfile_footer.html
+
+# 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 
+# stylesheet in the HTML output directory as well, or it will be erased!
+
+HTML_STYLESHEET        = 
+
+# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, 
+# files or namespaces will be aligned in HTML using tables. If set to 
+# NO a bullet list will be used.
+
+HTML_ALIGN_MEMBERS     = YES
+
+# 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 compressed 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 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
+
+# The DISABLE_INDEX tag can be used to turn on/off the condensed index at 
+# top of each HTML page. The value NO (the default) enables the index and 
+# the value YES disables it.
+
+DISABLE_INDEX          = NO
+
+# This tag can be used to set the number of enum values (range [1..20]) 
+# that doxygen will group on one line in the generated HTML documentation.
+
+ENUM_VALUES_PER_LINE   = 4
+
+# If the GENERATE_TREEVIEW tag 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 (for instance Mozilla 1.0+, 
+# Netscape 6.0+, Internet explorer 5.0+, or Konqueror). Windows users are 
+# probably better off using the HTML help feature.
+
+GENERATE_TREEVIEW      = NO
+
+# 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
+
+#---------------------------------------------------------------------------
+# 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.
+
+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, a4wide, 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           = 
+
+# 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         = NO
+
+# 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           = NO
+
+# 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
+
+#---------------------------------------------------------------------------
+# 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 stylesheet 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              = YES
+
+#---------------------------------------------------------------------------
+# 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 
+# in the INCLUDE_PATH (see below) will be search if 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.
+
+EXPAND_AS_DEFINED      = 
+
+# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then 
+# doxygen's preprocessor will remove all function-like macros that are alone 
+# on a line, have an all uppercase name, and do not end with a semicolon. Such 
+# function macros are typically used for boiler-plate code, and 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. 
+# Optionally an initial location of the external documentation 
+# can be added for each tagfile. 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. If a location is present for each tag, the installdox tool 
+# does not have to be run to correct the links.
+# 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        = NO
+
+# 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 is superseded by the HAVE_DOT option below. This is only a 
+# fallback. It is recommended to install and use dot, since it yields more 
+# powerful graphs.
+
+CLASS_DIAGRAMS         = YES
+
+# 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
+
+# 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 
+# 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               = NO
+
+# 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 tags 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 graphical hierarchy of all classes instead of a textual one.
+
+GRAPHICAL_HIERARCHY    = YES
+
+# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES 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 png, jpg, or gif
+# If left blank png will be used.
+
+DOT_IMAGE_FORMAT       = png
+
+# 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 MAX_DOT_GRAPH_WIDTH tag can be used to set the maximum allowed width 
+# (in pixels) of the graphs generated by dot. If a graph becomes larger than 
+# this value, doxygen will try to truncate the graph, so that it fits within 
+# the specified constraint. Beware that most browsers cannot cope with very 
+# large images.
+
+MAX_DOT_GRAPH_WIDTH    = 1024
+
+# The MAX_DOT_GRAPH_HEIGHT tag can be used to set the maximum allows height 
+# (in pixels) of the graphs generated by dot. If a graph becomes larger than 
+# this value, doxygen will try to truncate the graph, so that it fits within 
+# the specified constraint. Beware that most browsers cannot cope with very 
+# large images.
+
+MAX_DOT_GRAPH_HEIGHT   = 1024
+
+# 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 a graph may be further truncated if the graph's 
+# image dimensions are not sufficient to fit the graph (see MAX_DOT_GRAPH_WIDTH 
+# and MAX_DOT_GRAPH_HEIGHT). If 0 is used for the depth value (the default), 
+# the graph is not depth-constrained.
+
+MAX_DOT_GRAPH_DEPTH    = 0
+
+# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent 
+# background. This is disabled by default, which results in a white background. 
+# 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
+
+#---------------------------------------------------------------------------
+# Configuration::additions related to the search engine   
+#---------------------------------------------------------------------------
+
+# The SEARCHENGINE tag specifies whether or not a search engine should be 
+# used. If set to NO the values of all tags below this one will be ignored.
+
+SEARCHENGINE           = NO
diff --git a/doc/api/Doxyfile_footer.html b/doc/api/Doxyfile_footer.html
new file mode 100644
index 0000000..0620e74
--- /dev/null
+++ b/doc/api/Doxyfile_footer.html
@@ -0,0 +1,2 @@
+<hr>
+pkcs11-helper, Copyright (C) Alon Bar-Lev <alon.barlev at gmail.com>
diff --git a/doc/api/Makefile.am b/doc/api/Makefile.am
new file mode 100644
index 0000000..e392737
--- /dev/null
+++ b/doc/api/Makefile.am
@@ -0,0 +1,68 @@
+#
+# Copyright (c) 2005-2006 Alon Bar-Lev <alon.barlev at gmail.com>
+# All rights reserved.
+#
+# This software is available to you under a choice of one of two
+# licenses.  You may choose to be licensed under the terms of the GNU
+# General Public License (GPL) Version 2, or the OpenIB.org BSD license.
+#
+# GNU General Public License (GPL) Version 2
+# ===========================================
+#  This program is free software; you can redistribute it and/or modify
+#  it under the terms of the GNU General Public License version 2
+#  as published by the Free Software Foundation.
+#
+#  This program 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 General Public License for more details.
+#
+#  You should have received a copy of the GNU General Public License
+#  along with this program (see the file COPYING[.GPL2] included with this
+#  distribution); if not, write to the Free Software Foundation, Inc.,
+#  59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+#
+# OpenIB.org BSD license
+# =======================
+# Redistribution and use in source and binary forms, with or without modifi-
+# cation, are permitted provided that the following conditions are met:
+#
+#   o  Redistributions of source code must retain the above copyright notice,
+#      this list of conditions and the following disclaimer.
+#
+#   o  Redistributions in binary form must reproduce the above copyright no-
+#      tice, this list of conditions and the following disclaimer in the do-
+#      cumentation and/or other materials provided with the distribution.
+#
+#   o  The names of the contributors may not be used to endorse or promote
+#      products derived from this software without specific prior written
+#      permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# ``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 REGENTS OR CONTRIBUTORS BE LI-
+# ABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUEN-
+# TIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEV-
+# ER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABI-
+# LITY, 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.
+#
+
+EXTRA_DIST=Doxyfile Doxyfile_footer.html
+
+if ENABLE_DOC
+
+apidir=$(htmldir)/api
+api_DATA=api/html/*
+
+api/html/*:	$(EXTRA_DIST) ../../include/pkcs11-helper-1.0/*.h
+	-rm -fr api
+	$(DOXYGEN)
+
+clean-generic:
+	-rm -fr api
+
+endif
+
diff --git a/include/Makefile.am b/include/Makefile.am
new file mode 100644
index 0000000..a496bd1
--- /dev/null
+++ b/include/Makefile.am
@@ -0,0 +1,53 @@
+#
+# Copyright (c) 2005-2006 Alon Bar-Lev <alon.barlev at gmail.com>
+# All rights reserved.
+#
+# This software is available to you under a choice of one of two
+# licenses.  You may choose to be licensed under the terms of the GNU
+# General Public License (GPL) Version 2, or the OpenIB.org BSD license.
+#
+# GNU General Public License (GPL) Version 2
+# ===========================================
+#  This program is free software; you can redistribute it and/or modify
+#  it under the terms of the GNU General Public License version 2
+#  as published by the Free Software Foundation.
+#
+#  This program 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 General Public License for more details.
+#
+#  You should have received a copy of the GNU General Public License
+#  along with this program (see the file COPYING[.GPL2] included with this
+#  distribution); if not, write to the Free Software Foundation, Inc.,
+#  59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+#
+# OpenIB.org BSD license
+# =======================
+# Redistribution and use in source and binary forms, with or without modifi-
+# cation, are permitted provided that the following conditions are met:
+#
+#   o  Redistributions of source code must retain the above copyright notice,
+#      this list of conditions and the following disclaimer.
+#
+#   o  Redistributions in binary form must reproduce the above copyright no-
+#      tice, this list of conditions and the following disclaimer in the do-
+#      cumentation and/or other materials provided with the distribution.
+#
+#   o  The names of the contributors may not be used to endorse or promote
+#      products derived from this software without specific prior written
+#      permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# ``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 REGENTS OR CONTRIBUTORS BE LI-
+# ABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUEN-
+# TIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEV-
+# ER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABI-
+# LITY, 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.
+#
+
+SUBDIRS=pkcs11-helper-1.0
diff --git a/include/pkcs11-helper-1.0/Makefile.am b/include/pkcs11-helper-1.0/Makefile.am
new file mode 100644
index 0000000..de2b117
--- /dev/null
+++ b/include/pkcs11-helper-1.0/Makefile.am
@@ -0,0 +1,95 @@
+#
+# Copyright (c) 2005-2006 Alon Bar-Lev <alon.barlev at gmail.com>
+# All rights reserved.
+#
+# This software is available to you under a choice of one of two
+# licenses.  You may choose to be licensed under the terms of the GNU
+# General Public License (GPL) Version 2, or the OpenIB.org BSD license.
+#
+# GNU General Public License (GPL) Version 2
+# ===========================================
+#  This program is free software; you can redistribute it and/or modify
+#  it under the terms of the GNU General Public License version 2
+#  as published by the Free Software Foundation.
+#
+#  This program 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 General Public License for more details.
+#
+#  You should have received a copy of the GNU General Public License
+#  along with this program (see the file COPYING[.GPL2] included with this
+#  distribution); if not, write to the Free Software Foundation, Inc.,
+#  59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+#
+# OpenIB.org BSD license
+# =======================
+# Redistribution and use in source and binary forms, with or without modifi-
+# cation, are permitted provided that the following conditions are met:
+#
+#   o  Redistributions of source code must retain the above copyright notice,
+#      this list of conditions and the following disclaimer.
+#
+#   o  Redistributions in binary form must reproduce the above copyright no-
+#      tice, this list of conditions and the following disclaimer in the do-
+#      cumentation and/or other materials provided with the distribution.
+#
+#   o  The names of the contributors may not be used to endorse or promote
+#      products derived from this software without specific prior written
+#      permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# ``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 REGENTS OR CONTRIBUTORS BE LI-
+# ABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUEN-
+# TIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEV-
+# ER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABI-
+# LITY, 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.
+#
+
+myincdir=$(includedir)/pkcs11-helper-1.0
+
+SUBDIRS=pkcs11-headers
+
+myinc_HEADERS= \
+	cryptoki.h \
+	cryptoki-win32.h \
+	pkcs11h-def.h \
+	pkcs11h-engines.h \
+	pkcs11h-core.h
+noinst_HEADERS=
+
+if ENABLE_PKCS11H_CERTIFICATE
+myinc_HEADERS+=pkcs11h-certificate.h
+else
+noinst_HEADERS+=pkcs11h-certificate.h
+endif
+if ENABLE_PKCS11H_DATA
+myinc_HEADERS+=pkcs11h-data.h
+else
+noinst_HEADERS+=pkcs11h-data.h
+endif
+if ENABLE_PKCS11H_LOCATE
+myinc_HEADERS+=pkcs11h-locate.h
+else
+noinst_HEADERS+=pkcs11h-locate.h
+endif
+if ENABLE_PKCS11H_OPENSSL
+myinc_HEADERS+=pkcs11h-openssl.h
+else
+noinst_HEADERS+=pkcs11h-openssl.h
+endif
+if ENABLE_PKCS11H_STANDALONE
+myinc_HEADERS+=pkcs11h-standalone.h
+else
+noinst_HEADERS+=pkcs11h-standalone.h
+endif
+if ENABLE_PKCS11H_TOKEN
+myinc_HEADERS+=pkcs11h-token.h
+else
+noinst_HEADERS+=pkcs11h-token.h
+endif
+
diff --git a/include/pkcs11-helper-1.0/cryptoki-win32.h b/include/pkcs11-helper-1.0/cryptoki-win32.h
new file mode 100644
index 0000000..ff038f4
--- /dev/null
+++ b/include/pkcs11-helper-1.0/cryptoki-win32.h
@@ -0,0 +1,66 @@
+/* cryptoki.h include file for PKCS #11. */
+/* $Revision: 1.4 $ */
+
+/* License to copy and use this software is granted provided that it is
+ * identified as "RSA Security Inc. PKCS #11 Cryptographic Token Interface
+ * (Cryptoki)" in all material mentioning or referencing this software.
+
+ * License is also granted to make and use derivative works provided that
+ * such works are identified as "derived from the RSA Security Inc. PKCS #11
+ * Cryptographic Token Interface (Cryptoki)" in all material mentioning or 
+ * referencing the derived work.
+
+ * RSA Security Inc. makes no representations concerning either the 
+ * merchantability of this software or the suitability of this software for
+ * any particular purpose. It is provided "as is" without express or implied
+ * warranty of any kind.
+ */
+
+/* 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-helper-1.0/pkcs11-headers/pkcs11.h"
+
+#pragma pack(pop, cryptoki)
+
+#endif /* ___CRYPTOKI_H_INC___ */
diff --git a/include/pkcs11-helper-1.0/cryptoki.h b/include/pkcs11-helper-1.0/cryptoki.h
new file mode 100644
index 0000000..435a6cc
--- /dev/null
+++ b/include/pkcs11-helper-1.0/cryptoki.h
@@ -0,0 +1,35 @@
+/* cryptoki.h include file for PKCS #11. */
+/* $Revision: 1.4 $ */
+
+/* License to copy and use this software is granted provided that it is
+ * identified as "RSA Security Inc. PKCS #11 Cryptographic Token Interface
+ * (Cryptoki)" in all material mentioning or referencing this software.
+
+ * License is also granted to make and use derivative works provided that
+ * such works are identified as "derived from the RSA Security Inc. PKCS #11
+ * Cryptographic Token Interface (Cryptoki)" in all material mentioning or 
+ * referencing the derived work.
+
+ * RSA Security Inc. makes no representations concerning either the 
+ * merchantability of this software or the suitability of this software for
+ * any particular purpose. It is provided "as is" without express or implied
+ * warranty of any kind.
+ */
+
+#ifndef ___CRYPTOKI_H_INC___
+#define ___CRYPTOKI_H_INC___
+
+#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
+
+#include "pkcs11-helper-1.0/pkcs11-headers/pkcs11.h"
+
+#endif /* ___CRYPTOKI_H_INC___ */
diff --git a/include/pkcs11-helper-1.0/pkcs11-headers/Makefile.am b/include/pkcs11-helper-1.0/pkcs11-headers/Makefile.am
new file mode 100644
index 0000000..9b4b39d
--- /dev/null
+++ b/include/pkcs11-helper-1.0/pkcs11-headers/Makefile.am
@@ -0,0 +1,58 @@
+#
+# Copyright (c) 2005-2006 Alon Bar-Lev <alon.barlev at gmail.com>
+# All rights reserved.
+#
+# This software is available to you under a choice of one of two
+# licenses.  You may choose to be licensed under the terms of the GNU
+# General Public License (GPL) Version 2, or the OpenIB.org BSD license.
+#
+# GNU General Public License (GPL) Version 2
+# ===========================================
+#  This program is free software; you can redistribute it and/or modify
+#  it under the terms of the GNU General Public License version 2
+#  as published by the Free Software Foundation.
+#
+#  This program 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 General Public License for more details.
+#
+#  You should have received a copy of the GNU General Public License
+#  along with this program (see the file COPYING[.GPL2] included with this
+#  distribution); if not, write to the Free Software Foundation, Inc.,
+#  59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+#
+# OpenIB.org BSD license
+# =======================
+# Redistribution and use in source and binary forms, with or without modifi-
+# cation, are permitted provided that the following conditions are met:
+#
+#   o  Redistributions of source code must retain the above copyright notice,
+#      this list of conditions and the following disclaimer.
+#
+#   o  Redistributions in binary form must reproduce the above copyright no-
+#      tice, this list of conditions and the following disclaimer in the do-
+#      cumentation and/or other materials provided with the distribution.
+#
+#   o  The names of the contributors may not be used to endorse or promote
+#      products derived from this software without specific prior written
+#      permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# ``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 REGENTS OR CONTRIBUTORS BE LI-
+# ABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUEN-
+# TIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEV-
+# ER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABI-
+# LITY, 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.
+#
+
+myincdir=$(includedir)/pkcs11-helper-1.0/pkcs11-headers
+
+myinc_HEADERS= \
+	pkcs11.h \
+	pkcs11t.h \
+	pkcs11f.h
diff --git a/include/pkcs11-helper-1.0/pkcs11-headers/pkcs11.h b/include/pkcs11-helper-1.0/pkcs11-headers/pkcs11.h
new file mode 100644
index 0000000..6c61220
--- /dev/null
+++ b/include/pkcs11-helper-1.0/pkcs11-headers/pkcs11.h
@@ -0,0 +1,299 @@
+/* pkcs11.h include file for PKCS #11. */
+/* $Revision: 1.4 $ */
+
+/* License to copy and use this software is granted provided that it is
+ * identified as "RSA Security Inc. PKCS #11 Cryptographic Token Interface
+ * (Cryptoki)" in all material mentioning or referencing this software.
+
+ * License is also granted to make and use derivative works provided that
+ * such works are identified as "derived from the RSA Security Inc. PKCS #11
+ * Cryptographic Token Interface (Cryptoki)" in all material mentioning or 
+ * referencing the derived work.
+
+ * RSA Security Inc. makes no representations concerning either the 
+ * merchantability of this software or the suitability of this software for
+ * any particular purpose. It is provided "as is" without express or implied
+ * warranty of any kind.
+ */
+
+#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
+ */
+
+
+/* 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/include/pkcs11-helper-1.0/pkcs11-headers/pkcs11f.h b/include/pkcs11-helper-1.0/pkcs11-headers/pkcs11f.h
new file mode 100644
index 0000000..a479384
--- /dev/null
+++ b/include/pkcs11-helper-1.0/pkcs11-headers/pkcs11f.h
@@ -0,0 +1,912 @@
+/* pkcs11f.h include file for PKCS #11. */
+/* $Revision: 1.4 $ */
+
+/* License to copy and use this software is granted provided that it is
+ * identified as "RSA Security Inc. PKCS #11 Cryptographic Token Interface
+ * (Cryptoki)" in all material mentioning or referencing this software.
+
+ * License is also granted to make and use derivative works provided that
+ * such works are identified as "derived from the RSA Security Inc. PKCS #11
+ * Cryptographic Token Interface (Cryptoki)" in all material mentioning or 
+ * referencing the derived work.
+
+ * RSA Security Inc. makes no representations concerning either the 
+ * merchantability of this software or the suitability of this software for
+ * any particular purpose. It is provided "as is" without express or implied
+ * warranty of any kind.
+ */
+
+/* This header file 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/include/pkcs11-helper-1.0/pkcs11-headers/pkcs11t.h b/include/pkcs11-helper-1.0/pkcs11-headers/pkcs11t.h
new file mode 100644
index 0000000..b1a231a
--- /dev/null
+++ b/include/pkcs11-helper-1.0/pkcs11-headers/pkcs11t.h
@@ -0,0 +1,1685 @@
+/* pkcs11t.h include file for PKCS #11. */
+/* $Revision: 1.6 $ */
+
+/* License to copy and use this software is granted provided that it is
+ * identified as "RSA Security Inc. PKCS #11 Cryptographic Token Interface
+ * (Cryptoki)" in all material mentioning or referencing this software.
+
+ * License is also granted to make and use derivative works provided that
+ * such works are identified as "derived from the RSA Security Inc. PKCS #11
+ * Cryptographic Token Interface (Cryptoki)" in all material mentioning or
+ * referencing the derived work.
+
+ * RSA Security Inc. makes no representations concerning either the
+ * merchantability of this software or the suitability of this software for
+ * any particular purpose. It is provided "as is" without express or implied
+ * warranty of any kind.
+ */
+
+/* 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
+
+#define CK_TRUE 1
+#define CK_FALSE 0
+
+#ifndef CK_DISABLE_TRUE_FALSE
+#ifndef FALSE
+#define FALSE CK_FALSE
+#endif
+
+#ifndef TRUE
+#define TRUE CK_TRUE
+#endif
+#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. This flag is deprecated in v2.11 and
+   onwards. */
+#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
+/* Context specific (added in v2.20) */
+#define CKU_CONTEXT_SPECIFIC   2
+
+/* 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 */
+/* CKO_MECHANISM is new for v2.20 */
+#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_MECHANISM         0x00000007
+#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 */
+/* CKH_USER_INTERFACE is new for v2.20 */
+#define CKH_MONOTONIC_COUNTER  0x00000001
+#define CKH_CLOCK           0x00000002
+#define CKH_USER_INTERFACE  0x00000003
+#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
+
+/* BlowFish and TwoFish are new for v2.20 */
+#define CKK_BLOWFISH        0x00000020
+#define CKK_TWOFISH         0x00000021
+
+#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 */
+/* CKC_WTLS is new for v2.20 */
+#define CKC_X_509           0x00000000
+#define CKC_X_509_ATTR_CERT 0x00000001
+#define CKC_WTLS            0x00000002
+#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 CKF_ARRAY_ATTRIBUTE flag identifies an attribute which
+   consists of an array of values. */
+#define CKF_ARRAY_ATTRIBUTE    0x40000000
+
+/* 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
+
+/* CKA_CERTIFICATE_CATEGORY ...
+ * CKA_CHECK_VALUE are new for v2.20 */
+#define CKA_CERTIFICATE_CATEGORY        0x00000087
+#define CKA_JAVA_MIDP_SECURITY_DOMAIN   0x00000088
+#define CKA_URL                         0x00000089
+#define CKA_HASH_OF_SUBJECT_PUBLIC_KEY  0x0000008A
+#define CKA_HASH_OF_ISSUER_PUBLIC_KEY   0x0000008B
+#define CKA_CHECK_VALUE                 0x00000090
+
+#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_SUBPRIME_BITS      0x00000134
+#define CKA_SUB_PRIME_BITS     CKA_SUBPRIME_BITS
+/* (To retain backwards-compatibility) */
+
+#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,
+ * are new for v2.10. Deprecated in v2.11 and onwards. */
+#define CKA_SECONDARY_AUTH     0x00000200
+#define CKA_AUTH_PIN_FLAGS     0x00000201
+
+/* CKA_ALWAYS_AUTHENTICATE ...
+ * CKA_UNWRAP_TEMPLATE are new for v2.20 */
+#define CKA_ALWAYS_AUTHENTICATE  0x00000202
+
+#define CKA_WRAP_WITH_TRUSTED    0x00000210
+#define CKA_WRAP_TEMPLATE        (CKF_ARRAY_ATTRIBUTE|0x00000211)
+#define CKA_UNWRAP_TEMPLATE      (CKF_ARRAY_ATTRIBUTE|0x00000212)
+
+/* CKA_HW_FEATURE_TYPE, CKA_RESET_ON_INIT, and CKA_HAS_RESET
+ * are new for v2.10 */
+#define CKA_HW_FEATURE_TYPE    0x00000300
+#define CKA_RESET_ON_INIT      0x00000301
+#define CKA_HAS_RESET          0x00000302
+
+/* The following attributes are new for v2.20 */
+#define CKA_PIXEL_X                     0x00000400
+#define CKA_PIXEL_Y                     0x00000401
+#define CKA_RESOLUTION                  0x00000402
+#define CKA_CHAR_ROWS                   0x00000403
+#define CKA_CHAR_COLUMNS                0x00000404
+#define CKA_COLOR                       0x00000405
+#define CKA_BITS_PER_PIXEL              0x00000406
+#define CKA_CHAR_SETS                   0x00000480
+#define CKA_ENCODING_METHODS            0x00000481
+#define CKA_MIME_TYPES                  0x00000482
+#define CKA_MECHANISM_TYPE              0x00000500
+#define CKA_REQUIRED_CMS_ATTRIBUTES     0x00000501
+#define CKA_DEFAULT_CMS_ATTRIBUTES      0x00000502
+#define CKA_SUPPORTED_CMS_ATTRIBUTES    0x00000503
+#define CKA_ALLOWED_MECHANISMS          (CKF_ARRAY_ATTRIBUTE|0x00000600)
+
+#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
+
+/* CKM_SHA256/384/512 are new for v2.20 */
+#define CKM_SHA256_RSA_PKCS            0x00000040
+#define CKM_SHA384_RSA_PKCS            0x00000041
+#define CKM_SHA512_RSA_PKCS            0x00000042
+#define CKM_SHA256_RSA_PKCS_PSS        0x00000043
+#define CKM_SHA384_RSA_PKCS_PSS        0x00000044
+#define CKM_SHA512_RSA_PKCS_PSS        0x00000045
+
+#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
+
+/* the following four DES mechanisms are new for v2.20 */
+#define CKM_DES_OFB64                  0x00000150
+#define CKM_DES_OFB8                   0x00000151
+#define CKM_DES_CFB64                  0x00000152
+#define CKM_DES_CFB8                   0x00000153
+
+#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
+
+/* CKM_SHA256/384/512 are new for v2.20 */
+#define CKM_SHA256                     0x00000250
+#define CKM_SHA256_HMAC                0x00000251
+#define CKM_SHA256_HMAC_GENERAL        0x00000252
+#define CKM_SHA384                     0x00000260
+#define CKM_SHA384_HMAC                0x00000261
+#define CKM_SHA384_HMAC_GENERAL        0x00000262
+#define CKM_SHA512                     0x00000270
+#define CKM_SHA512_HMAC                0x00000271
+#define CKM_SHA512_HMAC_GENERAL        0x00000272
+
+/* 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
+
+/* CKM_TLS_PRF is new for v2.20 */
+#define CKM_TLS_PRF                    0x00000378
+
+#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
+
+/* CKM_SHA256/384/512 are new for v2.20 */
+#define CKM_SHA256_KEY_DERIVATION      0x00000393
+#define CKM_SHA384_KEY_DERIVATION      0x00000394
+#define CKM_SHA512_KEY_DERIVATION      0x00000395
+
+#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
+
+/* WTLS mechanisms are new for v2.20 */
+#define CKM_WTLS_PRE_MASTER_KEY_GEN         0x000003D0
+#define CKM_WTLS_MASTER_KEY_DERIVE          0x000003D1
+#define CKM_WTLS_MASTER_KEY_DERIVE_DH_ECC   0x000003D2
+#define CKM_WTLS_PRF                        0x000003D3
+#define CKM_WTLS_SERVER_KEY_AND_MAC_DERIVE  0x000003D4
+#define CKM_WTLS_CLIENT_KEY_AND_MAC_DERIVE  0x000003D5
+
+#define CKM_KEY_WRAP_LYNKS             0x00000400
+#define CKM_KEY_WRAP_SET_OAEP          0x00000401
+
+/* CKM_CMS_SIG is new for v2.20 */
+#define CKM_CMS_SIG                    0x00000500
+
+/* 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
+
+/* BlowFish and TwoFish are new for v2.20 */
+#define CKM_BLOWFISH_KEY_GEN           0x00001090
+#define CKM_BLOWFISH_CBC               0x00001091
+#define CKM_TWOFISH_KEY_GEN            0x00001092
+#define CKM_TWOFISH_CBC                0x00001093
+
+
+/* CKM_xxx_ENCRYPT_DATA mechanisms are new for v2.20 */
+#define CKM_DES_ECB_ENCRYPT_DATA       0x00001100
+#define CKM_DES_CBC_ENCRYPT_DATA       0x00001101
+#define CKM_DES3_ECB_ENCRYPT_DATA      0x00001102
+#define CKM_DES3_CBC_ENCRYPT_DATA      0x00001103
+#define CKM_AES_ECB_ENCRYPT_DATA       0x00001104
+#define CKM_AES_CBC_ENCRYPT_DATA       0x00001105
+
+#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 this version */
+
+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
+
+/* This is new to v2.20 */
+#define CKR_FUNCTION_REJECTED                 0x00000200
+
+#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 */
+/* CKG_MGF1_SHA256, CKG_MGF1_SHA384, and CKG_MGF1_SHA512
+ * are new for v2.20 */
+#define CKG_MGF1_SHA1         0x00000001
+#define CKG_MGF1_SHA256       0x00000002
+#define CKG_MGF1_SHA384       0x00000003
+#define CKG_MGF1_SHA512       0x00000004
+
+/* 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;
+
+typedef CK_RSA_PKCS_PSS_PARAMS CK_PTR CK_RSA_PKCS_PSS_PARAMS_PTR;
+
+/* CK_EC_KDF_TYPE is new for v2.11. */
+typedef CK_ULONG CK_EC_KDF_TYPE;
+
+/* The following EC Key Derivation Functions are defined */
+#define CKD_NULL                 0x00000001
+#define CKD_SHA1_KDF             0x00000002
+
+/* CK_ECDH1_DERIVE_PARAMS is new for v2.11.
+ * CK_ECDH1_DERIVE_PARAMS provides the parameters to the
+ * CKM_ECDH1_DERIVE and CKM_ECDH1_COFACTOR_DERIVE mechanisms,
+ * where each party contributes one key pair.
+ */
+typedef struct CK_ECDH1_DERIVE_PARAMS {
+  CK_EC_KDF_TYPE kdf;
+  CK_ULONG ulSharedDataLen;
+  CK_BYTE_PTR pSharedData;
+  CK_ULONG ulPublicDataLen;
+  CK_BYTE_PTR pPublicData;
+} CK_ECDH1_DERIVE_PARAMS;
+
+typedef CK_ECDH1_DERIVE_PARAMS CK_PTR CK_ECDH1_DERIVE_PARAMS_PTR;
+
+
+/* CK_ECDH2_DERIVE_PARAMS is new for v2.11.
+ * CK_ECDH2_DERIVE_PARAMS provides the parameters to the
+ * CKM_ECMQV_DERIVE mechanism, where each party contributes two key pairs. */
+typedef struct CK_ECDH2_DERIVE_PARAMS {
+  CK_EC_KDF_TYPE kdf;
+  CK_ULONG ulSharedDataLen;
+  CK_BYTE_PTR pSharedData;
+  CK_ULONG ulPublicDataLen;
+  CK_BYTE_PTR pPublicData;
+  CK_ULONG ulPrivateDataLen;
+  CK_OBJECT_HANDLE hPrivateData;
+  CK_ULONG ulPublicDataLen2;
+  CK_BYTE_PTR pPublicData2;
+} CK_ECDH2_DERIVE_PARAMS;
+
+typedef CK_ECDH2_DERIVE_PARAMS CK_PTR CK_ECDH2_DERIVE_PARAMS_PTR;
+
+typedef struct CK_ECMQV_DERIVE_PARAMS {
+  CK_EC_KDF_TYPE kdf;
+  CK_ULONG ulSharedDataLen;
+  CK_BYTE_PTR pSharedData;
+  CK_ULONG ulPublicDataLen;
+  CK_BYTE_PTR pPublicData;
+  CK_ULONG ulPrivateDataLen;
+  CK_OBJECT_HANDLE hPrivateData;
+  CK_ULONG ulPublicDataLen2;
+  CK_BYTE_PTR pPublicData2;
+  CK_OBJECT_HANDLE publicKey;
+} CK_ECMQV_DERIVE_PARAMS;
+
+typedef CK_ECMQV_DERIVE_PARAMS CK_PTR CK_ECMQV_DERIVE_PARAMS_PTR;
+
+/* Typedefs and defines for the CKM_X9_42_DH_KEY_PAIR_GEN and the
+ * CKM_X9_42_DH_PARAMETER_GEN mechanisms (new for PKCS #11 v2.11) */
+typedef CK_ULONG CK_X9_42_DH_KDF_TYPE;
+typedef CK_X9_42_DH_KDF_TYPE CK_PTR CK_X9_42_DH_KDF_TYPE_PTR;
+
+/* The following X9.42 DH key derivation functions are defined
+   (besides CKD_NULL already defined : */
+#define CKD_SHA1_KDF_ASN1        0x00000003
+#define CKD_SHA1_KDF_CONCATENATE 0x00000004
+
+/* CK_X9_42_DH1_DERIVE_PARAMS is new for v2.11.
+ * CK_X9_42_DH1_DERIVE_PARAMS provides the parameters to the
+ * CKM_X9_42_DH_DERIVE key derivation mechanism, where each party
+ * contributes one key pair */
+typedef struct CK_X9_42_DH1_DERIVE_PARAMS {
+  CK_X9_42_DH_KDF_TYPE kdf;
+  CK_ULONG ulOtherInfoLen;
+  CK_BYTE_PTR pOtherInfo;
+  CK_ULONG ulPublicDataLen;
+  CK_BYTE_PTR pPublicData;
+} CK_X9_42_DH1_DERIVE_PARAMS;
+
+typedef struct CK_X9_42_DH1_DERIVE_PARAMS CK_PTR CK_X9_42_DH1_DERIVE_PARAMS_PTR;
+
+/* CK_X9_42_DH2_DERIVE_PARAMS is new for v2.11.
+ * CK_X9_42_DH2_DERIVE_PARAMS provides the parameters to the
+ * CKM_X9_42_DH_HYBRID_DERIVE and CKM_X9_42_MQV_DERIVE key derivation
+ * mechanisms, where each party contributes two key pairs */
+typedef struct CK_X9_42_DH2_DERIVE_PARAMS {
+  CK_X9_42_DH_KDF_TYPE kdf;
+  CK_ULONG ulOtherInfoLen;
+  CK_BYTE_PTR pOtherInfo;
+  CK_ULONG ulPublicDataLen;
+  CK_BYTE_PTR pPublicData;
+  CK_ULONG ulPrivateDataLen;
+  CK_OBJECT_HANDLE hPrivateData;
+  CK_ULONG ulPublicDataLen2;
+  CK_BYTE_PTR pPublicData2;
+} CK_X9_42_DH2_DERIVE_PARAMS;
+
+typedef CK_X9_42_DH2_DERIVE_PARAMS CK_PTR CK_X9_42_DH2_DERIVE_PARAMS_PTR;
+
+typedef struct CK_X9_42_MQV_DERIVE_PARAMS {
+  CK_X9_42_DH_KDF_TYPE kdf;
+  CK_ULONG ulOtherInfoLen;
+  CK_BYTE_PTR pOtherInfo;
+  CK_ULONG ulPublicDataLen;
+  CK_BYTE_PTR pPublicData;
+  CK_ULONG ulPrivateDataLen;
+  CK_OBJECT_HANDLE hPrivateData;
+  CK_ULONG ulPublicDataLen2;
+  CK_BYTE_PTR pPublicData2;
+  CK_OBJECT_HANDLE publicKey;
+} CK_X9_42_MQV_DERIVE_PARAMS;
+
+typedef CK_X9_42_MQV_DERIVE_PARAMS CK_PTR CK_X9_42_MQV_DERIVE_PARAMS_PTR;
+
+/* 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_DES/AES_ECB/CBC_ENCRYPT_DATA_PARAMS are new for v2.20 */
+typedef struct CK_DES_CBC_ENCRYPT_DATA_PARAMS {
+  CK_BYTE      iv[8];
+  CK_BYTE_PTR  pData;
+  CK_ULONG     length;
+} CK_DES_CBC_ENCRYPT_DATA_PARAMS;
+
+typedef CK_DES_CBC_ENCRYPT_DATA_PARAMS CK_PTR CK_DES_CBC_ENCRYPT_DATA_PARAMS_PTR;
+
+typedef struct CK_AES_CBC_ENCRYPT_DATA_PARAMS {
+  CK_BYTE      iv[16];
+  CK_BYTE_PTR  pData;
+  CK_ULONG     length;
+} CK_AES_CBC_ENCRYPT_DATA_PARAMS;
+
+typedef CK_AES_CBC_ENCRYPT_DATA_PARAMS CK_PTR CK_AES_CBC_ENCRYPT_DATA_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;
+
+/* CK_TLS_PRF_PARAMS is new for version 2.20 */
+typedef struct CK_TLS_PRF_PARAMS {
+  CK_BYTE_PTR  pSeed;
+  CK_ULONG     ulSeedLen;
+  CK_BYTE_PTR  pLabel;
+  CK_ULONG     ulLabelLen;
+  CK_BYTE_PTR  pOutput;
+  CK_ULONG_PTR pulOutputLen;
+} CK_TLS_PRF_PARAMS;
+
+typedef CK_TLS_PRF_PARAMS CK_PTR CK_TLS_PRF_PARAMS_PTR;
+
+/* WTLS is new for version 2.20 */
+typedef struct CK_WTLS_RANDOM_DATA {
+  CK_BYTE_PTR pClientRandom;
+  CK_ULONG    ulClientRandomLen;
+  CK_BYTE_PTR pServerRandom;
+  CK_ULONG    ulServerRandomLen;
+} CK_WTLS_RANDOM_DATA;
+
+typedef CK_WTLS_RANDOM_DATA CK_PTR CK_WTLS_RANDOM_DATA_PTR;
+
+typedef struct CK_WTLS_MASTER_KEY_DERIVE_PARAMS {
+  CK_MECHANISM_TYPE   DigestMechanism;
+  CK_WTLS_RANDOM_DATA RandomInfo;
+  CK_BYTE_PTR         pVersion;
+} CK_WTLS_MASTER_KEY_DERIVE_PARAMS;
+
+typedef CK_WTLS_MASTER_KEY_DERIVE_PARAMS CK_PTR \
+  CK_WTLS_MASTER_KEY_DERIVE_PARAMS_PTR;
+
+typedef struct CK_WTLS_PRF_PARAMS {
+  CK_MECHANISM_TYPE DigestMechanism;
+  CK_BYTE_PTR       pSeed;
+  CK_ULONG          ulSeedLen;
+  CK_BYTE_PTR       pLabel;
+  CK_ULONG          ulLabelLen;
+  CK_BYTE_PTR       pOutput;
+  CK_ULONG_PTR      pulOutputLen;
+} CK_WTLS_PRF_PARAMS;
+
+typedef CK_WTLS_PRF_PARAMS CK_PTR CK_WTLS_PRF_PARAMS_PTR;
+
+typedef struct CK_WTLS_KEY_MAT_OUT {
+  CK_OBJECT_HANDLE hMacSecret;
+  CK_OBJECT_HANDLE hKey;
+  CK_BYTE_PTR      pIV;
+} CK_WTLS_KEY_MAT_OUT;
+
+typedef CK_WTLS_KEY_MAT_OUT CK_PTR CK_WTLS_KEY_MAT_OUT_PTR;
+
+typedef struct CK_WTLS_KEY_MAT_PARAMS {
+  CK_MECHANISM_TYPE       DigestMechanism;
+  CK_ULONG                ulMacSizeInBits;
+  CK_ULONG                ulKeySizeInBits;
+  CK_ULONG                ulIVSizeInBits;
+  CK_ULONG                ulSequenceNumber;
+  CK_BBOOL                bIsExport;
+  CK_WTLS_RANDOM_DATA     RandomInfo;
+  CK_WTLS_KEY_MAT_OUT_PTR pReturnedKeyMaterial;
+} CK_WTLS_KEY_MAT_PARAMS;
+
+typedef CK_WTLS_KEY_MAT_PARAMS CK_PTR CK_WTLS_KEY_MAT_PARAMS_PTR;
+
+/* CMS is new for version 2.20 */
+typedef struct CK_CMS_SIG_PARAMS {
+  CK_OBJECT_HANDLE      certificateHandle;
+  CK_MECHANISM_PTR      pSigningMechanism;
+  CK_MECHANISM_PTR      pDigestMechanism;
+  CK_UTF8CHAR_PTR       pContentType;
+  CK_BYTE_PTR           pRequestedAttributes;
+  CK_ULONG              ulRequestedAttributesLen;
+  CK_BYTE_PTR           pRequiredAttributes;
+  CK_ULONG              ulRequiredAttributesLen;
+} CK_CMS_SIG_PARAMS;
+
+typedef CK_CMS_SIG_PARAMS CK_PTR CK_CMS_SIG_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/include/pkcs11-helper-1.0/pkcs11h-certificate.h b/include/pkcs11-helper-1.0/pkcs11h-certificate.h
new file mode 100644
index 0000000..fc597cb
--- /dev/null
+++ b/include/pkcs11-helper-1.0/pkcs11h-certificate.h
@@ -0,0 +1,538 @@
+/*
+ * Copyright (c) 2005-2006 Alon Bar-Lev <alon.barlev at gmail.com>
+ * All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, or the OpenIB.org BSD license.
+ *
+ * GNU General Public License (GPL) Version 2
+ * ===========================================
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2
+ *  as published by the Free Software Foundation.
+ *
+ *  This program 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 General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program (see the file COPYING[.GPL2] included with this
+ *  distribution); if not, write to the Free Software Foundation, Inc.,
+ *  59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * OpenIB.org BSD license
+ * =======================
+ * Redistribution and use in source and binary forms, with or without modifi-
+ * cation, are permitted provided that the following conditions are met:
+ *
+ *   o  Redistributions of source code must retain the above copyright notice,
+ *      this list of conditions and the following disclaimer.
+ *
+ *   o  Redistributions in binary form must reproduce the above copyright no-
+ *      tice, this list of conditions and the following disclaimer in the do-
+ *      cumentation and/or other materials provided with the distribution.
+ *
+ *   o  The names of the contributors may not be used to endorse or promote
+ *      products derived from this software without specific prior written
+ *      permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``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 REGENTS OR CONTRIBUTORS BE LI-
+ * ABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUEN-
+ * TIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEV-
+ * ER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABI-
+ * LITY, 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.
+ */
+
+/**
+ * @file pkcs11h-certificate.h
+ * @brief pkcs11-helper certificate functions.
+ * @author Alon Bar-Lev <alon.barlev at gmail.com>
+ */
+
+#ifndef __PKCS11H_CERTIFICATE_H
+#define __PKCS11H_CERTIFICATE_H
+
+#include <pkcs11-helper-1.0/pkcs11h-core.h>
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+struct pkcs11h_certificate_id_s;
+struct pkcs11h_certificate_s;
+
+/**
+ * @brief Certificate id reference.
+ */
+typedef struct pkcs11h_certificate_id_s *pkcs11h_certificate_id_t;
+
+/**
+ * @brief Certificate object.
+ */
+typedef struct pkcs11h_certificate_s *pkcs11h_certificate_t;
+
+struct pkcs11h_certificate_id_list_s;
+
+/**
+ * @brief Certificate id list.
+ */
+typedef struct pkcs11h_certificate_id_list_s *pkcs11h_certificate_id_list_t;
+
+/**
+ * @brief Certificate id reference
+ */
+struct pkcs11h_certificate_id_s {
+	/** Token id */
+	pkcs11h_token_id_t token_id;
+
+	/** displayName for users */
+	char displayName[1024];
+	/** CKA_ID of object */
+	CK_BYTE_PTR attrCKA_ID;
+	/** CKA_ID size */
+	size_t attrCKA_ID_size;
+
+	/** Certificate blob (if available) */
+	unsigned char *certificate_blob;
+	/** Certificate blob size */
+	size_t certificate_blob_size;
+};
+
+/**
+ * @brief Certificate id list
+ */
+struct pkcs11h_certificate_id_list_s {
+	/** Next element */
+	pkcs11h_certificate_id_list_t next;
+	/** Certificate id */
+	pkcs11h_certificate_id_t certificate_id;
+};
+
+/**
+ * @brief Free certificate_id object.
+ * @param certificate_id	Certificate id.
+ * @return CK_RV.
+ */
+CK_RV
+pkcs11h_certificate_freeCertificateId (
+	IN pkcs11h_certificate_id_t certificate_id
+);
+
+/**
+ * @brief Duplicate certificate_id object.
+ * @param to	Target.
+ * @param from	Source.
+ * @return CK_RV.
+ * @note Caller must free result.
+ * @see pkcs11h_certificate_freeCertificateId().
+ */
+CK_RV
+pkcs11h_certificate_duplicateCertificateId (
+	OUT pkcs11h_certificate_id_t * const to,
+	IN const pkcs11h_certificate_id_t from
+);
+
+/**
+ * @brief Sets internal certificate_id blob.
+ * @param certificate_id	Certificate id object.
+ * @param blob			Certificate blob.
+ * @param blob_size		Certificate blob size.
+ * @return CK_RV.
+ * @remarks
+ * Useful to set after deserialization so certificate is available and not read from token.
+ */
+CK_RV
+pkcs11h_certificate_setCertificateIdCertificateBlob (
+	IN const pkcs11h_certificate_id_t certificate_id,
+	IN const unsigned char * const blob,
+	IN const size_t blob_size
+);
+
+/**
+ * @brief Free certificate object.
+ * @param certificate	Certificate object.
+ * @return CK_RV.
+ */
+CK_RV
+pkcs11h_certificate_freeCertificate (
+	IN pkcs11h_certificate_t certificate
+);
+
+/**
+ * @brief Create a certificate object out of certificate_id.
+ * @param certificate_id	Certificate id object to be based on.
+ * @param user_data		Optional user data, to be passed to hooks.
+ * @param mask_prompt		Allow prompt.
+ * @param pin_cache_period	Session specific cache period.
+ * @param p_certificate		Receives certificate object.
+ * @note Caller must free result.
+ * @see pkcs11h_certificate_freeCertificate().
+ * @remarks
+ * The certificate id object may not specify the certificate blob.
+ */	
+CK_RV
+pkcs11h_certificate_create (
+	IN const pkcs11h_certificate_id_t certificate_id,
+	IN void * const user_data,
+	IN const unsigned mask_prompt,
+	IN const int pin_cache_period,
+	OUT pkcs11h_certificate_t * const p_certificate
+);
+
+/**
+ * @brief Extract user data out of certificate.
+ * @param certificate	Certificate object.
+ * @return Mask prompt @ref PKCS11H_PROMPT_MASK.
+ */
+unsigned
+pkcs11h_certificate_getPromptMask (
+	IN const pkcs11h_certificate_t certificate
+);
+
+/**
+ * @brief Extract user data out of certificate.
+ * @param certificate	Certificate object.
+ * @param mask_prompt	Allow prompt @ref PKCS11H_PROMPT_MASK.
+ */
+void
+pkcs11h_certificate_setPromptMask (
+	IN const pkcs11h_certificate_t certificate,
+	IN const unsigned mask_prompt
+);
+
+/**
+ * @brief Extract user data out of certificate.
+ * @param certificate	Certificate object.
+ * @return User data.
+ */
+void *
+pkcs11h_certificate_getUserData (
+	IN const pkcs11h_certificate_t certificate
+);
+
+/**
+ * @brief Extract user data out of certificate.
+ * @param certificate	Certificate object.
+ * @param user_data	Optional user data, to be passed to hooks.
+ */
+void
+pkcs11h_certificate_setUserData (
+	IN const pkcs11h_certificate_t certificate,
+	IN void * const user_data
+);
+
+/**
+ * @brief Get certifiate id object out of a certifiate.
+ * @param certificate		Certificate object.
+ * @param p_certificate_id	Certificate id object pointer.
+ * @return CK_RV.
+ * @note Caller must free result.
+ * @see pkcs11h_certificate_freeCertificateId().
+ */
+CK_RV
+pkcs11h_certificate_getCertificateId (
+	IN const pkcs11h_certificate_t certificate,
+	OUT pkcs11h_certificate_id_t * const p_certificate_id
+);
+
+/**
+ * @brief Get the certificate blob out of the certificate object.
+ * @param certificate			Certificate object.
+ * @param certificate_blob		Buffer.
+ * @param p_certificate_blob_size	Buffer size.
+ * @return CK_RV.
+ * @note certificate_blob may be NULL in order to get size.
+ */
+CK_RV
+pkcs11h_certificate_getCertificateBlob (
+	IN const pkcs11h_certificate_t certificate,
+	OUT unsigned char * const certificate_blob,
+	IN OUT size_t * const p_certificate_blob_size
+);
+
+/**
+ * @brief Serialize certificate_id into a string
+ * @param sz			Output string.
+ * @param max			Max buffer size.
+ * @param certificate_id	id to serialize
+ * @return CK_RV.
+ * @note sz may be NULL in order to get size.
+ */
+CK_RV
+pkcs11h_certificate_serializeCertificateId (
+	OUT char * const sz,
+	IN OUT size_t *max,
+	IN const pkcs11h_certificate_id_t certificate_id
+);
+
+/**
+ * @brief Deserialize certificate_id out of string.
+ * @param p_certificate_id	id.
+ * @param sz			Inut string
+ * @return CK_RV.
+ * @note Caller must free result.
+ * @see pkcs11h_certificate_freeCertificateId().
+ */
+CK_RV
+pkcs11h_certificate_deserializeCertificateId (
+	OUT pkcs11h_certificate_id_t * const p_certificate_id,
+	IN const char * const sz
+);
+
+/**
+ * @brief Ensure certificate is accessible.
+ * @param certificate		Certificate object.
+ * @return CK_RV.
+ */
+CK_RV
+pkcs11h_certificate_ensureCertificateAccess (
+	IN const pkcs11h_certificate_t certificate
+);
+
+/**
+ * @brief Ensure key is accessible.
+ * @param certificate		Certificate object.
+ * @return CK_RV.
+ */
+CK_RV
+pkcs11h_certificate_ensureKeyAccess (
+	IN const pkcs11h_certificate_t certificate
+);
+
+/**
+ * @brief Lock session for threded environment.
+ * @param certificate		Certificate object.
+ * @return CK_RV.
+ * @remarks
+ * This must be called on threaded environment, so both calls to _sign and
+ * _signRecover and _decrypt will be from the same source.
+ * Failing to lock session, will result with CKR_OPERATION_ACTIVE if
+ * provider is good, or unexpected behaviour for others.
+ * @remarks
+ * It is save to call this also in none threaded environment, it will do nothing.
+ * Call this also if you are doing one stage operation, since locking is not
+ * done by method.
+ */
+CK_RV
+pkcs11h_certificate_lockSession (
+	IN const pkcs11h_certificate_t certificate
+);
+
+/**
+ * @brief Releases session lock.
+ * @param certificate		Certificate object.
+ * @return CK_RV.
+ * @see pkcs11h_certificate_lockSession().
+ */
+CK_RV
+pkcs11h_certificate_releaseSession (
+	IN const pkcs11h_certificate_t certificate
+);
+
+/**
+ * @brief Sign data.
+ * @param certificate		Certificate object.
+ * @param mech_type		PKCS#11 mechanism.
+ * @param source		Buffer to sign.
+ * @param source_size		Buffer size.
+ * @param target		Target buffer.
+ * @param p_target_size		Target buffer size.
+ * @return CK_RV.
+ * @note target may be NULL to get size.
+ * @attention When using in threaded environment session must be locked.
+ * @see pkcs11h_certificate_lockSession().
+ * @see pkcs11h_certificate_signAny().
+ */
+CK_RV
+pkcs11h_certificate_sign (
+	IN const pkcs11h_certificate_t certificate,
+	IN const CK_MECHANISM_TYPE mech_type,
+	IN const unsigned char * const source,
+	IN const size_t source_size,
+	OUT unsigned char * const target,
+	IN OUT size_t * const p_target_size
+);
+
+/**
+ * @brief Sign data.
+ * @param certificate		Certificate object.
+ * @param mech_type		PKCS#11 mechanism.
+ * @param source		Buffer to sign.
+ * @param source_size		Buffer size.
+ * @param target		Target buffer.
+ * @param p_target_size		Target buffer size.
+ * @return CK_RV.
+ * @note target may be NULL to get size.
+ * @attention When using in threaded environment session must be locked.
+ * @see pkcs11h_certificate_lockSession().
+ * @see pkcs11h_certificate_signAny().
+ */
+CK_RV
+pkcs11h_certificate_signRecover (
+	IN const pkcs11h_certificate_t certificate,
+	IN const CK_MECHANISM_TYPE mech_type,
+	IN const unsigned char * const source,
+	IN const size_t source_size,
+	OUT unsigned char * const target,
+	IN OUT size_t * const p_target_size
+);
+
+/**
+ * @brief Decrypt data.
+ * @param certificate		Certificate object.
+ * @param mech_type		PKCS#11 mechanism.
+ * @param source		Buffer to sign.
+ * @param source_size		Buffer size.
+ * @param target		Target buffer.
+ * @param p_target_size		Target buffer size.
+ * @return CK_RV.
+ * @note target may be NULL to get size.
+ * @attention When using in threaded environment session must be locked.
+ * @see pkcs11h_certificate_lockSession().
+ */
+CK_RV
+pkcs11h_certificate_decrypt (
+	IN const pkcs11h_certificate_t certificate,
+	IN const CK_MECHANISM_TYPE mech_type,
+	IN const unsigned char * const source,
+	IN const size_t source_size,
+	OUT unsigned char * const target,
+	IN OUT size_t * const p_target_size
+);
+
+/**
+ * @brief Decrypt data.
+ * @param certificate		Certificate object.
+ * @param mech_type		PKCS#11 mechanism.
+ * @param source		Buffer to sign.
+ * @param source_size		Buffer size.
+ * @param target		Target buffer.
+ * @param p_target_size		Target buffer size.
+ * @return CK_RV.
+ * @note target may be NULL to get size.
+ * @attention When using in threaded environment session must be locked.
+ * @see pkcs11h_certificate_lockSession().
+ */
+CK_RV
+pkcs11h_certificate_unwrap (
+	IN const pkcs11h_certificate_t certificate,
+	IN const CK_MECHANISM_TYPE mech_type,
+	IN const unsigned char * const source,
+	IN const size_t source_size,
+	OUT unsigned char * const target,
+	IN OUT size_t * const p_target_size
+);
+
+/**
+ * @brief Sign data mechanism determined by key attributes.
+ * @param certificate		Certificate object.
+ * @param mech_type		PKCS#11 mechanism.
+ * @param source		Buffer to sign.
+ * @param source_size		Buffer size.
+ * @param target		Target buffer.
+ * @param p_target_size		Target buffer size.
+ * @return CK_RV.
+ * @note target may be NULL to get size.
+ * @attention When using in threaded environment session must be locked.
+ * @see pkcs11h_certificate_lockSession().
+ */
+CK_RV
+pkcs11h_certificate_signAny (
+	IN const pkcs11h_certificate_t certificate,
+	IN const CK_MECHANISM_TYPE mech_type,
+	IN const unsigned char * const source,
+	IN const size_t source_size,
+	OUT unsigned char * const target,
+	IN OUT size_t * const p_target_size
+);
+
+/**
+ * @brief Decrypt data mechanism determined by key attributes.
+ * @param certificate		Certificate object.
+ * @param mech_type		PKCS#11 mechanism.
+ * @param source		Buffer to sign.
+ * @param source_size		Buffer size.
+ * @param target		Target buffer.
+ * @param p_target_size		Target buffer size.
+ * @return CK_RV.
+ * @note target may be NULL to get size.
+ * @attention When using in threaded environment session must be locked.
+ * @see pkcs11h_certificate_lockSession().
+ */
+CK_RV
+pkcs11h_certificate_decryptAny (
+	IN const pkcs11h_certificate_t certificate,
+	IN const CK_MECHANISM_TYPE mech_type,
+	IN const unsigned char * const source,
+	IN const size_t source_size,
+	OUT unsigned char * const target,
+	IN OUT size_t * const p_target_size
+);
+
+/**
+ * @brief Free certificate_id list.
+ * @param cert_id_list		List.
+ * @return CK_RV.
+ */
+CK_RV
+pkcs11h_certificate_freeCertificateIdList (
+	IN const pkcs11h_certificate_id_list_t cert_id_list
+);
+
+/**
+ * @brief Enumerate available certificates on specific token
+ * @param token_id			Token id to enum.
+ * @param method			How to fetch certificates @ref PKCS11H_ENUM_METHOD.
+ * @param user_data			Some user specific data.
+ * @param mask_prompt			Allow prompt @ref PKCS11H_PROMPT_MASK.
+ * @param p_cert_id_issuers_list	Receives issues list.
+ * @param p_cert_id_end_list		Receives end certificates list.
+ * @return CK_RV.
+ * @note p_cert_id_issuers_list may be NULL.
+ * @note Caller must free result.
+ * @note This function will likely take long time.
+ * @see pkcs11h_certificate_freeCertificateIdList().
+ */
+CK_RV
+pkcs11h_certificate_enumTokenCertificateIds (
+	IN const pkcs11h_token_id_t token_id,
+	IN const int method,
+	IN void * const user_data,
+	IN const unsigned mask_prompt,
+	OUT pkcs11h_certificate_id_list_t * const p_cert_id_issuers_list,
+	OUT pkcs11h_certificate_id_list_t * const p_cert_id_end_list
+);
+
+/**
+ * @brief Enumerate available certificates.
+ * @param method			How to fetch certificates @ref PKCS11H_ENUM_METHOD.
+ * @param user_data			Some user specific data.
+ * @param mask_prompt			Allow prompt @ref PKCS11H_PROMPT_MASK.
+ * @param p_cert_id_issuers_list	Receives issues list.
+ * @param p_cert_id_end_list		Receives end certificates list.
+ * @note p_cert_id_issuers_list may be NULL.
+ * @note Caller must free result.
+ * @note This function will likely take long time.
+ * @see pkcs11h_certificate_freeCertificateIdList().
+ */
+CK_RV
+pkcs11h_certificate_enumCertificateIds (
+	IN const int method,
+	IN void * const user_data,
+	IN const unsigned mask_prompt,
+	OUT pkcs11h_certificate_id_list_t * const p_cert_id_issuers_list,
+	OUT pkcs11h_certificate_id_list_t * const p_cert_id_end_list
+);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif				/* __PKCS11H_CERTIFICATE_H */
diff --git a/include/pkcs11-helper-1.0/pkcs11h-core.h b/include/pkcs11-helper-1.0/pkcs11h-core.h
new file mode 100644
index 0000000..9338f67
--- /dev/null
+++ b/include/pkcs11-helper-1.0/pkcs11h-core.h
@@ -0,0 +1,539 @@
+/**
+ * @page License License
+ * @code
+ * Copyright (c) 2005-2006 Alon Bar-Lev <alon.barlev at gmail.com>
+ * All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, or the OpenIB.org BSD license.
+ *
+ * GNU General Public License (GPL) Version 2
+ * ===========================================
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2
+ *  as published by the Free Software Foundation.
+ *
+ *  This program 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 General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program (see the file COPYING[.GPL2] included with this
+ *  distribution); if not, write to the Free Software Foundation, Inc.,
+ *  59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * OpenIB.org BSD license
+ * =======================
+ * Redistribution and use in source and binary forms, with or without modifi-
+ * cation, are permitted provided that the following conditions are met:
+ *
+ *   o  Redistributions of source code must retain the above copyright notice,
+ *      this list of conditions and the following disclaimer.
+ *
+ *   o  Redistributions in binary form must reproduce the above copyright no-
+ *      tice, this list of conditions and the following disclaimer in the do-
+ *      cumentation and/or other materials provided with the distribution.
+ *
+ *   o  The names of the contributors may not be used to endorse or promote
+ *      products derived from this software without specific prior written
+ *      permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``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 REGENTS OR CONTRIBUTORS BE LI-
+ * ABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUEN-
+ * TIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEV-
+ * ER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABI-
+ * LITY, 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.
+ * @endcode
+ */
+
+/**
+ * @mainpage pkcs11-helper-1.0
+ * @par About
+ * <a href="http://www.rsasecurity.com/rsalabs/pkcs/pkcs-11">PKCS#11</a> 
+ * is
+ * <a href="http://www.rsasecurity.com">RSA Security</a>
+ * published standard. PKCS#11 is the de-facto standard to access cryptographic
+ * devices.
+ * @par
+ * pkcs11-helper is a library that provides simplified interaction with PKCS#11
+ * providers for user applications.
+ * @par Features
+ * pkcs11-helper allows using multiple PKCS#11 providers at the same time, selecting 
+ * keys by id, label or certificate subject, handling card removal and card insert
+ * events, handling card re-insert to a different slot, supporting session expiration
+ * serialization and much more, all using a simple API.
+ * @par
+ * pkcs11-helper is not designed to manage card content, since object attributes
+ * are usually vendor specific, and 99% of application need to access
+ * existing objects in order to perform signature and decryption.
+ * @par The following modules are available:
+ * - @ref pkcs11h-core.h "Core" - Initialize library, adding providers, hooks.
+ * - @ref pkcs11h-token.h "Token" - Handle tokens.
+ * - @ref pkcs11h-certificate.h "Certificate" - Handle certificate objects.
+ * - @ref pkcs11h-data.h "Data" - Handle data objects.
+ * - @ref pkcs11h-locate.h "Locate" - Simplified object locate interface.
+ * - @ref pkcs11h-openssl.h "OpenSSL" - OpenSSL engine support.
+ * - @ref pkcs11h-standalone.h "Standalone Debugging" - Token structure debugging interface.
+ * @par Compatability
+ * - The pkcs11-helper is available in POSIX complient systems and WIN32.
+ * - pkcs11-helper should work with almost every PKCS#11 provider, since it
+ *   uses the minimum features of the provider.
+ * @par License
+ * @ref License is dual BSD or GPL.
+ */
+
+/**
+ * @file pkcs11h-core.h
+ * @brief pkcs11-helper core.
+ * @author Alon Bar-Lev <alon.barlev at gmail.com>
+ */
+
+#ifndef __PKCS11H_BASE_H
+#define __PKCS11H_BASE_H
+
+#include <stdarg.h>
+#include <time.h>
+
+#include <pkcs11-helper-1.0/pkcs11h-def.h>
+#include <pkcs11-helper-1.0/pkcs11h-engines.h>
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+/** Static pkcs11-helper library version */
+#define PKCS11H_VERSION	0x00010000
+
+/**
+ * @brief pkcs11-helper features mask.
+ * @addtogroup PKCS11H_FEATURE_MASK
+ * @see pkcs11h_getFeatures().
+ * @{
+ */
+/** Engine OpenSSL is enabled. */
+#define PKCS11H_FEATURE_MASK_ENGINE_OPENSSL	(1<< 0)
+/** Engine GNUTLS is enabled. */
+#define PKCS11H_FEATURE_MASK_ENGINE_GNUTLS	(1<< 1)
+/** Debugging (logging) is enabled. */
+#define PKCS11H_FEATURE_MASK_DEBUG		(1<< 2)
+/** Threading support is enabled. */
+#define PKCS11H_FEATURE_MASK_THREADING		(1<< 3)
+/** Token interface is enabled. */
+#define PKCS11H_FEATURE_MASK_TOKEN		(1<< 4)
+/** Data interface is enabled. */
+#define PKCS11H_FEATURE_MASK_DATA		(1<< 5)
+/** Certificate interface is enabled, */
+#define PKCS11H_FEATURE_MASK_CERTIFICATE	(1<< 6)
+/** Locate interface is enabled. */
+#define PKCS11H_FEATURE_MASK_LOCATE		(1<< 7)
+/** Slotevent interface is enabled. */
+#define PKCS11H_FEATURE_MASK_SLOTEVENT		(1<< 8)
+/** OpenSSL interface is enabled. */
+#define PKCS11H_FEATURE_MASK_OPENSSL		(1<< 9)
+/** Standalone interface is enabled. */
+#define PKCS11H_FEATURE_MASK_STANDALONE		(1<<10)
+/** @} */
+
+/**
+ * @brief pkcs11-helper log level.
+ * @addtogroup PKCS11H_LOG
+ * @see pkcs11h_getLogLevel().
+ * @see pkcs11h_setLogLevel().
+ * @{
+ */
+/** Most verbose log (entry/return). */
+#define PKCS11H_LOG_DEBUG2	5
+/** Important logic log. */
+#define PKCS11H_LOG_DEBUG1	4
+/** Information messages. */
+#define PKCS11H_LOG_INFO	3
+/** Warning messages, */
+#define PKCS11H_LOG_WARN	2
+/** Error messages. */
+#define PKCS11H_LOG_ERROR	1
+/** Used in order to turn off logging. */
+#define PKCS11H_LOG_QUITE	0
+/** @} */
+
+/** Inifite session limit */
+#define PKCS11H_PIN_CACHE_INFINITE	-1
+
+/**
+ * @brief Signature mask selection.
+ * @addtogroup PKCS11H_PRIVATEMODE_MASK
+ * @{
+ */
+/** Auto select by private key attributes. */
+#define PKCS11H_PRIVATEMODE_MASK_AUTO		(0)
+/** Force signature. */
+#define PKCS11H_PRIVATEMODE_MASK_SIGN		(1<<0)
+/** Force recover. */
+#define PKCS11H_PRIVATEMODE_MASK_RECOVER	(1<<1)
+/** Force decrypt. */
+#define PKCS11H_PRIVATEMODE_MASK_DECRYPT	(1<<2)
+/** Force unwrap. */
+#define PKCS11H_PRIVATEMODE_MASK_UNWRAP		(1<<3)
+/** @} */
+
+/**
+ * @brief Slotevent mode selection.
+ * @addtogroup PKCS11H_SLOTEVENT_METHOD
+ * @{
+ */
+/* Auto select by provider information. */
+#define PKCS11H_SLOTEVENT_METHOD_AUTO		0
+/** Force trigger. */
+#define PKCS11H_SLOTEVENT_METHOD_TRIGGER	1
+/** Force poll. */
+#define PKCS11H_SLOTEVENT_METHOD_POLL		2
+/** @} */
+
+/**
+ * @brief Prompt mask selection.
+ * @addtogroup PKCS11H_PROMPT_MASK
+ * @{
+ */
+/** Allow PIN prompt. */
+#define PKCS11H_PROMPT_MASK_ALLOW_PIN_PROMPT	(1<<0)
+/** Allow token prompt. */
+#define PKCS11H_PROMPT_MASK_ALLOW_TOKEN_PROMPT	(1<<1)
+/** Allow all prompt. */
+#define PKCS11H_PROMPT_MASK_ALLOW_ALL ( \
+		PKCS11H_PROMPT_MASK_ALLOW_PIN_PROMPT | \
+		PKCS11H_PROMPT_MASK_ALLOW_TOKEN_PROMPT \
+	)
+/** @} */
+
+/**
+ * @brief Enumeration mode selection.
+ * @addtogroup PKCS11H_ENUM_METHOD
+ * @{
+ */
+/** Get from cache, if available. */
+#define PKCS11H_ENUM_METHOD_CACHE               0
+/** Get from cache, but only available objects. */
+#define PKCS11H_ENUM_METHOD_CACHE_EXIST         1
+/** Reload objects. */
+#define PKCS11H_ENUM_METHOD_RELOAD              2
+/** @} */
+
+struct pkcs11h_token_id_s;
+
+/**
+ * @brief Token identifier.
+ */
+typedef struct pkcs11h_token_id_s *pkcs11h_token_id_t;
+
+/**
+ * @brief Log hook.
+ * @param global_data	Hook data.
+ * @param flags		Log flags.
+ * @param format	printf style format.
+ * @param args		stdargs
+ */
+typedef void (*pkcs11h_hook_log_t)(
+	IN void * const global_data,
+	IN const unsigned flags,
+	IN const char * const format,
+	IN va_list args
+);
+
+/**
+ * @brief Slotevent hook.
+ * @param global_data	Hook data.
+ */
+typedef void (*pkcs11h_hook_slotevent_t)(
+	IN void * const global_data
+);
+
+/**
+ * @brief Token prompt hook.
+ * @param global_data	Hook data.
+ * @param user_data	Local data.
+ * @param token		Token.
+ * @param retry		Retry counter.
+ * @return TRUE success.
+ */
+typedef PKCS11H_BOOL (*pkcs11h_hook_token_prompt_t)(
+	IN void * const global_data,
+	IN void * const user_data,
+	IN const pkcs11h_token_id_t token,
+	IN const unsigned retry
+);
+
+/**
+ * @brief PIN prompt hook.
+ * @param global_data	Hook data.
+ * @param user_data	Local data.
+ * @param token		Token.
+ * @param retry		Retry counter.
+ * @param pin		PIN buffer.
+ * @param pin_max	PIN buffer size.
+ * @return TRUE success.
+ */
+typedef PKCS11H_BOOL (*pkcs11h_hook_pin_prompt_t)(
+	IN void * const global_data,
+	IN void * const user_data,
+	IN const pkcs11h_token_id_t token,
+	IN const unsigned retry,
+	OUT char * const pin,
+	IN const size_t pin_max
+);
+
+/**
+ * @brief Token identifier.
+ */
+struct pkcs11h_token_id_s {
+	/** Display for user. */
+	char display[1024];
+	/** NULL terminated manufacturerID */
+	char manufacturerID[sizeof (((CK_TOKEN_INFO *)NULL)->manufacturerID)+1];
+	/** NULL terminated model */
+	char model[sizeof (((CK_TOKEN_INFO *)NULL)->model)+1];
+	/** NULL terminated serialNumber */
+	char serialNumber[sizeof (((CK_TOKEN_INFO *)NULL)->serialNumber)+1];
+	/** NULL terminated label */
+	char label[sizeof (((CK_TOKEN_INFO *)NULL)->label)+1];
+};
+
+/**
+ * @brief Get message by return value.
+ * @param rv	Return value.
+ * @return CK_RV.
+ */
+const char *
+pkcs11h_getMessage (
+	IN const CK_RV rv
+);
+
+/**
+ * @brief Set system engine to be used.
+ * @param engine	Engine to use.
+ * @return CK_RV.
+ * @note Must be called before pkcs11h_initialize.
+ * @note Default engine is libc functions.
+ */
+CK_RV
+pkcs11h_engine_setSystem (
+	IN const pkcs11h_engine_system_t * const engine
+);
+
+/**
+ * @brief Set crypto engine to be used.
+ * @param engine	Engine to use.
+ * @return CK_RV.
+ * @note Must be called before pkcs11h_initialize.
+ * @note Default is provided at configuration time.
+ */
+CK_RV
+pkcs11h_engine_setCrypto (
+	IN const pkcs11h_engine_crypto_t * const engine
+);
+
+/**
+ * @brief Get version of library.
+ * @return version identifier.
+ */
+unsigned int
+pkcs11h_getVersion (void);
+
+/**
+ * @brief Get features of library.
+ * @return feature mask @ref PKCS11H_FEATURE_MASK.
+ */
+unsigned int
+pkcs11h_getFeatures (void);
+
+/**
+ * @brief Inititalize helper interface.
+ * @return CK_RV.
+ * @see pkcs11h_terminate().
+ * @attention This function must be called from the main thread.
+ */
+CK_RV
+pkcs11h_initialize (void);
+
+/**
+ * @brief Terminate helper interface.
+ * @return CK_RV.
+ * @attention This function must be called from the main thread.
+ */
+CK_RV
+pkcs11h_terminate (void);
+
+/**
+ * @brief Set current log level of the helper.
+ * @param flags	Current log level @ref PKCS11H_LOG.
+ */
+void
+pkcs11h_setLogLevel (
+	IN const unsigned flags
+);
+
+/**
+ * @brief Get current log level.
+ * @return Log level @ref PKCS11H_LOG.
+ */
+unsigned
+pkcs11h_getLogLevel (void);
+
+/**
+ * @brief Set a log callback.
+ * @param hook		Callback.
+ * @param global_data	Data to send to callback.
+ * @return CK_RV.
+ */
+CK_RV
+pkcs11h_setLogHook (
+	IN const pkcs11h_hook_log_t hook,
+	IN void * const global_data
+);
+
+/**
+ * @brief Set a slot event callback.
+ * @param hook		Callback.
+ * @param global_data	Data to send to callback.
+ * @return CK_RV.
+ * @see pkcs11h_terminate().
+ * @attention
+ * Calling this function initialize slot event notifications, these
+ * notifications can be started, but never terminate due to PKCS#11 limitation.
+ * @note In order to use slot events you must have threading @ref PKCS11H_FEATURE_MASK_THREADING enabled.
+ */
+CK_RV
+pkcs11h_setSlotEventHook (
+	IN const pkcs11h_hook_slotevent_t hook,
+	IN void * const global_data
+);
+
+/**
+ * @brief Set a token prompt callback.
+ * @param hook		Callback.
+ * @param global_data	Data to send to callback.
+ * @return CK_RV.
+ */
+CK_RV
+pkcs11h_setTokenPromptHook (
+	IN const pkcs11h_hook_token_prompt_t hook,
+	IN void * const global_data
+);
+
+/**
+ * @brief Set a pin prompt callback.
+ * @param hook	Callback.
+ * @param global_data	Data to send to callback.
+ * @return CK_RV.
+ */
+CK_RV
+pkcs11h_setPINPromptHook (
+	IN const pkcs11h_hook_pin_prompt_t hook,
+	IN void * const global_data
+);
+
+/**
+ * @brief Set global protected authentication mode.
+ * @param allow_protected_auth	Allow protected authentication if enabled by token.
+ * @return CK_RV.
+ * @note Default is on.
+ */
+CK_RV
+pkcs11h_setProtectedAuthentication (
+	IN const PKCS11H_BOOL allow_protected_auth
+);
+
+/**
+ * @brief Set global PIN cache timeout.
+ * @param pin_cache_period	Cache period in seconds, or @ref PKCS11H_PIN_CACHE_INFINITE.
+ * @return CK_RV.
+ * @note Default is infinite.
+ */
+CK_RV
+pkcs11h_setPINCachePeriod (
+	IN const int pin_cache_period
+);
+
+/**
+ * @brief Set global login retries attempts.
+ * @param max_retries	Login retries handled by the helper.
+ * @return CK_RV.
+ * @note Default is 3.
+ */
+CK_RV
+pkcs11h_setMaxLoginRetries (
+	IN const unsigned max_retries
+);
+
+/**
+ * @brief Add a PKCS#11 provider.
+ * @param reference		Reference name for this provider.
+ * @param provider_location	Provider library location.
+ * @param allow_protected_auth	Allow this provider to use protected authentication.
+ * @param mask_private_mode	Provider private mode @ref PKCS11H_PRIVATE_MASK override.
+ * @param slot_event_method	Provider slot event @ref PKCS11H_SLOTEVENT_METHOD method.
+ * @param slot_poll_interval	Slot event poll interval (If in polling mode).
+ * @param cert_is_private	Provider's certificate access should be done after login.
+ * @return CK_RV.
+ * @attention This function must be called from the main thread.
+ * @note The global allow_protected_auth must be enabled in order to allow provider specific.
+ */
+CK_RV
+pkcs11h_addProvider (
+	IN const char * const reference,
+	IN const char * const provider_location,
+	IN const PKCS11H_BOOL allow_protected_auth,
+	IN const unsigned mask_private_mode,
+	IN const int slot_event_method,
+	IN const int slot_poll_interval,
+	IN const PKCS11H_BOOL cert_is_private
+);
+
+/**
+ * @brief Delete a PKCS#11 provider.
+ * @param reference	Reference name for this provider.
+ * @return CK_RV.
+ * @attention This function must be called from the main thread.
+ */
+CK_RV
+pkcs11h_removeProvider (
+	IN const char * const reference
+);
+
+/**
+ * @brief Handle special case of POSIX fork()
+ * @return CK_RV.
+ * @attention This function must be called from the main thread.
+ * @attention
+ * This function should be called after fork is called. This is required
+ * due to a limitation of the PKCS#11 standard.
+ * @note The helper library handles fork automatically if @ref PKCS11H_FEATURE_MASK_THREADING
+ * is set on configuration file, by use of pthread_atfork.
+ */
+CK_RV
+pkcs11h_forkFixup (void);
+
+/**
+ * @brief Handle slot rescan.
+ * @return CK_RV.
+ * @attention This function must be called from the main thread.
+ * @remarks
+ * PKCS#11 providers do not allow plug&play, plug&play can be established by
+ * finalizing all providers and initializing them again.
+ * @remarks
+ * The cost of this process is invalidating all sessions, and require user
+ * login at the next access.
+ */
+CK_RV
+pkcs11h_plugAndPlay (void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif				/* __PKCS11H_BASE_H */
diff --git a/include/pkcs11-helper-1.0/pkcs11h-data.h b/include/pkcs11-helper-1.0/pkcs11h-data.h
new file mode 100644
index 0000000..130461c
--- /dev/null
+++ b/include/pkcs11-helper-1.0/pkcs11h-data.h
@@ -0,0 +1,190 @@
+/*
+ * Copyright (c) 2005-2006 Alon Bar-Lev <alon.barlev at gmail.com>
+ * All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, or the OpenIB.org BSD license.
+ *
+ * GNU General Public License (GPL) Version 2
+ * ===========================================
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2
+ *  as published by the Free Software Foundation.
+ *
+ *  This program 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 General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program (see the file COPYING[.GPL2] included with this
+ *  distribution); if not, write to the Free Software Foundation, Inc.,
+ *  59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * OpenIB.org BSD license
+ * =======================
+ * Redistribution and use in source and binary forms, with or without modifi-
+ * cation, are permitted provided that the following conditions are met:
+ *
+ *   o  Redistributions of source code must retain the above copyright notice,
+ *      this list of conditions and the following disclaimer.
+ *
+ *   o  Redistributions in binary form must reproduce the above copyright no-
+ *      tice, this list of conditions and the following disclaimer in the do-
+ *      cumentation and/or other materials provided with the distribution.
+ *
+ *   o  The names of the contributors may not be used to endorse or promote
+ *      products derived from this software without specific prior written
+ *      permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``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 REGENTS OR CONTRIBUTORS BE LI-
+ * ABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUEN-
+ * TIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEV-
+ * ER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABI-
+ * LITY, 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.
+ */
+
+/**
+ * @file pkcs11h-data.h
+ * @brief pkcs11-helper data object support.
+ * @author Alon Bar-Lev <alon.barlev at gmail.com>
+ */
+
+#ifndef __PKCS11H_DATA_H
+#define __PKCS11H_DATA_H
+
+#include <pkcs11-helper-1.0/pkcs11h-core.h>
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+struct pkcs11h_data_id_list_s;
+
+/**
+ * @brief Data identifier list.
+ */
+typedef struct pkcs11h_data_id_list_s *pkcs11h_data_id_list_t;
+
+/**
+ * @brief Data identifier list.
+ */
+struct pkcs11h_data_id_list_s {
+	/** Next element */
+	pkcs11h_data_id_list_t next;
+
+	/** Application string */
+	char *application;
+	/** Label string */
+	char *label;
+};
+
+/**
+ * @brief Get data object.
+ * @param token_id		Token id object.
+ * @param is_public		Object is public.
+ * @param application		Object application attribute.
+ * @param label			Object label attribute.
+ * @param user_data		Optional user data, to be passed to hooks.
+ * @param mask_prompt		Allow prompt.
+ * @param blob			Blob, set to NULL to get size.
+ * @param p_blob_size		Blob size.
+ * @return CK_RV.
+ * @note blob may be NULL to get size.
+ */
+CK_RV
+pkcs11h_data_get (
+	IN const pkcs11h_token_id_t token_id,
+	IN const PKCS11H_BOOL is_public,
+	IN const char * const application,
+	IN const char * const label,
+	IN void * const user_data,
+	IN const unsigned mask_prompt,
+	OUT unsigned char * const blob,
+	IN OUT size_t * const p_blob_size
+);
+
+/**
+ * @brief Put data object.
+ * @param token_id		Token id object.
+ * @param is_public		Object is public.
+ * @param application		Object application attribute.
+ * @param label			Object label attribute.
+ * @param user_data		Optional user data, to be passed to hooks.
+ * @param mask_prompt		Allow prompt.
+ * @param blob			Blob, set to NULL to get size.
+ * @param blob_size		Blob size.
+ * @return CK_RV.
+ */
+CK_RV
+pkcs11h_data_put (
+	IN const pkcs11h_token_id_t token_id,
+	IN const PKCS11H_BOOL is_public,
+	IN const char * const application,
+	IN const char * const label,
+	IN void * const user_data,
+	IN const unsigned mask_prompt,
+	OUT unsigned char * const blob,
+	IN const size_t blob_size
+);
+
+/**
+ * @brief Delete data object.
+ * @param token_id		Token id object.
+ * @param is_public		Object is public.
+ * @param application		Object application attribute.
+ * @param label			Object label attribute.
+ * @param user_data		Optional user data, to be passed to hooks.
+ * @param mask_prompt		Allow prompt.
+ * @return CK_RV.
+ */
+CK_RV
+pkcs11h_data_del (
+	IN const pkcs11h_token_id_t token_id,
+	IN const PKCS11H_BOOL is_public,
+	IN const char * const application,
+	IN const char * const label,
+	IN void * const user_data,
+	IN const unsigned mask_prompt
+);
+
+/**
+ * @brief Free data object list.
+ * @param data_id_list		List to free.
+ * @return CK_RV.
+ */
+CK_RV
+pkcs11h_data_freeDataIdList (
+	IN const pkcs11h_data_id_list_t data_id_list
+);
+
+/**
+ * @brief Get list of data objects.
+ * @param token_id		Token id object.
+ * @param is_public		Get a list of public objects.
+ * @param user_data		Optional user data, to be passed to hooks.
+ * @param mask_prompt		Allow prompt.
+ * @param p_data_id_list	List location.
+ * @see pkcs11h_data_freeDataIdList().
+ * @return CK_RV.
+ */
+CK_RV
+pkcs11h_data_enumDataObjects (
+	IN const pkcs11h_token_id_t token_id,
+	IN const PKCS11H_BOOL is_public,
+	IN void * const user_data,
+	IN const unsigned mask_prompt,
+	OUT pkcs11h_data_id_list_t * const p_data_id_list
+);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif				/* __PKCS11H_DATA_H */
diff --git a/include/pkcs11-helper-1.0/pkcs11h-def.h b/include/pkcs11-helper-1.0/pkcs11h-def.h
new file mode 100644
index 0000000..98bd634
--- /dev/null
+++ b/include/pkcs11-helper-1.0/pkcs11h-def.h
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 2005-2006 Alon Bar-Lev <alon.barlev at gmail.com>
+ * All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, or the OpenIB.org BSD license.
+ *
+ * GNU General Public License (GPL) Version 2
+ * ===========================================
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2
+ *  as published by the Free Software Foundation.
+ *
+ *  This program 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 General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program (see the file COPYING[.GPL2] included with this
+ *  distribution); if not, write to the Free Software Foundation, Inc.,
+ *  59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * OpenIB.org BSD license
+ * =======================
+ * Redistribution and use in source and binary forms, with or without modifi-
+ * cation, are permitted provided that the following conditions are met:
+ *
+ *   o  Redistributions of source code must retain the above copyright notice,
+ *      this list of conditions and the following disclaimer.
+ *
+ *   o  Redistributions in binary form must reproduce the above copyright no-
+ *      tice, this list of conditions and the following disclaimer in the do-
+ *      cumentation and/or other materials provided with the distribution.
+ *
+ *   o  The names of the contributors may not be used to endorse or promote
+ *      products derived from this software without specific prior written
+ *      permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``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 REGENTS OR CONTRIBUTORS BE LI-
+ * ABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUEN-
+ * TIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEV-
+ * ER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABI-
+ * LITY, 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.
+ */
+
+/**
+ * @file pkcs11h-def.h
+ * @brief pkcs11-helper core definitions.
+ * @author Alon Bar-Lev <alon.barlev at gmail.com>
+ */
+
+#ifndef __PKCS11H_DEF_H
+#define __PKCS11H_DEF_H
+
+#include <time.h>
+#if !defined(_WIN32)
+#include <sys/time.h>
+#endif
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+#if !defined(IN)
+#define IN
+#endif
+#if !defined(OUT)
+#define OUT
+#endif
+
+#if defined(_WIN32) || defined(PKCS11H_USE_CYGWIN)
+#include <pkcs11-helper-1.0/cryptoki-win32.h>
+#else
+#include <pkcs11-helper-1.0/cryptoki.h>
+#endif
+
+typedef int PKCS11H_BOOL;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif				/* __PKCS11H_DEF_H */
diff --git a/include/pkcs11-helper-1.0/pkcs11h-engines.h b/include/pkcs11-helper-1.0/pkcs11h-engines.h
new file mode 100644
index 0000000..300edd7
--- /dev/null
+++ b/include/pkcs11-helper-1.0/pkcs11h-engines.h
@@ -0,0 +1,208 @@
+/*
+ * Copyright (c) 2005-2006 Alon Bar-Lev <alon.barlev at gmail.com>
+ * All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, or the OpenIB.org BSD license.
+ *
+ * GNU General Public License (GPL) Version 2
+ * ===========================================
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2
+ *  as published by the Free Software Foundation.
+ *
+ *  This program 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 General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program (see the file COPYING[.GPL2] included with this
+ *  distribution); if not, write to the Free Software Foundation, Inc.,
+ *  59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * OpenIB.org BSD license
+ * =======================
+ * Redistribution and use in source and binary forms, with or without modifi-
+ * cation, are permitted provided that the following conditions are met:
+ *
+ *   o  Redistributions of source code must retain the above copyright notice,
+ *      this list of conditions and the following disclaimer.
+ *
+ *   o  Redistributions in binary form must reproduce the above copyright no-
+ *      tice, this list of conditions and the following disclaimer in the do-
+ *      cumentation and/or other materials provided with the distribution.
+ *
+ *   o  The names of the contributors may not be used to endorse or promote
+ *      products derived from this software without specific prior written
+ *      permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``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 REGENTS OR CONTRIBUTORS BE LI-
+ * ABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUEN-
+ * TIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEV-
+ * ER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABI-
+ * LITY, 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.
+ */
+
+/**
+ * @file pkcs11h-engines.h
+ * @brief pkcs11-helper engines definitions.
+ * @author Alon Bar-Lev <alon.barlev at gmail.com>
+ */
+
+#ifndef __PKCS11H_ENGINES_H
+#define __PKCS11H_ENGINES_H
+
+#include <time.h>
+#if !defined(_WIN32)
+#include <sys/time.h>
+#endif
+#include <pkcs11-helper-1.0/pkcs11h-def.h>
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+/**
+ * @brief System engine.
+ */
+typedef struct pkcs11h_sys_engine_s {
+
+	/**
+	 * @brief malloc provider.
+	 * @param size	Block size.
+	 * @return Pointer.
+	 */
+	void *(*malloc) (size_t size);
+
+	/**
+	 * @brief free provider.
+	 * @param ptr	Pointer.
+	 */
+	void (*free) (void *ptr);
+
+	/**
+	 * @brief time provider.
+	 * @return time_t.
+	 */
+	time_t (*time) (void);
+
+	/**
+	 * @brief usleep provider.
+	 * @param usec	Microseconds.
+	 */
+	void (*usleep) (const unsigned long usec);
+
+	/**
+	 * @brief gettimeofday provider (unix).
+	 * @param rv	timeval.
+	 */
+#if defined(_WIN32)
+	void *gettimeofday;
+#else
+	int (*gettimeofday) (struct timeval *tv);
+#endif
+} pkcs11h_engine_system_t;
+
+/**
+ * @brief Crypto engine.
+ */
+typedef struct pkcs11h_crypto_engine_s {
+	void *global_data;
+
+	/**
+	 * @brief Initialize engine.
+	 * @param global_data	Engine data.
+	 * @return None zero - Sucess.
+	 */
+	int (*initialize) (
+		IN void * const global_data
+	);
+
+	/**
+	 * @brief Uninitialize engine.
+	 * @param global_data	Engine data.
+	 * @return None zero - Sucess.
+	 */
+	int (*uninitialize) (
+		IN void * const global_data
+	);
+
+	/**
+	 * @brief Get exportation date out of certificate.
+	 * @param global_data	Engine data.
+	 * @param blob		Certificate blob.
+	 * @param blob_size	Certificate blob size.
+	 * @param expiration	Certificate expiration time.
+	 * @return None zero - Sucess.
+	 */
+	int (*certificate_get_expiration) (
+		IN void * const global_data,
+		IN const unsigned char * const blob,
+		IN const size_t blob_size,
+		OUT time_t * const expiration
+	);
+
+	/**
+	 * @brief Get certificate distinguished name.
+	 * @param global_data	Engine data.
+	 * @param blob		Certificate blob.
+	 * @param blob_size	Certificate blob size.
+	 * @param dn		dn buffer.
+	 * @param dn_max	dn buffer size.
+	 * @return None zero - Sucess.
+	 */
+	int (*certificate_get_dn) (
+		IN void * const global_data,
+		IN const unsigned char * const blob,
+		IN const size_t blob_size,
+		OUT char * const dn,
+		IN const size_t dn_max
+	);
+
+	/**
+	 * @brief Get certificate serial number.
+	 * @param global_data	Engine data.
+	 * @param blob		Certificate blob.
+	 * @param blob_size	Certificate blob size.
+	 * @param serial	serial buffer.
+	 * @param serial_max	serial buffer size.
+	 * @return None zero - Sucess.
+	 */
+	int (*certificate_get_serial) (
+		IN void * const global_data,
+		IN const unsigned char * const blob,
+		IN const size_t blob_size,
+		OUT char * const serial,
+		IN const size_t serial_max
+	);
+
+	/**
+	 * @brief Determine if one certificate is an issuer of another.
+	 * @param global_data		Engine data.
+	 * @param issuer_blob		Issuer's certificate blob.
+	 * @param issuer_blob_size	Issuer's certificate blob size.
+	 * @param cert_blob		Certificate blob.
+	 * @param cert_blob_size	Certificate blob size.
+	 * @return None zero - Sucess.
+	 */
+	int (*certificate_is_issuer) (
+		IN void * const global_data,
+		IN const unsigned char * const issuer_blob,
+		IN const size_t issuer_blob_size,
+		IN const unsigned char * const cert_blob,
+		IN const size_t cert_blob_size
+	);
+} pkcs11h_engine_crypto_t;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif				/* __PKCS11H_ENGINES_H */
diff --git a/include/pkcs11-helper-1.0/pkcs11h-locate.h b/include/pkcs11-helper-1.0/pkcs11h-locate.h
new file mode 100644
index 0000000..65ea857
--- /dev/null
+++ b/include/pkcs11-helper-1.0/pkcs11h-locate.h
@@ -0,0 +1,128 @@
+/*
+ * Copyright (c) 2005-2006 Alon Bar-Lev <alon.barlev at gmail.com>
+ * All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, or the OpenIB.org BSD license.
+ *
+ * GNU General Public License (GPL) Version 2
+ * ===========================================
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2
+ *  as published by the Free Software Foundation.
+ *
+ *  This program 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 General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program (see the file COPYING[.GPL2] included with this
+ *  distribution); if not, write to the Free Software Foundation, Inc.,
+ *  59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * OpenIB.org BSD license
+ * =======================
+ * Redistribution and use in source and binary forms, with or without modifi-
+ * cation, are permitted provided that the following conditions are met:
+ *
+ *   o  Redistributions of source code must retain the above copyright notice,
+ *      this list of conditions and the following disclaimer.
+ *
+ *   o  Redistributions in binary form must reproduce the above copyright no-
+ *      tice, this list of conditions and the following disclaimer in the do-
+ *      cumentation and/or other materials provided with the distribution.
+ *
+ *   o  The names of the contributors may not be used to endorse or promote
+ *      products derived from this software without specific prior written
+ *      permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``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 REGENTS OR CONTRIBUTORS BE LI-
+ * ABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUEN-
+ * TIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEV-
+ * ER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABI-
+ * LITY, 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.
+ */
+
+/**
+ * @file pkcs11h-locate.h
+ * @brief pkcs11-helper locate interface.
+ * @author Alon Bar-Lev <alon.barlev at gmail.com>
+ */
+
+#ifndef __PKCS11H_LOCATE_H
+#define __PKCS11H_LOCATE_H
+
+#include <pkcs11-helper-1.0/pkcs11h-core.h>
+#include <pkcs11-helper-1.0/pkcs11h-certificate.h>
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+/**
+ * @brief Locate token based on atributes.
+ * @param slot_type		How to locate slot.
+ * @param slot			Slot name.
+ * @param user_data		Optional user data, to be passed to hooks.
+ * @param mask_prompt		Allow prompt @ref PKCS11H_PROMPT_MASK.
+ * @param p_token_id		Token object.
+ * @note Caller must free result.
+ * @see pkcs11h_token_freeTokenId().
+ * @remarks
+ * Slot:
+ * 	- id		- Slot number.
+ * 	- name		- Slot name.
+ * 	- label		- Available token label.
+ */
+CK_RV
+pkcs11h_locate_token (
+	IN const char * const slot_type,
+	IN const char * const slot,
+	IN void * const user_data,
+	IN const unsigned mask_prompt,
+	OUT pkcs11h_token_id_t * const p_token_id
+);
+
+/**
+ * @brief Locate certificate based on atributes.
+ * @param slot_type		How to locate slot.
+ * @param slot			Slot name.
+ * @param id_type		How to locate object.
+ * @param id			Object name.
+ * @param user_data		Optional user data, to be passed to hooks.
+ * @param mask_prompt		Allow prompt @ref PKCS11H_PROMPT_MASK.
+ * @param p_certificate_id	Certificate object.
+ * @note Caller must free result.
+ * @see pkcs11h_certificate_freeCertificateId().
+ * @remarks
+ * Slot:
+ *	Same as in @ref pkcs11h_locate_token().
+ * @remarks
+ * Object:
+ * 	- id		- Certificate CKA_ID (hex string) (Fastest).
+ * 	- label		- Certificate CKA_LABEL (string).
+ * 	- subject	- Certificate subject (OpenSSL or GNUTLS DN).
+ */
+CK_RV
+pkcs11h_locate_certificate (
+	IN const char * const slot_type,
+	IN const char * const slot,
+	IN const char * const id_type,
+	IN const char * const id,
+	IN void * const user_data,
+	IN const unsigned mask_prompt,
+	OUT pkcs11h_certificate_id_t * const p_certificate_id
+);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif				/* __PKCS11H_LOCATE_H */
diff --git a/include/pkcs11-helper-1.0/pkcs11h-openssl.h b/include/pkcs11-helper-1.0/pkcs11h-openssl.h
new file mode 100644
index 0000000..0102964
--- /dev/null
+++ b/include/pkcs11-helper-1.0/pkcs11h-openssl.h
@@ -0,0 +1,162 @@
+/*
+ * Copyright (c) 2005-2006 Alon Bar-Lev <alon.barlev at gmail.com>
+ * All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, or the OpenIB.org BSD license.
+ *
+ * GNU General Public License (GPL) Version 2
+ * ===========================================
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2
+ *  as published by the Free Software Foundation.
+ *
+ *  This program 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 General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program (see the file COPYING[.GPL2] included with this
+ *  distribution); if not, write to the Free Software Foundation, Inc.,
+ *  59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * OpenIB.org BSD license
+ * =======================
+ * Redistribution and use in source and binary forms, with or without modifi-
+ * cation, are permitted provided that the following conditions are met:
+ *
+ *   o  Redistributions of source code must retain the above copyright notice,
+ *      this list of conditions and the following disclaimer.
+ *
+ *   o  Redistributions in binary form must reproduce the above copyright no-
+ *      tice, this list of conditions and the following disclaimer in the do-
+ *      cumentation and/or other materials provided with the distribution.
+ *
+ *   o  The names of the contributors may not be used to endorse or promote
+ *      products derived from this software without specific prior written
+ *      permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``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 REGENTS OR CONTRIBUTORS BE LI-
+ * ABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUEN-
+ * TIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEV-
+ * ER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABI-
+ * LITY, 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.
+ */
+
+/**
+ * @file pkcs11h-openssl.h
+ * @brief pkcs11-helper OpenSSL interface.
+ * @author Alon Bar-Lev <alon.barlev at gmail.com>
+ */
+
+#ifndef __PKCS11H_HELPER_H
+#define __PKCS11H_HELPER_H
+
+#include <openssl/x509.h>
+#include <pkcs11-helper-1.0/pkcs11h-core.h>
+#include <pkcs11-helper-1.0/pkcs11h-certificate.h>
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+/**
+ * @brief OpenSSL RSA cleanup hook.
+ * @param certificate	Certificate attached to the RSA object.
+ */
+typedef void (*pkcs11h_hook_openssl_cleanup_t) (
+	IN const pkcs11h_certificate_t certificate
+);
+
+struct pkcs11h_openssl_session_s;
+
+/**
+ * @brief OpenSSL session reference.
+ */
+typedef struct pkcs11h_openssl_session_s *pkcs11h_openssl_session_t;
+
+/**
+ * @brief Returns an X509 object out of the openssl_session object.
+ * @param certificate	Certificate object.
+ * @return X509.
+ */
+X509 *
+pkcs11h_openssl_getX509 (
+	IN const pkcs11h_certificate_t certificate
+);
+
+/**
+ * @brief Create OpenSSL session based on a certificate object.
+ * @param certificate	Certificate object.
+ * @return OpenSSL session reference.
+ * @note The certificate object will be freed by the OpenSSL interface on session end.
+ * @see pkcs11h_openssl_freeSession().
+ */
+pkcs11h_openssl_session_t
+pkcs11h_openssl_createSession (
+	IN const pkcs11h_certificate_t certificate
+);
+
+/**
+ * @brief Sets cleanup hook
+ * @param openssl_session	OpenSSL session reference.
+ * @return Current hook.
+ */
+pkcs11h_hook_openssl_cleanup_t
+pkcs11h_openssl_getCleanupHook (
+	IN const pkcs11h_openssl_session_t openssl_session
+);
+
+/**
+ * @brief Sets cleanup hook
+ * @param openssl_session	OpenSSL session reference.
+ * @param cleanup		hook.
+ */
+void
+pkcs11h_openssl_setCleanupHook (
+	IN const pkcs11h_openssl_session_t openssl_session,
+	IN const pkcs11h_hook_openssl_cleanup_t cleanup
+);
+
+/**
+ * @brief Free OpenSSL session.
+ * @param openssl_session	OpenSSL session reference.
+ * @note The openssl_session object has a reference count just like other OpenSSL objects.
+ */
+void
+pkcs11h_openssl_freeSession (
+	IN const pkcs11h_openssl_session_t openssl_session
+);
+
+/**
+ * @brief Returns an RSA object out of the openssl_session object.
+ * @param openssl_session	OpenSSL session reference.
+ * @return RSA.
+ */
+RSA *
+pkcs11h_openssl_session_getRSA (
+	IN const pkcs11h_openssl_session_t openssl_session
+);
+
+/**
+ * @brief Returns an X509 object out of the openssl_session object.
+ * @param openssl_session	OpenSSL session reference.
+ * @return X509.
+ */
+X509 *
+pkcs11h_openssl_session_getX509 (
+	IN const pkcs11h_openssl_session_t openssl_session
+);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif				/* __PKCS11H_OPENSSL_H */
diff --git a/include/pkcs11-helper-1.0/pkcs11h-standalone.h b/include/pkcs11-helper-1.0/pkcs11h-standalone.h
new file mode 100644
index 0000000..4bbbe69
--- /dev/null
+++ b/include/pkcs11-helper-1.0/pkcs11h-standalone.h
@@ -0,0 +1,129 @@
+/*
+ * Copyright (c) 2005-2006 Alon Bar-Lev <alon.barlev at gmail.com>
+ * All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, or the OpenIB.org BSD license.
+ *
+ * GNU General Public License (GPL) Version 2
+ * ===========================================
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2
+ *  as published by the Free Software Foundation.
+ *
+ *  This program 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 General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program (see the file COPYING[.GPL2] included with this
+ *  distribution); if not, write to the Free Software Foundation, Inc.,
+ *  59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * OpenIB.org BSD license
+ * =======================
+ * Redistribution and use in source and binary forms, with or without modifi-
+ * cation, are permitted provided that the following conditions are met:
+ *
+ *   o  Redistributions of source code must retain the above copyright notice,
+ *      this list of conditions and the following disclaimer.
+ *
+ *   o  Redistributions in binary form must reproduce the above copyright no-
+ *      tice, this list of conditions and the following disclaimer in the do-
+ *      cumentation and/or other materials provided with the distribution.
+ *
+ *   o  The names of the contributors may not be used to endorse or promote
+ *      products derived from this software without specific prior written
+ *      permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``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 REGENTS OR CONTRIBUTORS BE LI-
+ * ABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUEN-
+ * TIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEV-
+ * ER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABI-
+ * LITY, 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.
+ */
+
+/**
+ * @file pkcs11h-standalone.h
+ * @brief pkcs11-helper standalone interface.
+ * @author Alon Bar-Lev <alon.barlev at gmail.com>
+ */
+
+#ifndef __PKCS11H_STANDALONE_H
+#define __PKCS11H_STANDALONE_H
+
+#include <pkcs11-helper-1.0/pkcs11h-core.h>
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+/**
+ * @brief Output hook.
+ * @param global_data	Hook global data.
+ * @param format	printf style format.
+ * @param ...		printf style args.
+ */
+typedef void (*pkcs11h_output_print_t)(
+	IN void * const global_data,
+	IN const char * const format,
+	IN ...
+)
+#if __GNUC__ > 2
+	__attribute__ ((format (printf, 2, 3)))
+#endif
+;
+
+
+/**
+ * @brief Dumps slots, suitabe for debugging.
+ * @param my_output	Output function.
+ * @param global_data	Parameter to output function.
+ * @param provider	Provider to load.
+ * @param prms[]	If not null:
+ *	- 0	slot type parameter name
+ *	- 1	slot parameter name
+ */
+void
+pkcs11h_standalone_dump_slots (
+	IN const pkcs11h_output_print_t my_output,
+	IN void * const global_data,
+	IN const char * const provider,
+	IN const char * const prms[]
+);
+
+/**
+ * @brief Dumps objects, suitabe for debugging.
+ * @param my_output	Output function.
+ * @param global_data	Parameter to output function.
+ * @param provider	Provider to load.
+ * @param slot		slot to dump (number).
+ * @param pin		PIN to use.
+ * @param prms[]	If not null:
+ *	- 0	slot type parameter name
+ *	- 1	slot parameter name
+ * 	- 2	object type parameter name
+ * 	- 3	object parameter name
+ */
+void
+pkcs11h_standalone_dump_objects (
+	IN const pkcs11h_output_print_t my_output,
+	IN void * const global_data,
+	IN const char * const provider,
+	IN const char * const slot,
+	IN const char * const pin,
+	IN const char * const prms[]
+);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif				/* __PKCS11H_STANDALONE_H */
diff --git a/include/pkcs11-helper-1.0/pkcs11h-token.h b/include/pkcs11-helper-1.0/pkcs11h-token.h
new file mode 100644
index 0000000..d553edb
--- /dev/null
+++ b/include/pkcs11-helper-1.0/pkcs11h-token.h
@@ -0,0 +1,205 @@
+/*
+ * Copyright (c) 2005-2006 Alon Bar-Lev <alon.barlev at gmail.com>
+ * All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, or the OpenIB.org BSD license.
+ *
+ * GNU General Public License (GPL) Version 2
+ * ===========================================
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2
+ *  as published by the Free Software Foundation.
+ *
+ *  This program 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 General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program (see the file COPYING[.GPL2] included with this
+ *  distribution); if not, write to the Free Software Foundation, Inc.,
+ *  59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * OpenIB.org BSD license
+ * =======================
+ * Redistribution and use in source and binary forms, with or without modifi-
+ * cation, are permitted provided that the following conditions are met:
+ *
+ *   o  Redistributions of source code must retain the above copyright notice,
+ *      this list of conditions and the following disclaimer.
+ *
+ *   o  Redistributions in binary form must reproduce the above copyright no-
+ *      tice, this list of conditions and the following disclaimer in the do-
+ *      cumentation and/or other materials provided with the distribution.
+ *
+ *   o  The names of the contributors may not be used to endorse or promote
+ *      products derived from this software without specific prior written
+ *      permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``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 REGENTS OR CONTRIBUTORS BE LI-
+ * ABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUEN-
+ * TIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEV-
+ * ER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABI-
+ * LITY, 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.
+ */
+
+/**
+ * @file pkcs11h-token.h
+ * @brief pkcs11-helper token interface.
+ * @author Alon Bar-Lev <alon.barlev at gmail.com>
+ */
+
+#ifndef __PKCS11H_TOKEN_H
+#define __PKCS11H_TOKEN_H
+
+#include <pkcs11-helper-1.0/pkcs11h-core.h>
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+struct pkcs11h_token_id_list_s;
+
+/**
+ * @brief Token identifier list.
+ */
+typedef struct pkcs11h_token_id_list_s *pkcs11h_token_id_list_t;
+
+/**
+ * @brief Token identifier list.
+ */
+struct pkcs11h_token_id_list_s {
+	/** Next element. */
+	pkcs11h_token_id_list_t next;
+	/** Token id element. */
+	pkcs11h_token_id_t token_id;
+};
+
+/**
+ * @brief Free token_id object.
+ * @param token_id	Token reference.
+ * @return CK_RV.
+ */
+CK_RV
+pkcs11h_token_freeTokenId (
+	IN pkcs11h_token_id_t token_id
+);
+
+/**
+ * @brief Duplicate token_id object.
+ * @param to		Target.
+ * @param from		Source.
+ * @return CK_RV.
+ * @see pkcs11h_token_freeTokenId().
+ */
+CK_RV
+pkcs11h_token_duplicateTokenId (
+	OUT pkcs11h_token_id_t * const to,
+	IN const pkcs11h_token_id_t from
+);
+
+/**
+ * @brief Returns TRUE if same token id
+ * @param a		a.
+ * @param b		b.
+ * @return TRUE if same token identifier.
+ */
+PKCS11H_BOOL
+pkcs11h_token_sameTokenId (
+	IN const pkcs11h_token_id_t a,
+	IN const pkcs11h_token_id_t b
+);
+
+/**
+ * @brief Force login, avoid hooks.
+ * @param token_id	Token to login into.
+ * @param readonly	Should session be readonly.
+ * @param pin		PIN to login, NULL for protected authentication.
+ * @return CK_RV.
+ */
+CK_RV
+pkcs11h_token_login (
+	IN const pkcs11h_token_id_t token_id,
+	IN const PKCS11H_BOOL readonly,
+	IN const char * const pin
+);
+
+/**
+ * @brief Ensure token is accessible.
+ * @brief token_id	Token id object.
+ * @brief user_data	Optional user data, to be passed to hooks.
+ * @brief mask_prompt	Allow prompt @ref PKCS11H_PROMPT_MASK.
+ * @return CK_RV.
+ */
+CK_RV
+pkcs11h_token_ensureAccess (
+	IN const pkcs11h_token_id_t token_id,
+	IN void * const user_data,
+	IN const unsigned mask_prompt
+);
+
+/**
+ * @brief Free certificate_id list.
+ * @param token_id_list	List.
+ * @return CK_RV.
+ */
+CK_RV
+pkcs11h_token_freeTokenIdList (
+	IN const pkcs11h_token_id_list_t token_id_list
+);
+
+/**
+ * @brief Enumerate available tokens.
+ * @param method		Enum method @ref PKCS11H_ENUM_METHOD.
+ * @param p_token_id_list	List.
+ * @return CK_RV.
+ * @note Caller must free result.
+ * @see pkcs11h_token_freeTokenIdList().
+ */
+CK_RV
+pkcs11h_token_enumTokenIds (
+	IN const int method,
+	OUT pkcs11h_token_id_list_t * const p_token_id_list
+);
+
+/**
+ * @brief Serialize token_id into string.
+ * @param sz			Output string.
+ * @param max			Maximum string size.
+ * @param token_id		id to serialize
+ * @return CK_RV.
+ * @note sz may be NULL to get size.
+ */
+CK_RV
+pkcs11h_token_serializeTokenId (
+	OUT char * const sz,
+	IN OUT size_t *max,
+	IN const pkcs11h_token_id_t token_id
+);
+
+/**
+ * @brief Deserialize token_id from string.
+ * @param p_token_id		id.
+ * @param sz			Input string.
+ * @return CK_RV.
+ * @note Caller must free result.
+ * @see pkcs11h_token_freeTokenId().
+ */
+CK_RV
+pkcs11h_token_deserializeTokenId (
+	OUT pkcs11h_token_id_t *p_token_id,
+	IN const char * const sz
+);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif				/* __PKCS11H_TOKEN_H */
diff --git a/lib/Makefile.am b/lib/Makefile.am
new file mode 100644
index 0000000..211279c
--- /dev/null
+++ b/lib/Makefile.am
@@ -0,0 +1,157 @@
+#
+# Copyright (c) 2005-2006 Alon Bar-Lev <alon.barlev at gmail.com>
+# All rights reserved.
+#
+# This software is available to you under a choice of one of two
+# licenses.  You may choose to be licensed under the terms of the GNU
+# General Public License (GPL) Version 2, or the OpenIB.org BSD license.
+#
+# GNU General Public License (GPL) Version 2
+# ===========================================
+#  This program is free software; you can redistribute it and/or modify
+#  it under the terms of the GNU General Public License version 2
+#  as published by the Free Software Foundation.
+#
+#  This program 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 General Public License for more details.
+#
+#  You should have received a copy of the GNU General Public License
+#  along with this program (see the file COPYING[.GPL2] included with this
+#  distribution); if not, write to the Free Software Foundation, Inc.,
+#  59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+#
+# OpenIB.org BSD license
+# =======================
+# Redistribution and use in source and binary forms, with or without modifi-
+# cation, are permitted provided that the following conditions are met:
+#
+#   o  Redistributions of source code must retain the above copyright notice,
+#      this list of conditions and the following disclaimer.
+#
+#   o  Redistributions in binary form must reproduce the above copyright no-
+#      tice, this list of conditions and the following disclaimer in the do-
+#      cumentation and/or other materials provided with the distribution.
+#
+#   o  The names of the contributors may not be used to endorse or promote
+#      products derived from this software without specific prior written
+#      permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# ``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 REGENTS OR CONTRIBUTORS BE LI-
+# ABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUEN-
+# TIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEV-
+# ER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABI-
+# LITY, 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.
+#
+
+INCLUDES= \
+	-I$(top_srcdir)/include
+
+PKCS11_INCLUDES= \
+	../pkcs11-helper-1.0/pkcs11-headers/*.h \
+	../pkcs11-helper-1.0/cryptoki.h \
+	../pkcs11-helper-1.0/cryptoki-win32.h
+
+EXTRA_DIST= \
+	Makefile.w32-vc \
+	certificate.exports \
+	core.exports \
+	data.exports \
+	locate.exports \
+	openssl.exports \
+	slotevent.exports \
+	standalone.exports \
+	token.exports
+
+pkgconfig_DATA = libpkcs11-helper-1.pc
+
+lib_LTLIBRARIES=libpkcs11-helper.la
+BUILT_SOURCES=pkcs11-helper.exports
+nodist_libpkcs11_helper_la_SOURCES= \
+	../pkcs11-helper-1.0/pkcs11h-def.h \
+	../pkcs11-helper-1.0/pkcs11h-engines.h \
+	../pkcs11-helper-1.0/pkcs11h-core.h \
+	../pkcs11-helper-1.0/pkcs11h-token.h \
+	../pkcs11-helper-1.0/pkcs11h-certificate.h \
+	../pkcs11-helper-1.0/pkcs11h-data.h \
+	../pkcs11-helper-1.0/pkcs11h-locate.h \
+	../pkcs11-helper-1.0/pkcs11h-openssl.h \
+	../pkcs11-helper-1.0/pkcs11h-standalone.h \
+	$(PKCS11_INCLUDES) \
+	pkcs11-helper.exports
+libpkcs11_helper_la_SOURCES= \
+	common.h \
+	_pkcs11h-mem.h pkcs11h-mem.c \
+	_pkcs11h-sys.h pkcs11h-sys.c \
+	_pkcs11h-crypto.h pkcs11h-crypto.c \
+	_pkcs11h-threading.h pkcs11h-threading.c \
+	_pkcs11h-util.h pkcs11h-util.c \
+	_pkcs11h-session.h pkcs11h-session.c \
+	_pkcs11h-token.h pkcs11h-token.c \
+	_pkcs11h-certificate.h pkcs11h-certificate.c \
+	_pkcs11h-slotevent.h pkcs11h-slotevent.c \
+	_pkcs11h-core.h pkcs11h-core.c \
+	pkcs11h-locate.c \
+	pkcs11h-data.c \
+	pkcs11h-serialization.c \
+	pkcs11h-openssl.c \
+	pkcs11h-standalone.c
+libpkcs11_helper_la_LDFLAGS= \
+	-version-info @LIBPKCS11_HELPER_LT_CURRENT@:@LIBPKCS11_HELPER_LT_REVISION@:@LIBPKCS11_HELPER_LT_AGE@ \
+	-export-symbols pkcs11-helper.exports \
+	-no-undefined \
+	$(no_undefined) $(export_symbols)
+
+pkcs11-helper.exports: \
+		../config.h \
+		certificate.exports \
+		core.exports \
+		data.exports \
+		locate.exports \
+		openssl.exports \
+		slotevent.exports \
+		standalone.exports \
+		token.exports
+	cat core.exports > pkcs11-helper.exports
+if ENABLE_PKCS11H_CERTIFICATE
+	cat certificate.exports >> pkcs11-helper.exports
+endif
+if ENABLE_PKCS11H_DATA
+	cat data.exports >> pkcs11-helper.exports
+endif
+if ENABLE_PKCS11H_LOCATE
+	cat locate.exports >> pkcs11-helper.exports
+endif
+if ENABLE_PKCS11H_OPENSSL
+	cat openssl.exports >> pkcs11-helper.exports
+endif
+if ENABLE_PKCS11H_SLOTEVENT
+	cat slotevent.exports >> pkcs11-helper.exports
+endif
+if ENABLE_PKCS11H_STANDALONE
+	cat standalone.exports >> pkcs11-helper.exports
+endif
+if ENABLE_PKCS11H_TOKEN
+	cat token.exports >> pkcs11-helper.exports
+endif
+
+if WIN32
+mylibdir=$(libdir)
+if CYGWIN
+mylib_DATA=.libs/cygpkcs11-helper-1.dll.def
+.libs/cygpkcs11-helper-1.dll.def:	libpkcs11-helper.la
+else
+mylib_DATA=.libs/libpkcs11-helper-1.dll.def
+.libs/libpkcs11-helper-1.dll.def:	libpkcs11-helper.la
+endif
+endif
+
+clean-generic:
+	-rm -fr pkcs11-helper.exports
+
diff --git a/lib/Makefile.w32-vc b/lib/Makefile.w32-vc
new file mode 100644
index 0000000..d2410d6
--- /dev/null
+++ b/lib/Makefile.w32-vc
@@ -0,0 +1,159 @@
+#
+# Copyright (c) 2005-2006 Alon Bar-Lev <alon.barlev at gmail.com>
+# All rights reserved.
+#
+# This software is available to you under a choice of one of two
+# licenses.  You may choose to be licensed under the terms of the GNU
+# General Public License (GPL) Version 2, or the OpenIB.org BSD license.
+#
+# GNU General Public License (GPL) Version 2
+# ===========================================
+#  This program is free software; you can redistribute it and/or modify
+#  it under the terms of the GNU General Public License version 2
+#  as published by the Free Software Foundation.
+#
+#  This program 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 General Public License for more details.
+#
+#  You should have received a copy of the GNU General Public License
+#  along with this program (see the file COPYING[.GPL2] included with this
+#  distribution); if not, write to the Free Software Foundation, Inc.,
+#  59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+#
+# OpenIB.org BSD license
+# =======================
+# Redistribution and use in source and binary forms, with or without modifi-
+# cation, are permitted provided that the following conditions are met:
+#
+#   o  Redistributions of source code must retain the above copyright notice,
+#      this list of conditions and the following disclaimer.
+#
+#   o  Redistributions in binary form must reproduce the above copyright no-
+#      tice, this list of conditions and the following disclaimer in the do-
+#      cumentation and/or other materials provided with the distribution.
+#
+#   o  The names of the contributors may not be used to endorse or promote
+#      products derived from this software without specific prior written
+#      permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# ``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 REGENTS OR CONTRIBUTORS BE LI-
+# ABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUEN-
+# TIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEV-
+# ER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABI-
+# LITY, 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.
+#
+
+# Targets:
+#	static -- link statically with OpenSSL
+#	dynamic -- link dynamically with OpenSSL
+#
+
+# Change these to point to your OpenSSL top-level
+# directories.
+
+OPENSSL = c:\Temp\openssl
+OPENSSL_STATIC = libeay32s.lib
+#OPENSSL_STATIC = libeay32sd.lib
+OPENSSL_DYNAMIC = libeay32.lib
+#OPENSSL_DYNAMIC = libeay32d.lib
+
+INCLUDE_DIRS = -I$(OPENSSL)/include -I../include
+
+LIBS = kernel32.lib gdi32.lib
+
+LIB_DIRS = -LIBPATH:$(OPENSSL)\lib
+
+DLL = pkcs11-helper-1.dll
+
+CC=cl.exe
+CC_ARG_COMMON=/nologo /W3 /O2 -DWIN32 -DWIN32_LEAN_AND_MEAN -D_MBCS -D_CRT_SECURE_NO_DEPRECATE $(INCLUDE_DIRS) /FD /c
+# release:
+CC_PROJ=$(CC_ARG_COMMON) /MD -DNDEBUG
+# debug:
+#CC_PROJ=$(CC_ARG_COMMON) /MDd /Zi /Od -D_DEBUG
+
+LINK32=link.exe
+# release:
+LINK32_FLAGS=/nologo /subsystem:windows /dll /incremental:no /out:"$(DLL)"
+# debug:
+#LINK32_FLAGS=/nologo /subsystem:windows /dll /incremental:no /debug /out:"$(DLL)"
+
+HEADERS = \
+	config.h \
+	common.h \
+	_pkcs11h-core.h \
+	_pkcs11h-certificate.h \
+	_pkcs11h-crypto.h \
+	_pkcs11h-mem.h \
+	_pkcs11h-session.h \
+	_pkcs11h-slotevent.h \
+	_pkcs11h-sys.h \
+	_pkcs11h-threading.h \
+	_pkcs11h-token.h \
+	_pkcs11h-util.h \
+	../include/pkcs11-helper-1.0/cryptoki.h \
+	../include/pkcs11-helper-1.0/cryptoki-win32.h \
+	../include/pkcs11-helper-1.0/pkcs11h-core.h \
+	../include/pkcs11-helper-1.0/pkcs11h-certificate.h \
+	../include/pkcs11-helper-1.0/pkcs11h-data.h \
+	../include/pkcs11-helper-1.0/pkcs11h-def.h \
+	../include/pkcs11-helper-1.0/pkcs11h-engines.h \
+	../include/pkcs11-helper-1.0/pkcs11h-locate.h \
+	../include/pkcs11-helper-1.0/pkcs11h-openssl.h \
+	../include/pkcs11-helper-1.0/pkcs11h-standalone.h \
+	../include/pkcs11-helper-1.0/pkcs11h-token.h
+
+OBJS =  \
+	pkcs11h-core.obj \
+	pkcs11h-certificate.obj \
+	pkcs11h-crypto.obj \
+	pkcs11h-data.obj \
+	pkcs11h-locate.obj \
+	pkcs11h-mem.obj \
+	pkcs11h-openssl.obj \
+	pkcs11h-serialization.obj \
+	pkcs11h-session.obj \
+	pkcs11h-slotevent.obj \
+	pkcs11h-standalone.obj \
+	pkcs11h-sys.obj \
+	pkcs11h-threading.obj \
+	pkcs11h-token.obj \
+	pkcs11h-util.obj
+
+all:	dynamic
+
+pkcs11-helper-1.def:
+	echo LIBRARY pkcs11-helper-1 > pkcs11-helper-1.def
+	echo EXPORTS >> pkcs11-helper-1.def
+	type core.exports >> pkcs11-helper-1.def
+	type certificate.exports >> pkcs11-helper-1.def
+	type data.exports >> pkcs11-helper-1.def
+	type locate.exports >> pkcs11-helper-1.def
+	type slotevent.exports >> pkcs11-helper-1.def
+	type standalone.exports >> pkcs11-helper-1.def
+	type token.exports >> pkcs11-helper-1.def
+
+dynamic: pkcs11-helper-1.def $(OBJS)
+	$(LINK32) @<<
+	$(LINK32_FLAGS) $(LIB_DIRS) $(LIBS) $(OPENSSL_DYNAMIC) /def:pkcs11-helper-1.def  $(OBJS)
+<<
+
+static: pkcs11-helper-1.def $(OBJS)
+	$(LINK32) @<<
+	$(LINK32_FLAGS) $(LIB_DIRS) $(LIBS) $(OPENSSL_STATIC) /def:pkcs11-helper-1.def $(OBJS)
+<<
+
+clean:
+	del /Q $(OBJS) $(DLL) *.lib *.exp *.manifest *.idb *.pdb pkcs11-helper-1.def
+
+.c.obj::
+   $(CC) @<<
+   $(CC_PROJ) $<
+<<
diff --git a/lib/_pkcs11h-certificate.h b/lib/_pkcs11h-certificate.h
new file mode 100644
index 0000000..32fe118
--- /dev/null
+++ b/lib/_pkcs11h-certificate.h
@@ -0,0 +1,98 @@
+/*
+ * Copyright (c) 2005-2006 Alon Bar-Lev <alon.barlev at gmail.com>
+ * All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, or the OpenIB.org BSD license.
+ *
+ * GNU General Public License (GPL) Version 2
+ * ===========================================
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2
+ *  as published by the Free Software Foundation.
+ *
+ *  This program 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 General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program (see the file COPYING[.GPL2] included with this
+ *  distribution); if not, write to the Free Software Foundation, Inc.,
+ *  59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * OpenIB.org BSD license
+ * =======================
+ * Redistribution and use in source and binary forms, with or without modifi-
+ * cation, are permitted provided that the following conditions are met:
+ *
+ *   o  Redistributions of source code must retain the above copyright notice,
+ *      this list of conditions and the following disclaimer.
+ *
+ *   o  Redistributions in binary form must reproduce the above copyright no-
+ *      tice, this list of conditions and the following disclaimer in the do-
+ *      cumentation and/or other materials provided with the distribution.
+ *
+ *   o  The names of the contributors may not be used to endorse or promote
+ *      products derived from this software without specific prior written
+ *      permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``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 REGENTS OR CONTRIBUTORS BE LI-
+ * ABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUEN-
+ * TIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEV-
+ * ER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABI-
+ * LITY, 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.
+ */
+
+#ifndef ___PKCS11H_CERTIFICATE_H
+#define ___PKCS11H_CERTIFICATE_H
+
+#include "common.h"
+
+#if defined(ENABLE_PKCS11H_CERTIFICATE)
+
+#include "_pkcs11h-core.h"
+#include <pkcs11-helper-1.0/pkcs11h-certificate.h>
+
+PKCS11H_BOOL
+_pkcs11h_certificate_isBetterCertificate (
+	IN const unsigned char * const current,
+	IN const size_t current_size,
+	IN const unsigned char * const newone,
+	IN const size_t newone_size
+);
+
+CK_RV
+_pkcs11h_certificate_newCertificateId (
+	OUT pkcs11h_certificate_id_t * const certificate_id
+);
+
+CK_RV
+_pkcs11h_certificate_validateSession (
+	IN const pkcs11h_certificate_t certificate
+);
+
+CK_RV
+_pkcs11h_certificate_resetSession (
+	IN const pkcs11h_certificate_t certificate,
+	IN const PKCS11H_BOOL public_only,
+	IN const PKCS11H_BOOL session_mutex_locked
+);
+
+CK_RV
+_pkcs11h_certificate_enumSessionCertificates (
+	IN const pkcs11h_session_t session,
+	IN void * const user_data,
+	IN const unsigned mask_prompt
+);
+
+#endif				/* ENABLE_PKCS11H_CERTIFICATE */
+
+#endif				/* ___PKCS11H_CERTIFICATE_H */
+
diff --git a/lib/_pkcs11h-core.h b/lib/_pkcs11h-core.h
new file mode 100644
index 0000000..5b8251a
--- /dev/null
+++ b/lib/_pkcs11h-core.h
@@ -0,0 +1,238 @@
+/*
+ * Copyright (c) 2005-2006 Alon Bar-Lev <alon.barlev at gmail.com>
+ * All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, or the OpenIB.org BSD license.
+ *
+ * GNU General Public License (GPL) Version 2
+ * ===========================================
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2
+ *  as published by the Free Software Foundation.
+ *
+ *  This program 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 General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program (see the file COPYING[.GPL2] included with this
+ *  distribution); if not, write to the Free Software Foundation, Inc.,
+ *  59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * OpenIB.org BSD license
+ * =======================
+ * Redistribution and use in source and binary forms, with or without modifi-
+ * cation, are permitted provided that the following conditions are met:
+ *
+ *   o  Redistributions of source code must retain the above copyright notice,
+ *      this list of conditions and the following disclaimer.
+ *
+ *   o  Redistributions in binary form must reproduce the above copyright no-
+ *      tice, this list of conditions and the following disclaimer in the do-
+ *      cumentation and/or other materials provided with the distribution.
+ *
+ *   o  The names of the contributors may not be used to endorse or promote
+ *      products derived from this software without specific prior written
+ *      permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``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 REGENTS OR CONTRIBUTORS BE LI-
+ * ABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUEN-
+ * TIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEV-
+ * ER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABI-
+ * LITY, 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.
+ */
+
+#ifndef ___PKCS11H_BASE_H
+#define ___PKCS11H_BASE_H
+
+#include "common.h"
+
+#include <pkcs11-helper-1.0/pkcs11h-core.h>
+#include <pkcs11-helper-1.0/pkcs11h-certificate.h>
+#include "_pkcs11h-threading.h"
+
+#define PKCS11H_INVALID_SLOT_ID		((CK_SLOT_ID)-1)
+#define PKCS11H_INVALID_SESSION_HANDLE	((CK_SESSION_HANDLE)-1)
+#define PKCS11H_INVALID_OBJECT_HANDLE	((CK_OBJECT_HANDLE)-1)
+
+#define PKCS11H_DEFAULT_SLOTEVENT_POLL		5000
+#define PKCS11H_DEFAULT_MAX_LOGIN_RETRY		3
+#define PKCS11H_DEFAULT_PIN_CACHE_PERIOD	PKCS11H_PIN_CACHE_INFINITE
+
+/*===========================================
+ * Macros
+ */
+
+#define PKCS11H_MSG_LEVEL_TEST(flags) (((unsigned int)flags) <= g_pkcs11h_loglevel)
+
+#if defined(HAVE_CPP_VARARG_MACRO_ISO) && !defined(__LCLINT__)
+# define PKCS11H_LOG(flags, ...) do { if (PKCS11H_MSG_LEVEL_TEST(flags)) _pkcs11h_log((flags), __VA_ARGS__); } while (FALSE)
+# ifdef ENABLE_PKCS11H_DEBUG
+#  define PKCS11H_DEBUG(flags, ...) do { if (PKCS11H_MSG_LEVEL_TEST(flags)) _pkcs11h_log((flags), __VA_ARGS__); } while (FALSE)
+# else
+#  define PKCS11H_DEBUG(flags, ...)
+# endif
+#elif defined(HAVE_CPP_VARARG_MACRO_GCC) && !defined(__LCLINT__)
+# define PKCS11H_LOG(flags, args...) do { if (PKCS11H_MSG_LEVEL_TEST(flags)) _pkcs11h_log((flags), args); } while (FALSE)
+# ifdef ENABLE_PKCS11H_DEBUG
+#  define PKCS11H_DEBUG(flags, args...) do { if (PKCS11H_MSG_LEVEL_TEST(flags)) _pkcs11h_log((flags), args); } while (FALSE)
+# else
+#  define PKCS11H_DEBUG(flags, args...)
+# endif
+#else
+# define PKCS11H_LOG _pkcs11h_log
+# define PKCS11H_DEBUG _pkcs11h_log
+#endif
+
+/*===========================================
+ * Types
+ */
+
+struct pkcs11h_provider_s;
+struct pkcs11h_session_s;
+struct pkcs11h_data_s;
+typedef struct pkcs11h_provider_s *pkcs11h_provider_t;
+typedef struct pkcs11h_session_s *pkcs11h_session_t;
+typedef struct pkcs11h_data_s *pkcs11h_data_t;
+
+struct pkcs11h_provider_s {
+	pkcs11h_provider_t next;
+
+	PKCS11H_BOOL enabled;
+	char reference[1024];
+	char manufacturerID[sizeof (((CK_TOKEN_INFO *)NULL)->manufacturerID)+1];
+	
+#if defined(_WIN32)
+	HANDLE handle;
+#else
+	void *handle;
+#endif
+
+	CK_FUNCTION_LIST_PTR f;
+	PKCS11H_BOOL should_finalize;
+	PKCS11H_BOOL allow_protected_auth;
+	PKCS11H_BOOL cert_is_private;
+	unsigned mask_private_mode;
+	unsigned mask_decrypt_mode;
+	int slot_event_method;
+	int slot_poll_interval;
+
+#if defined(ENABLE_PKCS11H_SLOTEVENT)
+	pkcs11h_thread_t slotevent_thread;
+#endif
+};
+
+struct pkcs11h_session_s {
+	pkcs11h_session_t next;
+
+	int reference_count;
+	PKCS11H_BOOL valid;
+
+	pkcs11h_provider_t provider;
+
+	pkcs11h_token_id_t token_id;
+
+	CK_SESSION_HANDLE session_handle;
+
+	PKCS11H_BOOL allow_protected_auth_supported;
+	int pin_cache_period;
+	time_t pin_expire_time;
+
+#if defined(ENABLE_PKCS11H_CERTIFICATE)
+	pkcs11h_certificate_id_list_t cached_certs;
+	PKCS11H_BOOL touch;
+#endif
+
+#if defined(ENABLE_PKCS11H_THREADING)
+	pkcs11h_mutex_t mutex;
+#endif
+};
+
+#if defined (ENABLE_PKCS11H_CERTIFICATE)
+
+struct pkcs11h_certificate_s {
+
+	pkcs11h_certificate_id_t id;
+	int pin_cache_period;
+	PKCS11H_BOOL pin_cache_populated_to_session;
+
+	unsigned mask_private_mode;
+
+	pkcs11h_session_t session;
+	CK_OBJECT_HANDLE key_handle;
+
+	PKCS11H_BOOL operation_active;
+
+#if defined(ENABLE_PKCS11H_THREADING)
+	pkcs11h_mutex_t mutex;
+#endif
+
+	unsigned mask_prompt;
+	void * user_data;
+};
+
+#endif				/* ENABLE_PKCS11H_CERTIFICATE */
+
+struct pkcs11h_data_s {
+	PKCS11H_BOOL initialized;
+	int pin_cache_period;
+
+	pkcs11h_provider_t providers;
+	pkcs11h_session_t sessions;
+
+	struct {
+		void * log_data;
+		void * slotevent_data;
+		void * token_prompt_data;
+		void * pin_prompt_data;
+		pkcs11h_hook_log_t log;
+		pkcs11h_hook_slotevent_t slotevent;
+		pkcs11h_hook_token_prompt_t token_prompt;
+		pkcs11h_hook_pin_prompt_t pin_prompt;
+	} hooks;
+
+	PKCS11H_BOOL allow_protected_auth;
+	unsigned max_retries;
+
+#if defined(ENABLE_PKCS11H_THREADING)
+	struct {
+		pkcs11h_mutex_t global;
+		pkcs11h_mutex_t session;
+		pkcs11h_mutex_t cache;
+	} mutexes;
+#endif
+
+#if defined(ENABLE_PKCS11H_SLOTEVENT)
+	struct {
+		PKCS11H_BOOL initialized;
+		PKCS11H_BOOL should_terminate;
+		PKCS11H_BOOL skip_event;
+		pkcs11h_cond_t cond_event;
+		pkcs11h_thread_t thread;
+	} slotevent;
+#endif
+};
+
+void
+_pkcs11h_log (
+	IN const unsigned flags,
+	IN const char * const format,
+	IN ...
+)
+#ifdef __GNUC__
+    __attribute__ ((format (printf, 2, 3)))
+#endif
+    ;
+
+extern pkcs11h_data_t g_pkcs11h_data;
+extern unsigned int g_pkcs11h_loglevel;
+
+#endif
diff --git a/lib/_pkcs11h-crypto.h b/lib/_pkcs11h-crypto.h
new file mode 100644
index 0000000..a45cc00
--- /dev/null
+++ b/lib/_pkcs11h-crypto.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2005-2006 Alon Bar-Lev <alon.barlev at gmail.com>
+ * All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, or the OpenIB.org BSD license.
+ *
+ * GNU General Public License (GPL) Version 2
+ * ===========================================
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2
+ *  as published by the Free Software Foundation.
+ *
+ *  This program 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 General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program (see the file COPYING[.GPL2] included with this
+ *  distribution); if not, write to the Free Software Foundation, Inc.,
+ *  59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * OpenIB.org BSD license
+ * =======================
+ * Redistribution and use in source and binary forms, with or without modifi-
+ * cation, are permitted provided that the following conditions are met:
+ *
+ *   o  Redistributions of source code must retain the above copyright notice,
+ *      this list of conditions and the following disclaimer.
+ *
+ *   o  Redistributions in binary form must reproduce the above copyright no-
+ *      tice, this list of conditions and the following disclaimer in the do-
+ *      cumentation and/or other materials provided with the distribution.
+ *
+ *   o  The names of the contributors may not be used to endorse or promote
+ *      products derived from this software without specific prior written
+ *      permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``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 REGENTS OR CONTRIBUTORS BE LI-
+ * ABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUEN-
+ * TIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEV-
+ * ER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABI-
+ * LITY, 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.
+ */
+
+#ifndef ___PKCS11H_CRYPTO_H
+#define ___PKCS11H_CRYPTO_H
+
+#include "common.h"
+
+#include <pkcs11-helper-1.0/pkcs11h-engines.h>
+
+extern pkcs11h_engine_crypto_t g_pkcs11h_crypto_engine;
+
+#endif
+
diff --git a/lib/_pkcs11h-mem.h b/lib/_pkcs11h-mem.h
new file mode 100644
index 0000000..b1bfb24
--- /dev/null
+++ b/lib/_pkcs11h-mem.h
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2005-2006 Alon Bar-Lev <alon.barlev at gmail.com>
+ * All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, or the OpenIB.org BSD license.
+ *
+ * GNU General Public License (GPL) Version 2
+ * ===========================================
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2
+ *  as published by the Free Software Foundation.
+ *
+ *  This program 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 General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program (see the file COPYING[.GPL2] included with this
+ *  distribution); if not, write to the Free Software Foundation, Inc.,
+ *  59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * OpenIB.org BSD license
+ * =======================
+ * Redistribution and use in source and binary forms, with or without modifi-
+ * cation, are permitted provided that the following conditions are met:
+ *
+ *   o  Redistributions of source code must retain the above copyright notice,
+ *      this list of conditions and the following disclaimer.
+ *
+ *   o  Redistributions in binary form must reproduce the above copyright no-
+ *      tice, this list of conditions and the following disclaimer in the do-
+ *      cumentation and/or other materials provided with the distribution.
+ *
+ *   o  The names of the contributors may not be used to endorse or promote
+ *      products derived from this software without specific prior written
+ *      permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``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 REGENTS OR CONTRIBUTORS BE LI-
+ * ABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUEN-
+ * TIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEV-
+ * ER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABI-
+ * LITY, 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.
+ */
+
+#ifndef ___PKCS11H_MEM_H
+#define ___PKCS11H_MEM_H
+
+#include "common.h"
+
+#include <pkcs11-helper-1.0/pkcs11h-def.h>
+
+CK_RV
+_pkcs11h_mem_malloc (
+	OUT const void * * const p,
+	IN const size_t s
+);
+
+CK_RV
+_pkcs11h_mem_free (
+	IN const void * * const p
+);
+
+CK_RV
+_pkcs11h_mem_strdup (
+	OUT const char * * const dest,
+	IN const char * const src
+);
+
+CK_RV
+_pkcs11h_mem_duplicate (
+	OUT const void * * const dest,
+	OUT size_t * const dest_size,
+	IN const void * const src,
+	IN const size_t mem_size
+);
+
+#endif
+
diff --git a/lib/_pkcs11h-session.h b/lib/_pkcs11h-session.h
new file mode 100644
index 0000000..0bc1bc3
--- /dev/null
+++ b/lib/_pkcs11h-session.h
@@ -0,0 +1,143 @@
+/*
+ * Copyright (c) 2005-2006 Alon Bar-Lev <alon.barlev at gmail.com>
+ * All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, or the OpenIB.org BSD license.
+ *
+ * GNU General Public License (GPL) Version 2
+ * ===========================================
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2
+ *  as published by the Free Software Foundation.
+ *
+ *  This program 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 General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program (see the file COPYING[.GPL2] included with this
+ *  distribution); if not, write to the Free Software Foundation, Inc.,
+ *  59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * OpenIB.org BSD license
+ * =======================
+ * Redistribution and use in source and binary forms, with or without modifi-
+ * cation, are permitted provided that the following conditions are met:
+ *
+ *   o  Redistributions of source code must retain the above copyright notice,
+ *      this list of conditions and the following disclaimer.
+ *
+ *   o  Redistributions in binary form must reproduce the above copyright no-
+ *      tice, this list of conditions and the following disclaimer in the do-
+ *      cumentation and/or other materials provided with the distribution.
+ *
+ *   o  The names of the contributors may not be used to endorse or promote
+ *      products derived from this software without specific prior written
+ *      permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``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 REGENTS OR CONTRIBUTORS BE LI-
+ * ABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUEN-
+ * TIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEV-
+ * ER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABI-
+ * LITY, 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.
+ */
+
+#ifndef ___PKCS11H_SESSION_H
+#define ___PKCS11H_SESSION_H
+
+#include "common.h"
+#include "_pkcs11h-core.h"
+
+CK_RV
+_pkcs11h_session_getSlotList (
+	IN const pkcs11h_provider_t provider,
+	IN const CK_BBOOL token_present,
+	OUT CK_SLOT_ID_PTR * const pSlotList,
+	OUT CK_ULONG_PTR pulCount
+);
+
+CK_RV
+_pkcs11h_session_getObjectAttributes (
+	IN const pkcs11h_session_t session,
+	IN const CK_OBJECT_HANDLE object,
+	IN OUT const CK_ATTRIBUTE_PTR attrs,
+	IN const unsigned count
+);
+
+CK_RV
+_pkcs11h_session_freeObjectAttributes (
+	IN OUT const CK_ATTRIBUTE_PTR attrs,
+	IN const unsigned count
+);
+
+CK_RV
+_pkcs11h_session_findObjects (
+	IN const pkcs11h_session_t session,
+	IN const CK_ATTRIBUTE * const filter,
+	IN const CK_ULONG filter_attrs,
+	OUT CK_OBJECT_HANDLE **const p_objects,
+	OUT CK_ULONG *p_objects_found
+);
+
+CK_RV
+_pkcs11h_session_getSessionByTokenId (
+	IN const pkcs11h_token_id_t token_id,
+	OUT pkcs11h_session_t * const p_session
+);
+
+CK_RV
+_pkcs11h_session_release (
+	IN const pkcs11h_session_t session
+);
+
+CK_RV
+_pkcs11h_session_reset (
+	IN const pkcs11h_session_t session,
+	IN void * const user_data,
+	IN const unsigned mask_prompt,
+	OUT CK_SLOT_ID * const p_slot
+);
+
+CK_RV
+_pkcs11h_session_getObjectById (
+	IN const pkcs11h_session_t session,
+	IN const CK_OBJECT_CLASS class,
+	IN const CK_BYTE_PTR id,
+	IN const size_t id_size,
+	OUT CK_OBJECT_HANDLE * const p_handle
+);
+
+CK_RV
+_pkcs11h_session_validate (
+	IN const pkcs11h_session_t session
+);
+
+CK_RV
+_pkcs11h_session_touch (
+	IN const pkcs11h_session_t session
+);
+
+CK_RV
+_pkcs11h_session_login (
+	IN const pkcs11h_session_t session,
+	IN const PKCS11H_BOOL public_only,
+	IN const PKCS11H_BOOL readonly,
+	IN void * const user_data,
+	IN const unsigned mask_prompt
+);
+
+CK_RV
+_pkcs11h_session_logout (
+	IN const pkcs11h_session_t session
+);
+
+#endif
+
diff --git a/lib/_pkcs11h-slotevent.h b/lib/_pkcs11h-slotevent.h
new file mode 100644
index 0000000..80dcc1c
--- /dev/null
+++ b/lib/_pkcs11h-slotevent.h
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2005-2006 Alon Bar-Lev <alon.barlev at gmail.com>
+ * All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, or the OpenIB.org BSD license.
+ *
+ * GNU General Public License (GPL) Version 2
+ * ===========================================
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2
+ *  as published by the Free Software Foundation.
+ *
+ *  This program 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 General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program (see the file COPYING[.GPL2] included with this
+ *  distribution); if not, write to the Free Software Foundation, Inc.,
+ *  59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * OpenIB.org BSD license
+ * =======================
+ * Redistribution and use in source and binary forms, with or without modifi-
+ * cation, are permitted provided that the following conditions are met:
+ *
+ *   o  Redistributions of source code must retain the above copyright notice,
+ *      this list of conditions and the following disclaimer.
+ *
+ *   o  Redistributions in binary form must reproduce the above copyright no-
+ *      tice, this list of conditions and the following disclaimer in the do-
+ *      cumentation and/or other materials provided with the distribution.
+ *
+ *   o  The names of the contributors may not be used to endorse or promote
+ *      products derived from this software without specific prior written
+ *      permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``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 REGENTS OR CONTRIBUTORS BE LI-
+ * ABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUEN-
+ * TIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEV-
+ * ER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABI-
+ * LITY, 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.
+ */
+
+#ifndef ___PKCS11H_SLOTEVENT_H
+#define ___PKCS11H_SLOTEVENT_H
+
+#include "common.h"
+
+#if defined(ENABLE_PKCS11H_SLOTEVENT)
+
+#include <pkcs11-helper-1.0/pkcs11h-def.h>
+
+CK_RV
+_pkcs11h_slotevent_init (void);
+
+CK_RV
+_pkcs11h_slotevent_notify (void);
+
+CK_RV
+_pkcs11h_slotevent_terminate (void);
+
+#endif				/* ENABLE_PKCS11H_SLOTEVENT */
+
+#endif				/* ___PKCS11H_SLOTEVENT_H */
+
diff --git a/lib/_pkcs11h-sys.h b/lib/_pkcs11h-sys.h
new file mode 100644
index 0000000..6f41baa
--- /dev/null
+++ b/lib/_pkcs11h-sys.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2005-2006 Alon Bar-Lev <alon.barlev at gmail.com>
+ * All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, or the OpenIB.org BSD license.
+ *
+ * GNU General Public License (GPL) Version 2
+ * ===========================================
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2
+ *  as published by the Free Software Foundation.
+ *
+ *  This program 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 General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program (see the file COPYING[.GPL2] included with this
+ *  distribution); if not, write to the Free Software Foundation, Inc.,
+ *  59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * OpenIB.org BSD license
+ * =======================
+ * Redistribution and use in source and binary forms, with or without modifi-
+ * cation, are permitted provided that the following conditions are met:
+ *
+ *   o  Redistributions of source code must retain the above copyright notice,
+ *      this list of conditions and the following disclaimer.
+ *
+ *   o  Redistributions in binary form must reproduce the above copyright no-
+ *      tice, this list of conditions and the following disclaimer in the do-
+ *      cumentation and/or other materials provided with the distribution.
+ *
+ *   o  The names of the contributors may not be used to endorse or promote
+ *      products derived from this software without specific prior written
+ *      permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``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 REGENTS OR CONTRIBUTORS BE LI-
+ * ABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUEN-
+ * TIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEV-
+ * ER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABI-
+ * LITY, 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.
+ */
+
+#ifndef ___PKCS11H_SYS_H
+#define ___PKCS11H_SYS_H
+
+#include "common.h"
+
+#include <pkcs11-helper-1.0/pkcs11h-engines.h>
+
+extern pkcs11h_engine_system_t g_pkcs11h_sys_engine;
+
+#endif
+
diff --git a/lib/_pkcs11h-threading.h b/lib/_pkcs11h-threading.h
new file mode 100644
index 0000000..583e119
--- /dev/null
+++ b/lib/_pkcs11h-threading.h
@@ -0,0 +1,161 @@
+/*
+ * Copyright (c) 2005-2006 Alon Bar-Lev <alon.barlev at gmail.com>
+ * All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, or the OpenIB.org BSD license.
+ *
+ * GNU General Public License (GPL) Version 2
+ * ===========================================
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2
+ *  as published by the Free Software Foundation.
+ *
+ *  This program 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 General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program (see the file COPYING[.GPL2] included with this
+ *  distribution); if not, write to the Free Software Foundation, Inc.,
+ *  59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * OpenIB.org BSD license
+ * =======================
+ * Redistribution and use in source and binary forms, with or without modifi-
+ * cation, are permitted provided that the following conditions are met:
+ *
+ *   o  Redistributions of source code must retain the above copyright notice,
+ *      this list of conditions and the following disclaimer.
+ *
+ *   o  Redistributions in binary form must reproduce the above copyright no-
+ *      tice, this list of conditions and the following disclaimer in the do-
+ *      cumentation and/or other materials provided with the distribution.
+ *
+ *   o  The names of the contributors may not be used to endorse or promote
+ *      products derived from this software without specific prior written
+ *      permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``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 REGENTS OR CONTRIBUTORS BE LI-
+ * ABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUEN-
+ * TIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEV-
+ * ER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABI-
+ * LITY, 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.
+ */
+
+#ifndef ___PKCS11H_THREADING_H
+#define ___PKCS11H_THREADING_H
+
+#include "common.h"
+
+#if defined(ENABLE_PKCS11H_THREADING)
+
+#include <pkcs11-helper-1.0/pkcs11h-def.h>
+
+#if !defined(_WIN32)
+#include <pthread.h>
+#endif
+
+#define PKCS11H_COND_INFINITE	0xffffffff
+
+#if defined(_WIN32)
+#define PKCS11H_THREAD_NULL	NULL
+typedef HANDLE pkcs11h_cond_t;
+typedef HANDLE pkcs11h_mutex_t;
+typedef HANDLE pkcs11h_thread_t;
+#else
+#define PKCS11H_THREAD_NULL	0l
+typedef pthread_mutex_t pkcs11h_mutex_t;
+typedef pthread_t pkcs11h_thread_t;
+
+typedef struct {
+	pthread_cond_t cond;
+	pthread_mutex_t mut;
+} pkcs11h_cond_t;
+
+typedef struct __pkcs11h_threading_mutex_entry_s {
+	struct __pkcs11h_threading_mutex_entry_s *next;
+	pkcs11h_mutex_t *p_mutex;
+	PKCS11H_BOOL locked;
+} *__pkcs11h_threading_mutex_entry_t;
+#endif
+
+typedef void * (*pkcs11h_thread_start_t)(void *);
+
+void
+_pkcs11h_threading_sleep (
+	IN const unsigned milli
+);
+
+CK_RV
+_pkcs11h_threading_mutexInit (
+	OUT pkcs11h_mutex_t * const mutex
+);
+
+CK_RV
+_pkcs11h_threading_mutexLock (
+	IN OUT pkcs11h_mutex_t *const mutex
+);
+
+CK_RV
+_pkcs11h_threading_mutexRelease (
+	IN OUT pkcs11h_mutex_t *const mutex
+);
+
+CK_RV
+_pkcs11h_threading_mutexFree (
+	IN OUT pkcs11h_mutex_t *const mutex
+);
+
+CK_RV
+_pkcs11h_threading_condSignal (
+	IN OUT pkcs11h_cond_t *const cond
+);
+
+CK_RV
+_pkcs11h_threading_condInit (
+	OUT pkcs11h_cond_t * const cond
+);
+
+CK_RV
+_pkcs11h_threading_condWait (
+	IN OUT pkcs11h_cond_t *const cond,
+	IN const unsigned milli
+);
+
+CK_RV
+_pkcs11h_threading_condFree (
+	IN OUT pkcs11h_cond_t *const cond
+);
+
+CK_RV
+_pkcs11h_threading_threadStart (
+	OUT pkcs11h_thread_t * const thread,
+	IN pkcs11h_thread_start_t const start,
+	IN void * data
+);
+
+CK_RV
+_pkcs11h_threading_threadJoin (
+	IN pkcs11h_thread_t * const thread
+);
+
+#if !defined(_WIN32)
+void
+_pkcs1h_threading_mutexLockAll (void);
+
+void
+_pkcs1h_threading_mutexReleaseAll (void);
+#endif
+
+#endif
+
+#endif
+
diff --git a/lib/_pkcs11h-token.h b/lib/_pkcs11h-token.h
new file mode 100644
index 0000000..cb0dd13
--- /dev/null
+++ b/lib/_pkcs11h-token.h
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2005-2006 Alon Bar-Lev <alon.barlev at gmail.com>
+ * All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, or the OpenIB.org BSD license.
+ *
+ * GNU General Public License (GPL) Version 2
+ * ===========================================
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2
+ *  as published by the Free Software Foundation.
+ *
+ *  This program 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 General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program (see the file COPYING[.GPL2] included with this
+ *  distribution); if not, write to the Free Software Foundation, Inc.,
+ *  59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * OpenIB.org BSD license
+ * =======================
+ * Redistribution and use in source and binary forms, with or without modifi-
+ * cation, are permitted provided that the following conditions are met:
+ *
+ *   o  Redistributions of source code must retain the above copyright notice,
+ *      this list of conditions and the following disclaimer.
+ *
+ *   o  Redistributions in binary form must reproduce the above copyright no-
+ *      tice, this list of conditions and the following disclaimer in the do-
+ *      cumentation and/or other materials provided with the distribution.
+ *
+ *   o  The names of the contributors may not be used to endorse or promote
+ *      products derived from this software without specific prior written
+ *      permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``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 REGENTS OR CONTRIBUTORS BE LI-
+ * ABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUEN-
+ * TIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEV-
+ * ER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABI-
+ * LITY, 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.
+ */
+
+#ifndef ___PKCS11H_TOKEN_H
+#define ___PKCS11H_TOKEN_H
+
+#include "common.h"
+#include "_pkcs11h-core.h"
+#include <pkcs11-helper-1.0/pkcs11h-token.h>
+
+CK_RV
+_pkcs11h_token_getTokenId (
+	IN const CK_TOKEN_INFO_PTR info,
+	OUT pkcs11h_token_id_t * const p_token_id
+);
+
+CK_RV
+_pkcs11h_token_newTokenId (
+	OUT pkcs11h_token_id_t * const token_id
+);
+
+#endif
diff --git a/lib/_pkcs11h-util.h b/lib/_pkcs11h-util.h
new file mode 100644
index 0000000..c5c211b
--- /dev/null
+++ b/lib/_pkcs11h-util.h
@@ -0,0 +1,98 @@
+/*
+ * Copyright (c) 2005-2006 Alon Bar-Lev <alon.barlev at gmail.com>
+ * All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, or the OpenIB.org BSD license.
+ *
+ * GNU General Public License (GPL) Version 2
+ * ===========================================
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2
+ *  as published by the Free Software Foundation.
+ *
+ *  This program 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 General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program (see the file COPYING[.GPL2] included with this
+ *  distribution); if not, write to the Free Software Foundation, Inc.,
+ *  59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * OpenIB.org BSD license
+ * =======================
+ * Redistribution and use in source and binary forms, with or without modifi-
+ * cation, are permitted provided that the following conditions are met:
+ *
+ *   o  Redistributions of source code must retain the above copyright notice,
+ *      this list of conditions and the following disclaimer.
+ *
+ *   o  Redistributions in binary form must reproduce the above copyright no-
+ *      tice, this list of conditions and the following disclaimer in the do-
+ *      cumentation and/or other materials provided with the distribution.
+ *
+ *   o  The names of the contributors may not be used to endorse or promote
+ *      products derived from this software without specific prior written
+ *      permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``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 REGENTS OR CONTRIBUTORS BE LI-
+ * ABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUEN-
+ * TIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEV-
+ * ER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABI-
+ * LITY, 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.
+ */
+
+#ifndef ___PKCS11H_UTIL_H
+#define ___PKCS11H_UTIL_H
+
+#include "common.h"
+
+#include <pkcs11-helper-1.0/pkcs11h-def.h>
+
+void
+_pkcs11h_util_fixupFixedString (
+	OUT char * const target,			/* MUST BE >= length+1 */
+	IN const char * const source,
+	IN const size_t length				/* FIXED STRING LENGTH */
+);
+
+CK_RV
+_pkcs11h_util_hexToBinary (
+	OUT unsigned char * const target,
+	IN const char * const source,
+	IN OUT size_t * const p_target_size
+);
+
+CK_RV
+_pkcs11h_util_binaryToHex (
+	OUT char * const target,
+	IN const size_t target_size,
+	IN const unsigned char * const source,
+	IN const size_t source_size
+);
+
+CK_RV
+_pkcs11h_util_escapeString (
+	IN OUT char * const target,
+	IN const char * const source,
+	IN size_t * const max,
+	IN const char * const invalid_chars
+);
+
+CK_RV
+_pkcs11h_util_unescapeString (
+	IN OUT char * const target,
+	IN const char * const source,
+	IN size_t * const max
+);
+
+#endif
+
diff --git a/lib/certificate.exports b/lib/certificate.exports
new file mode 100644
index 0000000..be09438
--- /dev/null
+++ b/lib/certificate.exports
@@ -0,0 +1,27 @@
+pkcs11h_certificate_create
+pkcs11h_certificate_decrypt
+pkcs11h_certificate_deserializeCertificateId
+pkcs11h_certificate_duplicateCertificateId
+pkcs11h_certificate_ensureCertificateAccess
+pkcs11h_certificate_ensureKeyAccess
+pkcs11h_certificate_enumCertificateIds
+pkcs11h_certificate_enumTokenCertificateIds
+pkcs11h_certificate_freeCertificate
+pkcs11h_certificate_freeCertificateId
+pkcs11h_certificate_freeCertificateIdList
+pkcs11h_certificate_getCertificateBlob
+pkcs11h_certificate_getCertificateId
+pkcs11h_certificate_getPromptMask
+pkcs11h_certificate_getUserData
+pkcs11h_certificate_lockSession
+pkcs11h_certificate_releaseSession
+pkcs11h_certificate_serializeCertificateId
+pkcs11h_certificate_setCertificateIdCertificateBlob
+pkcs11h_certificate_setPromptMask
+pkcs11h_certificate_setUserData
+pkcs11h_certificate_sign
+pkcs11h_certificate_signAny
+pkcs11h_certificate_signRecover
+pkcs11h_certificate_decrypt
+pkcs11h_certificate_unwrap
+pkcs11h_certificate_decryptAny
diff --git a/lib/common.h b/lib/common.h
new file mode 100644
index 0000000..6c6af4a
--- /dev/null
+++ b/lib/common.h
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2005-2006 Alon Bar-Lev <alon.barlev at gmail.com>
+ * All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, or the OpenIB.org BSD license.
+ *
+ * GNU General Public License (GPL) Version 2
+ * ===========================================
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2
+ *  as published by the Free Software Foundation.
+ *
+ *  This program 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 General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program (see the file COPYING[.GPL2] included with this
+ *  distribution); if not, write to the Free Software Foundation, Inc.,
+ *  59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * OpenIB.org BSD license
+ * =======================
+ * Redistribution and use in source and binary forms, with or without modifi-
+ * cation, are permitted provided that the following conditions are met:
+ *
+ *   o  Redistributions of source code must retain the above copyright notice,
+ *      this list of conditions and the following disclaimer.
+ *
+ *   o  Redistributions in binary form must reproduce the above copyright no-
+ *      tice, this list of conditions and the following disclaimer in the do-
+ *      cumentation and/or other materials provided with the distribution.
+ *
+ *   o  The names of the contributors may not be used to endorse or promote
+ *      products derived from this software without specific prior written
+ *      permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``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 REGENTS OR CONTRIBUTORS BE LI-
+ * ABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUEN-
+ * TIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEV-
+ * ER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABI-
+ * LITY, 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.
+ */
+
+#ifndef __COMMON_H
+#define __COMMON_H
+
+#if defined(_MSC_VER)
+#include "../config-w32-vc.h"
+#else
+#include "../config.h"
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <assert.h>
+#include <ctype.h>
+
+#if defined(_WIN32)
+#include <windows.h>
+#endif
+
+#define PKCS11H_ASSERT		assert
+
+#endif
+
diff --git a/lib/core.exports b/lib/core.exports
new file mode 100644
index 0000000..6851107
--- /dev/null
+++ b/lib/core.exports
@@ -0,0 +1,19 @@
+pkcs11h_addProvider
+pkcs11h_engine_setCrypto
+pkcs11h_engine_setSystem
+pkcs11h_forkFixup
+pkcs11h_getFeatures
+pkcs11h_getLogLevel
+pkcs11h_getMessage
+pkcs11h_getVersion
+pkcs11h_initialize
+pkcs11h_terminate
+pkcs11h_plugAndPlay
+pkcs11h_removeProvider
+pkcs11h_setLogHook
+pkcs11h_setLogLevel
+pkcs11h_setMaxLoginRetries
+pkcs11h_setPINCachePeriod
+pkcs11h_setPINPromptHook
+pkcs11h_setProtectedAuthentication
+pkcs11h_setTokenPromptHook
diff --git a/lib/data.exports b/lib/data.exports
new file mode 100644
index 0000000..136d634
--- /dev/null
+++ b/lib/data.exports
@@ -0,0 +1,5 @@
+pkcs11h_data_del
+pkcs11h_data_enumDataObjects
+pkcs11h_data_freeDataIdList
+pkcs11h_data_get
+pkcs11h_data_put
diff --git a/lib/libpkcs11-helper-1.pc.in b/lib/libpkcs11-helper-1.pc.in
new file mode 100644
index 0000000..ab1cf09
--- /dev/null
+++ b/lib/libpkcs11-helper-1.pc.in
@@ -0,0 +1,11 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+features=@PKCS11H_FEATURES@
+
+Name: pkcs11-helper
+Description: PKCS#11 helper library
+Version: @PACKAGE_VERSION@
+Cflags: -I${includedir}
+Libs: -L${libdir} -lpkcs11-helper @LIBS@
diff --git a/lib/locate.exports b/lib/locate.exports
new file mode 100644
index 0000000..027174b
--- /dev/null
+++ b/lib/locate.exports
@@ -0,0 +1,2 @@
+pkcs11h_locate_certificate
+pkcs11h_locate_token
diff --git a/lib/openssl.exports b/lib/openssl.exports
new file mode 100644
index 0000000..0396e44
--- /dev/null
+++ b/lib/openssl.exports
@@ -0,0 +1,7 @@
+pkcs11h_openssl_createSession
+pkcs11h_openssl_freeSession
+pkcs11h_openssl_getCleanupHook
+pkcs11h_openssl_getX509
+pkcs11h_openssl_session_getRSA
+pkcs11h_openssl_session_getX509
+pkcs11h_openssl_setCleanupHook
diff --git a/lib/pkcs11h-certificate.c b/lib/pkcs11h-certificate.c
new file mode 100644
index 0000000..41fce22
--- /dev/null
+++ b/lib/pkcs11h-certificate.c
@@ -0,0 +1,2914 @@
+/*
+ * Copyright (c) 2005-2006 Alon Bar-Lev <alon.barlev at gmail.com>
+ * All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, or the OpenIB.org BSD license.
+ *
+ * GNU General Public License (GPL) Version 2
+ * ===========================================
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2
+ *  as published by the Free Software Foundation.
+ *
+ *  This program 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 General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program (see the file COPYING[.GPL2] included with this
+ *  distribution); if not, write to the Free Software Foundation, Inc.,
+ *  59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * OpenIB.org BSD license
+ * =======================
+ * Redistribution and use in source and binary forms, with or without modifi-
+ * cation, are permitted provided that the following conditions are met:
+ *
+ *   o  Redistributions of source code must retain the above copyright notice,
+ *      this list of conditions and the following disclaimer.
+ *
+ *   o  Redistributions in binary form must reproduce the above copyright no-
+ *      tice, this list of conditions and the following disclaimer in the do-
+ *      cumentation and/or other materials provided with the distribution.
+ *
+ *   o  The names of the contributors may not be used to endorse or promote
+ *      products derived from this software without specific prior written
+ *      permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``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 REGENTS OR CONTRIBUTORS BE LI-
+ * ABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUEN-
+ * TIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEV-
+ * ER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABI-
+ * LITY, 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.
+ */
+
+#include "common.h"
+
+#if defined(ENABLE_PKCS11H_CERTIFICATE)
+
+#include <pkcs11-helper-1.0/pkcs11h-token.h>
+#include <pkcs11-helper-1.0/pkcs11h-certificate.h>
+#include "_pkcs11h-mem.h"
+#include "_pkcs11h-sys.h"
+#include "_pkcs11h-crypto.h"
+#include "_pkcs11h-session.h"
+#include "_pkcs11h-token.h"
+#include "_pkcs11h-certificate.h"
+
+enum _pkcs11h_private_op_e {
+	_pkcs11h_private_op_sign=0,
+	_pkcs11h_private_op_sign_recover,
+	_pkcs11h_private_op_decrypt,
+	_pkcs11h_private_op_unwrap
+};
+
+static
+CK_RV
+__pkcs11h_certificate_doPrivateOperation (
+	IN const pkcs11h_certificate_t certificate,
+	IN const enum _pkcs11h_private_op_e op,
+	IN const CK_MECHANISM_TYPE mech_type,
+	IN const unsigned char * const source,
+	IN const size_t source_size,
+	OUT unsigned char * const target,
+	IN OUT size_t * const p_target_size
+);
+
+static
+CK_RV
+__pkcs11h_certificate_loadCertificate (
+	IN const pkcs11h_certificate_t certificate
+);
+
+static
+CK_RV
+__pkcs11h_certificate_updateCertificateIdDescription (
+	IN OUT pkcs11h_certificate_id_t certificate_id
+);
+
+static
+CK_RV
+__pkcs11h_certificate_getKeyAttributes (
+	IN const pkcs11h_certificate_t certificate
+);
+
+static
+CK_RV
+__pkcs11h_certificate_splitCertificateIdList (
+	IN const pkcs11h_certificate_id_list_t cert_id_all,
+	OUT pkcs11h_certificate_id_list_t * const p_cert_id_issuers_list,
+	OUT pkcs11h_certificate_id_list_t * const p_cert_id_end_list
+);
+
+PKCS11H_BOOL
+_pkcs11h_certificate_isBetterCertificate (
+	IN const unsigned char * const current,
+	IN const size_t current_size,
+	IN const unsigned char * const newone,
+	IN const size_t newone_size
+) {
+	PKCS11H_BOOL is_better = FALSE;
+
+	/*PKCS11H_ASSERT (current!=NULL); NOT NEEDED */
+	PKCS11H_ASSERT (newone!=NULL);
+
+	PKCS11H_DEBUG (
+		PKCS11H_LOG_DEBUG2,
+		"PKCS#11: _pkcs11h_certificate_isBetterCertificate entry current=%p, current_size=%u, newone=%p, newone_size=%u",
+		current,
+		current_size,
+		newone,
+		newone_size
+	);
+
+	/*
+	 * First certificae
+	 * always select
+	 */
+	if (current_size == 0 || current == NULL) {
+		is_better = TRUE;
+	}
+	else {
+		time_t notAfterCurrent, notAfterNew;
+
+		if (
+			!g_pkcs11h_crypto_engine.certificate_get_expiration (
+				g_pkcs11h_crypto_engine.global_data,
+				current,
+				current_size,
+				&notAfterCurrent
+			)
+		) {
+			notAfterCurrent = (time_t)0;
+		}
+
+		if (
+			!g_pkcs11h_crypto_engine.certificate_get_expiration (
+				g_pkcs11h_crypto_engine.global_data,
+				newone,
+				newone_size,
+				&notAfterNew
+			)
+		) {
+			notAfterCurrent = (time_t)0;
+		}
+
+		PKCS11H_DEBUG (
+			PKCS11H_LOG_DEBUG2,
+			"PKCS#11: _pkcs11h_certificate_isBetterCertificate notAfterCurrent='%s', notAfterNew='%s'",
+			asctime (localtime (&notAfterCurrent)),
+			asctime (localtime (&notAfterNew))
+		);
+
+		is_better = notAfterNew > notAfterCurrent;
+	}
+
+	PKCS11H_DEBUG (
+		PKCS11H_LOG_DEBUG2,
+		"PKCS#11: _pkcs11h_certificate_isBetterCertificate return is_better=%d",
+		is_better ? 1 : 0
+	);
+	
+	return is_better;
+}
+
+CK_RV
+_pkcs11h_certificate_newCertificateId (
+	OUT pkcs11h_certificate_id_t * const p_certificate_id
+) {
+	CK_RV rv = CKR_OK;
+
+	PKCS11H_ASSERT (p_certificate_id!=NULL);
+
+	PKCS11H_DEBUG (
+		PKCS11H_LOG_DEBUG2,
+		"PKCS#11: _pkcs11h_certificate_newCertificateId entry p_certificate_id=%p",
+		(void *)p_certificate_id
+	);
+
+	*p_certificate_id = NULL;
+
+	if (rv == CKR_OK) {
+		rv = _pkcs11h_mem_malloc ((void *)p_certificate_id, sizeof (struct pkcs11h_certificate_id_s));
+	}
+
+	PKCS11H_DEBUG (
+		PKCS11H_LOG_DEBUG2,
+		"PKCS#11: _pkcs11h_certificate_newCertificateId return rv=%ld-'%s', *p_certificate_id=%p",
+		rv,
+		pkcs11h_getMessage (rv),
+		(void *)*p_certificate_id
+	);
+
+	return rv;
+}
+
+static
+CK_RV
+__pkcs11h_certificate_loadCertificate (
+	IN const pkcs11h_certificate_t certificate
+) {
+	/*
+	 * THREADING:
+	 * certificate->mutex must be locked
+	 */
+#if defined(ENABLE_PKCS11H_THREADING)
+	PKCS11H_BOOL mutex_locked = FALSE;
+#endif
+	CK_OBJECT_CLASS cert_filter_class = CKO_CERTIFICATE;
+	CK_ATTRIBUTE cert_filter[] = {
+		{CKA_CLASS, &cert_filter_class, sizeof (cert_filter_class)},
+		{CKA_ID, NULL, 0}
+	};
+
+	CK_OBJECT_HANDLE *objects = NULL;
+	CK_ULONG objects_found = 0;
+	CK_RV rv = CKR_OK;
+
+	CK_ULONG i;
+
+	PKCS11H_ASSERT (certificate!=NULL);
+	PKCS11H_ASSERT (certificate->id!=NULL);
+	
+	/* Must be after assert */
+	cert_filter[1].pValue = certificate->id->attrCKA_ID;
+	cert_filter[1].ulValueLen = certificate->id->attrCKA_ID_size;
+
+	PKCS11H_DEBUG (
+		PKCS11H_LOG_DEBUG2,
+		"PKCS#11: __pkcs11h_certificate_loadCertificate entry certificate=%p",
+		(void *)certificate
+	);
+
+#if defined(ENABLE_PKCS11H_THREADING)
+	if (
+		rv == CKR_OK &&
+		(rv = _pkcs11h_threading_mutexLock (&certificate->session->mutex)) == CKR_OK
+	) {
+		mutex_locked = TRUE;
+	}
+#endif
+
+	if (rv == CKR_OK) {
+		rv = _pkcs11h_session_validate (certificate->session);
+	}
+
+	if (rv == CKR_OK) {
+		rv = _pkcs11h_session_findObjects (
+			certificate->session,
+			cert_filter,
+			sizeof (cert_filter) / sizeof (CK_ATTRIBUTE),
+			&objects,
+			&objects_found
+		);
+	}
+
+	for (i=0;rv == CKR_OK && i < objects_found;i++) {
+		CK_ATTRIBUTE attrs[] = {
+			{CKA_VALUE, NULL, 0}
+		};
+
+		if (
+			rv == CKR_OK &&
+			(rv = _pkcs11h_session_getObjectAttributes (
+				certificate->session,
+				objects[i],
+				attrs,
+				sizeof (attrs) / sizeof (CK_ATTRIBUTE)
+			)) == CKR_OK
+		) {
+			if (
+				_pkcs11h_certificate_isBetterCertificate (
+					certificate->id->certificate_blob,
+					certificate->id->certificate_blob_size,
+					attrs[0].pValue,
+					attrs[0].ulValueLen
+				)
+			) {
+				if (certificate->id->certificate_blob != NULL) {
+					_pkcs11h_mem_free ((void *)&certificate->id->certificate_blob);
+				}
+
+				rv = _pkcs11h_mem_duplicate (
+					(void*)&certificate->id->certificate_blob,
+					&certificate->id->certificate_blob_size,
+					attrs[0].pValue,
+					attrs[0].ulValueLen
+				);
+			}
+		}
+
+		if (rv != CKR_OK) {
+			PKCS11H_DEBUG (
+				PKCS11H_LOG_DEBUG1,
+				"PKCS#11: Cannot get object attribute for provider '%s' object %ld rv=%ld-'%s'",
+				certificate->session->provider->manufacturerID,
+				objects[i],
+				rv,
+				pkcs11h_getMessage (rv)
+			);
+
+			/*
+			 * Ignore error
+			 */
+			rv = CKR_OK;
+		}
+
+		_pkcs11h_session_freeObjectAttributes (
+			attrs,
+			sizeof (attrs) / sizeof (CK_ATTRIBUTE)
+		);
+	}
+	
+#if defined(ENABLE_PKCS11H_THREADING)
+	if (mutex_locked) {
+		_pkcs11h_threading_mutexRelease (&certificate->session->mutex);
+		mutex_locked = FALSE;
+	}
+#endif
+
+	if (
+		rv == CKR_OK &&
+		certificate->id->certificate_blob == NULL
+	) {
+		rv = CKR_ATTRIBUTE_VALUE_INVALID;
+	}
+
+	if (objects != NULL) {
+		_pkcs11h_mem_free ((void *)&objects);
+	}
+
+	/*
+	 * No need to free allocated objects
+	 * on error, since the certificate_id
+	 * should be free by caller.
+	 */
+
+	PKCS11H_DEBUG (
+		PKCS11H_LOG_DEBUG2,
+		"PKCS#11: __pkcs11h_certificate_loadCertificate return rv=%ld-'%s'",
+		rv,
+		pkcs11h_getMessage (rv)
+	);
+
+	return rv;
+}
+
+static
+CK_RV
+__pkcs11h_certificate_updateCertificateIdDescription (
+	IN OUT pkcs11h_certificate_id_t certificate_id
+) {
+	static const char * separator = " on ";
+	static const char * unknown = "UNKNOWN";
+
+	PKCS11H_ASSERT (certificate_id!=NULL);
+
+	PKCS11H_DEBUG (
+		PKCS11H_LOG_DEBUG2,
+		"PKCS#11: __pkcs11h_certificate_updateCertificateIdDescription entry certificate_id=%p",
+		(void *)certificate_id
+	);
+
+	if (
+		certificate_id->certificate_blob_size != 0 &&
+		!g_pkcs11h_crypto_engine.certificate_get_dn (
+			g_pkcs11h_crypto_engine.global_data,
+			certificate_id->certificate_blob,
+			certificate_id->certificate_blob_size,
+			certificate_id->displayName,
+			sizeof (certificate_id->displayName)
+		)
+	) {
+		certificate_id->displayName[0] = '\x0';
+	}
+
+	if (strlen (certificate_id->displayName) == 0) {
+		strncpy (
+			certificate_id->displayName,
+			unknown,
+			sizeof (certificate_id->displayName)-1
+		);
+	}
+
+	/*
+	 * Try to avoid using snprintf,
+	 * may be unavailable
+	 */
+	strncat (
+		certificate_id->displayName,
+		separator,
+		sizeof (certificate_id->displayName)-1-strlen (certificate_id->displayName)
+	);
+	strncat (
+		certificate_id->displayName,
+		certificate_id->token_id->display,
+		sizeof (certificate_id->displayName)-1-strlen (certificate_id->displayName)
+	);
+	certificate_id->displayName[sizeof (certificate_id->displayName) - 1] = '\0';
+
+	PKCS11H_DEBUG (
+		PKCS11H_LOG_DEBUG2,
+		"PKCS#11: __pkcs11h_certificate_updateCertificateIdDescription return displayName='%s'",
+		certificate_id->displayName
+	);
+
+	return CKR_OK;
+}
+
+static
+CK_RV
+__pkcs11h_certificate_getKeyAttributes (
+	IN const pkcs11h_certificate_t certificate
+) {
+#if defined(ENABLE_PKCS11H_THREADING)
+	PKCS11H_BOOL mutex_locked = FALSE;
+#endif
+	CK_RV rv = CKR_OK;
+
+	PKCS11H_BOOL op_succeed = FALSE;
+	PKCS11H_BOOL login_retry = FALSE;
+
+	PKCS11H_ASSERT (certificate!=NULL);
+
+	PKCS11H_DEBUG (
+		PKCS11H_LOG_DEBUG2,
+		"PKCS#11: __pkcs11h_certificate_getKeyAttributes entry certificate=%p",
+		(void *)certificate
+	);
+
+#if defined(ENABLE_PKCS11H_THREADING)
+	if (
+		rv == CKR_OK &&
+		(rv = _pkcs11h_threading_mutexLock (&certificate->mutex)) == CKR_OK
+	) {
+		mutex_locked = TRUE;
+	}
+#endif
+
+	certificate->mask_private_mode = 0;
+
+	while (rv == CKR_OK && !op_succeed) {
+		CK_ATTRIBUTE key_attrs[] = {
+			{CKA_SIGN, NULL, 0},
+			{CKA_SIGN_RECOVER, NULL, 0},
+			{CKA_DECRYPT, NULL, 0},
+			{CKA_UNWRAP, NULL, 0}
+		};
+
+		/*
+		 * Don't try invalid object
+		 */
+		if (
+			rv == CKR_OK &&
+			certificate->key_handle == PKCS11H_INVALID_OBJECT_HANDLE
+		) {
+			rv = CKR_OBJECT_HANDLE_INVALID;
+		}
+
+		if (rv == CKR_OK) {
+			if (certificate->session->provider->mask_private_mode != 0) {
+				certificate->mask_private_mode = certificate->session->provider->mask_private_mode;
+				op_succeed = TRUE;
+				PKCS11H_DEBUG (
+					PKCS11H_LOG_DEBUG1,
+					"PKCS#11: Key attributes enforced by provider (%08x)",
+					certificate->mask_private_mode
+				);
+			}
+		}
+
+		if (rv == CKR_OK && !op_succeed) {
+			rv = _pkcs11h_session_getObjectAttributes (
+				certificate->session,
+				certificate->key_handle,
+				key_attrs,
+				sizeof (key_attrs) / sizeof (CK_ATTRIBUTE)
+			);
+		}
+
+		if (rv == CKR_OK && !op_succeed) {
+			CK_BBOOL *key_attrs_sign = (CK_BBOOL *)key_attrs[0].pValue;
+			CK_BBOOL *key_attrs_sign_recover = (CK_BBOOL *)key_attrs[1].pValue;
+			CK_BBOOL *key_attrs_decrypt = (CK_BBOOL *)key_attrs[2].pValue;
+			CK_BBOOL *key_attrs_unwrap = (CK_BBOOL *)key_attrs[3].pValue;
+
+			if (key_attrs_sign != NULL && *key_attrs_sign != CK_FALSE) {
+				certificate->mask_private_mode |= PKCS11H_PRIVATEMODE_MASK_SIGN;
+			}
+			if (key_attrs_sign_recover != NULL && *key_attrs_sign_recover != CK_FALSE) {
+				certificate->mask_private_mode |= PKCS11H_PRIVATEMODE_MASK_RECOVER;
+			}
+			if (key_attrs_decrypt != NULL && *key_attrs_decrypt != CK_FALSE) {
+				certificate->mask_private_mode |= PKCS11H_PRIVATEMODE_MASK_DECRYPT;
+			}
+			if (key_attrs_unwrap != NULL && *key_attrs_unwrap != CK_FALSE) {
+				certificate->mask_private_mode |= PKCS11H_PRIVATEMODE_MASK_UNWRAP;
+			}
+			if (certificate->mask_private_mode == 0) {
+				rv = CKR_KEY_TYPE_INCONSISTENT;
+			}
+			PKCS11H_DEBUG (
+				PKCS11H_LOG_DEBUG1,
+				"PKCS#11: Key attributes loaded (%08x)",
+				certificate->mask_private_mode
+			);
+		}
+
+		_pkcs11h_session_freeObjectAttributes (
+			key_attrs,
+			sizeof (key_attrs) / sizeof (CK_ATTRIBUTE)
+		);
+
+		if (rv == CKR_OK) {
+			op_succeed = TRUE;
+		}
+		else {
+			if (!login_retry) {
+				PKCS11H_DEBUG (
+					PKCS11H_LOG_DEBUG1,
+					"PKCS#11: Get private key attributes failed: %ld:'%s'",
+					rv,
+					pkcs11h_getMessage (rv)
+				);
+
+				rv = _pkcs11h_certificate_resetSession (
+					certificate,
+					FALSE,
+					TRUE
+				);
+
+				login_retry = TRUE;
+			}
+		}
+	}
+
+#if defined(ENABLE_PKCS11H_THREADING)
+	if (mutex_locked) {
+		_pkcs11h_threading_mutexRelease (&certificate->mutex);
+		mutex_locked = FALSE;
+	}
+#endif
+	
+	PKCS11H_DEBUG (
+		PKCS11H_LOG_DEBUG2,
+		"PKCS#11: __pkcs11h_certificate_getKeyAttributes return rv=%ld-'%s'",
+		rv,
+		pkcs11h_getMessage (rv)
+	);
+
+	return rv;
+}
+
+CK_RV
+_pkcs11h_certificate_validateSession (
+	IN const pkcs11h_certificate_t certificate
+) {
+	/*
+	 * THREADING:
+	 * certificate->mutex must be locked
+	 * certificate->session->mutex must be locked
+	 */
+	CK_RV rv = CKR_OK;
+
+	PKCS11H_ASSERT (certificate!=NULL);
+
+	PKCS11H_DEBUG (
+		PKCS11H_LOG_DEBUG2,
+		"PKCS#11: _pkcs11h_certificate_validateSession entry certificate=%p",
+		(void *)certificate
+	);
+
+	if (certificate->session == NULL) {
+		rv = CKR_SESSION_HANDLE_INVALID;
+	}
+
+	if (rv == CKR_OK) {
+		rv = _pkcs11h_session_validate (certificate->session);
+	}
+
+	if (rv == CKR_OK) {
+		if (certificate->key_handle == PKCS11H_INVALID_OBJECT_HANDLE) {
+			rv = CKR_OBJECT_HANDLE_INVALID;
+		}
+	}
+
+	PKCS11H_DEBUG (
+		PKCS11H_LOG_DEBUG2,
+		"PKCS#11: _pkcs11h_certificate_validateSession return rv=%ld-'%s'",
+		rv,
+		pkcs11h_getMessage (rv)
+	);
+
+	return rv;
+}
+
+CK_RV
+_pkcs11h_certificate_resetSession (
+	IN const pkcs11h_certificate_t certificate,
+	IN const PKCS11H_BOOL public_only,
+	IN const PKCS11H_BOOL session_mutex_locked
+) {
+	/*
+	 * THREADING:
+	 * certificate->mutex must be locked
+	 */
+#if defined(ENABLE_PKCS11H_THREADING)
+	PKCS11H_BOOL mutex_locked = FALSE;
+#endif
+	PKCS11H_BOOL is_key_valid = FALSE;
+	CK_RV rv = CKR_OK;
+
+	PKCS11H_ASSERT (certificate!=NULL);
+	
+	PKCS11H_DEBUG (
+		PKCS11H_LOG_DEBUG2,
+		"PKCS#11: _pkcs11h_certificate_resetSession entry certificate=%p, public_only=%d, session_mutex_locked=%d",
+		(void *)certificate,
+		public_only ? 1 : 0,
+		session_mutex_locked ? 1 : 0
+	);
+
+	if (rv == CKR_OK && certificate->session == NULL) {
+		rv = _pkcs11h_session_getSessionByTokenId (certificate->id->token_id, &certificate->session);
+	}
+
+#if defined(ENABLE_PKCS11H_THREADING)
+	if (
+		rv == CKR_OK &&
+		!session_mutex_locked &&
+		(rv = _pkcs11h_threading_mutexLock (&certificate->session->mutex)) == CKR_OK
+	) {
+		mutex_locked = TRUE;
+	}
+#endif
+
+	if (
+		rv == CKR_OK &&
+		!certificate->pin_cache_populated_to_session
+	) {
+		certificate->pin_cache_populated_to_session = TRUE;
+
+		if (certificate->pin_cache_period != PKCS11H_PIN_CACHE_INFINITE) {
+			if (certificate->session->pin_cache_period != PKCS11H_PIN_CACHE_INFINITE) {
+				if (certificate->session->pin_cache_period > certificate->pin_cache_period) {
+					certificate->session->pin_expire_time = (
+						certificate->session->pin_expire_time -
+						(time_t)certificate->session->pin_cache_period +
+						(time_t)certificate->pin_cache_period
+					);
+					certificate->session->pin_cache_period = certificate->pin_cache_period;
+				}
+			}
+			else {
+				certificate->session->pin_expire_time = (
+					g_pkcs11h_sys_engine.time () +
+					(time_t)certificate->pin_cache_period
+				);
+				certificate->session->pin_cache_period = certificate->pin_cache_period;
+			}
+		}	
+	}
+
+	/*
+	 * First, if session seems to be valid
+	 * and key handle is invalid (hard-set),
+	 * try to fetch key handle,
+	 * maybe the token is already logged in
+	 */
+	if (rv == CKR_OK) {
+		if (
+			certificate->session->session_handle != PKCS11H_INVALID_SESSION_HANDLE &&
+			certificate->key_handle == PKCS11H_INVALID_OBJECT_HANDLE
+		) {
+			if (!public_only || certificate->session->provider->cert_is_private) {
+				if (
+					(rv = _pkcs11h_session_getObjectById (
+						certificate->session,
+						CKO_PRIVATE_KEY,
+						certificate->id->attrCKA_ID,
+						certificate->id->attrCKA_ID_size,
+						&certificate->key_handle
+					)) == CKR_OK
+				) {
+					is_key_valid = TRUE;
+				}
+				else {
+					/*
+					 * Ignore error
+					 */
+					rv = CKR_OK;
+					certificate->key_handle = PKCS11H_INVALID_OBJECT_HANDLE;
+				}
+			}
+		}
+	}
+
+	if (
+		!is_key_valid &&
+		rv == CKR_OK &&
+		(rv = _pkcs11h_session_login (
+			certificate->session,
+			public_only,
+			TRUE,
+			certificate->user_data,
+			certificate->mask_prompt
+		)) == CKR_OK
+	) {
+		rv = __pkcs11h_certificate_updateCertificateIdDescription (certificate->id);
+	}
+
+	if (
+		!is_key_valid &&
+		rv == CKR_OK &&
+		!public_only &&
+		(rv = _pkcs11h_session_getObjectById (
+			certificate->session,
+			CKO_PRIVATE_KEY,
+			certificate->id->attrCKA_ID,
+			certificate->id->attrCKA_ID_size,
+			&certificate->key_handle
+		)) == CKR_OK
+	) {
+		is_key_valid = TRUE;
+	}
+
+	if (
+		rv == CKR_OK &&
+		!public_only &&
+		!is_key_valid
+	) {
+		rv = CKR_FUNCTION_REJECTED;
+	}
+
+#if defined(ENABLE_PKCS11H_THREADING)
+	if (mutex_locked) {
+		_pkcs11h_threading_mutexRelease (&certificate->session->mutex);
+		mutex_locked = FALSE;
+	}
+#endif
+
+	PKCS11H_DEBUG (
+		PKCS11H_LOG_DEBUG2,
+		"PKCS#11: _pkcs11h_certificate_resetSession return rv=%ld-'%s'",
+		rv,
+		pkcs11h_getMessage (rv)
+	);
+
+	return rv;
+}
+
+static
+CK_RV
+__pkcs11h_certificate_doPrivateOperation (
+	IN const pkcs11h_certificate_t certificate,
+	IN const enum _pkcs11h_private_op_e op,
+	IN const CK_MECHANISM_TYPE mech_type,
+	IN const unsigned char * const source,
+	IN const size_t source_size,
+	OUT unsigned char * const target,
+	IN OUT size_t * const p_target_size
+) {
+#if defined(ENABLE_PKCS11H_THREADING)
+	PKCS11H_BOOL mutex_locked = FALSE;
+#endif
+	CK_MECHANISM mech = {
+		mech_type, NULL, 0
+	};
+
+	CK_BBOOL wrap_attrs_false = CK_FALSE;
+	CK_BBOOL wrap_attrs_true = CK_TRUE;
+	CK_ATTRIBUTE wrap_attrs[] = {
+		{CKA_VALUE, target, *p_target_size},
+		{CKA_ALWAYS_SENSITIVE, &wrap_attrs_false, sizeof (wrap_attrs_false)},
+		{CKA_NEVER_EXTRACTABLE, &wrap_attrs_false, sizeof (wrap_attrs_false)},
+		{CKA_EXTRACTABLE, &wrap_attrs_true, sizeof (wrap_attrs_true)},
+		{CKA_LOCAL, &wrap_attrs_false, sizeof (wrap_attrs_false)},
+		{CKA_TOKEN, &wrap_attrs_false, sizeof (wrap_attrs_false)}
+	};
+	CK_OBJECT_HANDLE wrap_key = PKCS11H_INVALID_OBJECT_HANDLE;
+	
+	CK_RV rv = CKR_OK;
+	PKCS11H_BOOL login_retry = FALSE;
+	PKCS11H_BOOL op_succeed = FALSE;
+
+	PKCS11H_ASSERT (g_pkcs11h_data!=NULL);
+	PKCS11H_ASSERT (g_pkcs11h_data->initialized);
+	PKCS11H_ASSERT (certificate!=NULL);
+	PKCS11H_ASSERT (source!=NULL);
+	/*PKCS11H_ASSERT (target); NOT NEEDED*/
+	PKCS11H_ASSERT (p_target_size!=NULL);
+
+	PKCS11H_DEBUG (
+		PKCS11H_LOG_DEBUG2,
+		"PKCS#11: __pkcs11h_certificate_doPrivateOperation entry certificate=%p, op=%d, mech_type=%ld, source=%p, source_size=%u, target=%p, *p_target_size=%u",
+		(void *)certificate,
+		op,
+		mech_type,
+		source,
+		source_size,
+		target,
+		target != NULL ? *p_target_size : 0
+	);
+
+	if (target == NULL) {
+		*p_target_size = 0;
+	}
+
+#if defined(ENABLE_PKCS11H_THREADING)
+	if (
+		rv == CKR_OK &&
+		(rv = _pkcs11h_threading_mutexLock (&certificate->mutex)) == CKR_OK
+	) {
+		mutex_locked = TRUE;
+	}
+#endif
+
+	while (rv == CKR_OK && !op_succeed) {
+		if (rv == CKR_OK && !certificate->operation_active) {
+			rv = _pkcs11h_certificate_validateSession (certificate);
+		}
+
+		if (rv == CKR_OK && !certificate->operation_active) {
+			switch (op) {
+				case _pkcs11h_private_op_sign:
+					rv = certificate->session->provider->f->C_SignInit (
+						certificate->session->session_handle,
+						&mech,
+						certificate->key_handle
+					);
+				break;
+				case _pkcs11h_private_op_sign_recover:
+					rv = certificate->session->provider->f->C_SignRecoverInit (
+						certificate->session->session_handle,
+						&mech,
+						certificate->key_handle
+					);
+				break;
+				case _pkcs11h_private_op_decrypt:
+					rv = certificate->session->provider->f->C_DecryptInit (
+						certificate->session->session_handle,
+						&mech,
+						certificate->key_handle
+					);
+				break;
+				case _pkcs11h_private_op_unwrap:
+					rv = certificate->session->provider->f->C_UnwrapKey (
+						certificate->session->session_handle,
+						&mech,
+						certificate->key_handle,
+						(CK_BYTE_PTR)source,
+						source_size,
+						wrap_attrs,
+						sizeof (wrap_attrs) / sizeof (CK_ATTRIBUTE),
+						&wrap_key
+					);
+				break;
+				default:
+					rv = CKR_ARGUMENTS_BAD;
+				break;
+			}
+
+			PKCS11H_DEBUG (
+				PKCS11H_LOG_DEBUG2,
+				"PKCS#11: __pkcs11h_certificate_doPrivateOperation init rv=%ld",
+				rv
+			);
+		}
+
+		if (rv == CKR_OK) {
+			CK_ULONG size = *p_target_size;
+
+			switch (op) {
+				case _pkcs11h_private_op_sign:
+					rv = certificate->session->provider->f->C_Sign (
+						certificate->session->session_handle,
+						(CK_BYTE_PTR)source,
+						source_size,
+						(CK_BYTE_PTR)target,
+						&size
+					);
+				break;
+				case _pkcs11h_private_op_sign_recover:
+					rv = certificate->session->provider->f->C_SignRecover (
+						certificate->session->session_handle,
+						(CK_BYTE_PTR)source,
+						source_size,
+						(CK_BYTE_PTR)target,
+						&size
+					);
+				break;
+				case _pkcs11h_private_op_decrypt:
+					rv = certificate->session->provider->f->C_Decrypt (
+						certificate->session->session_handle,
+						(CK_BYTE_PTR)source,
+						source_size,
+						(CK_BYTE_PTR)target,
+						&size
+					);
+				break;
+				case _pkcs11h_private_op_unwrap:
+					size = wrap_attrs[0].ulValueLen;
+					rv = certificate->session->provider->f->C_DestroyObject (
+						certificate->session->session_handle,
+						wrap_key
+					);
+				break;
+				default:
+					rv = CKR_ARGUMENTS_BAD;
+				break;
+			}
+
+			*p_target_size = size;
+
+			PKCS11H_DEBUG (
+				PKCS11H_LOG_DEBUG2,
+				"PKCS#11: __pkcs11h_certificate_doPrivateOperation op rv=%ld",
+				rv
+			);
+		}
+		
+		if (
+			target == NULL &&
+			(
+				rv == CKR_BUFFER_TOO_SMALL ||
+				rv == CKR_OK
+			)
+		) {
+			certificate->operation_active = TRUE;
+			rv = CKR_OK;
+		}
+		else {
+			certificate->operation_active = FALSE;
+		}
+
+		if (rv == CKR_OK) {
+			op_succeed = TRUE;
+		}
+		else {
+			/*
+			 * OpenSC workaround
+			 * It still allows C_FindObjectsInit when
+			 * token is removed/inserted but fails
+			 * private key operation.
+			 * So we force logout.
+			 * bug#108 at OpenSC trac
+			 */
+			if (login_retry && rv == CKR_DEVICE_REMOVED) {
+				login_retry = FALSE;
+				_pkcs11h_session_logout (certificate->session);
+			}
+
+			if (!login_retry) {
+				PKCS11H_DEBUG (
+					PKCS11H_LOG_DEBUG1,
+					"PKCS#11: Private key operation failed rv=%ld-'%s'",
+					rv,
+					pkcs11h_getMessage (rv)
+				);
+				login_retry = TRUE;
+				rv = _pkcs11h_certificate_resetSession (
+					certificate,
+					FALSE,
+					TRUE
+				);
+			}
+		}
+
+	}
+
+#if defined(ENABLE_PKCS11H_THREADING)
+	if (mutex_locked) {
+		_pkcs11h_threading_mutexRelease (&certificate->mutex);
+		mutex_locked = FALSE;
+	}
+#endif
+
+	PKCS11H_DEBUG (
+		PKCS11H_LOG_DEBUG2,
+		"PKCS#11: __pkcs11h_certificate_doPrivateOperation return rv=%ld-'%s', *p_target_size=%u",
+		rv,
+		pkcs11h_getMessage (rv),
+		*p_target_size
+	);
+	
+	return rv;
+}
+
+CK_RV
+pkcs11h_certificate_freeCertificateId (
+	IN pkcs11h_certificate_id_t certificate_id
+) {
+	PKCS11H_ASSERT (g_pkcs11h_data!=NULL);
+	PKCS11H_ASSERT (g_pkcs11h_data->initialized);
+	PKCS11H_ASSERT (certificate_id!=NULL);
+
+	PKCS11H_DEBUG (
+		PKCS11H_LOG_DEBUG2,
+		"PKCS#11: pkcs11h_certificate_freeCertificateId entry certificate_id=%p",
+		(void *)certificate_id
+	);
+
+	if (certificate_id->attrCKA_ID != NULL) {
+		_pkcs11h_mem_free ((void *)&certificate_id->attrCKA_ID);
+	}
+	if (certificate_id->certificate_blob != NULL) {
+		_pkcs11h_mem_free ((void *)&certificate_id->certificate_blob);
+	}
+	if (certificate_id->token_id != NULL) {
+		pkcs11h_token_freeTokenId (certificate_id->token_id);
+		certificate_id->token_id = NULL;
+	}
+	_pkcs11h_mem_free ((void *)&certificate_id);
+
+	PKCS11H_DEBUG (
+		PKCS11H_LOG_DEBUG2,
+		"PKCS#11: pkcs11h_certificate_freeCertificateId return"
+	);
+
+	return CKR_OK;
+}
+
+CK_RV
+pkcs11h_certificate_duplicateCertificateId (
+	OUT pkcs11h_certificate_id_t * const to,
+	IN const pkcs11h_certificate_id_t from
+) {
+	CK_RV rv = CKR_OK;
+
+	PKCS11H_ASSERT (g_pkcs11h_data!=NULL);
+	PKCS11H_ASSERT (g_pkcs11h_data->initialized);
+	PKCS11H_ASSERT (to!=NULL);
+	PKCS11H_ASSERT (from!=NULL);
+
+	PKCS11H_DEBUG (
+		PKCS11H_LOG_DEBUG2,
+		"PKCS#11: pkcs11h_certificate_duplicateCertificateId entry to=%p form=%p",
+		(void *)to,
+		(void *)from
+	);
+
+	*to = NULL;
+
+	if (rv == CKR_OK) {
+		rv = _pkcs11h_mem_duplicate (
+			(void*)to,
+			NULL,
+			from,
+			sizeof (struct pkcs11h_certificate_id_s)
+		);
+	}
+
+	if (rv == CKR_OK) {
+		rv = _pkcs11h_mem_duplicate (
+			(void*)&(*to)->token_id,
+			NULL,
+			from->token_id,
+			sizeof (struct pkcs11h_token_id_s)
+		);
+	}
+
+	if (rv == CKR_OK) {
+		rv = _pkcs11h_mem_duplicate (
+			(void*)&(*to)->attrCKA_ID,
+			&(*to)->attrCKA_ID_size,
+			from->attrCKA_ID,
+			from->attrCKA_ID_size
+		);
+	}
+
+	if (rv == CKR_OK) {
+		rv = _pkcs11h_mem_duplicate (
+			(void*)&(*to)->certificate_blob,
+			&(*to)->certificate_blob_size,
+			from->certificate_blob,
+			from->certificate_blob_size
+		);
+	}
+
+	PKCS11H_DEBUG (
+		PKCS11H_LOG_DEBUG2,
+		"PKCS#11: pkcs11h_certificate_duplicateCertificateId return rv=%ld-'%s', *to=%p",
+		rv,
+		pkcs11h_getMessage (rv),
+		(void *)*to
+	);
+	
+	return rv;
+}
+
+CK_RV
+pkcs11h_certificate_setCertificateIdCertificateBlob (
+	IN const pkcs11h_certificate_id_t certificate_id,
+	IN const unsigned char * const blob,
+	IN const size_t blob_size
+) {
+	CK_RV rv = CKR_OK;
+
+	PKCS11H_ASSERT (g_pkcs11h_data!=NULL);
+	PKCS11H_ASSERT (g_pkcs11h_data->initialized);
+	PKCS11H_ASSERT (certificate_id!=NULL);
+	PKCS11H_ASSERT (blob!=NULL);
+
+	PKCS11H_DEBUG (
+		PKCS11H_LOG_DEBUG2,
+		"PKCS#11: pkcs11h_certificate_setCertificateIdCertificateBlob entry certificate_id=%p",
+		(void *)certificate_id
+	);
+
+	if (rv == CKR_OK && certificate_id->certificate_blob != NULL) {
+		rv = _pkcs11h_mem_free ((void *)&certificate_id->certificate_blob);
+	}
+
+	if (rv == CKR_OK) {
+		rv = _pkcs11h_mem_duplicate (
+			(void *)&certificate_id->certificate_blob,
+			&certificate_id->certificate_blob_size,
+			blob,
+			blob_size
+		);
+	}
+
+	PKCS11H_DEBUG (
+		PKCS11H_LOG_DEBUG2,
+		"PKCS#11: pkcs11h_certificate_setCertificateIdCertificateBlob return rv=%ld-'%s'",
+		rv,
+		pkcs11h_getMessage (rv)
+	);
+	
+	return rv;
+}
+
+CK_RV
+pkcs11h_certificate_freeCertificate (
+	IN pkcs11h_certificate_t certificate
+) {
+	PKCS11H_ASSERT (g_pkcs11h_data!=NULL);
+	PKCS11H_ASSERT (g_pkcs11h_data->initialized);
+
+	PKCS11H_DEBUG (
+		PKCS11H_LOG_DEBUG2,
+		"PKCS#11: pkcs11h_certificate_freeCertificate entry certificate=%p",
+		(void *)certificate
+	);
+
+	if (certificate != NULL) {
+		if (certificate->session != NULL) {
+			_pkcs11h_session_release (certificate->session);
+		}
+		pkcs11h_certificate_freeCertificateId (certificate->id);
+		certificate->id = NULL;
+
+#if defined(ENABLE_PKCS11H_THREADING)
+		_pkcs11h_threading_mutexFree (&certificate->mutex);
+#endif
+
+		_pkcs11h_mem_free ((void *)&certificate);
+	}
+
+	PKCS11H_DEBUG (
+		PKCS11H_LOG_DEBUG2,
+		"PKCS#11: pkcs11h_certificate_freeCertificate return"
+	);
+
+	return CKR_OK;
+}
+
+CK_RV
+pkcs11h_certificate_lockSession (
+	IN const pkcs11h_certificate_t certificate
+) {
+#if defined(ENABLE_PKCS11H_THREADING)
+	CK_RV rv = CKR_OK;
+
+	PKCS11H_ASSERT (g_pkcs11h_data!=NULL);
+	PKCS11H_ASSERT (g_pkcs11h_data->initialized);
+	PKCS11H_ASSERT (certificate!=NULL);
+
+	if (rv == CKR_OK && certificate->session == NULL) {
+		rv = _pkcs11h_session_getSessionByTokenId (certificate->id->token_id, &certificate->session);
+	}
+
+	if (rv == CKR_OK) {
+		rv = _pkcs11h_threading_mutexLock (&certificate->session->mutex);
+	}
+
+	return rv;
+#else
+	return CKR_OK;
+#endif
+}
+
+CK_RV
+pkcs11h_certificate_releaseSession (
+	IN const pkcs11h_certificate_t certificate
+) {
+#if defined(ENABLE_PKCS11H_THREADING)
+	CK_RV rv = CKR_OK;
+
+	PKCS11H_ASSERT (g_pkcs11h_data!=NULL);
+	PKCS11H_ASSERT (g_pkcs11h_data->initialized);
+	PKCS11H_ASSERT (certificate!=NULL);
+
+	if (certificate->session != NULL) {
+		rv = _pkcs11h_threading_mutexRelease (&certificate->session->mutex);
+	}
+
+	return rv;
+#else
+	return CKR_OK;
+#endif
+}
+
+CK_RV
+pkcs11h_certificate_sign (
+	IN const pkcs11h_certificate_t certificate,
+	IN const CK_MECHANISM_TYPE mech_type,
+	IN const unsigned char * const source,
+	IN const size_t source_size,
+	OUT unsigned char * const target,
+	IN OUT size_t * const p_target_size
+) {
+	CK_RV rv = CKR_OK;
+
+	PKCS11H_ASSERT (g_pkcs11h_data!=NULL);
+	PKCS11H_ASSERT (g_pkcs11h_data->initialized);
+	PKCS11H_ASSERT (certificate!=NULL);
+	PKCS11H_ASSERT (source!=NULL);
+	/*PKCS11H_ASSERT (target); NOT NEEDED*/
+	PKCS11H_ASSERT (p_target_size!=NULL);
+
+	PKCS11H_DEBUG (
+		PKCS11H_LOG_DEBUG2,
+		"PKCS#11: pkcs11h_certificate_sign entry certificate=%p, mech_type=%ld, source=%p, source_size=%u, target=%p, *p_target_size=%u",
+		(void *)certificate,
+		mech_type,
+		source,
+		source_size,
+		target,
+		target != NULL ? *p_target_size : 0
+	);
+
+	if (target == NULL) {
+		*p_target_size = 0;
+	}
+
+	if (rv == CKR_OK) {
+		rv = __pkcs11h_certificate_doPrivateOperation (
+			certificate,
+			_pkcs11h_private_op_sign,
+			mech_type,
+			source,
+			source_size,
+			target,
+			p_target_size
+		);
+	}
+
+	PKCS11H_DEBUG (
+		PKCS11H_LOG_DEBUG2,
+		"PKCS#11: pkcs11h_certificate_sign return rv=%ld-'%s', *p_target_size=%u",
+		rv,
+		pkcs11h_getMessage (rv),
+		*p_target_size
+	);
+	
+	return rv;
+}
+
+CK_RV
+pkcs11h_certificate_signRecover (
+	IN const pkcs11h_certificate_t certificate,
+	IN const CK_MECHANISM_TYPE mech_type,
+	IN const unsigned char * const source,
+	IN const size_t source_size,
+	OUT unsigned char * const target,
+	IN OUT size_t * const p_target_size
+) {
+	CK_RV rv = CKR_OK;
+
+	PKCS11H_ASSERT (g_pkcs11h_data!=NULL);
+	PKCS11H_ASSERT (g_pkcs11h_data->initialized);
+	PKCS11H_ASSERT (certificate!=NULL);
+	PKCS11H_ASSERT (source!=NULL);
+	/*PKCS11H_ASSERT (target); NOT NEEDED*/
+	PKCS11H_ASSERT (p_target_size!=NULL);
+
+	PKCS11H_DEBUG (
+		PKCS11H_LOG_DEBUG2,
+		"PKCS#11: pkcs11h_certificate_signRecover entry certificate=%p, mech_type=%ld, source=%p, source_size=%u, target=%p, *p_target_size=%u",
+		(void *)certificate,
+		mech_type,
+		source,
+		source_size,
+		target,
+		target != NULL ? *p_target_size : 0
+	);
+
+	if (target == NULL) {
+		*p_target_size = 0;
+	}
+
+	if (rv == CKR_OK) {
+		rv = __pkcs11h_certificate_doPrivateOperation (
+			certificate,
+			_pkcs11h_private_op_sign_recover,
+			mech_type,
+			source,
+			source_size,
+			target,
+			p_target_size
+		);
+	}
+
+	PKCS11H_DEBUG (
+		PKCS11H_LOG_DEBUG2,
+		"PKCS#11: pkcs11h_certificate_signRecover return rv=%ld-'%s', *p_target_size=%u",
+		rv,
+		pkcs11h_getMessage (rv),
+		*p_target_size
+	);
+
+	return rv;
+}
+
+CK_RV
+pkcs11h_certificate_decrypt (
+	IN const pkcs11h_certificate_t certificate,
+	IN const CK_MECHANISM_TYPE mech_type,
+	IN const unsigned char * const source,
+	IN const size_t source_size,
+	OUT unsigned char * const target,
+	IN OUT size_t * const p_target_size
+) {
+	CK_RV rv = CKR_OK;
+
+	PKCS11H_ASSERT (g_pkcs11h_data!=NULL);
+	PKCS11H_ASSERT (g_pkcs11h_data->initialized);
+	PKCS11H_ASSERT (certificate!=NULL);
+	PKCS11H_ASSERT (source!=NULL);
+	/*PKCS11H_ASSERT (target); NOT NEEDED*/
+	PKCS11H_ASSERT (p_target_size!=NULL);
+
+	PKCS11H_DEBUG (
+		PKCS11H_LOG_DEBUG2,
+		"PKCS#11: pkcs11h_decrypt entry certificate=%p, mech_type=%ld, source=%p, source_size=%u, target=%p, *p_target_size=%u",
+		(void *)certificate,
+		mech_type,
+		source,
+		source_size,
+		target,
+		target != NULL ? *p_target_size : 0
+	);
+
+	if (target == NULL) {
+		*p_target_size = 0;
+	}
+
+	if (rv == CKR_OK) {
+		rv = __pkcs11h_certificate_doPrivateOperation (
+			certificate,
+			_pkcs11h_private_op_decrypt,
+			mech_type,
+			source,
+			source_size,
+			target,
+			p_target_size
+		);
+	}
+
+	PKCS11H_DEBUG (
+		PKCS11H_LOG_DEBUG2,
+		"PKCS#11: pkcs11h_decrypt return rv=%ld-'%s', *p_target_size=%u",
+		rv,
+		pkcs11h_getMessage (rv),
+		*p_target_size
+	);
+
+	return rv;
+}
+
+CK_RV
+pkcs11h_certificate_unwrap (
+	IN const pkcs11h_certificate_t certificate,
+	IN const CK_MECHANISM_TYPE mech_type,
+	IN const unsigned char * const source,
+	IN const size_t source_size,
+	OUT unsigned char * const target,
+	IN OUT size_t * const p_target_size
+) {
+	CK_RV rv = CKR_OK;
+
+	PKCS11H_ASSERT (g_pkcs11h_data!=NULL);
+	PKCS11H_ASSERT (g_pkcs11h_data->initialized);
+	PKCS11H_ASSERT (certificate!=NULL);
+	PKCS11H_ASSERT (source!=NULL);
+	/*PKCS11H_ASSERT (target); NOT NEEDED*/
+	PKCS11H_ASSERT (p_target_size!=NULL);
+
+	PKCS11H_DEBUG (
+		PKCS11H_LOG_DEBUG2,
+		"PKCS#11: pkcs11h_unwrap entry certificate=%p, mech_type=%ld, source=%p, source_size=%u, target=%p, *p_target_size=%u",
+		(void *)certificate,
+		mech_type,
+		source,
+		source_size,
+		target,
+		target != NULL ? *p_target_size : 0
+	);
+
+	if (target == NULL) {
+		*p_target_size = 0;
+	}
+
+	if (rv == CKR_OK) {
+		rv = __pkcs11h_certificate_doPrivateOperation (
+			certificate,
+			_pkcs11h_private_op_unwrap,
+			mech_type,
+			source,
+			source_size,
+			target,
+			p_target_size
+		);
+	}
+
+	PKCS11H_DEBUG (
+		PKCS11H_LOG_DEBUG2,
+		"PKCS#11: pkcs11h_unwrap return rv=%ld-'%s', *p_target_size=%u",
+		rv,
+		pkcs11h_getMessage (rv),
+		*p_target_size
+	);
+
+	return rv;
+}
+
+CK_RV
+pkcs11h_certificate_signAny (
+	IN const pkcs11h_certificate_t certificate,
+	IN const CK_MECHANISM_TYPE mech_type,
+	IN const unsigned char * const source,
+	IN const size_t source_size,
+	OUT unsigned char * const target,
+	IN OUT size_t * const p_target_size
+) {
+	CK_RV rv = CKR_OK;
+	PKCS11H_BOOL acked = FALSE;
+
+	PKCS11H_ASSERT (g_pkcs11h_data!=NULL);
+	PKCS11H_ASSERT (g_pkcs11h_data->initialized);
+	PKCS11H_ASSERT (certificate!=NULL);
+	PKCS11H_ASSERT (source!=NULL);
+	/*PKCS11H_ASSERT (target); NOT NEEDED*/
+	PKCS11H_ASSERT (p_target_size!=NULL);
+
+	PKCS11H_DEBUG (
+		PKCS11H_LOG_DEBUG2,
+		"PKCS#11: pkcs11h_certificate_signAny entry certificate=%p, mech_type=%ld, source=%p, source_size=%u, target=%p, *p_target_size=%u",
+		(void *)certificate,
+		mech_type,
+		source,
+		source_size,
+		target,
+		target != NULL ? *p_target_size : 0
+	);
+
+	if (
+		rv == CKR_OK &&
+		certificate->mask_private_mode == 0
+	) {
+		PKCS11H_DEBUG (
+			PKCS11H_LOG_DEBUG1,
+			"PKCS#11: Getting key attributes"
+		);
+		rv = __pkcs11h_certificate_getKeyAttributes (certificate);
+	}
+
+	if (
+		rv == CKR_OK &&
+		!acked &&
+		(certificate->mask_private_mode & PKCS11H_PRIVATEMODE_MASK_SIGN) != 0
+	) {
+		rv = pkcs11h_certificate_sign (
+			certificate,
+			mech_type,
+			source,
+			source_size,
+			target,
+			p_target_size
+		);
+
+		if (rv == CKR_OK) {
+			acked = TRUE;
+		}
+		else if (
+			rv == CKR_FUNCTION_NOT_SUPPORTED ||
+			rv == CKR_KEY_FUNCTION_NOT_PERMITTED ||
+			rv == CKR_KEY_TYPE_INCONSISTENT
+		) {
+			certificate->mask_private_mode &= ~PKCS11H_PRIVATEMODE_MASK_SIGN;
+			rv = CKR_OK;
+		}
+	}
+	
+	if (
+		rv == CKR_OK &&
+		!acked &&
+		(certificate->mask_private_mode & PKCS11H_PRIVATEMODE_MASK_RECOVER) != 0
+	) {
+		rv = pkcs11h_certificate_signRecover (
+			certificate,
+			mech_type,
+			source,
+			source_size,
+			target,
+			p_target_size
+		);
+
+		if (rv == CKR_OK) {
+			acked = TRUE;
+		}
+		else if (
+			rv == CKR_FUNCTION_NOT_SUPPORTED ||
+			rv == CKR_KEY_FUNCTION_NOT_PERMITTED ||
+			rv == CKR_KEY_TYPE_INCONSISTENT
+		) {
+			certificate->mask_private_mode &= ~PKCS11H_PRIVATEMODE_MASK_RECOVER;
+			rv = CKR_OK;
+		}
+	}
+
+	if (rv == CKR_OK && !acked) {
+		rv = CKR_FUNCTION_FAILED;
+	}
+	
+	PKCS11H_DEBUG (
+		PKCS11H_LOG_DEBUG2,
+		"PKCS#11: pkcs11h_certificate_signAny return rv=%ld-'%s', *p_target_size=%u",
+		rv,
+		pkcs11h_getMessage (rv),
+		*p_target_size
+	);
+
+	return rv;
+}
+
+CK_RV
+pkcs11h_certificate_decryptAny (
+	IN const pkcs11h_certificate_t certificate,
+	IN const CK_MECHANISM_TYPE mech_type,
+	IN const unsigned char * const source,
+	IN const size_t source_size,
+	OUT unsigned char * const target,
+	IN OUT size_t * const p_target_size
+) {
+	CK_RV rv = CKR_OK;
+	PKCS11H_BOOL acked = FALSE;
+
+	PKCS11H_ASSERT (g_pkcs11h_data!=NULL);
+	PKCS11H_ASSERT (g_pkcs11h_data->initialized);
+	PKCS11H_ASSERT (certificate!=NULL);
+	PKCS11H_ASSERT (source!=NULL);
+	/*PKCS11H_ASSERT (target); NOT NEEDED*/
+	PKCS11H_ASSERT (p_target_size!=NULL);
+
+	PKCS11H_DEBUG (
+		PKCS11H_LOG_DEBUG2,
+		"PKCS#11: pkcs11h_certificate_decryptAny entry certificate=%p, mech_type=%ld, source=%p, source_size=%u, target=%p, *p_target_size=%u",
+		(void *)certificate,
+		mech_type,
+		source,
+		source_size,
+		target,
+		target != NULL ? *p_target_size : 0
+	);
+
+	if (
+		rv == CKR_OK &&
+		certificate->mask_private_mode == 0
+	) {
+		PKCS11H_DEBUG (
+			PKCS11H_LOG_DEBUG1,
+			"PKCS#11: Getting key attributes"
+		);
+		rv = __pkcs11h_certificate_getKeyAttributes (certificate);
+	}
+
+	if (
+		rv == CKR_OK &&
+		!acked &&
+		(certificate->mask_private_mode & PKCS11H_PRIVATEMODE_MASK_DECRYPT) != 0
+	) {
+		rv = pkcs11h_certificate_decrypt (
+			certificate,
+			mech_type,
+			source,
+			source_size,
+			target,
+			p_target_size
+		);
+
+		if (rv == CKR_OK) {
+			acked = TRUE;
+		}
+		else if (
+			rv == CKR_FUNCTION_NOT_SUPPORTED ||
+			rv == CKR_KEY_FUNCTION_NOT_PERMITTED ||
+			rv == CKR_KEY_TYPE_INCONSISTENT
+		) {
+			certificate->mask_private_mode &= ~PKCS11H_PRIVATEMODE_MASK_DECRYPT;
+			rv = CKR_OK;
+		}
+	}
+	
+	if (
+		rv == CKR_OK &&
+		!acked &&
+		(certificate->mask_private_mode & PKCS11H_PRIVATEMODE_MASK_UNWRAP) != 0
+	) {
+		rv = pkcs11h_certificate_unwrap (
+			certificate,
+			mech_type,
+			source,
+			source_size,
+			target,
+			p_target_size
+		);
+
+		if (rv == CKR_OK) {
+			acked = TRUE;
+		}
+		else if (
+			rv == CKR_FUNCTION_NOT_SUPPORTED ||
+			rv == CKR_KEY_FUNCTION_NOT_PERMITTED ||
+			rv == CKR_KEY_TYPE_INCONSISTENT
+		) {
+			certificate->mask_private_mode &= ~PKCS11H_PRIVATEMODE_MASK_UNWRAP;
+			rv = CKR_OK;
+		}
+	}
+
+	if (rv == CKR_OK && !acked) {
+		rv = CKR_FUNCTION_FAILED;
+	}
+	
+	PKCS11H_DEBUG (
+		PKCS11H_LOG_DEBUG2,
+		"PKCS#11: pkcs11h_certificate_decryptAny return rv=%ld-'%s', *p_target_size=%u",
+		rv,
+		pkcs11h_getMessage (rv),
+		*p_target_size
+	);
+
+	return rv;
+}
+
+CK_RV
+pkcs11h_certificate_create (
+	IN const pkcs11h_certificate_id_t certificate_id,
+	IN void * const user_data,
+	IN const unsigned mask_prompt,
+	IN const int pin_cache_period,
+	OUT pkcs11h_certificate_t * const p_certificate
+) {
+	pkcs11h_certificate_t certificate = NULL;
+	CK_RV rv = CKR_OK;
+
+	PKCS11H_ASSERT (g_pkcs11h_data!=NULL);
+	PKCS11H_ASSERT (g_pkcs11h_data->initialized);
+	/*PKCS11H_ASSERT (user_data!=NULL); NOT NEEDED */
+	PKCS11H_ASSERT (p_certificate!=NULL);
+
+	PKCS11H_DEBUG (
+		PKCS11H_LOG_DEBUG2,
+		"PKCS#11: pkcs11h_certificate_create entry certificate_id=%p, user_data=%p, mask_prompt=%08x, pin_cache_period=%d, p_certificate=%p",
+		(void *)certificate_id,
+		user_data,
+		mask_prompt,
+		pin_cache_period,
+		(void *)p_certificate
+	);
+
+	*p_certificate = NULL;
+
+	if (
+		rv == CKR_OK &&
+		(rv = _pkcs11h_mem_malloc ((void*)&certificate, sizeof (struct pkcs11h_certificate_s))) == CKR_OK
+	) {
+		certificate->user_data = user_data;
+		certificate->mask_prompt = mask_prompt;
+		certificate->key_handle = PKCS11H_INVALID_OBJECT_HANDLE;
+		certificate->pin_cache_period = pin_cache_period;
+	}
+
+#if defined(ENABLE_PKCS11H_THREADING)
+	if (rv == CKR_OK) {
+		rv = _pkcs11h_threading_mutexInit (&certificate->mutex);
+	}
+#endif
+
+	if (rv == CKR_OK) {
+		rv = pkcs11h_certificate_duplicateCertificateId (&certificate->id, certificate_id);
+	}
+
+	if (rv == CKR_OK) {
+		*p_certificate = certificate;
+		certificate = NULL;
+	}
+
+	if (certificate != NULL) {
+#if defined(ENABLE_PKCS11H_THREADING)
+		_pkcs11h_threading_mutexFree (&certificate->mutex);
+#endif
+		_pkcs11h_mem_free ((void *)&certificate);
+	}
+
+	PKCS11H_DEBUG (
+		PKCS11H_LOG_DEBUG2,
+		"PKCS#11: pkcs11h_certificate_create return rv=%ld-'%s' *p_certificate=%p",
+		rv,
+		pkcs11h_getMessage (rv),
+		(void *)*p_certificate
+	);
+	
+	return rv;
+}
+
+unsigned
+pkcs11h_certificate_getPromptMask (
+	IN const pkcs11h_certificate_t certificate
+) {
+	PKCS11H_ASSERT (certificate!=NULL);
+
+	return certificate->mask_prompt;
+}
+
+void
+pkcs11h_certificate_setPromptMask (
+	IN const pkcs11h_certificate_t certificate,
+	IN const unsigned mask_prompt
+) {
+	PKCS11H_ASSERT (certificate!=NULL);
+
+	certificate->mask_prompt = mask_prompt;
+}
+
+void *
+pkcs11h_certificate_getUserData (
+	IN const pkcs11h_certificate_t certificate
+) {
+	PKCS11H_ASSERT (certificate!=NULL);
+
+	return certificate->user_data;
+}
+
+void
+pkcs11h_certificate_setUserData (
+	IN const pkcs11h_certificate_t certificate,
+	IN void * const user_data
+) {
+	PKCS11H_ASSERT (certificate!=NULL);
+
+	certificate->user_data = user_data;
+}
+
+CK_RV
+pkcs11h_certificate_getCertificateId (
+	IN const pkcs11h_certificate_t certificate,
+	OUT pkcs11h_certificate_id_t * const p_certificate_id
+) {
+	CK_RV rv = CKR_OK;
+
+	PKCS11H_ASSERT (g_pkcs11h_data!=NULL);
+	PKCS11H_ASSERT (g_pkcs11h_data->initialized);
+	PKCS11H_ASSERT (certificate!=NULL);
+	PKCS11H_ASSERT (p_certificate_id!=NULL);
+
+	PKCS11H_DEBUG (
+		PKCS11H_LOG_DEBUG2,
+		"PKCS#11: pkcs11h_certificate_getCertificateId entry certificate=%p, certificate_id=%p",
+		(void *)certificate,
+		(void *)p_certificate_id
+	);
+
+	if (rv == CKR_OK) {
+		rv = pkcs11h_certificate_duplicateCertificateId (
+			p_certificate_id,
+			certificate->id
+		);
+	}
+
+	PKCS11H_DEBUG (
+		PKCS11H_LOG_DEBUG2,
+		"PKCS#11: pkcs11h_certificate_getCertificateId return rv=%ld-'%s'",
+		rv,
+		pkcs11h_getMessage (rv)
+	);
+
+	return rv;
+}
+
+CK_RV
+pkcs11h_certificate_getCertificateBlob (
+	IN const pkcs11h_certificate_t certificate,
+	OUT unsigned char * const certificate_blob,
+	IN OUT size_t * const p_certificate_blob_size
+) {
+#if defined(ENABLE_PKCS11H_THREADING)
+	PKCS11H_BOOL mutex_locked = FALSE;
+#endif
+	CK_RV rv = CKR_OK;
+	size_t certifiate_blob_size_max = 0;
+	
+	PKCS11H_ASSERT (g_pkcs11h_data!=NULL);
+	PKCS11H_ASSERT (g_pkcs11h_data->initialized);
+	PKCS11H_ASSERT (certificate!=NULL);
+	/*PKCS11H_ASSERT (certificate_blob!=NULL); NOT NEEDED */
+	PKCS11H_ASSERT (p_certificate_blob_size!=NULL);
+
+	PKCS11H_DEBUG (
+		PKCS11H_LOG_DEBUG2,
+		"PKCS#11: pkcs11h_certificate_getCertificateBlob entry certificate=%p, certificate_blob=%p, *p_certificate_blob_size=%u",
+		(void *)certificate,
+		certificate_blob,
+		certificate_blob != NULL ? *p_certificate_blob_size : 0
+	);
+
+	if (certificate_blob != NULL) {
+		certifiate_blob_size_max = *p_certificate_blob_size;
+	}
+	*p_certificate_blob_size = 0;
+
+#if defined(ENABLE_PKCS11H_THREADING)
+	if (
+		rv == CKR_OK &&
+		(rv = _pkcs11h_threading_mutexLock (&certificate->mutex)) == CKR_OK
+	) {
+		mutex_locked = TRUE;
+	}
+#endif
+
+	if (rv == CKR_OK && certificate->id->certificate_blob == NULL) {
+		PKCS11H_BOOL op_succeed = FALSE;
+		PKCS11H_BOOL login_retry = FALSE;
+		while (rv == CKR_OK && !op_succeed) {
+			if (certificate->session == NULL) {
+				rv = CKR_SESSION_HANDLE_INVALID;
+			}
+
+			if (rv == CKR_OK) {
+				rv = __pkcs11h_certificate_loadCertificate (certificate);
+			}
+
+			if (rv == CKR_OK) {
+				op_succeed = TRUE;
+			}
+			else {
+				if (!login_retry) {
+					login_retry = TRUE;
+					rv = _pkcs11h_certificate_resetSession (
+						certificate,
+						TRUE,
+						FALSE
+					);
+				}
+			}
+		}
+	}
+	
+	if (
+		rv == CKR_OK &&
+		certificate->id->certificate_blob == NULL
+	) {
+		rv = CKR_FUNCTION_REJECTED;
+	}
+
+	if (rv == CKR_OK) {
+		__pkcs11h_certificate_updateCertificateIdDescription (certificate->id);
+	}
+
+	if (rv == CKR_OK) {
+		*p_certificate_blob_size = certificate->id->certificate_blob_size;
+	}
+
+	if (certificate_blob != NULL) {
+		if (
+			rv == CKR_OK &&
+			certificate->id->certificate_blob_size > certifiate_blob_size_max
+		) {
+			rv = CKR_BUFFER_TOO_SMALL;
+		}
+	
+		if (rv == CKR_OK) {
+			memmove (
+				certificate_blob,
+				certificate->id->certificate_blob,
+				*p_certificate_blob_size
+			);
+		}
+	}
+
+#if defined(ENABLE_PKCS11H_THREADING)
+	if (mutex_locked) {
+		_pkcs11h_threading_mutexRelease (&certificate->mutex);
+		mutex_locked = FALSE;
+	}
+#endif
+
+	PKCS11H_DEBUG (
+		PKCS11H_LOG_DEBUG2,
+		"PKCS#11: pkcs11h_certificate_getCertificateBlob return rv=%ld-'%s'",
+		rv,
+		pkcs11h_getMessage (rv)
+	);
+
+	return rv;
+}
+
+CK_RV
+pkcs11h_certificate_ensureCertificateAccess (
+	IN const pkcs11h_certificate_t certificate
+) {
+#if defined(ENABLE_PKCS11H_THREADING)
+	PKCS11H_BOOL mutex_locked_cert = FALSE;
+	PKCS11H_BOOL mutex_locked_sess = FALSE;
+#endif
+	PKCS11H_BOOL validCert = FALSE;
+	CK_RV rv = CKR_OK;
+
+	PKCS11H_ASSERT (g_pkcs11h_data!=NULL);
+	PKCS11H_ASSERT (g_pkcs11h_data->initialized);
+	PKCS11H_ASSERT (certificate!=NULL);
+
+	PKCS11H_DEBUG (
+		PKCS11H_LOG_DEBUG2,
+		"PKCS#11: pkcs11h_certificate_ensureCertificateAccess entry certificate=%p",
+		(void *)certificate
+	);
+
+#if defined(ENABLE_PKCS11H_THREADING)
+	if (
+		rv == CKR_OK &&
+		(rv = _pkcs11h_threading_mutexLock (&certificate->mutex)) == CKR_OK
+	) {
+		mutex_locked_cert = TRUE;
+	}
+#endif
+
+	if (!validCert && rv == CKR_OK) {
+		CK_OBJECT_HANDLE h = PKCS11H_INVALID_OBJECT_HANDLE;
+
+		if (certificate->session == NULL) {
+			rv = CKR_SESSION_HANDLE_INVALID;
+		}
+
+#if defined(ENABLE_PKCS11H_THREADING)
+		if (
+			rv == CKR_OK &&
+			(rv = _pkcs11h_threading_mutexLock (&certificate->session->mutex)) == CKR_OK
+		) {
+			mutex_locked_sess = TRUE;
+		}
+#endif
+
+		if (
+			(rv = _pkcs11h_session_getObjectById (
+				certificate->session,
+				CKO_CERTIFICATE,
+				certificate->id->attrCKA_ID,
+				certificate->id->attrCKA_ID_size,
+				&h
+			)) == CKR_OK
+		) {
+			validCert = TRUE;
+		}
+
+#if defined(ENABLE_PKCS11H_THREADING)
+		if (mutex_locked_sess) {
+			_pkcs11h_threading_mutexRelease (&certificate->session->mutex);
+			mutex_locked_sess = FALSE;
+		}
+#endif
+
+		if (rv != CKR_OK) {
+			PKCS11H_DEBUG (
+				PKCS11H_LOG_DEBUG1,
+				"PKCS#11: Cannot access existing object rv=%ld-'%s'",
+				rv,
+				pkcs11h_getMessage (rv)
+			);
+
+			/*
+			 * Ignore error
+			 */
+			rv = CKR_OK;
+		}
+	}
+
+	if (!validCert && rv == CKR_OK) {
+		if (
+			(rv = _pkcs11h_certificate_resetSession (
+				certificate,
+				TRUE,
+				FALSE
+			)) == CKR_OK
+		) {
+			validCert = TRUE;
+		}
+	}
+
+#if defined(ENABLE_PKCS11H_THREADING)
+	if (mutex_locked_cert) {
+		_pkcs11h_threading_mutexRelease (&certificate->mutex);
+		mutex_locked_cert = FALSE;
+	}
+#endif
+
+	PKCS11H_DEBUG (
+		PKCS11H_LOG_DEBUG2,
+		"PKCS#11: pkcs11h_certificate_ensureCertificateAccess return rv=%ld-'%s'",
+		rv,
+		pkcs11h_getMessage (rv)
+	);
+	
+	return rv;
+}
+
+CK_RV
+pkcs11h_certificate_ensureKeyAccess (
+	IN const pkcs11h_certificate_t certificate
+) {
+#if defined(ENABLE_PKCS11H_THREADING)
+	PKCS11H_BOOL mutex_locked_cert = FALSE;
+	PKCS11H_BOOL mutex_locked_sess = FALSE;
+#endif
+	CK_RV rv = CKR_OK;
+	PKCS11H_BOOL valid_key = FALSE;
+
+	PKCS11H_ASSERT (g_pkcs11h_data!=NULL);
+	PKCS11H_ASSERT (g_pkcs11h_data->initialized);
+	PKCS11H_ASSERT (certificate!=NULL);
+
+	PKCS11H_DEBUG (
+		PKCS11H_LOG_DEBUG2,
+		"PKCS#11: pkcs11h_certificate_ensureKeyAccess entry certificate=%p",
+		(void *)certificate
+	);
+
+#if defined(ENABLE_PKCS11H_THREADING)
+	if (
+		rv == CKR_OK &&
+		(rv = _pkcs11h_threading_mutexLock (&certificate->mutex)) == CKR_OK
+	) {
+		mutex_locked_cert = TRUE;
+	}
+#endif
+
+	if (!valid_key && rv == CKR_OK) {
+
+		if (certificate->session == NULL) {
+			rv = CKR_SESSION_HANDLE_INVALID;
+		}
+
+#if defined(ENABLE_PKCS11H_THREADING)
+		if (
+			rv == CKR_OK &&
+			(rv = _pkcs11h_threading_mutexLock (&certificate->session->mutex)) == CKR_OK
+		) {
+			mutex_locked_sess = TRUE;
+		}
+#endif
+
+		if (
+			(rv = _pkcs11h_session_getObjectById (
+				certificate->session,
+				CKO_PRIVATE_KEY,
+				certificate->id->attrCKA_ID,
+				certificate->id->attrCKA_ID_size,
+				&certificate->key_handle
+			)) == CKR_OK
+		) {
+			valid_key = TRUE;
+		}
+
+#if defined(ENABLE_PKCS11H_THREADING)
+		if (mutex_locked_sess) {
+			_pkcs11h_threading_mutexRelease (&certificate->session->mutex);
+			mutex_locked_sess = FALSE;
+		}
+#endif
+
+		if (rv != CKR_OK) {
+			PKCS11H_DEBUG (
+				PKCS11H_LOG_DEBUG1,
+				"PKCS#11: Cannot access existing object rv=%ld-'%s'",
+				rv,
+				pkcs11h_getMessage (rv)
+			);
+
+			/*
+			 * Ignore error
+			 */
+			rv = CKR_OK;
+			certificate->key_handle = PKCS11H_INVALID_OBJECT_HANDLE;
+		}
+	}
+
+	if (!valid_key && rv == CKR_OK) {
+		if (
+			(rv = _pkcs11h_certificate_resetSession (
+				certificate,
+				FALSE,
+				FALSE
+			)) == CKR_OK
+		) {
+			valid_key = TRUE;
+		}
+	}
+
+#if defined(ENABLE_PKCS11H_THREADING)
+	if (mutex_locked_cert) {
+		_pkcs11h_threading_mutexRelease (&certificate->mutex);
+		mutex_locked_cert = FALSE;
+	}
+#endif
+
+	PKCS11H_DEBUG (
+		PKCS11H_LOG_DEBUG2,
+		"PKCS#11: pkcs11h_certificate_ensureKeyAccess return rv=%ld-'%s'",
+		rv,
+		pkcs11h_getMessage (rv)
+	);
+	
+	return rv;
+}
+
+CK_RV
+_pkcs11h_certificate_enumSessionCertificates (
+	IN const pkcs11h_session_t session,
+	IN void * const user_data,
+	IN const unsigned mask_prompt
+) {
+#if defined(ENABLE_PKCS11H_THREADING)
+	PKCS11H_BOOL mutex_locked = FALSE;
+#endif
+	PKCS11H_BOOL op_succeed = FALSE;
+	PKCS11H_BOOL login_retry = FALSE;
+
+	CK_RV rv = CKR_OK;
+
+	PKCS11H_ASSERT (session!=NULL);
+	/*PKCS11H_ASSERT (user_data) NOT NEEDED */
+
+	PKCS11H_DEBUG (
+		PKCS11H_LOG_DEBUG2,
+		"PKCS#11: _pkcs11h_certificate_enumSessionCertificates entry session=%p, user_data=%p, mask_prompt=%08x",
+		(void *)session,
+		user_data,
+		mask_prompt
+	);
+	
+	/* THREADS: NO NEED TO LOCK, GLOBAL CACHE IS LOCKED */
+#if defined(ENABLE_PKCS11H_THREADING)
+	if (
+		rv == CKR_OK &&
+		(rv = _pkcs11h_threading_mutexLock (&session->mutex)) == CKR_OK
+	) {
+		mutex_locked = TRUE;
+	}
+#endif
+
+	while (rv == CKR_OK && !op_succeed) {
+		CK_OBJECT_CLASS cert_filter_class = CKO_CERTIFICATE;
+		CK_ATTRIBUTE cert_filter[] = {
+			{CKA_CLASS, &cert_filter_class, sizeof (cert_filter_class)}
+		};
+
+		CK_OBJECT_HANDLE *objects = NULL;
+		CK_ULONG objects_found = 0;
+
+		CK_ULONG i;
+
+		if (rv == CKR_OK) {
+			rv = _pkcs11h_session_validate (session);
+		}
+
+		if (rv == CKR_OK) {
+			rv = _pkcs11h_session_findObjects (
+				session,
+				cert_filter,
+				sizeof (cert_filter) / sizeof (CK_ATTRIBUTE),
+				&objects,
+				&objects_found
+			);
+		}
+			
+		for (i=0;rv == CKR_OK && i < objects_found;i++) {
+			pkcs11h_certificate_id_t certificate_id = NULL;
+			pkcs11h_certificate_id_list_t new_element = NULL;
+			
+			CK_ATTRIBUTE attrs[] = {
+				{CKA_ID, NULL, 0},
+				{CKA_VALUE, NULL, 0}
+			};
+
+			if (rv == CKR_OK) {
+				rv = _pkcs11h_session_getObjectAttributes (
+					session,
+					objects[i],
+					attrs,
+					sizeof (attrs) / sizeof (CK_ATTRIBUTE)
+				);
+			}
+
+			if (
+				rv == CKR_OK &&
+				(rv = _pkcs11h_certificate_newCertificateId (&certificate_id)) == CKR_OK
+			) {
+				rv = pkcs11h_token_duplicateTokenId (
+					&certificate_id->token_id,
+					session->token_id
+				);
+			}
+
+			if (rv == CKR_OK) {
+				rv = _pkcs11h_mem_duplicate (
+					(void*)&certificate_id->attrCKA_ID,
+					&certificate_id->attrCKA_ID_size,
+					attrs[0].pValue,
+					attrs[0].ulValueLen
+				);
+			}
+
+			if (rv == CKR_OK) {
+				rv = _pkcs11h_mem_duplicate (
+					(void*)&certificate_id->certificate_blob,
+					&certificate_id->certificate_blob_size,
+					attrs[1].pValue,
+					attrs[1].ulValueLen
+				);
+			}
+
+			if (rv == CKR_OK) {
+				rv = __pkcs11h_certificate_updateCertificateIdDescription (certificate_id);
+			}
+
+			if (
+				rv == CKR_OK &&
+				(rv = _pkcs11h_mem_malloc (
+					(void *)&new_element,
+					sizeof (struct pkcs11h_certificate_id_list_s)
+				)) == CKR_OK
+			) {
+				new_element->next = session->cached_certs;
+				new_element->certificate_id = certificate_id;
+				certificate_id = NULL;
+
+				session->cached_certs = new_element;
+				new_element = NULL;
+			}
+
+			if (certificate_id != NULL) {
+				pkcs11h_certificate_freeCertificateId (certificate_id);
+				certificate_id = NULL;
+			}
+
+			if (new_element != NULL) {
+				_pkcs11h_mem_free ((void *)&new_element);
+				new_element = NULL;
+			}
+
+			_pkcs11h_session_freeObjectAttributes (
+				attrs,
+				sizeof (attrs) / sizeof (CK_ATTRIBUTE)
+			);
+
+			if (rv != CKR_OK) {
+				PKCS11H_DEBUG (
+					PKCS11H_LOG_DEBUG1,
+					"PKCS#11: Cannot get object attribute for provider '%s' object %ld rv=%ld-'%s'",
+					session->provider->manufacturerID,
+					objects[i],
+					rv,
+					pkcs11h_getMessage (rv)
+				);
+
+				/*
+				 * Ignore error
+				 */
+				rv = CKR_OK;
+			}
+		}
+
+		if (objects != NULL) {
+			_pkcs11h_mem_free ((void *)&objects);
+		}
+
+		if (rv == CKR_OK) {
+			op_succeed = TRUE;
+		}
+		else {
+			if (!login_retry) {
+				PKCS11H_DEBUG (
+					PKCS11H_LOG_DEBUG1,
+					"PKCS#11: Get certificate attributes failed: %ld:'%s'",
+					rv,
+					pkcs11h_getMessage (rv)
+				);
+
+				rv = _pkcs11h_session_login (
+					session,
+					TRUE,
+					TRUE,
+					user_data,
+					(mask_prompt & PKCS11H_PROMPT_MASK_ALLOW_PIN_PROMPT)
+				);
+
+				login_retry = TRUE;
+			}
+		}
+	}
+
+#if defined(ENABLE_PKCS11H_THREADING)
+	if (mutex_locked) {
+		_pkcs11h_threading_mutexRelease (&session->mutex);
+		mutex_locked = FALSE;
+	}
+#endif
+
+	PKCS11H_DEBUG (
+		PKCS11H_LOG_DEBUG2,
+		"PKCS#11: _pkcs11h_certificate_enumSessionCertificates return rv=%ld-'%s'",
+		rv,
+		pkcs11h_getMessage (rv)
+	);
+
+	return rv;
+}
+
+static
+CK_RV
+__pkcs11h_certificate_splitCertificateIdList (
+	IN const pkcs11h_certificate_id_list_t cert_id_all,
+	OUT pkcs11h_certificate_id_list_t * const p_cert_id_issuers_list,
+	OUT pkcs11h_certificate_id_list_t * const p_cert_id_end_list
+) {
+	typedef struct info_s {
+		struct info_s *next;
+		pkcs11h_certificate_id_t e;
+		PKCS11H_BOOL is_issuer;
+	} *info_t;
+
+	pkcs11h_certificate_id_list_t cert_id_issuers_list = NULL;
+	pkcs11h_certificate_id_list_t cert_id_end_list = NULL;
+
+	info_t head = NULL;
+	info_t info = NULL;
+
+	CK_RV rv = CKR_OK;
+
+	/*PKCS11H_ASSERT (cert_id_all!=NULL); NOT NEEDED */
+	/*PKCS11H_ASSERT (p_cert_id_issuers_list!=NULL); NOT NEEDED*/
+	PKCS11H_ASSERT (p_cert_id_end_list!=NULL);
+
+	PKCS11H_DEBUG (
+		PKCS11H_LOG_DEBUG2,
+		"PKCS#11: __pkcs11h_certificate_splitCertificateIdList entry cert_id_all=%p, p_cert_id_issuers_list=%p, p_cert_id_end_list=%p",
+		(void *)cert_id_all,
+		(void *)p_cert_id_issuers_list,
+		(void *)p_cert_id_end_list
+	);
+
+	if (p_cert_id_issuers_list != NULL) {
+		*p_cert_id_issuers_list = NULL;
+	}
+	*p_cert_id_end_list = NULL;
+
+	if (rv == CKR_OK) {
+		pkcs11h_certificate_id_list_t entry = NULL;
+
+		for (
+			entry = cert_id_all;
+			entry != NULL && rv == CKR_OK;
+			entry = entry->next
+		) {
+			info_t new_info = NULL;
+
+			if (rv == CKR_OK) {
+				rv = _pkcs11h_mem_malloc ((void *)&new_info, sizeof (struct info_s));
+			}
+
+			if (rv == CKR_OK) {
+				new_info->next = head;
+				new_info->e = entry->certificate_id;
+				head = new_info;
+				new_info = NULL;
+			}
+		}
+
+	}
+
+	if (rv == CKR_OK) {
+		for (
+			info = head;
+			info != NULL;
+			info = info->next
+		) {
+			info_t info2 = NULL;
+
+			for (
+				info2 = head;
+				info2 != NULL && !info->is_issuer;
+				info2 = info2->next
+			) {
+				if (info != info2) {
+					info->is_issuer = g_pkcs11h_crypto_engine.certificate_is_issuer (
+						g_pkcs11h_crypto_engine.global_data,
+						info->e->certificate_blob,
+						info->e->certificate_blob_size,
+						info2->e->certificate_blob,
+						info2->e->certificate_blob_size
+					);
+				}
+
+			}
+		}
+	}
+
+	if (rv == CKR_OK) {
+		for (
+			info = head;
+			info != NULL && rv == CKR_OK;
+			info = info->next
+		) {
+			pkcs11h_certificate_id_list_t new_entry = NULL;
+
+			if (rv == CKR_OK) {
+				rv = _pkcs11h_mem_malloc (
+					(void *)&new_entry,
+					sizeof (struct pkcs11h_certificate_id_list_s)
+				);
+			}
+
+			if (
+				rv == CKR_OK &&
+				(rv = pkcs11h_certificate_duplicateCertificateId (
+					&new_entry->certificate_id,
+					info->e
+				)) == CKR_OK
+			) {
+				/*
+				 * Should not free base list
+				 */
+				info->e = NULL;
+			}
+
+			if (rv == CKR_OK) {
+				if (info->is_issuer) {
+					new_entry->next = cert_id_issuers_list;
+					cert_id_issuers_list = new_entry;
+					new_entry = NULL;
+				}
+				else {
+					new_entry->next = cert_id_end_list;
+					cert_id_end_list = new_entry;
+					new_entry = NULL;
+				}
+			}
+
+			if (new_entry != NULL) {
+				if (new_entry->certificate_id != NULL) {
+					pkcs11h_certificate_freeCertificateId (new_entry->certificate_id);
+				}
+				_pkcs11h_mem_free ((void *)&new_entry);
+			}
+		}
+	}
+
+	if (rv == CKR_OK) {
+		while (head != NULL) {
+			info_t entry = head;
+			head = head->next;
+
+			_pkcs11h_mem_free ((void *)&entry);
+		}
+	}
+
+	if (rv == CKR_OK && p_cert_id_issuers_list != NULL ) {
+		*p_cert_id_issuers_list = cert_id_issuers_list;
+		cert_id_issuers_list = NULL;
+	}
+
+	if (rv == CKR_OK) {
+		*p_cert_id_end_list = cert_id_end_list;
+		cert_id_end_list = NULL;
+	}
+
+	if (cert_id_issuers_list != NULL) {
+		pkcs11h_certificate_freeCertificateIdList (cert_id_issuers_list);
+	}
+
+	if (cert_id_end_list != NULL) {
+		pkcs11h_certificate_freeCertificateIdList (cert_id_end_list);
+	}
+
+	PKCS11H_DEBUG (
+		PKCS11H_LOG_DEBUG2,
+		"PKCS#11: __pkcs11h_certificate_splitCertificateIdList return rv=%ld-'%s'",
+		rv,
+		pkcs11h_getMessage (rv)
+	);
+
+	return rv;
+}
+
+CK_RV
+pkcs11h_certificate_freeCertificateIdList (
+	IN const pkcs11h_certificate_id_list_t cert_id_list
+) {
+	pkcs11h_certificate_id_list_t _id = cert_id_list;
+
+	PKCS11H_ASSERT (g_pkcs11h_data!=NULL);
+	PKCS11H_ASSERT (g_pkcs11h_data->initialized);
+	/*PKCS11H_ASSERT (cert_id_list!=NULL); NOT NEEDED*/
+
+	PKCS11H_DEBUG (
+		PKCS11H_LOG_DEBUG2,
+		"PKCS#11: pkcs11h_certificate_freeCertificateIdList entry cert_id_list=%p",
+		(void *)cert_id_list
+	);
+
+	while (_id != NULL) {
+		pkcs11h_certificate_id_list_t x = _id;
+		_id = _id->next;
+		if (x->certificate_id != NULL) {
+			pkcs11h_certificate_freeCertificateId (x->certificate_id);
+		}
+		x->next = NULL;
+		_pkcs11h_mem_free ((void *)&x);
+	}
+
+	PKCS11H_DEBUG (
+		PKCS11H_LOG_DEBUG2,
+		"PKCS#11: pkcs11h_certificate_freeCertificateIdList return"
+	);
+
+	return CKR_OK;
+}
+
+CK_RV
+pkcs11h_certificate_enumTokenCertificateIds (
+	IN const pkcs11h_token_id_t token_id,
+	IN const int method,
+	IN void * const user_data,
+	IN const unsigned mask_prompt,
+	OUT pkcs11h_certificate_id_list_t * const p_cert_id_issuers_list,
+	OUT pkcs11h_certificate_id_list_t * const p_cert_id_end_list
+) {
+#if defined(ENABLE_PKCS11H_THREADING)
+	PKCS11H_BOOL mutex_locked = FALSE;
+#endif
+	pkcs11h_session_t session = NULL;
+	CK_RV rv = CKR_OK;
+
+	PKCS11H_ASSERT (g_pkcs11h_data!=NULL);
+	PKCS11H_ASSERT (g_pkcs11h_data->initialized);
+	PKCS11H_ASSERT (token_id!=NULL);
+	/*PKCS11H_ASSERT (user_data) NOT NEEDED */
+	/*PKCS11H_ASSERT (p_cert_id_issuers_list!=NULL); NOT NEEDED*/
+	PKCS11H_ASSERT (p_cert_id_end_list!=NULL);
+
+	PKCS11H_DEBUG (
+		PKCS11H_LOG_DEBUG2,
+		"PKCS#11: pkcs11h_certificate_enumTokenCertificateIds entry token_id=%p, method=%d, user_data=%p, mask_prompt=%08x, p_cert_id_issuers_list=%p, p_cert_id_end_list=%p",
+		(void *)token_id,
+		method,
+		user_data,
+		mask_prompt,
+		(void *)p_cert_id_issuers_list,
+		(void *)p_cert_id_end_list
+	);
+
+	if (p_cert_id_issuers_list != NULL) {
+		*p_cert_id_issuers_list = NULL;
+	}
+	*p_cert_id_end_list = NULL;
+
+#if defined(ENABLE_PKCS11H_THREADING)
+	if (
+		rv == CKR_OK &&
+		(rv = _pkcs11h_threading_mutexLock (&g_pkcs11h_data->mutexes.cache)) == CKR_OK
+	) {
+		mutex_locked = TRUE;
+	}
+#endif
+
+	if (
+		rv == CKR_OK &&
+		(rv = _pkcs11h_session_getSessionByTokenId (
+			token_id,
+			&session
+		)) == CKR_OK
+	) {
+		if (method == PKCS11H_ENUM_METHOD_RELOAD) {
+			pkcs11h_certificate_freeCertificateIdList (session->cached_certs);
+			session->cached_certs = NULL;
+		}
+
+		if (session->cached_certs == NULL) {
+			rv = _pkcs11h_certificate_enumSessionCertificates (session, user_data, mask_prompt);
+		}
+	}
+
+	if (rv == CKR_OK) {
+		rv = __pkcs11h_certificate_splitCertificateIdList (
+			session->cached_certs,
+			p_cert_id_issuers_list,
+			p_cert_id_end_list
+		);
+	}
+
+	if (session != NULL) {
+		_pkcs11h_session_release (session);
+	}
+
+#if defined(ENABLE_PKCS11H_THREADING)
+	if (mutex_locked) {
+		_pkcs11h_threading_mutexRelease (&g_pkcs11h_data->mutexes.cache);
+		mutex_locked = FALSE;
+	}
+#endif
+
+	PKCS11H_DEBUG (
+		PKCS11H_LOG_DEBUG2,
+		"PKCS#11: pkcs11h_certificate_enumTokenCertificateIds return rv=%ld-'%s'",
+		rv,
+		pkcs11h_getMessage (rv)
+	);
+	
+	return rv;
+}
+
+CK_RV
+pkcs11h_certificate_enumCertificateIds (
+	IN const int method,
+	IN void * const user_data,
+	IN const unsigned mask_prompt,
+	OUT pkcs11h_certificate_id_list_t * const p_cert_id_issuers_list,
+	OUT pkcs11h_certificate_id_list_t * const p_cert_id_end_list
+) {
+#if defined(ENABLE_PKCS11H_THREADING)
+	PKCS11H_BOOL mutex_locked = FALSE;
+#endif
+	pkcs11h_certificate_id_list_t cert_id_list = NULL;
+	pkcs11h_provider_t current_provider;
+	pkcs11h_session_t current_session;
+	CK_RV rv = CKR_OK;
+
+	PKCS11H_ASSERT (g_pkcs11h_data!=NULL);
+	PKCS11H_ASSERT (g_pkcs11h_data->initialized);
+	/*PKCS11H_ASSERT (user_data!=NULL); NOT NEEDED*/
+	/*PKCS11H_ASSERT (p_cert_id_issuers_list!=NULL); NOT NEEDED*/
+	PKCS11H_ASSERT (p_cert_id_end_list!=NULL);
+
+	PKCS11H_DEBUG (
+		PKCS11H_LOG_DEBUG2,
+		"PKCS#11: pkcs11h_certificate_enumCertificateIds entry method=%d, mask_prompt=%08x, p_cert_id_issuers_list=%p, p_cert_id_end_list=%p",
+		method,
+		mask_prompt,
+		(void *)p_cert_id_issuers_list,
+		(void *)p_cert_id_end_list
+	);
+
+	if (p_cert_id_issuers_list != NULL) {
+		*p_cert_id_issuers_list = NULL;
+	}
+	*p_cert_id_end_list = NULL;
+
+#if defined(ENABLE_PKCS11H_THREADING)
+	if (
+		rv == CKR_OK &&
+		(rv = _pkcs11h_threading_mutexLock (&g_pkcs11h_data->mutexes.cache)) == CKR_OK
+	) {
+		mutex_locked = TRUE;
+	}
+#endif
+
+	for (
+		current_session = g_pkcs11h_data->sessions;
+		current_session != NULL;
+		current_session = current_session->next
+	) {
+		current_session->touch = FALSE;
+		if (method == PKCS11H_ENUM_METHOD_RELOAD) {
+			pkcs11h_certificate_freeCertificateIdList (current_session->cached_certs);
+			current_session->cached_certs = NULL;
+		}
+	}
+
+	for (
+		current_provider = g_pkcs11h_data->providers;
+		(
+			current_provider != NULL &&
+			rv == CKR_OK
+		);
+		current_provider = current_provider->next
+	) {
+		CK_SLOT_ID_PTR slots = NULL;
+		CK_ULONG slotnum;
+		CK_SLOT_ID slot_index;
+
+		if (!current_provider->enabled) {
+			rv = CKR_CRYPTOKI_NOT_INITIALIZED;
+		}
+
+		if (rv == CKR_OK) {
+			rv = _pkcs11h_session_getSlotList (
+				current_provider,
+				CK_TRUE,
+				&slots,
+				&slotnum
+			);
+		}
+
+		for (
+			slot_index=0;
+			(
+				slot_index < slotnum &&
+				rv == CKR_OK
+			);
+			slot_index++
+		) {
+			pkcs11h_session_t session = NULL;
+			pkcs11h_token_id_t token_id = NULL;
+			CK_TOKEN_INFO info;
+
+			if (rv == CKR_OK) {
+				rv = current_provider->f->C_GetTokenInfo (
+					slots[slot_index],
+					&info
+				);
+			}
+
+			if (
+				rv == CKR_OK &&
+				(rv = _pkcs11h_token_getTokenId (
+					&info,
+					&token_id
+				)) == CKR_OK &&
+				(rv = _pkcs11h_session_getSessionByTokenId (
+					token_id,
+					&session
+				)) == CKR_OK
+			) {
+				session->touch = TRUE;
+
+				if (session->cached_certs == NULL) {
+					rv = _pkcs11h_certificate_enumSessionCertificates (session, user_data, mask_prompt);
+				}
+			}
+
+			if (rv != CKR_OK) {
+				PKCS11H_DEBUG (
+					PKCS11H_LOG_DEBUG1,
+					"PKCS#11: Cannot get token information for provider '%s' slot %ld rv=%ld-'%s'",
+					current_provider->manufacturerID,
+					slots[slot_index],
+					rv,
+					pkcs11h_getMessage (rv)
+				);
+
+				/*
+				 * Ignore error
+				 */
+				rv = CKR_OK;
+			}
+
+			if (session != NULL) {
+				_pkcs11h_session_release (session);
+				session = NULL;
+			}
+
+			if (token_id != NULL) {
+				pkcs11h_token_freeTokenId (token_id);
+				token_id = NULL;
+			}
+		}
+
+		if (rv != CKR_OK) {
+			PKCS11H_DEBUG (
+				PKCS11H_LOG_DEBUG1,
+				"PKCS#11: Cannot get slot list for provider '%s' rv=%ld-'%s'",
+				current_provider->manufacturerID,
+				rv,
+				pkcs11h_getMessage (rv)
+			);
+
+			/*
+			 * Ignore error
+			 */
+			rv = CKR_OK;
+		}
+
+		if (slots != NULL) {
+			_pkcs11h_mem_free ((void *)&slots);
+			slots = NULL;
+		}
+	}
+
+	for (
+		current_session = g_pkcs11h_data->sessions;
+		(
+			current_session != NULL &&
+			rv == CKR_OK
+		);
+		current_session = current_session->next
+	) {
+		if (
+			method == PKCS11H_ENUM_METHOD_CACHE ||
+			(
+				(
+					method == PKCS11H_ENUM_METHOD_RELOAD ||
+					method == PKCS11H_ENUM_METHOD_CACHE_EXIST
+				) &&
+				current_session->touch
+			)
+		) {
+			pkcs11h_certificate_id_list_t entry = NULL;
+
+			for (
+				entry = current_session->cached_certs;
+				(
+					entry != NULL &&
+					rv == CKR_OK
+				);
+				entry = entry->next
+			) {
+				pkcs11h_certificate_id_list_t new_entry = NULL;
+
+				if (
+					rv == CKR_OK &&
+					(rv = _pkcs11h_mem_malloc (
+						(void *)&new_entry,
+						sizeof (struct pkcs11h_certificate_id_list_s)
+					)) == CKR_OK &&
+					(rv = pkcs11h_certificate_duplicateCertificateId (
+						&new_entry->certificate_id,
+						entry->certificate_id
+					)) == CKR_OK
+				) {
+					new_entry->next = cert_id_list;
+					cert_id_list = new_entry;
+					new_entry = NULL;
+				}
+
+				if (new_entry != NULL) {
+					new_entry->next = NULL;
+					pkcs11h_certificate_freeCertificateIdList (new_entry);
+					new_entry = NULL;
+				}
+			}
+		}
+	}
+
+	if (rv == CKR_OK) {
+		rv = __pkcs11h_certificate_splitCertificateIdList (
+			cert_id_list,
+			p_cert_id_issuers_list,
+			p_cert_id_end_list
+		);
+	}
+
+	if (cert_id_list != NULL) {
+		pkcs11h_certificate_freeCertificateIdList (cert_id_list);
+		cert_id_list = NULL;
+	}
+
+
+#if defined(ENABLE_PKCS11H_THREADING)
+	if (mutex_locked) {
+		_pkcs11h_threading_mutexRelease (&g_pkcs11h_data->mutexes.cache);
+		mutex_locked = FALSE;
+	}
+#endif
+
+	PKCS11H_DEBUG (
+		PKCS11H_LOG_DEBUG2,
+		"PKCS#11: pkcs11h_certificate_enumCertificateIds return rv=%ld-'%s'",
+		rv,
+		pkcs11h_getMessage (rv)
+	);
+	
+	return rv;
+}
+
+#endif				/* ENABLE_PKCS11H_CERTIFICATE */
diff --git a/lib/pkcs11h-core.c b/lib/pkcs11h-core.c
new file mode 100644
index 0000000..ceb53df
--- /dev/null
+++ b/lib/pkcs11h-core.c
@@ -0,0 +1,1179 @@
+/*
+ * Copyright (c) 2005-2006 Alon Bar-Lev <alon.barlev at gmail.com>
+ * All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, or the OpenIB.org BSD license.
+ *
+ * GNU General Public License (GPL) Version 2
+ * ===========================================
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2
+ *  as published by the Free Software Foundation.
+ *
+ *  This program 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 General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program (see the file COPYING[.GPL2] included with this
+ *  distribution); if not, write to the Free Software Foundation, Inc.,
+ *  59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * OpenIB.org BSD license
+ * =======================
+ * Redistribution and use in source and binary forms, with or without modifi-
+ * cation, are permitted provided that the following conditions are met:
+ *
+ *   o  Redistributions of source code must retain the above copyright notice,
+ *      this list of conditions and the following disclaimer.
+ *
+ *   o  Redistributions in binary form must reproduce the above copyright no-
+ *      tice, this list of conditions and the following disclaimer in the do-
+ *      cumentation and/or other materials provided with the distribution.
+ *
+ *   o  The names of the contributors may not be used to endorse or promote
+ *      products derived from this software without specific prior written
+ *      permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``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 REGENTS OR CONTRIBUTORS BE LI-
+ * ABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUEN-
+ * TIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEV-
+ * ER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABI-
+ * LITY, 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.
+ */
+
+#include "common.h"
+
+#if !defined(_WIN32)
+#include <sys/types.h>
+#include <dlfcn.h>
+#endif
+
+#include <pkcs11-helper-1.0/pkcs11h-core.h>
+#include <pkcs11-helper-1.0/pkcs11h-token.h>
+#include "_pkcs11h-threading.h"
+#include "_pkcs11h-mem.h"
+#include "_pkcs11h-sys.h"
+#include "_pkcs11h-crypto.h"
+#include "_pkcs11h-util.h"
+#include "_pkcs11h-core.h"
+#include "_pkcs11h-slotevent.h"
+
+/*======================================================================*
+ * COMMON INTERNAL INTERFACE
+ *======================================================================*/
+
+static
+void
+__pkcs11h_hooks_default_log (
+	IN void * const global_data,
+	IN const unsigned flags,
+	IN const char * const format,
+	IN va_list args
+);
+
+static
+PKCS11H_BOOL
+__pkcs11h_hooks_default_token_prompt (
+	IN void * const global_data,
+	IN void * const user_data,
+	IN const pkcs11h_token_id_t token,
+	IN const unsigned retry
+);
+
+static
+PKCS11H_BOOL
+__pkcs11h_hooks_default_pin_prompt (
+	IN void * const global_data,
+	IN void * const user_data,
+	IN const pkcs11h_token_id_t token,
+	IN const unsigned retry,
+	OUT char * const pin,
+	IN const size_t pin_max
+);
+
+#if !defined(_WIN32)
+#if defined(ENABLE_PKCS11H_THREADING)
+static
+void
+__pkcs11h_threading_atfork_prepare  (void);
+static
+void
+__pkcs11h_threading_atfork_parent (void);
+static
+void
+__pkcs11h_threading_atfork_child (void);
+#endif
+static
+CK_RV
+__pkcs11h_forkFixup (void);
+#endif
+
+
+/*==========================================
+ * Data
+ */
+
+pkcs11h_data_t g_pkcs11h_data = NULL;
+unsigned int g_pkcs11h_loglevel = PKCS11H_LOG_INFO;
+
+/*======================================================================*
+ * PUBLIC INTERFACE
+ *======================================================================*/
+
+const char *
+pkcs11h_getMessage (
+	IN const CK_RV rv
+) {
+	switch (rv) {
+		case CKR_OK: return "CKR_OK";
+		case CKR_CANCEL: return "CKR_CANCEL";
+		case CKR_HOST_MEMORY: return "CKR_HOST_MEMORY";
+		case CKR_SLOT_ID_INVALID: return "CKR_SLOT_ID_INVALID";
+		case CKR_GENERAL_ERROR: return "CKR_GENERAL_ERROR";
+		case CKR_FUNCTION_FAILED: return "CKR_FUNCTION_FAILED";
+		case CKR_ARGUMENTS_BAD: return "CKR_ARGUMENTS_BAD";
+		case CKR_NO_EVENT: return "CKR_NO_EVENT";
+		case CKR_NEED_TO_CREATE_THREADS: return "CKR_NEED_TO_CREATE_THREADS";
+		case CKR_CANT_LOCK: return "CKR_CANT_LOCK";
+		case CKR_ATTRIBUTE_READ_ONLY: return "CKR_ATTRIBUTE_READ_ONLY";
+		case CKR_ATTRIBUTE_SENSITIVE: return "CKR_ATTRIBUTE_SENSITIVE";
+		case CKR_ATTRIBUTE_TYPE_INVALID: return "CKR_ATTRIBUTE_TYPE_INVALID";
+		case CKR_ATTRIBUTE_VALUE_INVALID: return "CKR_ATTRIBUTE_VALUE_INVALID";
+		case CKR_DATA_INVALID: return "CKR_DATA_INVALID";
+		case CKR_DATA_LEN_RANGE: return "CKR_DATA_LEN_RANGE";
+		case CKR_DEVICE_ERROR: return "CKR_DEVICE_ERROR";
+		case CKR_DEVICE_MEMORY: return "CKR_DEVICE_MEMORY";
+		case CKR_DEVICE_REMOVED: return "CKR_DEVICE_REMOVED";
+		case CKR_ENCRYPTED_DATA_INVALID: return "CKR_ENCRYPTED_DATA_INVALID";
+		case CKR_ENCRYPTED_DATA_LEN_RANGE: return "CKR_ENCRYPTED_DATA_LEN_RANGE";
+		case CKR_FUNCTION_CANCELED: return "CKR_FUNCTION_CANCELED";
+		case CKR_FUNCTION_NOT_PARALLEL: return "CKR_FUNCTION_NOT_PARALLEL";
+		case CKR_FUNCTION_NOT_SUPPORTED: return "CKR_FUNCTION_NOT_SUPPORTED";
+		case CKR_KEY_HANDLE_INVALID: return "CKR_KEY_HANDLE_INVALID";
+		case CKR_KEY_SIZE_RANGE: return "CKR_KEY_SIZE_RANGE";
+		case CKR_KEY_TYPE_INCONSISTENT: return "CKR_KEY_TYPE_INCONSISTENT";
+		case CKR_KEY_NOT_NEEDED: return "CKR_KEY_NOT_NEEDED";
+		case CKR_KEY_CHANGED: return "CKR_KEY_CHANGED";
+		case CKR_KEY_NEEDED: return "CKR_KEY_NEEDED";
+		case CKR_KEY_INDIGESTIBLE: return "CKR_KEY_INDIGESTIBLE";
+		case CKR_KEY_FUNCTION_NOT_PERMITTED: return "CKR_KEY_FUNCTION_NOT_PERMITTED";
+		case CKR_KEY_NOT_WRAPPABLE: return "CKR_KEY_NOT_WRAPPABLE";
+		case CKR_KEY_UNEXTRACTABLE: return "CKR_KEY_UNEXTRACTABLE";
+		case CKR_MECHANISM_INVALID: return "CKR_MECHANISM_INVALID";
+		case CKR_MECHANISM_PARAM_INVALID: return "CKR_MECHANISM_PARAM_INVALID";
+		case CKR_OBJECT_HANDLE_INVALID: return "CKR_OBJECT_HANDLE_INVALID";
+		case CKR_OPERATION_ACTIVE: return "CKR_OPERATION_ACTIVE";
+		case CKR_OPERATION_NOT_INITIALIZED: return "CKR_OPERATION_NOT_INITIALIZED";
+		case CKR_PIN_INCORRECT: return "CKR_PIN_INCORRECT";
+		case CKR_PIN_INVALID: return "CKR_PIN_INVALID";
+		case CKR_PIN_LEN_RANGE: return "CKR_PIN_LEN_RANGE";
+		case CKR_PIN_EXPIRED: return "CKR_PIN_EXPIRED";
+		case CKR_PIN_LOCKED: return "CKR_PIN_LOCKED";
+		case CKR_SESSION_CLOSED: return "CKR_SESSION_CLOSED";
+		case CKR_SESSION_COUNT: return "CKR_SESSION_COUNT";
+		case CKR_SESSION_HANDLE_INVALID: return "CKR_SESSION_HANDLE_INVALID";
+		case CKR_SESSION_PARALLEL_NOT_SUPPORTED: return "CKR_SESSION_PARALLEL_NOT_SUPPORTED";
+		case CKR_SESSION_READ_ONLY: return "CKR_SESSION_READ_ONLY";
+		case CKR_SESSION_EXISTS: return "CKR_SESSION_EXISTS";
+		case CKR_SESSION_READ_ONLY_EXISTS: return "CKR_SESSION_READ_ONLY_EXISTS";
+		case CKR_SESSION_READ_WRITE_SO_EXISTS: return "CKR_SESSION_READ_WRITE_SO_EXISTS";
+		case CKR_SIGNATURE_INVALID: return "CKR_SIGNATURE_INVALID";
+		case CKR_SIGNATURE_LEN_RANGE: return "CKR_SIGNATURE_LEN_RANGE";
+		case CKR_TEMPLATE_INCOMPLETE: return "CKR_TEMPLATE_INCOMPLETE";
+		case CKR_TEMPLATE_INCONSISTENT: return "CKR_TEMPLATE_INCONSISTENT";
+		case CKR_TOKEN_NOT_PRESENT: return "CKR_TOKEN_NOT_PRESENT";
+		case CKR_TOKEN_NOT_RECOGNIZED: return "CKR_TOKEN_NOT_RECOGNIZED";
+		case CKR_TOKEN_WRITE_PROTECTED: return "CKR_TOKEN_WRITE_PROTECTED";
+		case CKR_UNWRAPPING_KEY_HANDLE_INVALID: return "CKR_UNWRAPPING_KEY_HANDLE_INVALID";
+		case CKR_UNWRAPPING_KEY_SIZE_RANGE: return "CKR_UNWRAPPING_KEY_SIZE_RANGE";
+		case CKR_UNWRAPPING_KEY_TYPE_INCONSISTENT: return "CKR_UNWRAPPING_KEY_TYPE_INCONSISTENT";
+		case CKR_USER_ALREADY_LOGGED_IN: return "CKR_USER_ALREADY_LOGGED_IN";
+		case CKR_USER_NOT_LOGGED_IN: return "CKR_USER_NOT_LOGGED_IN";
+		case CKR_USER_PIN_NOT_INITIALIZED: return "CKR_USER_PIN_NOT_INITIALIZED";
+		case CKR_USER_TYPE_INVALID: return "CKR_USER_TYPE_INVALID";
+		case CKR_USER_ANOTHER_ALREADY_LOGGED_IN: return "CKR_USER_ANOTHER_ALREADY_LOGGED_IN";
+		case CKR_USER_TOO_MANY_TYPES: return "CKR_USER_TOO_MANY_TYPES";
+		case CKR_WRAPPED_KEY_INVALID: return "CKR_WRAPPED_KEY_INVALID";
+		case CKR_WRAPPED_KEY_LEN_RANGE: return "CKR_WRAPPED_KEY_LEN_RANGE";
+		case CKR_WRAPPING_KEY_HANDLE_INVALID: return "CKR_WRAPPING_KEY_HANDLE_INVALID";
+		case CKR_WRAPPING_KEY_SIZE_RANGE: return "CKR_WRAPPING_KEY_SIZE_RANGE";
+		case CKR_WRAPPING_KEY_TYPE_INCONSISTENT: return "CKR_WRAPPING_KEY_TYPE_INCONSISTENT";
+		case CKR_RANDOM_SEED_NOT_SUPPORTED: return "CKR_RANDOM_SEED_NOT_SUPPORTED";
+		case CKR_RANDOM_NO_RNG: return "CKR_RANDOM_NO_RNG";
+		case CKR_DOMAIN_PARAMS_INVALID: return "CKR_DOMAIN_PARAMS_INVALID";
+		case CKR_BUFFER_TOO_SMALL: return "CKR_BUFFER_TOO_SMALL";
+		case CKR_SAVED_STATE_INVALID: return "CKR_SAVED_STATE_INVALID";
+		case CKR_INFORMATION_SENSITIVE: return "CKR_INFORMATION_SENSITIVE";
+		case CKR_STATE_UNSAVEABLE: return "CKR_STATE_UNSAVEABLE";
+		case CKR_CRYPTOKI_NOT_INITIALIZED: return "CKR_CRYPTOKI_NOT_INITIALIZED";
+		case CKR_CRYPTOKI_ALREADY_INITIALIZED: return "CKR_CRYPTOKI_ALREADY_INITIALIZED";
+		case CKR_MUTEX_BAD: return "CKR_MUTEX_BAD";
+		case CKR_MUTEX_NOT_LOCKED: return "CKR_MUTEX_NOT_LOCKED";
+		case CKR_FUNCTION_REJECTED: return "CKR_FUNCTION_REJECTED";
+		case CKR_VENDOR_DEFINED: return "CKR_VENDOR_DEFINED";
+		default: return "Unknown PKCS#11 error";
+	}
+}
+
+unsigned int
+pkcs11h_getVersion (void) {
+	return PKCS11H_VERSION;
+}
+
+unsigned int
+pkcs11h_getFeatures (void) {
+	unsigned int features = (
+#if defined(ENABLE_PKCS11H_ENGINE_OPENSSL)
+		PKCS11H_FEATURE_MASK_ENGINE_OPENSSL |
+#endif
+#if defined(ENABLE_PKCS11H_ENGINE_GNUTLS)
+		PKCS11H_FEATURE_MASK_ENGINE_GNUTLS |
+#endif
+#if defined(ENABLE_PKCS11H_DEBUG)
+		PKCS11H_FEATURE_MASK_DEBUG |
+#endif
+#if defined(ENABLE_PKCS11H_THREADING)
+		PKCS11H_FEATURE_MASK_THREADING |
+#endif
+#if defined(ENABLE_PKCS11H_TOKEN)
+		PKCS11H_FEATURE_MASK_TOKEN |
+#endif
+#if defined(ENABLE_PKCS11H_DATA)
+		PKCS11H_FEATURE_MASK_DATA |
+#endif
+#if defined(ENABLE_PKCS11H_CERTIFICATE)
+		PKCS11H_FEATURE_MASK_CERTIFICATE |
+#endif
+#if defined(ENABLE_PKCS11H_LOCATE)
+		PKCS11H_FEATURE_MASK_LOCATE |
+#endif
+#if defined(ENABLE_PKCS11H_SLOTEVENT)
+		PKCS11H_FEATURE_MASK_SLOTEVENT |
+#endif
+#if defined(ENABLE_PKCS11H_OPENSSL)
+		PKCS11H_FEATURE_MASK_OPENSSL |
+#endif
+#if defined(ENABLE_PKCS11H_STANDALONE)
+		PKCS11H_FEATURE_MASK_STANDALONE |
+#endif
+		0
+	);
+	return features;
+}
+
+CK_RV
+pkcs11h_initialize (void) {
+
+#if defined(ENABLE_PKCS11H_THREADING)
+	PKCS11H_BOOL mutex_locked = FALSE;
+#endif
+	CK_RV rv = CKR_OK;
+
+	PKCS11H_DEBUG (
+		PKCS11H_LOG_DEBUG2,
+		"PKCS#11: pkcs11h_initialize entry"
+	);
+
+	pkcs11h_terminate ();
+
+	if (rv == CKR_OK) {
+		rv = _pkcs11h_mem_malloc ((void*)&g_pkcs11h_data, sizeof (struct pkcs11h_data_s));
+	}
+
+	if (rv == CKR_OK && g_pkcs11h_crypto_engine.initialize == NULL) {
+		rv = CKR_FUNCTION_FAILED;
+	}
+
+	if (
+		rv == CKR_OK &&
+		!g_pkcs11h_crypto_engine.initialize (g_pkcs11h_crypto_engine.global_data)
+	) {
+		PKCS11H_DEBUG (
+			PKCS11H_LOG_ERROR,
+			"PKCS#11: Cannot initialize crypto engine"
+		);
+
+		rv = CKR_FUNCTION_FAILED;
+	}
+
+#if defined(ENABLE_PKCS11H_THREADING)
+	if (rv == CKR_OK) {
+		rv = _pkcs11h_threading_mutexInit (&g_pkcs11h_data->mutexes.global); 
+	}
+	if (rv == CKR_OK) {
+		rv = _pkcs11h_threading_mutexInit (&g_pkcs11h_data->mutexes.session); 
+	}
+	if (rv == CKR_OK) {
+		rv = _pkcs11h_threading_mutexInit (&g_pkcs11h_data->mutexes.cache); 
+	}
+#if !defined(_WIN32)
+	if (
+		rv == CKR_OK &&
+		pthread_atfork (
+			__pkcs11h_threading_atfork_prepare,
+			__pkcs11h_threading_atfork_parent,
+			__pkcs11h_threading_atfork_child
+		)
+	) {
+		rv = CKR_FUNCTION_FAILED;
+	}
+#endif
+	if (
+		rv == CKR_OK &&
+		(rv = _pkcs11h_threading_mutexLock (&g_pkcs11h_data->mutexes.global)) == CKR_OK
+	) {
+		mutex_locked = TRUE;
+	}
+#endif
+
+	if (rv == CKR_OK) {
+		g_pkcs11h_data->max_retries = PKCS11H_DEFAULT_MAX_LOGIN_RETRY;
+		g_pkcs11h_data->allow_protected_auth = TRUE;
+		g_pkcs11h_data->pin_cache_period = PKCS11H_DEFAULT_PIN_CACHE_PERIOD;
+		g_pkcs11h_data->initialized = TRUE;
+	}
+
+	if (rv == CKR_OK) {
+		pkcs11h_setLogHook (__pkcs11h_hooks_default_log, NULL);
+		pkcs11h_setTokenPromptHook (__pkcs11h_hooks_default_token_prompt, NULL);
+		pkcs11h_setPINPromptHook (__pkcs11h_hooks_default_pin_prompt, NULL);
+	}
+	
+#if defined(ENABLE_PKCS11H_THREADING)
+	if (mutex_locked) {
+		_pkcs11h_threading_mutexRelease (&g_pkcs11h_data->mutexes.global);
+		mutex_locked = FALSE;
+	}
+#endif
+
+	PKCS11H_DEBUG (
+		PKCS11H_LOG_DEBUG2,
+		"PKCS#11: pkcs11h_initialize return rv=%ld-'%s'",
+		rv,
+		pkcs11h_getMessage (rv)
+	);
+
+	return rv;
+}
+
+CK_RV
+pkcs11h_terminate (void) {
+
+	PKCS11H_DEBUG (
+		PKCS11H_LOG_DEBUG2,
+		"PKCS#11: pkcs11h_terminate entry"
+	);
+
+	if (g_pkcs11h_data != NULL) {
+		pkcs11h_provider_t current_provider = NULL;
+
+		PKCS11H_DEBUG (
+			PKCS11H_LOG_DEBUG1,
+			"PKCS#11: Removing providers"
+		);
+
+		for (
+			current_provider = g_pkcs11h_data->providers;
+			current_provider != NULL;
+			current_provider = current_provider->next
+		) {
+			pkcs11h_removeProvider (current_provider->reference);
+		}
+
+#if defined(ENABLE_PKCS11H_THREADING)
+		_pkcs11h_threading_mutexLock (&g_pkcs11h_data->mutexes.cache);
+		_pkcs11h_threading_mutexLock (&g_pkcs11h_data->mutexes.session);
+		_pkcs11h_threading_mutexLock (&g_pkcs11h_data->mutexes.global);
+#endif
+
+		PKCS11H_DEBUG (
+			PKCS11H_LOG_DEBUG1,
+			"PKCS#11: Releasing sessions"
+		);
+
+		while (g_pkcs11h_data->sessions != NULL) {
+			pkcs11h_session_t current = g_pkcs11h_data->sessions;
+			g_pkcs11h_data->sessions = g_pkcs11h_data->sessions->next;
+
+#if defined(ENABLE_PKCS11H_THREADING)
+			_pkcs11h_threading_mutexLock (&current->mutex);
+#endif
+
+			current->valid = FALSE;
+
+			if (current->reference_count != 0) {
+				PKCS11H_DEBUG (
+					PKCS11H_LOG_DEBUG1,
+					"PKCS#11: Warning: Found session with references"
+				);
+			}
+
+			if (current->token_id != NULL) {
+				pkcs11h_token_freeTokenId (current->token_id);
+				current->token_id = NULL;
+			}
+
+#if defined(ENABLE_PKCS11H_CERTIFICATE)
+			pkcs11h_certificate_freeCertificateIdList (current->cached_certs);
+#endif
+
+			current->provider = NULL;
+
+#if defined(ENABLE_PKCS11H_THREADING)
+			_pkcs11h_threading_mutexFree (&current->mutex);
+#endif
+
+			_pkcs11h_mem_free ((void *)&current);
+		}
+
+#if defined(ENABLE_PKCS11H_SLOTEVENT)
+		PKCS11H_DEBUG (
+			PKCS11H_LOG_DEBUG1,
+			"PKCS#11: Terminating slotevent"
+		);
+
+		_pkcs11h_slotevent_terminate ();
+#endif
+		PKCS11H_DEBUG (
+			PKCS11H_LOG_DEBUG1,
+			"PKCS#11: Marking as uninitialized"
+		);
+		
+		g_pkcs11h_data->initialized = FALSE;
+
+		while (g_pkcs11h_data->providers != NULL) {
+			pkcs11h_provider_t current = g_pkcs11h_data->providers;
+			g_pkcs11h_data->providers = g_pkcs11h_data->providers->next;
+
+			_pkcs11h_mem_free ((void *)&current);
+		}
+
+#if defined(ENABLE_PKCS11H_THREADING)
+		_pkcs11h_threading_mutexFree (&g_pkcs11h_data->mutexes.cache);
+		_pkcs11h_threading_mutexFree (&g_pkcs11h_data->mutexes.global); 
+		_pkcs11h_threading_mutexFree (&g_pkcs11h_data->mutexes.session); 
+#endif
+
+		g_pkcs11h_crypto_engine.uninitialize (g_pkcs11h_crypto_engine.global_data);
+
+		_pkcs11h_mem_free ((void *)&g_pkcs11h_data);
+	}
+
+	PKCS11H_DEBUG (
+		PKCS11H_LOG_DEBUG2,
+		"PKCS#11: pkcs11h_terminate return"
+	);
+
+	return CKR_OK;
+}
+
+void
+pkcs11h_setLogLevel (
+	IN const unsigned flags
+) {
+	g_pkcs11h_loglevel = flags;
+}
+
+unsigned
+pkcs11h_getLogLevel (void) {
+	PKCS11H_ASSERT (g_pkcs11h_data!=NULL);
+	PKCS11H_ASSERT (g_pkcs11h_data->initialized);
+
+	return g_pkcs11h_loglevel;
+}
+
+CK_RV
+pkcs11h_setLogHook (
+	IN const pkcs11h_hook_log_t hook,
+	IN void * const global_data
+) {
+	PKCS11H_ASSERT (g_pkcs11h_data!=NULL);
+	PKCS11H_ASSERT (g_pkcs11h_data->initialized);
+	PKCS11H_ASSERT (hook!=NULL);
+
+	g_pkcs11h_data->hooks.log = hook;
+	g_pkcs11h_data->hooks.log_data = global_data;
+
+	return CKR_OK;
+}
+
+CK_RV
+pkcs11h_setSlotEventHook (
+	IN const pkcs11h_hook_slotevent_t hook,
+	IN void * const global_data
+) {
+	PKCS11H_ASSERT (g_pkcs11h_data!=NULL);
+	PKCS11H_ASSERT (g_pkcs11h_data->initialized);
+	PKCS11H_ASSERT (hook!=NULL);
+
+#if defined(ENABLE_PKCS11H_SLOTEVENT)
+	g_pkcs11h_data->hooks.slotevent = hook;
+	g_pkcs11h_data->hooks.slotevent_data = global_data;
+
+	return _pkcs11h_slotevent_init ();
+#else
+	(void)global_data;
+
+	return CKR_FUNCTION_NOT_SUPPORTED;
+#endif
+}
+
+CK_RV
+pkcs11h_setPINPromptHook (
+	IN const pkcs11h_hook_pin_prompt_t hook,
+	IN void * const global_data
+) {
+	PKCS11H_ASSERT (g_pkcs11h_data!=NULL);
+	PKCS11H_ASSERT (g_pkcs11h_data->initialized);
+	PKCS11H_ASSERT (hook!=NULL);
+
+	g_pkcs11h_data->hooks.pin_prompt = hook;
+	g_pkcs11h_data->hooks.pin_prompt_data = global_data;
+
+	return CKR_OK;
+}
+
+CK_RV
+pkcs11h_setTokenPromptHook (
+	IN const pkcs11h_hook_token_prompt_t hook,
+	IN void * const global_data
+) {
+	PKCS11H_ASSERT (g_pkcs11h_data!=NULL);
+	PKCS11H_ASSERT (g_pkcs11h_data->initialized);
+	PKCS11H_ASSERT (hook!=NULL);
+
+	g_pkcs11h_data->hooks.token_prompt = hook;
+	g_pkcs11h_data->hooks.token_prompt_data = global_data;
+
+	return CKR_OK;
+}
+
+CK_RV
+pkcs11h_setPINCachePeriod (
+	IN const int pin_cache_period
+) {
+	PKCS11H_ASSERT (g_pkcs11h_data!=NULL);
+	PKCS11H_ASSERT (g_pkcs11h_data->initialized);
+
+	g_pkcs11h_data->pin_cache_period = pin_cache_period;
+
+	return CKR_OK;
+}
+
+CK_RV
+pkcs11h_setMaxLoginRetries (
+	IN const unsigned max_retries
+) {
+	PKCS11H_ASSERT (g_pkcs11h_data!=NULL);
+	PKCS11H_ASSERT (g_pkcs11h_data->initialized);
+
+	g_pkcs11h_data->max_retries = max_retries;
+
+	return CKR_OK;
+}
+
+CK_RV
+pkcs11h_setProtectedAuthentication (
+	IN const PKCS11H_BOOL allow_protected_auth
+) {
+	PKCS11H_ASSERT (g_pkcs11h_data!=NULL);
+	PKCS11H_ASSERT (g_pkcs11h_data->initialized);
+
+	g_pkcs11h_data->allow_protected_auth = allow_protected_auth;
+
+	return CKR_OK;
+}
+
+CK_RV
+pkcs11h_addProvider (
+	IN const char * const reference,
+	IN const char * const provider_location,
+	IN const PKCS11H_BOOL allow_protected_auth,
+	IN const unsigned mask_private_mode,
+	IN const int slot_event_method,
+	IN const int slot_poll_interval,
+	IN const PKCS11H_BOOL cert_is_private
+) {
+#if defined(ENABLE_PKCS11H_THREADING)
+	PKCS11H_BOOL mutex_locked = FALSE;
+#endif
+#if defined(_WIN32)
+	int mypid = 0;
+#else
+	pid_t mypid = getpid ();
+#endif
+	pkcs11h_provider_t provider = NULL;
+	CK_C_GetFunctionList gfl = NULL;
+	CK_INFO info;
+	CK_RV rv = CKR_OK;
+
+	PKCS11H_ASSERT (g_pkcs11h_data!=NULL);
+	PKCS11H_ASSERT (g_pkcs11h_data->initialized);
+	PKCS11H_ASSERT (provider_location!=NULL);
+	/*PKCS11H_ASSERT (szSignMode!=NULL); NOT NEEDED*/
+
+	PKCS11H_DEBUG (
+		PKCS11H_LOG_DEBUG2,
+		"PKCS#11: pkcs11h_addProvider entry pid=%d, reference='%s', provider_location='%s', allow_protected_auth=%d, mask_private_mode=%08x, cert_is_private=%d",
+		mypid,
+		reference,
+		provider_location,
+		allow_protected_auth ? 1 : 0,
+		mask_private_mode,
+		cert_is_private ? 1 : 0
+	);
+
+	PKCS11H_DEBUG (
+		PKCS11H_LOG_DEBUG1,
+		"PKCS#11: Adding provider '%s'-'%s'",
+		reference,
+		provider_location
+	);
+
+#if defined(ENABLE_PKCS11H_THREADING)
+	if (
+		rv == CKR_OK &&
+		(rv = _pkcs11h_threading_mutexLock (&g_pkcs11h_data->mutexes.global)) == CKR_OK
+	) {
+		mutex_locked = TRUE;
+	}
+#endif
+
+	if (
+		rv == CKR_OK &&
+		(rv = _pkcs11h_mem_malloc ((void *)&provider, sizeof (struct pkcs11h_provider_s))) == CKR_OK
+	) {
+		strncpy (
+			provider->reference,
+			reference,
+			sizeof (provider->reference)-1
+		);
+		provider->reference[sizeof (provider->reference)-1] = '\x0';
+		strncpy (
+			provider->manufacturerID,
+			(
+			 	strlen (provider_location) < sizeof (provider->manufacturerID) ?
+				provider_location :
+				provider_location+strlen (provider_location)-sizeof (provider->manufacturerID)+1
+			),
+			sizeof (provider->manufacturerID)-1
+		);
+		provider->manufacturerID[sizeof (provider->manufacturerID)-1] = '\x0';
+		provider->allow_protected_auth = allow_protected_auth;
+		provider->mask_private_mode = mask_private_mode;
+		provider->slot_event_method = slot_event_method;
+		provider->slot_poll_interval = slot_poll_interval;
+		provider->cert_is_private = cert_is_private;
+	}
+		
+	if (rv == CKR_OK) {
+#if defined(_WIN32)
+		provider->handle = LoadLibraryA (provider_location);
+#else
+		provider->handle = dlopen (provider_location, RTLD_NOW);
+#endif
+		if (provider->handle == NULL) {
+			rv = CKR_FUNCTION_FAILED;
+		}
+	}
+
+	if (rv == CKR_OK) {
+#if defined(_WIN32)
+		gfl = (CK_C_GetFunctionList)GetProcAddress (
+			provider->handle,
+			"C_GetFunctionList"
+		);
+#else
+		/*
+		 * Make compiler happy!
+		 */
+		void *p = dlsym (
+			provider->handle,
+			"C_GetFunctionList"
+		);
+		memmove (
+			&gfl, 
+			&p,
+			sizeof (void *)
+		);
+#endif
+		if (gfl == NULL) {
+			rv = CKR_FUNCTION_FAILED;
+		}
+	}
+
+	if (rv == CKR_OK) {
+		rv = gfl (&provider->f);
+	}
+
+	if (rv == CKR_OK) {
+		if ((rv = provider->f->C_Initialize (NULL)) != CKR_OK) {
+			if (rv == CKR_CRYPTOKI_ALREADY_INITIALIZED) {
+				rv = CKR_OK;
+			}
+		}
+		else {
+			provider->should_finalize = TRUE;
+		}
+	}
+
+	if (
+		rv == CKR_OK &&
+		(rv = provider->f->C_GetInfo (&info)) == CKR_OK
+	) {
+		_pkcs11h_util_fixupFixedString (
+			provider->manufacturerID,
+			(char *)info.manufacturerID,
+			sizeof (info.manufacturerID)
+		);
+	}
+
+	if (rv == CKR_OK) {
+		provider->enabled = TRUE;
+	}
+
+	if (provider != NULL) {
+		if (g_pkcs11h_data->providers == NULL) {
+			g_pkcs11h_data->providers = provider;
+		}
+		else {
+			pkcs11h_provider_t last = NULL;
+	
+			for (
+				last = g_pkcs11h_data->providers;
+				last->next != NULL;
+				last = last->next
+			);
+			last->next = provider;
+		}
+	}
+
+#if defined(ENABLE_PKCS11H_THREADING)
+	if (mutex_locked) {
+		_pkcs11h_threading_mutexRelease (&g_pkcs11h_data->mutexes.global);
+		mutex_locked = FALSE;
+	}
+#endif
+
+#if defined(ENABLE_PKCS11H_SLOTEVENT)
+	_pkcs11h_slotevent_notify ();
+#endif
+
+	PKCS11H_DEBUG (
+		PKCS11H_LOG_DEBUG1,
+		"PKCS#11: Provider '%s' added rv=%ld-'%s'",
+		reference,
+		rv,
+		pkcs11h_getMessage (rv)
+	);
+
+	PKCS11H_DEBUG (
+		PKCS11H_LOG_DEBUG2,
+		"PKCS#11: pkcs11h_addProvider return rv=%ld-'%s'",
+		rv,
+		pkcs11h_getMessage (rv)
+	);
+
+	return rv;
+}
+
+CK_RV
+pkcs11h_removeProvider (
+	IN const char * const reference
+) {
+#if defined(ENABLE_PKCS11H_THREADING)
+	pkcs11h_session_t current_session = NULL;
+#endif
+	pkcs11h_provider_t provider = NULL;
+	CK_RV rv = CKR_OK;
+
+	PKCS11H_ASSERT (reference!=NULL);
+
+	PKCS11H_DEBUG (
+		PKCS11H_LOG_DEBUG2,
+		"PKCS#11: pkcs11h_removeProvider entry reference='%s'",
+		reference
+	);
+
+	PKCS11H_DEBUG (
+		PKCS11H_LOG_DEBUG1,
+		"PKCS#11: Removing provider '%s'",
+		reference
+	);
+
+#if defined(ENABLE_PKCS11H_THREADING)
+	_pkcs11h_threading_mutexLock (&g_pkcs11h_data->mutexes.cache);
+	_pkcs11h_threading_mutexLock (&g_pkcs11h_data->mutexes.session);
+	_pkcs11h_threading_mutexLock (&g_pkcs11h_data->mutexes.global);
+
+	for (
+		current_session = g_pkcs11h_data->sessions;
+		current_session != NULL;
+		current_session = current_session->next
+	) {
+		_pkcs11h_threading_mutexLock (&current_session->mutex);
+	}
+#endif
+
+	provider = g_pkcs11h_data->providers;
+	while (
+		rv == CKR_OK &&
+		provider != NULL &&
+		strcmp (reference, provider->reference)
+	) {
+		provider = provider->next;
+	}
+
+	if (rv == CKR_OK && provider == NULL) {
+		rv = CKR_OBJECT_HANDLE_INVALID;
+	}
+
+	if (rv == CKR_OK) {
+		provider->enabled = FALSE;
+		provider->reference[0] = '\0';
+
+		if (provider->should_finalize) {
+			provider->f->C_Finalize (NULL);
+			provider->should_finalize = FALSE;
+		}
+
+#if defined(ENABLE_PKCS11H_SLOTEVENT)
+		_pkcs11h_slotevent_notify ();
+		
+		/*
+		 * Wait until manager join this thread
+		 * this happens saldom so I can poll
+		 */
+		while (provider->slotevent_thread != PKCS11H_THREAD_NULL) {
+			_pkcs11h_threading_sleep (500);
+		}
+#endif
+
+		if (provider->f != NULL) {
+			provider->f = NULL;
+		}
+
+		if (provider->handle != NULL) {
+#if defined(_WIN32)
+			FreeLibrary (provider->handle);
+#else
+			dlclose (provider->handle);
+#endif
+			provider->handle = NULL;
+		}
+	}
+
+#if defined(ENABLE_PKCS11H_THREADING)
+	for (
+		current_session = g_pkcs11h_data->sessions;
+		current_session != NULL;
+		current_session = current_session->next
+	) {
+		_pkcs11h_threading_mutexRelease (&current_session->mutex);
+	}
+
+	_pkcs11h_threading_mutexRelease (&g_pkcs11h_data->mutexes.cache);
+	_pkcs11h_threading_mutexRelease (&g_pkcs11h_data->mutexes.session);
+	_pkcs11h_threading_mutexRelease (&g_pkcs11h_data->mutexes.global);
+#endif
+	
+	PKCS11H_DEBUG (
+		PKCS11H_LOG_DEBUG2,
+		"PKCS#11: pkcs11h_removeProvider return rv=%ld-'%s'",
+		rv,
+		pkcs11h_getMessage (rv)
+	);
+
+	return rv;
+}
+
+CK_RV
+pkcs11h_forkFixup (void) {
+#if defined(_WIN32)
+	return CKR_OK;
+#else
+#if defined(ENABLE_PKCS11H_THREADING)
+	return CKR_OK;
+#else
+	return __pkcs11h_forkFixup ();
+#endif
+#endif
+}
+
+CK_RV
+pkcs11h_plugAndPlay (void) {
+#if defined(_WIN32)
+	int mypid = 0;
+#else
+	pid_t mypid = getpid ();
+#endif
+
+	PKCS11H_DEBUG (
+		PKCS11H_LOG_DEBUG2,
+		"PKCS#11: pkcs11h_forkFixup entry pid=%d",
+		mypid
+	);
+
+	if (g_pkcs11h_data != NULL && g_pkcs11h_data->initialized) {
+		pkcs11h_provider_t current;
+#if defined(ENABLE_PKCS11H_SLOTEVENT)
+		PKCS11H_BOOL slot_event_active = FALSE;
+#endif
+
+#if defined(ENABLE_PKCS11H_THREADING)
+		_pkcs11h_threading_mutexLock (&g_pkcs11h_data->mutexes.global);
+#endif
+		for (
+			current = g_pkcs11h_data->providers;
+			current != NULL;
+			current = current->next
+		) {
+			if (current->enabled) {
+				current->f->C_Finalize (NULL);
+			}
+		}
+
+#if defined(ENABLE_PKCS11H_SLOTEVENT)
+		if (g_pkcs11h_data->slotevent.initialized) {
+			slot_event_active = TRUE;
+			_pkcs11h_slotevent_terminate ();
+		}
+#endif
+
+		for (
+			current = g_pkcs11h_data->providers;
+			current != NULL;
+			current = current->next
+		) {
+			if (current->enabled) {
+				current->f->C_Initialize (NULL);
+			}
+		}
+
+#if defined(ENABLE_PKCS11H_SLOTEVENT)
+		if (slot_event_active) {
+			_pkcs11h_slotevent_init ();
+		}
+#endif
+
+#if defined(ENABLE_PKCS11H_THREADING)
+		_pkcs11h_threading_mutexRelease (&g_pkcs11h_data->mutexes.global);
+#endif
+	}
+
+	PKCS11H_DEBUG (
+		PKCS11H_LOG_DEBUG2,
+		"PKCS#11: pkcs11h_forkFixup return"
+	);
+
+	return CKR_OK;
+}
+
+/*======================================================================*
+ * COMMON INTERNAL INTERFACE
+ *======================================================================*/
+
+void
+_pkcs11h_log (
+	IN const unsigned flags,
+	IN const char * const format,
+	IN ...
+) {
+	va_list args;
+
+	PKCS11H_ASSERT (format!=NULL);
+
+	va_start (args, format);
+
+	if (
+		g_pkcs11h_data != NULL &&
+		g_pkcs11h_data->initialized
+	) { 
+		if (PKCS11H_MSG_LEVEL_TEST (flags)) {
+			if (g_pkcs11h_data->hooks.log == NULL) {
+				__pkcs11h_hooks_default_log (
+					NULL,
+					flags,
+					format,
+					args
+				);
+			}
+			else {
+				g_pkcs11h_data->hooks.log (
+					g_pkcs11h_data->hooks.log_data,
+					flags,
+					format,
+					args
+				);
+			}
+		}
+	}
+
+	va_end (args);
+}
+
+static
+void
+__pkcs11h_hooks_default_log (
+	IN void * const global_data,
+	IN const unsigned flags,
+	IN const char * const format,
+	IN va_list args
+) {
+	(void)global_data;
+	(void)flags;
+	(void)format;
+	(void)args;
+}
+
+static
+PKCS11H_BOOL
+__pkcs11h_hooks_default_token_prompt (
+	IN void * const global_data,
+	IN void * const user_data,
+	IN const pkcs11h_token_id_t token,
+	IN const unsigned retry
+) {
+	/*PKCS11H_ASSERT (global_data) NOT NEEDED */
+	/*PKCS11H_ASSERT (user_data) NOT NEEDED */
+	PKCS11H_ASSERT (token!=NULL);
+
+	(void)global_data;
+	(void)user_data;
+	(void)retry;
+
+	PKCS11H_DEBUG (
+		PKCS11H_LOG_DEBUG2,
+		"PKCS#11: __pkcs11h_hooks_default_token_prompt global_data=%p, user_data=%p, display='%s'",
+		global_data,
+		user_data,
+		token->display
+	);
+
+	return FALSE;
+}
+
+static
+PKCS11H_BOOL
+__pkcs11h_hooks_default_pin_prompt (
+	IN void * const global_data,
+	IN void * const user_data,
+	IN const pkcs11h_token_id_t token,
+	IN const unsigned retry,
+	OUT char * const pin,
+	IN const size_t pin_max
+) {
+	/*PKCS11H_ASSERT (global_data) NOT NEEDED */
+	/*PKCS11H_ASSERT (user_data) NOT NEEDED */
+	PKCS11H_ASSERT (token!=NULL);
+
+	(void)global_data;
+	(void)user_data;
+	(void)retry;
+	(void)pin;
+	(void)pin_max;
+
+	PKCS11H_DEBUG (
+		PKCS11H_LOG_DEBUG2,
+		"PKCS#11: __pkcs11h_hooks_default_pin_prompt global_data=%p, user_data=%p, display='%s'",
+		global_data,
+		user_data,
+		token->display
+	);
+	
+	return FALSE;
+}
+
+#if !defined(_WIN32)
+#if defined(ENABLE_PKCS11H_THREADING)
+
+static
+void
+__pkcs11h_threading_atfork_prepare  (void) {
+	_pkcs1h_threading_mutexLockAll ();
+}
+static
+void
+__pkcs11h_threading_atfork_parent (void) {
+	_pkcs1h_threading_mutexReleaseAll ();
+}
+static
+void
+__pkcs11h_threading_atfork_child (void) {
+	_pkcs1h_threading_mutexReleaseAll ();
+	__pkcs11h_forkFixup ();
+}
+
+#endif				/* ENABLE_PKCS11H_THREADING */
+
+static
+CK_RV
+__pkcs11h_forkFixup (void) {
+#if defined(ENABLE_PKCS11H_THREADING)
+	PKCS11H_BOOL mutex_locked = FALSE;
+#endif
+	pid_t mypid = getpid ();
+
+	PKCS11H_DEBUG (
+		PKCS11H_LOG_DEBUG2,
+		"PKCS#11: pkcs11h_forkFixup entry pid=%d",
+		mypid
+	);
+
+	if (g_pkcs11h_data != NULL && g_pkcs11h_data->initialized) {
+		pkcs11h_provider_t current;
+
+#if defined(ENABLE_PKCS11H_THREADING)
+		if (_pkcs11h_threading_mutexLock (&g_pkcs11h_data->mutexes.global) == CKR_OK) {
+			mutex_locked = TRUE;
+		}
+#endif
+
+		for (
+			current = g_pkcs11h_data->providers;
+			current != NULL;
+			current = current->next
+		) {
+			if (current->enabled) {
+				current->f->C_Initialize (NULL);
+			}
+
+#if defined(ENABLE_PKCS11H_SLOTEVENT)
+			/*
+			 * After fork we have no threads...
+			 * So just initialized.
+			 */
+			if (g_pkcs11h_data->slotevent.initialized) {
+				g_pkcs11h_data->slotevent.initialized = FALSE;
+				_pkcs11h_slotevent_init ();
+			}
+#endif
+		}
+	}
+
+#if defined(ENABLE_PKCS11H_THREADING)
+	if (mutex_locked) {
+		_pkcs11h_threading_mutexRelease (&g_pkcs11h_data->mutexes.global);
+		mutex_locked = FALSE;
+	}
+#endif
+
+	PKCS11H_DEBUG (
+		PKCS11H_LOG_DEBUG2,
+		"PKCS#11: pkcs11h_forkFixup return"
+	);
+
+	return CKR_OK;
+}
+
+#endif				/* !WIN32 */
+
diff --git a/lib/pkcs11h-crypto.c b/lib/pkcs11h-crypto.c
new file mode 100644
index 0000000..eb884e2
--- /dev/null
+++ b/lib/pkcs11h-crypto.c
@@ -0,0 +1,1280 @@
+/*
+ * Copyright (c) 2005-2006 Alon Bar-Lev <alon.barlev at gmail.com>
+ * All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, or the OpenIB.org BSD license.
+ *
+ * GNU General Public License (GPL) Version 2
+ * ===========================================
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2
+ *  as published by the Free Software Foundation.
+ *
+ *  This program 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 General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program (see the file COPYING[.GPL2] included with this
+ *  distribution); if not, write to the Free Software Foundation, Inc.,
+ *  59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * OpenIB.org BSD license
+ * =======================
+ * Redistribution and use in source and binary forms, with or without modifi-
+ * cation, are permitted provided that the following conditions are met:
+ *
+ *   o  Redistributions of source code must retain the above copyright notice,
+ *      this list of conditions and the following disclaimer.
+ *
+ *   o  Redistributions in binary form must reproduce the above copyright no-
+ *      tice, this list of conditions and the following disclaimer in the do-
+ *      cumentation and/or other materials provided with the distribution.
+ *
+ *   o  The names of the contributors may not be used to endorse or promote
+ *      products derived from this software without specific prior written
+ *      permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``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 REGENTS OR CONTRIBUTORS BE LI-
+ * ABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUEN-
+ * TIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEV-
+ * ER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABI-
+ * LITY, 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.
+ */
+
+#include "common.h"
+
+#include <pkcs11-helper-1.0/pkcs11h-core.h>
+#include "_pkcs11h-util.h"
+#include "_pkcs11h-sys.h"
+#include "_pkcs11h-crypto.h"
+
+#if defined(ENABLE_PKCS11H_ENGINE_OPENSSL)
+#include <openssl/x509.h>
+#endif
+
+#if defined(ENABLE_PKCS11H_ENGINE_GNUTLS)
+#include <gnutls/x509.h>
+#endif
+
+#if defined(ENABLE_PKCS11H_ENGINE_WIN32)
+#include <wincrypt.h>
+#if !defined(X509_MULTI_BYTE_INTEGER)
+#define X509_MULTI_BYTE_INTEGER	((LPCSTR)28)
+#endif
+#if !defined(CRYPT_VERIFY_CERT_SIGN_SUBJECT_CERT)
+#define CRYPT_VERIFY_CERT_SIGN_SUBJECT_CERT	0x02
+#endif
+#if !defined(CRYPT_VERIFY_CERT_SIGN_ISSUER_CERT)
+#define CRYPT_VERIFY_CERT_SIGN_ISSUER_CERT	0x02
+#endif
+
+#endif
+
+/*===========================================
+ * Constants
+ */
+
+#if defined(ENABLE_PKCS11H_ENGINE_OPENSSL)
+
+#if OPENSSL_VERSION_NUMBER < 0x00907000L && defined(CRYPTO_LOCK_ENGINE)
+# define RSA_get_default_method RSA_get_default_openssl_method
+#else
+# ifdef HAVE_ENGINE_GET_DEFAULT_RSA
+#  include <openssl/engine.h>
+#  if OPENSSL_VERSION_NUMBER < 0x0090704fL
+#   define BROKEN_OPENSSL_ENGINE
+#  endif
+# endif
+#endif
+
+#if OPENSSL_VERSION_NUMBER < 0x00907000L
+#if !defined(RSA_PKCS1_PADDING_SIZE)
+#define RSA_PKCS1_PADDING_SIZE 11
+#endif
+#endif
+
+#endif
+
+#if defined(ENABLE_PKCS11H_ENGINE_OPENSSL)
+
+#if OPENSSL_VERSION_NUMBER < 0x00908000L
+typedef unsigned char *pkcs11_openssl_d2i_t;
+#else
+typedef const unsigned char *pkcs11_openssl_d2i_t;
+#endif
+
+#endif
+
+#if defined(ENABLE_PKCS11H_ENGINE_OPENSSL)
+
+static
+int
+__pkcs11h_crypto_openssl_initialize (
+	IN void * const global_data
+);
+
+static
+int
+__pkcs11h_crypto_openssl_uninitialize (
+	IN void * const global_data
+);
+
+static
+int
+__pkcs11h_crypto_openssl_certificate_get_expiration (
+	IN void * const global_data,
+	IN const unsigned char * const blob,
+	IN const size_t blob_size,
+	OUT time_t * const expiration
+);
+
+static
+int
+__pkcs11h_crypto_openssl_certificate_get_dn (
+	IN void * const global_data,
+	IN const unsigned char * const blob,
+	IN const size_t blob_size,
+	OUT char * const dn,
+	IN const size_t dn_max
+);
+
+static
+int
+__pkcs11h_crypto_openssl_certificate_get_serial (
+	IN void * const global_data,
+	IN const unsigned char * const blob,
+	IN const size_t blob_size,
+	OUT char * const serial,
+	IN const size_t serial_max
+);
+
+static
+int
+__pkcs11h_crypto_openssl_certificate_is_issuer (
+	IN void * const global_data,
+	IN const unsigned char * const signer_blob,
+	IN const size_t signer_blob_size,
+	IN const unsigned char * const cert_blob,
+	IN const size_t cert_blob_size
+);
+
+#endif
+
+#if defined(ENABLE_PKCS11H_ENGINE_GNUTLS)
+
+static
+int
+__pkcs11h_crypto_gnutls_initialize (
+	IN void * const global_data
+);
+
+static
+int
+__pkcs11h_crypto_gnutls_uninitialize (
+	IN void * const global_data
+);
+
+static
+int
+__pkcs11h_crypto_gnutls_certificate_get_expiration (
+	IN void * const global_data,
+	IN const unsigned char * const blob,
+	IN const size_t blob_size,
+	OUT time_t * const expiration
+);
+
+static
+int
+__pkcs11h_crypto_gnutls_certificate_get_dn (
+	IN void * const global_data,
+	IN const unsigned char * const blob,
+	IN const size_t blob_size,
+	OUT char * const dn,
+	IN const size_t dn_max
+);
+
+static
+int
+__pkcs11h_crypto_gnutls_certificate_get_serial (
+	IN void * const global_data,
+	IN const unsigned char * const blob,
+	IN const size_t blob_size,
+	OUT char * const serial,
+	IN const size_t serial_max
+);
+
+static
+int
+__pkcs11h_crypto_gnutls_certificate_is_issuer (
+	IN void * const global_data,
+	IN const unsigned char * const signer_blob,
+	IN const size_t signer_blob_size,
+	IN const unsigned char * const cert_blob,
+	IN const size_t cert_blob_size
+);
+
+#endif
+
+#if defined(ENABLE_PKCS11H_ENGINE_WIN32)
+
+typedef PCCERT_CONTEXT (WINAPI *CertCreateCertificateContext_t) (
+	DWORD dwCertEncodingType,
+	const BYTE *pbCertEncoded,
+	DWORD cbCertEncoded
+);
+typedef BOOL (WINAPI *CertFreeCertificateContext_t) (
+	PCCERT_CONTEXT pCertContext
+);
+typedef DWORD (WINAPI *CertNameToStrW_t) (
+	DWORD dwCertEncodingType,
+	PCERT_NAME_BLOB pName,
+	DWORD dwStrType,
+	LPWSTR psz,
+	DWORD csz
+);
+typedef BOOL (WINAPI *CryptDecodeObject_t) (
+	DWORD dwCertEncodingType,
+	LPCSTR lpszStructType,
+	const BYTE* pbEncoded,
+	DWORD cbEncoded,
+	DWORD dwFlags,
+	void* pvStructInfo,
+	DWORD* pcbStructInfo
+);
+typedef BOOL (WINAPI *CryptVerifyCertificateSignatureEx_t) (
+	void *hCryptProv,
+	DWORD dwCertEncodingType,
+	DWORD dwSubjectType,
+	void* pvSubject,
+	DWORD dwIssuerType,
+	void* pvIssuer,
+	DWORD dwFlags,
+	void* pvReserved
+);
+
+typedef struct __crypto_win32_data_s {
+	HMODULE handle;
+	CertCreateCertificateContext_t p_CertCreateCertificateContext;
+	CertFreeCertificateContext_t p_CertFreeCertificateContext;
+	CertNameToStrW_t p_CertNameToStrW;
+	CryptDecodeObject_t p_CryptDecodeObject;
+	CryptVerifyCertificateSignatureEx_t p_CryptVerifyCertificateSignatureEx;
+} *__crypto_win32_data_t;
+
+static
+int
+__pkcs11h_crypto_win32_initialize (
+	IN void * const global_data
+);
+
+static
+int
+__pkcs11h_crypto_win32_uninitialize (
+	IN void * const global_data
+);
+
+static
+int
+__pkcs11h_crypto_win32_certificate_get_expiration (
+	IN void * const global_data,
+	IN const unsigned char * const blob,
+	IN const size_t blob_size,
+	OUT time_t * const expiration
+);
+
+static
+int
+__pkcs11h_crypto_win32_certificate_get_dn (
+	IN void * const global_data,
+	IN const unsigned char * const blob,
+	IN const size_t blob_size,
+	OUT char * const dn,
+	IN const size_t dn_max
+);
+
+static
+int
+__pkcs11h_crypto_win32_certificate_get_serial (
+	IN void * const global_data,
+	IN const unsigned char * const blob,
+	IN const size_t blob_size,
+	OUT char * const serial,
+	IN const size_t serial_max
+);
+
+static
+int
+__pkcs11h_crypto_win32_certificate_is_issuer (
+	IN void * const global_data,
+	IN const unsigned char * const signer_blob,
+	IN const size_t signer_blob_size,
+	IN const unsigned char * const cert_blob,
+	IN const size_t cert_blob_size
+);
+
+#endif
+
+#if defined(ENABLE_PKCS11H_ENGINE_OPENSSL)
+pkcs11h_engine_crypto_t g_pkcs11h_crypto_engine = {
+	NULL,
+	__pkcs11h_crypto_openssl_initialize,
+	__pkcs11h_crypto_openssl_uninitialize,
+	__pkcs11h_crypto_openssl_certificate_get_expiration,
+	__pkcs11h_crypto_openssl_certificate_get_dn,
+	__pkcs11h_crypto_openssl_certificate_get_serial,
+	__pkcs11h_crypto_openssl_certificate_is_issuer
+};
+#elif defined(ENABLE_PKCS11H_ENGINE_GNUTLS)
+pkcs11h_engine_crypto_t g_pkcs11h_crypto_engine = {
+	NULL,
+	__pkcs11h_crypto_gnutls_initialize,
+	__pkcs11h_crypto_gnutls_uninitialize,
+	__pkcs11h_crypto_gnutls_certificate_get_expiration,
+	__pkcs11h_crypto_gnutls_certificate_get_dn,
+	__pkcs11h_crypto_gnutls_certificate_get_serial,
+	__pkcs11h_crypto_gnutls_certificate_is_issuer
+};
+#elif defined(ENABLE_PKCS11H_ENGINE_WIN32)
+static struct __crypto_win32_data_s s_win32_data;
+pkcs11h_engine_crypto_t g_pkcs11h_crypto_engine = {
+	&s_win32_data,
+	__pkcs11h_crypto_win32_initialize,
+	__pkcs11h_crypto_win32_uninitialize,
+	__pkcs11h_crypto_win32_certificate_get_expiration,
+	__pkcs11h_crypto_win32_certificate_get_dn,
+	__pkcs11h_crypto_win32_certificate_get_serial,
+	__pkcs11h_crypto_win32_certificate_is_issuer
+};
+#else
+pkcs11h_engine_crypto_t g_pkcs11h_crypto_engine = {
+	NULL,
+	NULL,
+	NULL,
+	NULL,
+	NULL,
+	NULL,
+	NULL
+};
+#endif
+
+CK_RV
+pkcs11h_engine_setCrypto (
+	IN const pkcs11h_engine_crypto_t * const engine
+) {
+	PKCS11H_ASSERT (engine!=NULL);
+
+	memmove (&g_pkcs11h_crypto_engine, engine, sizeof (pkcs11h_engine_crypto_t));
+
+	return CKR_OK;
+}
+
+#if defined(ENABLE_PKCS11H_ENGINE_OPENSSL)
+
+static
+int
+__pkcs11h_crypto_openssl_initialize (
+	IN void * const global_data
+) {
+	(void)global_data;
+
+	OpenSSL_add_all_digests ();
+
+	return TRUE;
+}
+
+static
+int
+__pkcs11h_crypto_openssl_uninitialize (
+	IN void * const global_data
+) {
+	(void)global_data;
+
+	return TRUE;
+}
+
+static
+int
+__pkcs11h_crypto_openssl_certificate_get_expiration (
+	IN void * const global_data,
+	IN const unsigned char * const blob,
+	IN const size_t blob_size,
+	OUT time_t * const expiration
+) {
+	X509 *x509 = NULL;
+
+	(void)global_data;
+
+	/*PKCS11H_ASSERT (global_data!=NULL); NOT NEEDED*/
+	PKCS11H_ASSERT (blob!=NULL);
+	PKCS11H_ASSERT (expiration!=NULL);
+
+	*expiration = (time_t)0;
+
+	x509 = X509_new ();
+
+	if (x509 != NULL) {
+		pkcs11_openssl_d2i_t d2i = (pkcs11_openssl_d2i_t)blob;
+
+		if (
+			d2i_X509 (&x509, &d2i, blob_size)
+		) {
+			ASN1_TIME *notBefore = X509_get_notBefore (x509);
+			ASN1_TIME *notAfter = X509_get_notAfter (x509);
+
+			if (
+				notBefore != NULL &&
+				notAfter != NULL &&
+				X509_cmp_current_time (notBefore) <= 0 &&
+				X509_cmp_current_time (notAfter) >= 0 &&
+				notAfter->length >= 12
+			) {
+				struct tm tm1;
+				time_t now = time (NULL);
+
+				memset (&tm1, 0, sizeof (tm1));
+				tm1.tm_year = (notAfter->data[ 0] - '0') * 10 + (notAfter->data[ 1] - '0') + 100;
+				tm1.tm_mon  = (notAfter->data[ 2] - '0') * 10 + (notAfter->data[ 3] - '0') - 1;
+				tm1.tm_mday = (notAfter->data[ 4] - '0') * 10 + (notAfter->data[ 5] - '0');
+				tm1.tm_hour = (notAfter->data[ 6] - '0') * 10 + (notAfter->data[ 7] - '0');
+				tm1.tm_min  = (notAfter->data[ 8] - '0') * 10 + (notAfter->data[ 9] - '0');
+				tm1.tm_sec  = (notAfter->data[10] - '0') * 10 + (notAfter->data[11] - '0');
+
+				tm1.tm_sec += (int)(mktime (localtime (&now)) - mktime (gmtime (&now)));
+
+				*expiration = mktime (&tm1);
+			}
+		}
+
+		X509_free (x509);
+		x509 = NULL;
+	}
+
+	return *expiration != (time_t)0;
+}
+
+static
+int
+__pkcs11h_crypto_openssl_certificate_get_dn (
+	IN void * const global_data,
+	IN const unsigned char * const blob,
+	IN const size_t blob_size,
+	OUT char * const dn,
+	IN const size_t dn_max
+) {
+	X509 *x509 = NULL;
+	pkcs11_openssl_d2i_t d2i1;
+
+	(void)global_data;
+
+	/*PKCS11H_ASSERT (global_data!=NULL); NOT NEEDED*/
+	PKCS11H_ASSERT (blob!=NULL);
+	PKCS11H_ASSERT (dn!=NULL);
+	PKCS11H_ASSERT (dn_max>0);
+
+	dn[0] = '\x0';
+
+	if (blob_size > 0) {
+		if ((x509 = X509_new ()) != NULL) {
+			d2i1 = (pkcs11_openssl_d2i_t)blob;
+			if (d2i_X509 (&x509, &d2i1, blob_size)) {
+				X509_NAME_oneline (
+					X509_get_subject_name (x509),
+					dn,
+					dn_max
+				);
+			}
+
+			X509_free (x509);
+			x509 = NULL;
+		}
+	}
+
+	return dn[0] != '\x0';
+}
+
+static
+int
+__pkcs11h_crypto_openssl_certificate_get_serial (
+	IN void * const global_data,
+	IN const unsigned char * const blob,
+	IN const size_t blob_size,
+	OUT char * const serial,
+	IN const size_t serial_max
+) {
+	X509 *x509 = NULL;
+	BIO *bioSerial = NULL;
+
+	(void)global_data;
+
+	/*PKCS11H_ASSERT (global_data!=NULL); NOT NEEDED*/
+	PKCS11H_ASSERT (blob!=NULL);
+	PKCS11H_ASSERT (serial!=NULL);
+	PKCS11H_ASSERT (serial_max>0);
+
+	serial[0] = '\x0';
+
+	if ((x509 = X509_new ()) != NULL) {
+		pkcs11_openssl_d2i_t d2i1 = (pkcs11_openssl_d2i_t)blob;
+		if (d2i_X509 (&x509, &d2i1, blob_size)) {
+			if ((bioSerial = BIO_new (BIO_s_mem ())) != NULL) {
+				int n;
+
+				i2a_ASN1_INTEGER(bioSerial, X509_get_serialNumber (x509));
+				n = BIO_read (bioSerial, serial, serial_max-1);
+				if (n<0) {
+					serial[0] = '\0';
+				}
+				else {
+					serial[n] = '\0';
+				}
+
+				BIO_free_all (bioSerial);
+				bioSerial = NULL;
+			}
+		}
+
+		X509_free (x509);
+		x509 = NULL;
+	}
+
+	return serial[0] != '\x0';
+}
+
+static
+int
+__pkcs11h_crypto_openssl_certificate_is_issuer (
+	IN void * const global_data,
+	IN const unsigned char * const issuer_blob,
+	IN const size_t issuer_blob_size,
+	IN const unsigned char * const cert_blob,
+	IN const size_t cert_blob_size
+) {
+	X509 *x509_issuer = NULL;
+	X509 *x509_cert = NULL;
+	EVP_PKEY *pub_issuer = NULL;
+	pkcs11_openssl_d2i_t d2i;
+	PKCS11H_BOOL is_issuer = FALSE;
+	PKCS11H_BOOL ok = TRUE;
+
+	(void)global_data;
+
+	/*PKCS11H_ASSERT (global_data!=NULL); NOT NEEDED*/
+	PKCS11H_ASSERT (issuer_blob!=NULL);
+	PKCS11H_ASSERT (cert_blob!=NULL);
+
+	if (
+		ok &&
+		(x509_issuer = X509_new ()) == NULL
+	) {
+		ok = FALSE;
+	}
+
+	if (
+		ok &&
+		(x509_cert = X509_new ()) == NULL
+	) {
+		ok = FALSE;
+	}
+
+	if (ok && (x509_issuer == NULL || x509_cert == NULL)) {
+		ok = FALSE;
+	}
+
+	d2i = (pkcs11_openssl_d2i_t)issuer_blob;
+	if (
+		ok &&
+		!d2i_X509 (
+			&x509_issuer,
+			&d2i,
+			issuer_blob_size
+		)
+	) {
+		ok = FALSE;
+	}
+
+	d2i = (pkcs11_openssl_d2i_t)cert_blob;
+	if (
+		ok &&
+		!d2i_X509 (
+			&x509_cert,
+			&d2i,
+			cert_blob_size
+		)
+	) {
+		ok = FALSE;
+	}
+
+	if (
+		ok &&
+		(pub_issuer = X509_get_pubkey (x509_issuer)) == NULL
+	) {
+		ok = FALSE;
+	}
+
+	if (
+		ok &&
+		!X509_NAME_cmp (
+			X509_get_subject_name (x509_issuer),
+			X509_get_issuer_name (x509_cert)
+		) &&
+		X509_verify (x509_cert, pub_issuer) == 1
+	) {
+		is_issuer = TRUE;
+	}
+
+	if (pub_issuer != NULL) {
+		EVP_PKEY_free (pub_issuer);
+		pub_issuer = NULL;
+	}
+	if (x509_issuer != NULL) {
+		X509_free (x509_issuer);
+		x509_issuer = NULL;
+	}
+	if (x509_cert != NULL) {
+		X509_free (x509_cert);
+		x509_cert = NULL;
+	}
+
+	return is_issuer;
+}
+
+/*======================================================================*
+ * FIXUPS
+ *======================================================================*/
+
+#ifdef BROKEN_OPENSSL_ENGINE
+static void broken_openssl_init(void) __attribute__ ((constructor));
+static void  broken_openssl_init(void)
+{
+	SSL_library_init();
+	ENGINE_load_openssl();
+	ENGINE_register_all_RSA();
+}
+#endif
+
+#endif				/* ENABLE_PKCS11H_ENGINE_OPENSSL */
+
+#if defined(ENABLE_PKCS11H_ENGINE_GNUTLS)
+
+static
+int
+__pkcs11h_crypto_gnutls_initialize (
+	IN void * const global_data
+) {
+	(void)global_data;
+
+	/*PKCS11H_ASSERT (global_data!=NULL); NOT NEEDED*/
+	if (gnutls_global_init () != GNUTLS_E_SUCCESS) {
+		return FALSE;
+	}
+	else {
+		return TRUE;
+	}
+}
+
+static
+int
+__pkcs11h_crypto_gnutls_uninitialize (
+	IN void * const global_data
+) {
+	(void)global_data;
+
+	/*PKCS11H_ASSERT (global_data!=NULL); NOT NEEDED*/
+	gnutls_global_deinit ();
+
+	return TRUE;
+}
+
+static
+int
+__pkcs11h_crypto_gnutls_certificate_get_expiration (
+	IN void * const global_data,
+	IN const unsigned char * const blob,
+	IN const size_t blob_size,
+	OUT time_t * const expiration
+) {
+	gnutls_x509_crt_t cert = NULL;
+
+	(void)global_data;
+
+	/*PKCS11H_ASSERT (global_data!=NULL); NOT NEEDED*/
+	PKCS11H_ASSERT (blob!=NULL);
+	PKCS11H_ASSERT (expiration!=NULL);
+
+	*expiration = (time_t)0;
+
+	if (gnutls_x509_crt_init (&cert) == GNUTLS_E_SUCCESS) {
+		gnutls_datum_t datum = {(unsigned char *)blob, blob_size};
+
+		if (gnutls_x509_crt_import (cert, &datum, GNUTLS_X509_FMT_DER) == GNUTLS_E_SUCCESS) {
+
+			time_t activation_time = gnutls_x509_crt_get_activation_time (cert);
+			time_t expiration_time = gnutls_x509_crt_get_expiration_time (cert);
+			time_t now = time (NULL);
+
+			if (
+				now >= activation_time &&
+				now <= expiration_time
+			) {
+				*expiration = expiration_time;
+			}
+		}
+		gnutls_x509_crt_deinit (cert);
+	}
+
+	return *expiration != (time_t)0;
+}
+
+static
+int
+__pkcs11h_crypto_gnutls_certificate_get_dn (
+	IN void * const global_data,
+	IN const unsigned char * const blob,
+	IN const size_t blob_size,
+	OUT char * const dn,
+	IN const size_t dn_max
+) {
+	gnutls_x509_crt_t cert = NULL;
+
+	(void)global_data;
+
+	/*PKCS11H_ASSERT (global_data!=NULL); NOT NEEDED*/
+	PKCS11H_ASSERT (blob!=NULL);
+	PKCS11H_ASSERT (dn!=NULL);
+	PKCS11H_ASSERT (dn_max>0);
+
+	dn[0] = '\x0';
+
+	if (gnutls_x509_crt_init (&cert) == GNUTLS_E_SUCCESS) {
+		gnutls_datum_t datum = {(unsigned char *)blob, blob_size};
+
+		if (gnutls_x509_crt_import (cert, &datum, GNUTLS_X509_FMT_DER) == GNUTLS_E_SUCCESS) {
+			size_t s = dn_max;
+			if (
+				gnutls_x509_crt_get_dn (
+					cert,
+					dn,
+					&s
+				) != GNUTLS_E_SUCCESS
+			) {
+				/* gnutls sets output parameters */
+				dn[0] = '\x0';
+			}
+		}
+		gnutls_x509_crt_deinit (cert);
+	}
+
+	return dn[0] != '\x0';
+}
+
+static
+int
+__pkcs11h_crypto_gnutls_certificate_get_serial (
+	IN void * const global_data,
+	IN const unsigned char * const blob,
+	IN const size_t blob_size,
+	OUT char * const serial,
+	IN const size_t serial_max
+) {
+	gnutls_x509_crt_t cert = NULL;
+
+	(void)global_data;
+
+	/*PKCS11H_ASSERT (global_data!=NULL); NOT NEEDED*/
+	PKCS11H_ASSERT (blob!=NULL);
+	PKCS11H_ASSERT (serial!=NULL);
+	PKCS11H_ASSERT (serial_max>0);
+
+	serial[0] = '\x0';
+
+	if (gnutls_x509_crt_init (&cert) == GNUTLS_E_SUCCESS) {
+		gnutls_datum_t datum = {(unsigned char *)blob, blob_size};
+
+		if (gnutls_x509_crt_import (cert, &datum, GNUTLS_X509_FMT_DER) == GNUTLS_E_SUCCESS) {
+			unsigned char ser[1024];
+			size_t ser_size = sizeof (ser);
+			if (gnutls_x509_crt_get_serial (cert, ser, &ser_size) == GNUTLS_E_SUCCESS) {
+				_pkcs11h_util_binaryToHex (
+					serial,
+					serial_max,
+					ser,
+					ser_size
+				);
+			}
+		}
+		gnutls_x509_crt_deinit (cert);
+	}
+
+	return serial[0] != '\x0';
+}
+
+static
+int
+__pkcs11h_crypto_gnutls_certificate_is_issuer (
+	IN void * const global_data,
+	IN const unsigned char * const issuer_blob,
+	IN const size_t issuer_blob_size,
+	IN const unsigned char * const cert_blob,
+	IN const size_t cert_blob_size
+) {
+	gnutls_x509_crt_t cert_issuer = NULL;
+	gnutls_x509_crt_t cert_cert = NULL;
+	gnutls_datum_t datum;
+	PKCS11H_BOOL is_issuer = FALSE;
+	PKCS11H_BOOL ok = TRUE;
+	unsigned int result = 0;
+
+	(void)global_data;
+
+	/*PKCS11H_ASSERT (global_data!=NULL); NOT NEEDED*/
+	PKCS11H_ASSERT (issuer_blob!=NULL);
+	PKCS11H_ASSERT (cert_blob!=NULL);
+
+	if (ok && gnutls_x509_crt_init (&cert_issuer) != GNUTLS_E_SUCCESS) {
+		/* gnutls sets output */
+		cert_issuer = NULL;
+		ok = FALSE;
+	}
+	if (ok && gnutls_x509_crt_init (&cert_cert) != GNUTLS_E_SUCCESS) {
+		/* gnutls sets output */
+		cert_cert = NULL;
+		ok = FALSE;
+	}
+
+	datum.data = (unsigned char *)issuer_blob;
+	datum.size = issuer_blob_size;
+
+	if (
+		ok &&
+		gnutls_x509_crt_import (
+			cert_issuer,
+			&datum,
+			GNUTLS_X509_FMT_DER
+		) != GNUTLS_E_SUCCESS
+	) {
+		ok = FALSE;
+	}
+
+	datum.data = (unsigned char *)cert_blob;
+	datum.size = cert_blob_size;
+
+	if (
+		ok &&
+		gnutls_x509_crt_import (
+			cert_cert,
+			&datum,
+			GNUTLS_X509_FMT_DER
+		) != GNUTLS_E_SUCCESS
+	) {
+		ok = FALSE;
+	}
+
+	if (
+		ok &&
+		gnutls_x509_crt_verify (
+			cert_cert,
+			&cert_issuer,
+			1,
+			0,
+			&result
+		) &&
+		(result & GNUTLS_CERT_INVALID) == 0
+	) {
+		is_issuer = TRUE;
+	}
+
+	if (cert_cert != NULL) {
+		gnutls_x509_crt_deinit (cert_cert);
+		cert_cert = NULL;
+	}
+
+	if (cert_issuer != NULL) {
+		gnutls_x509_crt_deinit (cert_issuer);
+		cert_issuer = NULL;
+	}
+
+	return is_issuer;
+}
+
+#endif				/* ENABLE_PKCS11H_ENGINE_GNUTLS */
+
+#if defined(ENABLE_PKCS11H_ENGINE_WIN32)
+
+static
+int
+__pkcs11h_crypto_win32_initialize (
+	IN void * const global_data
+) {
+	__crypto_win32_data_t data = (__crypto_win32_data_t)global_data;
+
+	PKCS11H_ASSERT (global_data!=NULL);
+
+	memset (data, 0, sizeof (struct __crypto_win32_data_s));
+
+	data->handle = LoadLibraryA ("crypt32.dll");
+	if (data->handle == NULL) {
+		return 0;
+	}
+
+	data->p_CertCreateCertificateContext = (CertCreateCertificateContext_t)GetProcAddress (
+		data->handle,
+		"CertCreateCertificateContext"
+	);
+	data->p_CertFreeCertificateContext = (CertFreeCertificateContext_t)GetProcAddress (
+		data->handle,
+		"CertFreeCertificateContext"
+	);
+	data->p_CertNameToStrW = (CertNameToStrW_t)GetProcAddress (
+		data->handle,
+		"CertNameToStrW"
+	);
+	data->p_CryptDecodeObject = (CryptDecodeObject_t)GetProcAddress (
+		data->handle,
+		"CryptDecodeObject"
+	);
+	data->p_CryptVerifyCertificateSignatureEx = (CryptVerifyCertificateSignatureEx_t)GetProcAddress (
+		data->handle,
+		"CryptVerifyCertificateSignatureEx"
+	);
+
+	if (
+		data->p_CertCreateCertificateContext == NULL ||
+		data->p_CertFreeCertificateContext == NULL ||
+		data->p_CertNameToStrW == NULL ||
+		data->p_CryptDecodeObject == NULL ||
+		data->p_CryptVerifyCertificateSignatureEx == NULL
+	) {
+		FreeLibrary (data->handle);
+		data->handle = NULL;
+		return 0;
+	}
+
+	return 1;
+}
+
+static
+int
+__pkcs11h_crypto_win32_uninitialize (
+	IN void * const global_data
+) {
+	__crypto_win32_data_t data = (__crypto_win32_data_t)global_data;
+
+	PKCS11H_ASSERT (global_data!=NULL);
+
+	if (data->handle != NULL) {
+		FreeLibrary (data->handle);
+		data->handle = NULL;
+	}
+
+	return 1;
+}
+
+static
+int
+__pkcs11h_crypto_win32_certificate_get_expiration (
+	IN void * const global_data,
+	IN const unsigned char * const blob,
+	IN const size_t blob_size,
+	OUT time_t * const expiration
+) {
+	__crypto_win32_data_t data = (__crypto_win32_data_t)global_data;
+	PCCERT_CONTEXT cert = NULL;
+	PKCS11H_BOOL ok = TRUE;
+	SYSTEMTIME st;
+
+	PKCS11H_ASSERT (global_data!=NULL);
+	PKCS11H_ASSERT (blob!=NULL);
+	PKCS11H_ASSERT (expiration!=NULL);
+
+	*expiration = (time_t)0;
+
+	if (
+		ok &&
+		(cert = data->p_CertCreateCertificateContext (
+			PKCS_7_ASN_ENCODING | X509_ASN_ENCODING,
+			blob,
+			blob_size
+		)) == NULL
+	) {
+		ok = FALSE;
+	}
+
+	if (
+		ok &&
+		!FileTimeToSystemTime (
+			&cert->pCertInfo->NotAfter,
+			&st
+		)
+	) {
+		ok = FALSE;
+	}
+
+	if (ok) {
+		struct tm tm1;
+		time_t now = time (NULL);
+
+		memset (&tm1, 0, sizeof (tm1));
+		tm1.tm_year = st.wYear - 1900;
+		tm1.tm_mon  = st.wMonth - 1;
+		tm1.tm_mday = st.wDay;
+		tm1.tm_hour = st.wHour;
+		tm1.tm_min  = st.wMinute;
+		tm1.tm_sec  = st.wSecond;
+
+		tm1.tm_sec += (int)(mktime (localtime (&now)) - mktime (gmtime (&now)));
+
+		*expiration = mktime (&tm1);
+	}
+
+	if (cert != NULL) {
+		data->p_CertFreeCertificateContext (cert);
+		cert = NULL;
+	}
+
+	return ok != FALSE;
+}
+
+static
+int
+__pkcs11h_crypto_win32_certificate_get_dn (
+	IN void * const global_data,
+	IN const unsigned char * const blob,
+	IN const size_t blob_size,
+	OUT char * const dn,
+	IN const size_t dn_max
+) {
+	__crypto_win32_data_t data = (__crypto_win32_data_t)global_data;
+	PCCERT_CONTEXT cert = NULL;
+	PKCS11H_BOOL ok = TRUE;
+	DWORD wsize;
+	WCHAR *wstr = NULL;
+
+	PKCS11H_ASSERT (global_data!=NULL);
+	PKCS11H_ASSERT (blob!=NULL);
+	PKCS11H_ASSERT (dn!=NULL);
+	PKCS11H_ASSERT (dn_max>0);
+
+	dn[0] = '\x0';
+
+	if (
+		ok &&
+		(cert = data->p_CertCreateCertificateContext (
+			PKCS_7_ASN_ENCODING | X509_ASN_ENCODING,
+			blob,
+			blob_size
+		)) == NULL
+	) {
+		ok = FALSE;
+	}
+
+	if (
+		ok &&
+		(wsize = data->p_CertNameToStrW (
+			X509_ASN_ENCODING,
+			&cert->pCertInfo->Subject,
+			CERT_X500_NAME_STR | CERT_NAME_STR_REVERSE_FLAG,
+			NULL,
+			0
+		)) == 0
+	) {
+		ok = FALSE;
+	}
+	
+	if (
+		ok &&
+		(wstr = (WCHAR *)g_pkcs11h_sys_engine.malloc (wsize * sizeof (WCHAR))) == NULL
+	) {
+		ok = FALSE;
+	}
+			
+	if (
+		ok &&
+		(wsize = data->p_CertNameToStrW (
+			X509_ASN_ENCODING,
+			&cert->pCertInfo->Subject,
+			CERT_X500_NAME_STR | CERT_NAME_STR_REVERSE_FLAG,
+			wstr,
+			wsize
+		)) == 0
+	) {
+		ok = FALSE;
+	}
+
+	if (
+		ok &&
+		WideCharToMultiByte (
+			CP_UTF8,
+			0,
+			wstr,
+			-1,
+			dn,
+			dn_max,
+			NULL,
+			NULL
+		) == 0
+	) {
+		ok = FALSE;
+	}
+
+	if (wstr != NULL) {
+		g_pkcs11h_sys_engine.free (wstr);
+		wstr = NULL;
+	}
+
+	if (cert != NULL) {
+		data->p_CertFreeCertificateContext (cert);
+		cert = NULL;
+	}
+
+	return ok != FALSE;
+}
+
+static
+int
+__pkcs11h_crypto_win32_certificate_get_serial (
+	IN void * const global_data,
+	IN const unsigned char * const blob,
+	IN const size_t blob_size,
+	OUT char * const serial,
+	IN const size_t serial_max
+) {
+	__crypto_win32_data_t data = (__crypto_win32_data_t)global_data;
+	PCCERT_CONTEXT cert = NULL;
+	PKCS11H_BOOL ok = TRUE;
+	PBYTE bin_serial = NULL;
+	size_t i;
+
+	PKCS11H_ASSERT (global_data!=NULL);
+	PKCS11H_ASSERT (blob!=NULL);
+	PKCS11H_ASSERT (serial!=NULL);
+	PKCS11H_ASSERT (serial_max>0);
+
+	serial[0] = '\x0';
+
+	if (
+		ok &&
+		(cert = data->p_CertCreateCertificateContext (
+			PKCS_7_ASN_ENCODING | X509_ASN_ENCODING,
+			blob,
+			blob_size
+		)) == NULL
+	) {
+		ok = FALSE;
+	}
+
+	if (
+		ok &&
+		(bin_serial = (PBYTE)g_pkcs11h_sys_engine.malloc (cert->pCertInfo->SerialNumber.cbData)) == NULL
+	) {
+		ok = FALSE;
+	}
+
+	for (i=0;ok && i<cert->pCertInfo->SerialNumber.cbData;i++) {
+		bin_serial[cert->pCertInfo->SerialNumber.cbData-1-i] = cert->pCertInfo->SerialNumber.pbData[i];
+	}
+
+	if (
+		ok &&
+		_pkcs11h_util_binaryToHex (
+			serial,
+			serial_max,
+			bin_serial,
+			cert->pCertInfo->SerialNumber.cbData
+		) != CKR_OK
+	) {
+		ok = FALSE;
+	}
+
+	if (bin_serial != NULL) {
+		g_pkcs11h_sys_engine.free (bin_serial);
+		bin_serial = NULL;
+	}
+
+	if (cert != NULL) {
+		data->p_CertFreeCertificateContext (cert);
+		cert = NULL;
+	}
+
+	return ok != FALSE;
+}
+
+static
+int
+__pkcs11h_crypto_win32_certificate_is_issuer (
+	IN void * const global_data,
+	IN const unsigned char * const issuer_blob,
+	IN const size_t issuer_blob_size,
+	IN const unsigned char * const cert_blob,
+	IN const size_t cert_blob_size
+) {
+	__crypto_win32_data_t data = (__crypto_win32_data_t)global_data;
+	PCCERT_CONTEXT cert_issuer = NULL;
+	PCCERT_CONTEXT cert_cert = NULL;
+	PKCS11H_BOOL ok = TRUE;
+	PKCS11H_BOOL issuer = FALSE;
+
+	PKCS11H_ASSERT (global_data!=NULL);
+	PKCS11H_ASSERT (issuer_blob!=NULL);
+	PKCS11H_ASSERT (cert_blob!=NULL);
+
+	if (
+		ok &&
+		(cert_issuer = data->p_CertCreateCertificateContext (
+			PKCS_7_ASN_ENCODING | X509_ASN_ENCODING,
+			issuer_blob,
+			issuer_blob_size
+		)) == NULL
+	) {
+		ok = FALSE;
+	}
+
+	if (
+		ok &&
+		(cert_cert = data->p_CertCreateCertificateContext (
+			PKCS_7_ASN_ENCODING | X509_ASN_ENCODING,
+			cert_blob,
+			cert_blob_size
+		)) == NULL
+	) {
+		ok = FALSE;
+	}
+
+	if (
+		ok &&
+		data->p_CryptVerifyCertificateSignatureEx (
+			NULL,
+			X509_ASN_ENCODING,
+			CRYPT_VERIFY_CERT_SIGN_SUBJECT_CERT,
+			(void *)cert_cert,
+			CRYPT_VERIFY_CERT_SIGN_ISSUER_CERT,
+			(void *)cert_issuer,
+			0,
+			NULL
+		)
+	) {
+		issuer = TRUE;
+	}
+
+	if (cert_issuer != NULL) {
+		data->p_CertFreeCertificateContext (cert_issuer);
+		cert_issuer = NULL;
+	}
+
+	if (cert_cert != NULL) {
+		data->p_CertFreeCertificateContext (cert_cert);
+		cert_cert = NULL;
+	}
+
+	return issuer != FALSE;
+}
+
+#endif				/* ENABLE_PKCS11H_ENGINE_WIN32 */
diff --git a/lib/pkcs11h-data.c b/lib/pkcs11h-data.c
new file mode 100644
index 0000000..174dc1b
--- /dev/null
+++ b/lib/pkcs11h-data.c
@@ -0,0 +1,779 @@
+/*
+ * Copyright (c) 2005-2006 Alon Bar-Lev <alon.barlev at gmail.com>
+ * All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, or the OpenIB.org BSD license.
+ *
+ * GNU General Public License (GPL) Version 2
+ * ===========================================
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2
+ *  as published by the Free Software Foundation.
+ *
+ *  This program 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 General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program (see the file COPYING[.GPL2] included with this
+ *  distribution); if not, write to the Free Software Foundation, Inc.,
+ *  59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * OpenIB.org BSD license
+ * =======================
+ * Redistribution and use in source and binary forms, with or without modifi-
+ * cation, are permitted provided that the following conditions are met:
+ *
+ *   o  Redistributions of source code must retain the above copyright notice,
+ *      this list of conditions and the following disclaimer.
+ *
+ *   o  Redistributions in binary form must reproduce the above copyright no-
+ *      tice, this list of conditions and the following disclaimer in the do-
+ *      cumentation and/or other materials provided with the distribution.
+ *
+ *   o  The names of the contributors may not be used to endorse or promote
+ *      products derived from this software without specific prior written
+ *      permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``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 REGENTS OR CONTRIBUTORS BE LI-
+ * ABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUEN-
+ * TIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEV-
+ * ER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABI-
+ * LITY, 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.
+ */
+
+#include "common.h"
+
+#include <pkcs11-helper-1.0/pkcs11h-data.h>
+#include "_pkcs11h-mem.h"
+#include "_pkcs11h-session.h"
+
+#if defined(ENABLE_PKCS11H_DATA)
+
+static
+CK_RV
+_pkcs11h_data_getObject (
+	IN const pkcs11h_session_t session,
+	IN const char * const application,
+	IN const char * const label,
+	OUT CK_OBJECT_HANDLE * const p_handle
+) {
+	CK_OBJECT_CLASS class = CKO_DATA;
+	CK_ATTRIBUTE filter[] = {
+		{CKA_CLASS, (void *)&class, sizeof (class)},
+		{CKA_APPLICATION, (void *)application, application == NULL ? 0 : strlen (application)},
+		{CKA_LABEL, (void *)label, label == NULL ? 0 : strlen (label)}
+	};
+	CK_OBJECT_HANDLE *objects = NULL;
+	CK_ULONG objects_found = 0;
+	CK_RV rv = CKR_OK;
+	
+	PKCS11H_ASSERT (session!=NULL);
+	PKCS11H_ASSERT (application!=NULL);
+	PKCS11H_ASSERT (label!=NULL);
+
+	PKCS11H_DEBUG (
+		PKCS11H_LOG_DEBUG2,
+		"PKCS#11: _pkcs11h_data_getObject entry session=%p, application='%s', label='%s', p_handle=%p",
+		(void *)session,
+		application,
+		label,
+		(void *)p_handle
+	);
+
+	*p_handle = PKCS11H_INVALID_OBJECT_HANDLE;
+
+	if (rv == CKR_OK) {
+		rv = _pkcs11h_session_validate (session);
+	}
+
+	if (rv == CKR_OK) {
+		rv = _pkcs11h_session_findObjects (
+			session,
+			filter,
+			sizeof (filter) / sizeof (CK_ATTRIBUTE),
+			&objects,
+			&objects_found
+		);
+	}
+
+	if (
+		rv == CKR_OK &&
+		objects_found == 0
+	) {
+		rv = CKR_FUNCTION_REJECTED;
+	}
+
+	if (rv == CKR_OK) {
+		*p_handle = objects[0];
+	}
+
+	if (objects != NULL) {
+		_pkcs11h_mem_free ((void *)&objects);
+	}
+
+	PKCS11H_DEBUG (
+		PKCS11H_LOG_DEBUG2,
+		"PKCS#11: _pkcs11h_data_getObject return rv=%ld-'%s', *p_handle=%08lx",
+		rv,
+		pkcs11h_getMessage (rv),
+		(unsigned long)*p_handle
+	);
+
+	return rv;
+}
+
+CK_RV
+pkcs11h_data_get (
+	IN const pkcs11h_token_id_t token_id,
+	IN const PKCS11H_BOOL is_public,
+	IN const char * const application,
+	IN const char * const label,
+	IN void * const user_data,
+	IN const unsigned mask_prompt,
+	OUT unsigned char * const blob,
+	IN OUT size_t * const p_blob_size
+) {
+	CK_ATTRIBUTE attrs[] = {
+		{CKA_VALUE, NULL, 0}
+	};
+	CK_OBJECT_HANDLE handle = PKCS11H_INVALID_OBJECT_HANDLE;
+	CK_RV rv = CKR_OK;
+
+#if defined(ENABLE_PKCS11H_THREADING)
+	PKCS11H_BOOL mutex_locked = FALSE;
+#endif
+	pkcs11h_session_t session = NULL;
+	PKCS11H_BOOL op_succeed = FALSE;
+	PKCS11H_BOOL login_retry = FALSE;
+	size_t blob_size_max = 0;
+
+	PKCS11H_ASSERT (g_pkcs11h_data!=NULL);
+	PKCS11H_ASSERT (g_pkcs11h_data->initialized);
+	PKCS11H_ASSERT (token_id!=NULL);
+	PKCS11H_ASSERT (application!=NULL);
+	PKCS11H_ASSERT (label!=NULL);
+	/*PKCS11H_ASSERT (user_data) NOT NEEDED */
+	/*PKCS11H_ASSERT (blob!=NULL); NOT NEEDED*/
+	PKCS11H_ASSERT (p_blob_size!=NULL);
+
+	PKCS11H_DEBUG (
+		PKCS11H_LOG_DEBUG2,
+		"PKCS#11: pkcs11h_data_get entry token_id=%p, application='%s', label='%s', user_data=%p, mask_prompt=%08x, blob=%p, *p_blob_size=%u",
+		(void *)token_id,
+		application,
+		label,
+		user_data,
+		mask_prompt,
+		blob,
+		blob != NULL ? *p_blob_size : 0
+	);
+
+	if (blob != NULL) {
+		blob_size_max = *p_blob_size;
+	}
+	*p_blob_size = 0;
+
+	if (rv == CKR_OK) {
+		rv = _pkcs11h_session_getSessionByTokenId (
+			token_id,
+			&session
+		);
+	}
+
+#if defined(ENABLE_PKCS11H_THREADING)
+	if (
+		rv == CKR_OK &&
+		(rv = _pkcs11h_threading_mutexLock (&session->mutex)) == CKR_OK
+	) {
+		mutex_locked = TRUE;
+	}
+#endif
+
+	while (rv == CKR_OK && !op_succeed) {
+
+		if (rv == CKR_OK) {
+			rv = _pkcs11h_session_validate (session);
+		}
+
+		if (rv == CKR_OK) {
+			rv = _pkcs11h_data_getObject (
+				session,
+				application,
+				label,
+				&handle
+			);
+		}
+
+		if (rv == CKR_OK) {
+			rv = _pkcs11h_session_getObjectAttributes (
+				session,
+				handle,
+				attrs,
+				sizeof (attrs)/sizeof (CK_ATTRIBUTE)
+			);
+		}
+
+		if (rv == CKR_OK) {
+			op_succeed = TRUE;
+		}
+		else {
+			if (!login_retry) {
+				PKCS11H_DEBUG (
+					PKCS11H_LOG_DEBUG1,
+					"PKCS#11: Read data object failed rv=%ld-'%s'",
+					rv,
+					pkcs11h_getMessage (rv)
+				);
+				login_retry = TRUE;
+				rv = _pkcs11h_session_login (
+					session,
+					is_public,
+					TRUE,
+					user_data,
+					mask_prompt
+				);
+			}
+		}
+	}
+
+#if defined(ENABLE_PKCS11H_THREADING)
+	if (mutex_locked) {
+		_pkcs11h_threading_mutexRelease (&session->mutex);
+		mutex_locked = FALSE;
+	}
+#endif
+
+	if (rv == CKR_OK) {
+		*p_blob_size = attrs[0].ulValueLen;
+	}
+
+	if (rv == CKR_OK) {
+		if (blob != NULL) {
+			if (*p_blob_size > blob_size_max) {
+				rv = CKR_BUFFER_TOO_SMALL;
+			}
+			else {
+				memmove (blob, attrs[0].pValue, *p_blob_size);
+			}
+		}
+	}
+
+	_pkcs11h_session_freeObjectAttributes (
+		attrs,
+		sizeof (attrs)/sizeof (CK_ATTRIBUTE)
+	);
+
+	if (session != NULL) {
+		_pkcs11h_session_release (session);
+		session = NULL;
+	}
+
+	PKCS11H_DEBUG (
+		PKCS11H_LOG_DEBUG2,
+		"PKCS#11: pkcs11h_data_get return rv=%ld-'%s', *p_blob_size=%u",
+		rv,
+		pkcs11h_getMessage (rv),
+		*p_blob_size
+	);
+
+	return rv;
+}
+
+CK_RV
+pkcs11h_data_put (
+	IN const pkcs11h_token_id_t token_id,
+	IN const PKCS11H_BOOL is_public,
+	IN const char * const application,
+	IN const char * const label,
+	IN void * const user_data,
+	IN const unsigned mask_prompt,
+	OUT unsigned char * const blob,
+	IN const size_t blob_size
+) {
+	CK_OBJECT_CLASS class = CKO_DATA;
+	CK_BBOOL ck_true = CK_TRUE;
+	CK_BBOOL ck_false = CK_FALSE;
+
+	CK_ATTRIBUTE attrs[] = {
+		{CKA_CLASS, &class, sizeof (class)},
+		{CKA_TOKEN, &ck_true, sizeof (ck_true)},
+		{CKA_PRIVATE, is_public ? &ck_false : &ck_true, sizeof (CK_BBOOL)},
+		{CKA_APPLICATION, (void *)application, strlen (application)},
+		{CKA_LABEL, (void *)label, strlen (label)},
+		{CKA_VALUE, blob, blob_size}
+	};
+
+	CK_OBJECT_HANDLE handle = PKCS11H_INVALID_OBJECT_HANDLE;
+	CK_RV rv = CKR_OK;
+
+#if defined(ENABLE_PKCS11H_THREADING)
+	PKCS11H_BOOL mutex_locked = FALSE;
+#endif
+	pkcs11h_session_t session = NULL;
+	PKCS11H_BOOL op_succeed = FALSE;
+	PKCS11H_BOOL login_retry = FALSE;
+
+	PKCS11H_ASSERT (g_pkcs11h_data!=NULL);
+	PKCS11H_ASSERT (g_pkcs11h_data->initialized);
+	PKCS11H_ASSERT (token_id!=NULL);
+	PKCS11H_ASSERT (application!=NULL);
+	PKCS11H_ASSERT (label!=NULL);
+	/*PKCS11H_ASSERT (user_data) NOT NEEDED */
+	PKCS11H_ASSERT (blob!=NULL);
+
+	PKCS11H_DEBUG (
+		PKCS11H_LOG_DEBUG2,
+		"PKCS#11: pkcs11h_data_put entry token_id=%p, application='%s', label='%s', user_data=%p, mask_prompt=%08x, blob=%p, blob_size=%u",
+		(void *)token_id,
+		application,
+		label,
+		user_data,
+		mask_prompt,
+		blob,
+		blob != NULL ? blob_size : 0
+	);
+
+	if (rv == CKR_OK) {
+		rv = _pkcs11h_session_getSessionByTokenId (
+			token_id,
+			&session
+		);
+	}
+
+#if defined(ENABLE_PKCS11H_THREADING)
+	if (
+		rv == CKR_OK &&
+		(rv = _pkcs11h_threading_mutexLock (&session->mutex)) == CKR_OK
+	) {
+		mutex_locked = TRUE;
+	}
+#endif
+
+	while (rv == CKR_OK && !op_succeed) {
+
+		if (rv == CKR_OK) {
+			rv = _pkcs11h_session_validate (session);
+		}
+
+		if (rv == CKR_OK) {
+			rv = session->provider->f->C_CreateObject (
+				session->session_handle,
+				attrs,
+				sizeof (attrs)/sizeof (CK_ATTRIBUTE),
+				&handle
+			);
+		}
+
+		if (rv == CKR_OK) {
+			op_succeed = TRUE;
+		}
+		else {
+			if (!login_retry) {
+				PKCS11H_DEBUG (
+					PKCS11H_LOG_DEBUG1,
+					"PKCS#11: Write data object failed rv=%ld-'%s'",
+					rv,
+					pkcs11h_getMessage (rv)
+				);
+				login_retry = TRUE;
+				rv = _pkcs11h_session_login (
+					session,
+					is_public,
+					FALSE,
+					user_data,
+					mask_prompt
+				);
+			}
+		}
+	}
+
+#if defined(ENABLE_PKCS11H_THREADING)
+	if (mutex_locked) {
+		_pkcs11h_threading_mutexRelease (&session->mutex);
+		mutex_locked = FALSE;
+	}
+#endif
+
+	if (session != NULL) {
+		_pkcs11h_session_release (session);
+		session = NULL;
+	}
+
+	PKCS11H_DEBUG (
+		PKCS11H_LOG_DEBUG2,
+		"PKCS#11: pkcs11h_data_put return rv=%ld-'%s'",
+		rv,
+		pkcs11h_getMessage (rv)
+	);
+
+	return rv;
+}
+
+CK_RV
+pkcs11h_data_del (
+	IN const pkcs11h_token_id_t token_id,
+	IN const PKCS11H_BOOL is_public,
+	IN const char * const application,
+	IN const char * const label,
+	IN void * const user_data,
+	IN const unsigned mask_prompt
+) {
+#if defined(ENABLE_PKCS11H_THREADING)
+	PKCS11H_BOOL mutex_locked = FALSE;
+#endif
+	pkcs11h_session_t session = NULL;
+	PKCS11H_BOOL op_succeed = FALSE;
+	PKCS11H_BOOL login_retry = FALSE;
+	CK_OBJECT_HANDLE handle = PKCS11H_INVALID_OBJECT_HANDLE;
+	CK_RV rv = CKR_OK;
+
+	PKCS11H_ASSERT (g_pkcs11h_data!=NULL);
+	PKCS11H_ASSERT (g_pkcs11h_data->initialized);
+	PKCS11H_ASSERT (token_id!=NULL);
+	PKCS11H_ASSERT (application!=NULL);
+	PKCS11H_ASSERT (label!=NULL);
+	/*PKCS11H_ASSERT (user_data) NOT NEEDED */
+
+	PKCS11H_DEBUG (
+		PKCS11H_LOG_DEBUG2,
+		"PKCS#11: pkcs11h_data_del entry token_id=%p, application='%s', label='%s', user_data=%p, mask_prompt=%08x",
+		(void *)token_id,
+		application,
+		label,
+		user_data,
+		mask_prompt
+	);
+
+	if (rv == CKR_OK) {
+		rv = _pkcs11h_session_getSessionByTokenId (
+			token_id,
+			&session
+		);
+	}
+
+#if defined(ENABLE_PKCS11H_THREADING)
+	if (
+		rv == CKR_OK &&
+		(rv = _pkcs11h_threading_mutexLock (&session->mutex)) == CKR_OK
+	) {
+		mutex_locked = TRUE;
+	}
+#endif
+
+	while (rv == CKR_OK && !op_succeed) {
+
+		if (rv == CKR_OK) {
+			rv = _pkcs11h_session_validate (session);
+		}
+
+		if (rv == CKR_OK) {
+			rv = _pkcs11h_data_getObject (
+				session,
+				application,
+				label,
+				&handle
+			);
+		}
+
+		if (rv == CKR_OK) {
+			rv = session->provider->f->C_DestroyObject (
+				session->session_handle,
+				handle
+			);
+		}
+
+		if (rv == CKR_OK) {
+			op_succeed = TRUE;
+		}
+		else {
+			if (!login_retry) {
+				PKCS11H_DEBUG (
+					PKCS11H_LOG_DEBUG1,
+					"PKCS#11: Remove data object failed rv=%ld-'%s'",
+					rv,
+					pkcs11h_getMessage (rv)
+				);
+				login_retry = TRUE;
+				rv = _pkcs11h_session_login (
+					session,
+					is_public,
+					FALSE,
+					user_data,
+					mask_prompt
+				);
+			}
+		}
+	}
+
+#if defined(ENABLE_PKCS11H_THREADING)
+		if (mutex_locked) {
+			_pkcs11h_threading_mutexRelease (&session->mutex);
+			mutex_locked = FALSE;
+		}
+#endif
+
+	if (session != NULL) {
+		_pkcs11h_session_release (session);
+		session = NULL;
+	}
+
+	PKCS11H_DEBUG (
+		PKCS11H_LOG_DEBUG2,
+		"PKCS#11: pkcs11h_data_del return rv=%ld-'%s'",
+		rv,
+		pkcs11h_getMessage (rv)
+	);
+
+	return rv;
+}
+
+CK_RV
+pkcs11h_data_freeDataIdList (
+	IN const pkcs11h_data_id_list_t data_id_list
+) {
+	pkcs11h_data_id_list_t _id = data_id_list;
+
+	PKCS11H_ASSERT (g_pkcs11h_data!=NULL);
+	PKCS11H_ASSERT (g_pkcs11h_data->initialized);
+	/*PKCS11H_ASSERT (data_id_list!=NULL); NOT NEEDED*/
+
+	PKCS11H_DEBUG (
+		PKCS11H_LOG_DEBUG2,
+		"PKCS#11: pkcs11h_freeDataIdList entry token_id_list=%p",
+		(void *)data_id_list
+	);
+
+	while (_id != NULL) {
+		pkcs11h_data_id_list_t x = _id;
+		_id = _id->next;
+
+		if (x->application != NULL) {
+			_pkcs11h_mem_free ((void *)&x->application);
+		}
+		if (x->label != NULL) {
+			_pkcs11h_mem_free ((void *)&x->label);
+		}
+		_pkcs11h_mem_free ((void *)&x);
+	}
+
+	PKCS11H_DEBUG (
+		PKCS11H_LOG_DEBUG2,
+		"PKCS#11: pkcs11h_token_freeDataIdList return"
+	);
+
+	return CKR_OK;
+}
+
+CK_RV
+pkcs11h_data_enumDataObjects (
+	IN const pkcs11h_token_id_t token_id,
+	IN const PKCS11H_BOOL is_public,
+	IN void * const user_data,
+	IN const unsigned mask_prompt,
+	OUT pkcs11h_data_id_list_t * const p_data_id_list
+) {
+#if defined(ENABLE_PKCS11H_THREADING)
+	PKCS11H_BOOL mutex_locked = FALSE;
+#endif
+	pkcs11h_session_t session = NULL;
+	pkcs11h_data_id_list_t data_id_list = NULL;
+	CK_RV rv = CKR_OK;
+
+	PKCS11H_BOOL op_succeed = FALSE;
+	PKCS11H_BOOL login_retry = FALSE;
+
+	PKCS11H_ASSERT (g_pkcs11h_data!=NULL);
+	PKCS11H_ASSERT (g_pkcs11h_data->initialized);
+	PKCS11H_ASSERT (p_data_id_list!=NULL);
+
+	PKCS11H_DEBUG (
+		PKCS11H_LOG_DEBUG2,
+		"PKCS#11: pkcs11h_data_enumDataObjects entry token_id=%p, is_public=%d, user_data=%p, mask_prompt=%08x, p_data_id_list=%p",
+		(void *)token_id,
+		is_public ? 1 : 0,
+		user_data,
+		mask_prompt,
+		(void *)p_data_id_list
+	);
+
+	*p_data_id_list = NULL;
+
+	if (rv == CKR_OK) {
+		rv = _pkcs11h_session_getSessionByTokenId (
+			token_id,
+			&session
+		);
+	}
+
+#if defined(ENABLE_PKCS11H_THREADING)
+	if (
+		rv == CKR_OK &&
+		(rv = _pkcs11h_threading_mutexLock (&session->mutex)) == CKR_OK
+	) {
+		mutex_locked = TRUE;
+	}
+#endif
+
+	while (rv == CKR_OK && !op_succeed) {
+
+		CK_OBJECT_CLASS class = CKO_DATA;
+		CK_ATTRIBUTE filter[] = {
+			{CKA_CLASS, (void *)&class, sizeof (class)}
+		};
+		CK_OBJECT_HANDLE *objects = NULL;
+		CK_ULONG objects_found = 0;
+
+		CK_ULONG i;
+
+		if (rv == CKR_OK) {
+			rv = _pkcs11h_session_validate (session);
+		}
+
+		if (rv == CKR_OK) {
+			rv = _pkcs11h_session_findObjects (
+				session,
+				filter,
+				sizeof (filter) / sizeof (CK_ATTRIBUTE),
+				&objects,
+				&objects_found
+			);
+		}
+
+		for (i = 0;rv == CKR_OK && i < objects_found;i++) {
+			pkcs11h_data_id_list_t entry = NULL;
+
+			CK_ATTRIBUTE attrs[] = {
+				{CKA_APPLICATION, NULL, 0},
+				{CKA_LABEL, NULL, 0}
+			};
+
+			if (rv == CKR_OK) {
+				rv = _pkcs11h_session_getObjectAttributes (
+					session,
+					objects[i],
+					attrs,
+					sizeof (attrs) / sizeof (CK_ATTRIBUTE)
+				);
+			}
+			
+			if (rv == CKR_OK) {
+				rv = _pkcs11h_mem_malloc (
+					(void *)&entry,
+					sizeof (struct pkcs11h_data_id_list_s)
+				);
+			}
+
+			if (
+				rv == CKR_OK &&
+				(rv = _pkcs11h_mem_malloc (
+					(void *)&entry->application,
+					attrs[0].ulValueLen+1
+				)) == CKR_OK
+			) {
+				memmove (entry->application, attrs[0].pValue, attrs[0].ulValueLen);
+				entry->application[attrs[0].ulValueLen] = '\0';
+			}
+
+			if (
+				rv == CKR_OK &&
+				(rv = _pkcs11h_mem_malloc (
+					(void *)&entry->label,
+					attrs[1].ulValueLen+1
+				)) == CKR_OK
+			) {
+				memmove (entry->label, attrs[1].pValue, attrs[1].ulValueLen);
+				entry->label[attrs[1].ulValueLen] = '\0';
+			}
+
+			if (rv == CKR_OK) {
+				entry->next = data_id_list;
+				data_id_list = entry;
+				entry = NULL;
+			}
+
+			_pkcs11h_session_freeObjectAttributes (
+				attrs,
+				sizeof (attrs) / sizeof (CK_ATTRIBUTE)
+			);
+
+			if (entry != NULL) {
+				if (entry->application != NULL) {
+					_pkcs11h_mem_free ((void *)&entry->application);
+				}
+				if (entry->label != NULL) {
+					_pkcs11h_mem_free ((void *)&entry->label);
+				}
+				_pkcs11h_mem_free ((void *)&entry);
+			}
+		}
+
+		if (objects != NULL) {
+			_pkcs11h_mem_free ((void *)&objects);
+		}
+
+		if (rv == CKR_OK) {
+			op_succeed = TRUE;
+		}
+		else {
+			if (!login_retry) {
+				PKCS11H_DEBUG (
+					PKCS11H_LOG_DEBUG1,
+					"PKCS#11: Enumerate data objects failed rv=%ld-'%s'",
+					rv,
+					pkcs11h_getMessage (rv)
+				);
+				login_retry = TRUE;
+				rv = _pkcs11h_session_login (
+					session,
+					is_public,
+					TRUE,
+					user_data,
+					mask_prompt
+				);
+			}
+		}
+	}
+
+#if defined(ENABLE_PKCS11H_THREADING)
+	if (mutex_locked) {
+		_pkcs11h_threading_mutexRelease (&session->mutex);
+		mutex_locked = FALSE;
+	}
+#endif
+
+	if (rv == CKR_OK) {
+		*p_data_id_list = data_id_list;
+		data_id_list = NULL;
+	}
+
+	if (session != NULL) {
+		_pkcs11h_session_release (session);
+		session = NULL;
+	}
+
+	if (data_id_list != NULL) {
+		pkcs11h_data_freeDataIdList (data_id_list);
+		data_id_list = NULL;
+	}
+
+	PKCS11H_DEBUG (
+		PKCS11H_LOG_DEBUG2,
+		"PKCS#11: pkcs11h_data_enumDataObjects return rv=%ld-'%s', *p_data_id_list=%p",
+		rv,
+		pkcs11h_getMessage (rv),
+		(void *)*p_data_id_list
+	);
+	
+	return rv;
+}
+
+#endif				/* ENABLE_PKCS11H_DATA */
diff --git a/lib/pkcs11h-locate.c b/lib/pkcs11h-locate.c
new file mode 100644
index 0000000..3746d68
--- /dev/null
+++ b/lib/pkcs11h-locate.c
@@ -0,0 +1,1163 @@
+/*
+ * Copyright (c) 2005-2006 Alon Bar-Lev <alon.barlev at gmail.com>
+ * All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, or the OpenIB.org BSD license.
+ *
+ * GNU General Public License (GPL) Version 2
+ * ===========================================
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2
+ *  as published by the Free Software Foundation.
+ *
+ *  This program 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 General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program (see the file COPYING[.GPL2] included with this
+ *  distribution); if not, write to the Free Software Foundation, Inc.,
+ *  59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * OpenIB.org BSD license
+ * =======================
+ * Redistribution and use in source and binary forms, with or without modifi-
+ * cation, are permitted provided that the following conditions are met:
+ *
+ *   o  Redistributions of source code must retain the above copyright notice,
+ *      this list of conditions and the following disclaimer.
+ *
+ *   o  Redistributions in binary form must reproduce the above copyright no-
+ *      tice, this list of conditions and the following disclaimer in the do-
+ *      cumentation and/or other materials provided with the distribution.
+ *
+ *   o  The names of the contributors may not be used to endorse or promote
+ *      products derived from this software without specific prior written
+ *      permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``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 REGENTS OR CONTRIBUTORS BE LI-
+ * ABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUEN-
+ * TIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEV-
+ * ER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABI-
+ * LITY, 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.
+ */
+
+#include "common.h"
+
+#if defined(ENABLE_PKCS11H_LOCATE)
+
+#include <pkcs11-helper-1.0/pkcs11h-token.h>
+#include <pkcs11-helper-1.0/pkcs11h-locate.h>
+#include "_pkcs11h-mem.h"
+#include "_pkcs11h-crypto.h"
+#include "_pkcs11h-util.h"
+#include "_pkcs11h-session.h"
+#include "_pkcs11h-token.h"
+#include "_pkcs11h-certificate.h"
+
+static
+CK_RV
+_pkcs11h_locate_getTokenIdBySlotId (
+	IN const char * const slot,
+	OUT pkcs11h_token_id_t * const p_token_id
+);
+
+static
+CK_RV
+_pkcs11h_locate_getTokenIdBySlotName (
+	IN const char * const name,
+	OUT pkcs11h_token_id_t * const p_token_id
+);
+
+static
+CK_RV
+_pkcs11h_locate_getTokenIdByLabel (
+	IN const char * const label,
+	OUT pkcs11h_token_id_t * const p_token_id
+);
+
+#if defined(ENABLE_PKCS11H_CERTIFICATE)
+
+static
+CK_RV
+_pkcs11h_locate_getCertificateIdByLabel (
+	IN const pkcs11h_session_t session,
+	IN OUT const pkcs11h_certificate_id_t certificate_id,
+	IN const char * const label
+);
+static
+CK_RV
+_pkcs11h_locate_getCertificateIdBySubject (
+	IN const pkcs11h_session_t session,
+	IN OUT const pkcs11h_certificate_id_t certificate_id,
+	IN const char * const subject
+);
+
+#endif				/* ENABLE_PKCS11H_CERTIFICATE */
+#if defined(ENABLE_PKCS11H_TOKEN) || defined(ENABLE_PKCS11H_CERTIFICATE)
+
+static
+CK_RV
+_pkcs11h_locate_getTokenIdBySlotId (
+	IN const char * const slot,
+	OUT pkcs11h_token_id_t * const p_token_id
+) {
+	pkcs11h_provider_t current_provider = NULL;
+	char reference[sizeof (((pkcs11h_provider_t)NULL)->reference)];
+
+	CK_SLOT_ID selected_slot = PKCS11H_INVALID_SLOT_ID;
+	CK_TOKEN_INFO info;
+	CK_RV rv = CKR_OK;
+
+	PKCS11H_ASSERT (slot!=NULL);
+	PKCS11H_ASSERT (p_token_id!=NULL);
+
+	PKCS11H_DEBUG (
+		PKCS11H_LOG_DEBUG2,
+		"PKCS#11: _pkcs11h_locate_getTokenIdBySlotId entry slot='%s', p_token_id=%p",
+		slot,
+		(void *)p_token_id
+	);
+
+	*p_token_id = NULL;
+
+	if (rv == CKR_OK) {
+		if (strchr (slot, ':') == NULL) {
+			reference[0] = '\0';
+			selected_slot = atol (slot);
+		}
+		else {
+			char *p;
+
+			strncpy (reference, slot, sizeof (reference));
+			reference[sizeof (reference)-1] = '\0';
+
+			p = strchr (reference, ':');
+
+			*p = '\0';
+			p++;
+			selected_slot = atol (p);
+		}
+	}
+	
+	if (rv == CKR_OK) {
+		current_provider=g_pkcs11h_data->providers;
+		while (
+			current_provider != NULL &&
+			reference[0] != '\0' &&		/* So first provider will be selected */
+			strcmp (current_provider->reference, reference)
+		) {
+			current_provider = current_provider->next;
+		}
+	
+		if (
+			current_provider == NULL ||
+			(
+				current_provider != NULL &&
+				!current_provider->enabled
+			)
+		) {
+			rv = CKR_SLOT_ID_INVALID;
+		}
+	}
+
+	if (
+		rv == CKR_OK &&
+		(rv = current_provider->f->C_GetTokenInfo (selected_slot, &info)) == CKR_OK
+	) {
+		rv = _pkcs11h_token_getTokenId (
+			&info,
+			p_token_id
+		);
+	}
+
+	PKCS11H_DEBUG (
+		PKCS11H_LOG_DEBUG2,
+		"PKCS#11: _pkcs11h_locate_getTokenIdBySlotId return rv=%ld-'%s', *p_token_id=%p",
+		rv,
+		pkcs11h_getMessage (rv),
+		(void *)*p_token_id
+	);
+
+	return rv;
+}
+
+static
+CK_RV
+_pkcs11h_locate_getTokenIdBySlotName (
+	IN const char * const name,
+	OUT pkcs11h_token_id_t * const p_token_id
+) {
+	pkcs11h_provider_t current_provider = NULL;
+
+	CK_SLOT_ID selected_slot = PKCS11H_INVALID_SLOT_ID;
+	CK_TOKEN_INFO info;
+	CK_RV rv = CKR_OK;
+
+	PKCS11H_BOOL found = FALSE;
+
+	PKCS11H_ASSERT (name!=NULL);
+	PKCS11H_ASSERT (p_token_id!=NULL);
+
+	PKCS11H_DEBUG (
+		PKCS11H_LOG_DEBUG2,
+		"PKCS#11: _pkcs11h_locate_getTokenIdBySlotName entry name='%s', p_token_id=%p",
+		name,
+		(void *)p_token_id
+	);
+
+	*p_token_id = NULL;
+
+	current_provider = g_pkcs11h_data->providers;
+	while (
+		current_provider != NULL &&
+		rv == CKR_OK &&
+		!found
+	) {
+		CK_SLOT_ID_PTR slots = NULL;
+		CK_ULONG slotnum;
+		CK_SLOT_ID slot_index;
+
+		if (!current_provider->enabled) {
+			rv = CKR_CRYPTOKI_NOT_INITIALIZED;
+		}
+
+		if (rv == CKR_OK) {
+			rv = _pkcs11h_session_getSlotList (
+				current_provider,
+				CK_TRUE,
+				&slots,
+				&slotnum
+			);
+		}
+
+		for (
+			slot_index=0;
+			(
+				slot_index < slotnum &&
+				rv == CKR_OK &&
+				!found
+			);
+			slot_index++
+		) {
+			CK_SLOT_INFO info;
+
+			if (
+				(rv = current_provider->f->C_GetSlotInfo (
+					slots[slot_index],
+					&info
+				)) == CKR_OK
+			) {
+				char current_name[sizeof (info.slotDescription)+1];
+
+				_pkcs11h_util_fixupFixedString (
+					current_name,
+					(char *)info.slotDescription,
+					sizeof (info.slotDescription)
+				);
+
+				if (!strcmp (current_name, name)) {
+					found = TRUE;
+					selected_slot = slots[slot_index];
+				}
+			}
+
+			if (rv != CKR_OK) {
+				PKCS11H_DEBUG (
+					PKCS11H_LOG_DEBUG1,
+					"PKCS#11: Cannot get slot information for provider '%s' slot %ld rv=%ld-'%s'",
+					current_provider->manufacturerID,
+					slots[slot_index],
+					rv,
+					pkcs11h_getMessage (rv)
+				);
+
+				/*
+				 * Ignore error
+				 */
+				rv = CKR_OK;
+			}
+		}
+
+		if (rv != CKR_OK) {
+			PKCS11H_DEBUG (
+				PKCS11H_LOG_DEBUG1,
+				"PKCS#11: Cannot get slot list for provider '%s' rv=%ld-'%s'",
+				current_provider->manufacturerID,
+				rv,
+				pkcs11h_getMessage (rv)
+			);
+
+			/*
+			 * Ignore error
+			 */
+			rv = CKR_OK;
+		}
+
+		if (slots != NULL) {
+			_pkcs11h_mem_free ((void *)&slots);
+			slots = NULL;
+		}
+
+		if (!found) {
+			current_provider = current_provider->next;
+		}
+	}
+
+	if (rv == CKR_OK && !found) {
+		rv = CKR_SLOT_ID_INVALID;
+	}
+
+	if (
+		rv == CKR_OK &&
+		(rv = current_provider->f->C_GetTokenInfo (selected_slot, &info)) == CKR_OK
+	) {
+		rv = _pkcs11h_token_getTokenId (
+			&info,
+			p_token_id
+		);
+	}
+
+	PKCS11H_DEBUG (
+		PKCS11H_LOG_DEBUG2,
+		"PKCS#11: _pkcs11h_locate_getTokenIdBySlotName return rv=%ld-'%s' *p_token_id=%p",
+		rv,
+		pkcs11h_getMessage (rv),
+		(void *)*p_token_id
+	);
+
+	return rv; 
+}
+
+static
+CK_RV
+_pkcs11h_locate_getTokenIdByLabel (
+	IN const char * const label,
+	OUT pkcs11h_token_id_t * const p_token_id
+) {
+	pkcs11h_provider_t current_provider = NULL;
+
+	CK_SLOT_ID selected_slot = PKCS11H_INVALID_SLOT_ID;
+	CK_TOKEN_INFO info;
+	CK_RV rv = CKR_OK;
+
+	PKCS11H_BOOL found = FALSE;
+
+	PKCS11H_ASSERT (label!=NULL);
+	PKCS11H_ASSERT (p_token_id!=NULL);
+
+	PKCS11H_DEBUG (
+		PKCS11H_LOG_DEBUG2,
+		"PKCS#11: _pkcs11h_locate_getTokenIdByLabel entry label='%s', p_token_id=%p",
+		label,
+		(void *)p_token_id
+	);
+
+	*p_token_id = NULL;
+
+	current_provider = g_pkcs11h_data->providers;
+	while (
+		current_provider != NULL &&
+		rv == CKR_OK &&
+		!found
+	) {
+		CK_SLOT_ID_PTR slots = NULL;
+		CK_ULONG slotnum;
+		CK_SLOT_ID slot_index;
+
+		if (!current_provider->enabled) {
+			rv = CKR_CRYPTOKI_NOT_INITIALIZED;
+		}
+
+		if (rv == CKR_OK) {
+			rv = _pkcs11h_session_getSlotList (
+				current_provider,
+				CK_TRUE,
+				&slots,
+				&slotnum
+			);
+		}
+
+		for (
+			slot_index=0;
+			(
+				slot_index < slotnum &&
+				rv == CKR_OK &&
+				!found
+			);
+			slot_index++
+		) {
+			CK_TOKEN_INFO info;
+
+			if (rv == CKR_OK) {
+				rv = current_provider->f->C_GetTokenInfo (
+					slots[slot_index],
+					&info
+				);
+			}
+
+			if (rv == CKR_OK) {
+				char current_label[sizeof (info.label)+1];
+		
+				_pkcs11h_util_fixupFixedString (
+					current_label,
+					(char *)info.label,
+					sizeof (info.label)
+				);
+
+				if (!strcmp (current_label, label)) {
+					found = TRUE;
+					selected_slot = slots[slot_index];
+				}
+			}
+
+			if (rv != CKR_OK) {
+				PKCS11H_DEBUG (
+					PKCS11H_LOG_DEBUG1,
+					"PKCS#11: Cannot get token information for provider '%s' slot %ld rv=%ld-'%s'",
+					current_provider->manufacturerID,
+					slots[slot_index],
+					rv,
+					pkcs11h_getMessage (rv)
+				);
+
+				/*
+				 * Ignore error
+				 */
+				rv = CKR_OK;
+			}
+		}
+
+		if (rv != CKR_OK) {
+			PKCS11H_DEBUG (
+				PKCS11H_LOG_DEBUG1,
+				"PKCS#11: Cannot get slot list for provider '%s' rv=%ld-'%s'",
+				current_provider->manufacturerID,
+				rv,
+				pkcs11h_getMessage (rv)
+			);
+
+			/*
+			 * Ignore error
+			 */
+			rv = CKR_OK;
+		}
+
+		if (slots != NULL) {
+			_pkcs11h_mem_free ((void *)&slots);
+			slots = NULL;
+		}
+
+		if (!found) {
+			current_provider = current_provider->next;
+		}
+	}
+
+	if (rv == CKR_OK && !found) {
+		rv = CKR_SLOT_ID_INVALID;
+	}
+
+	if (
+		rv == CKR_OK &&
+		(rv = current_provider->f->C_GetTokenInfo (selected_slot, &info)) == CKR_OK
+	) {
+		rv = _pkcs11h_token_getTokenId (
+			&info,
+			p_token_id
+		);
+	}
+
+	PKCS11H_DEBUG (
+		PKCS11H_LOG_DEBUG2,
+		"PKCS#11: _pkcs11h_locate_getTokenIdByLabel return rv=%ld-'%s', *p_token_id=%p",
+		rv,
+		pkcs11h_getMessage (rv),
+		(void *)*p_token_id
+	);
+
+	return rv;
+}
+
+CK_RV
+pkcs11h_locate_token (
+	IN const char * const slot_type,
+	IN const char * const slot,
+	IN void * const user_data,
+	IN const unsigned mask_prompt,
+	OUT pkcs11h_token_id_t * const p_token_id
+) {
+#if defined(ENABLE_PKCS11H_THREADING)
+	PKCS11H_BOOL mutex_locked = FALSE;
+#endif
+
+	pkcs11h_token_id_t dummy_token_id = NULL;
+	pkcs11h_token_id_t token_id = NULL;
+	PKCS11H_BOOL found = FALSE;
+	
+	CK_RV rv = CKR_OK;
+
+	unsigned nRetry = 0;
+
+	PKCS11H_ASSERT (g_pkcs11h_data!=NULL);
+	PKCS11H_ASSERT (g_pkcs11h_data->initialized);
+	PKCS11H_ASSERT (slot_type!=NULL);
+	PKCS11H_ASSERT (slot!=NULL);
+	/*PKCS11H_ASSERT (user_data) NOT NEEDED */
+	PKCS11H_ASSERT (p_token_id!=NULL);
+
+	PKCS11H_DEBUG (
+		PKCS11H_LOG_DEBUG2,
+		"PKCS#11: pkcs11h_locate_token entry slot_type='%s', slot='%s', user_data=%p, p_token_id=%p",
+		slot_type,
+		slot,
+		user_data,
+		(void *)p_token_id
+	);
+
+	*p_token_id = NULL;
+
+#if defined(ENABLE_PKCS11H_THREADING)
+	if (
+		rv == CKR_OK &&
+		(rv = _pkcs11h_threading_mutexLock (&g_pkcs11h_data->mutexes.global)) == CKR_OK
+	) {
+		mutex_locked = TRUE;
+	}
+#endif
+
+	if (
+		rv == CKR_OK &&
+		(rv = _pkcs11h_token_newTokenId (&dummy_token_id)) == CKR_OK
+	) {
+		/*
+		 * Temperary slot id
+		 */
+		strcpy (dummy_token_id->display, "SLOT(");
+		strncat (dummy_token_id->display, slot_type, sizeof (dummy_token_id->display)-1-strlen (dummy_token_id->display));
+		strncat (dummy_token_id->display, "=", sizeof (dummy_token_id->display)-1-strlen (dummy_token_id->display));
+		strncat (dummy_token_id->display, slot, sizeof (dummy_token_id->display)-1-strlen (dummy_token_id->display));
+		strncat (dummy_token_id->display, ")", sizeof (dummy_token_id->display)-1-strlen (dummy_token_id->display));
+		dummy_token_id->display[sizeof (dummy_token_id->display)-1] = 0;
+	}
+
+	while (rv == CKR_OK && !found) {
+		if (!strcmp (slot_type, "id")) {
+			rv = _pkcs11h_locate_getTokenIdBySlotId (
+				slot,
+				&token_id
+			);
+		}
+		else if (!strcmp (slot_type, "name")) {
+			rv = _pkcs11h_locate_getTokenIdBySlotName (
+				slot,
+				&token_id
+			);
+		}
+		else if (!strcmp (slot_type, "label")) {
+			rv = _pkcs11h_locate_getTokenIdByLabel (
+				slot,
+				&token_id
+			);
+		}
+		else {
+			rv = CKR_ARGUMENTS_BAD;
+		}
+
+		if (rv == CKR_OK) {
+			found = TRUE;
+		}
+
+		/*
+		 * Ignore error, since we have what we
+		 * want in found.
+		 */
+		if (rv != CKR_OK && rv != CKR_ARGUMENTS_BAD) {
+			PKCS11H_DEBUG (
+				PKCS11H_LOG_DEBUG1,
+				"PKCS#11: pkcs11h_locate_token failed rv=%ld-'%s'",
+				rv,
+				pkcs11h_getMessage (rv)
+			);
+
+			rv = CKR_OK;
+		}
+
+		if (rv == CKR_OK && !found && (mask_prompt & PKCS11H_PROMPT_MASK_ALLOW_TOKEN_PROMPT) == 0) {
+			rv = CKR_TOKEN_NOT_PRESENT;
+		}
+
+		if (rv == CKR_OK && !found) {
+
+			PKCS11H_DEBUG (
+				PKCS11H_LOG_DEBUG1,
+				"PKCS#11: Calling token_prompt hook for '%s'",
+				dummy_token_id->display
+			);
+	
+			if (
+				!g_pkcs11h_data->hooks.token_prompt (
+					g_pkcs11h_data->hooks.token_prompt_data,
+					user_data,
+					dummy_token_id,
+					nRetry++
+				)
+			) {
+				rv = CKR_CANCEL;
+			}
+
+			PKCS11H_DEBUG (
+				PKCS11H_LOG_DEBUG1,
+				"PKCS#11: token_prompt returned %ld",
+				rv
+			);
+		}
+	}
+
+	if (rv == CKR_OK && !found) {
+		rv = CKR_SLOT_ID_INVALID;
+	}
+
+	if (rv == CKR_OK) {
+		*p_token_id = token_id;
+		token_id = NULL;
+	}
+
+	if (dummy_token_id != NULL) {
+		pkcs11h_token_freeTokenId (dummy_token_id);
+		dummy_token_id = NULL;
+	}
+
+#if defined(ENABLE_PKCS11H_THREADING)
+	if (mutex_locked) {
+		_pkcs11h_threading_mutexRelease (&g_pkcs11h_data->mutexes.global);
+		mutex_locked = FALSE;
+	}
+#endif
+
+	PKCS11H_DEBUG (
+		PKCS11H_LOG_DEBUG2,
+		"PKCS#11: pkcs11h_locate_token return rv=%ld-'%s', *p_token_id=%p",
+		rv,
+		pkcs11h_getMessage (rv),
+		(void *)*p_token_id
+	);
+
+	return rv;
+}
+
+#endif				/* ENABLE_PKCS11H_TOKEN || ENABLE_PKCS11H_CERTIFICATE */
+
+#if defined(ENABLE_PKCS11H_CERTIFICATE)
+
+static
+CK_RV
+_pkcs11h_locate_getCertificateIdByLabel (
+	IN const pkcs11h_session_t session,
+	IN OUT const pkcs11h_certificate_id_t certificate_id,
+	IN const char * const label
+) {
+#if defined(ENABLE_PKCS11H_THREADING)
+	PKCS11H_BOOL mutex_locked = FALSE;
+#endif
+	CK_OBJECT_CLASS cert_filter_class = CKO_CERTIFICATE;
+	CK_ATTRIBUTE cert_filter[] = {
+		{CKA_CLASS, &cert_filter_class, sizeof (cert_filter_class)},
+		{CKA_LABEL, (CK_BYTE_PTR)label, strlen (label)}
+	};
+
+	CK_OBJECT_HANDLE *objects = NULL;
+	CK_ULONG objects_found = 0;
+	CK_RV rv = CKR_OK;
+
+	CK_ULONG i;
+
+	PKCS11H_ASSERT (session!=NULL);
+	PKCS11H_ASSERT (certificate_id!=NULL);
+	PKCS11H_ASSERT (label!=NULL);
+
+	PKCS11H_DEBUG (
+		PKCS11H_LOG_DEBUG2,
+		"PKCS#11: _pkcs11h_locate_getCertificateIdByLabel entry session=%p, certificate_id=%p, label='%s'",
+		(void *)session,
+		(void *)certificate_id,
+		label
+	);
+
+#if defined(ENABLE_PKCS11H_THREADING)
+	if (
+		rv == CKR_OK &&
+		(rv = _pkcs11h_threading_mutexLock (&session->mutex)) == CKR_OK
+	) {
+		mutex_locked = TRUE;
+	}
+#endif
+
+	if (rv == CKR_OK) {
+		rv = _pkcs11h_session_validate (session);
+	}
+
+	if (rv == CKR_OK) {
+		rv = _pkcs11h_session_findObjects (
+			session,
+			cert_filter,
+			sizeof (cert_filter) / sizeof (CK_ATTRIBUTE),
+			&objects,
+			&objects_found
+		);
+	}
+
+	for (i=0;rv == CKR_OK && i < objects_found;i++) {
+		CK_ATTRIBUTE attrs[] = {
+			{CKA_ID, NULL, 0},
+			{CKA_VALUE, NULL, 0}
+		};
+
+		if (rv == CKR_OK) {
+			rv = _pkcs11h_session_getObjectAttributes (
+				session,
+				objects[i],
+				attrs,
+				sizeof (attrs) / sizeof (CK_ATTRIBUTE)
+			);
+		}
+
+		if (
+			rv == CKR_OK &&
+			_pkcs11h_certificate_isBetterCertificate (
+				certificate_id->certificate_blob,
+				certificate_id->certificate_blob_size,
+				attrs[1].pValue,
+				attrs[1].ulValueLen
+			)
+		) {
+			if (certificate_id->attrCKA_ID != NULL) {
+				_pkcs11h_mem_free ((void *)&certificate_id->attrCKA_ID);
+			}
+			if (certificate_id->certificate_blob != NULL) {
+				_pkcs11h_mem_free ((void *)&certificate_id->certificate_blob);
+			}
+			rv = _pkcs11h_mem_duplicate (
+				(void *)&certificate_id->attrCKA_ID,
+				&certificate_id->attrCKA_ID_size,
+				attrs[0].pValue,
+				attrs[0].ulValueLen
+			);
+			rv = _pkcs11h_mem_duplicate (
+				(void *)&certificate_id->certificate_blob,
+				&certificate_id->certificate_blob_size,
+				attrs[1].pValue,
+				attrs[1].ulValueLen
+			);
+		}
+
+		if (rv != CKR_OK) {
+			PKCS11H_DEBUG (
+				PKCS11H_LOG_DEBUG1,
+				"PKCS#11: Cannot get object attribute for provider '%s' object %ld rv=%ld-'%s'",
+				session->provider->manufacturerID,
+				objects[i],
+				rv,
+				pkcs11h_getMessage (rv)
+			);
+
+			/*
+			 * Ignore error
+			 */
+			rv = CKR_OK;
+		}
+
+		_pkcs11h_session_freeObjectAttributes (
+			attrs,
+			sizeof (attrs) / sizeof (CK_ATTRIBUTE)
+		);
+	}
+	
+	if (
+		rv == CKR_OK &&
+		certificate_id->certificate_blob == NULL
+	) {
+		rv = CKR_ATTRIBUTE_VALUE_INVALID;
+	}
+
+	if (objects != NULL) {
+		_pkcs11h_mem_free ((void *)&objects);
+	}
+
+#if defined(ENABLE_PKCS11H_THREADING)
+	if (mutex_locked) {
+		_pkcs11h_threading_mutexRelease (&session->mutex);
+		mutex_locked = FALSE;
+	}
+#endif
+
+	/*
+	 * No need to free allocated objects
+	 * on error, since the certificate_id
+	 * should be free by caller.
+	 */
+
+	PKCS11H_DEBUG (
+		PKCS11H_LOG_DEBUG2,
+		"PKCS#11: _pkcs11h_locate_getCertificateIdByLabel return rv=%ld-'%s'",
+		rv,
+		pkcs11h_getMessage (rv)
+	);
+
+	return rv;
+}
+
+static
+CK_RV
+_pkcs11h_locate_getCertificateIdBySubject (
+	IN const pkcs11h_session_t session,
+	IN OUT const pkcs11h_certificate_id_t certificate_id,
+	IN const char * const subject
+) {
+#if defined(ENABLE_PKCS11H_THREADING)
+	PKCS11H_BOOL mutex_locked = FALSE;
+#endif
+	CK_OBJECT_CLASS cert_filter_class = CKO_CERTIFICATE;
+	CK_ATTRIBUTE cert_filter[] = {
+		{CKA_CLASS, &cert_filter_class, sizeof (cert_filter_class)}
+	};
+
+	CK_OBJECT_HANDLE *objects = NULL;
+	CK_ULONG objects_found = 0;
+	CK_RV rv = CKR_OK;
+
+	CK_ULONG i;
+
+	PKCS11H_ASSERT (session!=NULL);
+	PKCS11H_ASSERT (certificate_id!=NULL);
+	PKCS11H_ASSERT (subject!=NULL);
+
+	PKCS11H_DEBUG (
+		PKCS11H_LOG_DEBUG2,
+		"PKCS#11: _pkcs11h_locate_getCertificateIdBySubject entry session=%p, certificate_id=%p, subject='%s'",
+		(void *)session,
+		(void *)certificate_id,
+		subject
+	);
+
+#if defined(ENABLE_PKCS11H_THREADING)
+	if (
+		rv == CKR_OK &&
+		(rv = _pkcs11h_threading_mutexLock (&session->mutex)) == CKR_OK
+	) {
+		mutex_locked = TRUE;
+	}
+#endif
+
+	if (rv == CKR_OK) {
+		rv = _pkcs11h_session_validate (session);
+	}
+
+	if (rv == CKR_OK) {
+		rv = _pkcs11h_session_findObjects (
+			session,
+			cert_filter,
+			sizeof (cert_filter) / sizeof (CK_ATTRIBUTE),
+			&objects,
+			&objects_found
+		);
+	}
+
+#if defined(ENABLE_PKCS11H_THREADING)
+	if (mutex_locked) {
+		_pkcs11h_threading_mutexRelease (&session->mutex);
+		mutex_locked = FALSE;
+	}
+#endif
+
+	for (i=0;rv == CKR_OK && i < objects_found;i++) {
+		CK_ATTRIBUTE attrs[] = {
+			{CKA_ID, NULL, 0},
+			{CKA_VALUE, NULL, 0}
+		};
+		char current_subject[1024];
+		current_subject[0] = '\0';
+
+		if (rv == CKR_OK) {
+			rv = _pkcs11h_session_getObjectAttributes (
+				session,
+				objects[i],
+				attrs,
+				sizeof (attrs) / sizeof (CK_ATTRIBUTE)
+			);
+		}
+
+		if (
+			rv == CKR_OK &&
+			!g_pkcs11h_crypto_engine.certificate_get_dn (
+				g_pkcs11h_crypto_engine.global_data,
+				attrs[1].pValue,
+				attrs[1].ulValueLen,
+				current_subject,
+				sizeof (current_subject)
+			)
+		) {
+			rv = CKR_FUNCTION_FAILED;
+		}
+
+		if (
+			rv == CKR_OK &&
+			!strcmp (subject, current_subject) &&
+			_pkcs11h_certificate_isBetterCertificate (
+				certificate_id->certificate_blob,
+				certificate_id->certificate_blob_size,
+				attrs[1].pValue,
+				attrs[1].ulValueLen
+			)
+		) {
+			if (certificate_id->attrCKA_ID != NULL) {
+				_pkcs11h_mem_free ((void *)&certificate_id->attrCKA_ID);
+			}
+			if (certificate_id->certificate_blob != NULL) {
+				_pkcs11h_mem_free ((void *)&certificate_id->certificate_blob);
+			}
+			rv = _pkcs11h_mem_duplicate (
+				(void *)&certificate_id->attrCKA_ID,
+				&certificate_id->attrCKA_ID_size,
+				attrs[0].pValue,
+				attrs[0].ulValueLen
+			);
+			rv = _pkcs11h_mem_duplicate (
+				(void *)&certificate_id->certificate_blob,
+				&certificate_id->certificate_blob_size,
+				attrs[1].pValue,
+				attrs[1].ulValueLen
+			);
+		}
+
+		if (rv != CKR_OK) {
+			PKCS11H_DEBUG (
+				PKCS11H_LOG_DEBUG1,
+				"PKCS#11: Cannot get object attribute for provider '%s' object %ld rv=%ld-'%s'",
+				session->provider->manufacturerID,
+				objects[i],
+				rv,
+				pkcs11h_getMessage (rv)
+			);
+
+			/*
+			 * Ignore error
+			 */
+			rv = CKR_OK;
+		}
+
+		_pkcs11h_session_freeObjectAttributes (
+			attrs,
+			sizeof (attrs) / sizeof (CK_ATTRIBUTE)
+		);
+	}
+	
+	if (
+		rv == CKR_OK &&
+		certificate_id->certificate_blob == NULL
+	) {
+		rv = CKR_ATTRIBUTE_VALUE_INVALID;
+	}
+
+	if (objects != NULL) {
+		_pkcs11h_mem_free ((void *)&objects);
+	}
+
+	/*
+	 * No need to free allocated objects
+	 * on error, since the certificate_id
+	 * should be free by caller.
+	 */
+
+	PKCS11H_DEBUG (
+		PKCS11H_LOG_DEBUG2,
+		"PKCS#11: _pkcs11h_locate_getCertificateIdBySubject return rv=%ld-'%s'",
+		rv,
+		pkcs11h_getMessage (rv)
+	);
+
+	return rv;
+}
+
+CK_RV
+pkcs11h_locate_certificate (
+	IN const char * const slot_type,
+	IN const char * const slot,
+	IN const char * const id_type,
+	IN const char * const id,
+	IN void * const user_data,
+	IN const unsigned mask_prompt,
+	OUT pkcs11h_certificate_id_t * const p_certificate_id
+) {
+#if defined(ENABLE_PKCS11H_THREADING)
+	PKCS11H_BOOL mutex_locked = FALSE;
+#endif
+	pkcs11h_certificate_id_t certificate_id = NULL;
+	pkcs11h_session_t session = NULL;
+	PKCS11H_BOOL op_succeed = FALSE;
+	PKCS11H_BOOL login_retry = FALSE;
+	
+	CK_RV rv = CKR_OK;
+
+	PKCS11H_ASSERT (g_pkcs11h_data!=NULL);
+	PKCS11H_ASSERT (g_pkcs11h_data->initialized);
+	PKCS11H_ASSERT (slot_type!=NULL);
+	PKCS11H_ASSERT (slot!=NULL);
+	PKCS11H_ASSERT (id_type!=NULL);
+	PKCS11H_ASSERT (id!=NULL);
+	/*PKCS11H_ASSERT (user_data) NOT NEEDED */
+	PKCS11H_ASSERT (p_certificate_id!=NULL);
+
+	PKCS11H_DEBUG (
+		PKCS11H_LOG_DEBUG2,
+		"PKCS#11: pkcs11h_locateCertificate entry slot_type='%s', slot='%s', id_type='%s', id='%s', user_data=%p, mask_prompt=%08x, p_certificate_id=%p",
+		slot_type,
+		slot,
+		id_type,
+		id,
+		user_data,
+		mask_prompt,
+		(void *)p_certificate_id
+	);
+
+	*p_certificate_id = NULL;
+
+	if (rv == CKR_OK) {
+		rv = _pkcs11h_certificate_newCertificateId (&certificate_id);
+	}
+
+	if (rv == CKR_OK) {
+		rv = pkcs11h_locate_token (
+			slot_type,
+			slot,
+			user_data,
+			mask_prompt,
+			&certificate_id->token_id
+		);
+	}
+
+	if (rv == CKR_OK) {
+		rv = _pkcs11h_session_getSessionByTokenId (
+			certificate_id->token_id,
+			&session
+		);
+	}
+
+#if defined(ENABLE_PKCS11H_THREADING)
+	if (
+		rv == CKR_OK &&
+		(rv = _pkcs11h_threading_mutexLock (&g_pkcs11h_data->mutexes.global)) == CKR_OK
+	) {
+		mutex_locked = TRUE;
+	}
+#endif
+
+	while (rv == CKR_OK && !op_succeed) {
+		if (!strcmp (id_type, "id")) {
+			certificate_id->attrCKA_ID_size = strlen (id)/2;
+
+			if (certificate_id->attrCKA_ID_size == 0) {
+				rv = CKR_FUNCTION_FAILED;
+			}
+
+			if (
+				rv == CKR_OK &&
+				(rv = _pkcs11h_mem_malloc (
+					(void*)&certificate_id->attrCKA_ID,
+					certificate_id->attrCKA_ID_size
+				)) == CKR_OK
+			) {
+				_pkcs11h_util_hexToBinary (
+					certificate_id->attrCKA_ID,
+					id,
+					&certificate_id->attrCKA_ID_size
+				);
+			}
+		}
+		else if (!strcmp (id_type, "label")) {
+			rv = _pkcs11h_locate_getCertificateIdByLabel (
+				session,
+				certificate_id,
+				id
+			);
+		}
+		else if (!strcmp (id_type, "subject")) {
+			rv = _pkcs11h_locate_getCertificateIdBySubject (
+				session,
+				certificate_id,
+				id
+			);
+		}
+		else {
+			rv = CKR_ARGUMENTS_BAD;
+		}
+
+		if (rv == CKR_OK) {
+			op_succeed = TRUE;
+		}
+		else {
+			if (!login_retry) {
+				PKCS11H_DEBUG (
+					PKCS11H_LOG_DEBUG1,
+					"PKCS#11: Get certificate failed: %ld:'%s'",
+					rv,
+					pkcs11h_getMessage (rv)
+				);
+
+				rv = _pkcs11h_session_login (
+					session,
+					TRUE,
+					TRUE,
+					user_data,
+					mask_prompt
+				);
+
+				login_retry = TRUE;
+			}
+		}
+	}
+
+#if defined(ENABLE_PKCS11H_THREADING)
+	if (mutex_locked) {
+		_pkcs11h_threading_mutexRelease (&g_pkcs11h_data->mutexes.global);
+		mutex_locked = FALSE;
+	}
+#endif
+
+	if (rv == CKR_OK) {
+		*p_certificate_id = certificate_id;
+		certificate_id = NULL;
+	}
+
+	if (certificate_id != NULL) {
+		pkcs11h_certificate_freeCertificateId (certificate_id);
+		certificate_id = NULL;
+	}
+
+	if (session != NULL) {
+		_pkcs11h_session_release (session);
+		session = NULL;
+	}
+
+	PKCS11H_DEBUG (
+		PKCS11H_LOG_DEBUG2,
+		"PKCS#11: pkcs11h_locateCertificate return rv=%ld-'%s' *p_certificate_id=%p",
+		rv,
+		pkcs11h_getMessage (rv),
+		(void *)*p_certificate_id
+	);
+	
+	return rv;
+}
+
+#endif				/* ENABLE_PKCS11H_CERTIFICATE */
+
+#endif				/* ENABLE_PKCS11H_LOCATE */
+
diff --git a/lib/pkcs11h-mem.c b/lib/pkcs11h-mem.c
new file mode 100644
index 0000000..e7ac899
--- /dev/null
+++ b/lib/pkcs11h-mem.c
@@ -0,0 +1,141 @@
+/*
+ * Copyright (c) 2005-2006 Alon Bar-Lev <alon.barlev at gmail.com>
+ * All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, or the OpenIB.org BSD license.
+ *
+ * GNU General Public License (GPL) Version 2
+ * ===========================================
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2
+ *  as published by the Free Software Foundation.
+ *
+ *  This program 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 General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program (see the file COPYING[.GPL2] included with this
+ *  distribution); if not, write to the Free Software Foundation, Inc.,
+ *  59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * OpenIB.org BSD license
+ * =======================
+ * Redistribution and use in source and binary forms, with or without modifi-
+ * cation, are permitted provided that the following conditions are met:
+ *
+ *   o  Redistributions of source code must retain the above copyright notice,
+ *      this list of conditions and the following disclaimer.
+ *
+ *   o  Redistributions in binary form must reproduce the above copyright no-
+ *      tice, this list of conditions and the following disclaimer in the do-
+ *      cumentation and/or other materials provided with the distribution.
+ *
+ *   o  The names of the contributors may not be used to endorse or promote
+ *      products derived from this software without specific prior written
+ *      permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``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 REGENTS OR CONTRIBUTORS BE LI-
+ * ABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUEN-
+ * TIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEV-
+ * ER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABI-
+ * LITY, 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.
+ */
+
+#include "common.h"
+
+#include "_pkcs11h-sys.h"
+#include "_pkcs11h-mem.h"
+
+CK_RV
+_pkcs11h_mem_malloc (
+	OUT const void * * const p,
+	IN const size_t s
+) {
+	CK_RV rv = CKR_OK;
+
+	PKCS11H_ASSERT (p!=NULL);
+	PKCS11H_ASSERT (s!=0);
+
+	*p = NULL;
+
+	if (s > 0) {
+		if (
+			(*p = (void *)g_pkcs11h_sys_engine.malloc (s)) == NULL
+		) {
+			rv = CKR_HOST_MEMORY;
+		}
+		else {
+			memset ((void *)*p, 0, s);
+		}
+	}
+
+	return rv;
+}
+
+CK_RV
+_pkcs11h_mem_free (
+	IN const void * * const  p
+) {
+	PKCS11H_ASSERT (p!=NULL);
+
+	g_pkcs11h_sys_engine.free ((void *)*p);
+	*p = NULL;
+
+	return CKR_OK;
+}
+
+CK_RV
+_pkcs11h_mem_strdup (
+	OUT const char * * const dest,
+	IN const char * const src
+) {
+	return _pkcs11h_mem_duplicate (
+		(void *)dest,
+		NULL,
+		src,
+		strlen (src)+1
+	);
+}
+
+CK_RV
+_pkcs11h_mem_duplicate (
+	OUT const void * * const dest,
+	OUT size_t * const p_dest_size,
+	IN const void * const src,
+	IN const size_t mem_size
+) {
+	CK_RV rv = CKR_OK;
+
+	PKCS11H_ASSERT (dest!=NULL);
+	/*PKCS11H_ASSERT (dest_size!=NULL); NOT NEEDED*/
+	PKCS11H_ASSERT (!(mem_size!=0&&src==NULL));
+
+	*dest = NULL;
+	if (p_dest_size != NULL) {
+		*p_dest_size = 0;
+	}
+
+	if (src != NULL) {
+		if (
+			rv == CKR_OK &&
+			(rv = _pkcs11h_mem_malloc (dest, mem_size)) == CKR_OK
+		) {
+			if (p_dest_size != NULL) {
+				*p_dest_size = mem_size;
+			}
+			memmove ((void*)*dest, src, mem_size);
+		}
+	}
+
+	return rv;
+}
+
diff --git a/lib/pkcs11h-openssl.c b/lib/pkcs11h-openssl.c
new file mode 100644
index 0000000..9f49c6a
--- /dev/null
+++ b/lib/pkcs11h-openssl.c
@@ -0,0 +1,784 @@
+/*
+ * Copyright (c) 2005-2006 Alon Bar-Lev <alon.barlev at gmail.com>
+ * All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, or the OpenIB.org BSD license.
+ *
+ * GNU General Public License (GPL) Version 2
+ * ===========================================
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2
+ *  as published by the Free Software Foundation.
+ *
+ *  This program 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 General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program (see the file COPYING[.GPL2] included with this
+ *  distribution); if not, write to the Free Software Foundation, Inc.,
+ *  59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * OpenIB.org BSD license
+ * =======================
+ * Redistribution and use in source and binary forms, with or without modifi-
+ * cation, are permitted provided that the following conditions are met:
+ *
+ *   o  Redistributions of source code must retain the above copyright notice,
+ *      this list of conditions and the following disclaimer.
+ *
+ *   o  Redistributions in binary form must reproduce the above copyright no-
+ *      tice, this list of conditions and the following disclaimer in the do-
+ *      cumentation and/or other materials provided with the distribution.
+ *
+ *   o  The names of the contributors may not be used to endorse or promote
+ *      products derived from this software without specific prior written
+ *      permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``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 REGENTS OR CONTRIBUTORS BE LI-
+ * ABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUEN-
+ * TIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEV-
+ * ER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABI-
+ * LITY, 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.
+ */
+
+#include "common.h"
+
+#if defined(ENABLE_PKCS11H_OPENSSL)
+
+#include <pkcs11-helper-1.0/pkcs11h-openssl.h>
+#include "_pkcs11h-core.h"
+#include "_pkcs11h-mem.h"
+
+#if OPENSSL_VERSION_NUMBER < 0x00907000L
+#if !defined(RSA_PKCS1_PADDING_SIZE)
+#define RSA_PKCS1_PADDING_SIZE 11
+#endif
+#endif
+
+#if OPENSSL_VERSION_NUMBER < 0x00908000L
+typedef unsigned char *pkcs11_openssl_d2i_t;
+#else
+typedef const unsigned char *pkcs11_openssl_d2i_t;
+#endif
+
+struct pkcs11h_openssl_session_s {
+	int reference_count;
+	PKCS11H_BOOL initialized;
+	X509 *x509;
+	RSA_METHOD smart_rsa;
+	int (*orig_finish)(RSA *rsa);
+	pkcs11h_certificate_t certificate;
+	pkcs11h_hook_openssl_cleanup_t cleanup_hook;
+};
+
+static
+int
+_pkcs11h_openssl_finish (
+	IN OUT RSA *rsa
+);
+#if OPENSSL_VERSION_NUMBER < 0x00907000L
+static
+int
+_pkcs11h_openssl_dec (
+	IN int flen,
+	IN unsigned char *from,
+	OUT unsigned char *to,
+	IN OUT RSA *rsa,
+	IN int padding
+);
+static
+int
+_pkcs11h_openssl_sign (
+	IN int type,
+	IN unsigned char *m,
+	IN unsigned int m_len,
+	OUT unsigned char *sigret,
+	OUT unsigned int *siglen,
+	IN OUT RSA *rsa
+);
+#else
+static
+int
+_pkcs11h_openssl_dec (
+	IN int flen,
+	IN const unsigned char *from,
+	OUT unsigned char *to,
+	IN OUT RSA *rsa,
+	IN int padding
+);
+static
+int
+_pkcs11h_openssl_sign (
+	IN int type,
+	IN const unsigned char *m,
+	IN unsigned int m_len,
+	OUT unsigned char *sigret,
+	OUT unsigned int *siglen,
+	IN OUT const RSA *rsa
+);
+#endif
+static
+pkcs11h_openssl_session_t
+_pkcs11h_openssl_get_openssl_session (
+	IN OUT const RSA *rsa
+);  
+
+static
+pkcs11h_certificate_t
+_pkcs11h_openssl_get_pkcs11h_certificate (
+	IN OUT const RSA *rsa
+);  
+
+static
+pkcs11h_openssl_session_t
+_pkcs11h_openssl_get_openssl_session (
+	IN OUT const RSA *rsa
+) {
+	pkcs11h_openssl_session_t session;
+		
+	PKCS11H_ASSERT (rsa!=NULL);
+#if OPENSSL_VERSION_NUMBER < 0x00907000L
+	session = (pkcs11h_openssl_session_t)RSA_get_app_data ((RSA *)rsa);
+#else
+	session = (pkcs11h_openssl_session_t)RSA_get_app_data (rsa);
+#endif
+	PKCS11H_ASSERT (session!=NULL);
+
+	return session;
+}
+
+static
+pkcs11h_certificate_t
+_pkcs11h_openssl_get_pkcs11h_certificate (
+	IN OUT const RSA *rsa
+) {
+	pkcs11h_openssl_session_t session = _pkcs11h_openssl_get_openssl_session (rsa);
+	
+	PKCS11H_ASSERT (session!=NULL);
+	PKCS11H_ASSERT (session->certificate!=NULL);
+
+	return session->certificate;
+}
+
+#if OPENSSL_VERSION_NUMBER < 0x00907000L
+static
+int
+_pkcs11h_openssl_dec (
+	IN int flen,
+	IN unsigned char *from,
+	OUT unsigned char *to,
+	IN OUT RSA *rsa,
+	IN int padding
+) {
+#else
+static
+int
+_pkcs11h_openssl_dec (
+	IN int flen,
+	IN const unsigned char *from,
+	OUT unsigned char *to,
+	IN OUT RSA *rsa,
+	IN int padding
+) {
+#endif
+	PKCS11H_ASSERT (from!=NULL);
+	PKCS11H_ASSERT (to!=NULL);
+	PKCS11H_ASSERT (rsa!=NULL);
+
+	PKCS11H_DEBUG (
+		PKCS11H_LOG_DEBUG2,
+		"PKCS#11: _pkcs11h_openssl_dec entered - flen=%d, from=%p, to=%p, rsa=%p, padding=%d",
+		flen,
+		from,
+		to,
+		(void *)rsa,
+		padding
+	);
+
+	PKCS11H_LOG (
+		PKCS11H_LOG_ERROR,
+		"PKCS#11: Private key decryption is not supported"
+	);
+
+	PKCS11H_DEBUG (
+		PKCS11H_LOG_DEBUG2,
+		"PKCS#11: _pkcs11h_openssl_dec return"
+	);
+
+	return -1;
+}
+
+#if OPENSSL_VERSION_NUMBER < 0x00907000L
+static
+int
+_pkcs11h_openssl_sign (
+	IN int type,
+	IN unsigned char *m,
+	IN unsigned int m_len,
+	OUT unsigned char *sigret,
+	OUT unsigned int *siglen,
+	IN OUT RSA *rsa
+) {
+#else
+static
+int
+_pkcs11h_openssl_sign (
+	IN int type,
+	IN const unsigned char *m,
+	IN unsigned int m_len,
+	OUT unsigned char *sigret,
+	OUT unsigned int *siglen,
+	IN OUT const RSA *rsa
+) {
+#endif
+	pkcs11h_certificate_t certificate = _pkcs11h_openssl_get_pkcs11h_certificate (rsa);
+	PKCS11H_BOOL session_locked = FALSE;
+	CK_RV rv = CKR_OK;
+
+	int myrsa_size = 0;
+	
+	unsigned char *enc_alloc = NULL;
+	unsigned char *enc = NULL;
+	int enc_len = 0;
+
+	PKCS11H_ASSERT (m!=NULL);
+	PKCS11H_ASSERT (sigret!=NULL);
+	PKCS11H_ASSERT (siglen!=NULL);
+
+	PKCS11H_DEBUG (
+		PKCS11H_LOG_DEBUG2,
+		"PKCS#11: _pkcs11h_openssl_sign entered - type=%d, m=%p, m_len=%u, signret=%p, *signlen=%u, rsa=%p",
+		type,
+		m,
+		m_len,
+		sigret,
+		sigret != NULL ? *siglen : 0,
+		(void *)rsa
+	);
+
+	if (rv == CKR_OK) {
+		myrsa_size=RSA_size(rsa);
+	}
+
+	if (type == NID_md5_sha1) {
+		if (rv == CKR_OK) {
+			enc = (unsigned char *)m;
+			enc_len = m_len;
+		}
+	}
+	else {
+		X509_SIG sig;
+		ASN1_TYPE parameter;
+		X509_ALGOR algor;
+		ASN1_OCTET_STRING digest;
+		unsigned char *p = NULL;
+
+		if (
+			rv == CKR_OK &&
+			(rv = _pkcs11h_mem_malloc ((void*)&enc, myrsa_size+1)) == CKR_OK
+		) {
+			enc_alloc = enc;
+		}
+		
+		if (rv == CKR_OK) {
+			sig.algor = &algor;
+		}
+
+		if (
+			rv == CKR_OK &&
+			(sig.algor->algorithm = OBJ_nid2obj (type)) == NULL
+		) {
+			rv = CKR_FUNCTION_FAILED;
+		}
+	
+		if (
+			rv == CKR_OK &&
+			sig.algor->algorithm->length == 0
+		) {
+			rv = CKR_KEY_SIZE_RANGE;
+		}
+	
+		if (rv == CKR_OK) {
+			parameter.type = V_ASN1_NULL;
+			parameter.value.ptr = NULL;
+	
+			sig.algor->parameter = ¶meter;
+
+			sig.digest = &digest;
+			sig.digest->data = (unsigned char *)m;
+			sig.digest->length = m_len;
+		}
+	
+		if (
+			rv == CKR_OK &&
+			(enc_len=i2d_X509_SIG (&sig, NULL)) < 0
+		) {
+			rv = CKR_FUNCTION_FAILED;
+		}
+
+		/*
+		 * d_X509_SIG increments pointer!
+		 */
+		p = enc;
+	
+		if (
+			rv == CKR_OK &&
+			(enc_len=i2d_X509_SIG (&sig, &p)) < 0
+		) {
+			rv = CKR_FUNCTION_FAILED;
+		}
+	}
+
+	if (
+		rv == CKR_OK &&
+		enc_len > (myrsa_size-RSA_PKCS1_PADDING_SIZE)
+	) {
+		rv = CKR_KEY_SIZE_RANGE;
+	}
+
+	if (
+		rv == CKR_OK &&
+		(rv = pkcs11h_certificate_lockSession (certificate)) == CKR_OK
+	) {
+		session_locked = TRUE;
+	}
+
+	if (rv == CKR_OK) {
+		PKCS11H_DEBUG (
+			PKCS11H_LOG_DEBUG1,
+			"PKCS#11: Performing signature"
+		);
+
+		*siglen = myrsa_size;
+
+		if (
+			(rv = pkcs11h_certificate_signAny (
+				certificate,
+				CKM_RSA_PKCS,
+				enc,
+				enc_len,
+				sigret,
+				siglen
+			)) != CKR_OK
+		) {
+			PKCS11H_LOG (PKCS11H_LOG_WARN, "PKCS#11: Cannot perform signature %ld:'%s'", rv, pkcs11h_getMessage (rv));
+		}
+	}
+
+	if (session_locked) {
+		pkcs11h_certificate_releaseSession (certificate);
+		session_locked = FALSE;
+	}
+
+	if (enc_alloc != NULL) {
+		_pkcs11h_mem_free ((void *)&enc_alloc);
+	}
+	
+	PKCS11H_DEBUG (
+		PKCS11H_LOG_DEBUG2,
+		"PKCS#11: _pkcs11h_openssl_sign - return rv=%ld-'%s'",
+		rv,
+		pkcs11h_getMessage (rv)
+	);
+
+	return rv == CKR_OK ? 1 : -1; 
+}
+
+static
+int
+_pkcs11h_openssl_finish (
+	IN OUT RSA *rsa
+) {
+	pkcs11h_openssl_session_t openssl_session = _pkcs11h_openssl_get_openssl_session (rsa);
+
+	PKCS11H_DEBUG (
+		PKCS11H_LOG_DEBUG2,
+		"PKCS#11: _pkcs11h_openssl_finish - entered rsa=%p",
+		(void *)rsa
+	);
+
+	RSA_set_app_data (rsa, NULL);
+	
+	if (openssl_session->orig_finish != NULL) {
+		openssl_session->orig_finish (rsa);
+
+#ifdef BROKEN_OPENSSL_ENGINE
+		{
+			/* We get called TWICE here, once for
+			 * releasing the key and also for
+			 * releasing the engine.
+			 * To prevent endless recursion, FIRST
+			 * clear rsa->engine, THEN call engine->finish
+			 */
+			ENGINE *e = rsa->engine;
+			rsa->engine = NULL;
+			if (e) {
+				ENGINE_finish(e);
+			}
+		}
+#endif
+	}
+
+	pkcs11h_openssl_freeSession (openssl_session);
+
+	PKCS11H_DEBUG (
+		PKCS11H_LOG_DEBUG2,
+		"PKCS#11: _pkcs11h_openssl_finish - return"
+	);
+	
+	return 1;
+}
+
+X509 *
+pkcs11h_openssl_getX509 (
+	IN const pkcs11h_certificate_t certificate
+) {
+	unsigned char *certificate_blob = NULL;
+	size_t certificate_blob_size = 0;
+	X509 *x509 = NULL;
+	CK_RV rv = CKR_OK;
+
+	pkcs11_openssl_d2i_t d2i1 = NULL;
+	PKCS11H_BOOL ok = TRUE;
+
+	PKCS11H_ASSERT (certificate!=NULL);
+
+	PKCS11H_DEBUG (
+		PKCS11H_LOG_DEBUG2,
+		"PKCS#11: pkcs11h_openssl_getX509 - entry certificate=%p",
+		(void *)certificate
+	);
+
+	if (
+		ok &&
+		(x509 = X509_new ()) == NULL
+	) {
+		ok = FALSE;
+		PKCS11H_LOG (PKCS11H_LOG_WARN, "PKCS#11: Unable to allocate certificate object");
+	}
+
+	if (
+		ok &&
+		pkcs11h_certificate_getCertificateBlob (
+			certificate,
+			NULL,
+			&certificate_blob_size
+		) != CKR_OK
+	) {
+		ok = FALSE;
+		PKCS11H_LOG (PKCS11H_LOG_WARN, "PKCS#11: Cannot read X.509 certificate from token %ld-'%s'", rv, pkcs11h_getMessage (rv));
+	}
+
+	if (
+		ok &&
+		(rv = _pkcs11h_mem_malloc ((void *)&certificate_blob, certificate_blob_size)) != CKR_OK
+	) {
+		ok = FALSE;
+		PKCS11H_LOG (PKCS11H_LOG_WARN, "PKCS#11: Cannot allocate X.509 memory %ld-'%s'", rv, pkcs11h_getMessage (rv));
+	}
+
+	if (
+		ok &&
+		pkcs11h_certificate_getCertificateBlob (
+			certificate,
+			certificate_blob,
+			&certificate_blob_size
+		) != CKR_OK
+	) {
+		ok = FALSE;
+		PKCS11H_LOG (PKCS11H_LOG_WARN, "PKCS#11: Cannot read X.509 certificate from token %ld-'%s'", rv, pkcs11h_getMessage (rv));
+	}
+
+	d2i1 = (pkcs11_openssl_d2i_t)certificate_blob;
+	if (
+		ok &&
+		!d2i_X509 (&x509, &d2i1, certificate_blob_size)
+	) {
+		ok = FALSE;
+		PKCS11H_LOG (PKCS11H_LOG_WARN, "PKCS#11: Unable to parse X.509 certificate");
+	}
+
+	if (!ok) {
+		X509_free (x509);
+		x509 = NULL;
+	}
+	
+	PKCS11H_DEBUG (
+		PKCS11H_LOG_DEBUG2,
+		"PKCS#11: pkcs11h_openssl_getX509 - return x509=%p",
+		(void *)x509
+	);
+
+	return x509;
+}
+
+pkcs11h_openssl_session_t
+pkcs11h_openssl_createSession (
+	IN const pkcs11h_certificate_t certificate
+) {
+	pkcs11h_openssl_session_t openssl_session = NULL;
+	PKCS11H_BOOL ok = TRUE;
+
+	PKCS11H_DEBUG (
+		PKCS11H_LOG_DEBUG2,
+		"PKCS#11: pkcs11h_openssl_createSession - entry"
+	);
+
+	if (ok) {
+		OpenSSL_add_all_digests ();
+	}
+
+	if (
+		ok &&
+		_pkcs11h_mem_malloc (
+			(void*)&openssl_session,
+			sizeof (struct pkcs11h_openssl_session_s)) != CKR_OK
+	) {
+		ok = FALSE;
+		PKCS11H_LOG (PKCS11H_LOG_WARN, "PKCS#11: Cannot allocate memory");
+	}
+
+	if (ok) {
+		const RSA_METHOD *def = RSA_get_default_method ();
+
+		memmove (&openssl_session->smart_rsa, def, sizeof(RSA_METHOD));
+
+		openssl_session->orig_finish = def->finish;
+
+		openssl_session->smart_rsa.name = "pkcs11";
+		openssl_session->smart_rsa.rsa_priv_dec = _pkcs11h_openssl_dec;
+		openssl_session->smart_rsa.rsa_sign = _pkcs11h_openssl_sign;
+		openssl_session->smart_rsa.finish = _pkcs11h_openssl_finish;
+		openssl_session->smart_rsa.flags  = RSA_METHOD_FLAG_NO_CHECK | RSA_FLAG_EXT_PKEY;
+		openssl_session->certificate = certificate;
+		openssl_session->reference_count = 1;
+	}
+
+	if (!ok) {
+		_pkcs11h_mem_free ((void *)&openssl_session);
+	}
+	
+	PKCS11H_DEBUG (
+		PKCS11H_LOG_DEBUG2,
+		"PKCS#11: pkcs11h_openssl_createSession - return openssl_session=%p",
+		(void *)openssl_session
+	);
+
+	return openssl_session;
+}
+
+pkcs11h_hook_openssl_cleanup_t
+pkcs11h_openssl_getCleanupHook (
+	IN const pkcs11h_openssl_session_t openssl_session
+) {
+	PKCS11H_ASSERT (openssl_session!=NULL);
+
+	return openssl_session->cleanup_hook;
+}
+
+void
+pkcs11h_openssl_setCleanupHook (
+	IN const pkcs11h_openssl_session_t openssl_session,
+	IN const pkcs11h_hook_openssl_cleanup_t cleanup
+) {
+	PKCS11H_ASSERT (openssl_session!=NULL);
+
+	openssl_session->cleanup_hook = cleanup;
+}
+
+void
+pkcs11h_openssl_freeSession (
+	IN const pkcs11h_openssl_session_t openssl_session
+) {
+	PKCS11H_ASSERT (openssl_session!=NULL);
+	PKCS11H_ASSERT (openssl_session->reference_count>0);
+	
+	PKCS11H_DEBUG (
+		PKCS11H_LOG_DEBUG2,
+		"PKCS#11: pkcs11h_openssl_freeSession - entry openssl_session=%p, count=%d",
+		(void *)openssl_session,
+		openssl_session->reference_count
+	);
+
+	openssl_session->reference_count--;
+	
+	if (openssl_session->reference_count == 0) {
+		if (openssl_session->cleanup_hook != NULL) {
+			openssl_session->cleanup_hook (openssl_session->certificate);
+		}
+
+		if (openssl_session->x509 != NULL) {
+			X509_free (openssl_session->x509);
+			openssl_session->x509 = NULL;
+		}
+		if (openssl_session->certificate != NULL) {
+			pkcs11h_certificate_freeCertificate (openssl_session->certificate);
+			openssl_session->certificate = NULL;
+		}
+		
+		_pkcs11h_mem_free ((void *)&openssl_session);
+	}
+
+	PKCS11H_DEBUG (
+		PKCS11H_LOG_DEBUG2,
+		"PKCS#11: pkcs11h_openssl_freeSession - return"
+	);
+}
+
+RSA *
+pkcs11h_openssl_session_getRSA (
+	IN const pkcs11h_openssl_session_t openssl_session
+) {
+	X509 *x509 = NULL;
+	RSA *rsa = NULL;
+	EVP_PKEY *pubkey = NULL;
+	PKCS11H_BOOL ok = TRUE;
+
+	PKCS11H_ASSERT (openssl_session!=NULL);
+	PKCS11H_ASSERT (!openssl_session->initialized);
+	PKCS11H_ASSERT (openssl_session!=NULL);
+
+	PKCS11H_DEBUG (
+		PKCS11H_LOG_DEBUG2,
+		"PKCS#11: pkcs11h_openssl_session_getRSA - entry openssl_session=%p",
+		(void *)openssl_session
+	);
+	
+	/*
+	 * Dup x509 so RSA will not hold session x509
+	 */
+	if (
+		ok &&
+		(x509 = pkcs11h_openssl_session_getX509 (openssl_session)) == NULL
+	) {
+		ok = FALSE;
+		PKCS11H_LOG (PKCS11H_LOG_WARN, "PKCS#11: Cannot get certificate object");
+	}
+
+	if (
+		ok &&
+		(pubkey = X509_get_pubkey (x509)) == NULL
+	) {
+		ok = FALSE;
+		PKCS11H_LOG (PKCS11H_LOG_WARN, "PKCS#11: Cannot get public key");
+	}
+	
+	if (
+		ok &&
+		pubkey->type != EVP_PKEY_RSA
+	) {
+		ok = FALSE;
+		PKCS11H_LOG (PKCS11H_LOG_WARN, "PKCS#11: Invalid public key algorithm");
+	}
+
+	if (
+		ok &&
+		(rsa = EVP_PKEY_get1_RSA (pubkey)) == NULL
+	) {
+		ok = FALSE;
+		PKCS11H_LOG (PKCS11H_LOG_WARN, "PKCS#11: Cannot get RSA key");
+	}
+
+	if (ok) {
+		RSA_set_method (rsa, &openssl_session->smart_rsa);
+		RSA_set_app_data (rsa, openssl_session);
+		openssl_session->reference_count++;
+	}
+	
+#ifdef BROKEN_OPENSSL_ENGINE
+	if (ok) {
+		if (!rsa->engine) {
+			rsa->engine = ENGINE_get_default_RSA ();
+		}
+
+		ENGINE_set_RSA(ENGINE_get_default_RSA (), &openssl_session->smart_rsa);
+		PKCS11H_LOG (PKCS11H_LOG_WARN, "PKCS#11: OpenSSL engine support is broken! Workaround enabled");
+	}
+#endif
+		
+	if (ok) {
+		rsa->flags |= RSA_FLAG_SIGN_VER;
+		openssl_session->initialized = TRUE;
+	}
+	else {
+		if (rsa != NULL) {
+			RSA_free (rsa);
+			rsa = NULL;
+		}
+	}
+
+	/*
+	 * openssl objects have reference
+	 * count, so release them
+	 */
+	if (pubkey != NULL) {
+		EVP_PKEY_free (pubkey);
+		pubkey = NULL;
+	}
+
+	if (x509 != NULL) {
+		X509_free (x509);
+		x509 = NULL;
+	}
+	
+	PKCS11H_DEBUG (
+		PKCS11H_LOG_DEBUG2,
+		"PKCS#11: pkcs11h_openssl_session_getRSA - return rsa=%p",
+		(void *)rsa
+	);
+
+	return rsa;
+}
+
+X509 *
+pkcs11h_openssl_session_getX509 (
+	IN const pkcs11h_openssl_session_t openssl_session
+) {
+	X509 *x509 = NULL;
+	PKCS11H_BOOL ok = TRUE;
+	
+	PKCS11H_ASSERT (openssl_session!=NULL);
+
+	PKCS11H_DEBUG (
+		PKCS11H_LOG_DEBUG2,
+		"PKCS#11: pkcs11h_openssl_session_getX509 - entry openssl_session=%p",
+		(void *)openssl_session
+	);
+
+	if (
+		ok &&
+		openssl_session->x509 == NULL &&
+		(openssl_session->x509 = pkcs11h_openssl_getX509 (openssl_session->certificate)) == NULL
+	) {	
+		ok = FALSE;
+		PKCS11H_LOG (PKCS11H_LOG_WARN, "PKCS#11: Cannot get certificate object");
+	}
+
+	if (
+		ok &&
+		(x509 = X509_dup (openssl_session->x509)) == NULL
+	) {
+		ok = FALSE;
+		PKCS11H_LOG (PKCS11H_LOG_WARN, "PKCS#11: Cannot duplicate certificate object");
+	}
+	
+	PKCS11H_DEBUG (
+		PKCS11H_LOG_DEBUG2,
+		"PKCS#11: pkcs11h_openssl_session_getX509 - return x509=%p",
+		(void *)x509
+	);
+
+	return x509;
+}
+
+#endif				/* ENABLE_PKCS11H_OPENSSL */
+
diff --git a/lib/pkcs11h-serialization.c b/lib/pkcs11h-serialization.c
new file mode 100644
index 0000000..17f407f
--- /dev/null
+++ b/lib/pkcs11h-serialization.c
@@ -0,0 +1,435 @@
+/*
+ * Copyright (c) 2005-2006 Alon Bar-Lev <alon.barlev at gmail.com>
+ * All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, or the OpenIB.org BSD license.
+ *
+ * GNU General Public License (GPL) Version 2
+ * ===========================================
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2
+ *  as published by the Free Software Foundation.
+ *
+ *  This program 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 General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program (see the file COPYING[.GPL2] included with this
+ *  distribution); if not, write to the Free Software Foundation, Inc.,
+ *  59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * OpenIB.org BSD license
+ * =======================
+ * Redistribution and use in source and binary forms, with or without modifi-
+ * cation, are permitted provided that the following conditions are met:
+ *
+ *   o  Redistributions of source code must retain the above copyright notice,
+ *      this list of conditions and the following disclaimer.
+ *
+ *   o  Redistributions in binary form must reproduce the above copyright no-
+ *      tice, this list of conditions and the following disclaimer in the do-
+ *      cumentation and/or other materials provided with the distribution.
+ *
+ *   o  The names of the contributors may not be used to endorse or promote
+ *      products derived from this software without specific prior written
+ *      permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``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 REGENTS OR CONTRIBUTORS BE LI-
+ * ABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUEN-
+ * TIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEV-
+ * ER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABI-
+ * LITY, 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.
+ */
+
+#include "common.h"
+
+#include "_pkcs11h-core.h"
+#include "_pkcs11h-mem.h"
+#include "_pkcs11h-util.h"
+#include "_pkcs11h-token.h"
+#include "_pkcs11h-certificate.h"
+
+#define PKCS11H_SERIALIZE_INVALID_CHARS	"\\/\"'%&#@!?$* <>{}[]()`|"
+
+#if defined(ENABLE_PKCS11H_TOKEN) || defined(ENABLE_PKCS11H_CERTIFICATE)
+
+CK_RV
+pkcs11h_token_serializeTokenId (
+	OUT char * const sz,
+	IN OUT size_t *max,
+	IN const pkcs11h_token_id_t token_id
+) {
+	const char *sources[5];
+	CK_RV rv = CKR_OK;
+	size_t n;
+	int e;
+
+	/*PKCS11H_ASSERT (sz!=NULL); Not required*/
+	PKCS11H_ASSERT (max!=NULL);
+	PKCS11H_ASSERT (token_id!=NULL);
+
+	{ /* Must be after assert */
+		sources[0] = token_id->manufacturerID;
+		sources[1] = token_id->model;
+		sources[2] = token_id->serialNumber;
+		sources[3] = token_id->label;
+		sources[4] = NULL;
+	}
+
+	PKCS11H_DEBUG (
+		PKCS11H_LOG_DEBUG2,
+		"PKCS#11: pkcs11h_token_serializeTokenId entry sz=%p, *max=%u, token_id=%p",
+		sz,
+		sz != NULL ? *max : 0,
+		(void *)token_id
+	);
+
+	n = 0;
+	for (e=0;rv == CKR_OK && sources[e] != NULL;e++) {
+		size_t t;
+		rv = _pkcs11h_util_escapeString (NULL, sources[e], &t, PKCS11H_SERIALIZE_INVALID_CHARS);
+		n+=t;
+	}
+
+	if (sz != NULL) {
+		if (*max < n) {
+			rv = CKR_ATTRIBUTE_VALUE_INVALID;
+		}
+		else {
+			n = 0;
+			for (e=0;sources[e] != NULL;e++) {
+				size_t t = *max-n;
+				_pkcs11h_util_escapeString (sz+n, sources[e], &t, PKCS11H_SERIALIZE_INVALID_CHARS);
+				n+=t;
+				sz[n-1] = '/';
+			}
+			sz[n-1] = '\x0';
+		}
+	}
+
+	*max = n;
+
+	PKCS11H_DEBUG (
+		PKCS11H_LOG_DEBUG2,
+		"PKCS#11: pkcs11h_token_serializeTokenId return rv=%ld-'%s', *max=%u, sz='%s'",
+		rv,
+		pkcs11h_getMessage (rv),
+		*max,
+		sz
+	);
+
+	return rv;
+}
+
+CK_RV
+pkcs11h_token_deserializeTokenId (
+	OUT pkcs11h_token_id_t *p_token_id,
+	IN const char * const sz
+) {
+#define __PKCS11H_TARGETS_NUMBER 4
+	struct {
+		char *p;
+		size_t s;
+	} targets[__PKCS11H_TARGETS_NUMBER];
+
+	pkcs11h_token_id_t token_id = NULL;
+	char *p1 = NULL;
+	char *_sz = NULL;
+	int e;
+	CK_RV rv = CKR_OK;
+
+	PKCS11H_ASSERT (p_token_id!=NULL);
+	PKCS11H_ASSERT (sz!=NULL);
+
+	PKCS11H_DEBUG (
+		PKCS11H_LOG_DEBUG2,
+		"PKCS#11: pkcs11h_token_deserializeTokenId entry p_token_id=%p, sz='%s'",
+		(void *)p_token_id,
+		sz
+	);
+
+	*p_token_id = NULL;
+
+	if (rv == CKR_OK) {
+		rv = _pkcs11h_mem_strdup (
+			(void *)&_sz,
+			sz
+		);
+	}
+
+	if (rv == CKR_OK) {
+		p1 = _sz;
+	}
+
+	if (
+		rv == CKR_OK &&
+		(rv = _pkcs11h_token_newTokenId (&token_id)) == CKR_OK
+	) {
+		targets[0].p = token_id->manufacturerID;
+		targets[0].s = sizeof (token_id->manufacturerID);
+		targets[1].p = token_id->model;
+		targets[1].s = sizeof (token_id->model);
+		targets[2].p = token_id->serialNumber;
+		targets[2].s = sizeof (token_id->serialNumber);
+		targets[3].p = token_id->label;
+		targets[3].s = sizeof (token_id->label);
+	}
+
+	for (e=0;rv == CKR_OK && e < __PKCS11H_TARGETS_NUMBER;e++) {
+		size_t l;
+		char *p2 = NULL;
+
+		/*
+		 * Don't search for last
+		 * separator
+		 */
+		if (rv == CKR_OK) {
+			if (e != __PKCS11H_TARGETS_NUMBER-1) {
+				p2 = strchr (p1, '/');
+				if (p2 == NULL) {
+					rv = CKR_ATTRIBUTE_VALUE_INVALID;
+				}
+				else {
+					*p2 = '\x0';
+				}
+			}
+		}
+
+		if (rv == CKR_OK) {
+			_pkcs11h_util_unescapeString (
+				NULL,
+				p1,
+				&l
+			);
+		}
+
+		if (rv == CKR_OK) {
+			if (l > targets[e].s) {
+				rv = CKR_ATTRIBUTE_VALUE_INVALID;
+			}
+		}
+
+		if (rv == CKR_OK) {
+			l = targets[e].s;
+			_pkcs11h_util_unescapeString (
+				targets[e].p,
+				p1,
+				&l
+			);
+		}
+
+		if (rv == CKR_OK) {
+			p1 = p2+1;
+		}
+	}
+
+	if (rv == CKR_OK) {
+		strncpy (
+			token_id->display,
+			token_id->label,
+			sizeof (token_id->display)
+		);
+	}
+
+	if (rv == CKR_OK) {
+		*p_token_id = token_id;
+		token_id = NULL;
+	}
+
+	if (_sz != NULL) {
+		_pkcs11h_mem_free ((void *)&_sz);
+	}
+
+	if (token_id != NULL) {
+		pkcs11h_token_freeTokenId (token_id);
+	}
+
+	return rv;
+#undef __PKCS11H_TARGETS_NUMBER
+}
+
+#endif				/* ENABLE_PKCS11H_TOKEN || ENABLE_PKCS11H_CERTIFICATE */
+
+#if defined(ENABLE_PKCS11H_CERTIFICATE)
+
+CK_RV
+pkcs11h_certificate_serializeCertificateId (
+	OUT char * const sz,
+	IN OUT size_t *max,
+	IN const pkcs11h_certificate_id_t certificate_id
+) {
+	CK_RV rv = CKR_OK;
+	size_t saved_max = 0;
+	size_t n = 0;
+	size_t _max = 0;
+
+	/*PKCS11H_ASSERT (sz!=NULL); Not required */
+	PKCS11H_ASSERT (max!=NULL);
+	PKCS11H_ASSERT (certificate_id!=NULL);
+
+	PKCS11H_DEBUG (
+		PKCS11H_LOG_DEBUG2,
+		"PKCS#11: pkcs11h_certificate_serializeCertificateId entry sz=%p, *max=%u, certificate_id=%p",
+		sz,
+		sz != NULL ? *max : 0,
+		(void *)certificate_id
+	);
+
+	if (sz != NULL) {
+		saved_max = n = *max;
+	}
+	*max = 0;
+
+	if (rv == CKR_OK) {
+		rv = pkcs11h_token_serializeTokenId (
+			sz,
+			&n,
+			certificate_id->token_id
+		);
+	}
+
+	if (rv == CKR_OK) {
+		_max = n + certificate_id->attrCKA_ID_size*2 + 1;
+	}
+
+	if (sz != NULL) {
+		if (saved_max < _max) {
+			rv = CKR_ATTRIBUTE_VALUE_INVALID;
+		}
+
+		if (rv == CKR_OK) {
+			sz[n-1] = '/';
+			rv = _pkcs11h_util_binaryToHex (
+				sz+n,
+				saved_max-n,
+				certificate_id->attrCKA_ID,
+				certificate_id->attrCKA_ID_size
+			);
+
+		}
+	}
+
+	*max = _max;
+
+	PKCS11H_DEBUG (
+		PKCS11H_LOG_DEBUG2,
+		"PKCS#11: pkcs11h_certificate_serializeCertificateId return rv=%ld-'%s', *max=%u, sz='%s'",
+		rv,
+		pkcs11h_getMessage (rv),
+		*max,
+		sz
+	);
+
+	return rv;
+}
+
+CK_RV
+pkcs11h_certificate_deserializeCertificateId (
+	OUT pkcs11h_certificate_id_t * const p_certificate_id,
+	IN const char * const sz
+) {
+	pkcs11h_certificate_id_t certificate_id = NULL;
+	CK_RV rv = CKR_OK;
+	char *p = NULL;
+	char *_sz = NULL;
+
+	PKCS11H_ASSERT (p_certificate_id!=NULL);
+	PKCS11H_ASSERT (sz!=NULL);
+
+	*p_certificate_id = NULL;
+
+	PKCS11H_DEBUG (
+		PKCS11H_LOG_DEBUG2,
+		"PKCS#11: pkcs11h_certificate_deserializeCertificateId entry p_certificate_id=%p, sz='%s'",
+		(void *)p_certificate_id,
+		sz
+	);
+
+	if (rv == CKR_OK) {
+		rv = _pkcs11h_mem_strdup (
+			(void *)&_sz,
+			sz
+		);
+	}
+
+	if (rv == CKR_OK) {
+		p = _sz;
+	}
+
+	if (rv == CKR_OK) {
+		rv = _pkcs11h_certificate_newCertificateId (&certificate_id);
+	}
+
+	if (
+		rv == CKR_OK &&
+		(p = strrchr (_sz, '/')) == NULL
+	) {
+		rv = CKR_ATTRIBUTE_VALUE_INVALID;
+	}
+
+	if (rv == CKR_OK) {
+		*p = '\x0';
+		p++;
+	}
+
+	if (rv == CKR_OK) {
+		rv = pkcs11h_token_deserializeTokenId (
+			&certificate_id->token_id,
+			_sz
+		);
+	}
+
+	if (rv == CKR_OK) {
+		certificate_id->attrCKA_ID_size = strlen (p)/2;
+	}
+
+	if (
+		rv == CKR_OK &&
+		(rv = _pkcs11h_mem_malloc (
+			(void *)&certificate_id->attrCKA_ID,
+			certificate_id->attrCKA_ID_size)
+		) == CKR_OK
+	) {
+		rv = _pkcs11h_util_hexToBinary (
+			certificate_id->attrCKA_ID,
+			p,
+			&certificate_id->attrCKA_ID_size
+		);
+	}
+
+	if (rv == CKR_OK) {
+		*p_certificate_id = certificate_id;
+		certificate_id = NULL;
+	}
+
+	if (certificate_id != NULL) {
+		pkcs11h_certificate_freeCertificateId (certificate_id);
+		certificate_id = NULL;
+	}
+
+	if (_sz != NULL) {
+		_pkcs11h_mem_free ((void *)&_sz);
+	}
+
+	PKCS11H_DEBUG (
+		PKCS11H_LOG_DEBUG2,
+		"PKCS#11: pkcs11h_certificate_deserializeCertificateId return rv=%ld-'%s'",
+		rv,
+		pkcs11h_getMessage (rv)
+	);
+
+	return rv;
+
+}
+
+#endif				/* ENABLE_PKCS11H_CERTIFICATE */
+
diff --git a/lib/pkcs11h-session.c b/lib/pkcs11h-session.c
new file mode 100644
index 0000000..9303673
--- /dev/null
+++ b/lib/pkcs11h-session.c
@@ -0,0 +1,1127 @@
+/*
+ * Copyright (c) 2005-2006 Alon Bar-Lev <alon.barlev at gmail.com>
+ * All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, or the OpenIB.org BSD license.
+ *
+ * GNU General Public License (GPL) Version 2
+ * ===========================================
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2
+ *  as published by the Free Software Foundation.
+ *
+ *  This program 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 General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program (see the file COPYING[.GPL2] included with this
+ *  distribution); if not, write to the Free Software Foundation, Inc.,
+ *  59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * OpenIB.org BSD license
+ * =======================
+ * Redistribution and use in source and binary forms, with or without modifi-
+ * cation, are permitted provided that the following conditions are met:
+ *
+ *   o  Redistributions of source code must retain the above copyright notice,
+ *      this list of conditions and the following disclaimer.
+ *
+ *   o  Redistributions in binary form must reproduce the above copyright no-
+ *      tice, this list of conditions and the following disclaimer in the do-
+ *      cumentation and/or other materials provided with the distribution.
+ *
+ *   o  The names of the contributors may not be used to endorse or promote
+ *      products derived from this software without specific prior written
+ *      permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``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 REGENTS OR CONTRIBUTORS BE LI-
+ * ABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUEN-
+ * TIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEV-
+ * ER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABI-
+ * LITY, 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.
+ */
+
+#include "common.h"
+
+#include <pkcs11-helper-1.0/pkcs11h-token.h>
+
+#include "_pkcs11h-sys.h"
+#include "_pkcs11h-mem.h"
+#include "_pkcs11h-token.h"
+#include "_pkcs11h-session.h"
+
+CK_RV
+_pkcs11h_session_getSlotList (
+	IN const pkcs11h_provider_t provider,
+	IN const CK_BBOOL token_present,
+	OUT CK_SLOT_ID_PTR * const pSlotList,
+	OUT CK_ULONG_PTR pulCount
+) {
+	CK_SLOT_ID_PTR _slots = NULL;
+	CK_ULONG _slotnum = 0;
+	CK_RV rv = CKR_OK;
+
+	PKCS11H_ASSERT (provider!=NULL);
+	PKCS11H_ASSERT (pSlotList!=NULL);
+	PKCS11H_ASSERT (pulCount!=NULL);
+
+	PKCS11H_DEBUG (
+		PKCS11H_LOG_DEBUG2,
+		"PKCS#11: _pkcs11h_session_getSlotList entry provider=%p, token_present=%d, pSlotList=%p, pulCount=%p",
+		(void *)provider,
+		token_present,
+		(void *)pSlotList,
+		(void *)pulCount
+	);
+
+	*pSlotList = NULL;
+	*pulCount = 0;
+
+	if (
+		rv == CKR_OK &&
+		!provider->enabled
+	) {
+		rv = CKR_CRYPTOKI_NOT_INITIALIZED;
+	}
+
+	if (rv == CKR_OK) {
+		rv = provider->f->C_GetSlotList (
+			token_present,
+			NULL_PTR,
+			&_slotnum
+		);
+	}
+
+	if (rv == CKR_OK && _slotnum > 0) {
+		rv = _pkcs11h_mem_malloc ((void *)&_slots, _slotnum * sizeof (CK_SLOT_ID));
+	}
+
+	if (rv == CKR_OK && _slotnum > 0) {
+		rv = provider->f->C_GetSlotList (
+			token_present,
+			_slots,
+			&_slotnum
+		);
+	}
+
+	if (rv == CKR_OK) {
+		*pSlotList = _slots;
+		_slots = NULL;
+		*pulCount = _slotnum;
+	}
+
+	if (_slots != NULL) {
+		_pkcs11h_mem_free ((void *)&_slots);
+	}
+
+	PKCS11H_DEBUG (
+		PKCS11H_LOG_DEBUG2,
+		"PKCS#11: _pkcs11h_session_getSlotList return rv=%ld-'%s' *pulCount=%ld",
+		rv,
+		pkcs11h_getMessage (rv),
+		*pulCount
+	);
+
+	return rv;
+}
+
+CK_RV
+_pkcs11h_session_getObjectAttributes (
+	IN const pkcs11h_session_t session,
+	IN const CK_OBJECT_HANDLE object,
+	IN OUT const CK_ATTRIBUTE_PTR attrs,
+	IN const unsigned count
+) {
+	/*
+	 * THREADING:
+	 * session->mutex must be locked
+	 */
+	CK_RV rv = CKR_OK;
+
+	PKCS11H_ASSERT (session!=NULL);
+	PKCS11H_ASSERT (attrs!=NULL);
+
+	PKCS11H_DEBUG (
+		PKCS11H_LOG_DEBUG2,
+		"PKCS#11: _pkcs11h_session_getObjectAttributes entry session=%p, object=%ld, attrs=%p, count=%u",
+		(void *)session,
+		object,
+		(void *)attrs,
+		count
+	);
+
+	if (
+		rv == CKR_OK &&
+		(rv = session->provider->f->C_GetAttributeValue (
+			session->session_handle,
+			object,
+			attrs,
+			count
+		)) == CKR_OK
+	) {
+		unsigned i;
+		for (i=0;rv == CKR_OK && i<count;i++) {
+			if (attrs[i].ulValueLen == (CK_ULONG)-1) {
+				rv = CKR_ATTRIBUTE_VALUE_INVALID;
+			}
+			else if (attrs[i].ulValueLen == 0) {
+				attrs[i].pValue = NULL;
+			}
+			else {
+				rv = _pkcs11h_mem_malloc (
+					(void *)&attrs[i].pValue,
+					attrs[i].ulValueLen
+				);
+			}
+		}
+	}
+
+	if (rv == CKR_OK) {
+		rv = session->provider->f->C_GetAttributeValue (
+			session->session_handle,
+			object,
+			attrs,
+			count
+		);
+	}
+
+	PKCS11H_DEBUG (
+		PKCS11H_LOG_DEBUG2,
+		"PKCS#11: _pkcs11h_session_getObjectAttributes return rv=%ld-'%s'",
+		rv,
+		pkcs11h_getMessage (rv)
+	);
+
+	return rv;
+}
+
+CK_RV
+_pkcs11h_session_freeObjectAttributes (
+	IN OUT const CK_ATTRIBUTE_PTR attrs,
+	IN const unsigned count
+) {
+	unsigned i;
+
+	CK_RV rv = CKR_OK;
+
+	PKCS11H_ASSERT (attrs!=NULL);
+
+	PKCS11H_DEBUG (
+		PKCS11H_LOG_DEBUG2,
+		"PKCS#11: _pkcs11h_session_freeObjectAttributes entry attrs=%p, count=%u",
+		(void *)attrs,
+		count
+	);
+
+	for (i=0;i<count;i++) {
+		if (attrs[i].pValue != NULL) {
+			_pkcs11h_mem_free ((void *)&attrs[i].pValue);
+			attrs[i].pValue = NULL;
+		}
+	}
+
+	PKCS11H_DEBUG (
+		PKCS11H_LOG_DEBUG2,
+		"PKCS#11: _pkcs11h_session_freeObjectAttributes return rv=%ld-'%s'",
+		rv,
+		pkcs11h_getMessage (rv)
+	);
+
+	return rv;
+}
+
+CK_RV
+_pkcs11h_session_findObjects (
+	IN const pkcs11h_session_t session,
+	IN const CK_ATTRIBUTE * const filter,
+	IN const CK_ULONG filter_attrs,
+	OUT CK_OBJECT_HANDLE **const p_objects,
+	OUT CK_ULONG *p_objects_found
+) {
+	/*
+	 * THREADING:
+	 * session->mutex must be locked
+	 */
+	PKCS11H_BOOL should_FindObjectsFinal = FALSE;
+
+	CK_OBJECT_HANDLE *objects = NULL;
+	CK_ULONG objects_size = 0;
+	CK_OBJECT_HANDLE objects_buffer[100];
+	CK_ULONG objects_found;
+	CK_OBJECT_HANDLE oLast = PKCS11H_INVALID_OBJECT_HANDLE;
+	CK_RV rv = CKR_OK;
+
+	PKCS11H_ASSERT (session!=NULL);
+	PKCS11H_ASSERT (!(filter==NULL && filter_attrs!=0) || filter!=NULL);
+	PKCS11H_ASSERT (p_objects!=NULL);
+	PKCS11H_ASSERT (p_objects_found!=NULL);
+	
+	PKCS11H_DEBUG (
+		PKCS11H_LOG_DEBUG2,
+		"PKCS#11: _pkcs11h_session_findObjects entry session=%p, filter=%p, filter_attrs=%ld, p_objects=%p, p_objects_found=%p",
+		(void *)session,
+		(void *)filter,
+		filter_attrs,
+		(void *)p_objects,
+		(void *)p_objects_found
+	);
+
+	*p_objects = NULL;
+	*p_objects_found = 0;
+
+	if (
+		rv == CKR_OK &&
+		(rv = session->provider->f->C_FindObjectsInit (
+			session->session_handle,
+			(CK_ATTRIBUTE *)filter,
+			filter_attrs
+		)) == CKR_OK
+	) {
+		should_FindObjectsFinal = TRUE;
+	}
+
+	while (
+		rv == CKR_OK &&
+		(rv = session->provider->f->C_FindObjects (
+			session->session_handle,
+			objects_buffer,
+			sizeof (objects_buffer) / sizeof (CK_OBJECT_HANDLE),
+			&objects_found
+		)) == CKR_OK &&
+		objects_found > 0
+	) { 
+		CK_OBJECT_HANDLE *temp = NULL;
+		
+		/*
+		 * Begin workaround
+		 *
+		 * Workaround iKey bug
+		 * It returns the same objects over and over
+		 */
+		if (oLast == objects_buffer[0]) {
+			PKCS11H_LOG (
+				PKCS11H_LOG_WARN,
+				"PKCS#11: Bad PKCS#11 C_FindObjects implementation detected, workaround applied"
+			);
+			break;
+		}
+		oLast = objects_buffer[0];
+		/* End workaround */
+		
+		if (
+			(rv = _pkcs11h_mem_malloc (
+				(void *)&temp,
+				(objects_size+objects_found) * sizeof (CK_OBJECT_HANDLE)
+			)) == CKR_OK
+		) {
+			if (objects != NULL) {
+				memmove (
+					temp,
+					objects,
+					objects_size * sizeof (CK_OBJECT_HANDLE)
+				);
+			}
+			memmove (
+				temp + objects_size,
+				objects_buffer,
+				objects_found * sizeof (CK_OBJECT_HANDLE)
+			);
+		}
+
+		if (objects != NULL) {
+			_pkcs11h_mem_free ((void *)&objects);
+			objects = NULL;
+		}
+
+		if (rv == CKR_OK) {
+			objects = temp;
+			objects_size += objects_found;
+			temp = NULL;
+		}
+
+		if (temp != NULL) {
+			_pkcs11h_mem_free ((void *)&temp);
+			temp = NULL;
+		}
+	}
+
+	if (should_FindObjectsFinal) {
+		session->provider->f->C_FindObjectsFinal (
+			session->session_handle
+		);
+		should_FindObjectsFinal = FALSE;
+	}
+	
+	if (rv == CKR_OK) {
+		*p_objects = objects;
+		*p_objects_found = objects_size;
+		objects = NULL;
+		objects_size = 0;
+	}
+
+	if (objects != NULL) {
+		_pkcs11h_mem_free ((void *)&objects);
+		objects = NULL;
+		objects_size = 0;
+	}
+
+	PKCS11H_DEBUG (
+		PKCS11H_LOG_DEBUG2,
+		"PKCS#11: _pkcs11h_session_findObjects return rv=%ld-'%s', *p_objects_found=%ld",
+		rv,
+		pkcs11h_getMessage (rv),
+		*p_objects_found
+	);
+
+	return rv;
+}
+
+CK_RV
+_pkcs11h_session_getSessionByTokenId (
+	IN const pkcs11h_token_id_t token_id,
+	OUT pkcs11h_session_t * const p_session
+) {
+#if defined(ENABLE_PKCS11H_THREADING)
+	PKCS11H_BOOL mutex_locked = FALSE;
+#endif
+	pkcs11h_session_t session = NULL;
+	PKCS11H_BOOL is_new_session = FALSE;
+	CK_RV rv = CKR_OK;
+
+	PKCS11H_ASSERT (token_id!=NULL);
+	PKCS11H_ASSERT (p_session!=NULL);
+
+	PKCS11H_DEBUG (
+		PKCS11H_LOG_DEBUG2,
+		"PKCS#11: _pkcs11h_session_getSessionByTokenId entry token_id=%p, p_session=%p",
+		(void *)token_id,
+		(void *)p_session
+	);
+
+	*p_session = NULL;
+
+#if defined(ENABLE_PKCS11H_THREADING)
+	if (
+		rv == CKR_OK &&
+		(rv = _pkcs11h_threading_mutexLock (&g_pkcs11h_data->mutexes.session)) == CKR_OK
+	) {
+		mutex_locked = TRUE;
+	}
+#endif
+
+	if (rv == CKR_OK) {
+		pkcs11h_session_t current_session;
+
+		for (
+			current_session = g_pkcs11h_data->sessions;
+			current_session != NULL && session == NULL;
+			current_session = current_session->next
+		) {
+			if (
+				pkcs11h_token_sameTokenId (
+					current_session->token_id,
+					token_id
+				)
+			) {
+				PKCS11H_DEBUG (
+					PKCS11H_LOG_DEBUG1,
+					"PKCS#11: Using cached session"
+				);
+				session = current_session;
+				session->reference_count++;
+			}
+		}
+	}
+
+	if (
+		rv == CKR_OK &&
+		session == NULL
+	) {
+		is_new_session = TRUE;
+	}
+
+	if (is_new_session) {
+		PKCS11H_DEBUG (
+			PKCS11H_LOG_DEBUG1,
+			"PKCS#11: Creating a new session"
+		);
+
+		if (
+			rv == CKR_OK &&
+			(rv = _pkcs11h_mem_malloc ((void *)&session, sizeof (struct pkcs11h_session_s))) == CKR_OK
+		) {
+			session->reference_count = 1;
+			session->session_handle = PKCS11H_INVALID_SESSION_HANDLE;
+			
+			session->pin_cache_period = g_pkcs11h_data->pin_cache_period;
+
+		}
+
+		if (rv == CKR_OK) {
+			rv = pkcs11h_token_duplicateTokenId (
+				&session->token_id,
+				token_id
+			);
+		}
+
+#if defined(ENABLE_PKCS11H_THREADING)
+		if (rv == CKR_OK) {
+			rv = _pkcs11h_threading_mutexInit (&session->mutex);
+		}
+#endif
+
+		if (rv == CKR_OK) {
+			session->valid = TRUE;
+			session->next = g_pkcs11h_data->sessions;
+			g_pkcs11h_data->sessions = session;
+		}
+		else {
+#if defined(ENABLE_PKCS11H_THREADING)
+			_pkcs11h_threading_mutexFree (&session->mutex);
+#endif
+			_pkcs11h_mem_free ((void *)&session);
+		}
+	}
+
+	if (rv == CKR_OK) {
+		*p_session = session;
+		session = NULL;
+	}
+
+#if defined(ENABLE_PKCS11H_THREADING)
+	if (mutex_locked) {
+		_pkcs11h_threading_mutexRelease (&g_pkcs11h_data->mutexes.session);
+		mutex_locked = FALSE;
+	}
+#endif
+
+	PKCS11H_DEBUG (
+		PKCS11H_LOG_DEBUG2,
+		"PKCS#11: _pkcs11h_session_getSessionByTokenId return rv=%ld-'%s', *p_session=%p",
+		rv,
+		pkcs11h_getMessage (rv),
+		(void *)*p_session
+	);
+
+	return rv;
+}
+
+CK_RV
+_pkcs11h_session_release (
+	IN const pkcs11h_session_t session
+) {
+#if defined(ENABLE_PKCS11H_THREADING)
+	PKCS11H_BOOL mutex_locked = FALSE;
+#endif
+	CK_RV rv = CKR_OK;
+
+	PKCS11H_ASSERT (session!=NULL);
+	PKCS11H_ASSERT (session->reference_count>=0);
+
+	PKCS11H_DEBUG (
+		PKCS11H_LOG_DEBUG2,
+		"PKCS#11: _pkcs11h_session_release entry session=%p",
+		(void *)session
+	);
+
+#if defined(ENABLE_PKCS11H_THREADING)
+	if (
+		rv == CKR_OK &&
+		(rv = _pkcs11h_threading_mutexLock (&session->mutex)) == CKR_OK
+	) {
+		mutex_locked = TRUE;
+	}
+#endif
+
+	/*
+	 * Never logout for now
+	 */
+	if (rv == CKR_OK) {
+		if (session->reference_count > 0) {
+			session->reference_count--;
+		}
+	}
+
+#if defined(ENABLE_PKCS11H_THREADING)
+	if (mutex_locked) {
+		_pkcs11h_threading_mutexRelease (&session->mutex);
+		mutex_locked = FALSE;
+	}
+#endif
+
+	PKCS11H_DEBUG (
+		PKCS11H_LOG_DEBUG2,
+		"PKCS#11: _pkcs11h_session_release return rv=%ld-'%s'",
+		rv,
+		pkcs11h_getMessage (rv)
+	);
+
+	return rv;
+}
+
+CK_RV
+_pkcs11h_session_reset (
+	IN const pkcs11h_session_t session,
+	IN void * const user_data,
+	IN const unsigned mask_prompt,
+	OUT CK_SLOT_ID * const p_slot
+) {
+	PKCS11H_BOOL found = FALSE;
+
+	CK_RV rv = CKR_OK;
+
+	unsigned nRetry = 0;
+
+	PKCS11H_ASSERT (session!=NULL);
+	/*PKCS11H_ASSERT (user_data) NOT NEEDED */
+	PKCS11H_ASSERT (p_slot!=NULL);
+
+	PKCS11H_DEBUG (
+		PKCS11H_LOG_DEBUG2,
+		"PKCS#11: _pkcs11h_session_reset entry session=%p, user_data=%p, mask_prompt=%08x, p_slot=%p",
+		(void *)session,
+		user_data,
+		mask_prompt,
+		(void *)p_slot
+	);
+
+	*p_slot = PKCS11H_INVALID_SLOT_ID;
+
+	while (
+		rv == CKR_OK &&
+		!found
+	) {
+		pkcs11h_provider_t current_provider = NULL;
+
+		for (
+			current_provider = g_pkcs11h_data->providers;
+			(
+				rv == CKR_OK &&
+				current_provider != NULL &&
+				!found
+			);
+			current_provider = current_provider->next
+		) {
+			CK_SLOT_ID_PTR slots = NULL;
+			CK_ULONG slotnum;
+			CK_SLOT_ID slot_index;
+
+			/*
+			 * Skip all other providers,
+			 * if one was set in the past
+			 */
+			if (
+				session->provider != NULL &&
+				session->provider != current_provider
+			) {
+				rv = CKR_CANCEL;
+			}
+		
+			if (rv == CKR_OK) {
+				rv = _pkcs11h_session_getSlotList (
+					current_provider,
+					CK_TRUE,
+					&slots,
+					&slotnum
+				);
+			}
+
+			for (
+				slot_index=0;
+				(
+					slot_index < slotnum &&
+					rv == CKR_OK && 
+					!found
+				);
+				slot_index++
+			) {
+				pkcs11h_token_id_t token_id = NULL;
+				CK_TOKEN_INFO info;
+
+				if (rv == CKR_OK) {
+					rv = current_provider->f->C_GetTokenInfo (
+						slots[slot_index],
+						&info
+					);
+				}
+
+				if (
+					rv == CKR_OK &&
+					(rv = _pkcs11h_token_getTokenId (
+						&info,
+						&token_id
+					)) == CKR_OK &&
+					pkcs11h_token_sameTokenId (
+						session->token_id,
+						token_id
+					)
+				) {
+					found = TRUE;
+					*p_slot = slots[slot_index];
+					if (session->provider == NULL) {
+						session->provider = current_provider;
+						session->allow_protected_auth_supported = (info.flags & CKF_PROTECTED_AUTHENTICATION_PATH) != 0;
+					}
+				}
+
+				if (rv != CKR_OK) {
+					PKCS11H_DEBUG (
+						PKCS11H_LOG_DEBUG1,
+						"PKCS#11: Cannot get token information for provider '%s' slot %ld rv=%ld-'%s'",
+						current_provider->manufacturerID,
+						slots[slot_index],
+						rv,
+						pkcs11h_getMessage (rv)
+					);
+
+					/*
+					 * Ignore error
+					 */
+					rv = CKR_OK;
+				}
+
+				if (token_id != NULL) {
+					pkcs11h_token_freeTokenId (token_id);
+				}
+			}
+
+			if (rv != CKR_OK) {
+				PKCS11H_DEBUG (
+					PKCS11H_LOG_DEBUG1,
+					"PKCS#11: Cannot get slot list for provider '%s' rv=%ld-'%s'",
+					current_provider->manufacturerID,
+					rv,
+					pkcs11h_getMessage (rv)
+				);
+
+				/*
+				 * Ignore error
+				 */
+				rv = CKR_OK;
+			}
+
+			if (slots != NULL) {
+				_pkcs11h_mem_free ((void *)&slots);
+				slots = NULL;
+			}
+		}
+
+		if (rv == CKR_OK && !found && (mask_prompt & PKCS11H_PROMPT_MASK_ALLOW_TOKEN_PROMPT) == 0) {
+			rv = CKR_TOKEN_NOT_PRESENT;
+		}
+
+		if (
+			rv == CKR_OK &&
+			!found
+		) {
+			PKCS11H_DEBUG (
+				PKCS11H_LOG_DEBUG1,
+				"PKCS#11: Calling token_prompt hook for '%s'",
+				session->token_id->display
+			);
+	
+			if (
+				!g_pkcs11h_data->hooks.token_prompt (
+					g_pkcs11h_data->hooks.token_prompt_data,
+					user_data,
+					session->token_id,
+					nRetry++
+				)
+			) {
+				rv = CKR_CANCEL;
+			}
+
+			PKCS11H_DEBUG (
+				PKCS11H_LOG_DEBUG1,
+				"PKCS#11: token_prompt returned %ld",
+				rv
+			);
+		}
+	}
+
+	PKCS11H_DEBUG (
+		PKCS11H_LOG_DEBUG2,
+		"PKCS#11: _pkcs11h_session_reset return rv=%ld-'%s', *p_slot=%ld",
+		rv,
+		pkcs11h_getMessage (rv),
+		*p_slot
+	);
+
+	return rv;
+}
+
+CK_RV
+_pkcs11h_session_getObjectById (
+	IN const pkcs11h_session_t session,
+	IN const CK_OBJECT_CLASS class,
+	IN const CK_BYTE_PTR id,
+	IN const size_t id_size,
+	OUT CK_OBJECT_HANDLE * const p_handle
+) {
+	/*
+	 * THREADING:
+	 * session->mutex must be locked
+	 */
+	CK_ATTRIBUTE filter[] = {
+		{CKA_CLASS, (void *)&class, sizeof (class)},
+		{CKA_ID, (void *)id, id_size}
+	};
+	CK_OBJECT_HANDLE *objects = NULL;
+	CK_ULONG objects_found = 0;
+	CK_RV rv = CKR_OK;
+	
+	/*PKCS11H_ASSERT (session!=NULL); NOT NEEDED*/
+	PKCS11H_ASSERT (id!=NULL);
+	PKCS11H_ASSERT (p_handle!=NULL);
+
+	PKCS11H_DEBUG (
+		PKCS11H_LOG_DEBUG2,
+		"PKCS#11: _pkcs11h_session_getObjectById entry session=%p, class=%ld, id=%p, id_size=%u, p_handle=%p",
+		(void *)session,
+		class,
+		id,
+		id_size,
+		(void *)p_handle
+	);
+
+	*p_handle = PKCS11H_INVALID_OBJECT_HANDLE;
+
+	if (rv == CKR_OK) {
+		rv = _pkcs11h_session_validate (session);
+	}
+
+	if (rv == CKR_OK) { 
+		rv = _pkcs11h_session_findObjects (
+			session,
+			filter,
+			sizeof (filter) / sizeof (CK_ATTRIBUTE),
+			&objects,
+			&objects_found
+		);
+	}
+
+	if (
+		rv == CKR_OK &&
+		objects_found == 0
+	) {
+		rv = CKR_FUNCTION_REJECTED;
+	}
+
+	if (rv == CKR_OK) {
+		*p_handle = objects[0];
+	}
+
+	if (objects != NULL) {
+		_pkcs11h_mem_free ((void *)&objects);
+	}
+
+	PKCS11H_DEBUG (
+		PKCS11H_LOG_DEBUG2,
+		"PKCS#11: _pkcs11h_session_getObjectById return rv=%ld-'%s', *p_handle=%08lx",
+		rv,
+		pkcs11h_getMessage (rv),
+		(unsigned long)*p_handle
+	);
+
+	return rv;
+}
+
+CK_RV
+_pkcs11h_session_validate (
+	IN const pkcs11h_session_t session
+) {
+	CK_RV rv = CKR_OK;
+
+	/*PKCS11H_ASSERT (session!=NULL); NOT NEEDED*/
+
+	PKCS11H_DEBUG (
+		PKCS11H_LOG_DEBUG2,
+		"PKCS#11: _pkcs11h_session_validate entry session=%p",
+		(void *)session
+	);
+
+	if (
+		rv == CKR_OK &&
+		session == NULL
+	) {
+		rv = CKR_SESSION_HANDLE_INVALID;
+	}
+
+	if (
+		rv == CKR_OK &&
+		(
+			session->provider == NULL ||
+			!session->provider->enabled ||
+			session->session_handle == PKCS11H_INVALID_SESSION_HANDLE
+		)
+	) {
+		rv = CKR_SESSION_HANDLE_INVALID;
+	}
+
+	if (
+		rv == CKR_OK &&
+		session->pin_expire_time != (time_t)0 &&
+		session->pin_expire_time < g_pkcs11h_sys_engine.time ()
+	) {
+		PKCS11H_DEBUG (
+			PKCS11H_LOG_DEBUG1,
+			"PKCS#11: Forcing logout due to pin timeout"
+		);
+		_pkcs11h_session_logout (session);
+		rv = CKR_SESSION_HANDLE_INVALID;
+	}
+
+	PKCS11H_DEBUG (
+		PKCS11H_LOG_DEBUG2,
+		"PKCS#11: _pkcs11h_session_validate return rv=%ld-'%s'",
+		rv,
+		pkcs11h_getMessage (rv)
+	);
+
+	return rv;
+}
+
+CK_RV
+_pkcs11h_session_touch (
+	IN const pkcs11h_session_t session
+) {
+	/*
+	 * THREADING:
+	 * session->mutex must be locked
+	 */
+	PKCS11H_ASSERT (session!=NULL);
+
+	if (session->pin_cache_period == PKCS11H_PIN_CACHE_INFINITE) {
+		session->pin_expire_time = 0;
+	}
+	else {
+		session->pin_expire_time = (
+			g_pkcs11h_sys_engine.time () +
+			(time_t)session->pin_cache_period
+		);
+	}
+
+	return CKR_OK;
+}
+
+CK_RV
+_pkcs11h_session_login (
+	IN const pkcs11h_session_t session,
+	IN const PKCS11H_BOOL is_publicOnly,
+	IN const PKCS11H_BOOL readonly,
+	IN void * const user_data,
+	IN const unsigned mask_prompt
+) {
+	/*
+	 * THREADING:
+	 * session->mutex must be locked
+	 */
+	CK_SLOT_ID slot = PKCS11H_INVALID_SLOT_ID;
+	CK_RV rv = CKR_OK;
+
+	PKCS11H_ASSERT (session!=NULL);
+	/*PKCS11H_ASSERT (user_data) NOT NEEDED */
+
+	PKCS11H_DEBUG (
+		PKCS11H_LOG_DEBUG2,
+		"PKCS#11: _pkcs11h_session_login entry session=%p, is_publicOnly=%d, readonly=%d, user_data=%p, mask_prompt=%08x",
+		(void *)session,
+		is_publicOnly ? 1 : 0,
+		readonly ? 1 : 0,
+		user_data,
+		mask_prompt
+	);
+
+	if (rv == CKR_OK) {
+		rv = _pkcs11h_session_logout (session);
+	}
+
+	if (rv == CKR_OK) {
+		rv = _pkcs11h_session_reset (session, user_data, mask_prompt, &slot);
+	}
+
+	if (rv == CKR_OK) {
+		rv = session->provider->f->C_OpenSession (
+			slot,
+			(
+				CKF_SERIAL_SESSION |
+				(readonly ? 0 : CKF_RW_SESSION)
+			),
+			NULL_PTR,
+			NULL_PTR,
+			&session->session_handle
+		);
+	}
+
+	if (
+		rv == CKR_OK &&
+	   	(
+			!is_publicOnly ||
+			session->provider->cert_is_private
+		)
+	) {
+		PKCS11H_BOOL login_succeeded = FALSE;
+		unsigned nRetryCount = 0;
+
+		if ((mask_prompt & PKCS11H_PROMPT_MASK_ALLOW_PIN_PROMPT) == 0) {
+			rv = CKR_USER_NOT_LOGGED_IN;
+
+			PKCS11H_DEBUG (
+				PKCS11H_LOG_DEBUG1,
+				"PKCS#11: Calling pin_prompt hook denied because of prompt mask"
+			);
+		}
+
+		while (
+			rv == CKR_OK &&
+			!login_succeeded &&
+			nRetryCount < g_pkcs11h_data->max_retries 
+		) {
+			CK_UTF8CHAR_PTR utfPIN = NULL;
+			CK_ULONG lPINLength = 0;
+			char pin[1024];
+
+			if (
+				rv == CKR_OK &&
+				!(
+					g_pkcs11h_data->allow_protected_auth  &&
+					session->provider->allow_protected_auth &&
+					session->allow_protected_auth_supported
+				)
+			) {
+				PKCS11H_DEBUG (
+					PKCS11H_LOG_DEBUG1,
+					"PKCS#11: Calling pin_prompt hook for '%s'",
+					session->token_id->display
+				);
+
+				if (
+					!g_pkcs11h_data->hooks.pin_prompt (
+						g_pkcs11h_data->hooks.pin_prompt_data,
+						user_data,
+						session->token_id,
+						nRetryCount,
+						pin,
+						sizeof (pin)
+					)
+				) {
+					rv = CKR_CANCEL;
+				}
+				else {
+					utfPIN = (CK_UTF8CHAR_PTR)pin;
+					lPINLength = strlen (pin);
+				}
+
+				PKCS11H_DEBUG (
+					PKCS11H_LOG_DEBUG1,
+					"PKCS#11: pin_prompt hook return rv=%ld",
+					rv
+				);
+			}
+
+			if (rv == CKR_OK) {
+				rv = _pkcs11h_session_touch (session);
+			}
+
+			if (
+				rv == CKR_OK &&
+				(rv = session->provider->f->C_Login (
+					session->session_handle,
+					CKU_USER,
+					utfPIN,
+					lPINLength
+				)) != CKR_OK
+			) {
+				if (rv == CKR_USER_ALREADY_LOGGED_IN) {
+					rv = CKR_OK;
+				}
+			}
+
+			/*
+			 * Clean PIN buffer
+			 */
+			memset (pin, 0, sizeof (pin));
+
+			if (rv == CKR_OK) {
+				login_succeeded = TRUE;
+			}
+			else if (
+				rv == CKR_PIN_INCORRECT ||
+				rv == CKR_PIN_INVALID
+			) {
+				/*
+				 * Ignore these errors
+				 * so retry can be performed
+				 */
+				rv = CKR_OK;
+			}
+
+			nRetryCount++;
+		}
+
+		/*
+		 * Retry limit
+		 */
+		if (!login_succeeded && rv == CKR_OK) {
+			rv = CKR_PIN_INCORRECT;
+		}
+	}
+
+	PKCS11H_DEBUG (
+		PKCS11H_LOG_DEBUG2,
+		"PKCS#11: _pkcs11h_session_login return rv=%ld-'%s'",
+		rv,
+		pkcs11h_getMessage (rv)
+	);
+
+	return rv;
+}
+
+CK_RV
+_pkcs11h_session_logout (
+	IN const pkcs11h_session_t session
+) {
+	/*
+	 * THREADING:
+	 * session->mutex must be locked
+	 */
+	/*PKCS11H_ASSERT (session!=NULL); NOT NEEDED*/
+
+	PKCS11H_DEBUG (
+		PKCS11H_LOG_DEBUG2,
+		"PKCS#11: _pkcs11h_session_logout entry session=%p",
+		(void *)session
+	);
+
+	if (
+		session != NULL &&
+		session->session_handle != PKCS11H_INVALID_SESSION_HANDLE
+	) {
+		CK_RV rv = CKR_OK;
+
+		if (rv == CKR_OK) {
+			if (session->provider != NULL) {
+				session->provider->f->C_Logout (session->session_handle);
+				session->provider->f->C_CloseSession (session->session_handle);
+			}
+			session->session_handle = PKCS11H_INVALID_SESSION_HANDLE;
+		}
+	}
+
+	PKCS11H_DEBUG (
+		PKCS11H_LOG_DEBUG2,
+		"PKCS#11: _pkcs11h_session_logout return"
+	);
+
+	return CKR_OK;
+}
+
diff --git a/lib/pkcs11h-slotevent.c b/lib/pkcs11h-slotevent.c
new file mode 100644
index 0000000..f203e7b
--- /dev/null
+++ b/lib/pkcs11h-slotevent.c
@@ -0,0 +1,485 @@
+/*
+ * Copyright (c) 2005-2006 Alon Bar-Lev <alon.barlev at gmail.com>
+ * All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, or the OpenIB.org BSD license.
+ *
+ * GNU General Public License (GPL) Version 2
+ * ===========================================
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2
+ *  as published by the Free Software Foundation.
+ *
+ *  This program 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 General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program (see the file COPYING[.GPL2] included with this
+ *  distribution); if not, write to the Free Software Foundation, Inc.,
+ *  59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * OpenIB.org BSD license
+ * =======================
+ * Redistribution and use in source and binary forms, with or without modifi-
+ * cation, are permitted provided that the following conditions are met:
+ *
+ *   o  Redistributions of source code must retain the above copyright notice,
+ *      this list of conditions and the following disclaimer.
+ *
+ *   o  Redistributions in binary form must reproduce the above copyright no-
+ *      tice, this list of conditions and the following disclaimer in the do-
+ *      cumentation and/or other materials provided with the distribution.
+ *
+ *   o  The names of the contributors may not be used to endorse or promote
+ *      products derived from this software without specific prior written
+ *      permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``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 REGENTS OR CONTRIBUTORS BE LI-
+ * ABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUEN-
+ * TIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEV-
+ * ER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABI-
+ * LITY, 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.
+ */
+
+#include "common.h"
+
+#if defined(ENABLE_PKCS11H_SLOTEVENT)
+
+#include "_pkcs11h-mem.h"
+#include "_pkcs11h-session.h"
+#include "_pkcs11h-slotevent.h"
+
+static
+unsigned long
+__pkcs11h_slotevent_checksum (
+	IN const unsigned char * const p,
+	IN const size_t s
+);
+
+static
+void *
+__pkcs11h_slotevent_provider (
+	IN void *p
+);
+
+static
+void *
+__pkcs11h_slotevent_manager (
+	IN void *p
+);
+
+static
+unsigned long
+__pkcs11h_slotevent_checksum (
+	IN const unsigned char * const p,
+	IN const size_t s
+) {
+	unsigned long r = 0;
+	size_t i;
+	for (i=0;i<s;i++) {
+		r += p[i];
+	}
+	return r;
+}
+
+static
+void *
+__pkcs11h_slotevent_provider (
+	IN void *p
+) {
+	pkcs11h_provider_t provider = (pkcs11h_provider_t)p;
+	CK_SLOT_ID slot;
+	CK_RV rv = CKR_OK;
+
+	PKCS11H_DEBUG (
+		PKCS11H_LOG_DEBUG2,
+		"PKCS#11: __pkcs11h_slotevent_provider provider='%s' entry",
+		provider->manufacturerID
+	);
+
+	if (rv == CKR_OK && !provider->enabled) {
+		rv = CKR_OPERATION_NOT_INITIALIZED;
+	}
+
+	if (rv == CKR_OK) {
+
+		if (provider->slot_poll_interval == 0) {
+			provider->slot_poll_interval = PKCS11H_DEFAULT_SLOTEVENT_POLL;
+		}
+
+		/*
+		 * If we cannot finalize, we cannot cause
+		 * WaitForSlotEvent to terminate
+		 */
+		if (!provider->should_finalize) {
+			PKCS11H_DEBUG (
+				PKCS11H_LOG_DEBUG1,
+				"PKCS#11: Setup slotevent provider='%s' mode hardset to poll",
+				provider->manufacturerID
+			);
+			provider->slot_event_method = PKCS11H_SLOTEVENT_METHOD_POLL;
+		}
+
+		if (
+			provider->slot_event_method == PKCS11H_SLOTEVENT_METHOD_AUTO ||
+			provider->slot_event_method == PKCS11H_SLOTEVENT_METHOD_TRIGGER
+		) { 
+			if (
+				provider->f->C_WaitForSlotEvent (
+					CKF_DONT_BLOCK,
+					&slot,
+					NULL_PTR
+				) == CKR_FUNCTION_NOT_SUPPORTED
+			) {
+				PKCS11H_DEBUG (
+					PKCS11H_LOG_DEBUG1,
+					"PKCS#11: Setup slotevent provider='%s' mode is poll",
+					provider->manufacturerID
+				);
+
+				provider->slot_event_method = PKCS11H_SLOTEVENT_METHOD_POLL;
+			}
+			else {
+				PKCS11H_DEBUG (
+					PKCS11H_LOG_DEBUG1,
+					"PKCS#11: Setup slotevent provider='%s' mode is trigger",
+					provider->manufacturerID
+				);
+
+				provider->slot_event_method = PKCS11H_SLOTEVENT_METHOD_TRIGGER;
+			}
+		}
+	}
+
+	if (provider->slot_event_method == PKCS11H_SLOTEVENT_METHOD_TRIGGER) {
+		while (
+			!g_pkcs11h_data->slotevent.should_terminate &&
+			provider->enabled &&
+			rv == CKR_OK &&
+			(rv = provider->f->C_WaitForSlotEvent (
+				0,
+				&slot,
+				NULL_PTR
+			)) == CKR_OK
+		) {
+			PKCS11H_DEBUG (
+				PKCS11H_LOG_DEBUG1,
+				"PKCS#11: Slotevent provider='%s' event",
+				provider->manufacturerID
+			);
+
+			_pkcs11h_threading_condSignal (&g_pkcs11h_data->slotevent.cond_event);
+		}
+	}
+	else {
+		unsigned long ulLastChecksum = 0;
+		PKCS11H_BOOL is_first_time = TRUE;
+
+		while (
+			!g_pkcs11h_data->slotevent.should_terminate &&
+			provider->enabled &&
+			rv == CKR_OK
+		) {
+			unsigned long ulCurrentChecksum = 0;
+
+			CK_SLOT_ID_PTR slots = NULL;
+			CK_ULONG slotnum;
+
+			PKCS11H_DEBUG (
+				PKCS11H_LOG_DEBUG1,
+				"PKCS#11: Slotevent provider='%s' poll",
+				provider->manufacturerID
+			);
+
+			if (
+				rv == CKR_OK &&
+				(rv = _pkcs11h_session_getSlotList (
+					provider,
+					TRUE,
+					&slots,
+					&slotnum
+				)) == CKR_OK
+			) {
+				CK_ULONG i;
+				
+				for (i=0;i<slotnum;i++) {
+					CK_TOKEN_INFO info;
+
+					if (provider->f->C_GetTokenInfo (slots[i], &info) == CKR_OK) {
+						ulCurrentChecksum += (
+							__pkcs11h_slotevent_checksum (
+								info.label,
+								sizeof (info.label)
+							) +
+							__pkcs11h_slotevent_checksum (
+								info.manufacturerID,
+								sizeof (info.manufacturerID)
+							) +
+							__pkcs11h_slotevent_checksum (
+								info.model,
+								sizeof (info.model)
+							) +
+							__pkcs11h_slotevent_checksum (
+								info.serialNumber,
+								sizeof (info.serialNumber)
+							)
+						);
+					}
+				}
+			}
+			
+			if (rv == CKR_OK) {
+				if (is_first_time) {
+					is_first_time = FALSE;
+				}
+				else {
+					if (ulLastChecksum != ulCurrentChecksum) {
+						PKCS11H_DEBUG (
+							PKCS11H_LOG_DEBUG1,
+							"PKCS#11: Slotevent provider='%s' event",
+							provider->manufacturerID
+						);
+
+						_pkcs11h_threading_condSignal (&g_pkcs11h_data->slotevent.cond_event);
+					}
+				}
+				ulLastChecksum = ulCurrentChecksum;
+			}
+
+			if (slots != NULL) {
+				_pkcs11h_mem_free ((void *)&slots);
+			}
+			
+			if (!g_pkcs11h_data->slotevent.should_terminate) {
+				_pkcs11h_threading_sleep (provider->slot_poll_interval);
+			}
+		}
+	}
+
+	PKCS11H_DEBUG (
+		PKCS11H_LOG_DEBUG2,
+		"PKCS#11: __pkcs11h_slotevent_provider provider='%s' return",
+		provider->manufacturerID
+	);
+
+	return NULL;
+}
+
+static
+void *
+__pkcs11h_slotevent_manager (
+	IN void *p
+) {
+	PKCS11H_BOOL first_time = TRUE;
+
+	(void)p;
+
+	PKCS11H_DEBUG (
+		PKCS11H_LOG_DEBUG2,
+		"PKCS#11: __pkcs11h_slotevent_manager entry"
+	);
+
+	/*
+	 * Trigger hook, so application may
+	 * depend on initial slot change
+	 */
+	PKCS11H_DEBUG (
+		PKCS11H_LOG_DEBUG1,
+		"PKCS#11: Calling slotevent hook"
+	);
+	g_pkcs11h_data->hooks.slotevent (g_pkcs11h_data->hooks.slotevent_data);
+
+	while (
+		first_time ||	/* Must enter wait or mutex will never be free */
+		!g_pkcs11h_data->slotevent.should_terminate
+	) {
+		pkcs11h_provider_t current_provider;
+
+		first_time = FALSE;
+
+		/*
+		 * Start each provider thread
+		 * if not already started.
+		 * This is required in order to allow
+		 * adding new providers.
+		 */
+		PKCS11H_DEBUG (
+			PKCS11H_LOG_DEBUG2,
+			"PKCS#11: __pkcs11h_slotevent_manager examine provider list"
+		);
+		for (
+			current_provider = g_pkcs11h_data->providers;
+			current_provider != NULL;
+			current_provider = current_provider->next
+		) {
+			if (current_provider->enabled) {
+				if (current_provider->slotevent_thread == PKCS11H_THREAD_NULL) {
+					PKCS11H_DEBUG (
+						PKCS11H_LOG_DEBUG2,
+						"PKCS#11: __pkcs11h_slotevent_manager found enabled provider without thread"
+					);
+					_pkcs11h_threading_threadStart (
+						&current_provider->slotevent_thread,
+						__pkcs11h_slotevent_provider,
+						current_provider
+					);
+				}
+			}
+			else {
+				if (current_provider->slotevent_thread != PKCS11H_THREAD_NULL) {
+					PKCS11H_DEBUG (
+						PKCS11H_LOG_DEBUG2,
+						"PKCS#11: __pkcs11h_slotevent_manager found disabled provider with thread"
+					);
+					_pkcs11h_threading_threadJoin (&current_provider->slotevent_thread);
+				}
+			}
+		}
+
+		PKCS11H_DEBUG (
+			PKCS11H_LOG_DEBUG2,
+			"PKCS#11: __pkcs11h_slotevent_manager waiting for slotevent"
+		);
+		_pkcs11h_threading_condWait (&g_pkcs11h_data->slotevent.cond_event, PKCS11H_COND_INFINITE);
+
+		if (g_pkcs11h_data->slotevent.skip_event) {
+			PKCS11H_DEBUG (
+				PKCS11H_LOG_DEBUG1,
+				"PKCS#11: Slotevent skipping event"
+			);
+			g_pkcs11h_data->slotevent.skip_event = FALSE;
+		}
+		else {
+			PKCS11H_DEBUG (
+				PKCS11H_LOG_DEBUG1,
+				"PKCS#11: Calling slotevent hook"
+			);
+			g_pkcs11h_data->hooks.slotevent (g_pkcs11h_data->hooks.slotevent_data);
+		}
+	}
+
+	{
+		pkcs11h_provider_t current_provider;
+
+		PKCS11H_DEBUG (
+			PKCS11H_LOG_DEBUG2,
+			"PKCS#11: __pkcs11h_slotevent_manager joining threads"
+		);
+
+
+		for (
+			current_provider = g_pkcs11h_data->providers;
+			current_provider != NULL;
+			current_provider = current_provider->next
+		) {
+			if (current_provider->slotevent_thread != PKCS11H_THREAD_NULL) {
+				_pkcs11h_threading_threadJoin (&current_provider->slotevent_thread);
+			}
+		}
+	}
+
+	PKCS11H_DEBUG (
+		PKCS11H_LOG_DEBUG2,
+		"PKCS#11: __pkcs11h_slotevent_manager return"
+	);
+
+	return NULL;
+}
+
+CK_RV
+_pkcs11h_slotevent_init (void) {
+	CK_RV rv = CKR_OK;
+
+	PKCS11H_DEBUG (
+		PKCS11H_LOG_DEBUG2,
+		"PKCS#11: _pkcs11h_slotevent_init entry"
+	);
+
+	if (!g_pkcs11h_data->slotevent.initialized) {
+		if (rv == CKR_OK) {
+			rv = _pkcs11h_threading_condInit (&g_pkcs11h_data->slotevent.cond_event);
+		}
+		
+		if (rv == CKR_OK) {
+			rv = _pkcs11h_threading_threadStart (
+				&g_pkcs11h_data->slotevent.thread,
+				__pkcs11h_slotevent_manager,
+				NULL
+			);
+		}
+		
+		if (rv == CKR_OK) {
+			g_pkcs11h_data->slotevent.initialized = TRUE;
+		}
+	}
+
+	PKCS11H_DEBUG (
+		PKCS11H_LOG_DEBUG2,
+		"PKCS#11: _pkcs11h_slotevent_init return rv=%ld-'%s'",
+		rv,
+		pkcs11h_getMessage (rv)
+	);
+
+	return rv;
+}
+
+CK_RV
+_pkcs11h_slotevent_notify (void) {
+	
+	PKCS11H_DEBUG (
+		PKCS11H_LOG_DEBUG2,
+		"PKCS#11: _pkcs11h_slotevent_notify entry"
+	);
+
+	if (g_pkcs11h_data->slotevent.initialized) {
+		g_pkcs11h_data->slotevent.skip_event = TRUE;
+		_pkcs11h_threading_condSignal (&g_pkcs11h_data->slotevent.cond_event);
+	}
+
+	PKCS11H_DEBUG (
+		PKCS11H_LOG_DEBUG2,
+		"PKCS#11: _pkcs11h_slotevent_notify return"
+	);
+
+	return CKR_OK;
+}
+
+CK_RV
+_pkcs11h_slotevent_terminate (void) {
+	
+	PKCS11H_DEBUG (
+		PKCS11H_LOG_DEBUG2,
+		"PKCS#11: _pkcs11h_slotevent_terminate entry"
+	);
+
+	if (g_pkcs11h_data->slotevent.initialized) {
+		g_pkcs11h_data->slotevent.should_terminate = TRUE;
+
+		_pkcs11h_slotevent_notify ();
+
+		if (g_pkcs11h_data->slotevent.thread != PKCS11H_THREAD_NULL) {
+			_pkcs11h_threading_threadJoin (&g_pkcs11h_data->slotevent.thread);
+		}
+
+		_pkcs11h_threading_condFree (&g_pkcs11h_data->slotevent.cond_event);
+		g_pkcs11h_data->slotevent.initialized = FALSE;
+	}
+
+	PKCS11H_DEBUG (
+		PKCS11H_LOG_DEBUG2,
+		"PKCS#11: _pkcs11h_slotevent_terminate return"
+	);
+
+	return CKR_OK;
+}
+
+#endif
diff --git a/lib/pkcs11h-standalone.c b/lib/pkcs11h-standalone.c
new file mode 100644
index 0000000..a66d42a
--- /dev/null
+++ b/lib/pkcs11h-standalone.c
@@ -0,0 +1,857 @@
+/*
+ * Copyright (c) 2005-2006 Alon Bar-Lev <alon.barlev at gmail.com>
+ * All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, or the OpenIB.org BSD license.
+ *
+ * GNU General Public License (GPL) Version 2
+ * ===========================================
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2
+ *  as published by the Free Software Foundation.
+ *
+ *  This program 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 General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program (see the file COPYING[.GPL2] included with this
+ *  distribution); if not, write to the Free Software Foundation, Inc.,
+ *  59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * OpenIB.org BSD license
+ * =======================
+ * Redistribution and use in source and binary forms, with or without modifi-
+ * cation, are permitted provided that the following conditions are met:
+ *
+ *   o  Redistributions of source code must retain the above copyright notice,
+ *      this list of conditions and the following disclaimer.
+ *
+ *   o  Redistributions in binary form must reproduce the above copyright no-
+ *      tice, this list of conditions and the following disclaimer in the do-
+ *      cumentation and/or other materials provided with the distribution.
+ *
+ *   o  The names of the contributors may not be used to endorse or promote
+ *      products derived from this software without specific prior written
+ *      permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``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 REGENTS OR CONTRIBUTORS BE LI-
+ * ABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUEN-
+ * TIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEV-
+ * ER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABI-
+ * LITY, 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.
+ */
+
+#include "common.h"
+
+#if defined(ENABLE_PKCS11H_STANDALONE)
+
+#include "_pkcs11h-mem.h"
+#include "_pkcs11h-core.h"
+#include "_pkcs11h-util.h"
+#include "_pkcs11h-crypto.h"
+#include "_pkcs11h-session.h"
+#include "_pkcs11h-token.h"
+#include <pkcs11-helper-1.0/pkcs11h-standalone.h>
+
+void
+pkcs11h_standalone_dump_slots (
+	IN const pkcs11h_output_print_t my_output,
+	IN void * const global_data,
+	IN const char * const provider,
+	IN const char * const prms[]
+) {
+	CK_RV rv = CKR_OK;
+
+	pkcs11h_provider_t pkcs11h_provider;
+
+	PKCS11H_ASSERT (my_output!=NULL);
+	/*PKCS11H_ASSERT (global_data) NOT NEEDED */
+	PKCS11H_ASSERT (provider!=NULL);
+
+	if (
+		rv == CKR_OK &&
+		(rv = pkcs11h_initialize ()) != CKR_OK
+	) {
+		my_output (global_data, "PKCS#11: Cannot initialize interface %ld-'%s'\n", rv, pkcs11h_getMessage (rv));
+	}
+
+	if (
+		rv == CKR_OK &&
+		(rv = pkcs11h_addProvider (
+			provider,
+			provider,
+			FALSE,
+			PKCS11H_PRIVATEMODE_MASK_AUTO,
+			PKCS11H_SLOTEVENT_METHOD_AUTO,
+			0,
+			FALSE
+		)) != CKR_OK
+	) {
+		my_output (global_data, "PKCS#11: Cannot initialize provider %ld-'%s'\n", rv, pkcs11h_getMessage (rv));
+	}
+
+	/*
+	 * our provider is head
+	 */
+	if (rv == CKR_OK) {
+		pkcs11h_provider = g_pkcs11h_data->providers;
+		if (pkcs11h_provider == NULL || !pkcs11h_provider->enabled) {
+			my_output (global_data, "PKCS#11: Cannot get provider %ld-'%s'\n", rv, pkcs11h_getMessage (rv));
+			rv = CKR_GENERAL_ERROR;
+		}
+	}
+
+	if (rv == CKR_OK) {
+		CK_INFO info;
+		
+		if ((rv = pkcs11h_provider->f->C_GetInfo (&info)) != CKR_OK) {
+			my_output (global_data, "PKCS#11: Cannot get PKCS#11 provider information %ld-'%s'\n", rv, pkcs11h_getMessage (rv));
+			rv = CKR_OK;
+		}
+		else {
+			char manufacturerID[sizeof (info.manufacturerID)+1];
+	
+			_pkcs11h_util_fixupFixedString (
+				manufacturerID,
+				(char *)info.manufacturerID,
+				sizeof (info.manufacturerID)
+			);
+	
+			my_output (
+				global_data,
+				(
+					"Provider Information:\n"
+					"\tcryptokiVersion:\t%u.%u\n"
+					"\tmanufacturerID:\t\t%s\n"
+					"\tflags:\t\t\t%08x\n"
+					"\n"
+				),
+				info.cryptokiVersion.major,
+				info.cryptokiVersion.minor,
+				manufacturerID,
+				(unsigned)info.flags
+			);
+		}
+	}
+	
+	if (rv == CKR_OK) {
+		CK_SLOT_ID_PTR slots = NULL;
+		CK_ULONG slotnum;
+		CK_SLOT_ID slot_index;
+		
+		if (
+			 _pkcs11h_session_getSlotList (
+				pkcs11h_provider,
+				CK_FALSE,
+				&slots,
+				&slotnum
+			) != CKR_OK
+		) {
+			my_output (global_data, "PKCS#11: Cannot get slot list %ld-'%s'\n", rv, pkcs11h_getMessage (rv));
+		}
+		else {
+			my_output (
+				global_data,
+				"The following slots are available for use with this provider.\n"
+			);
+
+			if (prms != NULL) {
+				my_output (
+					global_data,
+					(
+						"Each slot shown below may be used as a parameter to a\n"
+						"%s and %s options.\n"
+					),
+					prms[0],
+					prms[1]
+				);
+			}
+
+			my_output (
+				global_data,
+				(
+					"\n"
+					"Slots: (id - name)\n"
+				)
+			);
+
+			for (slot_index=0;slot_index < slotnum;slot_index++) {
+				CK_SLOT_INFO info;
+	
+				if (
+					(rv = pkcs11h_provider->f->C_GetSlotInfo (
+						slots[slot_index],
+						&info
+					)) == CKR_OK
+				) {
+					char current_name[sizeof (info.slotDescription)+1];
+				
+					_pkcs11h_util_fixupFixedString (
+						current_name,
+						(char *)info.slotDescription,
+						sizeof (info.slotDescription)
+					);
+	
+					my_output (global_data, "\t%lu - %s\n", slots[slot_index], current_name);
+				}
+			}
+		}
+
+		if (slots != NULL) {
+			_pkcs11h_mem_free ((void *)&slots);
+		}
+	}
+	
+	pkcs11h_terminate ();
+}
+
+static
+PKCS11H_BOOL
+_pkcs11h_standalone_dump_objects_pin_prompt (
+	IN void * const global_data,
+	IN void * const user_data,
+	IN const pkcs11h_token_id_t token,
+	IN const unsigned retry,
+	OUT char * const pin,
+	IN const size_t pin_max
+) {
+	(void)user_data;
+	(void)token;
+
+	/*
+	 * Don't lock card
+	 */
+	if (retry == 0) {
+		strncpy (pin, (char *)global_data, pin_max);
+		return TRUE;
+	}
+	else {
+		return FALSE;
+	}
+}
+
+static
+void
+_pkcs11h_standalone_dump_objects_hex (
+	IN const unsigned char * const p,
+	IN const size_t p_size,
+	OUT char * const sz,
+	IN const size_t max,
+	IN const char * const prefix
+) {
+	size_t j;
+
+	sz[0] = '\0';
+
+	for (j=0;j<p_size;j+=16) {
+		char line[3*16+1];
+		size_t k;
+
+		line[0] = '\0';
+		for (k=0;k<16 && j+k<p_size;k++) {
+			sprintf (line+strlen (line), "%02x ", p[j+k]);
+		}
+
+		strncat (
+			sz,
+			prefix,
+			max-1-strlen (sz)
+		);
+		strncat (
+			sz,
+			line,
+			max-1-strlen (sz)
+		);
+		strncat (
+			sz,
+			"\n",
+			max-1-strlen (sz)
+		);
+	}
+
+	sz[max-1] = '\0';
+}
+	
+void
+pkcs11h_standalone_dump_objects (
+	IN const pkcs11h_output_print_t my_output,
+	IN void * const global_data,
+	IN const char * const provider,
+	IN const char * const slot,
+	IN const char * const pin,
+	IN const char * const prms[]
+) {
+	CK_SLOT_ID s;
+	CK_RV rv = CKR_OK;
+
+	pkcs11h_provider_t pkcs11h_provider = NULL;
+	pkcs11h_token_id_t token_id = NULL;
+	pkcs11h_session_t session = NULL;
+
+	PKCS11H_ASSERT (my_output!=NULL);
+	/*PKCS11H_ASSERT (global_data) NOT NEEDED */
+	PKCS11H_ASSERT (provider!=NULL);
+	PKCS11H_ASSERT (slot!=NULL);
+	PKCS11H_ASSERT (pin!=NULL);
+
+	s = atoi (slot);
+
+	if (
+		rv == CKR_OK &&
+		(rv = pkcs11h_initialize ()) != CKR_OK
+	) {
+		my_output (global_data, "PKCS#11: Cannot initialize interface %ld-'%s'\n", rv, pkcs11h_getMessage (rv));
+	}
+
+	if (
+		rv == CKR_OK &&
+		(rv = pkcs11h_setPINPromptHook (_pkcs11h_standalone_dump_objects_pin_prompt, (void *)pin)) != CKR_OK
+	) {
+		my_output (global_data, "PKCS#11: Cannot set hooks %ld-'%s'\n", rv, pkcs11h_getMessage (rv));
+	}
+
+	if (
+		rv == CKR_OK &&
+		(rv = pkcs11h_addProvider (
+			provider,
+			provider,
+			FALSE,
+			PKCS11H_PRIVATEMODE_MASK_AUTO,
+			PKCS11H_SLOTEVENT_METHOD_AUTO,
+			0,
+			FALSE
+		)) != CKR_OK
+	) {
+		my_output (global_data, "PKCS#11: Cannot initialize provider %ld-'%s'\n", rv, pkcs11h_getMessage (rv));
+	}
+
+	/*
+	 * our provider is head
+	 */
+	if (rv == CKR_OK) {
+		pkcs11h_provider = g_pkcs11h_data->providers;
+		if (pkcs11h_provider == NULL || !pkcs11h_provider->enabled) {
+			my_output (global_data, "PKCS#11: Cannot get provider %ld-'%s'\n", rv, pkcs11h_getMessage (rv));
+			rv = CKR_GENERAL_ERROR;
+		}
+	}
+
+	if (rv == CKR_OK) {
+		CK_TOKEN_INFO info;
+		
+		if (
+			(rv = pkcs11h_provider->f->C_GetTokenInfo (
+				s,
+				&info
+			)) != CKR_OK
+		) {
+			my_output (global_data, "PKCS#11: Cannot get token information for slot %ld %ld-'%s'\n", s, rv, pkcs11h_getMessage (rv));
+			/* Ignore this error */
+			rv = CKR_OK;
+		}
+		else {
+			char label[sizeof (info.label)+1];
+			char manufacturerID[sizeof (info.manufacturerID)+1];
+			char model[sizeof (info.model)+1];
+			char serialNumberNumber[sizeof (info.serialNumber)+1];
+			
+			_pkcs11h_util_fixupFixedString (
+				label,
+				(char *)info.label,
+				sizeof (info.label)
+			);
+			_pkcs11h_util_fixupFixedString (
+				manufacturerID,
+				(char *)info.manufacturerID,
+				sizeof (info.manufacturerID)
+			);
+			_pkcs11h_util_fixupFixedString (
+				model,
+				(char *)info.model,
+				sizeof (info.model)
+			);
+			_pkcs11h_util_fixupFixedString (
+				serialNumberNumber,
+				(char *)info.serialNumber,
+				sizeof (info.serialNumber)
+			);
+	
+			my_output (
+				global_data,
+				(
+					"Token Information:\n"
+					"\tlabel:\t\t%s\n"
+					"\tmanufacturerID:\t%s\n"
+					"\tmodel:\t\t%s\n"
+					"\tserialNumber:\t%s\n"
+					"\tflags:\t\t%08x\n"
+					"\n"
+				),
+				label,
+				manufacturerID,
+				model,
+				serialNumberNumber,
+				(unsigned)info.flags
+			);
+
+			if (prms!=NULL) {
+				my_output (
+					global_data,
+					(
+						"You can access this token using\n"
+						"%s \"label\" %s \"%s\" options.\n"
+						"\n"
+					),
+					prms[0],
+					prms[1],
+					label
+				);
+			}
+
+			if (
+				rv == CKR_OK &&
+				(rv = _pkcs11h_token_getTokenId (
+					&info,
+					&token_id
+				)) != CKR_OK
+			) {
+				my_output (global_data, "PKCS#11: Cannot get token id for slot %ld %ld-'%s'\n", s, rv, pkcs11h_getMessage (rv));		
+				rv = CKR_OK;
+			}
+		}
+	}
+
+	if (token_id != NULL) {
+		if (
+			(rv = _pkcs11h_session_getSessionByTokenId (
+				token_id,
+				&session
+			)) != CKR_OK
+		) {
+			my_output (global_data, "PKCS#11: Cannot session for token '%s' %ld-'%s'\n", token_id->display, rv, pkcs11h_getMessage (rv));		
+			rv = CKR_OK;
+		}
+	}
+
+	if (session != NULL) {
+		CK_OBJECT_HANDLE *objects = NULL;
+		CK_ULONG objects_found = 0;
+		CK_ULONG i;
+
+		if (
+			(rv = _pkcs11h_session_login (
+				session,
+				FALSE,
+				TRUE,
+				NULL,
+				PKCS11H_PROMPT_MASK_ALLOW_PIN_PROMPT
+			)) != CKR_OK
+		) {
+			my_output (global_data, "PKCS#11: Cannot open session to token '%s' %ld-'%s'\n", session->token_id->display, rv, pkcs11h_getMessage (rv));
+		}
+	
+		my_output (
+			global_data,
+			"The following objects are available for use with this token.\n"
+		);
+
+		if (prms != NULL) {
+			my_output (
+				global_data,
+				(
+					"Each object shown below may be used as a parameter to\n"
+					"%s and %s options.\n"
+				),
+				prms[2],
+				prms[3]
+			);
+		}
+
+		my_output (
+			global_data,
+			"\n"
+		);
+
+		if (
+			rv == CKR_OK &&
+			(rv = _pkcs11h_session_findObjects (
+				session,
+				NULL,
+				0,
+				&objects,
+				&objects_found
+			)) != CKR_OK
+		) {
+			my_output (global_data, "PKCS#11: Cannot query objects for token '%s' %ld-'%s'\n", session->token_id->display, rv, pkcs11h_getMessage (rv));
+		}
+	
+		for (i=0;rv == CKR_OK && i < objects_found;i++) {
+			CK_OBJECT_CLASS attrs_class = 0;
+			CK_ATTRIBUTE attrs[] = {
+				{CKA_CLASS, &attrs_class, sizeof (attrs_class)}
+			};
+
+			if (
+				_pkcs11h_session_getObjectAttributes (
+					session,
+					objects[i],
+					attrs,
+					sizeof (attrs) / sizeof (CK_ATTRIBUTE)
+				) == CKR_OK
+			) {
+				if (attrs_class == CKO_CERTIFICATE) {
+					CK_ATTRIBUTE attrs_cert[] = {
+						{CKA_ID, NULL, 0},
+						{CKA_LABEL, NULL, 0},
+						{CKA_VALUE, NULL, 0}
+					};
+					unsigned char *attrs_id = NULL;
+					int attrs_id_size = 0;
+					unsigned char *attrs_value = NULL;
+					int attrs_value_size = 0;
+					char *attrs_label = NULL;
+					char hex_id[1024];
+					char subject[1024];
+					char serialNumber[1024];
+					time_t notAfter = 0;
+
+					subject[0] = '\0';
+					serialNumber[0] = '\0';
+
+
+					if (
+						_pkcs11h_session_getObjectAttributes (
+							session,
+							objects[i],
+							attrs_cert,
+							sizeof (attrs_cert) / sizeof (CK_ATTRIBUTE)
+						) == CKR_OK &&
+						_pkcs11h_mem_malloc (
+							(void *)&attrs_label,
+							attrs_cert[1].ulValueLen+1
+						) == CKR_OK
+					) {
+						attrs_id = (unsigned char *)attrs_cert[0].pValue;
+						attrs_id_size = attrs_cert[0].ulValueLen;
+						attrs_value = (unsigned char *)attrs_cert[2].pValue;
+						attrs_value_size = attrs_cert[2].ulValueLen;
+
+						memset (attrs_label, 0, attrs_cert[1].ulValueLen+1);
+						memmove (attrs_label, attrs_cert[1].pValue, attrs_cert[1].ulValueLen);
+						_pkcs11h_standalone_dump_objects_hex (
+							attrs_id,
+							attrs_id_size,
+							hex_id,
+							sizeof (hex_id),
+							"\t\t"
+						);
+					}
+
+					if (attrs_value != NULL) {
+						if (
+							!g_pkcs11h_crypto_engine.certificate_get_dn (
+								g_pkcs11h_crypto_engine.global_data,
+								attrs_value,
+								attrs_value_size,
+								subject,
+								sizeof (subject)
+							)
+						) {
+							subject[0] = '\x0';
+						}
+
+						if (
+							!g_pkcs11h_crypto_engine.certificate_get_expiration (
+								g_pkcs11h_crypto_engine.global_data,
+								attrs_value,
+								attrs_value_size,
+								&notAfter
+							)
+						) {
+							notAfter = (time_t)0;
+						}
+
+						if (
+							!g_pkcs11h_crypto_engine.certificate_get_serial (
+								g_pkcs11h_crypto_engine.global_data,
+								attrs_value,
+								attrs_value_size,
+								serialNumber,
+								sizeof (serialNumber)
+							)
+						) {
+							serialNumber[0] = '\x0';
+						}
+					}
+
+					my_output (
+						global_data,
+						(
+							"Object\n"
+							"\tType:\t\t\tCertificate\n"
+							"\tCKA_ID:\n"
+							"%s"
+							"\tCKA_LABEL:\t\t%s\n"
+							"\tsubject:\t\t%s\n"
+							"\tserialNumber:\t\t%s\n"
+							"\tnotAfter:\t\t%s\n"
+						),
+						hex_id,
+						attrs_label,
+						subject,
+						serialNumber,
+						asctime (localtime (&notAfter))
+					);
+
+					if (attrs_label != NULL) {
+						_pkcs11h_mem_free ((void *)&attrs_label);
+						attrs_label = NULL;
+					}
+
+					_pkcs11h_session_freeObjectAttributes (
+						attrs_cert,
+						sizeof (attrs_cert) / sizeof (CK_ATTRIBUTE)
+					);
+				}
+				else if (attrs_class == CKO_PRIVATE_KEY) {
+					CK_BBOOL sign_recover = CK_FALSE;
+					CK_BBOOL sign = CK_FALSE;
+					CK_ATTRIBUTE attrs_key[] = {
+						{CKA_SIGN, &sign, sizeof (sign)},
+						{CKA_SIGN_RECOVER, &sign_recover, sizeof (sign_recover)}
+					};
+					CK_ATTRIBUTE attrs_key_common[] = {
+						{CKA_ID, NULL, 0},
+						{CKA_LABEL, NULL, 0}
+					};
+					unsigned char *attrs_id = NULL;
+					int attrs_id_size = 0;
+					char *attrs_label = NULL;
+					char hex_id[1024];
+
+					pkcs11h_provider->f->C_GetAttributeValue (
+						session->session_handle,
+						objects[i],
+						attrs_key,
+						sizeof (attrs_key) / sizeof (CK_ATTRIBUTE)
+					);
+
+					if (
+						_pkcs11h_session_getObjectAttributes (
+							session,
+							objects[i],
+							attrs_key_common,
+							sizeof (attrs_key_common) / sizeof (CK_ATTRIBUTE)
+						) == CKR_OK &&
+						_pkcs11h_mem_malloc (
+							(void *)&attrs_label,
+							attrs_key_common[1].ulValueLen+1
+						) == CKR_OK
+					) {
+						attrs_id = (unsigned char *)attrs_key_common[0].pValue;
+						attrs_id_size = attrs_key_common[0].ulValueLen;
+
+						memset (attrs_label, 0, attrs_key_common[1].ulValueLen+1);
+						memmove (attrs_label, attrs_key_common[1].pValue, attrs_key_common[1].ulValueLen);
+
+						_pkcs11h_standalone_dump_objects_hex (
+							attrs_id,
+							attrs_id_size,
+							hex_id,
+							sizeof (hex_id),
+							"\t\t"
+						);
+							
+					}
+
+					my_output (
+						global_data,
+						(
+							"Object\n"
+							"\tType:\t\t\tPrivate Key\n"
+							"\tCKA_ID:\n"
+							"%s"
+							"\tCKA_LABEL:\t\t%s\n"
+							"\tCKA_SIGN:\t\t%s\n"
+							"\tCKA_SIGN_RECOVER:\t%s\n"
+						),
+						hex_id,
+						attrs_label,
+						sign ? "TRUE" : "FALSE",
+						sign_recover ? "TRUE" : "FALSE"
+					);
+
+					if (attrs_label != NULL) {
+						_pkcs11h_mem_free ((void *)&attrs_label);
+						attrs_label = NULL;
+					}
+
+					_pkcs11h_session_freeObjectAttributes (
+						attrs_key_common,
+						sizeof (attrs_key_common) / sizeof (CK_ATTRIBUTE)
+					);
+				}
+				else if (attrs_class == CKO_PUBLIC_KEY) {
+					CK_ATTRIBUTE attrs_key_common[] = {
+						{CKA_ID, NULL, 0},
+						{CKA_LABEL, NULL, 0}
+					};
+					unsigned char *attrs_id = NULL;
+					int attrs_id_size = 0;
+					char *attrs_label = NULL;
+					char hex_id[1024];
+
+					if (
+						_pkcs11h_session_getObjectAttributes (
+							session,
+							objects[i],
+							attrs_key_common,
+							sizeof (attrs_key_common) / sizeof (CK_ATTRIBUTE)
+						) == CKR_OK &&
+						_pkcs11h_mem_malloc (
+							(void *)&attrs_label,
+							attrs_key_common[1].ulValueLen+1
+						) == CKR_OK
+					) {
+						attrs_id = (unsigned char *)attrs_key_common[0].pValue;
+						attrs_id_size = attrs_key_common[0].ulValueLen;
+
+						memset (attrs_label, 0, attrs_key_common[1].ulValueLen+1);
+						memmove (attrs_label, attrs_key_common[1].pValue, attrs_key_common[1].ulValueLen);
+
+						_pkcs11h_standalone_dump_objects_hex (
+							attrs_id,
+							attrs_id_size,
+							hex_id,
+							sizeof (hex_id),
+							"\t\t"
+						);
+							
+					}
+
+					my_output (
+						global_data,
+						(
+							"Object\n"
+							"\tType:\t\t\tPublic Key\n"
+							"\tCKA_ID:\n"
+							"%s"
+							"\tCKA_LABEL:\t\t%s\n"
+						),
+						hex_id,
+						attrs_label
+					);
+
+					_pkcs11h_mem_free ((void *)&attrs_label);
+
+					_pkcs11h_session_freeObjectAttributes (
+						attrs_key_common,
+						sizeof (attrs_key_common) / sizeof (CK_ATTRIBUTE)
+					);
+				}
+				else if (attrs_class == CKO_DATA) {
+					CK_ATTRIBUTE attrs_key_common[] = {
+						{CKA_APPLICATION, NULL, 0},
+						{CKA_LABEL, NULL, 0}
+					};
+					char *attrs_application = NULL;
+					char *attrs_label = NULL;
+
+					if (
+						_pkcs11h_session_getObjectAttributes (
+							session,
+							objects[i],
+							attrs_key_common,
+							sizeof (attrs_key_common) / sizeof (CK_ATTRIBUTE)
+						) == CKR_OK &&
+						_pkcs11h_mem_malloc (
+							(void *)&attrs_application,
+							attrs_key_common[0].ulValueLen+1
+						) == CKR_OK &&
+						_pkcs11h_mem_malloc (
+							(void *)&attrs_label,
+							attrs_key_common[1].ulValueLen+1
+						) == CKR_OK
+					) {
+						memset (attrs_application, 0, attrs_key_common[0].ulValueLen+1);
+						memmove (attrs_application, attrs_key_common[0].pValue, attrs_key_common[0].ulValueLen);
+						memset (attrs_label, 0, attrs_key_common[1].ulValueLen+1);
+						memmove (attrs_label, attrs_key_common[1].pValue, attrs_key_common[1].ulValueLen);
+					}
+
+					my_output (
+						global_data,
+						(
+							"Object\n"
+							"\tType:\t\t\tData\n"
+							"\tCKA_APPLICATION\t\t%s\n"
+							"\tCKA_LABEL:\t\t%s\n"
+						),
+						attrs_application,
+						attrs_label
+					);
+
+					_pkcs11h_mem_free ((void *)&attrs_application);
+					_pkcs11h_mem_free ((void *)&attrs_label);
+
+					_pkcs11h_session_freeObjectAttributes (
+						attrs_key_common,
+						sizeof (attrs_key_common) / sizeof (CK_ATTRIBUTE)
+					);
+				}
+				else {
+					my_output (
+						global_data,
+						(
+							"Object\n"
+							"\tType:\t\t\tUnsupported\n"
+						)
+					);
+				}
+			}
+
+			_pkcs11h_session_freeObjectAttributes (
+				attrs,
+				sizeof (attrs) / sizeof (CK_ATTRIBUTE)
+			);
+
+			/*
+			 * Ignore any error and
+			 * perform next iteration
+			 */
+			rv = CKR_OK;
+		}
+	
+		if (objects != NULL) {
+			_pkcs11h_mem_free ((void *)&objects);
+		}
+
+		/*
+		 * Ignore this error
+		 */
+		rv = CKR_OK;
+	}
+
+	if (session != NULL) {
+		_pkcs11h_session_release (session);
+		session = NULL;
+	}
+
+	if (token_id != NULL) {
+		pkcs11h_token_freeTokenId (token_id);
+		token_id = NULL;
+	}
+	
+	pkcs11h_terminate ();
+}
+
+#endif				/* ENABLE_PKCS11H_STANDALONE */
diff --git a/lib/pkcs11h-sys.c b/lib/pkcs11h-sys.c
new file mode 100644
index 0000000..935f46e
--- /dev/null
+++ b/lib/pkcs11h-sys.c
@@ -0,0 +1,109 @@
+/*
+ * Copyright (c) 2005-2006 Alon Bar-Lev <alon.barlev at gmail.com>
+ * All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, or the OpenIB.org BSD license.
+ *
+ * GNU General Public License (GPL) Version 2
+ * ===========================================
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2
+ *  as published by the Free Software Foundation.
+ *
+ *  This program 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 General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program (see the file COPYING[.GPL2] included with this
+ *  distribution); if not, write to the Free Software Foundation, Inc.,
+ *  59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * OpenIB.org BSD license
+ * =======================
+ * Redistribution and use in source and binary forms, with or without modifi-
+ * cation, are permitted provided that the following conditions are met:
+ *
+ *   o  Redistributions of source code must retain the above copyright notice,
+ *      this list of conditions and the following disclaimer.
+ *
+ *   o  Redistributions in binary form must reproduce the above copyright no-
+ *      tice, this list of conditions and the following disclaimer in the do-
+ *      cumentation and/or other materials provided with the distribution.
+ *
+ *   o  The names of the contributors may not be used to endorse or promote
+ *      products derived from this software without specific prior written
+ *      permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``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 REGENTS OR CONTRIBUTORS BE LI-
+ * ABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUEN-
+ * TIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEV-
+ * ER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABI-
+ * LITY, 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.
+ */
+
+#include "common.h"
+#include <time.h>
+
+#if !defined(_WIN32)
+#include <unistd.h>
+#endif
+
+#include <pkcs11-helper-1.0/pkcs11h-core.h>
+#include "_pkcs11h-sys.h"
+
+static
+time_t
+__mytime (void) {
+	return time (NULL);
+}
+
+static
+void
+__mysleep (const unsigned long usec) {
+#if defined(_WIN32)
+	Sleep (usec/1000);
+#else
+	usleep (usec);
+#endif
+}
+
+#if !defined(_WIN32)
+static
+int
+__mygettimeofday (struct timeval *tv) {
+	return gettimeofday (tv, NULL);
+}
+#endif
+
+pkcs11h_engine_system_t g_pkcs11h_sys_engine = {
+	malloc,
+	free,
+	__mytime,
+	__mysleep,
+#if defined(_WIN32)
+	NULL
+#else
+	__mygettimeofday
+#endif
+};
+
+CK_RV
+pkcs11h_engine_setSystem (
+	IN const pkcs11h_engine_system_t * const engine
+) {
+	PKCS11H_ASSERT (engine!=NULL);
+
+	memmove (&g_pkcs11h_sys_engine, engine, sizeof (pkcs11h_engine_system_t));
+
+	return CKR_OK;
+}
+
diff --git a/lib/pkcs11h-threading.c b/lib/pkcs11h-threading.c
new file mode 100644
index 0000000..0972160
--- /dev/null
+++ b/lib/pkcs11h-threading.c
@@ -0,0 +1,570 @@
+/*
+ * Copyright (c) 2005-2006 Alon Bar-Lev <alon.barlev at gmail.com>
+ * All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, or the OpenIB.org BSD license.
+ *
+ * GNU General Public License (GPL) Version 2
+ * ===========================================
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2
+ *  as published by the Free Software Foundation.
+ *
+ *  This program 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 General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program (see the file COPYING[.GPL2] included with this
+ *  distribution); if not, write to the Free Software Foundation, Inc.,
+ *  59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * OpenIB.org BSD license
+ * =======================
+ * Redistribution and use in source and binary forms, with or without modifi-
+ * cation, are permitted provided that the following conditions are met:
+ *
+ *   o  Redistributions of source code must retain the above copyright notice,
+ *      this list of conditions and the following disclaimer.
+ *
+ *   o  Redistributions in binary form must reproduce the above copyright no-
+ *      tice, this list of conditions and the following disclaimer in the do-
+ *      cumentation and/or other materials provided with the distribution.
+ *
+ *   o  The names of the contributors may not be used to endorse or promote
+ *      products derived from this software without specific prior written
+ *      permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``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 REGENTS OR CONTRIBUTORS BE LI-
+ * ABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUEN-
+ * TIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEV-
+ * ER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABI-
+ * LITY, 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.
+ */
+
+#include "common.h"
+
+#if defined(ENABLE_PKCS11H_THREADING)
+
+#if defined(_WIN32)
+#include <process.h>
+#else
+#include <signal.h>
+#endif
+
+#include "_pkcs11h-sys.h"
+#include "_pkcs11h-mem.h"
+#include "_pkcs11h-threading.h"
+
+typedef struct {
+	pkcs11h_thread_start_t start;
+	void *data;
+} __pkcs11h_thread_data_t;
+
+/*==========================================
+ * Static data
+ */
+
+#if !defined(_WIN32)
+static struct {
+	pkcs11h_mutex_t mutex;
+	__pkcs11h_threading_mutex_entry_t head;
+} __s_pkcs11h_threading_mutex_list = {
+	PTHREAD_MUTEX_INITIALIZER,
+	NULL
+};
+#endif
+
+void
+_pkcs11h_threading_sleep (
+	IN const unsigned milli
+) {
+	g_pkcs11h_sys_engine.usleep (milli*1000);
+}
+
+CK_RV
+_pkcs11h_threading_mutexInit (
+	OUT pkcs11h_mutex_t * const mutex
+) {
+	CK_RV rv = CKR_OK;
+#if defined(_WIN32)
+	if (
+		rv == CKR_OK &&
+		(*mutex = CreateMutex (NULL, FALSE, NULL)) == NULL
+	) {
+		rv = CKR_FUNCTION_FAILED;
+	}
+#else
+	{
+		__pkcs11h_threading_mutex_entry_t entry = NULL;
+		PKCS11H_BOOL mutex_locked = FALSE;
+
+		if (
+			rv == CKR_OK &&
+			(rv = _pkcs11h_threading_mutexLock (&__s_pkcs11h_threading_mutex_list.mutex)) == CKR_OK
+		) {
+			mutex_locked = TRUE;
+		}
+		
+		if (rv == CKR_OK) {
+			rv = _pkcs11h_mem_malloc (
+				(void *)&entry,
+				sizeof (struct __pkcs11h_threading_mutex_entry_s)
+			);
+		}
+
+		if (
+			rv == CKR_OK &&
+			pthread_mutex_init (mutex, NULL)
+		) {
+			rv = CKR_FUNCTION_FAILED;
+		}
+
+		if (rv == CKR_OK) {
+			entry->p_mutex = mutex;
+			entry->next = __s_pkcs11h_threading_mutex_list.head;
+			__s_pkcs11h_threading_mutex_list.head = entry;
+			entry = NULL;
+		}
+
+		if (entry != NULL) {
+			_pkcs11h_mem_free ((void *)&entry);
+		}
+
+		if (mutex_locked) {
+			_pkcs11h_threading_mutexRelease (&__s_pkcs11h_threading_mutex_list.mutex);
+			mutex_locked = FALSE;
+		}
+	}
+#endif
+	return rv;
+}
+
+CK_RV
+_pkcs11h_threading_mutexLock (
+	IN OUT pkcs11h_mutex_t *const mutex
+) {
+	CK_RV rv = CKR_OK;
+#if defined(_WIN32)
+	if (
+		rv == CKR_OK &&
+		WaitForSingleObject (*mutex, INFINITE) == WAIT_FAILED
+	) {
+		rv = CKR_FUNCTION_FAILED;
+	}
+#else
+	if (
+		rv == CKR_OK &&
+		pthread_mutex_lock (mutex)
+	) {
+		rv = CKR_FUNCTION_FAILED;
+	}
+#endif
+	return rv;
+}
+
+CK_RV
+_pkcs11h_threading_mutexRelease (
+	IN OUT pkcs11h_mutex_t *const mutex
+) {
+	CK_RV rv = CKR_OK;
+#if defined(_WIN32)
+	if (
+		rv == CKR_OK &&
+		!ReleaseMutex (*mutex)
+	) {
+		rv = CKR_FUNCTION_FAILED;
+	}
+#else
+	if (
+		rv == CKR_OK &&
+		pthread_mutex_unlock (mutex)
+	) {
+		rv = CKR_FUNCTION_FAILED;
+	}
+#endif
+	return rv;
+}
+
+CK_RV
+_pkcs11h_threading_mutexFree (
+	IN OUT pkcs11h_mutex_t *const mutex
+) {
+#if defined(_WIN32)
+	if (*mutex != NULL) {
+		CloseHandle (*mutex);
+		*mutex = NULL;
+	}
+#else
+	{
+		__pkcs11h_threading_mutex_entry_t last = NULL;
+		__pkcs11h_threading_mutex_entry_t entry = NULL;
+		PKCS11H_BOOL mutex_locked = FALSE;
+
+		if (_pkcs11h_threading_mutexLock (&__s_pkcs11h_threading_mutex_list.mutex) == CKR_OK) {
+			mutex_locked = TRUE;
+		}
+
+		entry =  __s_pkcs11h_threading_mutex_list.head;
+		while (
+			entry != NULL &&
+			entry->p_mutex != mutex
+		) {
+			last = entry;
+			entry = entry->next;
+		}
+
+		if (entry != NULL) {
+			if (last == NULL) {
+				__s_pkcs11h_threading_mutex_list.head = entry->next;
+			}
+			else {
+				last->next = entry->next;
+			}
+			_pkcs11h_mem_free ((void *)&entry);
+		}
+
+		pthread_mutex_destroy (mutex);
+
+		if (mutex_locked) {
+			_pkcs11h_threading_mutexRelease (&__s_pkcs11h_threading_mutex_list.mutex);
+			mutex_locked = FALSE;
+		}
+	}
+#endif
+	return CKR_OK;
+}
+
+#if !defined(_WIN32)
+/*
+ * This function is required in order
+ * to lock all mutexes before fork is called,
+ * and to avoid dedlocks.
+ * The loop is required because there is no
+ * way to lock all mutex in one system call...
+ */
+void
+_pkcs1h_threading_mutexLockAll (void) {
+	__pkcs11h_threading_mutex_entry_t entry = NULL;
+	PKCS11H_BOOL mutex_locked = FALSE;
+	PKCS11H_BOOL all_mutexes_locked = FALSE;
+
+	if (_pkcs11h_threading_mutexLock (&__s_pkcs11h_threading_mutex_list.mutex) == CKR_OK) {
+		mutex_locked = TRUE;
+	}
+
+	for (
+		entry = __s_pkcs11h_threading_mutex_list.head;
+		entry != NULL;
+		entry = entry->next
+	) {
+		entry->locked = FALSE;
+	}
+
+	while (!all_mutexes_locked) {
+		PKCS11H_BOOL ok = TRUE;
+		
+		for (
+			entry = __s_pkcs11h_threading_mutex_list.head;
+			entry != NULL && ok;
+			entry = entry->next
+		) {
+			if (!pthread_mutex_trylock (entry->p_mutex)) {
+				entry->locked = TRUE;
+			}
+			else {
+				ok = FALSE;
+			}
+		}
+
+		if (!ok) {
+			for (
+				entry = __s_pkcs11h_threading_mutex_list.head;
+				entry != NULL;
+				entry = entry->next
+			) {
+				if (entry->locked == TRUE) {
+					pthread_mutex_unlock (entry->p_mutex);
+					entry->locked = FALSE;
+				}
+			}
+
+			_pkcs11h_threading_mutexRelease (&__s_pkcs11h_threading_mutex_list.mutex);
+			_pkcs11h_threading_sleep (1000);
+			_pkcs11h_threading_mutexLock (&__s_pkcs11h_threading_mutex_list.mutex);
+		}
+		else {
+			all_mutexes_locked  = TRUE;
+		}
+	}
+
+	if (mutex_locked) {
+		_pkcs11h_threading_mutexRelease (&__s_pkcs11h_threading_mutex_list.mutex);
+		mutex_locked = FALSE;
+	}
+}
+
+void
+_pkcs1h_threading_mutexReleaseAll (void) {
+	__pkcs11h_threading_mutex_entry_t entry = NULL;
+	PKCS11H_BOOL mutex_locked = FALSE;
+
+	if (_pkcs11h_threading_mutexLock (&__s_pkcs11h_threading_mutex_list.mutex) == CKR_OK) {
+		mutex_locked = TRUE;
+	}
+
+	for (
+		entry = __s_pkcs11h_threading_mutex_list.head;
+		entry != NULL;
+		entry = entry->next
+	) {
+		pthread_mutex_unlock (entry->p_mutex);
+		entry->locked = FALSE;
+	}
+
+	if (mutex_locked) {
+		_pkcs11h_threading_mutexRelease (&__s_pkcs11h_threading_mutex_list.mutex);
+		mutex_locked = FALSE;
+	}
+}
+#endif
+
+CK_RV
+_pkcs11h_threading_condSignal (
+	IN OUT pkcs11h_cond_t *const cond
+) {
+	CK_RV rv = CKR_OK;
+#if defined(_WIN32)
+	if (
+		rv == CKR_OK &&
+		!SetEvent (*cond)
+	) {
+		rv = CKR_FUNCTION_FAILED;
+	}
+#else
+	if (
+		rv == CKR_OK &&
+		(
+			pthread_mutex_lock (&cond->mut) ||
+			pthread_cond_signal (&cond->cond) ||
+			pthread_mutex_unlock (&cond->mut)
+		)
+	) {
+		rv = CKR_FUNCTION_FAILED;
+	}
+#endif
+
+	return rv;
+}
+
+CK_RV
+_pkcs11h_threading_condInit (
+	OUT pkcs11h_cond_t * const cond
+) {
+	CK_RV rv = CKR_OK;
+#if defined(_WIN32)
+	if (
+		rv == CKR_OK &&
+		(*cond = CreateEvent (NULL, FALSE, FALSE, NULL)) == NULL
+	) {
+		rv = CKR_FUNCTION_FAILED;
+	}
+#else
+	if (
+		rv == CKR_OK &&
+		(
+			pthread_mutex_init (&cond->mut, NULL) ||
+			pthread_cond_init (&cond->cond, NULL) ||
+			pthread_mutex_lock (&cond->mut)
+		)
+	) {
+		rv = CKR_FUNCTION_FAILED;
+	}
+#endif
+	return rv;
+}
+
+CK_RV
+_pkcs11h_threading_condWait (
+	IN OUT pkcs11h_cond_t *const cond,
+	IN const unsigned milli
+) {
+	CK_RV rv = CKR_OK;
+
+#if defined(_WIN32)
+	DWORD dwMilli;
+
+	if (milli == PKCS11H_COND_INFINITE) {
+		dwMilli = INFINITE;
+	}
+	else {
+		dwMilli = milli;
+	}
+
+	if (
+		rv == CKR_OK &&
+		WaitForSingleObject (*cond, dwMilli) == WAIT_FAILED
+	) {
+		rv = CKR_FUNCTION_FAILED;
+	}
+#else
+	if (milli == PKCS11H_COND_INFINITE) {
+		if (
+			rv == CKR_OK &&
+			pthread_cond_wait (&cond->cond, &cond->mut)
+		) {
+			rv = CKR_FUNCTION_FAILED;
+		}
+	}
+	else {
+		struct timeval now;
+		struct timespec timeout;
+
+		if (
+			rv == CKR_OK &&
+			g_pkcs11h_sys_engine.gettimeofday (&now)
+		) {
+			rv = CKR_FUNCTION_FAILED;
+		}
+		
+		if (rv == CKR_OK) {
+			timeout.tv_sec = now.tv_sec + milli/1000;
+			timeout.tv_nsec = now.tv_usec*1000 + milli%1000;
+		}
+		
+		if (
+			rv == CKR_OK &&
+			pthread_cond_timedwait (&cond->cond, &cond->mut, &timeout)
+		) {
+			rv = CKR_FUNCTION_FAILED;
+		}
+	}
+#endif
+	return rv;
+}
+
+CK_RV
+_pkcs11h_threading_condFree (
+	IN OUT pkcs11h_cond_t *const cond
+) {
+#if defined(_WIN32)
+	CloseHandle (*cond);
+	*cond = NULL;
+#else
+	pthread_mutex_unlock (&cond->mut);
+#endif
+	return CKR_OK;
+}
+
+#if defined(_WIN32)
+static
+unsigned
+__stdcall
+__pkcs11h_thread_start (void *p) {
+	__pkcs11h_thread_data_t *_data = (__pkcs11h_thread_data_t *)p;
+	unsigned ret;
+
+	ret = (unsigned)_data->start (_data->data);
+
+	_pkcs11h_mem_free ((void *)&_data);
+
+	return ret;
+}
+#else
+static
+void *
+__pkcs11h_thread_start (void *p) {
+	__pkcs11h_thread_data_t *_data = (__pkcs11h_thread_data_t *)p;
+	void *ret;
+	int i;
+
+	/*
+	 * Ignore any signal in
+	 * this thread
+	 */
+	for (i=1;i<16;i++) {
+		signal (i, SIG_IGN);
+	}
+
+	ret = _data->start (_data->data);
+
+	_pkcs11h_mem_free ((void *)&_data);
+
+	return ret;
+}
+#endif
+
+CK_RV
+_pkcs11h_threading_threadStart (
+	OUT pkcs11h_thread_t * const thread,
+	IN pkcs11h_thread_start_t const start,
+	IN void * data
+) {
+	__pkcs11h_thread_data_t *_data = NULL;
+	CK_RV rv = CKR_OK;
+
+	if (rv == CKR_OK) {
+		rv = _pkcs11h_mem_malloc (
+			(void *)&_data,
+			sizeof (__pkcs11h_thread_data_t)
+		);
+	}
+
+	if (rv == CKR_OK) {
+		_data->start = start;
+		_data->data = data;
+	}
+
+#if defined(_WIN32)
+	{
+		unsigned tmp;
+
+		if (
+			rv == CKR_OK &&
+			(*thread = (HANDLE)_beginthreadex (
+				NULL,
+				0,
+				__pkcs11h_thread_start,
+				_data,
+				0,
+				&tmp
+			)) == NULL
+		) {
+			rv = CKR_FUNCTION_FAILED;
+		}
+	}
+#else
+	if (
+		rv == CKR_OK &&
+		pthread_create (thread, NULL, __pkcs11h_thread_start, _data)
+	) {
+		rv = CKR_FUNCTION_FAILED;
+	}
+#endif
+	return rv;
+}
+
+CK_RV
+_pkcs11h_threading_threadJoin (
+	IN pkcs11h_thread_t * const thread
+) {
+#if defined(_WIN32)
+	WaitForSingleObject (*thread, INFINITE);
+	CloseHandle (*thread);
+	*thread = NULL;
+#else
+	pthread_join (*thread, NULL);
+	*thread = 0l;
+#endif
+	return CKR_OK;
+}
+
+#endif
diff --git a/lib/pkcs11h-token.c b/lib/pkcs11h-token.c
new file mode 100644
index 0000000..6635f11
--- /dev/null
+++ b/lib/pkcs11h-token.c
@@ -0,0 +1,669 @@
+/*
+ * Copyright (c) 2005-2006 Alon Bar-Lev <alon.barlev at gmail.com>
+ * All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, or the OpenIB.org BSD license.
+ *
+ * GNU General Public License (GPL) Version 2
+ * ===========================================
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2
+ *  as published by the Free Software Foundation.
+ *
+ *  This program 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 General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program (see the file COPYING[.GPL2] included with this
+ *  distribution); if not, write to the Free Software Foundation, Inc.,
+ *  59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * OpenIB.org BSD license
+ * =======================
+ * Redistribution and use in source and binary forms, with or without modifi-
+ * cation, are permitted provided that the following conditions are met:
+ *
+ *   o  Redistributions of source code must retain the above copyright notice,
+ *      this list of conditions and the following disclaimer.
+ *
+ *   o  Redistributions in binary form must reproduce the above copyright no-
+ *      tice, this list of conditions and the following disclaimer in the do-
+ *      cumentation and/or other materials provided with the distribution.
+ *
+ *   o  The names of the contributors may not be used to endorse or promote
+ *      products derived from this software without specific prior written
+ *      permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``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 REGENTS OR CONTRIBUTORS BE LI-
+ * ABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUEN-
+ * TIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEV-
+ * ER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABI-
+ * LITY, 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.
+ */
+
+#include "common.h"
+
+#include <pkcs11-helper-1.0/pkcs11h-token.h>
+#include "_pkcs11h-mem.h"
+#include "_pkcs11h-session.h"
+#include "_pkcs11h-util.h"
+#include "_pkcs11h-token.h"
+
+CK_RV
+pkcs11h_token_freeTokenId (
+	IN pkcs11h_token_id_t token_id
+) {
+	PKCS11H_ASSERT (g_pkcs11h_data!=NULL);
+	PKCS11H_ASSERT (g_pkcs11h_data->initialized);
+	PKCS11H_ASSERT (token_id!=NULL);
+
+	PKCS11H_DEBUG (
+		PKCS11H_LOG_DEBUG2,
+		"PKCS#11: pkcs11h_token_freeTokenId entry certificate_id=%p",
+		(void *)token_id
+	);
+
+	_pkcs11h_mem_free ((void *)&token_id);
+
+	PKCS11H_DEBUG (
+		PKCS11H_LOG_DEBUG2,
+		"PKCS#11: pkcs11h_token_freeTokenId return"
+	);
+
+	return CKR_OK;
+}
+
+CK_RV
+pkcs11h_token_duplicateTokenId (
+	OUT pkcs11h_token_id_t * const to,
+	IN const pkcs11h_token_id_t from
+) {
+	CK_RV rv = CKR_OK;
+
+	PKCS11H_ASSERT (g_pkcs11h_data!=NULL);
+	PKCS11H_ASSERT (g_pkcs11h_data->initialized);
+	PKCS11H_ASSERT (to!=NULL);
+	PKCS11H_ASSERT (from!=NULL);
+
+	PKCS11H_DEBUG (
+		PKCS11H_LOG_DEBUG2,
+		"PKCS#11: pkcs11h_token_duplicateTokenId entry to=%p form=%p",
+		(void *)to,
+		(void *)from
+	);
+
+	*to = NULL;
+
+	if (rv == CKR_OK) {
+		rv = _pkcs11h_mem_duplicate (
+			(void*)to,
+			NULL,
+			from,
+			sizeof (struct pkcs11h_token_id_s)
+		);
+	}
+
+	PKCS11H_DEBUG (
+		PKCS11H_LOG_DEBUG2,
+		"PKCS#11: pkcs11h_token_duplicateTokenId return rv=%ld-'%s', *to=%p",
+		rv,
+		pkcs11h_getMessage (rv),
+		(void *)*to
+	);
+	
+	return rv;
+}
+
+PKCS11H_BOOL
+pkcs11h_token_sameTokenId (
+	IN const pkcs11h_token_id_t a,
+	IN const pkcs11h_token_id_t b
+) {
+	PKCS11H_ASSERT (a!=NULL);
+	PKCS11H_ASSERT (b!=NULL);
+
+	return (
+		!strcmp (a->manufacturerID, b->manufacturerID) &&
+		!strcmp (a->model, b->model) &&
+		!strcmp (a->serialNumber, b->serialNumber) &&
+		!strcmp (a->label, b->label)
+	);
+}
+
+CK_RV
+_pkcs11h_token_getTokenId (
+	IN const CK_TOKEN_INFO_PTR info,
+	OUT pkcs11h_token_id_t * const p_token_id
+) {
+	pkcs11h_token_id_t token_id;
+	CK_RV rv = CKR_OK;
+	
+	PKCS11H_ASSERT (info!=NULL);
+	PKCS11H_ASSERT (p_token_id!=NULL);
+	
+	PKCS11H_DEBUG (
+		PKCS11H_LOG_DEBUG2,
+		"PKCS#11: _pkcs11h_token_getTokenId entry p_token_id=%p",
+		(void *)p_token_id
+	);
+
+	*p_token_id = NULL;
+
+	if (
+		rv == CKR_OK &&
+		(rv = _pkcs11h_token_newTokenId (&token_id)) == CKR_OK
+	) {
+		_pkcs11h_util_fixupFixedString (
+			token_id->label,
+			(char *)info->label,
+			sizeof (info->label)
+		);
+		_pkcs11h_util_fixupFixedString (
+			token_id->manufacturerID,
+			(char *)info->manufacturerID,
+			sizeof (info->manufacturerID)
+		);
+		_pkcs11h_util_fixupFixedString (
+			token_id->model,
+			(char *)info->model,
+			sizeof (info->model)
+		);
+		_pkcs11h_util_fixupFixedString (
+			token_id->serialNumber,
+			(char *)info->serialNumber,
+			sizeof (info->serialNumber)
+		);
+		strncpy (
+			token_id->display,
+			token_id->label,
+			sizeof (token_id->display)
+		);
+	}
+
+	if (rv == CKR_OK) {
+		*p_token_id = token_id;
+		token_id = NULL;
+	}
+
+	if (token_id != NULL) {
+		_pkcs11h_mem_free ((void *)&token_id);
+	}
+
+	PKCS11H_DEBUG (
+		PKCS11H_LOG_DEBUG2,
+		"PKCS#11: _pkcs11h_token_getTokenId return rv=%ld-'%s', *p_token_id=%p",
+		rv,
+		pkcs11h_getMessage (rv),
+		(void *)*p_token_id
+	);
+
+	return rv;
+}
+
+CK_RV
+_pkcs11h_token_newTokenId (
+	OUT pkcs11h_token_id_t * const p_token_id
+) {
+	CK_RV rv = CKR_OK;
+
+	PKCS11H_ASSERT (g_pkcs11h_data!=NULL);
+	PKCS11H_ASSERT (g_pkcs11h_data->initialized);
+	PKCS11H_ASSERT (p_token_id!=NULL);
+
+	PKCS11H_DEBUG (
+		PKCS11H_LOG_DEBUG2,
+		"PKCS#11: _pkcs11h_token_newTokenId entry p_token_id=%p",
+		(void *)p_token_id
+	);
+
+	*p_token_id = NULL;
+
+	if (rv == CKR_OK) {
+		rv = _pkcs11h_mem_malloc ((void *)p_token_id, sizeof (struct pkcs11h_token_id_s));
+	}
+
+	PKCS11H_DEBUG (
+		PKCS11H_LOG_DEBUG2,
+		"PKCS#11: _pkcs11h_token_newTokenId return rv=%ld-'%s', *p_token_id=%p",
+		rv,
+		pkcs11h_getMessage (rv),
+		(void *)*p_token_id
+	);
+
+	return rv;
+}
+
+CK_RV
+pkcs11h_token_login (
+	IN const pkcs11h_token_id_t token_id,
+	IN const PKCS11H_BOOL readonly,
+	IN const char * const pin
+) {
+#if defined(ENABLE_PKCS11H_THREADING)
+	PKCS11H_BOOL mutex_locked = FALSE;
+#endif
+	CK_SLOT_ID slot = PKCS11H_INVALID_SLOT_ID;
+	CK_ULONG pin_size = 0;
+	CK_RV rv = CKR_OK;
+
+	pkcs11h_session_t session = NULL;
+
+	PKCS11H_ASSERT (token_id!=NULL);
+	/*PKCS11H_ASSERT (pin!=NULL); NOT NEEDED*/
+
+	PKCS11H_DEBUG (
+		PKCS11H_LOG_DEBUG2,
+		"PKCS#11: pkcs11h_token_login entry token_id=%p, readonly=%d\n", 
+		(void *)token_id,
+		readonly ? 1 : 0
+	);
+
+	if (pin != NULL) {
+		pin_size = strlen (pin);
+	}
+
+	if (rv == CKR_OK) {
+		rv = _pkcs11h_session_getSessionByTokenId (
+			token_id,
+			&session
+		);
+	}
+
+#if defined(ENABLE_PKCS11H_THREADING)
+	if (
+		rv == CKR_OK &&
+		(rv = _pkcs11h_threading_mutexLock (&session->mutex)) == CKR_OK
+	) {
+		mutex_locked = TRUE;
+	}
+#endif
+
+	if (rv == CKR_OK) {
+		rv = _pkcs11h_session_logout (session);
+	}
+
+	if (rv == CKR_OK) {
+		rv = _pkcs11h_session_reset (session, NULL, 0, &slot);
+	}
+
+	if (rv == CKR_OK) {
+		rv = _pkcs11h_session_touch (session);
+	}
+
+	if (rv == CKR_OK) {
+		rv = session->provider->f->C_OpenSession (
+			slot,
+			(
+				CKF_SERIAL_SESSION |
+				(readonly ? 0 : CKF_RW_SESSION)
+			),
+			NULL_PTR,
+			NULL_PTR,
+			&session->session_handle
+		);
+	}
+
+	if (
+		rv == CKR_OK &&
+		(rv = session->provider->f->C_Login (
+			session->session_handle,
+			CKU_USER,
+			(CK_UTF8CHAR_PTR)pin,
+			pin_size
+		)) != CKR_OK
+	) {
+		if (rv == CKR_USER_ALREADY_LOGGED_IN) {
+			rv = CKR_OK;
+		}
+	}
+
+#if defined(ENABLE_PKCS11H_THREADING)
+	if (mutex_locked) {
+		_pkcs11h_threading_mutexRelease (&session->mutex);
+		mutex_locked = FALSE;
+	}
+#endif
+
+	if (session != NULL) {
+		_pkcs11h_session_release (session);
+		session = NULL;
+	}
+
+	PKCS11H_DEBUG (
+		PKCS11H_LOG_DEBUG2,
+		"PKCS#11: pkcs11h_token_login return rv=%ld-'%s'",
+		rv,
+		pkcs11h_getMessage (rv)
+	);
+
+	return rv;
+}
+
+#if defined(ENABLE_PKCS11H_TOKEN)
+
+CK_RV
+pkcs11h_token_ensureAccess (
+	IN const pkcs11h_token_id_t token_id,
+	IN void * const user_data,
+	IN const unsigned mask_prompt
+) {
+#if defined(ENABLE_PKCS11H_THREADING)
+	PKCS11H_BOOL mutex_locked = FALSE;
+#endif
+	pkcs11h_session_t session = NULL;
+	CK_RV rv = CKR_OK;
+
+	PKCS11H_ASSERT (g_pkcs11h_data!=NULL);
+	PKCS11H_ASSERT (g_pkcs11h_data->initialized);
+	PKCS11H_ASSERT (token_id!=NULL);
+	/*PKCS11H_ASSERT (user_data) NOT NEEDED */
+
+	PKCS11H_DEBUG (
+		PKCS11H_LOG_DEBUG2,
+		"PKCS#11: pkcs11h_token_ensureAccess entry token_id=%p, user_data=%p, mask_prompt=%08x",
+		(void *)token_id,
+		user_data,
+		mask_prompt
+	);
+
+	if (rv == CKR_OK) {
+		rv = _pkcs11h_session_getSessionByTokenId (
+			token_id,
+			&session
+		);
+	}
+
+#if defined(ENABLE_PKCS11H_THREADING)
+	if (
+		rv == CKR_OK &&
+		(rv = _pkcs11h_threading_mutexLock (&session->mutex)) == CKR_OK
+	) {
+		mutex_locked = TRUE;
+	}
+#endif
+
+	if (rv == CKR_OK) {
+		CK_SLOT_ID slot;
+
+		rv = _pkcs11h_session_reset (
+			session,
+			user_data,
+			mask_prompt,
+			&slot
+		);
+	}
+
+#if defined(ENABLE_PKCS11H_THREADING)
+	if (mutex_locked) {
+		_pkcs11h_threading_mutexRelease (&session->mutex);
+		mutex_locked = FALSE;
+	}
+#endif
+
+	if (session != NULL) {
+		_pkcs11h_session_release (session);
+		session = NULL;
+	}
+
+	PKCS11H_DEBUG (
+		PKCS11H_LOG_DEBUG2,
+		"PKCS#11: pkcs11h_token_ensureAccess return rv=%ld-'%s'",
+		rv,
+		pkcs11h_getMessage (rv)
+	);
+
+	return rv;
+}
+
+CK_RV
+pkcs11h_token_freeTokenIdList (
+	IN const pkcs11h_token_id_list_t token_id_list
+) {
+	pkcs11h_token_id_list_t _id = token_id_list;
+
+	PKCS11H_ASSERT (g_pkcs11h_data!=NULL);
+	PKCS11H_ASSERT (g_pkcs11h_data->initialized);
+	/*PKCS11H_ASSERT (token_id_list!=NULL); NOT NEEDED*/
+
+	PKCS11H_DEBUG (
+		PKCS11H_LOG_DEBUG2,
+		"PKCS#11: pkcs11h_token_freeTokenIdList entry token_id_list=%p",
+		(void *)token_id_list
+	);
+
+	while (_id != NULL) {
+		pkcs11h_token_id_list_t x = _id;
+		_id = _id->next;
+		if (x->token_id != NULL) {
+			pkcs11h_token_freeTokenId (x->token_id);
+		}
+		x->next = NULL;
+		_pkcs11h_mem_free ((void *)&x);
+	}
+
+	PKCS11H_DEBUG (
+		PKCS11H_LOG_DEBUG2,
+		"PKCS#11: pkcs11h_token_freeTokenIdList return"
+	);
+
+	return CKR_OK;
+}
+
+CK_RV
+pkcs11h_token_enumTokenIds (
+	IN const int method,
+	OUT pkcs11h_token_id_list_t * const p_token_id_list
+) {
+#if defined(ENABLE_PKCS11H_THREADING)
+	PKCS11H_BOOL mutex_locked = FALSE;
+#endif
+
+	pkcs11h_token_id_list_t token_id_list = NULL;
+	pkcs11h_provider_t current_provider;
+	CK_RV rv = CKR_OK;
+
+	PKCS11H_ASSERT (g_pkcs11h_data!=NULL);
+	PKCS11H_ASSERT (g_pkcs11h_data->initialized);
+	PKCS11H_ASSERT (p_token_id_list!=NULL);
+
+	PKCS11H_DEBUG (
+		PKCS11H_LOG_DEBUG2,
+		"PKCS#11: pkcs11h_token_enumTokenIds entry p_token_id_list=%p",
+		(void *)p_token_id_list
+	);
+
+	*p_token_id_list = NULL;
+
+#if defined(ENABLE_PKCS11H_THREADING)
+	if (
+		rv == CKR_OK &&
+		(rv = _pkcs11h_threading_mutexLock (&g_pkcs11h_data->mutexes.global)) == CKR_OK
+	) {
+		mutex_locked = TRUE;
+	}
+#endif
+
+	for (
+		current_provider = g_pkcs11h_data->providers;
+		(
+			current_provider != NULL &&
+			rv == CKR_OK
+		);
+		current_provider = current_provider->next
+	) {
+		CK_SLOT_ID_PTR slots = NULL;
+		CK_ULONG slotnum;
+		CK_SLOT_ID slot_index;
+
+		if (!current_provider->enabled) {
+			rv = CKR_CRYPTOKI_NOT_INITIALIZED;
+		}
+
+		if (rv == CKR_OK) {
+			rv = _pkcs11h_session_getSlotList (
+				current_provider,
+				CK_TRUE,
+				&slots,
+				&slotnum
+			);
+		}
+
+		for (
+			slot_index=0;
+			(
+				slot_index < slotnum &&
+				rv == CKR_OK
+			);
+			slot_index++
+		) {
+			pkcs11h_token_id_list_t entry = NULL;
+			CK_TOKEN_INFO info;
+
+			if (rv == CKR_OK) {
+				rv = _pkcs11h_mem_malloc ((void *)&entry, sizeof (struct pkcs11h_token_id_list_s));
+			}
+
+			if (rv == CKR_OK) {
+				rv = current_provider->f->C_GetTokenInfo (
+					slots[slot_index],
+					&info
+				);
+			}
+
+			if (rv == CKR_OK) {
+				rv = _pkcs11h_token_getTokenId (
+					&info,
+					&entry->token_id
+				);
+			}
+
+			if (rv == CKR_OK) {
+				entry->next = token_id_list;
+				token_id_list = entry;
+				entry = NULL;
+			}
+
+			if (entry != NULL) {
+				pkcs11h_token_freeTokenIdList (entry);
+				entry = NULL;
+			}
+		}
+
+		if (rv != CKR_OK) {
+			PKCS11H_DEBUG (
+				PKCS11H_LOG_DEBUG1,
+				"PKCS#11: Cannot get slot list for provider '%s' rv=%ld-'%s'",
+				current_provider->manufacturerID,
+				rv,
+				pkcs11h_getMessage (rv)
+			);
+
+			/*
+			 * Ignore error
+			 */
+			rv = CKR_OK;
+		}
+
+		if (slots != NULL) {
+			_pkcs11h_mem_free ((void *)&slots);
+			slots = NULL;
+		}
+	}
+
+	if (rv == CKR_OK && method == PKCS11H_ENUM_METHOD_CACHE) {
+		pkcs11h_session_t session = NULL;
+
+		for (
+			session = g_pkcs11h_data->sessions;
+			session != NULL && rv == CKR_OK;
+			session = session->next
+		) {
+			pkcs11h_token_id_list_t entry = NULL;
+			PKCS11H_BOOL found = FALSE;
+
+			for (
+				entry = token_id_list;
+				entry != NULL && !found;
+				entry = entry->next
+			) {
+				if (
+					pkcs11h_token_sameTokenId (
+						session->token_id,
+						entry->token_id
+					)
+				) {
+					found = TRUE;
+				}
+			}
+
+			if (!found) {
+				entry = NULL;
+
+				if (rv == CKR_OK) {
+					rv = _pkcs11h_mem_malloc (
+						(void *)&entry,
+						sizeof (struct pkcs11h_token_id_list_s)
+					);
+				}
+
+				if (rv == CKR_OK) {
+					rv = pkcs11h_token_duplicateTokenId (
+						&entry->token_id,
+						session->token_id
+					);
+				}
+
+				if (rv == CKR_OK) {
+					entry->next = token_id_list;
+					token_id_list = entry;
+					entry = NULL;
+				}
+
+				if (entry != NULL) {
+					if (entry->token_id != NULL) {
+						pkcs11h_token_freeTokenId (entry->token_id);
+					}
+					_pkcs11h_mem_free ((void *)&entry);
+				}
+			}
+		}
+	}
+
+	if (rv == CKR_OK) {
+		*p_token_id_list = token_id_list;
+		token_id_list = NULL;
+	}
+
+	if (token_id_list != NULL) {
+		pkcs11h_token_freeTokenIdList (token_id_list);
+		token_id_list = NULL;
+	}
+
+#if defined(ENABLE_PKCS11H_THREADING)
+	if (mutex_locked) {
+		rv = _pkcs11h_threading_mutexRelease (&g_pkcs11h_data->mutexes.global);
+		mutex_locked = FALSE;
+	}
+#endif
+
+	PKCS11H_DEBUG (
+		PKCS11H_LOG_DEBUG2,
+		"PKCS#11: pkcs11h_token_enumTokenIds return rv=%ld-'%s', *p_token_id_list=%p",
+		rv,
+		pkcs11h_getMessage (rv),
+		(void *)p_token_id_list
+	);
+	
+	return rv;
+}
+
+#endif				/* ENABLE_PKCS11H_TOKEN */
diff --git a/lib/pkcs11h-util.c b/lib/pkcs11h-util.c
new file mode 100644
index 0000000..e0da128
--- /dev/null
+++ b/lib/pkcs11h-util.c
@@ -0,0 +1,279 @@
+/*
+ * Copyright (c) 2005-2006 Alon Bar-Lev <alon.barlev at gmail.com>
+ * All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, or the OpenIB.org BSD license.
+ *
+ * GNU General Public License (GPL) Version 2
+ * ===========================================
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2
+ *  as published by the Free Software Foundation.
+ *
+ *  This program 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 General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program (see the file COPYING[.GPL2] included with this
+ *  distribution); if not, write to the Free Software Foundation, Inc.,
+ *  59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * OpenIB.org BSD license
+ * =======================
+ * Redistribution and use in source and binary forms, with or without modifi-
+ * cation, are permitted provided that the following conditions are met:
+ *
+ *   o  Redistributions of source code must retain the above copyright notice,
+ *      this list of conditions and the following disclaimer.
+ *
+ *   o  Redistributions in binary form must reproduce the above copyright no-
+ *      tice, this list of conditions and the following disclaimer in the do-
+ *      cumentation and/or other materials provided with the distribution.
+ *
+ *   o  The names of the contributors may not be used to endorse or promote
+ *      products derived from this software without specific prior written
+ *      permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``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 REGENTS OR CONTRIBUTORS BE LI-
+ * ABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUEN-
+ * TIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEV-
+ * ER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABI-
+ * LITY, 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.
+ */
+
+#include "common.h"
+#include "_pkcs11h-util.h"
+
+void
+_pkcs11h_util_fixupFixedString (
+	OUT char * const target,			/* MUST BE >= length+1 */
+	IN const char * const source,
+	IN const size_t length				/* FIXED STRING LENGTH */
+) {
+	char *p;
+
+	PKCS11H_ASSERT (source!=NULL);
+	PKCS11H_ASSERT (target!=NULL);
+	
+	p = target+length;
+	memmove (target, source, length);
+	*p = '\0';
+	p--;
+	while (p >= target && *p == ' ') {
+		*p = '\0';
+		p--;
+	}
+}
+
+CK_RV
+_pkcs11h_util_hexToBinary (
+	OUT unsigned char * const target,
+	IN const char * const source,
+	IN OUT size_t * const p_target_size
+) {
+	size_t target_max_size;
+	const char *p;
+	char buf[3] = {'\0', '\0', '\0'};
+	int i = 0;
+
+	PKCS11H_ASSERT (source!=NULL);
+	PKCS11H_ASSERT (target!=NULL);
+	PKCS11H_ASSERT (p_target_size!=NULL);
+
+	target_max_size = *p_target_size;
+	p = source;
+	*p_target_size = 0;
+
+	while (*p != '\x0' && *p_target_size < target_max_size) {
+		if (isxdigit ((unsigned char)*p)) {
+			buf[i%2] = *p;
+
+			if ((i%2) == 1) {
+				unsigned v;
+				if (sscanf (buf, "%x", &v) != 1) {
+					v = 0;
+				}
+				target[*p_target_size] = (char)(v & 0xff);
+				(*p_target_size)++;
+			}
+
+			i++;
+		}
+		p++;
+	}
+
+	if (*p != '\x0') {
+		return CKR_ATTRIBUTE_VALUE_INVALID;
+	}
+	else {
+		return CKR_OK;
+	}
+}
+
+CK_RV
+_pkcs11h_util_binaryToHex (
+	OUT char * const target,
+	IN const size_t target_size,
+	IN const unsigned char * const source,
+	IN const size_t source_size
+) {
+	static const char *x = "0123456789ABCDEF";
+	size_t i;
+
+	PKCS11H_ASSERT (target!=NULL);
+	PKCS11H_ASSERT (source!=NULL);
+
+	if (target_size < source_size * 2 + 1) {
+		return CKR_ATTRIBUTE_VALUE_INVALID;
+	}
+
+	for (i=0;i<source_size;i++) {
+		target[i*2] =   x[(source[i]&0xf0)>>4];
+		target[i*2+1] = x[(source[i]&0x0f)>>0];
+	}
+	target[source_size*2] = '\x0';
+
+	return CKR_OK;
+}
+
+CK_RV
+_pkcs11h_util_escapeString (
+	IN OUT char * const target,
+	IN const char * const source,
+	IN size_t * const max,
+	IN const char * const invalid_chars
+) {
+	static const char *x = "0123456789ABCDEF";
+	CK_RV rv = CKR_OK;
+	const char *s = source;
+	char *t = target;
+	size_t n = 0;
+
+	/*PKCS11H_ASSERT (target!=NULL); Not required*/
+	PKCS11H_ASSERT (source!=NULL);
+	PKCS11H_ASSERT (max!=NULL);
+
+	while (rv == CKR_OK && *s != '\x0') {
+
+		if (*s == '\\' || strchr (invalid_chars, *s) || !isgraph (*s)) {
+			if (t != NULL) {
+				if (n+4 > *max) {
+					rv = CKR_ATTRIBUTE_VALUE_INVALID;
+				}
+				else {
+					t[0] = '\\';
+					t[1] = 'x';
+					t[2] = x[(*s&0xf0)>>4];
+					t[3] = x[(*s&0x0f)>>0];
+					t+=4;
+				}
+			}
+			n+=4;
+		}
+		else {
+			if (t != NULL) {
+				if (n+1 > *max) {
+					rv = CKR_ATTRIBUTE_VALUE_INVALID;
+				}
+				else {
+					*t = *s;
+					t++;
+				}
+			}
+			n+=1;
+		}
+
+		s++;
+	}
+
+	if (t != NULL) {
+		if (n+1 > *max) {
+			rv = CKR_ATTRIBUTE_VALUE_INVALID;
+		}
+		else {
+			*t = '\x0';
+			t++;
+		}
+	}
+	n++;
+
+	*max = n;
+
+	return rv;
+}
+
+CK_RV
+_pkcs11h_util_unescapeString (
+	IN OUT char * const target,
+	IN const char * const source,
+	IN size_t * const max
+) {
+	CK_RV rv = CKR_OK;
+	const char *s = source;
+	char *t = target;
+	size_t n = 0;
+
+	/*PKCS11H_ASSERT (target!=NULL); Not required*/
+	PKCS11H_ASSERT (source!=NULL);
+	PKCS11H_ASSERT (max!=NULL);
+
+	while (rv == CKR_OK && *s != '\x0') {
+		if (*s == '\\') {
+			if (t != NULL) {
+				if (n+1 > *max) {
+					rv = CKR_ATTRIBUTE_VALUE_INVALID;
+				}
+				else {
+					char b[3];
+					unsigned u;
+					b[0] = s[2];
+					b[1] = s[3];
+					b[2] = '\x0';
+					sscanf (b, "%08x", &u);
+					*t = (char)(u & 0xff);
+					t++;
+				}
+			}
+			s+=4;
+		}
+		else {
+			if (t != NULL) {
+				if (n+1 > *max) {
+					rv = CKR_ATTRIBUTE_VALUE_INVALID;
+				}
+				else {
+					*t = *s;
+					t++;
+				}
+			}
+			s++;
+		}
+
+		n+=1;
+	}
+
+	if (t != NULL) {
+		if (n+1 > *max) {
+			rv = CKR_ATTRIBUTE_VALUE_INVALID;
+		}
+		else {
+			*t = '\x0';
+			t++;
+		}
+	}
+	n++;
+
+	*max = n;
+
+	return rv;
+}
+
diff --git a/lib/slotevent.exports b/lib/slotevent.exports
new file mode 100644
index 0000000..dba86cb
--- /dev/null
+++ b/lib/slotevent.exports
@@ -0,0 +1 @@
+pkcs11h_setSlotEventHook
diff --git a/lib/standalone.exports b/lib/standalone.exports
new file mode 100644
index 0000000..289f476
--- /dev/null
+++ b/lib/standalone.exports
@@ -0,0 +1,2 @@
+pkcs11h_standalone_dump_objects
+pkcs11h_standalone_dump_slots
diff --git a/lib/token.exports b/lib/token.exports
new file mode 100644
index 0000000..9ac673b
--- /dev/null
+++ b/lib/token.exports
@@ -0,0 +1,9 @@
+pkcs11h_token_deserializeTokenId
+pkcs11h_token_duplicateTokenId
+pkcs11h_token_ensureAccess
+pkcs11h_token_enumTokenIds
+pkcs11h_token_freeTokenId
+pkcs11h_token_freeTokenIdList
+pkcs11h_token_login
+pkcs11h_token_sameTokenId
+pkcs11h_token_serializeTokenId
diff --git a/m4dir/Makefile.am b/m4dir/Makefile.am
new file mode 100644
index 0000000..8639793
--- /dev/null
+++ b/m4dir/Makefile.am
@@ -0,0 +1,55 @@
+#
+# Copyright (c) 2005-2006 Alon Bar-Lev <alon.barlev at gmail.com>
+# All rights reserved.
+#
+# This software is available to you under a choice of one of two
+# licenses.  You may choose to be licensed under the terms of the GNU
+# General Public License (GPL) Version 2, or the OpenIB.org BSD license.
+#
+# GNU General Public License (GPL) Version 2
+# ===========================================
+#  This program is free software; you can redistribute it and/or modify
+#  it under the terms of the GNU General Public License version 2
+#  as published by the Free Software Foundation.
+#
+#  This program 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 General Public License for more details.
+#
+#  You should have received a copy of the GNU General Public License
+#  along with this program (see the file COPYING[.GPL2] included with this
+#  distribution); if not, write to the Free Software Foundation, Inc.,
+#  59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+#
+# OpenIB.org BSD license
+# =======================
+# Redistribution and use in source and binary forms, with or without modifi-
+# cation, are permitted provided that the following conditions are met:
+#
+#   o  Redistributions of source code must retain the above copyright notice,
+#      this list of conditions and the following disclaimer.
+#
+#   o  Redistributions in binary form must reproduce the above copyright no-
+#      tice, this list of conditions and the following disclaimer in the do-
+#      cumentation and/or other materials provided with the distribution.
+#
+#   o  The names of the contributors may not be used to endorse or promote
+#      products derived from this software without specific prior written
+#      permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# ``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 REGENTS OR CONTRIBUTORS BE LI-
+# ABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUEN-
+# TIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEV-
+# ER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABI-
+# LITY, 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.
+#
+
+m4dir = $(datadir)/aclocal
+dist_m4_DATA = pkcs11-helper-1.m4
+
diff --git a/m4dir/pkcs11-helper-1.m4 b/m4dir/pkcs11-helper-1.m4
new file mode 100644
index 0000000..2fa72a7
--- /dev/null
+++ b/m4dir/pkcs11-helper-1.m4
@@ -0,0 +1,70 @@
+# pkcs11-helper-1.m4 - Macros to locate and utilise pkcs11-helper.     -*- Autoconf -*-
+#
+# Copyright (c) 2005-2006 Alon Bar-Lev <alon.barlev at gmail.com>
+# All rights reserved.
+#
+# This software is available to you under a choice of one of two
+# licenses.  You may choose to be licensed under the terms of the GNU
+# General Public License (GPL) Version 2, or the OpenIB.org BSD license.
+#
+# GNU General Public License (GPL) Version 2
+# ===========================================
+#  This program is free software; you can redistribute it and/or modify
+#  it under the terms of the GNU General Public License version 2
+#  as published by the Free Software Foundation.
+#
+#  This program 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 General Public License for more details.
+#
+#  You should have received a copy of the GNU General Public License
+#  along with this program (see the file COPYING[.GPL2] included with this
+#  distribution); if not, write to the Free Software Foundation, Inc.,
+#  59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+#
+# OpenIB.org BSD license
+# =======================
+# Redistribution and use in source and binary forms, with or without modifi-
+# cation, are permitted provided that the following conditions are met:
+#
+#   o  Redistributions of source code must retain the above copyright notice,
+#      this list of conditions and the following disclaimer.
+#
+#   o  Redistributions in binary form must reproduce the above copyright no-
+#      tice, this list of conditions and the following disclaimer in the do-
+#      cumentation and/or other materials provided with the distribution.
+#
+#   o  The names of the contributors may not be used to endorse or promote
+#      products derived from this software without specific prior written
+#      permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# ``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 REGENTS OR CONTRIBUTORS BE LI-
+# ABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUEN-
+# TIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEV-
+# ER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABI-
+# LITY, 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.
+#
+
+# PKCS11_HELPER_CHECK_FEATURES([features])
+#
+# Check whether features exists in pkcs11-helper.
+#
+# debug threading token data certificate locate slotevent openssl standalone engine_crypto
+#
+AC_DEFUN([PKCS11_HELPER_1_CHECK_FEATURES], [
+	AC_ARG_VAR([PKCS11_HELPER_FEATURES], [pkcs11-helperer feartures overriding pkg-config])
+	AC_MSG_CHECKING([pkcs11-helper features])
+	_PKG_CONFIG([PKCS11_HELPER_FEATURES], [variable features], [libpkcs11-helper-1])
+	PKCS11_HELPER_FEATURES=$pkg_cv_PKCS11_HELPER_FEATURES
+	for pkcs11h_feature in $1; do
+		echo " ${PKCS11_HELPER_FEATURES} " | grep " ${pkcs11h_feature} " > /dev/null 2>&1 || \
+			AC_MSG_ERROR([pkcs11-helper ${pkcs11h_feature} feature must be enabled.])
+	done
+	AC_MSG_RESULT([ok])
+])
diff --git a/man/Makefile.am b/man/Makefile.am
new file mode 100644
index 0000000..c6ecf75
--- /dev/null
+++ b/man/Makefile.am
@@ -0,0 +1,72 @@
+#
+# Copyright (c) 2005-2006 Alon Bar-Lev <alon.barlev at gmail.com>
+# All rights reserved.
+#
+# This software is available to you under a choice of one of two
+# licenses.  You may choose to be licensed under the terms of the GNU
+# General Public License (GPL) Version 2, or the OpenIB.org BSD license.
+#
+# GNU General Public License (GPL) Version 2
+# ===========================================
+#  This program is free software; you can redistribute it and/or modify
+#  it under the terms of the GNU General Public License version 2
+#  as published by the Free Software Foundation.
+#
+#  This program 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 General Public License for more details.
+#
+#  You should have received a copy of the GNU General Public License
+#  along with this program (see the file COPYING[.GPL2] included with this
+#  distribution); if not, write to the Free Software Foundation, Inc.,
+#  59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+#
+# OpenIB.org BSD license
+# =======================
+# Redistribution and use in source and binary forms, with or without modifi-
+# cation, are permitted provided that the following conditions are met:
+#
+#   o  Redistributions of source code must retain the above copyright notice,
+#      this list of conditions and the following disclaimer.
+#
+#   o  Redistributions in binary form must reproduce the above copyright no-
+#      tice, this list of conditions and the following disclaimer in the do-
+#      cumentation and/or other materials provided with the distribution.
+#
+#   o  The names of the contributors may not be used to endorse or promote
+#      products derived from this software without specific prior written
+#      permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# ``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 REGENTS OR CONTRIBUTORS BE LI-
+# ABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUEN-
+# TIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEV-
+# ER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABI-
+# LITY, 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.
+#
+
+if WIN32
+
+%.8.html:
+	$(MAN2HTML) < $*.8 > $@
+%.3.html:
+	$(MAN2HTML) < $*.3 > $@
+	
+nodist_html_DATA=$(shell ls *.[0-9] | sed -r 's/(\.[0-9])/\1.html/g')
+
+endif
+
+# Must add exist file so automake will add this dependency
+if WIN32
+EXTRA_DIST=$(shell ls *.[0-9]) pkcs11-helper.8
+else
+dist_man_MANS=$(shell ls *.[0-9]) pkcs11-helper.8
+endif
+
+clean-generic:
+	-rm -f *.html
diff --git a/man/pkcs11-helper.8 b/man/pkcs11-helper.8
new file mode 100644
index 0000000..23d0461
--- /dev/null
+++ b/man/pkcs11-helper.8
@@ -0,0 +1,72 @@
+.\"
+.\" Copyright (c) 2005-2006 Alon Bar-Lev <alon.barlev at gmail.com>
+.\" All rights reserved.
+.\"
+.\" This software is available to you under a choice of one of two
+.\" licenses.  You may choose to be licensed under the terms of the GNU
+.\" General Public License (GPL) Version 2, or the OpenIB.org BSD license.
+.\"
+.\" GNU General Public License (GPL) Version 2
+.\" ===========================================
+.\"  This program is free software; you can redistribute it and/or modify
+.\"  it under the terms of the GNU General Public License version 2
+.\"  as published by the Free Software Foundation.
+.\"
+.\"  This program 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 General Public License for more details.
+.\"
+.\"  You should have received a copy of the GNU General Public License
+.\"  along with this program (see the file COPYING[.GPL2] included with this
+.\"  distribution); if not, write to the Free Software Foundation, Inc.,
+.\"  59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+.\"
+.\" OpenIB.org BSD license
+.\" =======================
+.\" Redistribution and use in source and binary forms, with or without modifi-
+.\" cation, are permitted provided that the following conditions are met:
+.\"
+.\"   o  Redistributions of source code must retain the above copyright notice,
+.\"      this list of conditions and the following disclaimer.
+.\"
+.\"   o  Redistributions in binary form must reproduce the above copyright no-
+.\"      tice, this list of conditions and the following disclaimer in the do-
+.\"      cumentation and/or other materials provided with the distribution.
+.\"
+.\"   o  The names of the contributors may not be used to endorse or promote
+.\"      products derived from this software without specific prior written
+.\"      permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+.\" ``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 REGENTS OR CONTRIBUTORS BE LI-
+.\" ABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUEN-
+.\" TIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEV-
+.\" ER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABI-
+.\" LITY, 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.
+.\"
+.Dd November 18, 2006
+.Os POSIX-compatible
+.Dt pkcs11-helper 1
+.Sh NAME
+.Nm pkcs11-helper
+.Nd Simplefied PKCS#11 library.
+.Sh DESCRIPTION
+.Nm pkcs11-helper
+is a simplified API for accessing PKCS#11 tokens for user applications.
+.Sh AUTHORS AND COPYRIGHT
+Copyright (c) 2006 Alon Bar-Lev <alon.barlev at gmail.com>
+.Pp
+All rights reserved.
+.Pp
+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/tests/Makefile.am b/tests/Makefile.am
new file mode 100644
index 0000000..4e43a7e
--- /dev/null
+++ b/tests/Makefile.am
@@ -0,0 +1,53 @@
+#
+# Copyright (c) 2005-2006 Alon Bar-Lev <alon.barlev at gmail.com>
+# All rights reserved.
+#
+# This software is available to you under a choice of one of two
+# licenses.  You may choose to be licensed under the terms of the GNU
+# General Public License (GPL) Version 2, or the OpenIB.org BSD license.
+#
+# GNU General Public License (GPL) Version 2
+# ===========================================
+#  This program is free software; you can redistribute it and/or modify
+#  it under the terms of the GNU General Public License version 2
+#  as published by the Free Software Foundation.
+#
+#  This program 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 General Public License for more details.
+#
+#  You should have received a copy of the GNU General Public License
+#  along with this program (see the file COPYING[.GPL2] included with this
+#  distribution); if not, write to the Free Software Foundation, Inc.,
+#  59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+#
+# OpenIB.org BSD license
+# =======================
+# Redistribution and use in source and binary forms, with or without modifi-
+# cation, are permitted provided that the following conditions are met:
+#
+#   o  Redistributions of source code must retain the above copyright notice,
+#      this list of conditions and the following disclaimer.
+#
+#   o  Redistributions in binary form must reproduce the above copyright no-
+#      tice, this list of conditions and the following disclaimer in the do-
+#      cumentation and/or other materials provided with the distribution.
+#
+#   o  The names of the contributors may not be used to endorse or promote
+#      products derived from this software without specific prior written
+#      permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# ``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 REGENTS OR CONTRIBUTORS BE LI-
+# ABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUEN-
+# TIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEV-
+# ER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABI-
+# LITY, 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.
+#
+
+SUBDIRS=basic certificate slotevent
diff --git a/tests/basic/Makefile.am b/tests/basic/Makefile.am
new file mode 100644
index 0000000..c707ffa
--- /dev/null
+++ b/tests/basic/Makefile.am
@@ -0,0 +1,62 @@
+#
+# Copyright (c) 2005-2006 Alon Bar-Lev <alon.barlev at gmail.com>
+# All rights reserved.
+#
+# This software is available to you under a choice of one of two
+# licenses.  You may choose to be licensed under the terms of the GNU
+# General Public License (GPL) Version 2, or the OpenIB.org BSD license.
+#
+# GNU General Public License (GPL) Version 2
+# ===========================================
+#  This program is free software; you can redistribute it and/or modify
+#  it under the terms of the GNU General Public License version 2
+#  as published by the Free Software Foundation.
+#
+#  This program 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 General Public License for more details.
+#
+#  You should have received a copy of the GNU General Public License
+#  along with this program (see the file COPYING[.GPL2] included with this
+#  distribution); if not, write to the Free Software Foundation, Inc.,
+#  59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+#
+# OpenIB.org BSD license
+# =======================
+# Redistribution and use in source and binary forms, with or without modifi-
+# cation, are permitted provided that the following conditions are met:
+#
+#   o  Redistributions of source code must retain the above copyright notice,
+#      this list of conditions and the following disclaimer.
+#
+#   o  Redistributions in binary form must reproduce the above copyright no-
+#      tice, this list of conditions and the following disclaimer in the do-
+#      cumentation and/or other materials provided with the distribution.
+#
+#   o  The names of the contributors may not be used to endorse or promote
+#      products derived from this software without specific prior written
+#      permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# ``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 REGENTS OR CONTRIBUTORS BE LI-
+# ABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUEN-
+# TIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEV-
+# ER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABI-
+# LITY, 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.
+#
+
+INCLUDES= \
+	-I$(top_srcdir)/include
+DEPS= \
+	$(top_builddir)/lib/libpkcs11-helper.la
+LDADD= \
+	$(top_builddir)/lib/libpkcs11-helper.la
+
+TESTS=basic
+noinst_PROGRAMS=basic
+basic_SOURCES=basic.c
diff --git a/tests/basic/basic.c b/tests/basic/basic.c
new file mode 100644
index 0000000..f589c88
--- /dev/null
+++ b/tests/basic/basic.c
@@ -0,0 +1,69 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include "../../config.h"
+#include <pkcs11-helper-1.0/pkcs11h-core.h>
+
+static
+void
+fatal (const char * const m, CK_RV rv) {
+	fprintf (stderr, "%s - %08lx - %s\n", m, rv, pkcs11h_getMessage (rv));
+	exit (1);
+}
+
+static
+void
+_pkcs11h_hooks_log (
+	IN void * const global_data,
+	IN unsigned flags,
+	IN const char * const format,
+	IN va_list args
+) {
+	vfprintf (stdout, format, args);
+	fprintf (stdout, "\n");
+}
+
+int main () {
+	CK_RV rv;
+
+	printf ("Version: %08x\n", pkcs11h_getVersion ());
+	printf ("Features: %08x\n", pkcs11h_getFeatures ());
+
+	printf ("Initializing pkcs11-helper\n");
+
+	if ((rv = pkcs11h_initialize ()) != CKR_OK) {
+		fatal ("pkcs11h_initialize failed", rv);
+	}
+
+	printf ("Registering pkcs11-helper hooks\n");
+
+	if ((rv = pkcs11h_setLogHook (_pkcs11h_hooks_log, NULL)) != CKR_OK) {
+		fatal ("pkcs11h_setLogHook failed", rv);
+	}
+
+	pkcs11h_setLogLevel (TEST_LOG_LEVEL);
+
+	printf ("Adding provider '%s'\n", TEST_PROVIDER);
+
+	if (
+		(rv = pkcs11h_addProvider (
+			TEST_PROVIDER,
+			TEST_PROVIDER,
+			FALSE,
+			PKCS11H_PRIVATEMODE_MASK_AUTO,
+			PKCS11H_SLOTEVENT_METHOD_AUTO,
+			0,
+			FALSE
+		)) != CKR_OK
+	) {
+		fatal ("pkcs11h_terminate failed", rv);
+	}
+
+	printf ("Terminating pkcs11-helper\n");
+
+	if ((rv = pkcs11h_terminate ()) != CKR_OK) {
+		fatal ("pkcs11h_terminate failed", rv);
+	}
+
+	exit (0);
+	return 0;
+}
diff --git a/tests/certificate/Makefile.am b/tests/certificate/Makefile.am
new file mode 100644
index 0000000..9e1c99b
--- /dev/null
+++ b/tests/certificate/Makefile.am
@@ -0,0 +1,62 @@
+#
+# Copyright (c) 2005-2006 Alon Bar-Lev <alon.barlev at gmail.com>
+# All rights reserved.
+#
+# This software is available to you under a choice of one of two
+# licenses.  You may choose to be licensed under the terms of the GNU
+# General Public License (GPL) Version 2, or the OpenIB.org BSD license.
+#
+# GNU General Public License (GPL) Version 2
+# ===========================================
+#  This program is free software; you can redistribute it and/or modify
+#  it under the terms of the GNU General Public License version 2
+#  as published by the Free Software Foundation.
+#
+#  This program 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 General Public License for more details.
+#
+#  You should have received a copy of the GNU General Public License
+#  along with this program (see the file COPYING[.GPL2] included with this
+#  distribution); if not, write to the Free Software Foundation, Inc.,
+#  59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+#
+# OpenIB.org BSD license
+# =======================
+# Redistribution and use in source and binary forms, with or without modifi-
+# cation, are permitted provided that the following conditions are met:
+#
+#   o  Redistributions of source code must retain the above copyright notice,
+#      this list of conditions and the following disclaimer.
+#
+#   o  Redistributions in binary form must reproduce the above copyright no-
+#      tice, this list of conditions and the following disclaimer in the do-
+#      cumentation and/or other materials provided with the distribution.
+#
+#   o  The names of the contributors may not be used to endorse or promote
+#      products derived from this software without specific prior written
+#      permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# ``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 REGENTS OR CONTRIBUTORS BE LI-
+# ABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUEN-
+# TIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEV-
+# ER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABI-
+# LITY, 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.
+#
+
+INCLUDES= \
+	-I$(top_srcdir)/include
+DEPS= \
+	$(top_builddir)/lib/libpkcs11-helper.la
+LDADD= \
+	$(top_builddir)/lib/libpkcs11-helper.la
+
+TESTS=certificate
+noinst_PROGRAMS=certificate
+certificate_SOURCES=certificate.c
diff --git a/tests/certificate/certificate.c b/tests/certificate/certificate.c
new file mode 100644
index 0000000..a9e3732
--- /dev/null
+++ b/tests/certificate/certificate.c
@@ -0,0 +1,322 @@
+#include "../../config.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#if !(!defined(_WIN32) && defined(ENABLE_PKCS11H_CERTIFICATE) && (defined(ENABLE_PKCS11H_ENGINE_OPENSSL) || defined (ENABLE_PKCS11H_ENGINE_GNUTLS) || defined(ENABLE_PKCS11H_ENGINE_WIN32)))
+int main () {
+	printf ("!win32, certificate, enum and crypto engine interfaces should be enabled for this test");
+	exit (0);
+	return 0;
+}
+#else
+
+#include <pkcs11-helper-1.0/pkcs11h-certificate.h>
+#include <unistd.h>
+
+static
+void
+fatal (const char * const m, CK_RV rv) {
+	fprintf (stderr, "%s - %08lx - %s\n", m, rv, pkcs11h_getMessage (rv));
+	exit (1);
+}
+
+static
+void
+mypause (const char * const m) {
+	char temp[10];
+
+	fprintf (stdout, "%s", m);
+	fgets (temp, sizeof (temp), stdin);
+}
+
+static
+void
+_pkcs11h_hooks_log (
+	IN void * const global_data,
+	IN unsigned flags,
+	IN const char * const format,
+	IN va_list args
+) {
+	vfprintf (stdout, format, args);
+	fprintf (stdout, "\n");
+}
+
+static
+PKCS11H_BOOL
+_pkcs11h_hooks_token_prompt (
+	IN void * const global_data,
+	IN void * const user_data,
+	IN const pkcs11h_token_id_t token,
+	IN const unsigned retry
+) {
+	char buf[1024];
+	PKCS11H_BOOL fValidInput = FALSE;
+	PKCS11H_BOOL fRet = FALSE;
+
+	while (!fValidInput) {
+		fprintf (stderr, "Please insert token '%s' 'ok' or 'cancel': ", token->display);
+		fgets (buf, sizeof (buf), stdin);
+		buf[sizeof (buf)-1] = '\0';
+		fflush (stdin);
+
+		if (buf[strlen (buf)-1] == '\n') {
+			buf[strlen (buf)-1] = '\0';
+		}
+		if (buf[strlen (buf)-1] == '\r') {
+			buf[strlen (buf)-1] = '\0';
+		}
+
+		if (!strcmp (buf, "ok")) {
+			fValidInput = TRUE;
+			fRet = TRUE;
+		}
+		else if (!strcmp (buf, "cancel")) {
+			fValidInput = TRUE;
+		}
+	}
+
+	return fRet; 
+}
+
+static
+PKCS11H_BOOL
+_pkcs11h_hooks_pin_prompt (
+	IN void * const global_data,
+	IN void * const user_data,
+	IN const pkcs11h_token_id_t token,
+	IN const unsigned retry,
+	OUT char * const pin,
+	IN const size_t pin_max
+) {
+	char prompt[1024];
+	char *p = NULL;
+
+	snprintf (prompt, sizeof (prompt), "Please enter '%s' PIN or 'cancel': ", token->display);
+
+#if defined(_WIN32)
+	{
+		size_t i = 0;
+		char c;
+		while (i < pin_max && (c = getch ()) != '\r') {
+			pin[i++] = c;
+		}
+	}
+
+	fprintf (stderr, "\n");
+#else
+	p = getpass (prompt);
+#endif
+
+	strncpy (pin, p, pin_max);
+	pin[pin_max-1] = '\0';
+
+	return strcmp (pin, "cancel") != 0;
+}
+
+void
+sign_test (const pkcs11h_certificate_t cert) {
+
+	static unsigned const char sha1_data[] = {
+		0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e, 0x03, /* 1.3.14.3.2.26 */
+		0x02, 0x1a, 0x05, 0x00, 0x04, 0x14,
+		0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,	/* dummy data */
+		0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+		0x10, 0x11, 0x12, 0x13, 0x14
+	};
+
+	CK_RV rv;
+					 
+	unsigned char *blob;
+	size_t blob_size;
+
+	if (
+		(rv = pkcs11h_certificate_signAny (
+			cert,
+			CKM_RSA_PKCS,
+			sha1_data,
+			sizeof (sha1_data),
+			NULL,
+			&blob_size
+		)) != CKR_OK
+	) {
+		fatal ("pkcs11h_certificate_sign(1) failed", rv);
+	}
+
+	blob = (unsigned char *)malloc (blob_size);
+
+	if (
+		(rv = pkcs11h_certificate_signAny (
+			cert,
+			CKM_RSA_PKCS,
+			sha1_data,
+			sizeof (sha1_data),
+			blob,
+			&blob_size
+		)) != CKR_OK
+	) {
+		fatal ("pkcs11h_certificate_sign(1) failed", rv);
+	}
+
+	free (blob);
+}
+
+int main () {
+	pkcs11h_certificate_id_list_t issuers, certs, temp;
+	pkcs11h_certificate_t cert;
+	CK_RV rv;
+
+	printf ("Initializing pkcs11-helper\n");
+
+	if ((rv = pkcs11h_initialize ()) != CKR_OK) {
+		fatal ("pkcs11h_initialize failed", rv);
+	}
+
+	printf ("Registering pkcs11-helper hooks\n");
+
+	if ((rv = pkcs11h_setLogHook (_pkcs11h_hooks_log, NULL)) != CKR_OK) {
+		fatal ("pkcs11h_setLogHook failed", rv);
+	}
+
+	pkcs11h_setLogLevel (TEST_LOG_LEVEL);
+
+	if ((rv = pkcs11h_setTokenPromptHook (_pkcs11h_hooks_token_prompt, NULL)) != CKR_OK) {
+		fatal ("pkcs11h_setTokenPromptHook failed", rv);
+	}
+
+	if ((rv = pkcs11h_setPINPromptHook (_pkcs11h_hooks_pin_prompt, NULL)) != CKR_OK) {
+		fatal ("pkcs11h_setPINPromptHook failed", rv);
+	}
+
+	printf ("Adding provider '%s'\n", TEST_PROVIDER);
+
+	if (
+		(rv = pkcs11h_addProvider (
+			TEST_PROVIDER,
+			TEST_PROVIDER,
+			FALSE,
+			PKCS11H_PRIVATEMODE_MASK_AUTO,
+			PKCS11H_SLOTEVENT_METHOD_AUTO,
+			0,
+			FALSE
+		)) != CKR_OK
+	) {
+		fatal ("pkcs11h_terminate failed", rv);
+	}
+
+	mypause ("Please remove all tokens, press <Enter>: ");
+
+	printf ("Enumerating token certificate (list should be empty, no prompt)\n");
+
+	if (
+		(rv = pkcs11h_certificate_enumCertificateIds (
+			PKCS11H_ENUM_METHOD_CACHE,
+			NULL,
+			PKCS11H_PROMPT_MASK_ALLOW_ALL,
+			&issuers,
+			&certs
+		)) != CKR_OK
+	) {
+		fatal ("pkcs11h_certificate_enumCertificateIds failed", rv);
+	}
+
+	if (issuers != NULL || certs != NULL) {
+		fatal ("No certificates should be found", rv);
+	}
+
+	mypause ("Please insert token, press <Enter>: ");
+
+	printf ("Getting certificate cache, should be available certificates\n");
+
+	if (
+		(rv = pkcs11h_certificate_enumCertificateIds (
+			PKCS11H_ENUM_METHOD_CACHE,
+			NULL,
+			PKCS11H_PROMPT_MASK_ALLOW_ALL,
+			&issuers,
+			&certs
+		)) != CKR_OK
+	) {
+		fatal ("pkcs11h_certificate_enumCertificateIds failed", rv);
+	}
+
+	for (temp = issuers;temp != NULL;temp = temp->next) {
+		printf ("Issuer: %s\n", temp->certificate_id->displayName);
+	}
+	for (temp = certs;temp != NULL;temp = temp->next) {
+		printf ("Certificate: %s\n", temp->certificate_id->displayName);
+	}
+
+	if (certs == NULL) {
+		fatal ("No certificates found", rv);
+	}
+
+	pkcs11h_certificate_freeCertificateIdList (issuers);
+	pkcs11h_certificate_freeCertificateIdList (certs);
+
+	mypause ("Please remove token, press <Enter>: ");
+
+	printf ("Getting certificate cache, should be similar to last\n");
+
+	if (
+		(rv = pkcs11h_certificate_enumCertificateIds (
+			PKCS11H_ENUM_METHOD_CACHE,
+			NULL,
+			PKCS11H_PROMPT_MASK_ALLOW_ALL,
+			&issuers,
+			&certs
+		)) != CKR_OK
+	) {
+		fatal ("pkcs11h_certificate_enumCertificateIds failed", rv);
+	}
+
+	for (temp = issuers;temp != NULL;temp = temp->next) {
+		printf ("Issuer: %s\n", temp->certificate_id->displayName);
+	}
+	for (temp = certs;temp != NULL;temp = temp->next) {
+		printf ("Certificate: %s\n", temp->certificate_id->displayName);
+	}
+
+	if (certs == NULL) {
+		fatal ("No certificates found", rv);
+	}
+
+	printf ("Creating certificate context\n");
+
+	if (
+		(rv = pkcs11h_certificate_create (
+			certs->certificate_id,
+			NULL,
+			PKCS11H_PROMPT_MASK_ALLOW_ALL,
+			PKCS11H_PIN_CACHE_INFINITE,
+			&cert
+		)) != CKR_OK
+	) {
+		fatal ("pkcs11h_certificate_create failed", rv);
+	}
+
+	printf ("Perforing signature #1 (you should be prompt for token and PIN)\n");
+
+	sign_test (cert);
+
+	printf ("Perforing signature #2 (you should NOT be prompt for anything)\n");
+
+	sign_test (cert);
+
+	mypause ("Please remove and insert token, press <Enter>: ");
+
+	printf ("Perforing signature #3 (you should be prompt only for PIN)\n");
+
+	sign_test (cert);
+
+	printf ("Terminating pkcs11-helper\n");
+
+	if ((rv = pkcs11h_terminate ()) != CKR_OK) {
+		fatal ("pkcs11h_terminate failed", rv);
+	}
+
+	exit (0);
+	return 0;
+}
+
+#endif
diff --git a/tests/slotevent/Makefile.am b/tests/slotevent/Makefile.am
new file mode 100644
index 0000000..2e0e677
--- /dev/null
+++ b/tests/slotevent/Makefile.am
@@ -0,0 +1,62 @@
+#
+# Copyright (c) 2005-2006 Alon Bar-Lev <alon.barlev at gmail.com>
+# All rights reserved.
+#
+# This software is available to you under a choice of one of two
+# licenses.  You may choose to be licensed under the terms of the GNU
+# General Public License (GPL) Version 2, or the OpenIB.org BSD license.
+#
+# GNU General Public License (GPL) Version 2
+# ===========================================
+#  This program is free software; you can redistribute it and/or modify
+#  it under the terms of the GNU General Public License version 2
+#  as published by the Free Software Foundation.
+#
+#  This program 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 General Public License for more details.
+#
+#  You should have received a copy of the GNU General Public License
+#  along with this program (see the file COPYING[.GPL2] included with this
+#  distribution); if not, write to the Free Software Foundation, Inc.,
+#  59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+#
+# OpenIB.org BSD license
+# =======================
+# Redistribution and use in source and binary forms, with or without modifi-
+# cation, are permitted provided that the following conditions are met:
+#
+#   o  Redistributions of source code must retain the above copyright notice,
+#      this list of conditions and the following disclaimer.
+#
+#   o  Redistributions in binary form must reproduce the above copyright no-
+#      tice, this list of conditions and the following disclaimer in the do-
+#      cumentation and/or other materials provided with the distribution.
+#
+#   o  The names of the contributors may not be used to endorse or promote
+#      products derived from this software without specific prior written
+#      permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# ``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 REGENTS OR CONTRIBUTORS BE LI-
+# ABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUEN-
+# TIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEV-
+# ER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABI-
+# LITY, 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.
+#
+
+INCLUDES= \
+	-I$(top_srcdir)/include
+DEPS= \
+	$(top_builddir)/lib/libpkcs11-helper.la
+LDADD= \
+	$(top_builddir)/lib/libpkcs11-helper.la
+
+TESTS=slotevent
+noinst_PROGRAMS=slotevent
+slotevent_SOURCES=slotevent.c
diff --git a/tests/slotevent/slotevent.c b/tests/slotevent/slotevent.c
new file mode 100644
index 0000000..a36f95e
--- /dev/null
+++ b/tests/slotevent/slotevent.c
@@ -0,0 +1,141 @@
+#include "../../config.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#if !defined(ENABLE_PKCS11H_SLOTEVENT)
+int main () {
+	printf ("!win32, certificate, enum and crypto engine interfaces should be enabled for this test");
+	exit (0);
+	return 0;
+}
+#else
+
+#if defined(_WIN32)
+#include <windows.h>
+#else
+#include <unistd.h>
+#endif
+
+#include <pkcs11-helper-1.0/pkcs11h-core.h>
+
+static
+void
+fatal (const char * const m, CK_RV rv) {
+	fprintf (stderr, "%s - %08lx - %s\n", m, rv, pkcs11h_getMessage (rv));
+	exit (1);
+}
+
+static
+void
+mypause (const char * const m) {
+	char temp[10];
+
+	fprintf (stdout, "%s", m);
+	fgets (temp, sizeof (temp), stdin);
+}
+
+static
+void
+_pkcs11h_hooks_log (
+	IN void * const global_data,
+	IN unsigned flags,
+	IN const char * const format,
+	IN va_list args
+) {
+	vfprintf (stdout, format, args);
+	fprintf (stdout, "\n");
+}
+
+static
+void
+_pkcs11h_hooks_slotevent (
+	IN void * const global_data
+) {
+	printf ("slotevent\n");
+}
+
+int main () {
+	CK_RV rv;
+
+	printf ("Initializing pkcs11-helper\n");
+
+	if ((rv = pkcs11h_initialize ()) != CKR_OK) {
+		fatal ("pkcs11h_initialize failed", rv);
+	}
+
+	printf ("Registering pkcs11-helper hooks\n");
+
+	if ((rv = pkcs11h_setLogHook (_pkcs11h_hooks_log, NULL)) != CKR_OK) {
+		fatal ("pkcs11h_setLogHook failed", rv);
+	}
+
+	pkcs11h_setLogLevel (TEST_LOG_LEVEL);
+
+	if ((rv = pkcs11h_setSlotEventHook (_pkcs11h_hooks_slotevent, NULL)) != CKR_OK) {
+		fatal ("pkcs11h_setSlotEventHook failed", rv);
+	}
+
+	printf ("Adding provider '%s' as trigger\n", TEST_PROVIDER);
+
+	if (
+		(rv = pkcs11h_addProvider (
+			TEST_PROVIDER,
+			TEST_PROVIDER,
+			FALSE,
+			PKCS11H_PRIVATEMODE_MASK_AUTO,
+			PKCS11H_SLOTEVENT_METHOD_TRIGGER,
+			0,
+			FALSE
+		)) != CKR_OK
+	) {
+		fatal ("pkcs11h_terminate failed", rv);
+	}
+
+	printf ("Please remove and insert tokens (pause for 30 seconds)\n");
+
+#if defined(_WIN32)
+	Sleep (30*1024);
+#else
+	sleep (30);
+#endif
+
+	if ((rv = pkcs11h_removeProvider (TEST_PROVIDER)) != CKR_OK) {
+		fatal ("pkcs11h_removeProvider failed", rv);
+	}
+
+	printf ("Adding provider '%s' as poll\n", TEST_PROVIDER);
+
+	if (
+		(rv = pkcs11h_addProvider (
+			TEST_PROVIDER,
+			TEST_PROVIDER,
+			FALSE,
+			PKCS11H_PRIVATEMODE_MASK_AUTO,
+			PKCS11H_SLOTEVENT_METHOD_POLL,
+			0,
+			FALSE
+		)) != CKR_OK
+	) {
+		fatal ("pkcs11h_terminate failed", rv);
+	}
+
+	printf ("Please remove and insert tokens (pause for 30 seconds)\n");
+
+#if defined(_WIN32)
+	Sleep (30*1024);
+#else
+	sleep (30);
+#endif
+
+	printf ("Terminating pkcs11-helper\n");
+
+	if ((rv = pkcs11h_terminate ()) != CKR_OK) {
+		fatal ("pkcs11h_terminate failed", rv);
+	}
+
+	exit (0);
+	return 0;
+}
+
+#endif

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-opensc/pkcs11-helper.git



More information about the pkg-opensc-commit mailing list