gnutls-commit
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[SCM] GNU gnutls branch, new, updated. gnutls_2_9_10-124-g0f65714


From: Nikos Mavrogiannopoulos
Subject: [SCM] GNU gnutls branch, new, updated. gnutls_2_9_10-124-g0f65714
Date: Mon, 24 May 2010 14:59:14 +0000

This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "GNU gnutls".

http://git.savannah.gnu.org/cgit/gnutls.git/commit/?id=0f6571477775e596c61bf17941364b6ca1235029

The branch, new has been updated
       via  0f6571477775e596c61bf17941364b6ca1235029 (commit)
       via  64fe18da279969b3cd9aafb1a6c29ad87ccf5529 (commit)
       via  f185ecddeeedf3137ea512431cb19ee9dc7bf11f (commit)
       via  e86e02ffc63a052a2d13325146ef2a217a606e5c (commit)
       via  ae67fc67c4b6412922327b429044620ea001e6cf (commit)
      from  520827b6f8a49ee9351bb12f63160a773ad46997 (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commit 0f6571477775e596c61bf17941364b6ca1235029
Author: Nikos Mavrogiannopoulos <address@hidden>
Date:   Mon May 24 16:58:31 2010 +0200

    Added a modified pakchois library (to open arbitrary pkcs11 modules).
    Current gnutls works only with this one.

commit 64fe18da279969b3cd9aafb1a6c29ad87ccf5529
Author: Nikos Mavrogiannopoulos <address@hidden>
Date:   Mon May 24 16:58:27 2010 +0200

    Added missing file.

commit f185ecddeeedf3137ea512431cb19ee9dc7bf11f
Author: Nikos Mavrogiannopoulos <address@hidden>
Date:   Mon May 24 09:10:49 2010 +0200

    Removed finished items.

commit e86e02ffc63a052a2d13325146ef2a217a606e5c
Author: Nikos Mavrogiannopoulos <address@hidden>
Date:   Mon May 24 09:08:05 2010 +0200

    Noted that there things to be done.

commit ae67fc67c4b6412922327b429044620ea001e6cf
Author: Nikos Mavrogiannopoulos <address@hidden>
Date:   Mon May 24 09:07:50 2010 +0200

    Added documentation on abstract types.

-----------------------------------------------------------------------

Summary of changes:
 doc/Makefile.am           |    6 +-
 doc/TODO                  |    4 -
 doc/cha-cert-auth.texi    |  307 ++++++-----
 doc/cha-gtls-app.texi     |  495 +++++++++++++++++
 lib/Makefile.am           |    8 +-
 lib/configure.ac          |   17 -
 lib/m4/hooks.m4           |   29 +
 lib/pakchois/errors.c     |  146 +++++
 lib/pakchois/pakchois.c   |  982 ++++++++++++++++++++++++++++++++
 lib/pakchois/pakchois.h   |  361 ++++++++++++
 lib/pakchois/pakchois11.h | 1357 +++++++++++++++++++++++++++++++++++++++++++++
 lib/pkcs11_write.c        |   19 +-
 12 files changed, 3570 insertions(+), 161 deletions(-)
 create mode 100644 doc/cha-gtls-app.texi
 create mode 100644 lib/pakchois/errors.c
 create mode 100644 lib/pakchois/pakchois.c
 create mode 100644 lib/pakchois/pakchois.h
 create mode 100644 lib/pakchois/pakchois11.h

diff --git a/doc/Makefile.am b/doc/Makefile.am
index b474ab8..9d4c547 100644
--- a/doc/Makefile.am
+++ b/doc/Makefile.am
@@ -30,7 +30,11 @@ SUBDIRS += reference
 endif
 
 info_TEXINFOS = gnutls.texi
-gnutls_TEXINFOS = gnutls.texi fdl-1.3.texi lgpl-2.1.texi gpl-3.0.texi
+gnutls_TEXINFOS = gnutls.texi fdl-1.3.texi lgpl-2.1.texi gpl-3.0.texi \
+       cha-auth.texi cha-bib.texi cha-cert-auth.texi cha-ciphersuites.texi \
+       cha-copying.texi cha-functions.texi cha-gtls-app.texi \
+       cha-internals.texi cha-intro-tls.texi cha-library.texi \
+       cha-preface.texi cha-programs.texi cha-tls-app.texi
 
 # Examples.
 gnutls_TEXINFOS += examples/ex-client1.c examples/ex-client2.c         \
diff --git a/doc/TODO b/doc/TODO
index d561d57..7d7360d 100644
--- a/doc/TODO
+++ b/doc/TODO
@@ -5,7 +5,6 @@ in order to avoid having people working on the same thing.
 Current list:
 + Support PKCS#8 AES and DES-MD5 (tests/enc3pkcs8.pem) encrypted keys.
 * Implement Datagram-TLS (DTLS).
-* Correct TLS 1.2 support.
 * Cleanup pkix.asn and remove unused (by the certificate api) structures.
   That way memory used will be reduced.
 * Improve or rewrite libtasn1 to make it easier to maintain.
@@ -24,8 +23,6 @@ Current list:
 - Clean up name space of helper functions in library (memmem,
    firstElement, bit_mask, ...) for platforms that libtool's
    -export-symbols-regex doesn't work.
-- Allow sending V2 Hello messages. It seems that some (old) broken 
-  implementations require that.
 - Add Kerberos ciphersuites
 - Certificate chain validation improvements:
   - Implement "correct" DN comparison (instead of memcmp).
@@ -40,7 +37,6 @@ Current list:
   - Check path length constraints.
   - Check keyCertSign key usages.
   - Reject extensions in v1 certificates.
-- Support for cryptodev (and thus hardware accelerators)
 - Exhaustive test suite, using NIST's PKI Test vectors,
   see http://csrc.nist.gov/pki/testing/x509paths_old.html
   and http://csrc.nist.gov/pki/testing/x509paths.html
diff --git a/doc/cha-cert-auth.texi b/doc/cha-cert-auth.texi
index 7b76857..9843a2c 100644
--- a/doc/cha-cert-auth.texi
+++ b/doc/cha-cert-auth.texi
@@ -6,8 +6,9 @@
 @menu
 * The X.509 trust model::
 * The OpenPGP trust model::
-* Digital signatures::
 * PKCS #11 tokens::
+* Abstract data types::
+* Digital signatures::
 @end menu
 
 @node The X.509 trust model
@@ -317,123 +318,6 @@ MD5.  These algorithms have been broken and should not be 
trusted.
 
 @end table
 
address@hidden Digital signatures
address@hidden Digital Signatures
address@hidden Digital signatures
-
-In this section we will provide some information about digital
-signatures, how they work, and give the rationale for disabling some
-of the algorithms used.
-
-Digital signatures work by using somebody's secret key to sign some
-arbitrary data.  Then anybody else could use the public key of that
-person to verify the signature.  Since the data may be arbitrary it is
-not suitable input to a cryptographic digital signature algorithm. For
-this reason and also for performance cryptographic hash algorithms are
-used to preprocess the input to the signature algorithm. This works as
-long as it is difficult enough to generate two different messages with
-the same hash algorithm output. In that case the same signature could
-be used as a proof for both messages. Nobody wants to sign an innocent
-message of donating 1 @euro{} to Greenpeace and find out that he
-donated 1.000.000 @euro{} to Bad Inc.
-
-For a hash algorithm to be called cryptographic the following three
-requirements must hold:
-
address@hidden
address@hidden Preimage resistance.
-That means the algorithm must be one way and given the output of the
-hash function @math{H(x)}, it is impossible to calculate @math{x}.
-
address@hidden 2nd preimage resistance.
-That means that given a pair @math{x,y} with @math{y=H(x)} it is
-impossible to calculate an @math{x'} such that @math{y=H(x')}.
-
address@hidden Collision resistance.
-That means that it is impossible to calculate random @math{x} and
address@hidden'} such @math{H(x')=H(x)}.
address@hidden enumerate
-
-The last two requirements in the list are the most important in
-digital signatures. These protect against somebody who would like to
-generate two messages with the same hash output. When an algorithm is
-considered broken usually it means that the Collision resistance of
-the algorithm is less than brute force. Using the birthday paradox the
-brute force attack takes
address@hidden
address@hidden(\rm{hash\ size}) / 2}}
address@hidden iftex
address@hidden
address@hidden((hash size) / 2)}}
address@hidden ifnottex
-operations. Today colliding certificates using the MD5 hash algorithm
-have been generated as shown in @xcite{WEGER}.
-
-There has been cryptographic results for the SHA-1 hash algorithms as
-well, although they are not yet critical.  Before 2004, MD5 had a
-presumed collision strength of @math{2^{64}}, but it has been showed
-to have a collision strength well under @math{2^{50}}.  As of November
-2005, it is believed that SHA-1's collision strength is around
address@hidden  We consider this sufficiently hard so that we still
-support SHA-1.  We anticipate that SHA-256/386/512 will be used in
-publicly-distributed certificates in the future.  When @math{2^{63}}
-can be considered too weak compared to the computer power available
-sometime in the future, SHA-1 will be disabled as well.  The collision
-attacks on SHA-1 may also get better, given the new interest in tools
-for creating them.
-
address@hidden Trading Security for Interoperability
-
-If you connect to a server and use GnuTLS' functions to verify the
-certificate chain, and get a @ref{GNUTLS_CERT_INSECURE_ALGORITHM}
-validation error (@pxref{Verifying X.509 certificate paths}), it means
-that somewhere in the certificate chain there is a certificate signed
-using @code{RSA-MD2} or @code{RSA-MD5}.  These two digital signature
-algorithms are considered broken, so GnuTLS fail when attempting to
-verify the certificate.  In some situations, it may be useful to be
-able to verify the certificate chain anyway, assuming an attacker did
-not utilize the fact that these signatures algorithms are broken.
-This section will give help on how to achieve that.
-
-First, it is important to know that you do not have to enable any of
-the flags discussed here to be able to use trusted root CA
-certificates signed using @code{RSA-MD2} or @code{RSA-MD5}.  The only
-attack today is that it is possible to generate certificates with
-colliding signatures (collision resistance); you cannot generate a
-certificate that has the same signature as an already existing
-signature (2nd preimage resistance).
-
-If you are using @ref{gnutls_certificate_verify_peers2} to verify the
-certificate chain, you can call
address@hidden with the
address@hidden or
address@hidden flag, as in:
-
address@hidden
-  gnutls_certificate_set_verify_flags (x509cred,
-                                       GNUTLS_VERIFY_ALLOW_SIGN_RSA_MD5);
address@hidden example
-
-This will tell the verifier algorithm to enable @code{RSA-MD5} when
-verifying the certificates.
-
-If you are using @ref{gnutls_x509_crt_verify} or
address@hidden, you can pass the
address@hidden parameter directly in the
address@hidden parameter.
-
-If you are using these flags, it may also be a good idea to warn the
-user when verification failure occur for this reason.  The simplest is
-to not use the flags by default, and only fall back to using them
-after warning the user.  If you wish to inspect the certificate chain
-yourself, you can use @ref{gnutls_certificate_get_peers} to extract
-the raw server's certificate chain, then use
address@hidden to parse each of the certificates, and
-then use @ref{gnutls_x509_crt_get_signature_algorithm} to find out the
-signing algorithm used for each certificate.  If any of the
-intermediary certificates are using @code{GNUTLS_SIGN_RSA_MD2} or
address@hidden, you could present a warning.
-
 
 @node PKCS #11 tokens
 @section @acronym{PKCS #11} tokens
@@ -563,29 +447,29 @@ unsigned int obj_list_size = 0;
 gnutls_datum_t cinfo;
 int i;
 
-       crt_list_size = 0;
-       ret = gnutls_pkcs11_obj_list_import_url( crt_list, NULL, url, \
+       obj_list_size = 0;
+       ret = gnutls_pkcs11_obj_list_import_url( obj_list, NULL, url, \
                                GNUTLS_PKCS11_OBJ_ATTR_CRT_WITH_PRIVKEY);
        if (ret < 0 && ret != GNUTLS_E_SHORT_MEMORY_BUFFER)
                exit(1);
 
-       crt_list = malloc(sizeof(*crt_list)*crt_list_size);
-       if (crt_list == NULL)
+       obj_list = malloc(sizeof(*obj_list)*obj_list_size);
+       if (obj_list == NULL)
                exit(1);
 
-       ret = gnutls_pkcs11_obj_list_import_url( crt_list, &crt_list_size, url, 
flags);
+       ret = gnutls_pkcs11_obj_list_import_url( obj_list, &obj_list_size, url, 
flags);
        if (ret < 0)
                exit(1);
 
-       /* now all certificates are in crt_list */
+       /* now all certificates are in obj_list */
 
-       for (i=0;i<crt_list_size;i++) {
+       for (i=0;i<obj_list_size;i++) {
 
                ret = gnutls_x509_crt_init(&xcrt);
                if (ret < 0)
                        exit(1);
                
-               ret = gnutls_x509_crt_import_pkcs11(xcrt, crt_list[i]);
+               ret = gnutls_x509_crt_import_pkcs11(xcrt, obj_list[i]);
                if (ret < 0)
                        exit(1);
                
@@ -619,8 +503,173 @@ to a token. This can be achieved with the following 
functions
 
 @subsection Using a @acronym{PKCS #11} token with TLS
 
-This example will demonstrate how to load keys and certificates
-from a @acronym{PKCS} #11 token, and use it with a TLS connection.
+It is possible to use a @acronym{PKCS #11} token to a TLS
+session, as shown in @ref{ex:pkcs11-client}. In addition
+the following functions can be used to load PKCS #11 key and
+certificates.
+
address@hidden
+
address@hidden @ref{gnutls_certificate_set_x509_trust_file}: If given a PKCS 
#11 URL will load the trusted certificates from it.
+
address@hidden @ref{gnutls_certificate_set_x509_key_file}: Will also load PKCS 
#11 URLs for keys and certificates.
+
address@hidden itemize
+
+
address@hidden Abstract data types
address@hidden Abstract data types
address@hidden:abstract}
address@hidden Abstract types
 
address@hidden examples/ex-cert-select-pkcs11.c
+Since there are many forms of a public or private keys supported by 
@acronym{GnuTLS} such as
address@hidden, @acronym{OpenPGP}, or @acronym{PKCS #11} it is desirable to 
allow common operations
+on them. For these reasons the abstract @code{gnutls_privkey_t} and 
@code{gnutls_pubkey_t} were
+introduced in @code{gnutls/abstract.h} header. Those types are initialized 
using a specific type of key and then can be used to
+perform operations in an abstract way. For example in order for someone to 
sign an X.509 certificate
+with a key that resides in a smart he has to follow the steps below:
+
address@hidden
+#inlude <gnutls/abstract.h>
+#inlude <gnutls/pkcs11.h>
+
+void sign_cert( gnutls_x509_crt_t to_be_signed)
+{
+gnutls_pkcs11_privkey_t ca_key;
+gnutls_x509_crt_t ca_cert;
+gnutls_privkey_t abs_key;
+
+       /* load the PKCS 11 key and certificates */
+       gnutls_pkcs11_privkey_init(&ca_key);
+       gnutls_pkcs11_privkey_import_url(ca_key, key_url);
+
+       gnutls_x509_crt_init(&ca_cert);
+       gnutls_x509_crt_import_pkcs11_url(&ca_cert, cert_url);
+
+       /* initialize the abstract key */
+       gnutls_privkey_init(&abs_key);
+       gnutls_privkey_import_pkcs11(abs_key, ca_key);
+
+       /* sign the certificate to be signed */
+       gnutls_x509_crt_privkey_sign(to_be_signed, ca_cert, ca_key, 
GNUTLS_DIG_SHA1, 0);
+}
address@hidden verbatim
+
+
address@hidden Digital signatures
address@hidden Digital Signatures
address@hidden Digital signatures
+
+In this section we will provide some information about digital
+signatures, how they work, and give the rationale for disabling some
+of the algorithms used.
+
+Digital signatures work by using somebody's secret key to sign some
+arbitrary data.  Then anybody else could use the public key of that
+person to verify the signature.  Since the data may be arbitrary it is
+not suitable input to a cryptographic digital signature algorithm. For
+this reason and also for performance cryptographic hash algorithms are
+used to preprocess the input to the signature algorithm. This works as
+long as it is difficult enough to generate two different messages with
+the same hash algorithm output. In that case the same signature could
+be used as a proof for both messages. Nobody wants to sign an innocent
+message of donating 1 @euro{} to Greenpeace and find out that he
+donated 1.000.000 @euro{} to Bad Inc.
+
+For a hash algorithm to be called cryptographic the following three
+requirements must hold:
+
address@hidden
address@hidden Preimage resistance.
+That means the algorithm must be one way and given the output of the
+hash function @math{H(x)}, it is impossible to calculate @math{x}.
+
address@hidden 2nd preimage resistance.
+That means that given a pair @math{x,y} with @math{y=H(x)} it is
+impossible to calculate an @math{x'} such that @math{y=H(x')}.
+
address@hidden Collision resistance.
+That means that it is impossible to calculate random @math{x} and
address@hidden'} such @math{H(x')=H(x)}.
address@hidden enumerate
+
+The last two requirements in the list are the most important in
+digital signatures. These protect against somebody who would like to
+generate two messages with the same hash output. When an algorithm is
+considered broken usually it means that the Collision resistance of
+the algorithm is less than brute force. Using the birthday paradox the
+brute force attack takes
address@hidden
address@hidden(\rm{hash\ size}) / 2}}
address@hidden iftex
address@hidden
address@hidden((hash size) / 2)}}
address@hidden ifnottex
+operations. Today colliding certificates using the MD5 hash algorithm
+have been generated as shown in @xcite{WEGER}.
+
+There has been cryptographic results for the SHA-1 hash algorithms as
+well, although they are not yet critical.  Before 2004, MD5 had a
+presumed collision strength of @math{2^{64}}, but it has been showed
+to have a collision strength well under @math{2^{50}}.  As of November
+2005, it is believed that SHA-1's collision strength is around
address@hidden  We consider this sufficiently hard so that we still
+support SHA-1.  We anticipate that SHA-256/386/512 will be used in
+publicly-distributed certificates in the future.  When @math{2^{63}}
+can be considered too weak compared to the computer power available
+sometime in the future, SHA-1 will be disabled as well.  The collision
+attacks on SHA-1 may also get better, given the new interest in tools
+for creating them.
+
address@hidden Trading Security for Interoperability
+
+If you connect to a server and use GnuTLS' functions to verify the
+certificate chain, and get a @ref{GNUTLS_CERT_INSECURE_ALGORITHM}
+validation error (@pxref{Verifying X.509 certificate paths}), it means
+that somewhere in the certificate chain there is a certificate signed
+using @code{RSA-MD2} or @code{RSA-MD5}.  These two digital signature
+algorithms are considered broken, so GnuTLS fail when attempting to
+verify the certificate.  In some situations, it may be useful to be
+able to verify the certificate chain anyway, assuming an attacker did
+not utilize the fact that these signatures algorithms are broken.
+This section will give help on how to achieve that.
+
+First, it is important to know that you do not have to enable any of
+the flags discussed here to be able to use trusted root CA
+certificates signed using @code{RSA-MD2} or @code{RSA-MD5}.  The only
+attack today is that it is possible to generate certificates with
+colliding signatures (collision resistance); you cannot generate a
+certificate that has the same signature as an already existing
+signature (2nd preimage resistance).
+
+If you are using @ref{gnutls_certificate_verify_peers2} to verify the
+certificate chain, you can call
address@hidden with the
address@hidden or
address@hidden flag, as in:
+
address@hidden
+  gnutls_certificate_set_verify_flags (x509cred,
+                                       GNUTLS_VERIFY_ALLOW_SIGN_RSA_MD5);
address@hidden example
+
+This will tell the verifier algorithm to enable @code{RSA-MD5} when
+verifying the certificates.
+
+If you are using @ref{gnutls_x509_crt_verify} or
address@hidden, you can pass the
address@hidden parameter directly in the
address@hidden parameter.
+
+If you are using these flags, it may also be a good idea to warn the
+user when verification failure occur for this reason.  The simplest is
+to not use the flags by default, and only fall back to using them
+after warning the user.  If you wish to inspect the certificate chain
+yourself, you can use @ref{gnutls_certificate_get_peers} to extract
+the raw server's certificate chain, then use
address@hidden to parse each of the certificates, and
+then use @ref{gnutls_x509_crt_get_signature_algorithm} to find out the
+signing algorithm used for each certificate.  If any of the
+intermediary certificates are using @code{GNUTLS_SIGN_RSA_MD2} or
address@hidden, you could present a warning.
 
diff --git a/doc/cha-gtls-app.texi b/doc/cha-gtls-app.texi
new file mode 100644
index 0000000..4676802
--- /dev/null
+++ b/doc/cha-gtls-app.texi
@@ -0,0 +1,495 @@
address@hidden How to use GnuTLS in applications
address@hidden How To Use @acronym{GnuTLS} in Applications
address@hidden
address@hidden Example programs
+
address@hidden
+* Preparation::
+* Multi-threaded applications::
+* Client examples::
+* Server examples::
+* Miscellaneous examples::
+* Compatibility with the OpenSSL library::
+* Opaque PRF Input TLS Extension::
+* Keying Material Exporters::
address@hidden menu
+
address@hidden Preparation
address@hidden Preparation
+
+To use @acronym{GnuTLS}, you have to perform some changes to your
+sources and your build system. The necessary changes are explained in
+the following subsections.
+
address@hidden
+* Headers::
+* Initialization::
+* Version check::
+* Debugging::
+* Building the source::
address@hidden menu
+
address@hidden Headers
address@hidden Headers
+
+All the data types and functions of the @acronym{GnuTLS} library are
+defined in the header file @file{gnutls/gnutls.h}.  This must be
+included in all programs that make use of the @acronym{GnuTLS}
+library.
+
+The extra functionality of the @acronym{GnuTLS-extra} library is
+available by including the header file @file{gnutls/extra.h} in your
+programs.
+
address@hidden Initialization
address@hidden Initialization
+
+GnuTLS must be initialized before it can be used.  The library is
+initialized by calling @ref{gnutls_global_init}.  The resources
+allocated by the initialization process can be released if the
+application no longer has a need to call GnuTLS functions, this is
+done by calling @ref{gnutls_global_deinit}.
+
+The extra functionality of the @acronym{GnuTLS-extra} library is
+available after calling @ref{gnutls_global_init_extra}.
+
+In order to take advantage of the internationalisation features in
+GnuTLS, such as translated error messages, the application must set
+the current locale using @code{setlocale} before initializing GnuTLS.
+
address@hidden Version check
address@hidden Version Check
+
+It is often desirable to check that the version of `gnutls' used is
+indeed one which fits all requirements.  Even with binary
+compatibility new features may have been introduced but due to problem
+with the dynamic linker an old version is actually used.  So you may
+want to check that the version is okay right after program startup.
+See the function @ref{gnutls_check_version}.
+
address@hidden Debugging
address@hidden Debugging
+
+In many cases things may not go as expected and further information,
+to assist debugging, from @acronym{GnuTLS} is desired. Those are the
+case where the @ref{gnutls_global_set_log_level} and
address@hidden are to be used. Those will print
+verbose information on the @acronym{GnuTLS} functions internal flow.
+
address@hidden Building the source
address@hidden Building the Source
+
+If you want to compile a source file including the
address@hidden/gnutls.h} header file, you must make sure that the
+compiler can find it in the directory hierarchy.  This is accomplished
+by adding the path to the directory in which the header file is
+located to the compilers include file search path (via the @option{-I}
+option).
+
+However, the path to the include file is determined at the time the
+source is configured.  To solve this problem, the library uses the
+external package @command{pkg-config} that knows the path to the
+include file and other configuration options.  The options that need
+to be added to the compiler invocation at compile time are output by
+the @option{--cflags} option to @command{pkg-config gnutls}.  The
+following example shows how it can be used at the command line:
+
address@hidden
+gcc -c foo.c `pkg-config gnutls --cflags`
address@hidden example
+
+Adding the output of @samp{pkg-config gnutls --cflags} to the
+compilers command line will ensure that the compiler can find the
address@hidden/gnutls.h} header file.
+
+A similar problem occurs when linking the program with the library.
+Again, the compiler has to find the library files.  For this to work,
+the path to the library files has to be added to the library search
+path (via the @option{-L} option).  For this, the option
address@hidden to @command{pkg-config gnutls} can be used.  For
+convenience, this option also outputs all other options that are
+required to link the program with the libarary (for instance, the
address@hidden option).  The example shows how to link @file{foo.o}
+with the library to a program @command{foo}.
+
address@hidden
+gcc -o foo foo.o `pkg-config gnutls --libs`
address@hidden example
+
+Of course you can also combine both examples to a single command by
+specifying both options to @command{pkg-config}:
+
address@hidden
+gcc -o foo foo.c `pkg-config gnutls --cflags --libs`
address@hidden example
+
address@hidden Multi-threaded applications
address@hidden Multi-Threaded Applications
+
+Although the @acronym{GnuTLS} library is thread safe by design, some
+parts of Libgcrypt, such as the random generator, are not.
+Applications have to register callback functions to ensure proper
+locking in the sensitive parts of @emph{libgcrypt}.
+
+There are helper macros to help you properly initialize the libraries.
+Examples are shown below.
+
address@hidden
+
address@hidden POSIX threads
address@hidden
+#include <gnutls.h>
+#include <gcrypt.h>
+#include <errno.h>
+#include <pthread.h>
+GCRY_THREAD_OPTION_PTHREAD_IMPL;
+
+int main() 
address@hidden
+   /* The order matters.
+    */
+   gcry_control (GCRYCTL_SET_THREAD_CBS, &gcry_threads_pthread);
+   gnutls_global_init();
address@hidden
address@hidden example
+
address@hidden GNU PTH threads
address@hidden
+#include <gnutls.h>
+#include <gcrypt.h>
+#include <errno.h>
+#include <pth.h>
+GCRY_THREAD_OPTION_PTH_IMPL;
+
+int main() 
address@hidden
+   gcry_control (GCRYCTL_SET_THREAD_CBS, &gcry_threads_pth);
+   gnutls_global_init();
address@hidden
address@hidden example
+
address@hidden Other thread packages
address@hidden
+/* The gcry_thread_cbs structure must have been
+ * initialized.
+ */
+static struct gcry_thread_cbs gcry_threads_other = @{ ... @};
+
+int main()
address@hidden
+   gcry_control (GCRYCTL_SET_THREAD_CBS, &gcry_threads_other);
address@hidden
address@hidden example
address@hidden itemize
+
address@hidden Client examples
address@hidden Client Examples
+
+This section contains examples of @acronym{TLS} and @acronym{SSL}
+clients, using @acronym{GnuTLS}.  Note that these examples contain
+little or no error checking.  Some of the examples require functions
+implemented by another example.
+
address@hidden
+* Simple client example with anonymous authentication::
+* Simple client example with X.509 certificate support::
+* Obtaining session information::
+* Verifying peer's certificate::
+* Using a callback to select the certificate to use::
+* Client using a PKCS #11 token with TLS::
+* Client with Resume capability example::
+* Simple client example with SRP authentication::
+* Simple client example with TLS/IA support::
+* Simple client example in C++::
+* Helper function for TCP connections::
address@hidden menu
+
address@hidden Simple client example with anonymous authentication
address@hidden Simple Client Example with Anonymous Authentication
+
+The simplest client using TLS is the one that doesn't do any
+authentication.  This means no external certificates or passwords are
+needed to set up the connection.  As could be expected, the connection
+is vulnerable to man-in-the-middle (active or redirection) attacks.
+However, the data is integrity and privacy protected.
+
address@hidden examples/ex-client1.c
+
address@hidden Simple client example with X.509 certificate support
address@hidden Simple Client Example with @acronym{X.509} Certificate Support
+
+Let's assume now that we want to create a TCP client which
+communicates with servers that use @acronym{X.509} or
address@hidden certificate authentication. The following client is
+a very simple @acronym{TLS} client, it does not support session
+resuming, not even certificate verification. The TCP functions defined
+in this example are used in most of the other examples below, without
+redefining them.
+
address@hidden examples/ex-client2.c
+
address@hidden Obtaining session information
address@hidden Obtaining Session Information
+
+Most of the times it is desirable to know the security properties of
+the current established session.  This includes the underlying ciphers
+and the protocols involved.  That is the purpose of the following
+function.  Note that this function will print meaningful values only
+if called after a successful @ref{gnutls_handshake}.
+
address@hidden examples/ex-session-info.c
+
address@hidden Verifying peer's certificate
address@hidden Verifying Peer's Certificate
address@hidden:verify}
+
+A @acronym{TLS} session is not secure just after the handshake
+procedure has finished.  It must be considered secure, only after the
+peer's certificate and identity have been verified. That is, you have
+to verify the signature in peer's certificate, the hostname in the
+certificate, and expiration dates.  Just after this step you should
+treat the connection as being a secure one.
+
address@hidden examples/ex-rfc2818.c
+
+An other example is listed below which provides a more detailed
+verification output.
+
address@hidden examples/ex-verify.c
+
address@hidden Using a callback to select the certificate to use
address@hidden Using a Callback to Select the Certificate to Use
+
+There are cases where a client holds several certificate and key
+pairs, and may not want to load all of them in the credentials
+structure.  The following example demonstrates the use of the
+certificate selection callback.
+
address@hidden examples/ex-cert-select.c
+
+
address@hidden Client using a PKCS #11 token with TLS
address@hidden Using a @acronym{PKCS #11} token with TLS
address@hidden:pkcs11-client}
+
+This example will demonstrate how to load keys and certificates
+from a @acronym{PKCS} #11 token, and use it with a TLS connection.
+
address@hidden examples/ex-cert-select-pkcs11.c
+
+
address@hidden Client with Resume capability example
address@hidden Client with Resume Capability Example
address@hidden:resume-client}
+
+This is a modification of the simple client example. Here we
+demonstrate the use of session resumption. The client tries to connect
+once using @acronym{TLS}, close the connection and then try to
+establish a new connection using the previously negotiated data.
+
address@hidden examples/ex-client-resume.c
+
+
address@hidden Simple client example with SRP authentication
address@hidden Simple Client Example with @acronym{SRP} Authentication
+
+The following client is a very simple @acronym{SRP} @acronym{TLS}
+client which connects to a server and authenticates using a
address@hidden and a @emph{password}. The server may authenticate
+itself using a certificate, and in that case it has to be verified.
+
address@hidden examples/ex-client-srp.c
+
address@hidden Simple client example with TLS/IA support
address@hidden Simple Client Example with @acronym{TLS/IA} Support
+
+The following client is a simple client which uses the
address@hidden/IA} extension to authenticate with the server.
+
address@hidden examples/ex-client-tlsia.c
+
address@hidden Simple client example in C++
address@hidden Simple Client Example using the C++ API
+
+The following client is a simple example of a client client utilizing
+the GnuTLS C++ API.
+
address@hidden examples/ex-cxx.cpp
+
address@hidden Helper function for TCP connections
address@hidden Helper Function for TCP Connections
+
+This helper function abstracts away TCP connection handling from the
+other examples.  It is required to build some examples.
+
address@hidden examples/tcp.c
+
address@hidden Server examples
address@hidden Server Examples
+
+This section contains examples of @acronym{TLS} and @acronym{SSL}
+servers, using @acronym{GnuTLS}.
+
address@hidden
+* Echo Server with X.509 authentication::
+* Echo Server with X.509 authentication II::
+* Echo Server with OpenPGP authentication::
+* Echo Server with SRP authentication::
+* Echo Server with anonymous authentication::
address@hidden menu
+
address@hidden Echo Server with X.509 authentication
address@hidden Echo Server with @acronym{X.509} Authentication
+
+This example is a very simple echo server which supports
address@hidden authentication, using the RSA ciphersuites.
+
address@hidden examples/ex-serv1.c
+
address@hidden Echo Server with X.509 authentication II
address@hidden Echo Server with @acronym{X.509} Authentication II
+
+The following example is a server which supports @acronym{X.509}
+authentication.  This server supports the export-grade cipher suites,
+the DHE ciphersuites and session resuming.
+
address@hidden examples/ex-serv-export.c
+
address@hidden Echo Server with OpenPGP authentication
address@hidden Echo Server with @acronym{OpenPGP} Authentication
address@hidden @acronym{OpenPGP} Server
+
+The following example is an echo server which supports
address@hidden@acronym{OpenPGP}} key authentication. You can easily combine
+this functionality ---that is have a server that supports both
address@hidden and @acronym{OpenPGP} certificates--- but we separated
+them to keep these examples as simple as possible.
+
address@hidden examples/ex-serv-pgp.c
+
address@hidden Echo Server with SRP authentication
address@hidden Echo Server with @acronym{SRP} Authentication
+
+This is a server which supports @acronym{SRP} authentication. It is
+also possible to combine this functionality with a certificate
+server. Here it is separate for simplicity.
+
address@hidden examples/ex-serv-srp.c
+
address@hidden Echo Server with anonymous authentication
address@hidden Echo Server with Anonymous Authentication
+
+This example server support anonymous authentication, and could be
+used to serve the example client for anonymous authentication.
+
address@hidden examples/ex-serv-anon.c
+
address@hidden Miscellaneous examples
address@hidden Miscellaneous Examples
+
address@hidden
+* Checking for an alert::
+* X.509 certificate parsing example::
+* Certificate request generation::
+* PKCS #12 structure generation::
address@hidden menu
+
address@hidden Checking for an alert
address@hidden Checking for an Alert
+
+This is a function that checks if an alert has been received in the
+current session.
+
address@hidden examples/ex-alert.c
+
address@hidden X.509 certificate parsing example
address@hidden @acronym{X.509} Certificate Parsing Example
address@hidden:x509-info}
+
+To demonstrate the @acronym{X.509} parsing capabilities an example program is
+listed below.  That program reads the peer's certificate, and prints
+information about it.
+
address@hidden examples/ex-x509-info.c
+
address@hidden Certificate request generation
address@hidden Certificate Request Generation
address@hidden:crq}
+
+The following example is about generating a certificate request, and a
+private key. A certificate request can be later be processed by a CA,
+which should return a signed certificate.
+
address@hidden examples/ex-crq.c
+
address@hidden PKCS #12 structure generation
address@hidden @acronym{PKCS} #12 Structure Generation
address@hidden:pkcs12}
+
+The following example is about generating a @acronym{PKCS} #12
+structure.
+
address@hidden examples/ex-pkcs12.c
+
address@hidden Compatibility with the OpenSSL library
address@hidden Compatibility with the OpenSSL Library
address@hidden OpenSSL
+
+To ease @acronym{GnuTLS}' integration with existing applications, a
+compatibility layer with the widely used OpenSSL library is included
+in the @code{gnutls-openssl} library. This compatibility layer is not
+complete and it is not intended to completely reimplement the OpenSSL
+API with @acronym{GnuTLS}.  It only provides source-level
+compatibility. There is currently no attempt to make it
+binary-compatible with OpenSSL.
+
+The prototypes for the compatibility functions are in the
address@hidden/openssl.h} header file.
+
+Current limitations imposed by the compatibility layer include:
+
address@hidden
+
address@hidden Error handling is not thread safe.
+
address@hidden itemize
+
address@hidden Opaque PRF Input TLS Extension
address@hidden Opaque PRF Input TLS Extension
address@hidden Opaque PRF Input
+
+GnuTLS supports the Opaque PRF Input TLS extension
+(@code{draft-rescorla-tls-opaque-prf-input-00.txt}).  The API consists
+of one API for use in the client, @ref{gnutls_oprfi_enable_client},
+and one API for use in the server, @ref{gnutls_oprfi_enable_server}.
+You must invoke both functions before calling @ref{gnutls_handshake}.
+The server utilizes a callback function into the application.  The
+callback can look at the random string provided by the client, and
+also set the server string.  The string lengths must be equal
+according to the protocol.
+
address@hidden Keying Material Exporters
address@hidden Keying Material Exporters
address@hidden Keying Material Exporters
address@hidden Exporting Keying Material
+
+The TLS PRF can be used by other protocols to derive data.  The API to
+use is @ref{gnutls_prf}.  The function needs to be provided with the
+label in the parameter @code{label}, and the extra data to mix in the
address@hidden parameter.  Depending on whether you want to mix in the
+client or server random data first, you can set the
address@hidden parameter.
+
+For example, after establishing a TLS session using
address@hidden, you can invoke the TLS PRF with this call:
+
address@hidden
+#define MYLABEL "EXPORTER-FOO"
+#define MYCONTEXT "some context data"
+char out[32];
+rc = gnutls_prf (session, strlen (MYLABEL), MYLABEL, 0,
+                 strlen (MYCONTEXT), MYCONTEXT, 32, out);
address@hidden smallexample
+
+If you don't want to mix in the client/server random, there is a more
+low-level TLS PRF interface called @ref{gnutls_prf_raw}.
diff --git a/lib/Makefile.am b/lib/Makefile.am
index 0ccb5e0..fc1ef17 100644
--- a/lib/Makefile.am
+++ b/lib/Makefile.am
@@ -84,6 +84,7 @@ COBJECTS = gnutls_record.c gnutls_compress.c debug.c 
gnutls_cipher.c  \
        crypto-api.c ext_safe_renegotiation.c gnutls_privkey.c \
        pkcs11.c pkcs11_privkey.c gnutls_pubkey.c pkcs11_write.c
 
+
 if ENABLE_NETTLE
 SUBDIRS += nettle
 else
@@ -111,6 +112,11 @@ HFILES = debug.h gnutls_compress.h gnutls_cipher.h 
gnutls_buffers.h        \
        ext_session_ticket.h ext_signature.h gnutls_cryptodev.h         \
        ext_safe_renegotiation.h
 
+if ENABLE_LOCAL_PAKCHOIS
+COBJECTS+=pakchois/pakchois.c pakchois/errors.c
+HFILES+=pakchois/pakchois.h pakchois/pakchois11.h
+endif
+
 # Separate so we can create the documentation
 
 libgnutls_la_SOURCES = $(HFILES) $(COBJECTS) $(SRP_COBJECTS)   \
@@ -140,9 +146,7 @@ else
 libgnutls_la_LDFLAGS += $(LTLIBTASN1)
 endif
 
-if ENABLE_PAKCHOIS
 libgnutls_la_LDFLAGS += $(LTLIBPAKCHOIS)
-endif
 
 if ENABLE_NETTLE
 libgnutls_la_LDFLAGS += $(LTLIBNETTLE) -lgmp -lpthread -lhogweed
diff --git a/lib/configure.ac b/lib/configure.ac
index a372b89..35fa0d4 100644
--- a/lib/configure.ac
+++ b/lib/configure.ac
@@ -79,23 +79,6 @@ else
  AC_MSG_RESULT(no)
 fi
 
-AC_ARG_WITH(pakchois, AS_HELP_STRING([--without-pakchois],
-                                 [disable pakchois PKCS11 support]),
-            ac_pakchois=$withval, ac_pakchois=yes)
-AC_MSG_CHECKING([whether to include pakchois PKCS11 support])
-if test x$ac_pakchois != xno; then
- AC_MSG_RESULT(yes)
- AC_LIB_HAVE_LINKFLAGS(pakchois,, [#include <pakchois/pakchois.h>], 
[pakchois_module_load(0,0);])
- if test "$ac_cv_libpakchois" != yes; then
-   AC_MSG_ERROR(
-*** 
-*** Pakchois was not found. This is required for PKCS11 support.)
- fi
-else
- AC_MSG_RESULT(no)
-fi
-AM_CONDITIONAL(ENABLE_PAKCHOIS, test "$ac_cv_libpakchois" = "yes")
-
 lgl_INIT
 
 LIBGNUTLS_LIBS="-L${libdir} -lgnutls $LIBS"
diff --git a/lib/m4/hooks.m4 b/lib/m4/hooks.m4
index 316bf82..aaf95c6 100644
--- a/lib/m4/hooks.m4
+++ b/lib/m4/hooks.m4
@@ -92,6 +92,35 @@ AC_DEFUN([LIBGNUTLS_HOOKS],
   AC_MSG_RESULT($included_libtasn1)
   AM_CONDITIONAL(ENABLE_MINITASN1, test "$included_libtasn1" = "yes")
 
+  AC_ARG_WITH(included-pakchois,
+    AS_HELP_STRING([--with-included-pakchois], [use the included pakchois]),
+      included_pakchois=$withval,
+      included_pakchois=no)
+  if test "$included_pakchois" = "no"; then
+    AC_LIB_HAVE_LINKFLAGS(pakchois,, [#include <pakchois/pakchois.h>],
+                          [pakchois_module_load(0,0);])
+    if test "$ac_cv_pakchois" != yes; then
+      included_pakchois=yes
+      AC_MSG_WARN([[
+  *** 
+  *** Pakchois was not found. Will use the included one.
+  ]])
+    fi
+  fi
+  AC_MSG_CHECKING([whether to use the included pakchois])
+  AC_MSG_RESULT($included_pakchois)
+  AM_CONDITIONAL(ENABLE_LOCAL_PAKCHOIS, test "$included_pakchois" = "yes")
+  if test "$included_pakchois" = "yes";then
+       AC_CHECK_LIB(pthread, pthread_mutex_lock,,
+          [AC_MSG_ERROR([could not find pthread_mutex_lock])])
+       AC_CHECK_LIB(dl, dlopen,,
+          [AC_MSG_ERROR([could not find dlopen])])
+
+       module_path="${libdir}:${libdir}/pkcs11"
+
+       CPPFLAGS="$CPPFLAGS -DPAKCHOIS_MODPATH=\\\"${module_path}\\\""
+  fi
+
   AC_ARG_WITH(lzo,
     AS_HELP_STRING([--with-lzo], [use experimental LZO compression]),
                    use_lzo=$withval, use_lzo=no)
diff --git a/lib/pakchois/errors.c b/lib/pakchois/errors.c
new file mode 100644
index 0000000..de09b92
--- /dev/null
+++ b/lib/pakchois/errors.c
@@ -0,0 +1,146 @@
+/* 
+   pakchois PKCS#11 interface -- error mapping
+   Copyright (C) 2008, Joe Orton <address@hidden>
+
+   This library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public
+   License as published by the Free Software Foundation; either
+   version 2 of the License, or (at your option) any later version.
+   
+   This library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with this library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+   MA 02111-1307, USA
+*/
+
+/*
+  This code is directly derived from the scute.org PKCS#11 cryptoki
+  interface, which is:
+
+   Copyright 2006, 2007 g10 Code GmbH
+   Copyright 2006 Andreas Jellinghaus
+
+   This file is free software; as a special exception the author gives
+   unlimited permission to copy and/or distribute it, with or without
+   modifications, as long as this notice is preserved.
+
+   This file is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY, to the extent permitted by law; without even
+   the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+   PURPOSE.
+*/
+
+#include "config.h"
+
+#include "pakchois.h"
+
+#ifdef ENABLE_NLS
+#include <libintl.h>
+#define _(x) dgettext(PACKAGE_NAME, x)
+#else
+#define _(x) x
+#endif
+
+const char *pakchois_error(ck_rv_t rv)
+{
+    if (rv >= CKR_VENDOR_DEFINED) {
+        return _("Vendor defined error");
+    }
+
+    switch (rv) {
+    case CKR_OK: return _("OK");
+    case CKR_CANCEL: return _("Cancel");
+    case CKR_HOST_MEMORY: return _("Host memory");
+    case CKR_SLOT_ID_INVALID: return _("Slot id invalid");
+    case CKR_GENERAL_ERROR: return _("General error");
+    case CKR_FUNCTION_FAILED: return _("Function failed");
+    case CKR_ARGUMENTS_BAD: return _("Arguments bad");
+    case CKR_NO_EVENT: return _("No event");
+    case CKR_NEED_TO_CREATE_THREADS: return _("Need to create threads");
+    case CKR_CANT_LOCK: return _("Can't lock");
+    case CKR_ATTRIBUTE_READ_ONLY: return _("Attribute read only");
+    case CKR_ATTRIBUTE_SENSITIVE: return _("Attribute sensitive");
+    case CKR_ATTRIBUTE_TYPE_INVALID: return _("Attribute type invalid");
+    case CKR_ATTRIBUTE_VALUE_INVALID: return _("Attribute value invalid");
+    case CKR_DATA_INVALID: return _("Data invalid");
+    case CKR_DATA_LEN_RANGE: return _("Data len range");
+    case CKR_DEVICE_ERROR: return _("Device error");
+    case CKR_DEVICE_MEMORY: return _("Device memory");
+    case CKR_DEVICE_REMOVED: return _("Device removed");
+    case CKR_ENCRYPTED_DATA_INVALID: return _("Encrypted data invalid");
+    case CKR_ENCRYPTED_DATA_LEN_RANGE: return _("Encrypted data len range");
+    case CKR_FUNCTION_CANCELED: return _("Function canceled");
+    case CKR_FUNCTION_NOT_PARALLEL: return _("Function not parallel");
+    case CKR_FUNCTION_NOT_SUPPORTED: return _("Function not supported");
+    case CKR_KEY_HANDLE_INVALID: return _("Key handle invalid");
+    case CKR_KEY_SIZE_RANGE: return _("Key size range");
+    case CKR_KEY_TYPE_INCONSISTENT: return _("Key type inconsistent");
+    case CKR_KEY_NOT_NEEDED: return _("Key not needed");
+    case CKR_KEY_CHANGED: return _("Key changed");
+    case CKR_KEY_NEEDED: return _("Key needed");
+    case CKR_KEY_INDIGESTIBLE: return _("Key indigestible");
+    case CKR_KEY_FUNCTION_NOT_PERMITTED: return _("Key function not 
permitted");
+    case CKR_KEY_NOT_WRAPPABLE: return _("Key not wrappable");
+    case CKR_KEY_UNEXTRACTABLE: return _("Key unextractable");
+    case CKR_MECHANISM_INVALID: return _("Mechanism invalid");
+    case CKR_MECHANISM_PARAM_INVALID: return _("Mechanism param invalid");
+    case CKR_OBJECT_HANDLE_INVALID: return _("Object handle invalid");
+    case CKR_OPERATION_ACTIVE: return _("Operation active");
+    case CKR_OPERATION_NOT_INITIALIZED: return _("Operation not initialized");
+    case CKR_PIN_INCORRECT: return _("PIN incorrect");
+    case CKR_PIN_INVALID: return _("PIN invalid");
+    case CKR_PIN_LEN_RANGE: return _("PIN len range");
+    case CKR_PIN_EXPIRED: return _("PIN expired");
+    case CKR_PIN_LOCKED: return _("PIN locked");
+    case CKR_SESSION_CLOSED: return _("Session closed");
+    case CKR_SESSION_COUNT: return _("Session count");
+    case CKR_SESSION_HANDLE_INVALID: return _("Session handle invalid");
+    case CKR_SESSION_PARALLEL_NOT_SUPPORTED: return _("Session parallel not 
supported");
+    case CKR_SESSION_READ_ONLY: return _("Session read only");
+    case CKR_SESSION_EXISTS: return _("Session exists");
+    case CKR_SESSION_READ_ONLY_EXISTS: return _("Session read only exists");
+    case CKR_SESSION_READ_WRITE_SO_EXISTS: return _("Session read write so 
exists");
+    case CKR_SIGNATURE_INVALID: return _("Signature invalid");
+    case CKR_SIGNATURE_LEN_RANGE: return _("Signature length range");
+    case CKR_TEMPLATE_INCOMPLETE: return _("Template incomplete");
+    case CKR_TEMPLATE_INCONSISTENT: return _("Template inconsistent");
+    case CKR_TOKEN_NOT_PRESENT: return _("Token not present");
+    case CKR_TOKEN_NOT_RECOGNIZED: return _("Token not recognized");
+    case CKR_TOKEN_WRITE_PROTECTED: return _("Token write protected");
+    case CKR_UNWRAPPING_KEY_HANDLE_INVALID: return _("Unwrapping key handle 
invalid");
+    case CKR_UNWRAPPING_KEY_SIZE_RANGE: return _("Unwrapping key size range");
+    case CKR_UNWRAPPING_KEY_TYPE_INCONSISTENT: return _("Unwrapping key type 
inconsistent");
+    case CKR_USER_ALREADY_LOGGED_IN: return _("User already logged in");
+    case CKR_USER_NOT_LOGGED_IN: return _("User not logged in");
+    case CKR_USER_PIN_NOT_INITIALIZED: return _("User PIN not initialized");
+    case CKR_USER_TYPE_INVALID: return _("User type invalid");
+    case CKR_USER_ANOTHER_ALREADY_LOGGED_IN: return _("Another user already 
logged in");
+    case CKR_USER_TOO_MANY_TYPES: return _("User too many types");
+    case CKR_WRAPPED_KEY_INVALID: return _("Wrapped key invalid");
+    case CKR_WRAPPED_KEY_LEN_RANGE: return _("Wrapped key length range");
+    case CKR_WRAPPING_KEY_HANDLE_INVALID: return _("Wrapping key handle 
invalid");
+    case CKR_WRAPPING_KEY_SIZE_RANGE: return _("Wrapping key size range");
+    case CKR_WRAPPING_KEY_TYPE_INCONSISTENT: return _("Wrapping key type 
inconsistent");
+    case CKR_RANDOM_SEED_NOT_SUPPORTED: return _("Random seed not supported");
+    case CKR_RANDOM_NO_RNG: return _("Random no rng");
+    case CKR_DOMAIN_PARAMS_INVALID: return _("Domain params invalid");
+    case CKR_BUFFER_TOO_SMALL: return _("Buffer too small");
+    case CKR_SAVED_STATE_INVALID: return _("Saved state invalid");
+    case CKR_INFORMATION_SENSITIVE: return _("Information sensitive");
+    case CKR_STATE_UNSAVEABLE: return _("State unsaveable");
+    case CKR_CRYPTOKI_NOT_INITIALIZED: return _("Cryptoki not initialized");
+    case CKR_CRYPTOKI_ALREADY_INITIALIZED: return _("Cryptoki already 
initialized");
+    case CKR_MUTEX_BAD: return _("Mutex bad");
+    case CKR_MUTEX_NOT_LOCKED: return _("Mutex not locked");
+    case CKR_FUNCTION_REJECTED: return _("Function rejected");
+    default:
+        break;
+    }
+
+    return _("Unknown error");
+}
diff --git a/lib/pakchois/pakchois.c b/lib/pakchois/pakchois.c
new file mode 100644
index 0000000..a69dfb0
--- /dev/null
+++ b/lib/pakchois/pakchois.c
@@ -0,0 +1,982 @@
+/* 
+   pakchois PKCS#11 interface
+   Copyright (C) 2008, Joe Orton <address@hidden>
+
+   This library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public
+   License as published by the Free Software Foundation; either
+   version 2 of the License, or (at your option) any later version.
+   
+   This library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with this library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+   MA 02111-1307, USA
+*/
+
+/*
+  The interface is directly derived from the scute.org PKCS#11
+  cryptoki interface, which is:
+
+   Copyright 2006, 2007 g10 Code GmbH
+   Copyright 2006 Andreas Jellinghaus
+
+   This file is free software; as a special exception the author gives
+   unlimited permission to copy and/or distribute it, with or without
+   modifications, as long as this notice is preserved.
+
+   This file is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY, to the extent permitted by law; without even
+   the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+   PURPOSE.
+*/
+
+#include "config.h"
+
+#include <dlfcn.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <pthread.h>
+#include <assert.h>
+#include "pakchois.h"
+
+struct provider {
+    char *name;
+    void *handle;
+    pthread_mutex_t mutex;
+    const struct ck_function_list *fns;
+    unsigned int refcount;
+    struct provider *next, **prevref;
+};
+
+struct pakchois_module_s {
+    struct slot *slots;
+    struct provider *provider;
+};
+
+static pthread_mutex_t provider_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+/* List of loaded providers; any modification to the list or any
+ * individual module must performed whilst holding this mutex. */
+static struct provider *provider_list;
+
+struct pakchois_session_s {
+    pakchois_module_t *module;
+    ck_session_handle_t id;
+    pakchois_notify_t notify;
+    void *notify_data;
+    /* Doubly-linked list.  Either prevref = &previous->next or else
+     * prevref = &slot->sessions for the list head. */
+    pakchois_session_t **prevref;
+    pakchois_session_t *next;
+};
+
+struct slot {
+    ck_slot_id_t id;
+    pakchois_session_t *sessions;
+    struct slot *next;
+};
+
+#define DIR_DELIMITER '/'
+
+char* pkcs11ize(const char* name)
+{
+    int len;
+    char* oname;
+    char *base;
+    char *suffix;
+    
+    oname = strdup(name);
+    if (oname == NULL) {
+        return NULL;
+    }
+    
+    /* basename has too many ifs to use */
+    base = strrchr(oname, DIR_DELIMITER);
+    if (base == NULL) {
+        base = oname;
+    } else {
+        base++;
+    }
+
+    suffix = strchr(base, '.');
+    if (suffix != NULL) {
+               if (strncmp(suffix, ".so", 3)==0) {
+                       suffix[0] = 0; /* null terminate before . */
+               }
+    }
+
+    /* check and remove for -p11 or -pkcs11 */
+       suffix = base;
+    while((suffix=strchr(suffix, '-')) != NULL) {
+               if (strncasecmp(suffix, "-p11", 4)==0 || 
+                       strncasecmp(suffix, "-pkcs11", 7)==0) {
+                       suffix[0] = 0;
+                       break;
+               }
+               suffix++;
+       }
+    
+    len = strlen(base);
+
+    memmove(oname, base, len);
+    oname[len] = 0;
+
+    return oname;
+}
+
+static const char *suffix_prefixes[][2] = {
+    { "lib", "pk11.so" },
+    { "", "-pkcs11.so" },
+    { "", ".so" },
+    { "lib", ".so" },
+    { NULL, NULL }
+};
+
+#define CALL(name, args) (mod->provider->fns->C_ ## name) args
+#define CALLS(name, args) (sess->module->provider->fns->C_ ## name) args
+#define CALLS1(n, a) CALLS(n, (sess->id, a))
+#define CALLS2(n, a, b) CALLS(n, (sess->id, a, b))
+#define CALLS3(n, a, b, c) CALLS(n, (sess->id, a, b, c))
+#define CALLS4(n, a, b, c, d) CALLS(n, (sess->id, a, b, c, d))
+#define CALLS5(n, a, b, c, d, e) CALLS(n, (sess->id, a, b, c, d, e))
+#define CALLS7(n, a, b, c, d, e, f, g) CALLS(n, (sess->id, a, b, c, d, e, f, 
g))
+
+static void *find_pkcs11_module(const char *name, CK_C_GetFunctionList *gfl)
+{
+    char module_path[] = PAKCHOIS_MODPATH;
+    char *next = module_path;
+    void *h;
+
+    /* try the plain name first */
+    h = dlopen(name, RTLD_LOCAL|RTLD_NOW);
+    if (h != NULL) {
+         *gfl = dlsym(h, "C_GetFunctionList");
+         if (*gfl) {
+              return h;
+         }
+         dlclose(h);
+    }
+    
+    while (next) {
+        char *dir = next, *sep = strchr(next, ':');
+        unsigned i;
+
+        if (sep) { 
+            *sep++ = '\0';
+            next = sep;
+        }
+        else {
+            next = NULL;
+        }
+
+        
+        for (i = 0; suffix_prefixes[i][0]; i++) {
+            char path[PATH_MAX];
+            
+            snprintf(path, sizeof path, "%s/%s%s%s", dir,
+                     suffix_prefixes[i][0], name, suffix_prefixes[i][1]);
+
+            h = dlopen(path, RTLD_LOCAL|RTLD_NOW);
+            if (h != NULL) {
+                *gfl = dlsym(h, "C_GetFunctionList");
+                if (*gfl) {
+                    return h;
+                }
+                dlclose(h);
+            }
+        }
+    }
+
+    return NULL;
+}            
+
+static struct provider *find_provider(const char *name)
+{
+    struct provider *p;
+
+    for (p = provider_list; p; p = p->next) {
+        if (strcmp(name, p->name) == 0) {
+            return p;
+        }
+    }
+
+    return NULL;    
+}
+
+static ck_rv_t load_provider(struct provider **provider, const char *name, 
+                             void *reserved)
+{
+    CK_C_GetFunctionList gfl;
+    struct provider *prov;
+    struct ck_function_list *fns;
+    struct ck_c_initialize_args args;
+    void *h;
+    ck_rv_t rv;
+    char *cname = NULL;
+
+    if (pthread_mutex_lock(&provider_mutex) != 0) {
+        return CKR_CANT_LOCK;
+    }
+
+    cname = pkcs11ize(name);
+    if (cname == NULL) {
+        rv = CKR_HOST_MEMORY;
+        goto fail_locked;
+    }
+
+fprintf(stderr, "found name: %s\n", cname);
+
+    prov = find_provider(cname);
+    if (prov) {
+        prov->refcount++;
+        *provider = prov;
+        free(cname);
+        pthread_mutex_unlock(&provider_mutex);
+        return CKR_OK;
+    }
+
+    h = find_pkcs11_module(name, &gfl);
+    if (!h) {
+        rv = CKR_GENERAL_ERROR;
+        goto fail_ndup;
+    }
+    
+    rv = gfl(&fns);
+    if (rv != CKR_OK) {
+        goto fail_dso;
+    }
+    
+    *provider = prov = malloc(sizeof *prov);
+    if (prov == NULL) {
+        rv = CKR_HOST_MEMORY;
+        goto fail_dso;
+    }
+    
+    if (pthread_mutex_init(&prov->mutex, NULL)) {
+        rv = CKR_GENERAL_ERROR;
+        goto fail_ctx;
+    }
+
+    prov->name = cname;
+    prov->handle = h;
+    prov->fns = fns;
+    prov->refcount = 1;
+
+    /* Require OS locking, the only sane option. */
+    memset(&args, 0, sizeof args);
+    args.flags = CKF_OS_LOCKING_OK;          
+    args.reserved = reserved;
+
+    rv = fns->C_Initialize(&args);
+    if (rv != CKR_OK) {
+        goto fail_ctx;
+    }
+
+    prov->next = provider_list;
+    prov->prevref = &provider_list;
+    if (prov->next) {
+        prov->next->prevref = &prov->next;
+    }
+    provider_list = prov;
+
+    pthread_mutex_unlock(&provider_mutex);
+    
+    return CKR_OK;
+fail_ctx:        
+    free(prov);
+fail_dso:
+    dlclose(h);
+fail_ndup:
+    free(cname);
+fail_locked:
+    pthread_mutex_unlock(&provider_mutex);
+    *provider = NULL;
+    return rv;
+}    
+
+static ck_rv_t load_module(pakchois_module_t **module, const char *name, 
+                           void *reserved)
+{
+    ck_rv_t rv;
+    pakchois_module_t *pm = malloc(sizeof *pm);
+
+    if (!pm) {
+        return CKR_HOST_MEMORY;
+    }
+
+    rv = load_provider(&pm->provider, name, reserved);
+    if (rv) {
+        return rv;
+    }
+    
+    *module = pm;    
+    pm->slots = NULL;
+
+    return CKR_OK;
+}    
+
+ck_rv_t pakchois_module_load(pakchois_module_t **module, const char *name)
+{
+    return load_module(module, name, NULL);
+}
+
+ck_rv_t pakchois_module_nssload(pakchois_module_t **module, 
+                                const char *name,
+                                const char *directory,
+                                const char *cert_prefix,
+                                const char *key_prefix,
+                                const char *secmod_db)
+{
+    char buf[256];
+
+    snprintf(buf, sizeof buf, 
+             "configdir='%s' certPrefix='%s' keyPrefix='%s' secmod='%s'",
+             directory, cert_prefix ? cert_prefix : "",
+             key_prefix ? key_prefix : "", 
+             secmod_db ? secmod_db : "secmod.db");
+
+    return load_module(module, name, buf);
+}
+
+/* Unreference a provider structure and destoy if, if necessary.  Must
+ * be called WIHTOUT the provider mutex held.  */
+static void provider_unref(struct provider *prov)
+{
+    assert(pthread_mutex_lock(&provider_mutex) == 0);
+
+    if (--prov->refcount == 0) {
+        prov->fns->C_Finalize(NULL);
+        dlclose(prov->handle);
+        *prov->prevref = prov->next;
+        if (prov->next) {
+            prov->next->prevref = prov->prevref;
+        }
+        free(prov->name);
+        free(prov);
+    }
+    pthread_mutex_unlock(&provider_mutex);
+}
+
+void pakchois_module_destroy(pakchois_module_t *mod)
+{
+    provider_unref(mod->provider);
+
+    while (mod->slots) {
+        struct slot *slot = mod->slots;
+        pakchois_close_all_sessions(mod, slot->id);
+        mod->slots = slot->next;
+        free(slot);
+    }
+
+    free(mod);
+}
+
+#ifdef __GNUC__
+static void pakchois_destructor(void)
+    __attribute__((destructor));
+
+static void pakchois_destructor(void)
+{
+    pthread_mutex_destroy(&provider_mutex);
+}
+#else
+#warning need destructor support
+#endif
+
+ck_rv_t pakchois_get_info(pakchois_module_t *mod, struct ck_info *info)
+{
+    return CALL(GetInfo, (info));
+}
+
+ck_rv_t pakchois_get_slot_list(pakchois_module_t *mod,
+                              unsigned char token_present,
+                              ck_slot_id_t *slot_list,
+                              unsigned long *count)
+{
+    return CALL(GetSlotList, (token_present, slot_list, count));
+}
+
+ck_rv_t pakchois_get_slot_info(pakchois_module_t *mod,
+                              ck_slot_id_t slot_id,
+                              struct ck_slot_info *info)
+{
+    return CALL(GetSlotInfo, (slot_id, info));
+}
+
+ck_rv_t pakchois_get_token_info(pakchois_module_t *mod,
+                               ck_slot_id_t slot_id,
+                               struct ck_token_info *info)
+{
+    return CALL(GetTokenInfo, (slot_id, info));
+}
+
+ck_rv_t pakchois_wait_for_slot_event(pakchois_module_t *mod,
+                                    ck_flags_t flags, ck_slot_id_t *slot,
+                                    void *reserved)
+{
+    ck_rv_t rv;
+
+    if (pthread_mutex_lock(&mod->provider->mutex)) {
+        return CKR_CANT_LOCK;
+    }
+        
+    rv = CALL(WaitForSlotEvent, (flags, slot, reserved));
+    pthread_mutex_unlock(&mod->provider->mutex);
+    return rv;
+}
+
+ck_rv_t pakchois_get_mechanism_list(pakchois_module_t *mod,
+                                   ck_slot_id_t slot_id,
+                                   ck_mechanism_type_t *mechanism_list,
+                                   unsigned long *count)
+{
+    return CALL(GetMechanismList, (slot_id, mechanism_list, count));
+}
+
+ck_rv_t pakchois_get_mechanism_info(pakchois_module_t *mod,
+                                   ck_slot_id_t slot_id,
+                                   ck_mechanism_type_t type,
+                                   struct ck_mechanism_info *info)
+{
+    return CALL(GetMechanismInfo, (slot_id, type, info));
+}
+
+ck_rv_t pakchois_init_token(pakchois_module_t *mod,
+                           ck_slot_id_t slot_id, unsigned char *pin,
+                           unsigned long pin_len, unsigned char *label)
+{
+    return CALL(InitToken, (slot_id, pin, pin_len, label));
+}
+
+ck_rv_t pakchois_init_pin(pakchois_session_t *sess, unsigned char *pin,
+                         unsigned long pin_len)
+{
+    return CALLS2(InitPIN, pin, pin_len);
+}
+
+ck_rv_t pakchois_set_pin(pakchois_session_t *sess, unsigned char *old_pin,
+                        unsigned long old_len, unsigned char *new_pin,
+                        unsigned long new_len)
+{
+    return CALLS4(SetPIN, old_pin, old_len, new_pin, new_len);
+}
+
+static ck_rv_t notify_thunk(ck_session_handle_t session,
+                            ck_notification_t event, void *application)
+{
+    pakchois_session_t *sess = application;
+
+    return sess->notify(sess, event, sess->notify_data);
+}
+
+static struct slot *find_slot(pakchois_module_t *mod, ck_slot_id_t id)
+{
+    struct slot *slot;
+
+    for (slot = mod->slots; slot; slot = slot->next)
+        if (slot->id == id)
+            return slot;
+
+    return NULL;
+}
+
+static struct slot *find_or_create_slot(pakchois_module_t *mod,
+                                        ck_slot_id_t id)
+{
+    struct slot *slot = find_slot(mod, id);
+
+    if (slot) {
+        return slot;
+    }
+
+    slot = malloc(sizeof *slot);
+    if (!slot) {
+        return NULL;
+    }
+    
+    slot->id = id;
+    slot->sessions = NULL;
+    slot->next = mod->slots;
+    mod->slots = slot;
+
+    return slot;
+}
+
+static ck_rv_t insert_session(pakchois_module_t *mod,
+                              pakchois_session_t *session,
+                              ck_slot_id_t id)
+{
+    struct slot *slot = find_or_create_slot(mod, id);
+    
+    if (!slot) {
+        return CKR_HOST_MEMORY;
+    }
+
+    session->prevref = &slot->sessions;
+    session->next = slot->sessions;
+    if (session->next) {
+        session->next->prevref = session->prevref;
+    }
+    slot->sessions = session;
+
+    return CKR_OK;
+}
+
+ck_rv_t pakchois_open_session(pakchois_module_t *mod,
+                             ck_slot_id_t slot_id, ck_flags_t flags,
+                             void *application, pakchois_notify_t notify,
+                             pakchois_session_t **session)
+{
+    ck_session_handle_t sh;
+    pakchois_session_t *sess;
+    ck_rv_t rv;
+
+    sess = calloc(1, sizeof *sess);
+    if (sess == NULL) {
+        return CKR_HOST_MEMORY;
+    }    
+
+    rv = CALL(OpenSession, (slot_id, flags, sess, notify_thunk, &sh));
+    if (rv != CKR_OK) {
+        free(sess);
+        return rv;
+    }
+    
+    *session = sess;
+    sess->module = mod;
+    sess->id = sh;
+
+    return insert_session(mod, sess, slot_id);
+}
+
+ck_rv_t pakchois_close_session(pakchois_session_t *sess)
+{
+    /* PKCS#11 says that all bets are off on failure, so destroy the
+     * session object and just return the error code. */
+    ck_rv_t rv = CALLS(CloseSession, (sess->id));
+    *sess->prevref = sess->next;
+    if (sess->next) {
+        sess->next->prevref = sess->prevref;
+    }
+    free(sess);
+    return rv;
+}
+
+ck_rv_t pakchois_close_all_sessions(pakchois_module_t *mod,
+                                   ck_slot_id_t slot_id)
+{
+    struct slot *slot;
+    ck_rv_t rv, frv = CKR_OK;
+
+    slot = find_slot(mod, slot_id);
+
+    if (!slot) {
+        return CKR_SLOT_ID_INVALID;
+    }
+
+    while (slot->sessions) {
+        rv = pakchois_close_session(slot->sessions);
+        if (rv != CKR_OK) {
+            frv = rv;
+        }
+    }
+
+    return frv;
+}
+
+ck_rv_t pakchois_get_session_info(pakchois_session_t *sess,
+                                 struct ck_session_info *info)
+{
+    return CALLS1(GetSessionInfo, info);
+}
+
+ck_rv_t pakchois_get_operation_state(pakchois_session_t *sess,
+                                    unsigned char *operation_state,
+                                    unsigned long *operation_state_len)
+{
+    return CALLS2(GetOperationState, operation_state, 
+                  operation_state_len);
+}
+
+ck_rv_t pakchois_set_operation_state(pakchois_session_t *sess,
+                                    unsigned char *operation_state,
+                                    unsigned long operation_state_len,
+                                    ck_object_handle_t encryption_key,
+                                    ck_object_handle_t authentiation_key)
+{
+    return CALLS4(SetOperationState, operation_state, operation_state_len,
+                  encryption_key, authentiation_key);
+}
+
+ck_rv_t pakchois_login(pakchois_session_t *sess, ck_user_type_t user_type,
+                      unsigned char *pin, unsigned long pin_len)
+{
+    return CALLS3(Login, user_type, pin, pin_len);
+}
+
+ck_rv_t pakchois_logout(pakchois_session_t *sess)
+{
+    return CALLS(Logout, (sess->id));
+}
+
+ck_rv_t pakchois_create_object(pakchois_session_t *sess,
+                              struct ck_attribute *templ,
+                              unsigned long count,
+                              ck_object_handle_t *object)
+{
+    return CALLS3(CreateObject, templ, count, object);
+}
+
+ck_rv_t pakchois_copy_object(pakchois_session_t *sess,
+                            ck_object_handle_t object,
+                            struct ck_attribute *templ, unsigned long count,
+                            ck_object_handle_t *new_object)
+{
+    return CALLS4(CopyObject, object, templ, count, new_object);
+}
+
+ck_rv_t pakchois_destroy_object(pakchois_session_t *sess,
+                               ck_object_handle_t object)
+{
+    return CALLS1(DestroyObject, object);
+}    
+
+ck_rv_t pakchois_get_object_size(pakchois_session_t *sess,
+                                ck_object_handle_t object,
+                                unsigned long *size)
+{
+    return CALLS2(GetObjectSize, object, size);
+}
+
+ck_rv_t pakchois_get_attribute_value(pakchois_session_t *sess,
+                                    ck_object_handle_t object,
+                                    struct ck_attribute *templ,
+                                    unsigned long count)
+{
+    return CALLS3(GetAttributeValue, object, templ, count);
+}
+
+ck_rv_t pakchois_set_attribute_value(pakchois_session_t *sess,
+                                    ck_object_handle_t object,
+                                    struct ck_attribute *templ,
+                                    unsigned long count)
+{
+    return CALLS3(SetAttributeValue, object, templ, count);
+}
+
+ck_rv_t pakchois_find_objects_init(pakchois_session_t *sess,
+                                  struct ck_attribute *templ,
+                                  unsigned long count)
+{
+    return CALLS2(FindObjectsInit, templ, count);
+}
+
+ck_rv_t pakchois_find_objects(pakchois_session_t *sess,
+                             ck_object_handle_t *object,
+                             unsigned long max_object_count,
+                             unsigned long *object_count)
+{
+    return CALLS3(FindObjects, object, max_object_count, object_count);
+}
+
+ck_rv_t pakchois_find_objects_final(pakchois_session_t *sess)
+{
+    return CALLS(FindObjectsFinal, (sess->id));
+}
+
+ck_rv_t pakchois_encrypt_init(pakchois_session_t *sess,
+                             struct ck_mechanism *mechanism,
+                             ck_object_handle_t key)
+{
+    return CALLS2(EncryptInit, mechanism, key);
+}
+
+ck_rv_t pakchois_encrypt(pakchois_session_t *sess,
+                        unsigned char *data, unsigned long data_len,
+                        unsigned char *encrypted_data,
+                        unsigned long *encrypted_data_len)
+{
+    return CALLS4(Encrypt, data, data_len, 
+                  encrypted_data, encrypted_data_len);
+}
+
+ck_rv_t pakchois_encrypt_update(pakchois_session_t *sess,
+                               unsigned char *part, unsigned long part_len,
+                               unsigned char *encrypted_part,
+                               unsigned long *encrypted_part_len)
+{
+    return CALLS4(EncryptUpdate, part, part_len, 
+                  encrypted_part, encrypted_part_len);
+}
+
+ck_rv_t pakchois_encrypt_final(pakchois_session_t *sess,
+                              unsigned char *last_encrypted_part,
+                              unsigned long *last_encrypted_part_len)
+{
+    return CALLS2(EncryptFinal, last_encrypted_part, last_encrypted_part_len);
+}
+
+ck_rv_t pakchois_decrypt_init(pakchois_session_t *sess,
+                             struct ck_mechanism *mechanism,
+                             ck_object_handle_t key)
+{
+    return CALLS2(DecryptInit, mechanism, key);
+}
+
+ck_rv_t pakchois_decrypt(pakchois_session_t *sess,
+                        unsigned char *encrypted_data,
+                        unsigned long encrypted_data_len,
+                        unsigned char *data, unsigned long *data_len)
+{
+    return CALLS4(Decrypt, encrypted_data, encrypted_data_len, data, data_len);
+}
+
+ck_rv_t pakchois_decrypt_update(pakchois_session_t *sess,
+                               unsigned char *encrypted_part,
+                               unsigned long encrypted_part_len,
+                               unsigned char *part, unsigned long *part_len)
+{
+    return CALLS4(DecryptUpdate, encrypted_part, encrypted_part_len,
+                  part, part_len);
+}
+
+ck_rv_t pakchois_decrypt_final(pakchois_session_t *sess,
+                              unsigned char *last_part,
+                              unsigned long *last_part_len)
+{
+    return CALLS2(DecryptFinal, last_part, last_part_len);
+}
+
+ck_rv_t pakchois_digest_init(pakchois_session_t *sess,
+                            struct ck_mechanism *mechanism)
+{
+    return CALLS1(DigestInit, mechanism);
+}
+
+ck_rv_t pakchois_digest(pakchois_session_t *sess, unsigned char *data,
+                       unsigned long data_len, unsigned char *digest,
+                       unsigned long *digest_len)
+{
+    return CALLS4(Digest, data, data_len, digest, digest_len);
+}
+
+ck_rv_t pakchois_digest_update(pakchois_session_t *sess,
+                              unsigned char *part, unsigned long part_len)
+{
+    return CALLS2(DigestUpdate, part, part_len);
+}
+
+ck_rv_t pakchois_digest_key(pakchois_session_t *sess,
+                           ck_object_handle_t key)
+{
+    return CALLS1(DigestKey, key);
+}
+
+ck_rv_t pakchois_digest_final(pakchois_session_t *sess,
+                             unsigned char *digest,
+                             unsigned long *digest_len)
+{
+    return CALLS2(DigestFinal, digest, digest_len);
+}
+
+ck_rv_t pakchois_sign_init(pakchois_session_t *sess,
+                          struct ck_mechanism *mechanism,
+                          ck_object_handle_t key)
+{
+    return CALLS2(SignInit, mechanism, key);
+}
+
+ck_rv_t pakchois_sign(pakchois_session_t *sess, unsigned char *data,
+                     unsigned long data_len, unsigned char *signature,
+                     unsigned long *signature_len)
+{
+    return CALLS4(Sign, data, data_len, signature, signature_len);
+}
+
+ck_rv_t pakchois_sign_update(pakchois_session_t *sess,
+                            unsigned char *part, unsigned long part_len)
+{
+    return CALLS2(SignUpdate, part, part_len);
+}
+
+ck_rv_t pakchois_sign_final(pakchois_session_t *sess,
+                           unsigned char *signature,
+                           unsigned long *signature_len)
+{
+    return CALLS2(SignFinal, signature, signature_len);
+}
+
+ck_rv_t pakchois_sign_recover_init(pakchois_session_t *sess,
+                                  struct ck_mechanism *mechanism,
+                                  ck_object_handle_t key)
+{
+    return CALLS2(SignRecoverInit, mechanism, key);
+}
+
+ck_rv_t pakchois_sign_recover(pakchois_session_t *sess,
+                             unsigned char *data, unsigned long data_len,
+                             unsigned char *signature,
+                             unsigned long *signature_len)
+{
+    return CALLS4(SignRecover, data, data_len, signature, signature_len);
+}
+
+ck_rv_t pakchois_verify_init(pakchois_session_t *sess,
+                            struct ck_mechanism *mechanism,
+                            ck_object_handle_t key)
+{
+    return CALLS2(VerifyInit, mechanism, key);
+}
+
+ck_rv_t pakchois_verify(pakchois_session_t *sess, unsigned char *data,
+                       unsigned long data_len, unsigned char *signature,
+                       unsigned long signature_len)
+{
+    return CALLS4(Verify, data, data_len, signature, signature_len);
+}
+
+ck_rv_t pakchois_verify_update(pakchois_session_t *sess,
+                              unsigned char *part, unsigned long part_len)
+{
+    return CALLS2(VerifyUpdate, part, part_len);
+}
+
+ck_rv_t pakchois_verify_final(pakchois_session_t *sess,
+                             unsigned char *signature,
+                             unsigned long signature_len)
+{
+    return CALLS2(VerifyFinal, signature, signature_len);
+}
+
+ck_rv_t pakchois_verify_recover_init(pakchois_session_t *sess,
+                                    struct ck_mechanism *mechanism,
+                                    ck_object_handle_t key)
+{
+    return CALLS2(VerifyRecoverInit, mechanism, key);
+}
+
+ck_rv_t pakchois_verify_recover(pakchois_session_t *sess,
+                               unsigned char *signature,
+                               unsigned long signature_len,
+                               unsigned char *data, unsigned long *data_len)
+{
+    return CALLS4(VerifyRecover, signature, signature_len, data, data_len);
+}
+
+ck_rv_t pakchois_digest_encrypt_update(pakchois_session_t *sess,
+                                      unsigned char *part,
+                                      unsigned long part_len,
+                                      unsigned char *encrypted_part,
+                                      unsigned long *encrypted_part_len)
+{
+    return CALLS4(DigestEncryptUpdate, part, part_len,
+                  encrypted_part, encrypted_part_len);
+}
+
+ck_rv_t pakchois_decrypt_digest_update(pakchois_session_t *sess,
+                                      unsigned char *encrypted_part,
+                                      unsigned long encrypted_part_len,
+                                      unsigned char *part,
+                                      unsigned long *part_len)
+{
+    return CALLS4(DecryptDigestUpdate, encrypted_part, encrypted_part_len,
+                  part, part_len);
+}
+
+ck_rv_t pakchois_sign_encrypt_update(pakchois_session_t *sess,
+                                    unsigned char *part,
+                                    unsigned long part_len,
+                                    unsigned char *encrypted_part,
+                                    unsigned long *encrypted_part_len)
+{
+    return CALLS4(SignEncryptUpdate, part, part_len,
+                  encrypted_part, encrypted_part_len);
+}
+
+ck_rv_t pakchois_decrypt_verify_update(pakchois_session_t *sess,
+                                      unsigned char *encrypted_part,
+                                      unsigned long encrypted_part_len,
+                                      unsigned char *part,
+                                      unsigned long *part_len)
+{
+    return CALLS4(DecryptVerifyUpdate, encrypted_part, encrypted_part_len,
+                  part, part_len);
+}
+
+ck_rv_t pakchois_generate_key(pakchois_session_t *sess,
+                             struct ck_mechanism *mechanism,
+                             struct ck_attribute *templ,
+                             unsigned long count, ck_object_handle_t *key)
+{
+    return CALLS4(GenerateKey, mechanism, templ, count, key);
+}
+
+ck_rv_t pakchois_generate_key_pair(pakchois_session_t *sess,
+                                  struct ck_mechanism *mechanism,
+                                  struct ck_attribute *public_key_template,
+                                  unsigned long public_key_attribute_count,
+                                  struct ck_attribute *private_key_template,
+                                  unsigned long private_key_attribute_count,
+                                  ck_object_handle_t *public_key,
+                                  ck_object_handle_t *private_key)
+{
+    return CALLS7(GenerateKeyPair, mechanism,
+                  public_key_template, public_key_attribute_count,
+                  private_key_template, private_key_attribute_count,
+                  public_key, private_key);
+}
+
+ck_rv_t pakchois_wrap_key(pakchois_session_t *sess,
+                         struct ck_mechanism *mechanism,
+                         ck_object_handle_t wrapping_key,
+                         ck_object_handle_t key, unsigned char *wrapped_key,
+                         unsigned long *wrapped_key_len)
+{
+    return CALLS5(WrapKey, mechanism, wrapping_key,
+                  key, wrapped_key, wrapped_key_len);
+}    
+
+ck_rv_t pakchois_unwrap_key(pakchois_session_t *sess,
+                           struct ck_mechanism *mechanism,
+                           ck_object_handle_t unwrapping_key,
+                           unsigned char *wrapped_key,
+                           unsigned long wrapped_key_len,
+                           struct ck_attribute *templ,
+                           unsigned long attribute_count,
+                           ck_object_handle_t *key)
+{
+    return CALLS7(UnwrapKey, mechanism, unwrapping_key, 
+                  wrapped_key, wrapped_key_len, templ, attribute_count,
+                  key);
+}
+
+ck_rv_t pakchois_derive_key(pakchois_session_t *sess,
+                           struct ck_mechanism *mechanism,
+                           ck_object_handle_t base_key,
+                           struct ck_attribute *templ,
+                           unsigned long attribute_count,
+                           ck_object_handle_t *key)
+{
+    return CALLS5(DeriveKey, mechanism, base_key, templ, attribute_count, key);
+}
+
+
+ck_rv_t pakchois_seed_random(pakchois_session_t *sess,
+                            unsigned char *seed, unsigned long seed_len)
+{
+    return CALLS2(SeedRandom, seed, seed_len);
+}
+
+ck_rv_t pakchois_generate_random(pakchois_session_t *sess,
+                                unsigned char *random_data,
+                                unsigned long random_len)
+{
+    return CALLS2(GenerateRandom, random_data, random_len);
+}
diff --git a/lib/pakchois/pakchois.h b/lib/pakchois/pakchois.h
new file mode 100644
index 0000000..76999ef
--- /dev/null
+++ b/lib/pakchois/pakchois.h
@@ -0,0 +1,361 @@
+/* 
+   pakchois PKCS#11 interface
+   Copyright (C) 2008, Joe Orton <address@hidden>
+
+   This library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public
+   License as published by the Free Software Foundation; either
+   version 2 of the License, or (at your option) any later version.
+   
+   This library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with this library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+   MA 02111-1307, USA
+
+*/
+
+/*
+  This interface is directly derived from the scute.org PKCS#11
+  cryptoki interface, which is:
+
+   Copyright 2006, 2007 g10 Code GmbH
+   Copyright 2006 Andreas Jellinghaus
+
+   This file is free software; as a special exception the author gives
+   unlimited permission to copy and/or distribute it, with or without
+   modifications, as long as this notice is preserved.
+
+   This file is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY, to the extent permitted by law; without even
+   the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+   PURPOSE.
+*/
+
+#ifndef PAKCHOIS_H
+#define PAKCHOIS_H
+
+#define CRYPTOKI_GNU
+
+#include "pakchois11.h"
+
+/* API version: major is bumped for any backwards-incompatible
+ * changes. minor is bumped for any new interfaces.  Note that the API
+ * is versioned independent of the project release version.  */
+#define PAKCHOIS_API_MAJOR (0)
+#define PAKCHOIS_API_MINOR (2)
+
+/* API version history (note that API versions do not map directly to
+   the project version!):
+
+   0.1: Initial release
+   0.2: Addition of pakchois_error()
+        Concurrent access guarantee added for pakchois_module_load()
+        Thread-safety guarantee added for pakchois_wait_for_slot_event()
+*/
+
+typedef struct pakchois_module_s pakchois_module_t;
+typedef struct pakchois_session_s pakchois_session_t;
+
+/* Load a PKCS#11 module by name (for example "opensc" or
+ * "gnome-keyring").  Returns CKR_OK on success.  Any module of given
+ * name may be safely loaded multiple times within an application; the
+ * underlying PKCS#11 provider will be loaded only once. */
+ck_rv_t pakchois_module_load(pakchois_module_t **module, const char *name);
+
+/* Load an NSS "softokn" which violates the PKCS#11 standard in
+ * initialization, with given name (e.g. "softokn3").  The directory
+ * in which the NSS database resides must be specified; the other
+ * arguments may be NULL to use defaults. Returns CKR_OK on
+ * success. */
+ck_rv_t pakchois_module_nssload(pakchois_module_t **module, 
+                                const char *name,
+                                const char *directory,
+                                const char *cert_prefix,
+                                const char *key_prefix,
+                                const char *secmod_db);
+
+/* Destroy a PKCS#11 module. */
+void pakchois_module_destroy(pakchois_module_t *module);
+
+/* Return the error string corresponding to the given return value.
+ * Never returns NULL.  */
+const char *pakchois_error(ck_rv_t rv);
+
+/* All following interfaces model the PKCS#11 equivalents, without the
+   camel-cased naming convention.  The PKCS#11 specification has
+   detailed interface descriptions:
+   
+      http://www.rsa.com/rsalabs/node.asp?id=2133
+
+   The differences between this interface and PKCS#11 are:
+   
+   1. some interfaces take a module pointer as first argument
+
+   2. session handlers are represented as opaque objects
+
+   3. the notify callback type has changed accordingly
+
+   4. the C_Initialize, C_Finalize, and C_GetFunctionList interfaces
+   are not exposed (these are called internally by
+   pakchois_module_load and pakchois_module_destroy)
+
+   5. pakchois_wait_for_slot_event() is thread-safe against other
+   callers of pakchois_wait_for_slot_event(); the call to the
+   underlying provider's WaitForSlotEvent function is protected by a
+   mutex.
+
+   6. pakchois_close_all_sessions() only closes sessions associated
+   with the given module instance; any sessions opened by other users
+   of the underlying provider are unaffected.
+
+   If a module object is used concurrently from separate threads,
+   undefined behaviour results.  If a session object is used
+   concurrently from separate threads, undefined behavioure results.
+
+*/
+ck_rv_t pakchois_get_info(pakchois_module_t *module, struct ck_info *info);
+
+ck_rv_t pakchois_get_slot_list(pakchois_module_t *module,
+                              unsigned char token_present,
+                              ck_slot_id_t *slot_list,
+                              unsigned long *count);
+
+ck_rv_t pakchois_get_slot_info(pakchois_module_t *module,
+                              ck_slot_id_t slot_id,
+                              struct ck_slot_info *info);
+
+ck_rv_t pakchois_get_token_info(pakchois_module_t *module,
+                               ck_slot_id_t slot_id,
+                               struct ck_token_info *info);
+
+ck_rv_t pakchois_wait_for_slot_event(pakchois_module_t *module,
+                                    ck_flags_t flags, ck_slot_id_t *slot,
+                                    void *reserved);
+
+ck_rv_t pakchois_get_mechanism_list(pakchois_module_t *module,
+                                   ck_slot_id_t slot_id,
+                                   ck_mechanism_type_t *mechanism_list,
+                                   unsigned long *count);
+
+ck_rv_t pakchois_get_mechanism_info(pakchois_module_t *module,
+                                   ck_slot_id_t slot_id,
+                                   ck_mechanism_type_t type,
+                                   struct ck_mechanism_info *info);
+
+ck_rv_t pakchois_init_token(pakchois_module_t *module,
+                           ck_slot_id_t slot_id, unsigned char *pin,
+                           unsigned long pin_len, unsigned char *label);
+
+ck_rv_t pakchois_init_pin(pakchois_session_t *session, unsigned char *pin,
+                         unsigned long pin_len);
+
+ck_rv_t pakchois_set_pin(pakchois_session_t *session, unsigned char *old_pin,
+                        unsigned long old_len, unsigned char *new_pin,
+                        unsigned long new_len);
+
+typedef ck_rv_t (*pakchois_notify_t) (pakchois_session_t *sess,
+                                      ck_notification_t event,
+                                      void *application);
+
+ck_rv_t pakchois_open_session(pakchois_module_t *module,
+                             ck_slot_id_t slot_id, ck_flags_t flags,
+                             void *application, pakchois_notify_t notify,
+                             pakchois_session_t **session);
+
+ck_rv_t pakchois_close_session(pakchois_session_t *session);
+
+ck_rv_t pakchois_close_all_sessions(pakchois_module_t *module,
+                                   ck_slot_id_t slot_id);
+
+ck_rv_t pakchois_get_session_info(pakchois_session_t *session,
+                                 struct ck_session_info *info);
+ck_rv_t pakchois_get_operation_state(pakchois_session_t *session,
+                                    unsigned char *operation_state,
+                                    unsigned long *operation_state_len);
+ck_rv_t pakchois_set_operation_state(pakchois_session_t *session,
+                                    unsigned char *operation_state,
+                                    unsigned long operation_state_len,
+                                    ck_object_handle_t encryption_key,
+                                    ck_object_handle_t authentiation_key);
+
+ck_rv_t pakchois_login(pakchois_session_t *session, ck_user_type_t user_type,
+                      unsigned char *pin, unsigned long pin_len);
+ck_rv_t pakchois_logout(pakchois_session_t *session);
+
+ck_rv_t pakchois_create_object(pakchois_session_t *session,
+                              struct ck_attribute *templ,
+                              unsigned long count,
+                              ck_object_handle_t *object);
+ck_rv_t pakchois_copy_object(pakchois_session_t *session,
+                            ck_object_handle_t object,
+                            struct ck_attribute *templ, unsigned long count,
+                            ck_object_handle_t *new_object);
+ck_rv_t pakchois_destroy_object(pakchois_session_t *session,
+                               ck_object_handle_t object);
+ck_rv_t pakchois_get_object_size(pakchois_session_t *session,
+                                ck_object_handle_t object,
+                                unsigned long *size);
+
+ck_rv_t pakchois_get_attribute_value(pakchois_session_t *session,
+                                    ck_object_handle_t object,
+                                    struct ck_attribute *templ,
+                                    unsigned long count);
+ck_rv_t pakchois_set_attribute_value(pakchois_session_t *session,
+                                    ck_object_handle_t object,
+                                    struct ck_attribute *templ,
+                                    unsigned long count);
+ck_rv_t pakchois_find_objects_init(pakchois_session_t *session,
+                                  struct ck_attribute *templ,
+                                  unsigned long count);
+ck_rv_t pakchois_find_objects(pakchois_session_t *session,
+                             ck_object_handle_t *object,
+                             unsigned long max_object_count,
+                             unsigned long *object_count);
+ck_rv_t pakchois_find_objects_final(pakchois_session_t *session);
+
+ck_rv_t pakchois_encrypt_init(pakchois_session_t *session,
+                             struct ck_mechanism *mechanism,
+                             ck_object_handle_t key);
+ck_rv_t pakchois_encrypt(pakchois_session_t *session,
+                        unsigned char *data, unsigned long data_len,
+                        unsigned char *encrypted_data,
+                        unsigned long *encrypted_data_len);
+ck_rv_t pakchois_encrypt_update(pakchois_session_t *session,
+                               unsigned char *part, unsigned long part_len,
+                               unsigned char *encrypted_part,
+                               unsigned long *encrypted_part_len);
+ck_rv_t pakchois_encrypt_final(pakchois_session_t *session,
+                              unsigned char *last_encrypted_part,
+                              unsigned long *last_encrypted_part_len);
+
+ck_rv_t pakchois_decrypt_init(pakchois_session_t *session,
+                             struct ck_mechanism *mechanism,
+                             ck_object_handle_t key);
+ck_rv_t pakchois_decrypt(pakchois_session_t *session,
+                        unsigned char *encrypted_data,
+                        unsigned long encrypted_data_len,
+                        unsigned char *data, unsigned long *data_len);
+ck_rv_t pakchois_decrypt_update(pakchois_session_t *session,
+                               unsigned char *encrypted_part,
+                               unsigned long encrypted_part_len,
+                               unsigned char *part, unsigned long *part_len);
+ck_rv_t pakchois_decrypt_final(pakchois_session_t *session,
+                              unsigned char *last_part,
+                              unsigned long *last_part_len);
+ck_rv_t pakchois_digest_init(pakchois_session_t *session,
+                            struct ck_mechanism *mechanism);
+ck_rv_t pakchois_digest(pakchois_session_t *session, unsigned char *data,
+                       unsigned long data_len, unsigned char *digest,
+                       unsigned long *digest_len);
+ck_rv_t pakchois_digest_update(pakchois_session_t *session,
+                              unsigned char *part, unsigned long part_len);
+ck_rv_t pakchois_digest_key(pakchois_session_t *session,
+                           ck_object_handle_t key);
+ck_rv_t pakchois_digest_final(pakchois_session_t *session,
+                             unsigned char *digest,
+                             unsigned long *digest_len);
+
+ck_rv_t pakchois_sign_init(pakchois_session_t *session,
+                          struct ck_mechanism *mechanism,
+                          ck_object_handle_t key);
+ck_rv_t pakchois_sign(pakchois_session_t *session, unsigned char *data,
+                     unsigned long data_len, unsigned char *signature,
+                     unsigned long *signature_len);
+ck_rv_t pakchois_sign_update(pakchois_session_t *session,
+                            unsigned char *part, unsigned long part_len);
+ck_rv_t pakchois_sign_final(pakchois_session_t *session,
+                           unsigned char *signature,
+                           unsigned long *signature_len);
+ck_rv_t pakchois_sign_recover_init(pakchois_session_t *session,
+                                  struct ck_mechanism *mechanism,
+                                  ck_object_handle_t key);
+ck_rv_t pakchois_sign_recover(pakchois_session_t *session,
+                             unsigned char *data, unsigned long data_len,
+                             unsigned char *signature,
+                             unsigned long *signature_len);
+
+ck_rv_t pakchois_verify_init(pakchois_session_t *session,
+                            struct ck_mechanism *mechanism,
+                            ck_object_handle_t key);
+ck_rv_t pakchois_verify(pakchois_session_t *session, unsigned char *data,
+                       unsigned long data_len, unsigned char *signature,
+                       unsigned long signature_len);
+ck_rv_t pakchois_verify_update(pakchois_session_t *session,
+                              unsigned char *part, unsigned long part_len);
+ck_rv_t pakchois_verify_final(pakchois_session_t *session,
+                             unsigned char *signature,
+                             unsigned long signature_len);
+ck_rv_t pakchois_verify_recover_init(pakchois_session_t *session,
+                                    struct ck_mechanism *mechanism,
+                                    ck_object_handle_t key);
+ck_rv_t pakchois_verify_recover(pakchois_session_t *session,
+                               unsigned char *signature,
+                               unsigned long signature_len,
+                               unsigned char *data, unsigned long *data_len);
+
+ck_rv_t pakchois_digest_encrypt_update(pakchois_session_t *session,
+                                      unsigned char *part,
+                                      unsigned long part_len,
+                                      unsigned char *encrypted_part,
+                                      unsigned long *encrypted_part_len);
+ck_rv_t pakchois_decrypt_digest_update(pakchois_session_t *session,
+                                      unsigned char *encrypted_part,
+                                      unsigned long encrypted_part_len,
+                                      unsigned char *part,
+                                      unsigned long *part_len);
+ck_rv_t pakchois_sign_encrypt_update(pakchois_session_t *session,
+                                    unsigned char *part,
+                                    unsigned long part_len,
+                                    unsigned char *encrypted_part,
+                                    unsigned long *encrypted_part_len);
+ck_rv_t pakchois_decrypt_verify_update(pakchois_session_t *session,
+                                      unsigned char *encrypted_part,
+                                      unsigned long encrypted_part_len,
+                                      unsigned char *part,
+                                      unsigned long *part_len);
+
+ck_rv_t pakchois_generate_key(pakchois_session_t *session,
+                             struct ck_mechanism *mechanism,
+                             struct ck_attribute *templ,
+                             unsigned long count, ck_object_handle_t *key);
+ck_rv_t pakchois_generate_key_pair(pakchois_session_t *session,
+                                  struct ck_mechanism *mechanism,
+                                  struct ck_attribute *public_key_template,
+                                  unsigned long public_key_attribute_count,
+                                  struct ck_attribute *private_key_template,
+                                  unsigned long private_key_attribute_count,
+                                  ck_object_handle_t *public_key,
+                                  ck_object_handle_t *private_key);
+
+ck_rv_t pakchois_wrap_key(pakchois_session_t *session,
+                         struct ck_mechanism *mechanism,
+                         ck_object_handle_t wrapping_key,
+                         ck_object_handle_t key, unsigned char *wrapped_key,
+                         unsigned long *wrapped_key_len);
+ck_rv_t pakchois_unwrap_key(pakchois_session_t *session,
+                           struct ck_mechanism *mechanism,
+                           ck_object_handle_t unwrapping_key,
+                           unsigned char *wrapped_key,
+                           unsigned long wrapped_key_len,
+                           struct ck_attribute *templ,
+                           unsigned long attribute_count,
+                           ck_object_handle_t *key);
+ck_rv_t pakchois_derive_key(pakchois_session_t *session,
+                           struct ck_mechanism *mechanism,
+                           ck_object_handle_t base_key,
+                           struct ck_attribute *templ,
+                           unsigned long attribute_count,
+                           ck_object_handle_t *key);
+
+ck_rv_t pakchois_seed_random(pakchois_session_t *session,
+                            unsigned char *seed, unsigned long seed_len);
+ck_rv_t pakchois_generate_random(pakchois_session_t *session,
+                                unsigned char *random_data,
+                                unsigned long random_len);
+
+#endif /* PAKCHOIS_H */
diff --git a/lib/pakchois/pakchois11.h b/lib/pakchois/pakchois11.h
new file mode 100644
index 0000000..2e6a1e3
--- /dev/null
+++ b/lib/pakchois/pakchois11.h
@@ -0,0 +1,1357 @@
+/* pkcs11.h
+   Copyright 2006, 2007 g10 Code GmbH
+   Copyright 2006 Andreas Jellinghaus
+
+   This file is free software; as a special exception the author gives
+   unlimited permission to copy and/or distribute it, with or without
+   modifications, as long as this notice is preserved.
+
+   This file is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY, to the extent permitted by law; without even
+   the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+   PURPOSE.  */
+
+/* Please submit changes back to the Scute project at
+   http://www.scute.org/ (or send them to address@hidden), so that
+   they can be picked up by other projects from there as well.  */
+
+/* This file is a modified implementation of the PKCS #11 standard by
+   RSA Security Inc.  It is mostly a drop-in replacement, with the
+   following change:
+
+   This header file does not require any macro definitions by the user
+   (like CK_DEFINE_FUNCTION etc).  In fact, it defines those macros
+   for you (if useful, some are missing, let me know if you need
+   more).
+
+   There is an additional API available that does comply better to the
+   GNU coding standard.  It can be switched on by defining
+   CRYPTOKI_GNU before including this header file.  For this, the
+   following changes are made to the specification:
+
+   All structure types are changed to a "struct ck_foo" where CK_FOO
+   is the type name in PKCS #11.
+
+   All non-structure types are changed to ck_foo_t where CK_FOO is the
+   lowercase version of the type name in PKCS #11.  The basic types
+   (CK_ULONG et al.) are removed without substitute.
+
+   All members of structures are modified in the following way: Type
+   indication prefixes are removed, and underscore characters are
+   inserted before words.  Then the result is lowercased.
+
+   Note that function names are still in the original case, as they
+   need for ABI compatibility.
+
+   CK_FALSE, CK_TRUE and NULL_PTR are removed without substitute.  Use
+   <stdbool.h>.
+
+   If CRYPTOKI_COMPAT is defined before including this header file,
+   then none of the API changes above take place, and the API is the
+   one defined by the PKCS #11 standard.  */
+
+#ifndef PKCS11_H
+#define PKCS11_H 1
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+
+/* The version of cryptoki we implement.  The revision is changed with
+   each modification of this file.  If you do not use the "official"
+   version of this file, please consider deleting the revision macro
+   (you may use a macro with a different name to keep track of your
+   versions).  */
+#define CRYPTOKI_VERSION_MAJOR         2
+#define CRYPTOKI_VERSION_MINOR         20
+#define CRYPTOKI_VERSION_REVISION      6
+
+
+/* Compatibility interface is default, unless CRYPTOKI_GNU is
+   given.  */
+#ifndef CRYPTOKI_GNU
+#ifndef CRYPTOKI_COMPAT
+#define CRYPTOKI_COMPAT 1
+#endif
+#endif
+
+/* System dependencies.  */
+
+#if defined(_WIN32) || defined(CRYPTOKI_FORCE_WIN32)
+
+/* There is a matching pop below.  */
+#pragma pack(push, cryptoki, 1)
+
+#ifdef CRYPTOKI_EXPORTS
+#define CK_SPEC __declspec(dllexport)
+#else
+#define CK_SPEC __declspec(dllimport)
+#endif
+
+#else
+
+#define CK_SPEC
+
+#endif
+
+
+#ifdef CRYPTOKI_COMPAT
+  /* If we are in compatibility mode, switch all exposed names to the
+     PKCS #11 variant.  There are corresponding #undefs below.  */
+
+#define ck_flags_t CK_FLAGS
+#define ck_version _CK_VERSION
+
+#define ck_info _CK_INFO
+#define cryptoki_version cryptokiVersion
+#define manufacturer_id manufacturerID
+#define library_description libraryDescription
+#define library_version libraryVersion
+
+#define ck_notification_t CK_NOTIFICATION
+#define ck_slot_id_t CK_SLOT_ID
+
+#define ck_slot_info _CK_SLOT_INFO
+#define slot_description slotDescription
+#define hardware_version hardwareVersion
+#define firmware_version firmwareVersion
+
+#define ck_token_info _CK_TOKEN_INFO
+#define serial_number serialNumber
+#define max_session_count ulMaxSessionCount
+#define session_count ulSessionCount
+#define max_rw_session_count ulMaxRwSessionCount
+#define rw_session_count ulRwSessionCount
+#define max_pin_len ulMaxPinLen
+#define min_pin_len ulMinPinLen
+#define total_public_memory ulTotalPublicMemory
+#define free_public_memory ulFreePublicMemory
+#define total_private_memory ulTotalPrivateMemory
+#define free_private_memory ulFreePrivateMemory
+#define utc_time utcTime
+
+#define ck_session_handle_t CK_SESSION_HANDLE
+#define ck_user_type_t CK_USER_TYPE
+#define ck_state_t CK_STATE
+
+#define ck_session_info _CK_SESSION_INFO
+#define slot_id slotID
+#define device_error ulDeviceError
+
+#define ck_object_handle_t CK_OBJECT_HANDLE
+#define ck_object_class_t CK_OBJECT_CLASS
+#define ck_hw_feature_type_t CK_HW_FEATURE_TYPE
+#define ck_key_type_t CK_KEY_TYPE
+#define ck_certificate_type_t CK_CERTIFICATE_TYPE
+#define ck_attribute_type_t CK_ATTRIBUTE_TYPE
+
+#define ck_attribute _CK_ATTRIBUTE
+#define value pValue
+#define value_len ulValueLen
+
+#define ck_date _CK_DATE
+
+#define ck_mechanism_type_t CK_MECHANISM_TYPE
+
+#define ck_mechanism _CK_MECHANISM
+#define parameter pParameter
+#define parameter_len ulParameterLen
+
+#define ck_mechanism_info _CK_MECHANISM_INFO
+#define min_key_size ulMinKeySize
+#define max_key_size ulMaxKeySize
+
+#define ck_rv_t CK_RV
+#define ck_notify_t CK_NOTIFY
+
+#define ck_function_list _CK_FUNCTION_LIST
+
+#define ck_createmutex_t CK_CREATEMUTEX
+#define ck_destroymutex_t CK_DESTROYMUTEX
+#define ck_lockmutex_t CK_LOCKMUTEX
+#define ck_unlockmutex_t CK_UNLOCKMUTEX
+
+#define ck_c_initialize_args _CK_C_INITIALIZE_ARGS
+#define create_mutex CreateMutex
+#define destroy_mutex DestroyMutex
+#define lock_mutex LockMutex
+#define unlock_mutex UnlockMutex
+#define reserved pReserved
+
+#endif /* CRYPTOKI_COMPAT */
+
+
+
+typedef unsigned long ck_flags_t;
+
+struct ck_version
+{
+  unsigned char major;
+  unsigned char minor;
+};
+
+
+struct ck_info
+{
+  struct ck_version cryptoki_version;
+  unsigned char manufacturer_id[32];
+  ck_flags_t flags;
+  unsigned char library_description[32];
+  struct ck_version library_version;
+};
+
+
+typedef unsigned long ck_notification_t;
+
+#define CKN_SURRENDER  (0)
+
+
+typedef unsigned long ck_slot_id_t;
+
+
+struct ck_slot_info
+{
+  unsigned char slot_description[64];
+  unsigned char manufacturer_id[32];
+  ck_flags_t flags;
+  struct ck_version hardware_version;
+  struct ck_version firmware_version;
+};
+
+
+#define CKF_TOKEN_PRESENT      (1 << 0)
+#define CKF_REMOVABLE_DEVICE   (1 << 1)
+#define CKF_HW_SLOT            (1 << 2)
+#define CKF_ARRAY_ATTRIBUTE    (1 << 30)
+
+
+struct ck_token_info
+{
+  unsigned char label[32];
+  unsigned char manufacturer_id[32];
+  unsigned char model[16];
+  unsigned char serial_number[16];
+  ck_flags_t flags;
+  unsigned long max_session_count;
+  unsigned long session_count;
+  unsigned long max_rw_session_count;
+  unsigned long rw_session_count;
+  unsigned long max_pin_len;
+  unsigned long min_pin_len;
+  unsigned long total_public_memory;
+  unsigned long free_public_memory;
+  unsigned long total_private_memory;
+  unsigned long free_private_memory;
+  struct ck_version hardware_version;
+  struct ck_version firmware_version;
+  unsigned char utc_time[16];
+};
+
+
+#define CKF_RNG                                        (1 << 0)
+#define CKF_WRITE_PROTECTED                    (1 << 1)
+#define CKF_LOGIN_REQUIRED                     (1 << 2)
+#define CKF_USER_PIN_INITIALIZED               (1 << 3)
+#define CKF_RESTORE_KEY_NOT_NEEDED             (1 << 5)
+#define CKF_CLOCK_ON_TOKEN                     (1 << 6)
+#define CKF_PROTECTED_AUTHENTICATION_PATH      (1 << 8)
+#define CKF_DUAL_CRYPTO_OPERATIONS             (1 << 9)
+#define CKF_TOKEN_INITIALIZED                  (1 << 10)
+#define CKF_SECONDARY_AUTHENTICATION           (1 << 11)
+#define CKF_USER_PIN_COUNT_LOW                 (1 << 16)
+#define CKF_USER_PIN_FINAL_TRY                 (1 << 17)
+#define CKF_USER_PIN_LOCKED                    (1 << 18)
+#define CKF_USER_PIN_TO_BE_CHANGED             (1 << 19)
+#define CKF_SO_PIN_COUNT_LOW                   (1 << 20)
+#define CKF_SO_PIN_FINAL_TRY                   (1 << 21)
+#define CKF_SO_PIN_LOCKED                      (1 << 22)
+#define CKF_SO_PIN_TO_BE_CHANGED               (1 << 23)
+
+#define CK_UNAVAILABLE_INFORMATION     ((unsigned long) -1)
+#define CK_EFFECTIVELY_INFINITE                (0)
+
+
+typedef unsigned long ck_session_handle_t;
+
+#define CK_INVALID_HANDLE      (0)
+
+
+typedef unsigned long ck_user_type_t;
+
+#define CKU_SO                 (0)
+#define CKU_USER               (1)
+#define CKU_CONTEXT_SPECIFIC   (2)
+
+
+typedef unsigned long ck_state_t;
+
+#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)
+
+
+struct ck_session_info
+{
+  ck_slot_id_t slot_id;
+  ck_state_t state;
+  ck_flags_t flags;
+  unsigned long device_error;
+};
+
+#define CKF_RW_SESSION         (1 << 1)
+#define CKF_SERIAL_SESSION     (1 << 2)
+
+
+typedef unsigned long ck_object_handle_t;
+
+
+typedef unsigned long ck_object_class_t;
+
+#define CKO_DATA               (0)
+#define CKO_CERTIFICATE                (1)
+#define CKO_PUBLIC_KEY         (2)
+#define CKO_PRIVATE_KEY                (3)
+#define CKO_SECRET_KEY         (4)
+#define CKO_HW_FEATURE         (5)
+#define CKO_DOMAIN_PARAMETERS  (6)
+#define CKO_MECHANISM          (7)
+#define CKO_VENDOR_DEFINED     ((unsigned long) (1 << 31))
+
+
+typedef unsigned long ck_hw_feature_type_t;
+
+#define CKH_MONOTONIC_COUNTER  (1)
+#define CKH_CLOCK              (2)
+#define CKH_USER_INTERFACE     (3)
+#define CKH_VENDOR_DEFINED     ((unsigned long) (1 << 31))
+
+
+typedef unsigned long ck_key_type_t;
+
+#define CKK_RSA                        (0)
+#define CKK_DSA                        (1)
+#define CKK_DH                 (2)
+#define CKK_ECDSA              (3)
+#define CKK_EC                 (3)
+#define CKK_X9_42_DH           (4)
+#define CKK_KEA                        (5)
+#define CKK_GENERIC_SECRET     (0x10)
+#define CKK_RC2                        (0x11)
+#define CKK_RC4                        (0x12)
+#define CKK_DES                        (0x13)
+#define CKK_DES2               (0x14)
+#define CKK_DES3               (0x15)
+#define CKK_CAST               (0x16)
+#define CKK_CAST3              (0x17)
+#define CKK_CAST128            (0x18)
+#define CKK_RC5                        (0x19)
+#define CKK_IDEA               (0x1a)
+#define CKK_SKIPJACK           (0x1b)
+#define CKK_BATON              (0x1c)
+#define CKK_JUNIPER            (0x1d)
+#define CKK_CDMF               (0x1e)
+#define CKK_AES                        (0x1f)
+#define CKK_BLOWFISH           (0x20)
+#define CKK_TWOFISH            (0x21)
+#define CKK_VENDOR_DEFINED     ((unsigned long) (1 << 31))
+
+
+typedef unsigned long ck_certificate_type_t;
+
+#define CKC_X_509              (0)
+#define CKC_X_509_ATTR_CERT    (1)
+#define CKC_WTLS               (2)
+#define CKC_VENDOR_DEFINED     ((unsigned long) (1 << 31))
+
+
+typedef unsigned long ck_attribute_type_t;
+
+#define CKA_CLASS                      (0)
+#define CKA_TOKEN                      (1)
+#define CKA_PRIVATE                    (2)
+#define CKA_LABEL                      (3)
+#define CKA_APPLICATION                        (0x10)
+#define CKA_VALUE                      (0x11)
+#define CKA_OBJECT_ID                  (0x12)
+#define CKA_CERTIFICATE_TYPE           (0x80)
+#define CKA_ISSUER                     (0x81)
+#define CKA_SERIAL_NUMBER              (0x82)
+#define CKA_AC_ISSUER                  (0x83)
+#define CKA_OWNER                      (0x84)
+#define CKA_ATTR_TYPES                 (0x85)
+#define CKA_TRUSTED                    (0x86)
+#define CKA_CERTIFICATE_CATEGORY       (0x87)
+#define CKA_JAVA_MIDP_SECURITY_DOMAIN  (0x88)
+#define CKA_URL                                (0x89)
+#define CKA_HASH_OF_SUBJECT_PUBLIC_KEY (0x8a)
+#define CKA_HASH_OF_ISSUER_PUBLIC_KEY  (0x8b)
+#define CKA_CHECK_VALUE                        (0x90)
+#define CKA_KEY_TYPE                   (0x100)
+#define CKA_SUBJECT                    (0x101)
+#define CKA_ID                         (0x102)
+#define CKA_SENSITIVE                  (0x103)
+#define CKA_ENCRYPT                    (0x104)
+#define CKA_DECRYPT                    (0x105)
+#define CKA_WRAP                       (0x106)
+#define CKA_UNWRAP                     (0x107)
+#define CKA_SIGN                       (0x108)
+#define CKA_SIGN_RECOVER               (0x109)
+#define CKA_VERIFY                     (0x10a)
+#define CKA_VERIFY_RECOVER             (0x10b)
+#define CKA_DERIVE                     (0x10c)
+#define CKA_START_DATE                 (0x110)
+#define CKA_END_DATE                   (0x111)
+#define CKA_MODULUS                    (0x120)
+#define CKA_MODULUS_BITS               (0x121)
+#define CKA_PUBLIC_EXPONENT            (0x122)
+#define CKA_PRIVATE_EXPONENT           (0x123)
+#define CKA_PRIME_1                    (0x124)
+#define CKA_PRIME_2                    (0x125)
+#define CKA_EXPONENT_1                 (0x126)
+#define CKA_EXPONENT_2                 (0x127)
+#define CKA_COEFFICIENT                        (0x128)
+#define CKA_PRIME                      (0x130)
+#define CKA_SUBPRIME                   (0x131)
+#define CKA_BASE                       (0x132)
+#define CKA_PRIME_BITS                 (0x133)
+#define CKA_SUB_PRIME_BITS             (0x134)
+#define CKA_VALUE_BITS                 (0x160)
+#define CKA_VALUE_LEN                  (0x161)
+#define CKA_EXTRACTABLE                        (0x162)
+#define CKA_LOCAL                      (0x163)
+#define CKA_NEVER_EXTRACTABLE          (0x164)
+#define CKA_ALWAYS_SENSITIVE           (0x165)
+#define CKA_KEY_GEN_MECHANISM          (0x166)
+#define CKA_MODIFIABLE                 (0x170)
+#define CKA_ECDSA_PARAMS               (0x180)
+#define CKA_EC_PARAMS                  (0x180)
+#define CKA_EC_POINT                   (0x181)
+#define CKA_SECONDARY_AUTH             (0x200)
+#define CKA_AUTH_PIN_FLAGS             (0x201)
+#define CKA_ALWAYS_AUTHENTICATE                (0x202)
+#define CKA_WRAP_WITH_TRUSTED          (0x210)
+#define CKA_HW_FEATURE_TYPE            (0x300)
+#define CKA_RESET_ON_INIT              (0x301)
+#define CKA_HAS_RESET                  (0x302)
+#define CKA_PIXEL_X                    (0x400)
+#define CKA_PIXEL_Y                    (0x401)
+#define CKA_RESOLUTION                 (0x402)
+#define CKA_CHAR_ROWS                  (0x403)
+#define CKA_CHAR_COLUMNS               (0x404)
+#define CKA_COLOR                      (0x405)
+#define CKA_BITS_PER_PIXEL             (0x406)
+#define CKA_CHAR_SETS                  (0x480)
+#define CKA_ENCODING_METHODS           (0x481)
+#define CKA_MIME_TYPES                 (0x482)
+#define CKA_MECHANISM_TYPE             (0x500)
+#define CKA_REQUIRED_CMS_ATTRIBUTES    (0x501)
+#define CKA_DEFAULT_CMS_ATTRIBUTES     (0x502)
+#define CKA_SUPPORTED_CMS_ATTRIBUTES   (0x503)
+#define CKA_WRAP_TEMPLATE              (CKF_ARRAY_ATTRIBUTE | 0x211)
+#define CKA_UNWRAP_TEMPLATE            (CKF_ARRAY_ATTRIBUTE | 0x212)
+#define CKA_ALLOWED_MECHANISMS         (CKF_ARRAY_ATTRIBUTE | 0x600)
+#define CKA_VENDOR_DEFINED             ((unsigned long) (1 << 31))
+
+
+struct ck_attribute
+{
+  ck_attribute_type_t type;
+  void *value;
+  unsigned long value_len;
+};
+
+
+struct ck_date
+{
+  unsigned char year[4];
+  unsigned char month[2];
+  unsigned char day[2];
+};
+
+
+typedef unsigned long ck_mechanism_type_t;
+
+#define CKM_RSA_PKCS_KEY_PAIR_GEN      (0)
+#define CKM_RSA_PKCS                   (1)
+#define CKM_RSA_9796                   (2)
+#define CKM_RSA_X_509                  (3)
+#define CKM_MD2_RSA_PKCS               (4)
+#define CKM_MD5_RSA_PKCS               (5)
+#define CKM_SHA1_RSA_PKCS              (6)
+#define CKM_RIPEMD128_RSA_PKCS         (7)
+#define CKM_RIPEMD160_RSA_PKCS         (8)
+#define CKM_RSA_PKCS_OAEP              (9)
+#define CKM_RSA_X9_31_KEY_PAIR_GEN     (0xa)
+#define CKM_RSA_X9_31                  (0xb)
+#define CKM_SHA1_RSA_X9_31             (0xc)
+#define CKM_RSA_PKCS_PSS               (0xd)
+#define CKM_SHA1_RSA_PKCS_PSS          (0xe)
+#define CKM_DSA_KEY_PAIR_GEN           (0x10)
+#define        CKM_DSA                         (0x11)
+#define CKM_DSA_SHA1                   (0x12)
+#define CKM_DH_PKCS_KEY_PAIR_GEN       (0x20)
+#define CKM_DH_PKCS_DERIVE             (0x21)
+#define        CKM_X9_42_DH_KEY_PAIR_GEN       (0x30)
+#define CKM_X9_42_DH_DERIVE            (0x31)
+#define CKM_X9_42_DH_HYBRID_DERIVE     (0x32)
+#define CKM_X9_42_MQV_DERIVE           (0x33)
+#define CKM_SHA256_RSA_PKCS            (0x40)
+#define CKM_SHA384_RSA_PKCS            (0x41)
+#define CKM_SHA512_RSA_PKCS            (0x42)
+#define CKM_SHA256_RSA_PKCS_PSS                (0x43)
+#define CKM_SHA384_RSA_PKCS_PSS                (0x44)
+#define CKM_SHA512_RSA_PKCS_PSS                (0x45)
+#define CKM_RC2_KEY_GEN                        (0x100)
+#define CKM_RC2_ECB                    (0x101)
+#define        CKM_RC2_CBC                     (0x102)
+#define        CKM_RC2_MAC                     (0x103)
+#define CKM_RC2_MAC_GENERAL            (0x104)
+#define CKM_RC2_CBC_PAD                        (0x105)
+#define CKM_RC4_KEY_GEN                        (0x110)
+#define CKM_RC4                                (0x111)
+#define CKM_DES_KEY_GEN                        (0x120)
+#define CKM_DES_ECB                    (0x121)
+#define CKM_DES_CBC                    (0x122)
+#define CKM_DES_MAC                    (0x123)
+#define CKM_DES_MAC_GENERAL            (0x124)
+#define CKM_DES_CBC_PAD                        (0x125)
+#define CKM_DES2_KEY_GEN               (0x130)
+#define CKM_DES3_KEY_GEN               (0x131)
+#define CKM_DES3_ECB                   (0x132)
+#define CKM_DES3_CBC                   (0x133)
+#define CKM_DES3_MAC                   (0x134)
+#define CKM_DES3_MAC_GENERAL           (0x135)
+#define CKM_DES3_CBC_PAD               (0x136)
+#define CKM_CDMF_KEY_GEN               (0x140)
+#define CKM_CDMF_ECB                   (0x141)
+#define CKM_CDMF_CBC                   (0x142)
+#define CKM_CDMF_MAC                   (0x143)
+#define CKM_CDMF_MAC_GENERAL           (0x144)
+#define CKM_CDMF_CBC_PAD               (0x145)
+#define CKM_MD2                                (0x200)
+#define CKM_MD2_HMAC                   (0x201)
+#define CKM_MD2_HMAC_GENERAL           (0x202)
+#define CKM_MD5                                (0x210)
+#define CKM_MD5_HMAC                   (0x211)
+#define CKM_MD5_HMAC_GENERAL           (0x212)
+#define CKM_SHA_1                      (0x220)
+#define CKM_SHA_1_HMAC                 (0x221)
+#define CKM_SHA_1_HMAC_GENERAL         (0x222)
+#define CKM_RIPEMD128                  (0x230)
+#define CKM_RIPEMD128_HMAC             (0x231)
+#define CKM_RIPEMD128_HMAC_GENERAL     (0x232)
+#define CKM_RIPEMD160                  (0x240)
+#define CKM_RIPEMD160_HMAC             (0x241)
+#define CKM_RIPEMD160_HMAC_GENERAL     (0x242)
+#define CKM_SHA256                     (0x250)
+#define CKM_SHA256_HMAC                        (0x251)
+#define CKM_SHA256_HMAC_GENERAL                (0x252)
+#define CKM_SHA384                     (0x260)
+#define CKM_SHA384_HMAC                        (0x261)
+#define CKM_SHA384_HMAC_GENERAL                (0x262)
+#define CKM_SHA512                     (0x270)
+#define CKM_SHA512_HMAC                        (0x271)
+#define CKM_SHA512_HMAC_GENERAL                (0x272)
+#define CKM_CAST_KEY_GEN               (0x300)
+#define CKM_CAST_ECB                   (0x301)
+#define CKM_CAST_CBC                   (0x302)
+#define CKM_CAST_MAC                   (0x303)
+#define CKM_CAST_MAC_GENERAL           (0x304)
+#define CKM_CAST_CBC_PAD               (0x305)
+#define CKM_CAST3_KEY_GEN              (0x310)
+#define CKM_CAST3_ECB                  (0x311)
+#define CKM_CAST3_CBC                  (0x312)
+#define CKM_CAST3_MAC                  (0x313)
+#define CKM_CAST3_MAC_GENERAL          (0x314)
+#define CKM_CAST3_CBC_PAD              (0x315)
+#define CKM_CAST5_KEY_GEN              (0x320)
+#define CKM_CAST128_KEY_GEN            (0x320)
+#define CKM_CAST5_ECB                  (0x321)
+#define CKM_CAST128_ECB                        (0x321)
+#define CKM_CAST5_CBC                  (0x322)
+#define CKM_CAST128_CBC                        (0x322)
+#define CKM_CAST5_MAC                  (0x323)
+#define        CKM_CAST128_MAC                 (0x323)
+#define CKM_CAST5_MAC_GENERAL          (0x324)
+#define CKM_CAST128_MAC_GENERAL                (0x324)
+#define CKM_CAST5_CBC_PAD              (0x325)
+#define CKM_CAST128_CBC_PAD            (0x325)
+#define CKM_RC5_KEY_GEN                        (0x330)
+#define CKM_RC5_ECB                    (0x331)
+#define CKM_RC5_CBC                    (0x332)
+#define CKM_RC5_MAC                    (0x333)
+#define CKM_RC5_MAC_GENERAL            (0x334)
+#define CKM_RC5_CBC_PAD                        (0x335)
+#define CKM_IDEA_KEY_GEN               (0x340)
+#define CKM_IDEA_ECB                   (0x341)
+#define        CKM_IDEA_CBC                    (0x342)
+#define CKM_IDEA_MAC                   (0x343)
+#define CKM_IDEA_MAC_GENERAL           (0x344)
+#define CKM_IDEA_CBC_PAD               (0x345)
+#define CKM_GENERIC_SECRET_KEY_GEN     (0x350)
+#define CKM_CONCATENATE_BASE_AND_KEY   (0x360)
+#define CKM_CONCATENATE_BASE_AND_DATA  (0x362)
+#define CKM_CONCATENATE_DATA_AND_BASE  (0x363)
+#define CKM_XOR_BASE_AND_DATA          (0x364)
+#define CKM_EXTRACT_KEY_FROM_KEY       (0x365)
+#define CKM_SSL3_PRE_MASTER_KEY_GEN    (0x370)
+#define CKM_SSL3_MASTER_KEY_DERIVE     (0x371)
+#define CKM_SSL3_KEY_AND_MAC_DERIVE    (0x372)
+#define CKM_SSL3_MASTER_KEY_DERIVE_DH  (0x373)
+#define CKM_TLS_PRE_MASTER_KEY_GEN     (0x374)
+#define CKM_TLS_MASTER_KEY_DERIVE      (0x375)
+#define CKM_TLS_KEY_AND_MAC_DERIVE     (0x376)
+#define CKM_TLS_MASTER_KEY_DERIVE_DH   (0x377)
+#define CKM_SSL3_MD5_MAC               (0x380)
+#define CKM_SSL3_SHA1_MAC              (0x381)
+#define CKM_MD5_KEY_DERIVATION         (0x390)
+#define CKM_MD2_KEY_DERIVATION         (0x391)
+#define CKM_SHA1_KEY_DERIVATION                (0x392)
+#define CKM_PBE_MD2_DES_CBC            (0x3a0)
+#define CKM_PBE_MD5_DES_CBC            (0x3a1)
+#define CKM_PBE_MD5_CAST_CBC           (0x3a2)
+#define CKM_PBE_MD5_CAST3_CBC          (0x3a3)
+#define CKM_PBE_MD5_CAST5_CBC          (0x3a4)
+#define CKM_PBE_MD5_CAST128_CBC                (0x3a4)
+#define CKM_PBE_SHA1_CAST5_CBC         (0x3a5)
+#define CKM_PBE_SHA1_CAST128_CBC       (0x3a5)
+#define CKM_PBE_SHA1_RC4_128           (0x3a6)
+#define CKM_PBE_SHA1_RC4_40            (0x3a7)
+#define CKM_PBE_SHA1_DES3_EDE_CBC      (0x3a8)
+#define CKM_PBE_SHA1_DES2_EDE_CBC      (0x3a9)
+#define CKM_PBE_SHA1_RC2_128_CBC       (0x3aa)
+#define CKM_PBE_SHA1_RC2_40_CBC                (0x3ab)
+#define CKM_PKCS5_PBKD2                        (0x3b0)
+#define CKM_PBA_SHA1_WITH_SHA1_HMAC    (0x3c0)
+#define CKM_KEY_WRAP_LYNKS             (0x400)
+#define CKM_KEY_WRAP_SET_OAEP          (0x401)
+#define CKM_SKIPJACK_KEY_GEN           (0x1000)
+#define CKM_SKIPJACK_ECB64             (0x1001)
+#define CKM_SKIPJACK_CBC64             (0x1002)
+#define CKM_SKIPJACK_OFB64             (0x1003)
+#define CKM_SKIPJACK_CFB64             (0x1004)
+#define CKM_SKIPJACK_CFB32             (0x1005)
+#define CKM_SKIPJACK_CFB16             (0x1006)
+#define CKM_SKIPJACK_CFB8              (0x1007)
+#define CKM_SKIPJACK_WRAP              (0x1008)
+#define CKM_SKIPJACK_PRIVATE_WRAP      (0x1009)
+#define CKM_SKIPJACK_RELAYX            (0x100a)
+#define CKM_KEA_KEY_PAIR_GEN           (0x1010)
+#define CKM_KEA_KEY_DERIVE             (0x1011)
+#define CKM_FORTEZZA_TIMESTAMP         (0x1020)
+#define CKM_BATON_KEY_GEN              (0x1030)
+#define CKM_BATON_ECB128               (0x1031)
+#define CKM_BATON_ECB96                        (0x1032)
+#define CKM_BATON_CBC128               (0x1033)
+#define CKM_BATON_COUNTER              (0x1034)
+#define CKM_BATON_SHUFFLE              (0x1035)
+#define CKM_BATON_WRAP                 (0x1036)
+#define CKM_ECDSA_KEY_PAIR_GEN         (0x1040)
+#define CKM_EC_KEY_PAIR_GEN            (0x1040)
+#define CKM_ECDSA                      (0x1041)
+#define CKM_ECDSA_SHA1                 (0x1042)
+#define CKM_ECDH1_DERIVE               (0x1050)
+#define CKM_ECDH1_COFACTOR_DERIVE      (0x1051)
+#define CKM_ECMQV_DERIVE               (0x1052)
+#define CKM_JUNIPER_KEY_GEN            (0x1060)
+#define CKM_JUNIPER_ECB128             (0x1061)
+#define CKM_JUNIPER_CBC128             (0x1062)
+#define CKM_JUNIPER_COUNTER            (0x1063)
+#define CKM_JUNIPER_SHUFFLE            (0x1064)
+#define CKM_JUNIPER_WRAP               (0x1065)
+#define CKM_FASTHASH                   (0x1070)
+#define CKM_AES_KEY_GEN                        (0x1080)
+#define CKM_AES_ECB                    (0x1081)
+#define CKM_AES_CBC                    (0x1082)
+#define CKM_AES_MAC                    (0x1083)
+#define CKM_AES_MAC_GENERAL            (0x1084)
+#define CKM_AES_CBC_PAD                        (0x1085)
+#define CKM_DSA_PARAMETER_GEN          (0x2000)
+#define CKM_DH_PKCS_PARAMETER_GEN      (0x2001)
+#define CKM_X9_42_DH_PARAMETER_GEN     (0x2002)
+#define CKM_VENDOR_DEFINED             ((unsigned long) (1 << 31))
+
+
+struct ck_mechanism
+{
+  ck_mechanism_type_t mechanism;
+  void *parameter;
+  unsigned long parameter_len;
+};
+
+
+struct ck_mechanism_info
+{
+  unsigned long min_key_size;
+  unsigned long max_key_size;
+  ck_flags_t flags;
+};
+
+#define CKF_HW                 (1 << 0)
+#define CKF_ENCRYPT            (1 << 8)
+#define CKF_DECRYPT            (1 << 9)
+#define CKF_DIGEST             (1 << 10)
+#define CKF_SIGN               (1 << 11)
+#define CKF_SIGN_RECOVER       (1 << 12)
+#define CKF_VERIFY             (1 << 13)
+#define CKF_VERIFY_RECOVER     (1 << 14)
+#define CKF_GENERATE           (1 << 15)
+#define CKF_GENERATE_KEY_PAIR  (1 << 16)
+#define CKF_WRAP               (1 << 17)
+#define CKF_UNWRAP             (1 << 18)
+#define CKF_DERIVE             (1 << 19)
+#define CKF_EXTENSION          ((unsigned long) (1 << 31))
+
+
+/* Flags for C_WaitForSlotEvent.  */
+#define CKF_DONT_BLOCK                         (1)
+
+
+typedef unsigned long ck_rv_t;
+
+
+typedef ck_rv_t (*ck_notify_t) (ck_session_handle_t session,
+                               ck_notification_t event, void *application);
+
+/* Forward reference.  */
+struct ck_function_list;
+
+#define _CK_DECLARE_FUNCTION(name, args)       \
+typedef ck_rv_t (*CK_ ## name) args;           \
+ck_rv_t CK_SPEC name args
+
+_CK_DECLARE_FUNCTION (C_Initialize, (void *init_args));
+_CK_DECLARE_FUNCTION (C_Finalize, (void *reserved));
+_CK_DECLARE_FUNCTION (C_GetInfo, (struct ck_info *info));
+_CK_DECLARE_FUNCTION (C_GetFunctionList,
+                     (struct ck_function_list **function_list));
+
+_CK_DECLARE_FUNCTION (C_GetSlotList,
+                     (unsigned char token_present, ck_slot_id_t *slot_list,
+                      unsigned long *count));
+_CK_DECLARE_FUNCTION (C_GetSlotInfo,
+                     (ck_slot_id_t slot_id, struct ck_slot_info *info));
+_CK_DECLARE_FUNCTION (C_GetTokenInfo,
+                     (ck_slot_id_t slot_id, struct ck_token_info *info));
+_CK_DECLARE_FUNCTION (C_WaitForSlotEvent,
+                     (ck_flags_t flags, ck_slot_id_t *slot, void *reserved));
+_CK_DECLARE_FUNCTION (C_GetMechanismList,
+                     (ck_slot_id_t slot_id,
+                      ck_mechanism_type_t *mechanism_list,
+                      unsigned long *count));
+_CK_DECLARE_FUNCTION (C_GetMechanismInfo,
+                     (ck_slot_id_t slot_id, ck_mechanism_type_t type,
+                      struct ck_mechanism_info *info));
+_CK_DECLARE_FUNCTION (C_InitToken,
+                     (ck_slot_id_t slot_id, unsigned char *pin,
+                      unsigned long pin_len, unsigned char *label));
+_CK_DECLARE_FUNCTION (C_InitPIN,
+                     (ck_session_handle_t session, unsigned char *pin,
+                      unsigned long pin_len));
+_CK_DECLARE_FUNCTION (C_SetPIN,
+                     (ck_session_handle_t session, unsigned char *old_pin,
+                      unsigned long old_len, unsigned char *new_pin,
+                      unsigned long new_len));
+
+_CK_DECLARE_FUNCTION (C_OpenSession,
+                     (ck_slot_id_t slot_id, ck_flags_t flags,
+                      void *application, ck_notify_t notify,
+                      ck_session_handle_t *session));
+_CK_DECLARE_FUNCTION (C_CloseSession, (ck_session_handle_t session));
+_CK_DECLARE_FUNCTION (C_CloseAllSessions, (ck_slot_id_t slot_id));
+_CK_DECLARE_FUNCTION (C_GetSessionInfo,
+                     (ck_session_handle_t session,
+                      struct ck_session_info *info));
+_CK_DECLARE_FUNCTION (C_GetOperationState,
+                     (ck_session_handle_t session,
+                      unsigned char *operation_state,
+                      unsigned long *operation_state_len));
+_CK_DECLARE_FUNCTION (C_SetOperationState,
+                     (ck_session_handle_t session,
+                      unsigned char *operation_state,
+                      unsigned long operation_state_len,
+                      ck_object_handle_t encryption_key,
+                      ck_object_handle_t authentiation_key));
+_CK_DECLARE_FUNCTION (C_Login,
+                     (ck_session_handle_t session, ck_user_type_t user_type,
+                      unsigned char *pin, unsigned long pin_len));
+_CK_DECLARE_FUNCTION (C_Logout, (ck_session_handle_t session));
+
+_CK_DECLARE_FUNCTION (C_CreateObject,
+                     (ck_session_handle_t session,
+                      struct ck_attribute *templ,
+                      unsigned long count, ck_object_handle_t *object));
+_CK_DECLARE_FUNCTION (C_CopyObject,
+                     (ck_session_handle_t session, ck_object_handle_t object,
+                      struct ck_attribute *templ, unsigned long count,
+                      ck_object_handle_t *new_object));
+_CK_DECLARE_FUNCTION (C_DestroyObject,
+                     (ck_session_handle_t session,
+                      ck_object_handle_t object));
+_CK_DECLARE_FUNCTION (C_GetObjectSize,
+                     (ck_session_handle_t session,
+                      ck_object_handle_t object,
+                      unsigned long *size));
+_CK_DECLARE_FUNCTION (C_GetAttributeValue,
+                     (ck_session_handle_t session,
+                      ck_object_handle_t object,
+                      struct ck_attribute *templ,
+                      unsigned long count));
+_CK_DECLARE_FUNCTION (C_SetAttributeValue,
+                     (ck_session_handle_t session,
+                      ck_object_handle_t object,
+                      struct ck_attribute *templ,
+                      unsigned long count));
+_CK_DECLARE_FUNCTION (C_FindObjectsInit,
+                     (ck_session_handle_t session,
+                      struct ck_attribute *templ,
+                      unsigned long count));
+_CK_DECLARE_FUNCTION (C_FindObjects,
+                     (ck_session_handle_t session,
+                      ck_object_handle_t *object,
+                      unsigned long max_object_count,
+                      unsigned long *object_count));
+_CK_DECLARE_FUNCTION (C_FindObjectsFinal,
+                     (ck_session_handle_t session));
+
+_CK_DECLARE_FUNCTION (C_EncryptInit,
+                     (ck_session_handle_t session,
+                      struct ck_mechanism *mechanism,
+                      ck_object_handle_t key));
+_CK_DECLARE_FUNCTION (C_Encrypt,
+                     (ck_session_handle_t session,
+                      unsigned char *data, unsigned long data_len,
+                      unsigned char *encrypted_data,
+                      unsigned long *encrypted_data_len));
+_CK_DECLARE_FUNCTION (C_EncryptUpdate,
+                     (ck_session_handle_t session,
+                      unsigned char *part, unsigned long part_len,
+                      unsigned char *encrypted_part,
+                      unsigned long *encrypted_part_len));
+_CK_DECLARE_FUNCTION (C_EncryptFinal,
+                     (ck_session_handle_t session,
+                      unsigned char *last_encrypted_part,
+                      unsigned long *last_encrypted_part_len));
+
+_CK_DECLARE_FUNCTION (C_DecryptInit,
+                     (ck_session_handle_t session,
+                      struct ck_mechanism *mechanism,
+                      ck_object_handle_t key));
+_CK_DECLARE_FUNCTION (C_Decrypt,
+                     (ck_session_handle_t session,
+                      unsigned char *encrypted_data,
+                      unsigned long encrypted_data_len,
+                      unsigned char *data, unsigned long *data_len));
+_CK_DECLARE_FUNCTION (C_DecryptUpdate,
+                     (ck_session_handle_t session,
+                      unsigned char *encrypted_part,
+                      unsigned long encrypted_part_len,
+                      unsigned char *part, unsigned long *part_len));
+_CK_DECLARE_FUNCTION (C_DecryptFinal,
+                     (ck_session_handle_t session,
+                      unsigned char *last_part,
+                      unsigned long *last_part_len));
+
+_CK_DECLARE_FUNCTION (C_DigestInit,
+                     (ck_session_handle_t session,
+                      struct ck_mechanism *mechanism));
+_CK_DECLARE_FUNCTION (C_Digest,
+                     (ck_session_handle_t session,
+                      unsigned char *data, unsigned long data_len,
+                      unsigned char *digest,
+                      unsigned long *digest_len));
+_CK_DECLARE_FUNCTION (C_DigestUpdate,
+                     (ck_session_handle_t session,
+                      unsigned char *part, unsigned long part_len));
+_CK_DECLARE_FUNCTION (C_DigestKey,
+                     (ck_session_handle_t session, ck_object_handle_t key));
+_CK_DECLARE_FUNCTION (C_DigestFinal,
+                     (ck_session_handle_t session,
+                      unsigned char *digest,
+                      unsigned long *digest_len));
+
+_CK_DECLARE_FUNCTION (C_SignInit,
+                     (ck_session_handle_t session,
+                      struct ck_mechanism *mechanism,
+                      ck_object_handle_t key));
+_CK_DECLARE_FUNCTION (C_Sign,
+                     (ck_session_handle_t session,
+                      unsigned char *data, unsigned long data_len,
+                      unsigned char *signature,
+                      unsigned long *signature_len));
+_CK_DECLARE_FUNCTION (C_SignUpdate,
+                     (ck_session_handle_t session,
+                      unsigned char *part, unsigned long part_len));
+_CK_DECLARE_FUNCTION (C_SignFinal,
+                     (ck_session_handle_t session,
+                      unsigned char *signature,
+                      unsigned long *signature_len));
+_CK_DECLARE_FUNCTION (C_SignRecoverInit,
+                     (ck_session_handle_t session,
+                      struct ck_mechanism *mechanism,
+                      ck_object_handle_t key));
+_CK_DECLARE_FUNCTION (C_SignRecover,
+                     (ck_session_handle_t session,
+                      unsigned char *data, unsigned long data_len,
+                      unsigned char *signature,
+                      unsigned long *signature_len));
+
+_CK_DECLARE_FUNCTION (C_VerifyInit,
+                     (ck_session_handle_t session,
+                      struct ck_mechanism *mechanism,
+                      ck_object_handle_t key));
+_CK_DECLARE_FUNCTION (C_Verify,
+                     (ck_session_handle_t session,
+                      unsigned char *data, unsigned long data_len,
+                      unsigned char *signature,
+                      unsigned long signature_len));
+_CK_DECLARE_FUNCTION (C_VerifyUpdate,
+                     (ck_session_handle_t session,
+                      unsigned char *part, unsigned long part_len));
+_CK_DECLARE_FUNCTION (C_VerifyFinal,
+                     (ck_session_handle_t session,
+                      unsigned char *signature,
+                      unsigned long signature_len));
+_CK_DECLARE_FUNCTION (C_VerifyRecoverInit,
+                     (ck_session_handle_t session,
+                      struct ck_mechanism *mechanism,
+                      ck_object_handle_t key));
+_CK_DECLARE_FUNCTION (C_VerifyRecover,
+                     (ck_session_handle_t session,
+                      unsigned char *signature,
+                      unsigned long signature_len,
+                      unsigned char *data,
+                      unsigned long *data_len));
+
+_CK_DECLARE_FUNCTION (C_DigestEncryptUpdate,
+                     (ck_session_handle_t session,
+                      unsigned char *part, unsigned long part_len,
+                      unsigned char *encrypted_part,
+                      unsigned long *encrypted_part_len));
+_CK_DECLARE_FUNCTION (C_DecryptDigestUpdate,
+                     (ck_session_handle_t session,
+                      unsigned char *encrypted_part,
+                      unsigned long encrypted_part_len,
+                      unsigned char *part,
+                      unsigned long *part_len));
+_CK_DECLARE_FUNCTION (C_SignEncryptUpdate,
+                     (ck_session_handle_t session,
+                      unsigned char *part, unsigned long part_len,
+                      unsigned char *encrypted_part,
+                      unsigned long *encrypted_part_len));
+_CK_DECLARE_FUNCTION (C_DecryptVerifyUpdate,
+                     (ck_session_handle_t session,
+                      unsigned char *encrypted_part,
+                      unsigned long encrypted_part_len,
+                      unsigned char *part,
+                      unsigned long *part_len));
+
+_CK_DECLARE_FUNCTION (C_GenerateKey,
+                     (ck_session_handle_t session,
+                      struct ck_mechanism *mechanism,
+                      struct ck_attribute *templ,
+                      unsigned long count,
+                      ck_object_handle_t *key));
+_CK_DECLARE_FUNCTION (C_GenerateKeyPair,
+                     (ck_session_handle_t session,
+                      struct ck_mechanism *mechanism,
+                      struct ck_attribute *public_key_template,
+                      unsigned long public_key_attribute_count,
+                      struct ck_attribute *private_key_template,
+                      unsigned long private_key_attribute_count,
+                      ck_object_handle_t *public_key,
+                      ck_object_handle_t *private_key));
+_CK_DECLARE_FUNCTION (C_WrapKey,
+                     (ck_session_handle_t session,
+                      struct ck_mechanism *mechanism,
+                      ck_object_handle_t wrapping_key,
+                      ck_object_handle_t key,
+                      unsigned char *wrapped_key,
+                      unsigned long *wrapped_key_len));
+_CK_DECLARE_FUNCTION (C_UnwrapKey,
+                     (ck_session_handle_t session,
+                      struct ck_mechanism *mechanism,
+                      ck_object_handle_t unwrapping_key,
+                      unsigned char *wrapped_key,
+                      unsigned long wrapped_key_len,
+                      struct ck_attribute *templ,
+                      unsigned long attribute_count,
+                      ck_object_handle_t *key));
+_CK_DECLARE_FUNCTION (C_DeriveKey,
+                     (ck_session_handle_t session,
+                      struct ck_mechanism *mechanism,
+                      ck_object_handle_t base_key,
+                      struct ck_attribute *templ,
+                      unsigned long attribute_count,
+                      ck_object_handle_t *key));
+
+_CK_DECLARE_FUNCTION (C_SeedRandom,
+                     (ck_session_handle_t session, unsigned char *seed,
+                      unsigned long seed_len));
+_CK_DECLARE_FUNCTION (C_GenerateRandom,
+                     (ck_session_handle_t session,
+                      unsigned char *random_data,
+                      unsigned long random_len));
+
+_CK_DECLARE_FUNCTION (C_GetFunctionStatus, (ck_session_handle_t session));
+_CK_DECLARE_FUNCTION (C_CancelFunction, (ck_session_handle_t session));
+
+
+struct ck_function_list
+{
+  struct ck_version version;
+  CK_C_Initialize C_Initialize;
+  CK_C_Finalize C_Finalize;
+  CK_C_GetInfo C_GetInfo;
+  CK_C_GetFunctionList C_GetFunctionList;
+  CK_C_GetSlotList C_GetSlotList;
+  CK_C_GetSlotInfo C_GetSlotInfo;
+  CK_C_GetTokenInfo C_GetTokenInfo;
+  CK_C_GetMechanismList C_GetMechanismList;
+  CK_C_GetMechanismInfo C_GetMechanismInfo;
+  CK_C_InitToken C_InitToken;
+  CK_C_InitPIN C_InitPIN;
+  CK_C_SetPIN C_SetPIN;
+  CK_C_OpenSession C_OpenSession;
+  CK_C_CloseSession C_CloseSession;
+  CK_C_CloseAllSessions C_CloseAllSessions;
+  CK_C_GetSessionInfo C_GetSessionInfo;
+  CK_C_GetOperationState C_GetOperationState;
+  CK_C_SetOperationState C_SetOperationState;
+  CK_C_Login C_Login;
+  CK_C_Logout C_Logout;
+  CK_C_CreateObject C_CreateObject;
+  CK_C_CopyObject C_CopyObject;
+  CK_C_DestroyObject C_DestroyObject;
+  CK_C_GetObjectSize C_GetObjectSize;
+  CK_C_GetAttributeValue C_GetAttributeValue;
+  CK_C_SetAttributeValue C_SetAttributeValue;
+  CK_C_FindObjectsInit C_FindObjectsInit;
+  CK_C_FindObjects C_FindObjects;
+  CK_C_FindObjectsFinal C_FindObjectsFinal;
+  CK_C_EncryptInit C_EncryptInit;
+  CK_C_Encrypt C_Encrypt;
+  CK_C_EncryptUpdate C_EncryptUpdate;
+  CK_C_EncryptFinal C_EncryptFinal;
+  CK_C_DecryptInit C_DecryptInit;
+  CK_C_Decrypt C_Decrypt;
+  CK_C_DecryptUpdate C_DecryptUpdate;
+  CK_C_DecryptFinal C_DecryptFinal;
+  CK_C_DigestInit C_DigestInit;
+  CK_C_Digest C_Digest;
+  CK_C_DigestUpdate C_DigestUpdate;
+  CK_C_DigestKey C_DigestKey;
+  CK_C_DigestFinal C_DigestFinal;
+  CK_C_SignInit C_SignInit;
+  CK_C_Sign C_Sign;
+  CK_C_SignUpdate C_SignUpdate;
+  CK_C_SignFinal C_SignFinal;
+  CK_C_SignRecoverInit C_SignRecoverInit;
+  CK_C_SignRecover C_SignRecover;
+  CK_C_VerifyInit C_VerifyInit;
+  CK_C_Verify C_Verify;
+  CK_C_VerifyUpdate C_VerifyUpdate;
+  CK_C_VerifyFinal C_VerifyFinal;
+  CK_C_VerifyRecoverInit C_VerifyRecoverInit;
+  CK_C_VerifyRecover C_VerifyRecover;
+  CK_C_DigestEncryptUpdate C_DigestEncryptUpdate;
+  CK_C_DecryptDigestUpdate C_DecryptDigestUpdate;
+  CK_C_SignEncryptUpdate C_SignEncryptUpdate;
+  CK_C_DecryptVerifyUpdate C_DecryptVerifyUpdate;
+  CK_C_GenerateKey C_GenerateKey;
+  CK_C_GenerateKeyPair C_GenerateKeyPair;
+  CK_C_WrapKey C_WrapKey;
+  CK_C_UnwrapKey C_UnwrapKey;
+  CK_C_DeriveKey C_DeriveKey;
+  CK_C_SeedRandom C_SeedRandom;
+  CK_C_GenerateRandom C_GenerateRandom;
+  CK_C_GetFunctionStatus C_GetFunctionStatus;
+  CK_C_CancelFunction C_CancelFunction;
+  CK_C_WaitForSlotEvent C_WaitForSlotEvent;
+};
+
+
+typedef ck_rv_t (*ck_createmutex_t) (void **mutex);
+typedef ck_rv_t (*ck_destroymutex_t) (void *mutex);
+typedef ck_rv_t (*ck_lockmutex_t) (void *mutex);
+typedef ck_rv_t (*ck_unlockmutex_t) (void *mutex);
+
+
+struct ck_c_initialize_args
+{
+  ck_createmutex_t create_mutex;
+  ck_destroymutex_t destroy_mutex;
+  ck_lockmutex_t lock_mutex;
+  ck_unlockmutex_t unlock_mutex;
+  ck_flags_t flags;
+  void *reserved;
+};
+
+
+#define CKF_LIBRARY_CANT_CREATE_OS_THREADS     (1 << 0)
+#define CKF_OS_LOCKING_OK                      (1 << 1)
+
+#define CKR_OK                                 (0)
+#define CKR_CANCEL                             (1)
+#define CKR_HOST_MEMORY                                (2)
+#define CKR_SLOT_ID_INVALID                    (3)
+#define CKR_GENERAL_ERROR                      (5)
+#define CKR_FUNCTION_FAILED                    (6)
+#define CKR_ARGUMENTS_BAD                      (7)
+#define CKR_NO_EVENT                           (8)
+#define CKR_NEED_TO_CREATE_THREADS             (9)
+#define CKR_CANT_LOCK                          (0xa)
+#define CKR_ATTRIBUTE_READ_ONLY                        (0x10)
+#define CKR_ATTRIBUTE_SENSITIVE                        (0x11)
+#define CKR_ATTRIBUTE_TYPE_INVALID             (0x12)
+#define CKR_ATTRIBUTE_VALUE_INVALID            (0x13)
+#define CKR_DATA_INVALID                       (0x20)
+#define CKR_DATA_LEN_RANGE                     (0x21)
+#define CKR_DEVICE_ERROR                       (0x30)
+#define CKR_DEVICE_MEMORY                      (0x31)
+#define CKR_DEVICE_REMOVED                     (0x32)
+#define CKR_ENCRYPTED_DATA_INVALID             (0x40)
+#define CKR_ENCRYPTED_DATA_LEN_RANGE           (0x41)
+#define CKR_FUNCTION_CANCELED                  (0x50)
+#define CKR_FUNCTION_NOT_PARALLEL              (0x51)
+#define CKR_FUNCTION_NOT_SUPPORTED             (0x54)
+#define CKR_KEY_HANDLE_INVALID                 (0x60)
+#define CKR_KEY_SIZE_RANGE                     (0x62)
+#define CKR_KEY_TYPE_INCONSISTENT              (0x63)
+#define CKR_KEY_NOT_NEEDED                     (0x64)
+#define CKR_KEY_CHANGED                                (0x65)
+#define CKR_KEY_NEEDED                         (0x66)
+#define CKR_KEY_INDIGESTIBLE                   (0x67)
+#define CKR_KEY_FUNCTION_NOT_PERMITTED         (0x68)
+#define CKR_KEY_NOT_WRAPPABLE                  (0x69)
+#define CKR_KEY_UNEXTRACTABLE                  (0x6a)
+#define CKR_MECHANISM_INVALID                  (0x70)
+#define CKR_MECHANISM_PARAM_INVALID            (0x71)
+#define CKR_OBJECT_HANDLE_INVALID              (0x82)
+#define CKR_OPERATION_ACTIVE                   (0x90)
+#define CKR_OPERATION_NOT_INITIALIZED          (0x91)
+#define CKR_PIN_INCORRECT                      (0xa0)
+#define CKR_PIN_INVALID                                (0xa1)
+#define CKR_PIN_LEN_RANGE                      (0xa2)
+#define CKR_PIN_EXPIRED                                (0xa3)
+#define CKR_PIN_LOCKED                         (0xa4)
+#define CKR_SESSION_CLOSED                     (0xb0)
+#define CKR_SESSION_COUNT                      (0xb1)
+#define CKR_SESSION_HANDLE_INVALID             (0xb3)
+#define CKR_SESSION_PARALLEL_NOT_SUPPORTED     (0xb4)
+#define CKR_SESSION_READ_ONLY                  (0xb5)
+#define CKR_SESSION_EXISTS                     (0xb6)
+#define CKR_SESSION_READ_ONLY_EXISTS           (0xb7)
+#define CKR_SESSION_READ_WRITE_SO_EXISTS       (0xb8)
+#define CKR_SIGNATURE_INVALID                  (0xc0)
+#define CKR_SIGNATURE_LEN_RANGE                        (0xc1)
+#define CKR_TEMPLATE_INCOMPLETE                        (0xd0)
+#define CKR_TEMPLATE_INCONSISTENT              (0xd1)
+#define CKR_TOKEN_NOT_PRESENT                  (0xe0)
+#define CKR_TOKEN_NOT_RECOGNIZED               (0xe1)
+#define CKR_TOKEN_WRITE_PROTECTED              (0xe2)
+#define        CKR_UNWRAPPING_KEY_HANDLE_INVALID       (0xf0)
+#define CKR_UNWRAPPING_KEY_SIZE_RANGE          (0xf1)
+#define CKR_UNWRAPPING_KEY_TYPE_INCONSISTENT   (0xf2)
+#define CKR_USER_ALREADY_LOGGED_IN             (0x100)
+#define CKR_USER_NOT_LOGGED_IN                 (0x101)
+#define CKR_USER_PIN_NOT_INITIALIZED           (0x102)
+#define CKR_USER_TYPE_INVALID                  (0x103)
+#define CKR_USER_ANOTHER_ALREADY_LOGGED_IN     (0x104)
+#define CKR_USER_TOO_MANY_TYPES                        (0x105)
+#define CKR_WRAPPED_KEY_INVALID                        (0x110)
+#define CKR_WRAPPED_KEY_LEN_RANGE              (0x112)
+#define CKR_WRAPPING_KEY_HANDLE_INVALID                (0x113)
+#define CKR_WRAPPING_KEY_SIZE_RANGE            (0x114)
+#define CKR_WRAPPING_KEY_TYPE_INCONSISTENT     (0x115)
+#define CKR_RANDOM_SEED_NOT_SUPPORTED          (0x120)
+#define CKR_RANDOM_NO_RNG                      (0x121)
+#define CKR_DOMAIN_PARAMS_INVALID              (0x130)
+#define CKR_BUFFER_TOO_SMALL                   (0x150)
+#define CKR_SAVED_STATE_INVALID                        (0x160)
+#define CKR_INFORMATION_SENSITIVE              (0x170)
+#define CKR_STATE_UNSAVEABLE                   (0x180)
+#define CKR_CRYPTOKI_NOT_INITIALIZED           (0x190)
+#define CKR_CRYPTOKI_ALREADY_INITIALIZED       (0x191)
+#define CKR_MUTEX_BAD                          (0x1a0)
+#define CKR_MUTEX_NOT_LOCKED                   (0x1a1)
+#define CKR_FUNCTION_REJECTED                  (0x200)
+#define CKR_VENDOR_DEFINED                     ((unsigned long) (1 << 31))
+
+
+
+/* Compatibility layer.  */
+
+#ifdef CRYPTOKI_COMPAT
+
+#undef CK_DEFINE_FUNCTION
+#define CK_DEFINE_FUNCTION(retval, name) retval CK_SPEC name
+
+/* For NULL.  */
+#include <stddef.h>
+
+typedef unsigned char CK_BYTE;
+typedef unsigned char CK_CHAR;
+typedef unsigned char CK_UTF8CHAR;
+typedef unsigned char CK_BBOOL;
+typedef unsigned long int CK_ULONG;
+typedef long int CK_LONG;
+typedef CK_BYTE *CK_BYTE_PTR;
+typedef CK_CHAR *CK_CHAR_PTR;
+typedef CK_UTF8CHAR *CK_UTF8CHAR_PTR;
+typedef CK_ULONG *CK_ULONG_PTR;
+typedef void *CK_VOID_PTR;
+typedef void **CK_VOID_PTR_PTR;
+#define CK_FALSE 0
+#define CK_TRUE 1
+#ifndef CK_DISABLE_TRUE_FALSE
+#ifndef FALSE
+#define FALSE 0
+#endif
+#ifndef TRUE
+#define TRUE 1
+#endif
+#endif
+
+typedef struct ck_version CK_VERSION;
+typedef struct ck_version *CK_VERSION_PTR;
+
+typedef struct ck_info CK_INFO;
+typedef struct ck_info *CK_INFO_PTR;
+
+typedef ck_slot_id_t *CK_SLOT_ID_PTR;
+
+typedef struct ck_slot_info CK_SLOT_INFO;
+typedef struct ck_slot_info *CK_SLOT_INFO_PTR;
+
+typedef struct ck_token_info CK_TOKEN_INFO;
+typedef struct ck_token_info *CK_TOKEN_INFO_PTR;
+
+typedef ck_session_handle_t *CK_SESSION_HANDLE_PTR;
+
+typedef struct ck_session_info CK_SESSION_INFO;
+typedef struct ck_session_info *CK_SESSION_INFO_PTR;
+
+typedef ck_object_handle_t *CK_OBJECT_HANDLE_PTR;
+
+typedef ck_object_class_t *CK_OBJECT_CLASS_PTR;
+
+typedef struct ck_attribute CK_ATTRIBUTE;
+typedef struct ck_attribute *CK_ATTRIBUTE_PTR;
+
+typedef struct ck_date CK_DATE;
+typedef struct ck_date *CK_DATE_PTR;
+
+typedef ck_mechanism_type_t *CK_MECHANISM_TYPE_PTR;
+
+typedef struct ck_mechanism CK_MECHANISM;
+typedef struct ck_mechanism *CK_MECHANISM_PTR;
+
+typedef struct ck_mechanism_info CK_MECHANISM_INFO;
+typedef struct ck_mechanism_info *CK_MECHANISM_INFO_PTR;
+
+typedef struct ck_function_list CK_FUNCTION_LIST;
+typedef struct ck_function_list *CK_FUNCTION_LIST_PTR;
+typedef struct ck_function_list **CK_FUNCTION_LIST_PTR_PTR;
+
+typedef struct ck_c_initialize_args CK_C_INITIALIZE_ARGS;
+typedef struct ck_c_initialize_args *CK_C_INITIALIZE_ARGS_PTR;
+
+#define NULL_PTR NULL
+
+/* Delete the helper macros defined at the top of the file.  */
+#undef ck_flags_t
+#undef ck_version
+
+#undef ck_info
+#undef cryptoki_version
+#undef manufacturer_id
+#undef library_description
+#undef library_version
+
+#undef ck_notification_t
+#undef ck_slot_id_t
+
+#undef ck_slot_info
+#undef slot_description
+#undef hardware_version
+#undef firmware_version
+
+#undef ck_token_info
+#undef serial_number
+#undef max_session_count
+#undef session_count
+#undef max_rw_session_count
+#undef rw_session_count
+#undef max_pin_len
+#undef min_pin_len
+#undef total_public_memory
+#undef free_public_memory
+#undef total_private_memory
+#undef free_private_memory
+#undef utc_time
+
+#undef ck_session_handle_t
+#undef ck_user_type_t
+#undef ck_state_t
+
+#undef ck_session_info
+#undef slot_id
+#undef device_error
+
+#undef ck_object_handle_t
+#undef ck_object_class_t
+#undef ck_hw_feature_type_t
+#undef ck_key_type_t
+#undef ck_certificate_type_t
+#undef ck_attribute_type_t
+
+#undef ck_attribute
+#undef value
+#undef value_len
+
+#undef ck_date
+
+#undef ck_mechanism_type_t
+
+#undef ck_mechanism
+#undef parameter
+#undef parameter_len
+
+#undef ck_mechanism_info
+#undef min_key_size
+#undef max_key_size
+
+#undef ck_rv_t
+#undef ck_notify_t
+
+#undef ck_function_list
+
+#undef ck_createmutex_t
+#undef ck_destroymutex_t
+#undef ck_lockmutex_t
+#undef ck_unlockmutex_t
+
+#undef ck_c_initialize_args
+#undef create_mutex
+#undef destroy_mutex
+#undef lock_mutex
+#undef unlock_mutex
+#undef reserved
+
+#endif /* CRYPTOKI_COMPAT */
+
+
+/* System dependencies.  */
+#if defined(_WIN32) || defined(CRYPTOKI_FORCE_WIN32)
+#pragma pack(pop, cryptoki)
+#endif
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif /* PKCS11_H */
diff --git a/lib/pkcs11_write.c b/lib/pkcs11_write.c
index a8ed760..d7a8958 100644
--- a/lib/pkcs11_write.c
+++ b/lib/pkcs11_write.c
@@ -100,8 +100,9 @@ int gnutls_pkcs11_copy_x509_crt(const char* token_url, 
gnutls_x509_crt_t crt,
                goto cleanup;
        }
        
-       
-       a[0].type = CKA_CLASS;
+    /* FIXME: copy key usage flags */
+    
+    a[0].type = CKA_CLASS;
     a[0].value = &class;
     a[0].value_len = sizeof(class);
     a[1].type = CKA_ID;
@@ -206,18 +207,20 @@ int gnutls_pkcs11_copy_x509_privkey(const char* token_url,
                return ret;
        }
 
+    /* FIXME: copy key usage flags */
+
     a[0].type = CKA_CLASS;
     a[0].value = &class;
     a[0].value_len = sizeof(class);
     a[1].type = CKA_ID;
     a[1].value = id;
     a[1].value_len = id_size;
-       a[2].type = CKA_KEY_TYPE;
-       a[2].value = &type;
-       a[2].value_len = sizeof(type);
-       a[3].type = CKA_SENSITIVE;
-       a[3].value = &tval;
-       a[3].value_len = sizeof(tval);
+    a[2].type = CKA_KEY_TYPE;
+    a[2].value = &type;
+    a[2].value_len = sizeof(type);
+    a[3].type = CKA_SENSITIVE;
+    a[3].value = &tval;
+    a[3].value_len = sizeof(tval);
     
     a_val = 4;
 


hooks/post-receive
-- 
GNU gnutls



reply via email to

[Prev in Thread] Current Thread [Next in Thread]