gnutls-commit
[Top][All Lists]
Advanced

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

[SCM] GNU gnutls branch, master, updated. gnutls_2_9_10-211-g125ce48


From: Nikos Mavrogiannopoulos
Subject: [SCM] GNU gnutls branch, master, updated. gnutls_2_9_10-211-g125ce48
Date: Fri, 04 Jun 2010 15:52:55 +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=125ce4842ced6f4f8631b953b0ce0f3f5a22e3e5

The branch, master has been updated
       via  125ce4842ced6f4f8631b953b0ce0f3f5a22e3e5 (commit)
       via  e235bb89e1e1b03f1197805b9f2029b3473a7a0a (commit)
       via  d300a9a2ea886bee0cef4d97c274952b26ddbe13 (commit)
       via  5b2ef1f508289e618825cb05ebc864492b0db7de (commit)
       via  6537b9cad62c4912444434338052d537e760f069 (commit)
       via  570d12e7c3fc4349b2f2a0bc0c1022a4e6e5f4cf (commit)
       via  0639352dd51ba28d34e668c2b3c4f4c4d75ec6ea (commit)
       via  29208d3a80760554fad201a9d9a381a47725c78a (commit)
       via  d55d47640997b1a747d4a694551bb1b8e1ce8480 (commit)
       via  ff8ec39189625a9705fbccd2f906d18d38bece2a (commit)
       via  24a416ea2014cf26cf0d0082a456184d33b49cc1 (commit)
       via  5eeabed81dbfe7a2e4089e612db5c61e60edeb91 (commit)
       via  f0bb0ff371418b5a32fefd50e329733a9afc4b6d (commit)
       via  0a120e76db70a0db2713d7bcddda07b027ca1842 (commit)
       via  c80f335eb662ff41f20fcbde507404db67c48827 (commit)
       via  f35940429378d756fe0867d7d982e37723ab2fa9 (commit)
       via  0cf9987b56d4a8723352012a59f1011a0ce9b2b9 (commit)
       via  183314f6c6f06d67238014afe50f51732417d09d (commit)
       via  5ca78add8f2dec7d2b53394782b4e5b5f1d10402 (commit)
       via  0cd905b6959bba4d80b341d2eed20679b3e475e1 (commit)
       via  73b0d37190385b1610c268f51f65d0da987660e8 (commit)
       via  0ac77d86c0aa3956741aa6657256373ec0189238 (commit)
       via  c018de363fc17547d6c27005a22d425a58e53d5a (commit)
       via  69ed89cc8ab600e2ed8222ad1185563ddf2d3b8d (commit)
       via  17eb52d3f661026ec120fcbb4f8602a0d65f7686 (commit)
       via  50012145a1374307eb6540106398bf5f8d82d8b0 (commit)
       via  89eaee1e7fefb198a90b13b091392798da19c1a0 (commit)
       via  5aa87a5f88930958110adf1381d513915b8fa684 (commit)
       via  76a77fbc3959fb7a98721760bf3cfadcbd0549ac (commit)
       via  3bd54a908bca57b9579c234beff1773f93d5d8c5 (commit)
       via  60103e9032dc74f9e0606bea06eb715c3c941bb2 (commit)
       via  7819fab218b68f3941656cbcfd2aa49b8121e24e (commit)
       via  5a1c51ac3b3fc5517f1b0160b5da78d7502c1c83 (commit)
       via  0c6905d7aa6a44757578b71124d0c40a9e36050e (commit)
       via  ffcd96ef593f246b0db7a182a742f05ae4e94063 (commit)
       via  aab0a2848903a6f2bf0388e9a96c731cdb437a23 (commit)
       via  358479ebe6ad9a3f86432d20db7046799c46a5f5 (commit)
       via  ab307930167bc836495455adc9bdec4472ef60d5 (commit)
       via  b1e779819654c24341a67431e7987e5fa94c724d (commit)
       via  44defdb6d920505aced100a7f73bbea5b8f97aa8 (commit)
       via  f93a17c48e959698a485a08b7ecb8a65e3bb4175 (commit)
       via  5050b09b312ad0132d93539c90c7212a8bdbf9d1 (commit)
       via  329361fbd8ef93abcfce00a45ac5a8ce86827f4a (commit)
       via  ea522aa15f7807af9dad1e6e8332b6b7e2bd622c (commit)
       via  283485a418ca383e8c5fb170077e5a6e8afbfea2 (commit)
       via  204b7b78899456945151ce88dbc41e7cb9eba994 (commit)
       via  bbb915fefc9219150ef5be21d3926cd3d58ce9d1 (commit)
       via  dabf249a6e49d49628fee53c56c68fe713794c97 (commit)
       via  28fd4114ef1c88d5d7ca5510d99e76f6f20dc4c9 (commit)
       via  31c000989443efb80b9bb7d67880baa608ca656e (commit)
       via  95953b193541a0083a7e55965c5e0b2c6c8d9c4e (commit)
       via  d8622cfc7028b9a24bf0b992473d268e18831537 (commit)
       via  d45f3425dfbb8fb02d398d43d0c0699e7b8b3850 (commit)
       via  c10f5496c1bbe11c35971621278879a1c05dfceb (commit)
       via  9b7fe3a9f5ef6cf8bfc4610719e7e566a5191bcb (commit)
       via  9f4fae2679f34e0e42b86e38cce00cec60f149bb (commit)
       via  df646c6712a91db5e314268829d835c046d15b57 (commit)
       via  e4cceb23547c8dc8394f58fd087e0f17c8add2ca (commit)
       via  6347a98534c753689958345a3d8ee6ad6bf58ac2 (commit)
       via  a55d569b1873c6dceda275865d9035ff8479a527 (commit)
       via  c8e3c9a33ff147eac420431779cb8cb9f6d9d1aa (commit)
       via  459eaf4c9167160e4025a820345d3fa2d217406e (commit)
       via  bab8c93bf9501e0eece9d99b491987c83b998e26 (commit)
       via  805694523f9cead85dcf221f5f715527e2b15ffc (commit)
       via  71df305f042f9d54486cfb1122c4671a19559b69 (commit)
       via  24db1c027d69fb67c6ba9eb996d55b934c399a74 (commit)
       via  c4460a9921013a9700656d55f3c701e0fed5cd2d (commit)
       via  d4a4643dbe1bd739e55706fa4affaf10aae1dfa9 (commit)
       via  b6e40a9119444a56af19f5bbbd33c3842b758438 (commit)
       via  1231655dfee3105aeaf89094aecd4b45c51b29ec (commit)
       via  2f671fb4b159de431959f03496e4be46ea806f28 (commit)
       via  f1bbe2d1fec833323d7e8fe32c50736aec398751 (commit)
       via  0daa4508750f85feb72818b1a246d599873bde53 (commit)
       via  bfff18e96db1423e243a800db8fc3e74df51551e (commit)
       via  c0a6ea5047acd66707f3c2688016c29e888ee4b9 (commit)
       via  21579cb985744881759a9dad6759842b3e26546f (commit)
       via  48c5a7a070b240255c0303f8640519db94604345 (commit)
       via  5aaf7703a34e41e307241d6cdf8c4d5c63a203eb (commit)
       via  bb5967b3dc9f4615420030ce8451de0fe86f6ebe (commit)
       via  0bb48a2dcfc3d688475d423f5c9e1e1ab08b9164 (commit)
       via  bfb90f17b400206db7b0d0c81703a770492a8a3f (commit)
       via  a7a25b95e854ae1fdffc7592b89bb9bde0bdea9c (commit)
       via  ae52121def338a09d847e651ff5e0b46f20d0d97 (commit)
       via  f0f7aa5a180c9ee47c997227708abc828480a6f5 (commit)
       via  ea433f8343b360edc7f813a897bc2cfda4134c56 (commit)
       via  8f73ab26c1187c48aef05408321300c9c77e4194 (commit)
       via  09c8ad2bb46799cd92580694008d11b6db479c40 (commit)
       via  2184514f10dc92cc97d38c344e322a3afb737eb2 (commit)
       via  b6f4958c4f75791326ccef12915c78436d42b409 (commit)
       via  77fdd543b21e896a5637e956097672b9f79ab899 (commit)
       via  b57a08b232479fb002b1819837b71e26a9f928a6 (commit)
       via  4a8552433e86a691c25be6eaa9037da43f9cce37 (commit)
       via  a43180ff5c80d23277184691dac5ed97cf97d86f (commit)
       via  a85fffd50b34e8d5b9b8d1d699421ec2c0ee8dca (commit)
       via  eb24bfa808ee029e9b3b198d66d29256eea3fd08 (commit)
       via  e30457b0fdb9d7d05734197b4e3bc8a47405f016 (commit)
       via  2b3dc5053c3a04fdb69f642195190c466d4a539e (commit)
       via  68b714494d6b99104897738ccec676a81be7a35d (commit)
       via  4d8be74bbc3b60f539bff11a20544d80339ff34f (commit)
       via  7235776221b10fb6ab2640dad84b8fde7a21055d (commit)
       via  d3507b551241150eef8b4190b75a20ae235691ed (commit)
       via  a4ba092ab2aba436c51d8daba689afcdb0e3f517 (commit)
       via  8a9c9c32af04230763435c638d824379db5bf92f (commit)
       via  b25fd9c6d454492cfa2903fe9261372ceec4b17d (commit)
       via  56c7c519e0b2acf59b596e84389eddccae0110e3 (commit)
       via  e9966796a52634c40155e3e14cc02741a72f26fa (commit)
       via  4e825733ffc13cecd5c550ee3fee6b4607ebe19d (commit)
       via  2b4d022023d23fc820383222fca55ad6f57439b3 (commit)
       via  508523d16813a034a78eb7bfbd549addb7b04a9b (commit)
       via  bd73a4d78c7255069ac34ba9ed47654af1230c1a (commit)
       via  b3ed74e56063d6a501b32e22d19e42106c771a4c (commit)
       via  be560a8138daced8f37f2b6012e4417311dd4983 (commit)
       via  2750317ca1d76ab6524b231e69af7ac152449fbf (commit)
       via  fa40626c7d5841539d03cb43ec880eb5f35e3994 (commit)
       via  bbcdf1b0c3365174999b763fd6f6822ddc910f5a (commit)
       via  c67a003f2467fa3daf7ca2b85247df80c24e0ea2 (commit)
       via  96febfef5a80a4e128683663e3cdc4a50f8db78c (commit)
       via  e5db8e4f2a7874ebd047e0744a41157f2ad50866 (commit)
       via  af81d19ac9a439a95464badce982e670fda3d217 (commit)
       via  0731bfe19602c907d3e4e7693f7fef8bcd8eb58c (commit)
       via  c3b050f46e09be3a400f5002fa3a4ba655da813c (commit)
       via  954644245d2a3744bf07053f534f3ffd7915e4e7 (commit)
       via  b7ad62a4a8e2ff69dfc8cafb5ec3857a4170940c (commit)
       via  34da078a2f97501fcc2a97384f9b43beb0120951 (commit)
       via  c8efb9f644163b690fab12cd18f0a0cd509b3e29 (commit)
       via  df68b8d5f97bdb9ac6557236bf727762f19881bb (commit)
       via  3404a413106394af03ceee9cf11dfd3e9c0789a3 (commit)
       via  e84833017dc9c0724610e639043284644ad204d5 (commit)
       via  b05d938180a057dfe0f6a8d64ac4acab41ab26fe (commit)
       via  715f13ad839679f953b8efc3052bc9f335a96a79 (commit)
       via  80fee6924dd72b17113a1e72e8d2930634f4a463 (commit)
       via  b14cf0fdcd2d1af819522d36547e41730fa69fec (commit)
       via  15f439814c233351c9390fd5d8c4c5f24a610ab0 (commit)
       via  3ef62950845f551ebc629e50d5ddf75f71b84294 (commit)
       via  c6af0882e5d5e4439c6e3d76da82e05a928e9c1e (commit)
       via  599d0f21e62dea13273e7590841d8814319dae17 (commit)
       via  5217d518cdbe3e9cf32c3d72514d0f15242d67c2 (commit)
       via  f816631c8cdf8c1117248593ce3f9e6e40dea009 (commit)
       via  a209eced7ce4fc698d27d16e3403441b452d9c0e (commit)
       via  9793a81f4fbafd8f0897f3d486ba5a5a9e8bca33 (commit)
       via  6b5b3c0db249855c768aeef1325e6be265f2f7cb (commit)
       via  74c2bcd1cd9d46efac5a146aef3048e33aa557b8 (commit)
       via  95dd15a0b2bf4daff8f0bffa9903f71990d0156d (commit)
       via  8aaf546f1c1b8a198f3bf69bb380bff9a47713fd (commit)
       via  d1518b15a5da9ab713d14c8d7ccd2e7753ab1f8a (commit)
       via  2600a35a98b9c7e1515fce23ea5b63a7bcf9a119 (commit)
       via  39f81e44822fc51b678ae6bf7cbc5aa8b8adead8 (commit)
       via  8cb0a6412b655e67c81c71f82fb90c7e3761667c (commit)
       via  8ddb4553ae1d90ba8778797402e75330530519e4 (commit)
       via  9c8631c68a728584b46b7d2ceff2e872ae8a59dd (commit)
       via  11e32e847614d1f0736584d83360efeb0d11e459 (commit)
       via  493588c1a8a51cdb25429bf5865599f52d6303e3 (commit)
       via  a2374cc6c1408e7d3e3d0f391f3b187a4626f82e (commit)
      from  9fd9ba397442fa0d593766e1ae396e589abf4c41 (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 125ce4842ced6f4f8631b953b0ce0f3f5a22e3e5
Author: Nikos Mavrogiannopoulos <address@hidden>
Date:   Fri Jun 4 08:14:21 2010 +0200

    Provider unref must be done after all sessions have been closed.

commit e235bb89e1e1b03f1197805b9f2029b3473a7a0a
Author: Nikos Mavrogiannopoulos <address@hidden>
Date:   Thu Jun 3 20:06:20 2010 +0200

    Several fixes for the broken rebase.

commit d300a9a2ea886bee0cef4d97c274952b26ddbe13
Author: Nikos Mavrogiannopoulos <address@hidden>
Date:   Thu Jun 3 19:57:49 2010 +0200

    Merged with master.

commit 5b2ef1f508289e618825cb05ebc864492b0db7de
Author: Nikos Mavrogiannopoulos <address@hidden>
Date:   Thu Jun 3 00:59:39 2010 +0200

    Some other changes to mbuffers to make gnutls (a bit more) agnostic on 
their internal structure.

commit 6537b9cad62c4912444434338052d537e760f069
Author: Nikos Mavrogiannopoulos <address@hidden>
Date:   Thu Jun 3 00:48:20 2010 +0200

    Corrected prefered hash algorithm return value on RSA.

commit 570d12e7c3fc4349b2f2a0bc0c1022a4e6e5f4cf
Author: Nikos Mavrogiannopoulos <address@hidden>
Date:   Thu Jun 3 00:47:40 2010 +0200

    Use GCRYCTL_ENABLE_QUICK_RANDOM when using libgcrypt.

commit 0639352dd51ba28d34e668c2b3c4f4c4d75ec6ea
Author: Nikos Mavrogiannopoulos <address@hidden>
Date:   Mon May 31 17:18:55 2010 +0200

    Ignore more files.

commit 29208d3a80760554fad201a9d9a381a47725c78a
Author: Nikos Mavrogiannopoulos <address@hidden>
Date:   Mon May 31 17:18:51 2010 +0200

    Remove the correct file

commit d55d47640997b1a747d4a694551bb1b8e1ce8480
Author: Nikos Mavrogiannopoulos <address@hidden>
Date:   Mon May 31 17:17:45 2010 +0200

    Added missing files.

commit ff8ec39189625a9705fbccd2f906d18d38bece2a
Author: Nikos Mavrogiannopoulos <address@hidden>
Date:   Mon May 31 17:13:49 2010 +0200

    The get_preferred_hash_algorithm() functions have now an extra argument to 
indicate
    whether it is mandatory to use this algorithm.

commit 24a416ea2014cf26cf0d0082a456184d33b49cc1
Author: Nikos Mavrogiannopoulos <address@hidden>
Date:   Mon May 31 16:52:13 2010 +0200

    Added gnutls_x509_crq_get_preferred_hash_algorithm().

commit 5eeabed81dbfe7a2e4089e612db5c61e60edeb91
Author: Nikos Mavrogiannopoulos <address@hidden>
Date:   Mon May 31 00:52:27 2010 +0200

    Added gnutls_pubkey_get_preferred_hash_algorithm() and 
gnutls_x509_crt_get_preferred_hash_algorithm()
    to allow determining the hash algorithm to use during signing. This is 
needed in the case of DSA
    that uses specific versions of SHA depending on the size of the parameters.

commit f0bb0ff371418b5a32fefd50e329733a9afc4b6d
Author: Nikos Mavrogiannopoulos <address@hidden>
Date:   Mon May 31 00:17:14 2010 +0200

    Several fixes after big rebase.

commit 0a120e76db70a0db2713d7bcddda07b027ca1842
Author: Nikos Mavrogiannopoulos <address@hidden>
Date:   Sun May 30 12:54:53 2010 +0200

    Test the DSA with SHA256 as well.

commit c80f335eb662ff41f20fcbde507404db67c48827
Author: Nikos Mavrogiannopoulos <address@hidden>
Date:   Sun May 30 12:53:54 2010 +0200

    Print debugging information on error.

commit f35940429378d756fe0867d7d982e37723ab2fa9
Author: Nikos Mavrogiannopoulos <address@hidden>
Date:   Sun May 30 12:45:08 2010 +0200

    Nettle library can now parse the PGP integers. Except for SHA-224/384/512
    nettle seems to be fully working now.

commit 0cf9987b56d4a8723352012a59f1011a0ce9b2b9
Author: Nikos Mavrogiannopoulos <address@hidden>
Date:   Sun May 30 12:44:24 2010 +0200

    use --sec-param to generate privkey.

commit 183314f6c6f06d67238014afe50f51732417d09d
Author: Nikos Mavrogiannopoulos <address@hidden>
Date:   Sun May 30 12:44:00 2010 +0200

    reduced log level to a sane one

commit 5ca78add8f2dec7d2b53394782b4e5b5f1d10402
Author: Nikos Mavrogiannopoulos <address@hidden>
Date:   Sun May 30 12:43:40 2010 +0200

    Corrected for new output of --print-certificate-info

commit 0cd905b6959bba4d80b341d2eed20679b3e475e1
Author: Nikos Mavrogiannopoulos <address@hidden>
Date:   Sun May 30 12:35:07 2010 +0200

    Print information on failure.

commit 73b0d37190385b1610c268f51f65d0da987660e8
Author: Nikos Mavrogiannopoulos <address@hidden>
Date:   Sun May 30 12:31:57 2010 +0200

    Print exp1 and exp2 if they are available.

commit 0ac77d86c0aa3956741aa6657256373ec0189238
Author: Nikos Mavrogiannopoulos <address@hidden>
Date:   Sun May 30 12:12:26 2010 +0200

    Only print output if something fails

commit c018de363fc17547d6c27005a22d425a58e53d5a
Author: Nikos Mavrogiannopoulos <address@hidden>
Date:   Sun May 30 11:27:44 2010 +0200

    Some pakchois fixes.

commit 69ed89cc8ab600e2ed8222ad1185563ddf2d3b8d
Author: Nikos Mavrogiannopoulos <address@hidden>
Date:   Sun May 30 11:27:15 2010 +0200

    Fixup to compile with nettle

commit 17eb52d3f661026ec120fcbb4f8602a0d65f7686
Author: Nikos Mavrogiannopoulos <address@hidden>
Date:   Sat May 29 17:37:42 2010 +0200

    Do not bother with MODPATH. We don't use it.

commit 50012145a1374307eb6540106398bf5f8d82d8b0
Author: Nikos Mavrogiannopoulos <address@hidden>
Date:   Sat May 29 17:29:22 2010 +0200

    Added again _gnutls_dump_mpi() to assist in debugging.

commit 89eaee1e7fefb198a90b13b091392798da19c1a0
Author: Nikos Mavrogiannopoulos <address@hidden>
Date:   Sat May 29 14:16:15 2010 +0200

    Added debugging

commit 5aa87a5f88930958110adf1381d513915b8fa684
Author: Nikos Mavrogiannopoulos <address@hidden>
Date:   Sat May 29 14:15:59 2010 +0200

    Allow DSA with other than SHA1 algorithms in TLS.

commit 76a77fbc3959fb7a98721760bf3cfadcbd0549ac
Author: Nikos Mavrogiannopoulos <address@hidden>
Date:   Sat May 29 14:15:12 2010 +0200

    removed more stuff.

commit 3bd54a908bca57b9579c234beff1773f93d5d8c5
Author: Nikos Mavrogiannopoulos <address@hidden>
Date:   Sat May 29 13:25:45 2010 +0200

    LocalKeyId and XmppAddr were incorporated.

commit 60103e9032dc74f9e0606bea06eb715c3c941bb2
Author: Nikos Mavrogiannopoulos <address@hidden>
Date:   Sat May 29 13:17:12 2010 +0200

    No need for those OIDs any more.

commit 7819fab218b68f3941656cbcfd2aa49b8121e24e
Author: Nikos Mavrogiannopoulos <address@hidden>
Date:   Sat May 29 13:16:54 2010 +0200

    Corrected to support new EV_ values.

commit 5a1c51ac3b3fc5517f1b0160b5da78d7502c1c83
Author: Nikos Mavrogiannopoulos <address@hidden>
Date:   Sat May 29 13:13:31 2010 +0200

    avoid calling gcrypt directly.

commit 0c6905d7aa6a44757578b71124d0c40a9e36050e
Author: Nikos Mavrogiannopoulos <address@hidden>
Date:   Sat May 29 13:13:12 2010 +0200

    exported gnutls_rnd().

commit ffcd96ef593f246b0db7a182a742f05ae4e94063
Author: Nikos Mavrogiannopoulos <address@hidden>
Date:   Sat May 29 13:00:34 2010 +0200

    The recognition of DN elements is now self contained. It does not need 
entries in pkix.asn.

commit aab0a2848903a6f2bf0388e9a96c731cdb437a23
Author: Nikos Mavrogiannopoulos <address@hidden>
Date:   Sat May 29 12:43:24 2010 +0200

    Added support for EV certificate attributes.

commit 358479ebe6ad9a3f86432d20db7046799c46a5f5
Author: Nikos Mavrogiannopoulos <address@hidden>
Date:   Sat May 29 12:22:56 2010 +0200

    Fixed nettle detection and AES.

commit ab307930167bc836495455adc9bdec4472ef60d5
Author: Nikos Mavrogiannopoulos <address@hidden>
Date:   Sat May 29 12:22:52 2010 +0200

    documentation updates

commit b1e779819654c24341a67431e7987e5fa94c724d
Author: Nikos Mavrogiannopoulos <address@hidden>
Date:   Sat May 29 12:22:26 2010 +0200

    Generate dh-params also used --sec-param.

commit 44defdb6d920505aced100a7f73bbea5b8f97aa8
Author: Nikos Mavrogiannopoulos <address@hidden>
Date:   Sat May 29 11:37:29 2010 +0200

    Document that the generator is the generator of the subgroup and not the 
group.

commit f93a17c48e959698a485a08b7ecb8a65e3bb4175
Author: Nikos Mavrogiannopoulos <address@hidden>
Date:   Sat May 29 02:14:07 2010 +0200

    Corrected certificate callback.

commit 5050b09b312ad0132d93539c90c7212a8bdbf9d1
Author: Nikos Mavrogiannopoulos <address@hidden>
Date:   Fri May 28 23:06:28 2010 +0200

    More AES stuff (still doesn't work).

commit 329361fbd8ef93abcfce00a45ac5a8ce86827f4a
Author: Nikos Mavrogiannopoulos <address@hidden>
Date:   Fri May 28 23:06:25 2010 +0200

    Correction in RSA encryption.

commit ea522aa15f7807af9dad1e6e8332b6b7e2bd622c
Author: Nikos Mavrogiannopoulos <address@hidden>
Date:   Fri May 28 21:25:18 2010 +0200

    Fixed issue with AES.

commit 283485a418ca383e8c5fb170077e5a6e8afbfea2
Author: Nikos Mavrogiannopoulos <address@hidden>
Date:   Fri May 28 21:08:44 2010 +0200

    Added gnutls_sec_param_to_pk_bits() et al. to allow select bit
    sizes for private keys using a human understandable scale.

commit 204b7b78899456945151ce88dbc41e7cb9eba994
Author: Nikos Mavrogiannopoulos <address@hidden>
Date:   Fri May 28 20:37:58 2010 +0200

    Added support for SHA224 and SHA256 in DSA.

commit bbb915fefc9219150ef5be21d3926cd3d58ce9d1
Author: Nikos Mavrogiannopoulos <address@hidden>
Date:   Fri May 28 17:31:10 2010 +0200

    Always use included pakchois.

commit dabf249a6e49d49628fee53c56c68fe713794c97
Author: Nikos Mavrogiannopoulos <address@hidden>
Date:   Thu May 27 00:00:48 2010 +0200

    make sure all lines fit in page.

commit 28fd4114ef1c88d5d7ca5510d99e76f6f20dc4c9
Author: Nikos Mavrogiannopoulos <address@hidden>
Date:   Wed May 26 23:58:35 2010 +0200

    make example more compact by removing error checking.

commit 31c000989443efb80b9bb7d67880baa608ca656e
Author: Nikos Mavrogiannopoulos <address@hidden>
Date:   Wed May 26 23:55:40 2010 +0200

    Added bibliographic reference to PKCS #11.

commit 95953b193541a0083a7e55965c5e0b2c6c8d9c4e
Author: Nikos Mavrogiannopoulos <address@hidden>
Date:   Wed May 26 16:59:12 2010 +0200

    Added sketch for PKCS #11 usage.

commit d8622cfc7028b9a24bf0b992473d268e18831537
Author: Nikos Mavrogiannopoulos <address@hidden>
Date:   Wed May 26 09:14:50 2010 +0200

    Added 2048 bit DSA key

commit d45f3425dfbb8fb02d398d43d0c0699e7b8b3850
Author: Nikos Mavrogiannopoulos <address@hidden>
Date:   Wed May 26 09:04:16 2010 +0200

    Increased log level of several messages.

commit c10f5496c1bbe11c35971621278879a1c05dfceb
Author: Nikos Mavrogiannopoulos <address@hidden>
Date:   Tue May 25 23:56:05 2010 +0200

    Corrected coefficient and exp[12] values in key.

commit 9b7fe3a9f5ef6cf8bfc4610719e7e566a5191bcb
Author: Nikos Mavrogiannopoulos <address@hidden>
Date:   Tue May 25 23:53:25 2010 +0200

    Added blinding in RSA. Correct broken private keys on import. Nettle
    uses more values than gcrypt does from RSA decryption and it seemed
    that some values in our stored private keys were messy (generated by
    very old gnutls).

commit 9f4fae2679f34e0e42b86e38cce00cec60f149bb
Author: Nikos Mavrogiannopoulos <address@hidden>
Date:   Mon May 24 19:37:57 2010 +0200

    Simplified internal API. The only question that remains now is how to handle
    the gnutls_pkcs11_privkey_t. Currently it opens a session and maintains a 
handle
    to the object. This will require locks to be added on operations. 
Alternatively
    new sessions may be opened for each operation performed. This is 
guarranteed by
    PKCS #11 to be thread safe but will of course require to ask for the PIN 
again.

commit df646c6712a91db5e314268829d835c046d15b57
Author: Nikos Mavrogiannopoulos <address@hidden>
Date:   Mon May 24 19:24:46 2010 +0200

    Removed debugging print.

commit e4cceb23547c8dc8394f58fd087e0f17c8add2ca
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 6347a98534c753689958345a3d8ee6ad6bf58ac2
Author: Nikos Mavrogiannopoulos <address@hidden>
Date:   Mon May 24 16:58:27 2010 +0200

    Added missing file.

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

    Removed finished items.

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

    Noted that there things to be done.

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

    Added documentation on abstract types.

commit bab8c93bf9501e0eece9d99b491987c83b998e26
Author: Nikos Mavrogiannopoulos <address@hidden>
Date:   Sun May 23 21:19:48 2010 +0200

    Common code for calculation of RSA exp1 and exp2. Also update the openpgp
    code to calculate those values.

commit 805694523f9cead85dcf221f5f715527e2b15ffc
Author: Nikos Mavrogiannopoulos <address@hidden>
Date:   Sun May 23 20:54:25 2010 +0200

    More fixes.

commit 71df305f042f9d54486cfb1122c4671a19559b69
Author: Nikos Mavrogiannopoulos <address@hidden>
Date:   Sun May 23 19:42:14 2010 +0200

    Corrected nicely hidden bug that caused accesses to uninitialized variables
    if the gcry_mpi_print() functions were pessimists and returned more size 
than
    actually needed for the print.

commit 24db1c027d69fb67c6ba9eb996d55b934c399a74
Author: Nikos Mavrogiannopoulos <address@hidden>
Date:   Sun May 23 19:23:31 2010 +0200

    Added some sanity checks.

commit c4460a9921013a9700656d55f3c701e0fed5cd2d
Author: Nikos Mavrogiannopoulos <address@hidden>
Date:   Sun May 23 19:01:00 2010 +0200

    Documentation updates. Separated big gnutls.texi to chapter to allow easier
    maintainance.

commit d4a4643dbe1bd739e55706fa4affaf10aae1dfa9
Author: Nikos Mavrogiannopoulos <address@hidden>
Date:   Sun May 23 14:05:32 2010 +0200

    Added support to copy certificates and private keys to tokens.
    New functions:
    gnutls_pkcs11_copy_x509_crt()
    gnutls_pkcs11_copy_x509_privkey()
    gnutls_pkcs11_delete_url()
    
    Certtool was updated to allow copying certificates and private keys
    to tokens. Deleting an object has issues (segfault) but it seems to be 
related
    with libopensc and its pkcs11 API.

commit b6e40a9119444a56af19f5bbbd33c3842b758438
Author: Nikos Mavrogiannopoulos <address@hidden>
Date:   Sat May 22 20:46:36 2010 +0200

    Added gnutls_pubkey_verify_hash(), gnutls_pubkey_get_verify_algorithm().

commit 1231655dfee3105aeaf89094aecd4b45c51b29ec
Author: Nikos Mavrogiannopoulos <address@hidden>
Date:   Sat May 22 20:15:22 2010 +0200

    Added gnutls_pubkey_import_pkcs11(), gnutls_pubkey_import_rsa_raw(),
    gnutls_pubkey_import_dsa_raw(), gnutls_pkcs11_obj_export().

commit 2f671fb4b159de431959f03496e4be46ea806f28
Author: Nikos Mavrogiannopoulos <address@hidden>
Date:   Sat May 22 15:31:18 2010 +0200

    Tried to document recent changes.

commit f1bbe2d1fec833323d7e8fe32c50736aec398751
Author: Nikos Mavrogiannopoulos <address@hidden>
Date:   Sat May 22 15:13:20 2010 +0200

    Added gnutls_pubkey_t abstract type to handle public keys. It can currently
    import/export public keys from existing certificate types as well as from 
PKCS #11
    URL. This allows generating a certificate or certificate request from a 
given public key
    (currently one could only generate them from a given private key).
    
    PKCS#11 API augmented to allow reading arbitrary objects instead of just 
certificates.
    Certtool updated to list those objects.

commit 0daa4508750f85feb72818b1a246d599873bde53
Author: Nikos Mavrogiannopoulos <address@hidden>
Date:   Sat May 22 10:34:00 2010 +0200

    Added gnutls_pkcs11_token_get_flags() to distinguish between hardware and 
soft tokens.

commit bfff18e96db1423e243a800db8fc3e74df51551e
Author: Nikos Mavrogiannopoulos <address@hidden>
Date:   Fri May 21 17:00:01 2010 +0200

    Added support for libnettle backend. This uses gmp for big number 
operations.
    It is not currently completed. It lacks RSA blinding as well as 
optimizations.

commit c0a6ea5047acd66707f3c2688016c29e888ee4b9
Author: Nikos Mavrogiannopoulos <address@hidden>
Date:   Tue May 18 23:41:22 2010 +0200

    Corrected bug in DSA signature generation.

commit 21579cb985744881759a9dad6759842b3e26546f
Author: Nikos Mavrogiannopoulos <address@hidden>
Date:   Tue May 18 23:18:07 2010 +0200

    Added operations to sign CRLs, certificates and requests with an abstract 
key and thus with a PKCS #11 key as well.

commit 48c5a7a070b240255c0303f8640519db94604345
Author: Nikos Mavrogiannopoulos <address@hidden>
Date:   Tue May 18 22:26:13 2010 +0200

    privkey.h -> abstract.h

commit 5aaf7703a34e41e307241d6cdf8c4d5c63a203eb
Author: Nikos Mavrogiannopoulos <address@hidden>
Date:   Tue May 18 22:17:34 2010 +0200

    The gnutls-cli --x509cafile can now be a PKCS #11 URL. It can read 
gnome-keyring's
    certificates and use them in the trusted list.

commit bb5967b3dc9f4615420030ce8451de0fe86f6ebe
Author: Nikos Mavrogiannopoulos <address@hidden>
Date:   Sun May 16 11:44:27 2010 +0200

    Corrections in openpgp private key usage.

commit 0bb48a2dcfc3d688475d423f5c9e1e1ab08b9164
Author: Nikos Mavrogiannopoulos <address@hidden>
Date:   Sun May 16 11:13:21 2010 +0200

    Updated self tests and examples to avoid using deprecated functions such as
    gnutls_certificate_server_set_retrieve_function and the sign callback.

commit bfb90f17b400206db7b0d0c81703a770492a8a3f
Author: Nikos Mavrogiannopoulos <address@hidden>
Date:   Sun May 16 10:56:13 2010 +0200

    Added documentation for most of the new functions.

commit a7a25b95e854ae1fdffc7592b89bb9bde0bdea9c
Author: Nikos Mavrogiannopoulos <address@hidden>
Date:   Sun May 16 09:42:35 2010 +0200

    Documented that it was initially based on neon pkcs11 and got ideas from 
pkcs11-helper library.

commit ae52121def338a09d847e651ff5e0b46f20d0d97
Author: Nikos Mavrogiannopoulos <address@hidden>
Date:   Sat May 15 23:43:30 2010 +0200

    Corrections to properly handle token removal and insert.

commit f0f7aa5a180c9ee47c997227708abc828480a6f5
Author: Nikos Mavrogiannopoulos <address@hidden>
Date:   Sat May 15 22:00:22 2010 +0200

    Added gnutls_pkcs11_privkey_t and gnutls_privkey_t types. Those are
    an abstract private key type that can be used to sign/encrypt any private 
key
    of pkcs11,x509 or openpgp types. Added support for PKCS11 in 
gnutls-cli/gnutls-serv.

commit ea433f8343b360edc7f813a897bc2cfda4134c56
Author: Nikos Mavrogiannopoulos <address@hidden>
Date:   Mon May 10 23:35:33 2010 +0200

    Added several helper functions, to allow printing of tokens.

commit 8f73ab26c1187c48aef05408321300c9c77e4194
Author: Nikos Mavrogiannopoulos <address@hidden>
Date:   Mon May 10 16:26:24 2010 +0200

    Added ability to export certificates from PKCS #11 tokens.
    Added ability to list trusted certificates, or only certificates
    with a corresponding private key or just all.

commit 09c8ad2bb46799cd92580694008d11b6db479c40
Author: Nikos Mavrogiannopoulos <address@hidden>
Date:   Sun May 9 17:20:40 2010 +0200

    Added initial PKCS #11 support. Certtool can now print lists of certificates
    available in system.

commit 2184514f10dc92cc97d38c344e322a3afb737eb2
Author: Nikos Mavrogiannopoulos <address@hidden>
Date:   Sat May 22 20:46:36 2010 +0200

    Added gnutls_pubkey_verify_hash(), gnutls_pubkey_get_verify_algorithm().

commit b6f4958c4f75791326ccef12915c78436d42b409
Author: Nikos Mavrogiannopoulos <address@hidden>
Date:   Sat May 22 20:15:22 2010 +0200

    Added gnutls_pubkey_import_pkcs11(), gnutls_pubkey_import_rsa_raw(),
    gnutls_pubkey_import_dsa_raw(), gnutls_pkcs11_obj_export().

commit 77fdd543b21e896a5637e956097672b9f79ab899
Author: Nikos Mavrogiannopoulos <address@hidden>
Date:   Sat May 22 15:37:09 2010 +0200

    Ignore files that should be ignored.

commit b57a08b232479fb002b1819837b71e26a9f928a6
Author: Nikos Mavrogiannopoulos <address@hidden>
Date:   Sat May 22 15:31:18 2010 +0200

    Tried to document recent changes.

commit 4a8552433e86a691c25be6eaa9037da43f9cce37
Author: Nikos Mavrogiannopoulos <address@hidden>
Date:   Sat May 22 15:13:20 2010 +0200

    Added gnutls_pubkey_t abstract type to handle public keys. It can currently
    import/export public keys from existing certificate types as well as from 
PKCS #11
    URL. This allows generating a certificate or certificate request from a 
given public key
    (currently one could only generate them from a given private key).
    
    PKCS#11 API augmented to allow reading arbitrary objects instead of just 
certificates.
    Certtool updated to list those objects.

commit a43180ff5c80d23277184691dac5ed97cf97d86f
Author: Nikos Mavrogiannopoulos <address@hidden>
Date:   Sat May 22 10:34:00 2010 +0200

    Added gnutls_pkcs11_token_get_flags() to distinguish between hardware and 
soft tokens.

commit a85fffd50b34e8d5b9b8d1d699421ec2c0ee8dca
Author: Nikos Mavrogiannopoulos <address@hidden>
Date:   Sat May 22 10:06:50 2010 +0200

    Export all symbols from C++ library. This library doesn't contain any
    internal symbols anyway and there is no reason to mess with the C++ ABI
    that hasn't got the problems of C.

commit eb24bfa808ee029e9b3b198d66d29256eea3fd08
Author: Nikos Mavrogiannopoulos <address@hidden>
Date:   Fri May 21 17:00:01 2010 +0200

    Added support for libnettle backend. This uses gmp for big number 
operations.
    It is not currently completed. It lacks RSA blinding as well as 
optimizations.

commit e30457b0fdb9d7d05734197b4e3bc8a47405f016
Author: Nikos Mavrogiannopoulos <address@hidden>
Date:   Tue May 18 23:45:08 2010 +0200

    Documented that the --file options in gnutls-cli and gnutls-serv can accept 
a PKCS #11 URL.

commit 2b3dc5053c3a04fdb69f642195190c466d4a539e
Author: Nikos Mavrogiannopoulos <address@hidden>
Date:   Tue May 18 23:41:22 2010 +0200

    Corrected bug in DSA signature generation.

commit 68b714494d6b99104897738ccec676a81be7a35d
Author: Nikos Mavrogiannopoulos <address@hidden>
Date:   Tue May 18 23:18:07 2010 +0200

    Added operations to sign CRLs, certificates and requests with an abstract 
key and thus with a PKCS #11 key as well.

commit 4d8be74bbc3b60f539bff11a20544d80339ff34f
Author: Nikos Mavrogiannopoulos <address@hidden>
Date:   Tue May 18 22:26:13 2010 +0200

    privkey.h -> abstract.h

commit 7235776221b10fb6ab2640dad84b8fde7a21055d
Author: Nikos Mavrogiannopoulos <address@hidden>
Date:   Tue May 18 22:17:34 2010 +0200

    The gnutls-cli --x509cafile can now be a PKCS #11 URL. It can read 
gnome-keyring's
    certificates and use them in the trusted list.

commit d3507b551241150eef8b4190b75a20ae235691ed
Author: Nikos Mavrogiannopoulos <address@hidden>
Date:   Sun May 16 14:08:27 2010 +0200

    Documented that gnutls_global_init calls gnutls_pkcs11_init.

commit a4ba092ab2aba436c51d8daba689afcdb0e3f517
Author: Nikos Mavrogiannopoulos <address@hidden>
Date:   Sun May 16 13:54:05 2010 +0200

    Only send termination request to avoid stalling on servers that do not 
reply.

commit 8a9c9c32af04230763435c638d824379db5bf92f
Author: Nikos Mavrogiannopoulos <address@hidden>
Date:   Sun May 16 13:53:03 2010 +0200

    Corrected issue on the %SSL3_RECORD_VERSION priority string. It now
    works even when resuming a session.

commit b25fd9c6d454492cfa2903fe9261372ceec4b17d
Author: Nikos Mavrogiannopoulos <address@hidden>
Date:   Sun May 16 12:06:33 2010 +0200

    Added initial example.

commit 56c7c519e0b2acf59b596e84389eddccae0110e3
Author: Nikos Mavrogiannopoulos <address@hidden>
Date:   Sun May 16 11:44:27 2010 +0200

    Corrections in openpgp private key usage.

commit e9966796a52634c40155e3e14cc02741a72f26fa
Author: Nikos Mavrogiannopoulos <address@hidden>
Date:   Sun May 16 11:13:21 2010 +0200

    Updated self tests and examples to avoid using deprecated functions such as
    gnutls_certificate_server_set_retrieve_function and the sign callback.

commit 4e825733ffc13cecd5c550ee3fee6b4607ebe19d
Author: Nikos Mavrogiannopoulos <address@hidden>
Date:   Sun May 16 11:04:23 2010 +0200

    Use the new callback function.

commit 2b4d022023d23fc820383222fca55ad6f57439b3
Author: Nikos Mavrogiannopoulos <address@hidden>
Date:   Sun May 16 10:56:13 2010 +0200

    Added documentation for most of the new functions.

commit 508523d16813a034a78eb7bfbd549addb7b04a9b
Author: Nikos Mavrogiannopoulos <address@hidden>
Date:   Sun May 16 09:42:35 2010 +0200

    Documented that it was initially based on neon pkcs11 and got ideas from 
pkcs11-helper library.

commit bd73a4d78c7255069ac34ba9ed47654af1230c1a
Author: Nikos Mavrogiannopoulos <address@hidden>
Date:   Sat May 15 23:43:30 2010 +0200

    Corrections to properly handle token removal and insert.

commit b3ed74e56063d6a501b32e22d19e42106c771a4c
Author: Nikos Mavrogiannopoulos <address@hidden>
Date:   Sat May 15 22:10:42 2010 +0200

    Deprecated the sign callback.

commit be560a8138daced8f37f2b6012e4417311dd4983
Author: Nikos Mavrogiannopoulos <address@hidden>
Date:   Sat May 15 22:00:22 2010 +0200

    Added gnutls_pkcs11_privkey_t and gnutls_privkey_t types. Those are
    an abstract private key type that can be used to sign/encrypt any private 
key
    of pkcs11,x509 or openpgp types. Added support for PKCS11 in 
gnutls-cli/gnutls-serv.

commit 2750317ca1d76ab6524b231e69af7ac152449fbf
Author: Nikos Mavrogiannopoulos <address@hidden>
Date:   Sat May 15 12:10:09 2010 +0200

    ignore unrelated to gnutls files.

commit fa40626c7d5841539d03cb43ec880eb5f35e3994
Author: Nikos Mavrogiannopoulos <address@hidden>
Date:   Mon May 10 23:35:33 2010 +0200

    Added several helper functions, to allow printing of tokens.

commit bbcdf1b0c3365174999b763fd6f6822ddc910f5a
Author: Nikos Mavrogiannopoulos <address@hidden>
Date:   Mon May 10 16:26:24 2010 +0200

    Added ability to export certificates from PKCS #11 tokens.
    Added ability to list trusted certificates, or only certificates
    with a corresponding private key or just all.

commit c67a003f2467fa3daf7ca2b85247df80c24e0ea2
Author: Nikos Mavrogiannopoulos <address@hidden>
Date:   Sun May 9 17:20:40 2010 +0200

    Added initial PKCS #11 support. Certtool can now print lists of certificates
    available in system.

commit 96febfef5a80a4e128683663e3cdc4a50f8db78c
Author: Nikos Mavrogiannopoulos <address@hidden>
Date:   Sun Mar 7 10:23:21 2010 +0100

    Optimized the check_if_same().

commit e5db8e4f2a7874ebd047e0744a41157f2ad50866
Author: Nikos Mavrogiannopoulos <address@hidden>
Date:   Wed Feb 24 23:32:27 2010 +0100

    Added a forgoten by god OID for RSA. Warn using the actual OID
    on unknown public key algorithms.

commit af81d19ac9a439a95464badce982e670fda3d217
Author: Jonathan Bastien-Filiatrault <address@hidden>
Date:   Wed Dec 9 22:03:04 2009 -0500

    Adapt session ticket support to mbuffer API.

commit 0731bfe19602c907d3e4e7693f7fef8bcd8eb58c
Author: Jonathan Bastien-Filiatrault <address@hidden>
Date:   Sun Aug 16 14:09:38 2009 -0400

    Use mbuffers for handshake synthesis.

commit c3b050f46e09be3a400f5002fa3a4ba655da813c
Author: Jonathan Bastien-Filiatrault <address@hidden>
Date:   Sat Aug 15 17:09:59 2009 -0400

    Make _gnutls_handshake_io_send_int accept a mbuffer_st.

commit 954644245d2a3744bf07053f534f3ffd7915e4e7
Author: Jonathan Bastien-Filiatrault <address@hidden>
Date:   Sat Aug 15 16:56:19 2009 -0400

    Simplify handshake send buffer logic.

commit b7ad62a4a8e2ff69dfc8cafb5ec3857a4170940c
Author: Jonathan Bastien-Filiatrault <address@hidden>
Date:   Sat Aug 15 16:49:21 2009 -0400

    Fix interrupted write braino.

commit 34da078a2f97501fcc2a97384f9b43beb0120951
Author: Jonathan Bastien-Filiatrault <address@hidden>
Date:   Sat Aug 15 14:37:23 2009 -0400

    Avoid pointer warning.

commit c8efb9f644163b690fab12cd18f0a0cd509b3e29
Author: Jonathan Bastien-Filiatrault <address@hidden>
Date:   Sat Aug 15 14:36:42 2009 -0400

    Remove now useless _gnutls_mbuffer_enqueue{,copy} functions.

commit df68b8d5f97bdb9ac6557236bf727762f19881bb
Author: Jonathan Bastien-Filiatrault <address@hidden>
Date:   Sat Aug 15 14:32:38 2009 -0400

    Allocate data buffer with mbuffer_st structure as suggested by Nikos.

commit 3404a413106394af03ceee9cf11dfd3e9c0789a3
Author: Jonathan Bastien-Filiatrault <address@hidden>
Date:   Sat Aug 15 14:07:15 2009 -0400

    Prepare for mbuffer allocation by the caller.

commit e84833017dc9c0724610e639043284644ad204d5
Author: Jonathan Bastien-Filiatrault <address@hidden>
Date:   Sat Aug 15 13:40:26 2009 -0400

    GNUify some missed GNUification.

commit b05d938180a057dfe0f6a8d64ac4acab41ab26fe
Author: Jonathan Bastien-Filiatrault <address@hidden>
Date:   Sat Aug 15 13:32:04 2009 -0400

    Harmonize read and write function names.

commit 715f13ad839679f953b8efc3052bc9f335a96a79
Author: Jonathan Bastien-Filiatrault <address@hidden>
Date:   Sat Aug 15 13:19:39 2009 -0400

    Now that LEVEL and LEVEL_EQ are fixed, use less lines.

commit 80fee6924dd72b17113a1e72e8d2930634f4a463
Author: Jonathan Bastien-Filiatrault <address@hidden>
Date:   Sat Aug 15 13:17:25 2009 -0400

    Make LEVEL and LEVEL_EQ macros safer.
    
    Once again, I got bit by this pretty hard.

commit b14cf0fdcd2d1af819522d36547e41730fa69fec
Author: Jonathan Bastien-Filiatrault <address@hidden>
Date:   Sun Aug 9 16:08:25 2009 -0400

    Use a datum for ciphered data in _gnutls_send_int.

commit 15f439814c233351c9390fd5d8c4c5f24a610ab0
Author: Jonathan Bastien-Filiatrault <address@hidden>
Date:   Sun Aug 9 15:50:26 2009 -0400

    Remove the prototype for the non-existant function 
_gnutls_io_write_buffered2.

commit 3ef62950845f551ebc629e50d5ddf75f71b84294
Author: Jonathan Bastien-Filiatrault <address@hidden>
Date:   Sun Aug 9 15:48:38 2009 -0400

    Cleanup of the remaining internals.record_send_buffer mess.

commit c6af0882e5d5e4439c6e3d76da82e05a928e9c1e
Author: Jonathan Bastien-Filiatrault <address@hidden>
Date:   Sun Aug 9 14:54:25 2009 -0400

    Remove yet another address@hidden instance of redundant hexadecimal dumping.

commit 599d0f21e62dea13273e7590841d8814319dae17
Author: Jonathan Bastien-Filiatrault <address@hidden>
Date:   Sun Aug 9 14:46:14 2009 -0400

    Modify slightly the contract of _gnutls_io_write_buffered as suggested
    by Nikos Mavrogiannopoulos.

commit 5217d518cdbe3e9cf32c3d72514d0f15242d67c2
Author: Jonathan Bastien-Filiatrault <address@hidden>
Date:   Sun Aug 9 14:30:54 2009 -0400

    Pass datums to mbuffers by address instead of by value.

commit f816631c8cdf8c1117248593ce3f9e6e40dea009
Author: Nikos Mavrogiannopoulos <address@hidden>
Date:   Sat Aug 8 09:06:57 2009 +0300

    Corrected case where handshake data were received during a session. It now 
stores them for future use by a gnutls_handshake(). Reported by Peter 
Hendrickson <address@hidden>.

commit a209eced7ce4fc698d27d16e3403441b452d9c0e
Author: Jonathan Bastien-Filiatrault <address@hidden>
Date:   Thu Aug 6 20:42:42 2009 -0400

    Simplify _gnutls_io_write_buffered and _gnutls_io_write_flush with mbuffers.

commit 9793a81f4fbafd8f0897f3d486ba5a5a9e8bca33
Author: Jonathan Bastien-Filiatrault <address@hidden>
Date:   Thu Aug 6 20:41:50 2009 -0400

    Change type of internals.record_send_buffer to a mbuffer.

commit 6b5b3c0db249855c768aeef1325e6be265f2f7cb
Author: Jonathan Bastien-Filiatrault <address@hidden>
Date:   Thu Aug 6 20:36:35 2009 -0400

    Extract a simple_write function from _gnutls_io_write_buffered.

commit 74c2bcd1cd9d46efac5a146aef3048e33aa557b8
Author: Jonathan Bastien-Filiatrault <address@hidden>
Date:   Thu Aug 6 20:32:49 2009 -0400

    Add dump_bytes function.

commit 95dd15a0b2bf4daff8f0bffa9903f71990d0156d
Author: Jonathan Bastien-Filiatrault <address@hidden>
Date:   Thu Aug 6 16:37:15 2009 -0400

    Add gnutls_mbuffers.{c,h} with some basic mbuffer operations.

commit 8aaf546f1c1b8a198f3bf69bb380bff9a47713fd
Author: Jonathan Bastien-Filiatrault <address@hidden>
Date:   Sat Aug 1 13:41:57 2009 -0400

    Do not rely on version ordering; use switch..case instead.

commit d1518b15a5da9ab713d14c8d7ccd2e7753ab1f8a
Author: Jonathan Bastien-Filiatrault <address@hidden>
Date:   Sat Aug 1 12:30:01 2009 -0400

    Remove hardcoded version checks in auth_cert.c.

commit 2600a35a98b9c7e1515fce23ea5b63a7bcf9a119
Author: Jonathan Bastien-Filiatrault <address@hidden>
Date:   Sat Aug 1 12:20:25 2009 -0400

    Remove hardcoded version check in gnutls_state.c.

commit 39f81e44822fc51b678ae6bf7cbc5aa8b8adead8
Author: Jonathan Bastien-Filiatrault <address@hidden>
Date:   Sat Aug 1 12:16:33 2009 -0400

    Remove hardcoded version checks in gnutls_cipher.c.

commit 8cb0a6412b655e67c81c71f82fb90c7e3761667c
Author: Jonathan Bastien-Filiatrault <address@hidden>
Date:   Sat Aug 1 12:00:52 2009 -0400

    Remove hardcoded version checks in gnutls_sig.c.

commit 8ddb4553ae1d90ba8778797402e75330530519e4
Author: Jonathan Bastien-Filiatrault <address@hidden>
Date:   Sat Aug 1 11:54:08 2009 -0400

    Remove hardcoded version checks in gnutls_handshake.c.

commit 9c8631c68a728584b46b7d2ceff2e872ae8a59dd
Author: Jonathan Bastien-Filiatrault <address@hidden>
Date:   Sat Aug 1 12:29:18 2009 -0400

    Add version check function for selectable signature/hash certificate 
algorithms.

commit 11e32e847614d1f0736584d83360efeb0d11e459
Author: Jonathan Bastien-Filiatrault <address@hidden>
Date:   Sat Aug 1 12:15:01 2009 -0400

    Add version check functions for non-minimal padding.

commit 493588c1a8a51cdb25429bf5865599f52d6303e3
Author: Jonathan Bastien-Filiatrault <address@hidden>
Date:   Sat Aug 1 12:06:02 2009 -0400

    Add version check function for explicit IV.

commit a2374cc6c1408e7d3e3d0f391f3b187a4626f82e
Author: Jonathan Bastien-Filiatrault <address@hidden>
Date:   Sat Aug 1 11:45:55 2009 -0400

    Add version check functions for selectable PRF and extension handling.

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

Summary of changes:
 .gitignore                                  |   61 +-
 NEWS                                        |  120 +-
 configure.ac                                |    5 +-
 doc/Makefile.am                             |    6 +-
 doc/TODO                                    |    4 -
 doc/cha-auth.texi                           |  462 +++
 doc/cha-bib.texi                            |  147 +
 doc/cha-cert-auth.texi                      |  671 +++++
 doc/cha-ciphersuites.texi                   |   44 +
 doc/cha-copying.texi                        |   29 +
 doc/cha-functions.texi                      |  120 +
 doc/cha-gtls-app.texi                       |  495 ++++
 doc/cha-internals.texi                      |  336 +++
 doc/cha-intro-tls.texi                      |  781 +++++
 doc/cha-library.texi                        |  188 ++
 doc/cha-preface.texi                        |  257 ++
 doc/cha-programs.texi                       |  853 ++++++
 doc/cha-tls-app.texi                        |  130 +
 doc/credentials/x509-server-dsa.pem         |   44 +-
 doc/credentials/x509-server-key-dsa.pem     |   28 +-
 doc/credentials/x509/key.pem                |   31 +-
 doc/examples/Makefile.am                    |    2 +-
 doc/examples/ex-cert-select-pkcs11.c        |  272 ++
 doc/examples/ex-cert-select.c               |    9 +-
 doc/examples/ex-crq.c                       |    6 +-
 doc/examples/ex-serv-export.c               |    5 -
 doc/examples/ex-serv-psk.c                  |    5 -
 doc/examples/ex-serv1.c                     |    5 -
 doc/gnutls.texi                             | 4273 +--------------------------
 doc/manpages/Makefile.am                    |    7 +-
 doc/manpages/gnutls-cli.1                   |    7 +-
 doc/pkcs11-vision.dia                       |  Bin 0 -> 2343 bytes
 doc/pkcs11-vision.png                       |  Bin 0 -> 22488 bytes
 lib/Makefile.am                             |   31 +-
 lib/auth_cert.c                             |  299 ++-
 lib/auth_cert.h                             |   17 +-
 lib/auth_dh_common.c                        |   11 +-
 lib/auth_dhe.c                              |    2 +-
 lib/auth_rsa.c                              |   78 +-
 lib/auth_rsa_export.c                       |  177 ++-
 lib/auth_srp.c                              |    8 +-
 lib/auth_srp_rsa.c                          |    2 +-
 lib/build-aux/config.rpath                  |   34 +-
 lib/configure.ac                            |    2 +
 lib/debug.c                                 |   13 +
 lib/debug.h                                 |    1 +
 lib/ext_session_ticket.c                    |   10 +-
 lib/gcrypt/Makefile.am                      |   34 +
 lib/{cipher-libgcrypt.c => gcrypt/cipher.c} |    0
 lib/{mac-libgcrypt.c => gcrypt/mac.c}       |    0
 lib/gcrypt/mpi.c                            |  415 +++
 lib/gcrypt/pk.c                             |  859 ++++++
 lib/{rnd-libgcrypt.c => gcrypt/rnd.c}       |    0
 lib/gnutls.pc.in                            |    2 +-
 lib/gnutls_algorithms.c                     |  180 ++-
 lib/gnutls_buffers.c                        |  467 +--
 lib/gnutls_buffers.h                        |   15 +-
 lib/gnutls_cert.c                           |   42 +-
 lib/gnutls_cert.h                           |   23 -
 lib/gnutls_cipher.c                         |    1 +
 lib/gnutls_constate.c                       |    6 +-
 lib/gnutls_dh_primes.c                      |   11 +-
 lib/gnutls_errors.c                         |   13 +-
 lib/gnutls_errors.h                         |    8 +-
 lib/gnutls_global.c                         |   15 +-
 lib/gnutls_handshake.c                      |  296 +-
 lib/gnutls_handshake.h                      |    6 +-
 lib/gnutls_int.h                            |   37 +-
 lib/gnutls_kx.c                             |   73 +-
 lib/gnutls_mbuffers.c                       |  169 ++
 lib/gnutls_mbuffers.h                       |   95 +
 lib/gnutls_mpi.c                            |    4 +-
 lib/gnutls_pk.c                             |   50 +
 lib/gnutls_pk.h                             |    5 +
 lib/gnutls_privkey.c                        |  324 ++
 lib/gnutls_psk.c                            |    2 +-
 lib/gnutls_pubkey.c                         |  938 ++++++
 lib/gnutls_record.c                         |   44 +-
 lib/gnutls_sig.c                            |   23 +-
 lib/gnutls_sig.h                            |    8 +-
 lib/gnutls_srp.c                            |   13 +-
 lib/gnutls_state.c                          |   13 +-
 lib/gnutls_state.h                          |    3 +
 lib/gnutls_str.c                            |  156 +-
 lib/gnutls_str.h                            |    5 +-
 lib/gnutls_x509.c                           |  576 +++--
 lib/gnutls_x509.h                           |    5 +-
 lib/gnutlsxx.cpp                            |   12 +-
 lib/includes/Makefile.am                    |    2 +-
 lib/includes/gnutls/abstract.h              |  122 +
 lib/includes/gnutls/compat.h                |   73 +-
 lib/includes/gnutls/crypto.h                |   11 +-
 lib/includes/gnutls/gnutls.h.in             |  117 +-
 lib/includes/gnutls/gnutlsxx.h              |    7 +-
 lib/includes/gnutls/openpgp.h               |    4 +
 lib/includes/gnutls/pkcs11.h                |  232 ++
 lib/includes/gnutls/x509.h                  |   24 +
 lib/libgnutls.map                           |   82 +-
 lib/libgnutlsxx.map                         |   17 +-
 lib/m4/hooks.m4                             |   64 +-
 lib/mpi-libgcrypt.c                         |  404 ---
 lib/nettle/Makefile.am                      |   34 +
 lib/nettle/cipher.c                         |  272 ++
 lib/nettle/mac.c                            |  290 ++
 lib/nettle/mpi.c                            |  591 ++++
 lib/nettle/pk.c                             |  546 ++++
 lib/nettle/rnd.c                            |  210 ++
 lib/opencdk/armor.c                         |   10 +-
 lib/opencdk/pubkey.c                        |    7 +-
 lib/opencdk/read-packet.c                   |   30 +-
 lib/opencdk/sig-check.c                     |    8 +-
 lib/opencdk/stream.c                        |   42 +-
 lib/opencdk/verify.c                        |    1 +
 lib/opencdk/write-packet.c                  |   20 +-
 lib/openpgp/gnutls_openpgp.c                |  232 +-
 lib/openpgp/gnutls_openpgp.h                |    3 +-
 lib/openpgp/openpgp_int.h                   |    2 -
 lib/openpgp/output.c                        |    2 +
 lib/openpgp/pgp.c                           |    3 +
 lib/openpgp/privkey.c                       |   46 +-
 lib/pakchois/errors.c                       |  146 +
 lib/pakchois/pakchois.c                     |  985 ++++++
 lib/pakchois/pakchois.h                     |  361 +++
 lib/pakchois/pakchois11.h                   | 1357 +++++++++
 lib/pk-libgcrypt.c                          |  812 -----
 lib/pkcs11.c                                | 2150 ++++++++++++++
 lib/pkcs11_int.h                            |   74 +
 lib/pkcs11_privkey.c                        |  396 +++
 lib/pkcs11_write.c                          |  511 ++++
 lib/pkix.asn                                |  104 -
 lib/pkix_asn1_tab.c                         |  160 +-
 lib/random.c                                |   16 +-
 lib/random.h                                |    3 +-
 lib/x509/common.c                           |  151 +-
 lib/x509/common.h                           |   21 +
 lib/x509/crl_write.c                        |   74 +-
 lib/x509/crq.c                              |  208 ++-
 lib/x509/dn.c                               |    9 +-
 lib/x509/mpi.c                              |   35 +-
 lib/x509/output.c                           |    2 +
 lib/x509/privkey.c                          |  493 +++-
 lib/x509/sign.c                             |  156 +-
 lib/x509/sign.h                             |    7 +
 lib/x509/verify.c                           |   71 +-
 lib/x509/x509.c                             |  132 +-
 lib/x509/x509_int.h                         |   38 +-
 lib/x509/x509_write.c                       |   75 +-
 src/Makefile.am                             |    2 +-
 src/certtool-common.h                       |   41 +-
 src/certtool-gaa.c                          |  520 +++-
 src/certtool-gaa.h                          |   56 +-
 src/certtool.c                              |  407 +++-
 src/certtool.gaa                            |   34 +-
 src/cli-gaa.c                               |    6 +-
 src/cli.c                                   |  222 +-
 src/cli.gaa                                 |    6 +-
 src/common.c                                |   50 +
 src/common.h                                |    2 +-
 src/crypt-gaa.c                             |   64 +-
 src/crypt.c                                 |    2 +-
 src/pkcs11.c                                |  408 +++
 src/prime.c                                 |    8 +-
 src/psk.c                                   |    2 +-
 src/serv-gaa.c                              |    6 +-
 src/serv.c                                  |   17 +-
 src/serv.gaa                                |    6 +-
 src/tests.c                                 |    6 +-
 tests/Makefile.am                           |    2 +-
 tests/chainverify.c                         |    2 +-
 tests/crq_key_id.c                          |    2 -
 tests/cve-2009-1416.c                       |    1 -
 tests/dn2.c                                 |    2 +-
 tests/mini-eagain.c                         |    9 +-
 tests/openpgpself.c                         |    2 +-
 tests/pathlen/ca-no-pathlen.pem             |    1 +
 tests/pathlen/no-ca-or-pathlen.pem          |    1 +
 tests/pkcs1-padding/pkcs1-pad               |   31 +-
 tests/pkcs12-decode/pkcs12                  |    3 +-
 tests/pkcs12_encode.c                       |   13 +-
 tests/pkcs12_s2k.c                          |    8 +-
 tests/pkcs12_s2k_pem.c                      |    1 -
 tests/pkcs8-decode/pkcs8                    |    3 +-
 tests/sha2/Makefile.am                      |    7 +-
 tests/sha2/key-ca-dsa.pem                   |   28 +
 tests/sha2/key-dsa.pem                      |   20 +
 tests/sha2/sha2                             |   37 +-
 tests/sha2/sha2-dsa                         |   65 +
 tests/userid/userid                         |   12 +-
 tests/x509dn.c                              |    4 +-
 tests/x509self.c                            |    1 +
 tests/x509signself.c                        |  509 ----
 191 files changed, 21153 insertions(+), 8567 deletions(-)
 create mode 100644 doc/cha-auth.texi
 create mode 100644 doc/cha-bib.texi
 create mode 100644 doc/cha-cert-auth.texi
 create mode 100644 doc/cha-ciphersuites.texi
 create mode 100644 doc/cha-copying.texi
 create mode 100644 doc/cha-functions.texi
 create mode 100644 doc/cha-gtls-app.texi
 create mode 100644 doc/cha-internals.texi
 create mode 100644 doc/cha-intro-tls.texi
 create mode 100644 doc/cha-library.texi
 create mode 100644 doc/cha-preface.texi
 create mode 100644 doc/cha-programs.texi
 create mode 100644 doc/cha-tls-app.texi
 create mode 100644 doc/examples/ex-cert-select-pkcs11.c
 create mode 100644 doc/pkcs11-vision.dia
 create mode 100644 doc/pkcs11-vision.png
 create mode 100644 lib/gcrypt/Makefile.am
 rename lib/{cipher-libgcrypt.c => gcrypt/cipher.c} (100%)
 rename lib/{mac-libgcrypt.c => gcrypt/mac.c} (100%)
 create mode 100644 lib/gcrypt/mpi.c
 create mode 100644 lib/gcrypt/pk.c
 rename lib/{rnd-libgcrypt.c => gcrypt/rnd.c} (100%)
 create mode 100644 lib/gnutls_mbuffers.c
 create mode 100644 lib/gnutls_mbuffers.h
 create mode 100644 lib/gnutls_privkey.c
 create mode 100644 lib/gnutls_pubkey.c
 create mode 100644 lib/includes/gnutls/abstract.h
 create mode 100644 lib/includes/gnutls/pkcs11.h
 delete mode 100644 lib/mpi-libgcrypt.c
 create mode 100644 lib/nettle/Makefile.am
 create mode 100644 lib/nettle/cipher.c
 create mode 100644 lib/nettle/mac.c
 create mode 100644 lib/nettle/mpi.c
 create mode 100644 lib/nettle/pk.c
 create mode 100644 lib/nettle/rnd.c
 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
 delete mode 100644 lib/pk-libgcrypt.c
 create mode 100644 lib/pkcs11.c
 create mode 100644 lib/pkcs11_int.h
 create mode 100644 lib/pkcs11_privkey.c
 create mode 100644 lib/pkcs11_write.c
 create mode 100644 lib/x509/sign.h
 create mode 100644 src/pkcs11.c
 create mode 100644 tests/sha2/key-ca-dsa.pem
 create mode 100644 tests/sha2/key-dsa.pem
 create mode 100755 tests/sha2/sha2-dsa
 delete mode 100644 tests/x509signself.c

diff --git a/.gitignore b/.gitignore
index 2676562..5b8643f 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
+ABOUT-NLS
 *.lo
 *.o
 *~
@@ -33,6 +34,19 @@ doc/credentials/srp/Makefile
 doc/credentials/srp/Makefile.in
 doc/credentials/x509/Makefile
 doc/credentials/x509/Makefile.in
+doc/gnutls.pdf
+doc/gnutls.toc
+doc/gnutls.cp
+doc/gnutls.cps
+doc/gnutls.fn
+doc/gnutls.fns
+doc/gnutls.ky
+doc/gnutls.log
+doc/gnutls.pg
+doc/gnutls.tp
+doc/gnutls.vr
+doc/gnutls.vrs
+doc/gnutls.aux
 doc/cyclo/Makefile
 doc/cyclo/Makefile.in
 doc/doxygen/Doxyfile
@@ -56,6 +70,8 @@ doc/examples/ex-serv-psk
 doc/examples/ex-serv-srp
 doc/examples/ex-serv1
 doc/examples/libexamples.la
+lib/gcrypt/libcrypto.la
+lib/nettle/libcrypto.la
 doc/extra-api.texi
 doc/extra.c.texi
 doc/gnutls-api.texi
@@ -246,40 +262,6 @@ lib/includes/gnutls/gnutls.h
 lib/libgnutls.la
 lib/libgnutlsxx.la
 lib/libtool
-lib/m4/codeset.m4
-lib/m4/gettext.m4
-lib/m4/glibc2.m4
-lib/m4/glibc21.m4
-lib/m4/iconv.m4
-lib/m4/intdiv0.m4
-lib/m4/intl.m4
-lib/m4/intldir.m4
-lib/m4/intlmacosx.m4
-lib/m4/intmax.m4
-lib/m4/inttypes-pri.m4
-lib/m4/inttypes_h.m4
-lib/m4/lcmessage.m4
-lib/m4/lib-ld.m4
-lib/m4/lib-link.m4
-lib/m4/lib-prefix.m4
-lib/m4/libtool.m4
-lib/m4/lock.m4
-lib/m4/longlong.m4
-lib/m4/ltoptions.m4
-lib/m4/ltsugar.m4
-lib/m4/ltversion.m4
-lib/m4/lt~obsolete.m4
-lib/m4/nls.m4
-lib/m4/po.m4
-lib/m4/printf-posix.m4
-lib/m4/progtest.m4
-lib/m4/size_max.m4
-lib/m4/stdint_h.m4
-lib/m4/uintmax_t.m4
-lib/m4/visibility.m4
-lib/m4/wchar_t.m4
-lib/m4/wint_t.m4
-lib/m4/xsize.m4
 lib/minitasn1/Makefile
 lib/minitasn1/Makefile.in
 lib/opencdk/Makefile
@@ -376,6 +358,7 @@ src/psktool
 src/srptool
 stamp-h1
 tests/Makefile
+tests/*/out
 tests/Makefile.in
 tests/anonself
 tests/certder
@@ -423,6 +406,11 @@ tests/pkcs8-decode/Makefile
 tests/pkcs8-decode/Makefile.in
 tests/pskself
 tests/resume
+tests/mini-x509
+tests/mini-x509-rehandshake
+tests/safe-renegotiation/srn1
+tests/safe-renegotiation/srn2
+tests/safe-renegotiation/srn3
 tests/rsa-md5-collision/Makefile
 tests/rsa-md5-collision/Makefile.in
 tests/safe-renegotiation/Makefile
@@ -441,3 +429,8 @@ tests/x509paths/
 tests/x509self
 tests/x509sign-verify
 tests/x509signself
+tests/safe-renegotiation/srn*
+m4/
+po/
+lib/m4
+lgl/
diff --git a/NEWS b/NEWS
index b0a060b..3d947da 100644
--- a/NEWS
+++ b/NEWS
@@ -3,24 +3,120 @@ Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005,
               2006, 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
 See the end for copying conditions.
 
-* Version 2.9.11 (unreleased)
+* Version 2.11.0 (unreleased)
+
+** libgnutls: Added support for DSA-SHA256 and DSA-SHA224
+
+** libgnutls: Added PKCS #11 support and an API to access objects in
+gnutls/pkcs11.h. Currently certificates and public keys can be
+imported from tokens, and operations can be performed on private keys.
+
+** libgnutls: Added abstract gnutls_privkey_t and gnutls_pubkey_t
+
+** libgnutls: Added initial support for the nettle library (unsupported)
+
+** libgnutls: Corrected issue on the %SSL3_RECORD_VERSION priority string. It 
now
+    works even when resuming a session.
+
+** libgnutls: Added gnutls_certificate_set_retrieve_function() to replace the
+similar gnutls_certificate_set_server_retrieve_function() and
+gnutls_certificate_set_client_retrieve_function(). In addition it support
+PKCS #11 private keys.
+
+** libgnutls: Added  gnutls_pkcs11_copy_x509_crt(), 
gnutls_pkcs11_copy_x509_privkey(),
+and gnutls_pkcs11_delete_url() to allow copying and deleting data in tokens.
+
+** libgnutls: Added gnutls_sec_param_to_pk_bits() et al. to allow select bit
+sizes for private keys using a human understandable scale.
+
+** certtool: Added new options: --pkcs11-list-tokens, --pkcs11-list-all
+--pkcs11-list-all-certs, --pkcs11-list-trusted, --pkcs11-list-certs,
+--pkcs11-delete-url, --pkcs11-write
+
+** gnutls-cli/gnutls-serv: --x509cafile, --x509certfile and --x509keyfile
+can now accept a PKCS #11 URL in addition to a file. This will allow for
+example to use the Gnome-keyring trusted certificate list to verify
+connections using a url such as:
+pkcs11:token=Root%20CA%20Certificates;serial=1%3AROOTS%3ADEFAULT;model=1%2E0;manufacturer=Gnome%20Keyring
+
+** API and ABI modifications:
+gnutls_certificate_set_server_retrieve_function: DEPRECATED
+gnutls_certificate_set_client_retrieve_function: DEPRECATED
+gnutls_sign_callback_set: DEPRECATED
+gnutls_pubkey_get_preferred_hash_algorithm: ADDED
+gnutls_x509_crt_get_preferred_hash_algorithm: ADDED
+gnutls_x509_privkey_export_rsa_raw2: ADDED
+gnutls_rnd: ADDED
+gnutls_sec_param_to_pk_bits: ADDED
+gnutls_pk_bits_to_sec_param: ADDED
+gnutls_sec_param_get_name: ADDED
+gnutls_pkcs11_type_get_name: ADDED
+gnutls_certificate_set_retrieve_function: ADDED
+gnutls_pkcs11_init: ADDED
+gnutls_pkcs11_deinit: ADDED
+gnutls_pkcs11_set_pin_function: ADDED
+gnutls_pkcs11_set_token_function: ADDED
+gnutls_pkcs11_add_provider: ADDED
+gnutls_pkcs11_obj_init: ADDED
+gnutls_pkcs11_obj_import_url: ADDED
+gnutls_pkcs11_obj_export_url: ADDED
+gnutls_pkcs11_obj_deinit: ADDED
+gnutls_pkcs11_obj_export: ADDED
+gnutls_pkcs11_obj_list_import_url: ADDED
+gnutls_pkcs11_obj_export: ADDED
+gnutls_x509_crt_import_pkcs11: ADDED
+gnutls_pkcs11_obj_get_type: ADDED
+gnutls_x509_crt_list_import_pkcs11: ADDED
+gnutls_x509_crt_import_pkcs11_url: ADDED
+gnutls_pkcs11_obj_get_info: ADDED
+gnutls_pkcs11_token_get_info: ADDED
+gnutls_pkcs11_token_get_url: ADDED
+gnutls_pkcs11_privkey_init: ADDED
+gnutls_pkcs11_privkey_deinit: ADDED
+gnutls_pkcs11_privkey_get_pk_algorithm: ADDED
+gnutls_pkcs11_privkey_get_info: ADDED
+gnutls_pkcs11_privkey_import_url: ADDED
+gnutls_pkcs11_privkey_sign_data: ADDED
+gnutls_pkcs11_privkey_sign_hash: ADDED
+gnutls_pkcs11_privkey_decrypt_data: ADDED
+gnutls_privkey_init: ADDED
+gnutls_privkey_deinit: ADDED
+gnutls_privkey_get_pk_algorithm: ADDED
+gnutls_privkey_get_type: ADDED
+gnutls_privkey_import_pkcs11: ADDED
+gnutls_privkey_import_x509: ADDED
+gnutls_privkey_import_openpgp: ADDED
+gnutls_privkey_sign_data: ADDED
+gnutls_privkey_sign_hash: ADDED
+gnutls_privkey_decrypt_data: ADDED
+gnutls_pkcs11_privkey_export_url: ADDED
+gnutls_x509_crq_privkey_sign: ADDED
+gnutls_x509_crl_privkey_sign: ADDED
+gnutls_x509_crt_privkey_sign: ADDED
+gnutls_pubkey_init: ADDED
+gnutls_pubkey_deinit: ADDED
+gnutls_pubkey_get_pk_algorithm: ADDED
+gnutls_pubkey_import_x509: ADDED
+gnutls_pubkey_import_openpgp: ADDED
+gnutls_pubkey_get_pk_rsa_raw: ADDED
+gnutls_pubkey_get_pk_dsa_raw: ADDED
+gnutls_pubkey_export: ADDED
+gnutls_pubkey_get_key_id: ADDED
+gnutls_pubkey_get_key_usage: ADDED
+gnutls_pubkey_verify_hash: ADDED
+gnutls_pubkey_get_verify_algorithm: ADDED
+gnutls_pkcs11_type_get_name: ADDED
+gnutls_pubkey_import_pkcs11_url: ADDED
+gnutls_pubkey_import: ADDED
+gnutls_pubkey_import_pkcs11: ADDED
+gnutls_pubkey_import_dsa_raw: ADDED
+gnutls_pubkey_import_rsa_raw: ADDED
+gnutls_x509_crt_set_pubkey: ADDED
+gnutls_x509_crq_set_pubkey: ADDED
+gnutls_pkcs11_copy_x509_crt: ADDED
+gnutls_pkcs11_copy_x509_privkey: ADDED
+gnutls_pkcs11_delete_url: ADDED
 
-** libgnutls: Removed two APIs related to safe renegotiation.
-Use priority strings instead.  The APIs were
-gnutls_safe_negotiation_set_initial and gnutls_safe_renegotiation_set.
-(Remember that we don't promise ABI stability during development
-series, so this doesn't cause an shared library ABI increment.)
-
-** tests: More self testing of safe renegotiation extension.
-See tests/safe-renegotiation/README for more information.
-
-** doc: a PDF version of the API reference manual (GTK-DOC) is now built.
-
-** doc: Terms 'GNUTLS' and 'GNU TLS' were changed to 'GnuTLS' for consistency.
-
-** API and ABI modifications:
-gnutls_safe_negotiation_set_initial: REMOVED.
-gnutls_safe_renegotiation_set: REMOVED.
 
 * Version 2.9.10 (released 2010-04-22)
 
diff --git a/configure.ac b/configure.ac
index ed6e69d..9438f87 100644
--- a/configure.ac
+++ b/configure.ac
@@ -74,7 +74,7 @@ AC_DEFINE([HAVE_CTYPE_H], 1, [Hard-code for src/cfg/.])
 AC_DEFINE([HAVE_ERRNO_H], 1, [Hard-code for src/cfg/.])
 
 # No fork on MinGW, disable some self-tests until we fix them.
-AC_CHECK_FUNCS(fork,,)
+AC_CHECK_FUNCS(fork getrusage,,)
 AM_CONDITIONAL(HAVE_FORK, test "$ac_cv_func_fork" != "no")
 
 AC_CHECK_TYPES(uint,,, [
@@ -203,7 +203,7 @@ AC_ARG_ENABLE([gcc-warnings],
 
 if test "$gl_gcc_warnings" = yes; then
   gl_WARN_ADD([-Werror], [WERROR_CFLAGS])
-  gl_WARN_ADD([-Wframe-larger-than=2100], [WSTACK_CFLAGS])
+  gl_WARN_ADD([-Wframe-larger-than=5120], [WSTACK_CFLAGS])
 
   nw="$nw -Wsystem-headers"         # Don't let system headers trigger warnings
   nw="$nw -Wc++-compat"             # We don't care about C++ compilers
@@ -305,4 +305,5 @@ AC_MSG_NOTICE([summary of build options:
   C++ library:      $use_cxx
   OpenSSL library:  $enable_openssl
   /dev/crypto:      $enable_cryptodev
+  Crypto library:   $cryptolib
 ])
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-auth.texi b/doc/cha-auth.texi
new file mode 100644
index 0000000..39da7a5
--- /dev/null
+++ b/doc/cha-auth.texi
@@ -0,0 +1,462 @@
address@hidden Authentication methods
address@hidden Authentication Methods
+
+The @acronym{TLS} protocol provides confidentiality and encryption,
+but also offers authentication, which is a prerequisite for a secure
+connection. The available authentication methods in @acronym{GnuTLS}
+are:
+
address@hidden
+
address@hidden Certificate authentication
+
address@hidden Anonymous authentication
+
address@hidden @acronym{SRP} authentication
+
address@hidden @acronym{PSK} authentication
+
address@hidden itemize
+
address@hidden
+* Certificate authentication::
+* Anonymous authentication::
+* Authentication using SRP::
+* Authentication using PSK::
+* Authentication and credentials::
+* Parameters stored in credentials::
address@hidden menu
+
address@hidden Certificate authentication
address@hidden Certificate Authentication
+
address@hidden Authentication Using @acronym{X.509} Certificates
address@hidden @acronym{X.509} certificates
+
address@hidden certificates contain the public parameters, of a
+public key algorithm, and an authority's signature, which proves the
+authenticity of the parameters.  @xref{The X.509 trust model}, for
+more information on @acronym{X.509} protocols.
+
address@hidden Authentication Using @acronym{OpenPGP} Keys
address@hidden @acronym{OpenPGP} Keys
+
address@hidden keys also contain public parameters of a public key
+algorithm, and signatures from several other parties. Depending on
+whether a signer is trusted the key is considered trusted or not.
address@hidden's @acronym{OpenPGP} authentication implementation is
+based on the @xcite{TLSPGP} proposal.
+
address@hidden OpenPGP trust model}, for more information about the
address@hidden trust model.  For a more detailed introduction to
address@hidden and @acronym{GnuPG} see @xcite{GPGH}.
+
address@hidden Using Certificate Authentication
+
+In @acronym{GnuTLS} both the @acronym{OpenPGP} and @acronym{X.509}
+certificates are part of the certificate authentication and thus are
+handled using a common API.
+
+When using certificates the server is required to have at least one
+certificate and private key pair. A client may or may not have such a
+pair. The certificate and key pair should be loaded, before any
address@hidden session is initialized, in a certificate credentials
+structure. This should be done by using
address@hidden or
address@hidden depending on the
+certificate type.  In the @acronym{X.509} case, the functions will
+also accept and use a certificate list that leads to a trusted
+authority. The certificate list must be ordered in such way that every
+certificate certifies the one before it. The trusted authority's
+certificate need not to be included, since the peer should possess it
+already.
+
+As an alternative, a callback may be used so the server or the client
+specify the certificate and the key at the handshake time.  That
+callback can be set using the functions:
+
address@hidden
+
address@hidden @ref{gnutls_certificate_server_set_retrieve_function}
+
address@hidden @ref{gnutls_certificate_client_set_retrieve_function}
+
address@hidden itemize
+
+Clients and servers that will select certificates using callback
+functions should select a certificate according the peer's signature
+algorithm preferences. To get those preferences use
address@hidden
+
+Certificate verification is possible by loading the trusted
+authorities into the credentials structure by using
address@hidden or
address@hidden for openpgp
+keys. Note however that the peer's certificate is not automatically
+verified, you should call @ref{gnutls_certificate_verify_peers2},
+after a successful handshake, to verify the signatures of the
+certificate.  An alternative way, which reports a more detailed
+verification output, is to use @ref{gnutls_certificate_get_peers} to
+obtain the raw certificate of the peer and verify it using the
+functions discussed in @ref{The X.509 trust model}.
+
+In a handshake, the negotiated cipher suite depends on the
+certificate's parameters, so not all key exchange methods will be
+available with some certificates. @acronym{GnuTLS} will disable
+ciphersuites that are not compatible with the key, or the enabled
+authentication methods.  For example keys marked as sign-only, will
+not be able to access the plain RSA ciphersuites, but only the
address@hidden ones. It is recommended not to use RSA keys for both
+signing and encryption. If possible use the same key for the
address@hidden and @code{RSA_EXPORT} ciphersuites, which use signing,
+and a different key for the plain RSA ciphersuites, which use
+encryption.  All the key exchange methods shown below are available in
+certificate authentication.
+
+Note that the DHE key exchange methods are generally
address@hidden really depends on the group used.  Primes with
+lesser bits are always faster, but also easier to break.  Values less
+than 768 should not be used today} than plain RSA and require Diffie
+Hellman parameters to be generated and associated with a credentials
+structure, by the server.  The @code{RSA-EXPORT} method also requires
+512 bit RSA parameters, that should also be generated and associated
+with the credentials structure.  See the functions:
+
address@hidden
+
address@hidden @ref{gnutls_dh_params_generate2}
+
address@hidden @ref{gnutls_certificate_set_dh_params}
+
address@hidden @ref{gnutls_rsa_params_generate2}
+
address@hidden @ref{gnutls_certificate_set_rsa_export_params}
+
address@hidden itemize
+
+Sometimes in order to avoid bottlenecks in programs it is usefull to
+store and read parameters from formats that can be generated by
+external programs such as @code{certtool}. This is possible with
address@hidden by using the following functions:
+
address@hidden
+
address@hidden @ref{gnutls_dh_params_import_pkcs3}
+
address@hidden @ref{gnutls_rsa_params_import_pkcs1}
+
address@hidden @ref{gnutls_dh_params_export_pkcs3}
+
address@hidden @ref{gnutls_rsa_params_export_pkcs1}
+
address@hidden itemize
+
+Key exchange algorithms for @acronym{OpenPGP} and @acronym{X.509}
+certificates:
+
address@hidden @code
+
address@hidden RSA:
+The RSA algorithm is used to encrypt a key and send it to the peer.
+The certificate must allow the key to be used for encryption.
+
address@hidden RSA_EXPORT:
+The RSA algorithm is used to encrypt a key and send it to the peer.
+In the EXPORT algorithm, the server signs temporary RSA parameters of
+512 bits --- which are considered weak --- and sends them to the
+client.
+
address@hidden DHE_RSA:
+The RSA algorithm is used to sign Ephemeral Diffie-Hellman parameters
+which are sent to the peer. The key in the certificate must allow the
+key to be used for signing. Note that key exchange algorithms which
+use Ephemeral Diffie-Hellman parameters, offer perfect forward
+secrecy. That means that even if the private key used for signing is
+compromised, it cannot be used to reveal past session data.
+
address@hidden DHE_DSS:
+The DSS algorithm is used to sign Ephemeral Diffie-Hellman parameters
+which are sent to the peer. The certificate must contain DSA
+parameters to use this key exchange algorithm. DSS stands for Digital
+Signature Standard.
+
address@hidden table
+
address@hidden Anonymous authentication
address@hidden Anonymous Authentication
address@hidden Anonymous authentication
+
+The anonymous key exchange performs encryption but there is no
+indication of the identity of the peer.  This kind of authentication
+is vulnerable to a man in the middle attack, but this protocol can be
+used even if there is no prior communication and trusted parties with
+the peer, or when full anonymity is required.  Unless really required,
+do not use anonymous authentication.  Available key exchange methods
+are shown below.
+
+Note that the key exchange methods for anonymous authentication
+require Diffie-Hellman parameters to be generated by the server and
+associated with an anonymous credentials structure.
+
+Supported anonymous key exchange algorithms:
+
address@hidden @code
+
address@hidden ANON_DH:
+This algorithm exchanges Diffie-Hellman parameters.
+
address@hidden table
+
address@hidden Authentication using SRP
address@hidden Authentication using @acronym{SRP}
address@hidden @acronym{SRP} authentication
+
+Authentication via the Secure Remote Password protocol,
address@hidden@address@hidden is described in @xcite{RFC2945}},
+is supported.  The @acronym{SRP} key exchange is an extension to the
address@hidden protocol, and it is a password based authentication
+(unlike @acronym{X.509} or @acronym{OpenPGP} that use certificates).
+The two peers can be identified using a single password, or there can
+be combinations where the client is authenticated using @acronym{SRP}
+and the server using a certificate.
+
+The advantage of @acronym{SRP} authentication, over other proposed
+secure password authentication schemes, is that @acronym{SRP} does not
+require the server to hold the user's password.  This kind of
+protection is similar to the one used traditionally in the @emph{UNIX}
address@hidden/etc/passwd} file, where the contents of this file did not cause
+harm to the system security if they were revealed.  The @acronym{SRP}
+needs instead of the plain password something called a verifier, which
+is calculated using the user's password, and if stolen cannot be used
+to impersonate the user. Check @xcite{TOMSRP} for a detailed
+description of the @acronym{SRP} protocol and the Stanford
address@hidden libraries, which includes a PAM module that synchronizes
+the system's users passwords with the @acronym{SRP} password
+files. That way @acronym{SRP} authentication could be used for all the
+system's users.
+
+The implementation in @acronym{GnuTLS} is based on paper
address@hidden  The supported @acronym{SRP} key exchange methods are:
+
address@hidden @code
+
address@hidden SRP:
+Authentication using the @acronym{SRP} protocol.
+
address@hidden SRP_DSS:
+Client authentication using the @acronym{SRP} protocol. Server is
+authenticated using a certificate with DSA parameters.
+
address@hidden SRP_RSA:
+Client authentication using the @acronym{SRP} protocol. Server is
+authenticated using a certificate with RSA parameters.
+
address@hidden table
+
+If clients supporting @acronym{SRP} know the username and password
+before the connection, should initialize the client credentials and
+call the function @ref{gnutls_srp_set_client_credentials}.
+Alternatively they could specify a callback function by using the
+function @ref{gnutls_srp_set_client_credentials_function}.  This has
+the advantage that allows probing the server for @acronym{SRP}
+support.  In that case the callback function will be called twice per
+handshake.  The first time is before the ciphersuite is negotiated,
+and if the callback returns a negative error code, the callback will
+be called again if @acronym{SRP} has been negotiated.  This uses a
+special @address@hidden handshake idiom in order to avoid,
+in interactive applications, to ask the user for @acronym{SRP}
+password and username if the server does not negotiate an
address@hidden ciphersuite.
+
+In server side the default behaviour of @acronym{GnuTLS} is to read
+the usernames and @acronym{SRP} verifiers from password files. These
+password files are the ones used by the @emph{Stanford srp libraries}
+and can be specified using the
address@hidden  If a different
+password file format is to be used, then the function
address@hidden, should be called,
+in order to set an appropriate callback.
+
+Some helper functions such as
+
address@hidden
+
address@hidden @ref{gnutls_srp_verifier}
+
address@hidden @ref{gnutls_srp_base64_encode}
+
address@hidden @ref{gnutls_srp_base64_decode}
+
address@hidden itemize
+
+are included in @acronym{GnuTLS}, and can be used to generate and
+maintain @acronym{SRP} verifiers and password files.  A program to
+manipulate the required parameters for @acronym{SRP} authentication is
+also included.  @xref{srptool}, for more information.
+
+
address@hidden Authentication using PSK
address@hidden Authentication using @acronym{PSK}
address@hidden @acronym{PSK} authentication
+
+Authentication using Pre-shared keys is a method to authenticate using
+usernames and binary keys. This protocol avoids making use of public
+key infrastructure and expensive calculations, thus it is suitable for
+constraint clients.
+
+The implementation in @acronym{GnuTLS} is based on paper
address@hidden  The supported @acronym{PSK} key exchange methods are:
+
address@hidden @code
+
address@hidden PSK:
+Authentication using the @acronym{PSK} protocol.
+
address@hidden DHE-PSK:
+Authentication using the @acronym{PSK} protocol and Diffie-Hellman key
+exchange.  This method offers perfect forward secrecy.
+
address@hidden table
+
+Clients supporting @acronym{PSK} should supply the username and key
+before the connection to the client credentials by calling the
+function @ref{gnutls_psk_set_client_credentials}.  Alternatively they
+could specify a callback function by using the function
address@hidden  This has the
+advantage that the callback will be called only if @acronym{PSK} has
+been negotiated.
+
+In server side the default behaviour of @acronym{GnuTLS} is to read
+the usernames and @acronym{PSK} keys from a password file. The
+password file should contain usernames and keys in hexadecimal
+format. The name of the password file can be stored to the credentials
+structure by calling @ref{gnutls_psk_set_server_credentials_file}.  If
+a different password file format is to be used, then the function
address@hidden, should be used
+instead.
+
+The server can help the client chose a suitable username and password,
+by sending a hint.  In the server, specify the hint by calling
address@hidden  The client can retrieve
+the hint, for example in the callback function, using
address@hidden
+
+There is no standard mechanism to derive a PSK key from a password
+specified by the TLS PSK document.  However, GnuTLS provides
address@hidden which follows the algorithm
+specified in @file{draft-ietf-netconf-tls-02.txt}.
+
+Some helper functions such as:
+
address@hidden
+
address@hidden @ref{gnutls_hex_encode}
+
address@hidden @ref{gnutls_hex_decode}
+
address@hidden itemize
+
+are included in @acronym{GnuTLS}, and may be used to generate and
+maintain @acronym{PSK} keys.
+
+
address@hidden Authentication and credentials
address@hidden Authentication and Credentials
+
+In @acronym{GnuTLS} every key exchange method is associated with a
+credentials type. So in order to enable to enable a specific method,
+the corresponding credentials type should be initialized and set using
address@hidden  A mapping is shown below.
+
+Key exchange algorithms and the corresponding credential types:
+
address@hidden @columnfractions .3 .3 .3
+
address@hidden Key exchange @tab Client credentials @tab Server credentials
+
address@hidden @code{KX_RSA}
address@hidden @code{KX_DHE_RSA}
address@hidden @code{KX_DHE_DSS}
address@hidden @code{KX_RSA_EXPORT}
address@hidden @code{CRD_CERTIFICATE}
address@hidden @code{CRD_CERTIFICATE}
+
address@hidden @code{KX_SRP_RSA}
address@hidden @code{CRD_SRP}
address@hidden @code{CRD_SRP}
address@hidden @code{KX_SRP_DSS}
address@hidden
address@hidden @code{CRD_CERTIFICATE}
+
address@hidden @code{KX_SRP}
address@hidden @code{CRD_SRP}
address@hidden @code{CRD_SRP}
+
address@hidden @code{KX_ANON_DH}
address@hidden @code{CRD_ANON}
address@hidden @code{CRD_ANON}
+
address@hidden @code{KX_PSK}
address@hidden @code{CRD_PSK}
address@hidden @code{CRD_PSK}
+
address@hidden multitable
+
address@hidden Parameters stored in credentials
address@hidden Parameters Stored in Credentials
+
+Several parameters such as the ones used for Diffie-Hellman
+authentication are stored within the credentials structures, so all
+sessions can access them. Those parameters are stored in structures
+such as @code{gnutls_dh_params_t} and @code{gnutls_rsa_params_t}, and
+functions like @ref{gnutls_certificate_set_dh_params} and
address@hidden can be used to
+associate those parameters with the given credentials structure.
+
+Since those parameters need to be renewed from time to time and a
+global structure such as the credentials, may not be easy to modify
+since it is accessible by all sessions, an alternative interface is
+available using a callback function.  This can be set using the
address@hidden  An example is shown
+below.
+
address@hidden
+#include <gnutls.h>
+
+gnutls_rsa_params_t rsa_params;
+gnutls_dh_params_t dh_params;
+
+/* This function will be called once a session requests DH
+ * or RSA parameters. The parameters returned (if any) will
+ * be used for the first handshake only.
+ */
+static int get_params( gnutls_session_t session,
+        gnutls_params_type_t type,
+        gnutls_params_st *st)
address@hidden
+   if (type == GNUTLS_PARAMS_RSA_EXPORT)
+      st->params.rsa_export = rsa_params;
+   else if (type == GNUTLS_PARAMS_DH)
+      st->params.dh = dh_params;
+   else return -1;
+
+   st->type = type;
+   /* do not deinitialize those parameters.
+    */
+   st->deinit = 0;
+
+   return 0;
address@hidden
+
+int main()
address@hidden
+   gnutls_certificate_credentials_t cert_cred;
+
+   initialize_params();
+
+   /* ...
+    */
+
+   gnutls_certificate_set_params_function( cert_cred, get_params);
address@hidden
address@hidden example
diff --git a/doc/cha-bib.texi b/doc/cha-bib.texi
new file mode 100644
index 0000000..792bc8c
--- /dev/null
+++ b/doc/cha-bib.texi
@@ -0,0 +1,147 @@
address@hidden Bibliography
address@hidden Bibliography
+
address@hidden @asis
+
address@hidden @anchor{CBCATT}[CBCATT]
+Bodo Moeller, "Security of CBC Ciphersuites in SSL/TLS: Problems and
+Countermeasures", 2002, available from
address@hidden://www.openssl.org/~bodo/tls-cbc.txt}.
+
address@hidden @anchor{GPGH}[GPGH]
+Mike Ashley, "The GNU Privacy Handbook", 2002, available from
address@hidden://www.gnupg.org/gph/en/manual.pdf}.
+
address@hidden @anchor{GUTPKI}[GUTPKI]
+Peter Gutmann, "Everything you never wanted to know about PKI but were
+forced to find out", Available from
address@hidden://www.cs.auckland.ac.nz/~pgut001/}.
+
address@hidden @anchor{NISTSP80057}[NISTSP80057]
+NIST Special Publication 800-57, "Recommendation for Key Management -
+Part 1: General (Revised)", March 2007, available from
address@hidden://csrc.nist.gov/publications/nistpubs/800-57/sp800-57-Part1-revised2_Mar08-2007.pdf}.
+
address@hidden @anchor{RFC2246}[RFC2246]
+Tim Dierks and Christopher Allen, "The TLS Protocol Version 1.0",
+January 1999, Available from
address@hidden://www.ietf.org/rfc/rfc2246.txt}.
+
address@hidden @anchor{RFC4346}[RFC4346]
+Tim Dierks and Eric Rescorla, "The TLS Protocol Version 1.1", Match
+2006, Available from @url{http://www.ietf.org/rfc/rfc4346.txt}.
+
address@hidden @anchor{RFC2440}[RFC2440]
+Jon Callas, Lutz Donnerhacke, Hal Finney and Rodney Thayer, "OpenPGP
+Message Format", November 1998, Available from
address@hidden://www.ietf.org/rfc/rfc2440.txt}.
+
address@hidden @anchor{RFC4880}[RFC4880]
+Jon Callas, Lutz Donnerhacke, Hal Finney, David Shaw and Rodney
+Thayer, "OpenPGP Message Format", November 2007, Available from
address@hidden://www.ietf.org/rfc/rfc4880.txt}.
+
address@hidden @anchor{RFC4211}[RFC4211]
+J. Schaad, "Internet X.509 Public Key Infrastructure Certificate
+Request Message Format (CRMF)", September 2005, Available from
address@hidden://www.ietf.org/rfc/rfc4211.txt}.
+
address@hidden @anchor{RFC2817}[RFC2817]
+Rohit Khare and Scott Lawrence, "Upgrading to TLS Within HTTP/1.1",
+May 2000, Available from @url{http://www.ietf.org/rfc/rfc2817.txt}
+
address@hidden @anchor{RFC2818}[RFC2818]
+Eric Rescorla, "HTTP Over TLS", May 2000, Available from
address@hidden://www.ietf/rfc/rfc2818.txt}.
+
address@hidden @anchor{RFC2945}[RFC2945]
+Tom Wu, "The SRP Authentication and Key Exchange System", September
+2000, Available from @url{http://www.ietf.org/rfc/rfc2945.txt}.
+
address@hidden @anchor{RFC2986}[RFC2986]
+Magnus Nystrom and Burt Kaliski, "PKCS 10 v1.7: Certification Request
+Syntax Specification", November 2000, Available from
address@hidden://www.ietf.org/rfc/rfc2986.txt}.
+
address@hidden @anchor{PKIX}[PKIX]
+D. Cooper, S. Santesson, S. Farrel, S. Boeyen, R. Housley, W. Polk,
+"Internet X.509 Public Key Infrastructure Certificate and Certificate
+Revocation List (CRL) Profile", May 2008, available from
address@hidden://www.ietf.org/rfc/rfc5280.txt}.
+
address@hidden @anchor{RFC3749}[RFC3749]
+Scott Hollenbeck, "Transport Layer Security Protocol Compression
+Methods", May 2004, available from
address@hidden://www.ietf.org/rfc/rfc3749.txt}.
+
address@hidden @anchor{RFC3820}[RFC3820]
+Steven Tuecke, Von Welch, Doug Engert, Laura Pearlman, and Mary
+Thompson, "Internet X.509 Public Key Infrastructure (PKI) Proxy
+Certificate Profile", June 2004, available from
address@hidden://www.ietf.org/rfc/rfc3820}.
+
address@hidden @anchor{RFC5746}[RFC5746]
+E. Rescorla, M. Ray, S. Dispensa, and N. Oskov, "Transport Layer
+Security (TLS) Renegotiation Indication Extension", February 2010,
+available from @url{http://www.ietf.org/rfc/rfc5746}.
+
address@hidden @anchor{TLSTKT}[TLSTKT]
+Joseph Salowey, Hao Zhou, Pasi Eronen, Hannes Tschofenig, "Transport
+Layer Security (TLS) Session Resumption without Server-Side State",
+January 2008, available from @url{http://www.ietf.org/rfc/rfc5077}.
+
address@hidden @anchor{PKCS12}[PKCS12]
+RSA Laboratories, "PKCS 12 v1.0: Personal Information Exchange
+Syntax", June 1999, Available from @url{http://www.rsa.com}.
+
address@hidden @anchor{PKCS11}[PKCS11]
+RSA Laboratories, "PKCS #11 Base Functionality v2.30: Cryptoki – Draft 4",
+July 2009, Available from @url{http://www.rsa.com}.
+
address@hidden @anchor{RESCORLA}[RESCORLA]
+Eric Rescorla, "SSL and TLS: Designing and Building Secure Systems",
+2001
+
address@hidden @anchor{SELKEY}[SELKEY]
+Arjen Lenstra and Eric Verheul, "Selecting Cryptographic Key Sizes",
+2003, available from @url{http://www.win.tue.nl/~klenstra/key.pdf}.
+
address@hidden @anchor{SSL3}[SSL3]
+Alan Freier, Philip Karlton and Paul Kocher, "The SSL Protocol Version
+3.0", November 1996, Available from
address@hidden://wp.netscape.com/eng/ssl3/draft302.txt}.
+
address@hidden @anchor{STEVENS}[STEVENS]
+Richard Stevens, "UNIX Network Programming, Volume 1", Prentice Hall
+PTR, January 1998
+
address@hidden @anchor{TLSEXT}[TLSEXT]
+Simon Blake-Wilson, Magnus Nystrom, David Hopwood, Jan Mikkelsen and
+Tim Wright, "Transport Layer Security (TLS) Extensions", June 2003,
+Available from @url{http://www.ietf.org/rfc/rfc3546.txt}.
+
address@hidden @anchor{TLSPGP}[TLSPGP]
+Nikos Mavrogiannopoulos, "Using OpenPGP keys for TLS authentication",
+April 2004, November 2007. Available from
address@hidden://www.ietf.org/rfc/rfc5081.txt}.
+
address@hidden @anchor{TLSSRP}[TLSSRP]
+David Taylor, Trevor Perrin, Tom Wu and Nikos Mavrogiannopoulos,
+"Using SRP for TLS Authentication", November 2007. Available from
address@hidden://www.ietf.org/rfc/rfc5054.txt}.
+
address@hidden @anchor{TLSPSK}[TLSPSK]
+Pasi Eronen and Hannes Tschofenig, "Pre-shared key Ciphersuites for
+TLS", December 2005, Available from
address@hidden://www.ietf.org/rfc/rfc4279.txt}.
+
address@hidden @anchor{TOMSRP}[TOMSRP]
+Tom Wu, "The Stanford SRP Authentication Project", Available at
address@hidden://srp.stanford.edu/}.
+
address@hidden @anchor{WEGER}[WEGER]
+Arjen Lenstra and Xiaoyun Wang and Benne de Weger, "Colliding X.509
+Certificates", Cryptology ePrint Archive, Report 2005/067, Available
+at @url{http://eprint.iacr.org/}.
+
address@hidden table
diff --git a/doc/cha-cert-auth.texi b/doc/cha-cert-auth.texi
new file mode 100644
index 0000000..68999e1
--- /dev/null
+++ b/doc/cha-cert-auth.texi
@@ -0,0 +1,671 @@
address@hidden More on certificate authentication
address@hidden More on Certificate Authentication
address@hidden Authentication}
address@hidden Certificate authentication
+
address@hidden
+* The X.509 trust model::
+* The OpenPGP trust model::
+* PKCS #11 tokens::
+* Abstract data types::
+* Digital signatures::
address@hidden menu
+
address@hidden The X.509 trust model
address@hidden The @acronym{X.509} Trust Model
address@hidden @acronym{X.509} certificates
+
+The @acronym{X.509} protocols rely on a hierarchical trust model. In
+this trust model Certification Authorities (CAs) are used to certify
+entities.  Usually more than one certification authorities exist, and
+certification authorities may certify other authorities to issue
+certificates as well, following a hierarchical model.
+
address@hidden,7cm,9.5cm}
+
+One needs to trust one or more CAs for his secure communications. In
+that case only the certificates issued by the trusted authorities are
+acceptable.  See the figure above for a typical example.  The API for
+handling @acronym{X.509} certificates is described at section
address@hidden:x509api}.  Some examples are listed below.
+
address@hidden
+* X.509 certificates::
+* Verifying X.509 certificate paths::
+* PKCS #10 certificate requests::
+* PKCS #12 structures::
address@hidden menu
+
address@hidden X.509 certificates
address@hidden @acronym{X.509} Certificates
+
+An @acronym{X.509} certificate usually contains information about the
+certificate holder, the signer, a unique serial number, expiration
+dates and some other fields @xcite{PKIX} as shown in the table below.
+
address@hidden @code
+
address@hidden version:
+The field that indicates the version of the certificate.
+
address@hidden serialNumber:
+This field holds a unique serial number per certificate.
+
address@hidden issuer:
+Holds the issuer's distinguished name.
+
address@hidden validity:
+The activation and expiration dates.
+
address@hidden subject:
+The subject's distinguished name of the certificate.
+
address@hidden extensions:
+The extensions are fields only present in version 3 certificates.
+
address@hidden table
+
+The certificate's @emph{subject or issuer name} is not just a single
+string.  It is a Distinguished name and in the @acronym{ASN.1}
+notation is a sequence of several object IDs with their corresponding
+values. Some of available OIDs to be used in an @acronym{X.509}
+distinguished name are defined in @file{gnutls/x509.h}.
+
+The @emph{Version} field in a certificate has values either 1 or 3 for
+version 3 certificates.  Version 1 certificates do not support the
+extensions field so it is not possible to distinguish a CA from a
+person, thus their usage should be avoided.
+
+The @emph{validity} dates are there to indicate the date that the
+specific certificate was activated and the date the certificate's key
+would be considered invalid.
+
+Certificate @emph{extensions} are there to include information about
+the certificate's subject that did not fit in the typical certificate
+fields. Those may be e-mail addresses, flags that indicate whether the
+belongs to a CA etc.  All the supported @acronym{X.509} version 3
+extensions are shown in the table below.
+
address@hidden @code
+
address@hidden subject key id (2.5.29.14):
+An identifier of the key of the subject.
+
address@hidden authority key id (2.5.29.35):
+An identifier of the authority's key used to sign the certificate.
+
address@hidden subject alternative name (2.5.29.17):
+Alternative names to subject's distinguished name.
+
address@hidden key usage (2.5.29.15):
+Constraints the key's usage of the certificate.
+
address@hidden extended key usage (2.5.29.37):
+Constraints the purpose of the certificate.
+
address@hidden basic constraints (2.5.29.19):
+Indicates whether this is a CA certificate or not, and specify the
+maximum path lengths of certificate chains.
+
address@hidden CRL distribution points (2.5.29.31):
+This extension is set by the CA, in order to inform about the issued
+CRLs.
+
address@hidden Proxy Certification Information (1.3.6.1.5.5.7.1.14):
+Proxy Certificates includes this extension that contains the OID of
+the proxy policy language used, and can specify limits on the maximum
+lengths of proxy chains.  Proxy Certificates are specified in
address@hidden
+
address@hidden table
+
+In @acronym{GnuTLS} the @acronym{X.509} certificate structures are
+handled using the @code{gnutls_x509_crt_t} type and the corresponding
+private keys with the @code{gnutls_x509_privkey_t} type.  All the
+available functions for @acronym{X.509} certificate handling have
+their prototypes in @file{gnutls/x509.h}. An example program to
+demonstrate the @acronym{X.509} parsing capabilities can be found at
+section @ref{ex:x509-info}.
+
address@hidden Verifying X.509 certificate paths
address@hidden Verifying @acronym{X.509} Certificate Paths
address@hidden Verifying certificate paths
+
+Verifying certificate paths is important in @acronym{X.509}
+authentication. For this purpose the function
address@hidden is provided. The output of this function
+is the bitwise OR of the elements of the
address@hidden enumeration.  A detailed
+description of these elements can be found in figure below.  The
+function @ref{gnutls_certificate_verify_peers2} is equivalent to the
+previous one, and will verify the peer's certificate in a TLS session.
+
address@hidden @code
+
address@hidden GNUTLS_CERT_INVALID:
+The certificate is not signed by one of the known authorities, or
+the signature is invalid.
+
address@hidden GNUTLS_CERT_REVOKED:
+The certificate has been revoked by its CA.
+
address@hidden GNUTLS_CERT_SIGNER_NOT_FOUND:
+The certificate's issuer is not known. This is the case when the
+issuer is not in the trusted certificates list.
+
address@hidden GNUTLS_CERT_SIGNER_NOT_CA:
+The certificate's signer was not a CA. This may happen if
+this was a version 1 certificate, which is common with some CAs, or
+a version 3 certificate without the basic constrains extension.
+
address@hidden
address@hidden GNUTLS_CERT_INSECURE_ALGORITHM:
+The certificate was signed using an insecure algorithm such as MD2 or
+MD5.  These algorithms have been broken and should not be trusted.
+
address@hidden table
+
+There is also to possibility to pass some input to the verification
+functions in the form of flags. For @ref{gnutls_x509_crt_verify} the
+flags are passed straightforward, but
address@hidden depends on the flags set by
+calling @ref{gnutls_certificate_set_verify_flags}.  All the available
+flags are part of the enumeration
address@hidden and are explained in the table
+below.
+
address@hidden
address@hidden gnutls_certificate_verify_flags
address@hidden @code
address@hidden GNUTLS_VERIFY_DISABLE_CA_SIGN:
+If set a signer does not have to be a certificate authority. This
+flag should normaly be disabled, unless you know what this means.
+
address@hidden GNUTLS_VERIFY_ALLOW_X509_V1_CA_CRT:
+Allow only trusted CA certificates that have version 1.  This is
+safer than GNUTLS_VERIFY_ALLOW_ANY_X509_V1_CA_CRT, and should be
+used instead. That way only signers in your trusted list will be
+allowed to have certificates of version 1.
+
address@hidden GNUTLS_VERIFY_ALLOW_ANY_X509_V1_CA_CRT:
+Allow CA certificates that have version 1 (both root and
+intermediate). This is dangerous since those haven't the
+basicConstraints extension. Must be used in combination with
+GNUTLS_VERIFY_ALLOW_X509_V1_CA_CRT.
+
address@hidden GNUTLS_VERIFY_DO_NOT_ALLOW_SAME:
+If a certificate is not signed by anyone trusted but exists in
+the trusted CA list do not treat it as trusted.
+
address@hidden GNUTLS_VERIFY_ALLOW_SIGN_RSA_MD2:
+Allow certificates to be signed using the old MD2 algorithm.
+
address@hidden GNUTLS_VERIFY_ALLOW_SIGN_RSA_MD5:
+Allow certificates to be signed using the broken MD5 algorithm.
address@hidden table
+
+Although the verification of a certificate path indicates that the
+certificate is signed by trusted authority, does not reveal anything
+about the peer's identity. It is required to verify if the
+certificate's owner is the one you expect. For more information
+consult @xcite{RFC2818} and section @ref{ex:verify} for an example.
+
address@hidden PKCS #10 certificate requests
address@hidden @acronym{PKCS} #10 Certificate Requests
address@hidden Certificate requests
address@hidden @acronym{PKCS} #10
+
+A certificate request is a structure, which contain information about
+an applicant of a certificate service.  It usually contains a private
+key, a distinguished name and secondary data such as a challenge
+password. @acronym{GnuTLS} supports the requests defined in
address@hidden #10 @xcite{RFC2986}. Other certificate request's format
+such as PKIX's @xcite{RFC4211} are not currently supported.
+
+In @acronym{GnuTLS} the @acronym{PKCS} #10 structures are handled
+using the @code{gnutls_x509_crq_t} type.  An example of a certificate
+request generation can be found at section @ref{ex:crq}.
+
address@hidden PKCS #12 structures
address@hidden @acronym{PKCS} #12 Structures
address@hidden @acronym{PKCS} #12
+
+A @acronym{PKCS} #12 structure @xcite{PKCS12} usually contains a user's
+private keys and certificates. It is commonly used in browsers to
+export and import the user's identities.
+
+In @acronym{GnuTLS} the @acronym{PKCS} #12 structures are handled
+using the @code{gnutls_pkcs12_t} type. This is an abstract type that
+may hold several @code{gnutls_pkcs12_bag_t} types.  The Bag types are
+the holders of the actual data, which may be certificates, private
+keys or encrypted data.  An Bag of type encrypted should be decrypted
+in order for its data to be accessed.
+
+An example of a @acronym{PKCS} #12 structure generation can be found
+at section @ref{ex:pkcs12}.
+
address@hidden The OpenPGP trust model
address@hidden The @acronym{OpenPGP} Trust Model
address@hidden @acronym{OpenPGP} Keys
+
+The @acronym{OpenPGP} key authentication relies on a distributed trust
+model, called the ``web of trust''. The ``web of trust'' uses a
+decentralized system of trusted introducers, which are the same as a
+CA. @acronym{OpenPGP} allows anyone to sign anyone's else public
+key. When Alice signs Bob's key, she is introducing Bob's key to
+anyone who trusts Alice. If someone trusts Alice to introduce keys,
+then Alice is a trusted introducer in the mind of that observer.
+
address@hidden,11cm,9cm}
+
+For example: If David trusts Alice to be an introducer, and Alice
+signed Bob's key, Dave also trusts Bob's key to be the real one.
+
+There are some key points that are important in that model. In the
+example Alice has to sign Bob's key, only if she is sure that the key
+belongs to Bob. Otherwise she may also make Dave falsely believe that
+this is Bob's key. Dave has also the responsibility to know who to
+trust.  This model is similar to real life relations.
+
+Just see how Charlie behaves in the previous example. Although he has
+signed Bob's key - because he knows, somehow, that it belongs to Bob -
+he does not trust Bob to be an introducer. Charlie decided to trust
+only Kevin, for some reason. A reason could be that Bob is lazy
+enough, and signs other people's keys without being sure that they
+belong to the actual owner.
+
address@hidden @acronym{OpenPGP} Keys
+
+In @acronym{GnuTLS} the @acronym{OpenPGP} key structures
address@hidden are handled using the @code{gnutls_openpgp_crt_t} type
+and the corresponding private keys with the
address@hidden type. All the prototypes for the key
+handling functions can be found at @file{gnutls/openpgp.h}.
+
address@hidden Verifying an @acronym{OpenPGP} Key
+
+The verification functions of @acronym{OpenPGP} keys, included in
address@hidden, are simple ones, and do not use the features of the
+``web of trust''.  For that reason, if the verification needs are
+complex, the assistance of external tools like @acronym{GnuPG} and
+GPGME (@url{http://www.gnupg.org/related_software/gpgme/}) is
+recommended.
+
+There is one verification function in @acronym{GnuTLS}, the
address@hidden  This checks an
address@hidden key against a given set of public keys (keyring) and
+returns the key status. The key verification status is the same as in
address@hidden certificates, although the meaning and interpretation
+are different. For example an @acronym{OpenPGP} key may be valid, if
+the self signature is ok, even if no signers were found.  The meaning
+of verification status is shown in the figure below.
+
address@hidden @code
+
address@hidden CERT_INVALID:
+A signature on the key is invalid. That means that the key was
+modified by somebody, or corrupted during transport.
+
address@hidden CERT_REVOKED:
+The key has been revoked by its owner.
+
address@hidden CERT_SIGNER_NOT_FOUND:
+The key was not signed by a known signer.
+
address@hidden GNUTLS_CERT_INSECURE_ALGORITHM:
+The certificate was signed using an insecure algorithm such as MD2 or
+MD5.  These algorithms have been broken and should not be trusted.
+
address@hidden table
+
+
address@hidden PKCS #11 tokens
address@hidden @acronym{PKCS #11} tokens
address@hidden:pkcs11}
address@hidden @acronym{PKCS #11} tokens
+
address@hidden Introduction
+This section copes with the @acronym{PKCS #11} @xcite{PKCS11} support in 
@acronym{GnuTLS}.
address@hidden #11} is plugin API allowing applications to access cryptographic
+operations on a token, as well as to objects residing on the token. A token 
can 
+be a real hardware token such as a smart card, or it can be a software 
component
+such as @acronym{Gnome Keyring}. The objects residing on such token can be
+certificates, public keys, private keys or even plain data or  secret keys. Of 
those
+certificates and public/private key pairs can be used with @acronym{GnuTLS}. 
It's
+main advantage is that it allows operations on private key objects such as 
decryption
+and signing without accessing the key itself.
+
+Moreover it can be used to allow all applications in the same operating system 
to access
+shared cryptographic keys and certificates in a uniform way, as in the 
following picture.
+
address@hidden
+
address@hidden Initialization
+To allow all the  @acronym{GnuTLS} applications to access @acronym{PKCS #11} 
tokens
+it is adviceable to use @code{/etc/gnutls/pkcs11.conf}. This file has the 
following
+format:
+
address@hidden
+load=/usr/lib/opensc-pkcs11.so
+load=/usr/lib/gnome-keyring/gnome-keyring-pkcs11.so
address@hidden verbatim
+
+If you use this file, then there is no need for other initialization in
address@hidden, except for the PIN and token functions, to allow retrieving a 
PIN
+when accessing a protected object, such as a private key, or allowing probing
+the user to insert the token. All the initialization functions are below.
+
address@hidden
+
address@hidden @ref{gnutls_pkcs11_init}: Global initialization
+
address@hidden @ref{gnutls_pkcs11_deinit}: Global deinitialization
+
address@hidden @ref{gnutls_pkcs11_set_token_function}: Sets the token insertion 
function
+
address@hidden @ref{gnutls_pkcs11_set_pin_function}: Sets the PIN request 
function
+
address@hidden @ref{gnutls_pkcs11_add_provider}: Adds an additional 
@acronym{PKCS #11} provider
+
address@hidden itemize
+
address@hidden Reading Objects
+
+All @acronym{PKCS #11} objects are referenced by @acronym{GnuTLS} functions by
+URLs as described in @code{draft-pechanec-pkcs11uri-01}. For example a public
+key on a smart card may be referenced as:
+
address@hidden
+pkcs11:token=Nikos;serial=307521161601031;model=PKCS%2315; \
+manufacturer=EnterSafe;object=test1;objecttype=public;\
+id=32:f1:53:f3:e3:79:90:b0:86:24:14:10:77:ca:5d:ec:2d:15:fa:ed
address@hidden example
+
+while the smart card itself can be referenced as:
address@hidden
+pkcs11:token=Nikos;serial=307521161601031;model=PKCS%2315;manufacturer=EnterSafe
address@hidden example
+
+
+Objects can be accessed with the following functions
address@hidden
+
address@hidden @ref{gnutls_pkcs11_obj_init}: Initializes an object
+
address@hidden @ref{gnutls_pkcs11_obj_import_url}: To import an object from a 
url
+
address@hidden @ref{gnutls_pkcs11_obj_export_url}: To export the URL of the 
object
+
address@hidden @ref{gnutls_pkcs11_obj_deinit}: To deinitialize an object
+
address@hidden @ref{gnutls_pkcs11_obj_export}: To export data associated with 
object
+
address@hidden @ref{gnutls_pkcs11_obj_get_info}: To obtain information about an 
object
+
address@hidden @ref{gnutls_pkcs11_obj_list_import_url}: To mass load of objects
+
address@hidden @ref{gnutls_x509_crt_import_pkcs11}: Import a certificate object
+
address@hidden @ref{gnutls_x509_crt_import_pkcs11_url}: Helper function to 
directly import a URL into a certificate
+
address@hidden @ref{gnutls_x509_crt_list_import_pkcs11}: Mass import of 
certificates
+
address@hidden itemize
+
+
+Functions that relate to token handling are shown below
address@hidden
+
address@hidden @ref{gnutls_pkcs11_token_get_url}: Returns the URL of a token
+
address@hidden @ref{gnutls_pkcs11_token_get_info}: Obtain information about a 
token
+
address@hidden @ref{gnutls_pkcs11_token_get_flags}: Returns flags about a token 
(i.e. hardware or software)
+
address@hidden itemize
+
+The following example will list all tokens.
address@hidden
+int i;
+char* url;
+
+       gnutls_global_init();
+
+       for (i=0;;i++) {
+               ret = gnutls_pkcs11_token_get_url(i, &url);
+               if (ret == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE)
+                       break;
+
+               if (ret < 0)
+                       exit(1);
+               
+               fprintf(stdout, "Token[%d]: URL: %s\n", i, url);
+       }
+       gnutls_global_deinit();
address@hidden verbatim
+
+
+The next one will list all objects in a token:
address@hidden
+gnutls_pkcs11_obj_t *obj_list;
+unsigned int obj_list_size = 0;
+gnutls_datum_t cinfo;
+int i;
+
+       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);
+
+       /* no error checking from now on */
+       obj_list = malloc(sizeof(*obj_list)*obj_list_size);
+
+       gnutls_pkcs11_obj_list_import_url( obj_list, &obj_list_size, url, 
flags);
+
+       /* now all certificates are in obj_list */
+
+       for (i=0;i<obj_list_size;i++) {
+
+               gnutls_x509_crt_init(&xcrt);
+               
+               gnutls_x509_crt_import_pkcs11(xcrt, obj_list[i]);
+               
+               gnutls_x509_crt_print (xcrt, GNUTLS_CRT_PRINT_FULL, &cinfo);
+
+               fprintf(stdout, "cert[%d]:\n %s\n\n", cinfo.data);
+
+               gnutls_free(cinfo.data);
+               gnutls_x509_crt_deinit(&xcrt);
+       }
address@hidden verbatim
+
+
address@hidden Writing Objects
+
+With @acronym{GnuTLS} you can copy existing private keys and certificates
+to a token. This can be achieved with the following functions
+
address@hidden
+
address@hidden @ref{gnutls_pkcs11_delete_url}: To delete an object
+
address@hidden @ref{gnutls_pkcs11_copy_x509_privkey}: To copy a private key to 
a token
+
address@hidden @ref{gnutls_pkcs11_copy_x509_crt}: To copy a certificate to a 
token
+
address@hidden itemize
+
+
address@hidden Using a @acronym{PKCS #11} token with TLS
+
+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
+
+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-ciphersuites.texi b/doc/cha-ciphersuites.texi
new file mode 100644
index 0000000..e0fad22
--- /dev/null
+++ b/doc/cha-ciphersuites.texi
@@ -0,0 +1,44 @@
address@hidden All the supported ciphersuites in GnuTLS
address@hidden All the Supported Ciphersuites in @acronym{GnuTLS}
address@hidden
address@hidden Ciphersuites
+
address@hidden algorithms.texi
+
+Some additional information regarding some of the algorithms:
+
address@hidden @code
address@hidden RSA
+RSA is public key cryptosystem designed by Ronald Rivest, Adi Shamir
+and Leonard Adleman.  It can be used with any hash functions.
+
address@hidden DSA
+DSA is the USA's Digital Signature Standard.  It uses only the SHA-1
+hash algorithm.
+
address@hidden MD2
+MD2 is a cryptographic hash algorithm designed by Ron Rivest.  It is
+optimized for 8-bit processors. Outputs 128 bits of data.  There are
+no known weaknesses of this algorithm but since this algorithm is
+rarely used and not really studied it should not be used today.
+
address@hidden MD5
+MD5 is a cryptographic hash algorithm designed by Ron Rivest. Outputs
+128 bits of data.  It is considered to be broken.
+
address@hidden SHA-1
+SHA is a cryptographic hash algorithm designed by NSA. Outputs 160
+bits of data.  It is also considered to be broken, though no practical
+attacks have been found.
+
address@hidden RMD160
+RIPEMD is a cryptographic hash algorithm developed in the framework of
+the EU project RIPE.  Outputs 160 bits of data.
+
address@hidden table
+
address@hidden
address@hidden Guile Bindings
address@hidden
+
address@hidden guile.texi
diff --git a/doc/cha-copying.texi b/doc/cha-copying.texi
new file mode 100644
index 0000000..d35dd92
--- /dev/null
+++ b/doc/cha-copying.texi
@@ -0,0 +1,29 @@
address@hidden Copying Information
address@hidden Copying Information
+
address@hidden
+* GNU Free Documentation License::   License for copying this manual.
+* GNU LGPL::                     License for copying the core GnuTLS library.
+* GNU GPL::                      License for copying GnuTLS-extra and tools.
address@hidden menu
+
address@hidden GNU Free Documentation License
address@hidden GNU Free Documentation License
+
address@hidden FDL, GNU Free Documentation License
+
address@hidden fdl-1.3.texi
+
address@hidden GNU LGPL
address@hidden GNU Lesser General Public License
address@hidden LGPL, GNU Lesser General Public License
address@hidden License, GNU LGPL
+
address@hidden lgpl-2.1.texi
+
address@hidden GNU GPL
address@hidden GNU General Public License
address@hidden GPL, GNU General Public License
address@hidden License, GNU GPL
+
address@hidden gpl-3.0.texi
diff --git a/doc/cha-functions.texi b/doc/cha-functions.texi
new file mode 100644
index 0000000..f73bc57
--- /dev/null
+++ b/doc/cha-functions.texi
@@ -0,0 +1,120 @@
address@hidden Function reference
address@hidden Function Reference
address@hidden Function reference
+
address@hidden
+* Core functions::
+* X.509 certificate functions::
+* GnuTLS-extra functions::
+* OpenPGP functions::
+* TLS Inner Application (TLS/IA) functions::
+* Error codes and descriptions::
address@hidden menu
+
address@hidden Core functions
address@hidden Core Functions
+
+The prototypes for the following functions lie in
address@hidden/gnutls.h}.
+
address@hidden gnutls-api.texi
+
address@hidden X.509 certificate functions
address@hidden @acronym{X.509} Certificate Functions
address@hidden:x509api}
address@hidden @acronym{X.509} Functions
+
+The following functions are to be used for @acronym{X.509} certificate 
handling.
+Their prototypes lie in @file{gnutls/x509.h}.
+
address@hidden x509-api.texi
+
address@hidden GnuTLS-extra functions
address@hidden @acronym{GnuTLS-extra} Functions
address@hidden @acronym{GnuTLS-extra} functions
+
+These functions are only available in the GPLv3+ version of the
+library called @code{gnutls-extra}. The prototypes for this library
+lie in @file{gnutls/extra.h}.
+
address@hidden extra-api.texi
+
address@hidden OpenPGP functions
address@hidden @acronym{OpenPGP} Functions
address@hidden @acronym{OpenPGP} functions
address@hidden:openpgpapi}
+
+The following functions are to be used for @acronym{OpenPGP}
+certificate handling.  Their prototypes lie in
address@hidden/openpgp.h}.
+
address@hidden pgp-api.texi
+
address@hidden TLS Inner Application (TLS/IA) functions
address@hidden @acronym{TLS} Inner Application (@acronym{TLS/IA}) Functions
address@hidden @acronym{TLS} Inner Application (@acronym{TLS/IA}) functions
address@hidden Inner Application (@acronym{TLS/IA}) functions
+
+The following functions are used for @acronym{TLS} Inner Application
+(@acronym{TLS/IA}).  Their prototypes lie in @file{gnutls/extra.h}.
+You need to link with @file{libgnutls-extra} to be able to use these
+functions (@pxref{GnuTLS-extra functions}).
+
+The typical control flow in an TLS/IA client (that would not require
+an Application Phase for resumed sessions) would be similar to the
+following:
+
address@hidden
+int client_avp (gnuls_session_t *session, void *ptr,
+                const char *last, size_t lastlen,
+               char **new, size_t *newlen)
address@hidden
+...
address@hidden
+...
+int main ()
address@hidden
+  gnutls_ia_client_credentials_t iacred;
+...
+  gnutls_init (&session, GNUTLS_CLIENT);
+...
+  /* Enable TLS/IA. */
+  gnutls_ia_allocate_client_credentials(&iacred);
+  gnutls_ia_set_client_avp_function(iacred, client_avp);
+  gnutls_credentials_set (session, GNUTLS_CRD_IA, iacred);
+...
+  ret = gnutls_handshake (session);
+  // Error handling...
+...
+  if (gnutls_ia_handshake_p (session))
+    @{
+      ret = gnutls_ia_handshake (session);
+      // Error handling...
+...
address@hidden example
+
+See below for detailed descriptions of all the functions used above.
+
+The function @code{client_avp} would have to be implemented by your
+application.  The function is responsible for handling the AVP data.
+See @code{gnutls_ia_set_client_avp_function} below for more
+information on how that function should be implemented.
+
+The control flow in a typical server is similar to the above, use
address@hidden instead of
address@hidden, and replace the call to the
+client functions with the corresponding server functions.
+
address@hidden ia-api.texi
+
address@hidden Error codes and descriptions
address@hidden Error Codes and Descriptions
address@hidden Codes}
address@hidden Error codes
+
+The error codes used throughout the library are described below.  The
+return code @code{GNUTLS_E_SUCCESS} indicate successful operation, and
+is guaranteed to have the value 0, so you can use it in logical
+expressions.
+
address@hidden error_codes.texi
diff --git a/doc/cha-gtls-app.texi b/doc/cha-gtls-app.texi
new file mode 100644
index 0000000..13651a4
--- /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/doc/cha-internals.texi b/doc/cha-internals.texi
new file mode 100644
index 0000000..fda6221
--- /dev/null
+++ b/doc/cha-internals.texi
@@ -0,0 +1,336 @@
address@hidden Internal architecture of GnuTLS
address@hidden Internal Architecture of GnuTLS
address@hidden Internal architecture
+
+This chapter is to give a brief description of the
+way @acronym{GnuTLS} works. The focus is to give an idea
+to potential developers and those who want to know what
+happens inside the black box.
+
address@hidden
+* The TLS Protocol::
+* TLS Handshake Protocol::
+* TLS Authentication Methods::
+* TLS Extension Handling::
+* Certificate Handling::
+* Cryptographic Backend::
address@hidden menu
+
address@hidden The TLS Protocol
address@hidden The TLS Protocol
+The main needs for the TLS protocol to be used are
+shown in the image below.
+
address@hidden,9cm}
+
+This is being accomplished by the following object diagram.
+Note that since @acronym{GnuTLS} is being developed in C
+object are just structures with attributes. The operations listed
+are functions that require the first parameter to be that object.
address@hidden,15cm}
+
address@hidden TLS Handshake Protocol
address@hidden TLS Handshake Protocol
+The @acronym{GnuTLS} handshake protocol is implemented as a state
+machine that waits for input or returns immediately when the non-blocking
+transport layer functions are used. The main idea is shown in the following
+figure.
+
address@hidden,9cm}
+
+Also the way the input is processed varies per ciphersuite. Several 
+implementations of the internal handlers are available and 
address@hidden only multiplexes the input to the appropriate 
+handler. For example a @acronym{PSK} ciphersuite has a different 
+implementation of the @code{process_client_key_exchange} than a
+certificate ciphersuite.
+
address@hidden,12cm}
+
address@hidden TLS Authentication Methods
address@hidden TLS Authentication Methods
+In @acronym{GnuTLS} authentication methods can be implemented quite
+easily.  Since the required changes to add a new authentication method
+affect only the handshake protocol, a simple interface is used. An
+authentication method needs only to implement the functions as seen in
+the figure below.
+
address@hidden,12cm}
+
+The functions that need to be implemented are the ones responsible for
+interpreting the handshake protocol messages. It is common for such
+functions to read data from one or more @code{credentials_t}
address@hidden as the
address@hidden structures} and write data,
+such as certificates, usernames etc. to @code{auth_info_t} structures.
+
+Simple examples of existing authentication methods can be seen in
address@hidden for PSK ciphersuites and @code{auth_srp.c} for SRP
+ciphersuites. After implementing these functions the structure holding
+its pointers has to be registered in @code{gnutls_algorithms.c} in the
address@hidden structure.
+
address@hidden TLS Extension Handling
address@hidden TLS Extension Handling
+As with authentication methods, the TLS extensions handlers can be
+implemented using the following interface.
+
address@hidden,12cm}
+
+Here there are two functions, one for receiving the extension data
+and one for sending. These functions have to check internally whether
+they operate in client or server side. 
+
+A simple example of an extension handler can be seen in
address@hidden After implementing these functions, together with the
+extension number they handle, they have to be registered in
address@hidden in the @code{_gnutls_extensions} structure.
+
address@hidden Adding a New TLS Extension
+
+Adding support for a new TLS extension is done from time to time, and
+the process to do so is not difficult.  Here are the steps you need to
+follow if you wish to do this yourself.  For sake of discussion, let's
+consider adding support for the hypothetical TLS extension
address@hidden
+
address@hidden
+
address@hidden Add @code{configure} option like @code{--enable-foobar} or 
@code{--disable-foobar}.
+
+Which to chose depends on whether you intend to make the extension be
+enabled by default.  Look at existing checks (i.e., SRP, authz) for
+how to model the code.  For example:
+
address@hidden
+AC_MSG_CHECKING([whether to disable foobar support])
+AC_ARG_ENABLE(foobar,
+       AS_HELP_STRING([--disable-foobar],
+               [disable foobar support]),
+       ac_enable_foobar=no)
+if test x$ac_enable_foobar != xno; then
+ AC_MSG_RESULT(no)
+ AC_DEFINE(ENABLE_FOOBAR, 1, [enable foobar])
+else
+ ac_full=0
+ AC_MSG_RESULT(yes)
+fi
+AM_CONDITIONAL(ENABLE_FOOBAR, test "$ac_enable_foobar" != "no")
address@hidden example
+
+These lines should go in @code{lib/m4/hooks.m4}.
+
address@hidden Add IANA extension value to @code{extensions_t} in 
@code{gnutls_int.h}.
+
+A good name for the value would be GNUTLS_EXTENSION_FOOBAR.  Check
+with @url{http://www.iana.org/assignments/tls-extensiontype-values}
+for allocated values.  For experiments, you could pick a number but
+remember that some consider it a bad idea to deploy such modified
+version since it will lead to interoperability problems in the future
+when the IANA allocates that number to someone else, or when the
+foobar protocol is allocated another number.
+
address@hidden Add an entry to @code{_gnutls_extensions} in 
@code{gnutls_extensions.c}.
+
+A typical entry would be:
+
address@hidden
+  int ret;
+
+  /* ...
+   */
+
+#if ENABLE_FOOBAR
+  ret = gnutls_ext_register (GNUTLS_EXTENSION_FOOBAR,
+                             "FOOBAR",
+                             GNUTLS_EXT_TLS,
+                             _gnutls_foobar_recv_params,
+                             _gnutls_foobar_send_params);
+  if (ret != GNUTLS_E_SUCCESS)
+    return ret;
+#endif
address@hidden example
+
+The GNUTLS_EXTENSION_FOOBAR is the integer value you added to
address@hidden earlier.  The two functions are new functions that
+you will need to implement, most likely you'll need to add an
address@hidden "ext_foobar.h"} as well.
+
address@hidden Add new files @code{ext_foobar.c} and @code{ext_foobar.h} that 
implements the extension.
+
+The functions you are responsible to add are those mentioned in the
+previous step.  As a starter, you could add this:
+
address@hidden
+int
+_gnutls_foobar_recv_params (gnutls_session_t session,
+                            const opaque * data,
+                            size_t data_size)
address@hidden
+  return 0;
address@hidden
+
+int
+_gnutls_foobar_send_params (gnutls_session_t session,
+                            opaque * data,
+                            size_t _data_size)
address@hidden
+  return 0;
address@hidden
address@hidden example
+
+The @code{_gnutls_foobar_recv_params} function is responsible for
+parsing incoming extension data (both in the client and server).
+
+The @code{_gnutls_foobar_send_params} function is responsible for
+sending extension data (both in the client and server).
+
+If you receive length fields that doesn't match, return
address@hidden  If you receive invalid
+data, return @code{GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER}.  You can use
+other error codes too.  Return 0 on success.
+
+The function typically store some information in the @code{session}
+variable for later usage.  If you need to add new fields there, check
address@hidden in @code{gnutls_int.h} and compare with existing TLS
+extension specific variables.
+
+Recall that both the client and server both send and receives
+parameters, and your code most likely will need to do different things
+depending on which mode it is in.  It may be useful to make this
+distinction explicit in the code.  Thus, for example, a better
+template than above would be:
+
address@hidden
+int
+_gnutls_foobar_recv_params (gnutls_session_t session,
+                            const opaque * data,
+                            size_t data_size)
address@hidden
+  if (session->security_parameters.entity == GNUTLS_CLIENT)
+    return foobar_recv_client (session, data, data_size);
+  else
+    return foobar_recv_server (session, data, data_size);
address@hidden
+
+int
+_gnutls_foobar_send_params (gnutls_session_t session,
+                            opaque * data,
+                            size_t data_size)
address@hidden
+  if (session->security_parameters.entity == GNUTLS_CLIENT)
+    return foobar_send_client (session, data, data_size);
+  else
+    return foobar_send_server (session, data, data_size);
address@hidden
address@hidden example
+
+The functions used would be declared as @code{static} functions, of
+the appropriate prototype, in the same file.
+
+When adding the files, you'll need to add them to @code{Makefile.am}
+as well, for example:
+
address@hidden
+if ENABLE_FOOBAR
+COBJECTS += ext_foobar.c
+HFILES += ext_foobar.h
+endif
address@hidden example
+
address@hidden Add API functions to enable/disable the extension.
+
+Normally the client will have one API to request use of the extension,
+and setting some extension specific data.  The server will have one
+API to let the library know that it is willing to accept the
+extension, often this is implemented through a callback but it doesn't
+have to.
+
+The APIs need to be added to @code{includes/gnutls/gnutls.h} or
address@hidden/gnutls/extra.h} as appropriate.  It is recommended that
+if you don't have a requirement to use the LGPLv2.1+ license for your
+extension, that you place your work under the GPLv3+ license and thus
+in the libgnutls-extra library.
+
+You can implement the API function in the @code{ext_foobar.c} file, or
+if that file ends up becoming rather larger, add a
address@hidden file.
+
+To make the API available in the shared library you need to add the
+symbol in @code{lib/libgnutls.map} or
address@hidden/libgnutls-extra.map} as appropriate, so that the symbol
+is exported properly.
+
+When writing GTK-DOC style documentation for your new APIs, don't
+forget to add @code{Since:} tags to indicate the GnuTLS version the
+API was introduced in.
+
address@hidden enumerate
+
address@hidden Certificate Handling
address@hidden Certificate Handling
+What is provided by the certificate handling functions
+is summarized in the following diagram.
+
address@hidden,12cm}
+
address@hidden Cryptographic Backend
address@hidden Cryptographic Backend
+Several new systems provide hardware assisted cryptographic algorithm
+implementations that offer implementations some orders of magnitude
+faster than the software. For this reason GnuTLS supports by default
+the /dev/crypto device usually found in FreeBSD and OpenBSD system, to
+take advantage of installed hardware. 
+
+In addition it is possible to override parts of the crypto backend or the
+whole. It is possible to override them both at runtime and compile
+time, however here we will discuss the runtime possibility. The API
+available for this functionality is in @code{gnutls/crypto.h} header
+file.
+
address@hidden Override specific algorithms
+When an optimized implementation of a single algorithm is available,
+say a hardware assisted version of @acronym{AES-CBC} then the
+following functions can be used to register those algorithms.
+
address@hidden
+
address@hidden @ref{gnutls_crypto_single_cipher_register2}
+To register a cipher algorithm.
+
address@hidden
+To register a hash (digest) or MAC algorithm.
+
address@hidden itemize
+
+Those registration functions will only replace the specified algorithm
+and leave the rest of subsystem intact.
+
address@hidden Override parts of the backend
+In some systems, such as embedded ones, it might be desirable to
+override big parts of the cryptographic backend, or even all of
+them. For this reason the following functions are provided.
+
address@hidden
+
address@hidden @ref{gnutls_crypto_cipher_register2}
+To override the cryptographic algorithms backend.
+
address@hidden @ref{gnutls_crypto_digest_register2}
+To override the digest algorithms backend.
+
address@hidden @ref{gnutls_crypto_rnd_register2}
+To override the random number generator backend.
+
address@hidden @ref{gnutls_crypto_bigint_register2}
+To override the big number number operations backend.
+
address@hidden @ref{gnutls_crypto_pk_register2}
+To override the public key encryption backend. This is tight to the
+big number operations so either both of them should be updated or care
+must be taken to use the same format.
+
address@hidden itemize
+
+If all of them are used then GnuTLS will no longer use libgcrypt.
+
diff --git a/doc/cha-intro-tls.texi b/doc/cha-intro-tls.texi
new file mode 100644
index 0000000..b10ca88
--- /dev/null
+++ b/doc/cha-intro-tls.texi
@@ -0,0 +1,781 @@
address@hidden Introduction to TLS
address@hidden Introduction to @acronym{TLS}
+
address@hidden stands for ``Transport Layer Security'' and is the
+successor of SSL, the Secure Sockets Layer protocol @xcite{SSL3}
+designed by Netscape.  @acronym{TLS} is an Internet protocol, defined
+by @address@hidden, or Internet Engineering Task Force,
+is a large open international community of network designers,
+operators, vendors, and researchers concerned with the evolution of
+the Internet architecture and the smooth operation of the Internet.
+It is open to any interested individual.}, described in @acronym{RFC}
+4346 and also in @xcite{RESCORLA}.  The protocol provides
+confidentiality, and authentication layers over any reliable transport
+layer.  The description, below, refers to @acronym{TLS} 1.0 but also
+applies to @acronym{TLS} 1.1 @xcite{RFC4346} and @acronym{SSL} 3.0,
+since the differences of these protocols are minor.  Older protocols
+such as @acronym{SSL} 2.0 are not discussed nor implemented in
address@hidden since they are not considered secure today.  GnuTLS
+also supports @acronym{X.509} and @acronym{OpenPGP} @xcite{RFC4880}.
+
address@hidden
+* TLS layers::
+* The transport layer::
+* The TLS record protocol::
+* The TLS Alert Protocol::
+* The TLS Handshake Protocol::
+* TLS Extensions::
+* Selecting cryptographic key sizes::
+* On SSL 2 and older protocols::
+* On Record Padding::
+* Safe Renegotiation::
address@hidden menu
+
address@hidden TLS layers
address@hidden TLS Layers
address@hidden TLS Layers
+
address@hidden is a layered protocol, and consists of the Record
+Protocol, the Handshake Protocol and the Alert Protocol. The Record
+Protocol is to serve all other protocols and is above the transport
+layer.  The Record protocol offers symmetric encryption, data
+authenticity, and optionally compression.
+
+The Alert protocol offers some signaling to the other protocols. It
+can help informing the peer for the cause of failures and other error
+conditions.  @xref{The Alert Protocol}, for more information.  The
+alert protocol is above the record protocol.
+
+The Handshake protocol is responsible for the security parameters'
+negotiation, the initial key exchange and authentication.  @xref{The
+Handshake Protocol}, for more information about the handshake
+protocol.  The protocol layering in TLS is shown in the figure below.
+
address@hidden,12cm,8cm}
+
address@hidden The transport layer
address@hidden The Transport Layer
address@hidden Transport protocol
+
address@hidden is not limited to one transport layer, it can be used
+above any transport layer, as long as it is a reliable one.  A set of
+functions is provided and their purpose is to load to @acronym{GnuTLS} the
+required callbacks to access the transport layer.
+
address@hidden
address@hidden @ref{gnutls_transport_set_push_function}
address@hidden @ref{gnutls_transport_set_pull_function}
address@hidden @ref{gnutls_transport_set_ptr}
address@hidden @ref{gnutls_transport_set_lowat}
address@hidden @ref{gnutls_transport_set_errno}
address@hidden itemize
+
+These functions accept a callback function as a parameter.  The
+callback functions should return the number of bytes written, or -1 on
+error and should set @code{errno} appropriately.
+
+In some environments, setting @code{errno} is unreliable, for example
+Windows have several errno variables in different CRTs, or it may be
+that errno is not a thread-local variable.  If this is a concern to
+you, call @code{gnutls_transport_set_errno} with the intended errno
+value instead of setting @code{errno} directly.
+
address@hidden currently only interprets the EINTR and EAGAIN errno
+values and returns the corresponding @acronym{GnuTLS} error codes
address@hidden and @code{GNUTLS_E_AGAIN}.  These values
+are usually returned by interrupted system calls, or when non blocking
+IO is used.  All @acronym{GnuTLS} functions can be resumed (called
+again), if any of these error codes is returned.  The error codes
+above refer to the system call, not the @acronym{GnuTLS} function,
+since signals do not interrupt @acronym{GnuTLS}' functions.
+
+For non blocking sockets or other custom made pull/push functions
+the @ref{gnutls_transport_set_lowat} must be called, with a zero
+low water mark value.
+
+By default, if the transport functions are not set, @acronym{GnuTLS}
+will use the Berkeley Sockets functions.  In this case
address@hidden will use some hacks in order for @code{select} to
+work, thus making it easy to add @acronym{TLS} support to existing
+TCP/IP servers.
+
address@hidden The TLS record protocol
address@hidden The TLS Record Protocol
address@hidden Record protocol
+
+The Record protocol is the secure communications provider. Its purpose
+is to encrypt, authenticate and ---optionally--- compress packets.
+The following functions are available:
+
address@hidden @asis
+
address@hidden @ref{gnutls_record_send}:
+To send a record packet (with application data).
+
address@hidden @ref{gnutls_record_recv}:
+To receive a record packet (with application data).
+
address@hidden @ref{gnutls_record_get_direction}:
+To get the direction of the last interrupted function call.
address@hidden table
+
+As you may have already noticed, the functions which access the Record
+protocol, are quite limited, given the importance of this protocol in
address@hidden  This is because the Record protocol's parameters are
+all set by the Handshake protocol.
+
+The Record protocol initially starts with NULL parameters, which means
+no encryption, and no MAC is used. Encryption and authentication begin
+just after the handshake protocol has finished.
+
address@hidden
+* Encryption algorithms used in the record layer::
+* Compression algorithms used in the record layer::
+* Weaknesses and countermeasures::
address@hidden menu
+
address@hidden Encryption algorithms used in the record layer
address@hidden Encryption Algorithms Used in the Record Layer
address@hidden Symmetric encryption algorithms
+
+Confidentiality in the record layer is achieved by using symmetric
+block encryption algorithms like @code{3DES}, @address@hidden,
+or Advanced Encryption Standard, is actually the RIJNDAEL algorithm.
+This is the algorithm that replaced DES.}, or stream algorithms like
address@hidden@address@hidden is a compatible
+algorithm with RSA's RC4 algorithm, which is considered to be a trade
+secret.}. Ciphers are encryption algorithms that use a single, secret,
+key to encrypt and decrypt data. Block algorithms in TLS also provide
+protection against statistical analysis of the data.  Thus, if you're
+using the @acronym{TLS} protocol, a random number of blocks will be
+appended to data, to prevent eavesdroppers from guessing the actual
+data size.
+
+Supported cipher algorithms:
+
address@hidden @code
address@hidden 3DES_CBC
address@hidden is the DES block cipher algorithm used with triple
+encryption (EDE). Has 64 bits block size and is used in CBC mode.
+
address@hidden ARCFOUR_128
+ARCFOUR is a fast stream cipher.
+
address@hidden ARCFOUR_40
+This is the ARCFOUR cipher that is fed with a 40 bit key,
+which is considered weak.
+
address@hidden AES_CBC
+AES or RIJNDAEL is the block cipher algorithm that replaces the old
+DES algorithm.  Has 128 bits block size and is used in CBC mode. This
+is not officially supported in TLS.
address@hidden table
+
+Supported MAC algorithms:
+
address@hidden @code
address@hidden MAC_MD5
+MD5 is a cryptographic hash algorithm designed by Ron Rivest. Outputs
+128 bits of data.
+
address@hidden MAC_SHA
+SHA is a cryptographic hash algorithm designed by NSA. Outputs 160
+bits of data.
+
address@hidden table
+
address@hidden Compression algorithms used in the record layer
address@hidden Compression Algorithms Used in the Record Layer
address@hidden Compression algorithms
+
+The TLS record layer also supports compression.  The algorithms
+implemented in @acronym{GnuTLS} can be found in the table below.
+All the algorithms except for DEFLATE which is
+referenced in @xcite{RFC3749}, should be considered as
address@hidden' address@hidden should use
address@hidden to enable private
+extensions.}, and should be advertised only when the peer is known to
+have a compliant client, to avoid interoperability problems.
+
+The included algorithms perform really good when text, or other
+compressible data are to be transfered, but offer nothing on already
+compressed data, such as compressed images, zipped archives etc.
+These compression algorithms, may be useful in high bandwidth TLS
+tunnels, and in cases where network usage has to be minimized. As a
+drawback, compression increases latency.
+
+The record layer compression in @acronym{GnuTLS} is implemented based
+on the proposal @xcite{RFC3749}.
+The supported compression algorithms are:
+
address@hidden @code
address@hidden DEFLATE
+Zlib compression, using the deflate algorithm.
+
address@hidden LZO
+LZO is a very fast compression algorithm.  This algorithm is only
+available if the @acronym{GnuTLS-extra} library has been initialized
+and the private extensions are enabled, and if GnuTLS was built with
+LZO support.
+
address@hidden table
+
address@hidden Weaknesses and countermeasures
address@hidden Weaknesses and Countermeasures
+
+Some weaknesses that may affect the security of the Record layer have
+been found in @acronym{TLS} 1.0 protocol. These weaknesses can be
+exploited by active attackers, and exploit the facts that
+
address@hidden
+
address@hidden
address@hidden has separate alerts for ``decryption_failed'' and
+``bad_record_mac''
+
address@hidden
+The decryption failure reason can be detected by timing the response
+time.
+
address@hidden
+The IV for CBC encrypted packets is the last block of the previous
+encrypted packet.
+
address@hidden enumerate
+
+Those weaknesses were solved in @acronym{TLS} 1.1 @xcite{RFC4346}
+which is implemented in @acronym{GnuTLS}. For a detailed discussion
+see the archives of the TLS Working Group mailing list and the paper
address@hidden
+
address@hidden The TLS Alert Protocol
address@hidden The TLS Alert Protocol
address@hidden Alert Protocol}
address@hidden Alert protocol
+
+The Alert protocol is there to allow signals to be sent between peers.
+These signals are mostly used to inform the peer about the cause of a
+protocol failure. Some of these signals are used internally by the
+protocol and the application protocol does not have to cope with them
+(see @code{GNUTLS_A_CLOSE_NOTIFY}), and others refer to the
+application protocol solely (see @code{GNUTLS_A_USER_CANCELLED}).  An
+alert signal includes a level indication which may be either fatal or
+warning. Fatal alerts always terminate the current connection, and
+prevent future renegotiations using the current session ID.
+
+The alert messages are protected by the record protocol, thus the
+information that is included does not leak. You must take extreme care
+for the alert information not to leak to a possible attacker, via
+public log files etc.
+
address@hidden @asis
address@hidden @ref{gnutls_alert_send}:
+To send an alert signal.
+
address@hidden @ref{gnutls_error_to_alert}:
+To map a gnutls error number to an alert signal.
+
address@hidden @ref{gnutls_alert_get}:
+Returns the last received alert.
+
address@hidden @ref{gnutls_alert_get_name}:
+Returns the name, in a character array, of the given alert.
+
address@hidden table
+
address@hidden The TLS Handshake Protocol
address@hidden The TLS Handshake Protocol
address@hidden Handshake Protocol}
address@hidden Handshake protocol
+
+The Handshake protocol is responsible for the ciphersuite negotiation,
+the initial key exchange, and the authentication of the two peers.
+This is fully controlled by the application layer, thus your program
+has to set up the required parameters. Available functions to control
+the handshake protocol include:
+
address@hidden @asis
address@hidden @ref{gnutls_priority_init}:
+To initialize a priority set of ciphers.
+
address@hidden @ref{gnutls_priority_deinit}:
+To deinitialize a priority set of ciphers.
+
address@hidden @ref{gnutls_priority_set}:
+To associate a priority set with a @acronym{TLS} session.
+
address@hidden @ref{gnutls_priority_set_direct}:
+To directly associate a session with a given priority string.
+
address@hidden @ref{gnutls_credentials_set}:
+To set the appropriate credentials structures.
+
address@hidden @ref{gnutls_certificate_server_set_request}:
+To set whether client certificate is required or not.
+
address@hidden @ref{gnutls_handshake}:
+To initiate the handshake.
address@hidden table
+
address@hidden TLS Cipher Suites
+
+The Handshake Protocol of @acronym{TLS} negotiates cipher suites of
+the form @code{TLS_DHE_RSA_WITH_3DES_CBC_SHA}.  The usual cipher
+suites contain these parameters:
+
address@hidden
+
address@hidden The key exchange algorithm.
address@hidden in the example.
+
address@hidden The Symmetric encryption algorithm and mode
address@hidden in this example.
+
address@hidden The address@hidden stands for Message Authentication Code. It 
can be described as a keyed hash algorithm. See RFC2104.} algorithm used for 
authentication.
address@hidden is used in the above example.
+
address@hidden itemize
+
+The cipher suite negotiated in the handshake protocol will affect the
+Record Protocol, by enabling encryption and data authentication.  Note
+that you should not over rely on @acronym{TLS} to negotiate the
+strongest available cipher suite. Do not enable ciphers and algorithms
+that you consider weak.
+
+The priority functions, dicussed above, allow the application layer to
+enable and set priorities on the individual ciphers. It may imply that
+all combinations of ciphersuites are allowed, but this is not
+true. For several reasons, not discussed here, some combinations were
+not defined in the @acronym{TLS} protocol.  The supported ciphersuites
+are shown in @ref{ciphersuites}.
+
address@hidden Client Authentication
address@hidden Client Certificate authentication
+
+In the case of ciphersuites that use certificate authentication, the
+authentication of the client is optional in @acronym{TLS}.  A server
+may request a certificate from the client --- using the
address@hidden function. If a certificate
+is to be requested from the client during the handshake, the server
+will send a certificate request message that contains a list of
+acceptable certificate signers. In @acronym{GnuTLS} the certificate
+signers list is constructed using the trusted Certificate Authorities
+by the server. That is the ones set using
address@hidden
address@hidden @ref{gnutls_certificate_set_x509_trust_file}
address@hidden @ref{gnutls_certificate_set_x509_trust_mem}
address@hidden itemize
+
+Sending of the names of the CAs can be controlled using
address@hidden The client, then, may
+send a certificate, signed by one of the server's acceptable signers.
+
address@hidden Resuming Sessions
address@hidden
address@hidden Resuming sessions
+
+The @ref{gnutls_handshake} function, is expensive since a lot of
+calculations are performed. In order to support many fast connections
+to the same server a client may use session resuming. @strong{Session
+resuming} is a feature of the @acronym{TLS} protocol which allows a
+client to connect to a server, after a successful handshake, without
+the expensive calculations.  This is achieved by using the previously
+established keys. @acronym{GnuTLS} supports this feature, and the
+example (@pxref{ex:resume-client}) illustrates a typical use of it.
+
+Keep in mind that sessions are expired after some time, for security
+reasons, thus it may be normal for a server not to resume a session
+even if you requested that.  Also note that you must enable, using the
+priority functions, at least the algorithms used in the last session.
+
address@hidden Resuming Internals
+
+The resuming capability, mostly in the server side, is one of the
+problems of a thread-safe TLS implementations. The problem is that all
+threads must share information in order to be able to resume
+sessions. The gnutls approach is, in case of a client, to leave all
+the burden of resuming to the client. I.e., copy and keep the
+necessary parameters. See the functions:
+
address@hidden
+
address@hidden @ref{gnutls_session_get_data}
+
address@hidden @ref{gnutls_session_get_id}
+
address@hidden @ref{gnutls_session_set_data}
+
address@hidden itemize
+
+The server side is different. A server has to specify some callback
+functions which store, retrieve and delete session data. These can be
+registered with:
+
address@hidden
+
address@hidden @ref{gnutls_db_set_remove_function}
+
address@hidden @ref{gnutls_db_set_store_function}
+
address@hidden @ref{gnutls_db_set_retrieve_function}
+
address@hidden @ref{gnutls_db_set_ptr}
+
address@hidden itemize
+
+It might also be useful to be able to check for expired sessions in
+order to remove them, and save space. The function
address@hidden is provided for that reason.
+
address@hidden TLS Extensions
address@hidden TLS Extensions
address@hidden TLS Extensions
+
+A number of extensions to the @acronym{TLS} protocol have been
+proposed mainly in @xcite{TLSEXT}. The extensions supported
+in @acronym{GnuTLS} are:
+
address@hidden
address@hidden Maximum fragment length negotiation
address@hidden Server name indication
address@hidden Session tickets
address@hidden itemize
+
+and they will be discussed in the subsections that follow.
+
address@hidden Maximum Fragment Length Negotiation
address@hidden TLS Extensions
address@hidden Maximum fragment length
+
+This extension allows a @acronym{TLS} implementation to negotiate a
+smaller value for record packet maximum length. This extension may be
+useful to clients with constrained capabilities. See the
address@hidden and the
address@hidden functions.
+
address@hidden Server Name Indication
address@hidden
address@hidden TLS Extensions
address@hidden Server name indication
+
+A common problem in @acronym{HTTPS} servers is the fact that the
address@hidden protocol is not aware of the hostname that a client
+connects to, when the handshake procedure begins. For that reason the
address@hidden server has no way to know which certificate to send.
+
+This extension solves that problem within the @acronym{TLS} protocol,
+and allows a client to send the HTTP hostname before the handshake
+begins within the first handshake packet.  The functions
address@hidden and @ref{gnutls_server_name_get} can be
+used to enable this extension, or to retrieve the name sent by a
+client.
+
address@hidden Session Tickets
address@hidden TLS Extensions
address@hidden Session Tickets
address@hidden Ticket
+
+To resume a TLS session the server normally store some state.  This
+complicates deployment, and typical situations the client can cache
+information and send it to the server instead.  The Session Ticket
+extension implements this idea, and it is documented in
+RFC 5077 @xcite{TLSTKT}.
+
+Clients can enable support for TLS tickets with
address@hidden and servers use
address@hidden to generate a key and
address@hidden to enable the extension.
+Clients resume sessions using the ticket using the normal session
+resume functions, @ref{resume}.
+
address@hidden Selecting cryptographic key sizes
address@hidden Selecting Cryptographic Key Sizes
address@hidden key sizes
+
+In TLS, since a lot of algorithms are involved, it is not easy to set
+a consistent security level.  For this reason this section will
+present some correspondance between key sizes of symmetric algorithms
+and public key algorithms based on the most conservative values of
address@hidden  Those can be used to generate certificates with
+appropriate key sizes as well as parameters for Diffie-Hellman and SRP
+authentication.
+
address@hidden @columnfractions .15 .20 .20 .20
+
address@hidden Year
address@hidden Symmetric key size
address@hidden RSA key size, DH and SRP prime size
address@hidden ECC key size
+
address@hidden 1982
address@hidden 56
address@hidden 417
address@hidden 105
+
address@hidden 1988
address@hidden 61
address@hidden 566
address@hidden 114
+
address@hidden 2002
address@hidden 72
address@hidden 1028
address@hidden 139
+
address@hidden 2015
address@hidden 82
address@hidden 1613
address@hidden 173
+
address@hidden 2028
address@hidden 92
address@hidden 2362
address@hidden 210
+
address@hidden 2040
address@hidden 101
address@hidden 3214
address@hidden 244
+
address@hidden 2050
address@hidden 109
address@hidden 4047
address@hidden 272
+
address@hidden multitable
+
+The first column provides an estimation of the year until these
+parameters are considered safe and the rest of the columns list the
+parameters for the various algorithms.
+
+Note however that the values suggested here are nothing more than an
+educated guess that is valid today. There are no guarrantees that an
+algorithm will remain unbreakable or that these values will remain
+constant in time. There could be scientific breakthroughs that cannot
+be predicted or total failure of the current public key systems by
+quantum computers. On the other hand though the cryptosystems used in
+TLS are selected in a conservative way and such catastrophic
+breakthroughs or failures are believed to be unlikely.
+
+NIST publication SP 800-57 @xcite{NISTSP80057} contains a similar
+table that extends beyond the key sizes given above.
+
address@hidden @columnfractions .15 .20 .20 .20
+
address@hidden Bits of security
address@hidden Symmetric key algorithms
address@hidden RSA key size, DSA, DH and SRP prime size
address@hidden ECC key size
+
address@hidden 80
address@hidden 2TDEA
address@hidden 1024
address@hidden 160-223
+
address@hidden 112
address@hidden 3DES
address@hidden 2048
address@hidden 224-255
+
address@hidden 128
address@hidden AES-128
address@hidden 3072
address@hidden 256-383
+
address@hidden 192
address@hidden AES-192
address@hidden 7680
address@hidden 384-511
+
address@hidden 256
address@hidden AES-256
address@hidden 15360
address@hidden 512+
+
address@hidden multitable
+
+The recommendations are fairly consistent.
+
address@hidden On SSL 2 and older protocols
address@hidden On SSL 2 and Older Protocols
address@hidden SSL 2
+
+One of the initial decisions in the @acronym{GnuTLS} development was
+to implement the known security protocols for the transport layer.
+Initially @acronym{TLS} 1.0 was implemented since it was the latest at
+that time, and was considered to be the most advanced in security
+properties.  Later the @acronym{SSL} 3.0 protocol was implemented
+since it is still the only protocol supported by several servers and
+there are no serious security vulnerabilities known.
+
+One question that may arise is why we didn't implement @acronym{SSL}
+2.0 in the library.  There are several reasons, most important being
+that it has serious security flaws, unacceptable for a modern security
+library.  Other than that, this protocol is barely used by anyone
+these days since it has been deprecated since 1996.  The security
+problems in @acronym{SSL} 2.0 include:
+
address@hidden
+
address@hidden Message integrity compromised.
+The @acronym{SSLv2} message authentication uses the MD5 function, and
+is insecure.
+
address@hidden Man-in-the-middle attack.
+There is no protection of the handshake in @acronym{SSLv2}, which
+permits a man-in-the-middle attack.
+
address@hidden Truncation attack.
address@hidden relies on TCP FIN to close the session, so the
+attacker can forge a TCP FIN, and the peer cannot tell if it was a
+legitimate end of data or not.
+
address@hidden Weak message integrity for export ciphers.
+The cryptographic keys in @acronym{SSLv2} are used for both message
+authentication and encryption, so if weak encryption schemes are
+negotiated (say 40-bit keys) the message authentication code use the
+same weak key, which isn't necessary.
+
address@hidden itemize
+
address@hidden PCT
+Other protocols such as Microsoft's @acronym{PCT} 1 and @acronym{PCT}
+2 were not implemented because they were also abandoned and deprecated
+by @acronym{SSL} 3.0 and later @acronym{TLS} 1.0.
+
address@hidden On Record Padding
address@hidden On Record Padding
address@hidden Record padding
address@hidden Bad record MAC
+
+The TLS protocol allows for random padding of records, to make it more
+difficult to perform analysis on the length of exchanged messages.
+(In RFC 4346 this is specified in section 6.2.3.2.)  GnuTLS appears to
+be one of few implementation that take advantage of this text, and pad
+records by a random length.
+
+The TLS implementation in the Symbian operating system, frequently
+used by Nokia and Sony-Ericsson mobile phones, cannot handle
+non-minimal record padding.  What happens when one of these clients
+handshake with a GnuTLS server is that the client will fail to compute
+the correct MAC for the record.  The client sends a TLS alert
+(@code{bad_record_mac}) and disconnects.  Typically this will result
+in error messages such as 'A TLS fatal alert has been received', 'Bad
+record MAC', or both, on the GnuTLS server side.
+
+GnuTLS implements a work around for this problem.  However, it has to
+be enabled specifically.  It can be enabled by using
address@hidden, or @ref{gnutls_priority_set} with
+the @code{%COMPAT} priority string.
+
+If you implement an application that have a configuration file, we
+recommend that you make it possible for users or administrators to
+specify a GnuTLS protocol priority string, which is used by your
+application via @ref{gnutls_priority_set}.  To allow the best
+flexibility, make it possible to have a different priority string for
+different incoming IP addresses.
+
+To enable the workaround in the @code{gnutls-cli} client or the
address@hidden server, for testing of other implementations, use
+the following parameter: @code{--priority "%COMPAT"}.
+
+This problem has been discussed on mailing lists and in bug reports.
+This section tries to collect all pieces of information that we know
+about the problem.  If you wish to go back to the old discussions,
+here are some links:
+
address@hidden://bugs.debian.org/390712}
+
address@hidden://bugs.debian.org/402861}
+
address@hidden://bugs.debian.org/438137}
+
address@hidden://thread.gmane.org/gmane.ietf.tls/3079}
+
address@hidden Safe Renegotiation
address@hidden Safe Renegotiation
address@hidden renegotiation
+
+Some application protocols and implementations uses the TLS
+renegotiation feature in a manner that enables attackers to insert
+content of his choice in the beginning of a TLS session.
+
+One easy to understand vulnerability is HTTPS when servers request
+client certificates optionally for certain parts of a web site.  The
+attack works by having the attacker simulate a client and connect to a
+server, with server-only authentication, and send some data intended
+to cause harm.  When the proper client attempts to contact the server,
+the attacker hijacks that connection and uses the TLS renegotiation
+feature with the server and splices in the client connection to the
+already established connection between the attacker and server.  The
+attacker will not be able to read the data exchanged between the
+client and the server.  However, the server will (incorrectly) assume
+that the data sent by the attacker was sent by the now authenticated
+client.  The result is a prefix plain-text injection attack.
+
+The above is just one example.  Other vulnerabilities exists that do
+not rely on the TLS renegotiation to change the client's authenticated
+status (either TLS or application layer).
+
+While fixing these application protocols and implementations would be
+one natural reaction, an extension to TLS has been designed that
+cryptographically binds together any renegotiated handshakes with the
+initial negotiation.  When the extension is used, the attack is
+detected and the session can be terminated.  The extension is
+specified in @xcite{RFC5746}.
+
+GnuTLS supports the safe renegotiation extension.  The default
+behavior is as follows.  Clients will attempt to negotiate the safe
+renegotiation extension when talking to servers.  Servers will accept
+the extension when presented by clients.  Clients and servers will
+permit an initial handshake to complete even when the other side does
+not support the safe renegotiation extension.  Clients and servers
+will refuse renegotiation attempts when the extension has not been
+negotiated.
+
+Note that permitting clients to connect to servers even when the safe
+renegotiation extension is not negotiated open up for some attacks.
+Changing this default behaviour would prevent interoperability against
+the majority of deployed servers out there.  We will reconsider this
+default behaviour in the future when more servers have been upgraded.
+Note that it is easy to configure clients to always require the safe
+renegotiation extension from servers (see below on the
+%SAFE_RENEGOTIATION priority string).
+
+To modify the default behaviour, we have introduced some new priority
+strings.  The priority strings can be used by applications
+(@pxref{gnutls_priority_set}) and end users (e.g., @code{--priority}
+parameter to @code{gnutls-cli} and @code{gnutls-serv}).
+
+The @code{%UNSAFE_RENEGOTIATION} priority string permits
+(re-)handshakes even when the safe renegotiation extension was not
+negotiated. The default behavior is @code{%PARTIAL_RENEGOTIATION} that will
+prevent renegotiation with clients and servers not supporting the
+extension. This is secure for servers but leaves clients vulnerable
+to some attacks, but this is a tradeoff between security and compatibility
+with old servers. The @code{%SAFE_RENEGOTIATION} priority string makes
+clients and servers require the extension for every handshake. The latter
+is the most secure option for clients, at the cost of not being able
+to connect to legacy servers. Servers will also deny clients that
+do not support the extension from connecting.
+
+It is possible to disable use of the extension completely, in both
+clients and servers, by using the @code{%DISABLE_SAFE_RENEGOTIATION}
+priority string however we strongly recommend you to only do this for
+debugging and test purposes.
+
+The default values if the flags above are not specified are:
address@hidden @code
+
address@hidden Server:
+%PARTIAL_RENEGOTIATION
+
address@hidden Client:
+%PARTIAL_RENEGOTIATION
+
address@hidden table
+
+For applications we have introduced a new API related to safe
+renegotiation.  The @ref{gnutls_safe_renegotiation_status} function is
+used to check if the extension has been negotiated on a session, and
+can be used both by clients and servers.
diff --git a/doc/cha-library.texi b/doc/cha-library.texi
new file mode 100644
index 0000000..9213ea6
--- /dev/null
+++ b/doc/cha-library.texi
@@ -0,0 +1,188 @@
address@hidden The Library
address@hidden The Library
+
+In brief @acronym{GnuTLS} can be described as a library which offers an API
+to access secure communication protocols. These protocols provide
+privacy over insecure lines, and were designed to prevent
+eavesdropping, tampering, or message forgery.
+
+Technically @acronym{GnuTLS} is a portable ANSI C based library which
+implements the TLS 1.1 and SSL 3.0 protocols (@xref{Introduction to
+TLS}, for a more detailed description of the protocols), accompanied
+with the required framework for authentication and public key
+infrastructure.  Important features of the @acronym{GnuTLS} library
+include:
+
address@hidden
+
address@hidden Support for TLS 1.0, TLS 1.1, and SSL 3.0 protocols.
+
address@hidden Support for both @acronym{X.509} and @acronym{OpenPGP} 
certificates.
+
address@hidden Support for handling and verification of certificates.
+
address@hidden Support for @acronym{SRP} for TLS authentication.
+
address@hidden Support for @acronym{PSK} for TLS authentication.
+
address@hidden Support for TLS Extension mechanism.
+
address@hidden Support for TLS Compression Methods.
+
address@hidden itemize
+
+Additionally @acronym{GnuTLS} provides a limited emulation API for the
+widely used address@hidden@url{http://www.openssl.org/}} library,
+to ease integration with existing applications.
+
address@hidden consists of three independent parts, namely the ``TLS
+protocol part'', the ``Certificate part'', and the ``Cryptographic
+backend'' part.  The `TLS protocol part' is the actual protocol
+implementation, and is entirely implemented within the
address@hidden library.  The `Certificate part' consists of the
+certificate parsing, and verification functions which is partially
+implemented in the @acronym{GnuTLS} library.  The
address@hidden@address@hidden://ftp.gnupg.org/gcrypt/alpha/gnutls/libtasn1/}},
+a library which offers @acronym{ASN.1} parsing capabilities, is used
+for the @acronym{X.509} certificate parsing functions.  A smaller
+version of
address@hidden@address@hidden://ftp.gnupg.org/gcrypt/alpha/gnutls/opencdk/}}
+is used for the @acronym{OpenPGP} key support in @acronym{GnuTLS}.
+The ``Cryptographic backend'' is provided by the
address@hidden@address@hidden://ftp.gnupg.org/gcrypt/alpha/libgcrypt/}}
address@hidden current versions of GnuTLS it is possible to
+override the default crypto backend. Check @pxref{Cryptographic
+Backend} for details}.
+
+In order to ease integration in embedded systems, parts of the
address@hidden library can be disabled at compile time. That way a
+small library, with the required features, can be generated.
+
address@hidden
+* General Idea::
+* Error handling::
+* Memory handling::
+* Callback functions::
address@hidden menu
+
address@hidden General Idea
address@hidden General Idea
+
+A brief description of how @acronym{GnuTLS} works internally is shown
+at the figure below. This section may be easier to understand after
+having seen the examples (@pxref{examples}).
+
address@hidden,12cm,8cm}
+
+As shown in the figure, there is a read-only global state that is
+initialized once by the global initialization function.  This global
+structure, among others, contains the memory allocation functions
+used, and some structures needed for the @acronym{ASN.1} parser.  This
+structure is never modified by any @acronym{GnuTLS} function, except
+for the deinitialization function which frees all memory allocated in
+the global structure and is called after the program has permanently
+finished using @acronym{GnuTLS}.
+
+The credentials structure is used by some authentication methods, such
+as certificate authentication (@pxref{Certificate Authentication}).  A
+credentials structure may contain certificates, private keys,
+temporary parameters for Diffie-Hellman or RSA key exchange, and other
+stuff that may be shared between several TLS sessions.
+
+This structure should be initialized using the appropriate
+initialization functions. For example an application which uses
+certificate authentication would probably initialize the credentials,
+using the appropriate functions, and put its trusted certificates in
+this structure. The next step is to associate the credentials
+structure with each @acronym{TLS} session.
+
+A @acronym{GnuTLS} session contains all the required stuff for a
+session to handle one secure connection. This session calls directly
+to the transport layer functions, in order to communicate with the
+peer.  Every session has a unique session ID shared with the peer.
+
+Since TLS sessions can be resumed, servers would probably need a
+database backend to hold the session's parameters.  Every
address@hidden session after a successful handshake calls the
+appropriate backend function (@xref{resume}, for information on
+initialization) to store the newly negotiated session. The session
+database is examined by the server just after having received the
+client address@hidden first message in a @acronym{TLS} handshake},
+and if the session ID sent by the client, matches a stored session,
+the stored session will be retrieved, and the new session will be a
+resumed one, and will share the same session ID with the previous one.
+
address@hidden Error handling
address@hidden Error Handling
+
+In @acronym{GnuTLS} most functions return an integer type as a result.
+In almost all cases a zero or a positive number means success, and a
+negative number indicates failure, or a situation that some action has
+to be taken. Thus negative error codes may be fatal or not.
+
+Fatal errors terminate the connection immediately and further sends
+and receives will be disallowed. An example of a fatal error code is
address@hidden Non-fatal errors may warn about
+something, i.e., a warning alert was received, or indicate the some
+action has to be taken. This is the case with the error code
address@hidden returned by @ref{gnutls_record_recv}.
+This error code indicates that the server requests a re-handshake. The
+client may ignore this request, or may reply with an alert.  You can
+test if an error code is a fatal one by using the
address@hidden
+
+If any non fatal errors, that require an action, are to be returned by
+a function, these error codes will be documented in the function's
+reference.  @xref{Error Codes}, for all the error codes.
+
address@hidden Memory handling
address@hidden Memory Handling
+
address@hidden internally handles heap allocated objects
+differently, depending on the sensitivity of the data they
+contain. However for performance reasons, the default memory functions
+do not overwrite sensitive data from memory, nor protect such objects
+from being written to the swap.  In order to change the default
+behavior the @ref{gnutls_global_set_mem_functions} function is
+available which can be used to set other memory handlers than the
+defaults.
+
+The @acronym{Libgcrypt} library on which @acronym{GnuTLS} depends, has
+such secure memory allocation functions available. These should be
+used in cases where even the system's swap memory is not considered
+secure. See the documentation of @acronym{Libgcrypt} for more
+information.
+
address@hidden Callback functions
address@hidden Callback Functions
address@hidden Callback functions
+
+There are several cases where @acronym{GnuTLS} may need some out of
+band input from your program. This is now implemented using some
+callback functions, which your program is expected to register.
+
+An example of this type of functions are the push and pull callbacks
+which are used to specify the functions that will retrieve and send
+data to the transport layer.
+
address@hidden
+
address@hidden @ref{gnutls_transport_set_push_function}
+
address@hidden @ref{gnutls_transport_set_pull_function}
+
address@hidden itemize
+
+Other callback functions such as the one set by
address@hidden, may require more
+complicated input, including data to be allocated.  These callbacks
+should allocate and free memory using the functions shown below.
+
address@hidden
+
address@hidden @ref{gnutls_malloc}
+
address@hidden @ref{gnutls_free}
+
address@hidden itemize
+
diff --git a/doc/cha-preface.texi b/doc/cha-preface.texi
new file mode 100644
index 0000000..1c4058b
--- /dev/null
+++ b/doc/cha-preface.texi
@@ -0,0 +1,257 @@
address@hidden Preface
address@hidden Preface
+
+This document tries to demonstrate and explain the @acronym{GnuTLS}
+library API.  A brief introduction to the protocols and the technology
+involved, is also included so that an application programmer can
+better understand the @acronym{GnuTLS} purpose and actual offerings.
+Even if @acronym{GnuTLS} is a typical library software, it operates
+over several security and cryptographic protocols, which require the
+programmer to make careful and correct usage of them, otherwise he
+risks to offer just a false sense of security. Security and the
+network security terms are very general terms even for computer
+software thus cannot be easily restricted to a single cryptographic
+library.  For that reason, do not consider a program secure just
+because it uses @acronym{GnuTLS}; there are several ways to compromise
+a program or a communication line and @acronym{GnuTLS} only helps with
+some of them.
+
+Although this document tries to be self contained, basic network
+programming and PKI knowlegde is assumed in most of it. A good
+introduction to networking can be found in @xcite{STEVENS} and for
+Public Key Infrastructure in @xcite{GUTPKI}.
+
address@hidden
+
+Updated versions of the @acronym{GnuTLS} software and this document
+will be available from @url{http://www.gnutls.org/} and
address@hidden://www.gnu.org/software/gnutls/}.
+
address@hidden
+* Getting help::
+* Commercial Support::
+* Downloading and Installing::
+* Bug Reports::
+* Contributing::
address@hidden menu
+
address@hidden Getting help
address@hidden Getting Help
+
+A mailing list where users may help each other exists, and you can
+reach it by sending e-mail to @email{help-gnutls@@gnu.org}.  Archives
+of the mailing list discussions, and an interface to manage
+subscriptions, is available through the World Wide Web at
address@hidden://lists.gnu.org/mailman/listinfo/help-gnutls}.
+
+A mailing list for developers are also available, see
address@hidden://www.gnu.org/software/gnutls/lists.html}.
+
+Bug reports should be sent to @email{bug-gnutls@@gnu.org}, see
address@hidden Reports}.
+
address@hidden Commercial Support
address@hidden Commercial Support
+
+Commercial support is available for users of GnuTLS.  The kind of
+support that can be purchased may include:
+
address@hidden
+
address@hidden Implement new features.
+Such as a new TLS extension.
+
address@hidden Port GnuTLS to new platforms.
+This could include porting to an embedded platforms that may need
+memory or size optimization.
+
address@hidden Integrating TLS as a security environment in your existing 
project.
+
address@hidden System design of components related to TLS.
+
address@hidden itemize
+
+If you are interested, please write to:
+
address@hidden
+Simon Josefsson Datakonsult
+Hagagatan 24
+113 47 Stockholm
+Sweden
+
+E-mail: address@hidden
address@hidden verbatim
+
+If your company provides support related to GnuTLS and would like to
+be mentioned here, contact the author (@pxref{Bug Reports}).
+
address@hidden Downloading and Installing
address@hidden Downloading and Installing
address@hidden Installation
address@hidden Download
+
+GnuTLS is available for download from the following URL:
+
address@hidden://www.gnutls.org/download.html}
+
+The latest version is stored in a file, e.g.,
address@hidden@value{VERSION}.tar.gz} where the @address@hidden
+value is the highest version number in the directory.
+
+GnuTLS uses a Linux-like development cycle: even minor version numbers
+indicate a stable release and a odd minor version number indicates a
+development release.  For example, GnuTLS 1.6.3 denote a stable
+release since 6 is even, and GnuTLS 1.7.11 denote a development
+release since 7 is odd.
+
+GnuTLS depends on Libgcrypt,
+and you will need to install Libgcrypt
+before installing GnuTLS.  Libgcrypt is available from
address@hidden://ftp.gnupg.org/gcrypt/libgcrypt}.  Libgcrypt needs another
+library, libgpg-error, and you need to install libgpg-error before
+installing Libgcrypt.  Libgpg-error is available from
address@hidden://ftp.gnupg.org/gcrypt/libgpg-error}.
+
+Don't forget to verify the cryptographic signature after downloading
+source code packages.
+
+The package is then extracted, configured and built like many other
+packages that use Autoconf.  For detailed information on configuring
+and building it, refer to the @file{INSTALL} file that is part of the
+distribution archive.  Typically you invoke @code{./configure} and
+then @code{make check install}.  There are a number of compile-time
+parameters, as discussed below.
+
+The compression libraries (libz and lzo) are optional dependencies.
+You can get libz from @url{http://www.zlib.net/}.  You can get lzo
+from @url{http://www.oberhumer.com/opensource/lzo/}.
+
+The X.509 part of GnuTLS needs ASN.1 functionality, from a library
+called libtasn1.  A copy of libtasn1 is included in GnuTLS.  If you
+want to install it separately (e.g., to make it possibly to use
+libtasn1 in other programs), you can get it from
address@hidden://www.gnu.org/software/gnutls/download.html}.
+
+The OpenPGP part of GnuTLS uses a stripped down version of OpenCDK for
+parsing OpenPGP packets.  It is included GnuTLS.  Use parameter
address@hidden to disable the OpenPGP
+functionality in GnuTLS.  Unfortunately, we didn't have resources to
+maintain the code in a separate library.
+
+Regarding the Guile bindings, there are additional installation
+considerations, see @xref{Guile Preparations}.
+
+A few @code{configure} options may be relevant, summarized in the
+table.
+
address@hidden @code
+
address@hidden --disable-srp-authentication
address@hidden --disable-psk-authentication
address@hidden --disable-anon-authentication
address@hidden --disable-extra-pki
address@hidden --disable-openpgp-authentication
address@hidden --disable-openssl-compatibility
+Disable or enable particular features.  Generally not recommended.
+
address@hidden table
+
+For the complete list, refer to the output from @code{configure
+--help}.
+
address@hidden Bug Reports
address@hidden Bug Reports
address@hidden Reporting Bugs
+
+If you think you have found a bug in GnuTLS, please investigate it and
+report it.
+
address@hidden @bullet
+
address@hidden Please make sure that the bug is really in GnuTLS, and
+preferably also check that it hasn't already been fixed in the latest
+version.
+
address@hidden You have to send us a test case that makes it possible for us to
+reproduce the bug.
+
address@hidden You also have to explain what is wrong; if you get a crash, or
+if the results printed are not good and in that case, in what way.
+Make sure that the bug report includes all information you would need
+to fix this kind of bug for someone else.
+
address@hidden itemize
+
+Please make an effort to produce a self-contained report, with
+something definite that can be tested or debugged.  Vague queries or
+piecemeal messages are difficult to act on and don't help the
+development effort.
+
+If your bug report is good, we will do our best to help you to get a
+corrected version of the software; if the bug report is poor, we won't
+do anything about it (apart from asking you to send better bug
+reports).
+
+If you think something in this manual is unclear, or downright
+incorrect, or if the language needs to be improved, please also send a
+note.
+
+Send your bug report to:
+
address@hidden @samp{bug-gnutls@@gnu.org}
+
address@hidden Contributing
address@hidden Contributing
address@hidden Contributing
address@hidden Hacking
+
+If you want to submit a patch for inclusion -- from solve a typo you
+discovered, up to adding support for a new feature -- you should
+submit it as a bug report (@pxref{Bug Reports}).  There are some
+things that you can do to increase the chances for it to be included
+in the official package.
+
+Unless your patch is very small (say, under 10 lines) we require that
+you assign the copyright of your work to the Free Software Foundation.
+This is to protect the freedom of the project.  If you have not
+already signed papers, we will send you the necessary information when
+you submit your contribution.
+
+For contributions that doesn't consist of actual programming code, the
+only guidelines are common sense.  Use it.
+
+For code contributions, a number of style guides will help you:
+
address@hidden @bullet
+
address@hidden Coding Style.
+Follow the GNU Standards document (@pxref{top, GNU Coding Standards,,
+standards}).
+
+If you normally code using another coding standard, there is no
+problem, but you should use @samp{indent} to reformat the code
+(@pxref{top, GNU Indent,, indent}) before submitting your work.
+
address@hidden Use the unified diff format @samp{diff -u}.
+
address@hidden Return errors.
+No reason whatsoever should abort the execution of the library.  Even
+memory allocation errors, e.g. when malloc return NULL, should work
+although result in an error code.
+
address@hidden Design with thread safety in mind.
+Don't use global variables.  Don't even write to per-handle global
+variables unless the documented behaviour of the function you write is
+to write to the per-handle global variable.
+
address@hidden Avoid using the C math library.
+It causes problems for embedded implementations, and in most
+situations it is very easy to avoid using it.
+
address@hidden Document your functions.
+Use comments before each function headers, that, if properly
+formatted, are extracted into Texinfo manuals and GTK-DOC web pages.
+
address@hidden Supply a ChangeLog and NEWS entries, where appropriate.
+
address@hidden itemize
diff --git a/doc/cha-programs.texi b/doc/cha-programs.texi
new file mode 100644
index 0000000..c1b940c
--- /dev/null
+++ b/doc/cha-programs.texi
@@ -0,0 +1,853 @@
address@hidden Included programs
address@hidden Included Programs
+
+Included with @acronym{GnuTLS} are also a few command line tools that
+let you use the library for common tasks without writing an
+application.  The applications are discussed in this chapter.
+
address@hidden
+* Invoking certtool::
+* Invoking gnutls-cli::
+* Invoking gnutls-cli-debug::
+* Invoking gnutls-serv::
+* Invoking psktool::
+* Invoking srptool::
address@hidden menu
+
address@hidden Invoking certtool
address@hidden Invoking certtool
address@hidden certtool
+
+This is a program to generate @acronym{X.509} certificates, certificate
+requests, CRLs and private keys.
+
address@hidden
+Certtool help
+Usage: certtool [options]
+     -s, --generate-self-signed
+                              Generate a self-signed certificate.
+     -c, --generate-certificate
+                              Generate a signed certificate.
+     --generate-proxy         Generate a proxy certificate.
+     --generate-crl           Generate a CRL.
+     -u, --update-certificate
+                              Update a signed certificate.
+     -p, --generate-privkey   Generate a private key.
+     -q, --generate-request   Generate a PKCS #10 certificate
+                              request.
+     -e, --verify-chain       Verify a PEM encoded certificate chain.
+                              The last certificate in the chain must
+                              be a self signed one.
+     --verify-crl             Verify a CRL.
+     --generate-dh-params     Generate PKCS #3 encoded Diffie-Hellman
+                              parameters.
+     --get-dh-params          Get the included PKCS #3 encoded Diffie
+                              Hellman parameters.
+     --load-privkey FILE      Private key file to use.
+     --load-request FILE      Certificate request file to use.
+     --load-certificate FILE
+                              Certificate file to use.
+     --load-ca-privkey FILE   Certificate authority's private key
+                              file to use.
+     --load-ca-certificate FILE
+                              Certificate authority's certificate
+                              file to use.
+     --password PASSWORD      Password to use.
+     -i, --certificate-info   Print information on a certificate.
+     -l, --crl-info           Print information on a CRL.
+     --p12-info               Print information on a PKCS #12
+                              structure.
+     --p7-info                Print information on a PKCS #7
+                              structure.
+     --smime-to-p7            Convert S/MIME to PKCS #7 structure.
+     -k, --key-info           Print information on a private key.
+     --fix-key                Regenerate the parameters in a private
+                              key.
+     --to-p12                 Generate a PKCS #12 structure.
+     -8, --pkcs8              Use PKCS #8 format for private keys.
+     --dsa                    Use DSA keys.
+     --hash STR               Hash algorithm to use for signing
+                              (MD5,SHA1,RMD160).
+     --export-ciphers         Use weak encryption algorithms.
+     --inder                  Use DER format for input certificates
+                              and private keys.
+     --outder                 Use DER format for output certificates
+                              and private keys.
+     --bits BITS              specify the number of bits for key
+                              generation.
+     --outfile FILE           Output file.
+     --infile FILE            Input file.
+     --template FILE          Template file to use for non
+                              interactive operation.
+     -d, --debug LEVEL        specify the debug level. Default is 1.
+     -h, --help               shows this help text
+     -v, --version            shows the program's version
address@hidden verbatim
+
+The program can be used interactively or non interactively by
+specifying the @code{--template} command line option. See below for an
+example of a template file.
+
+How to use certtool interactively:
+
address@hidden
address@hidden
+To generate parameters for Diffie-Hellman key exchange, use the command:
address@hidden
+$ certtool --generate-dh-params --outfile dh.pem
address@hidden example
+
address@hidden
+To generate parameters for the RSA-EXPORT key exchange, use the command:
address@hidden
+$ certtool --generate-privkey --bits 512 --outfile rsa.pem
address@hidden example
+
address@hidden itemize
+
address@hidden
+
address@hidden
+To create a self signed certificate, use the command:
address@hidden
+$ certtool --generate-privkey --outfile ca-key.pem
+$ certtool --generate-self-signed --load-privkey ca-key.pem \
+   --outfile ca-cert.pem
address@hidden example
+
+Note that a self-signed certificate usually belongs to a certificate
+authority, that signs other certificates.
+
address@hidden
+To create a private key (RSA by default), run:
+
address@hidden
+$ certtool --generate-privkey --outfile key.pem
address@hidden example
+
+To create a DSA private key, run:
+
address@hidden
+$ certtool --dsa --generate-privkey --outfile key-dsa.pem
address@hidden example
+
address@hidden
+To generate a certificate using the private key, use the command:
+
address@hidden
+$ certtool --generate-certificate --load-privkey key.pem \
+   --outfile cert.pem --load-ca-certificate ca-cert.pem \
+   --load-ca-privkey ca-key.pem
address@hidden example
+
address@hidden
+To create a certificate request (needed when the certificate is issued by
+another party), run:
+
address@hidden
+$ certtool --generate-request --load-privkey key.pem \
+  --outfile request.pem
address@hidden example
+
address@hidden
+To generate a certificate using the previous request, use the command:
+
address@hidden
+$ certtool --generate-certificate --load-request request.pem \
+   --outfile cert.pem \
+   --load-ca-certificate ca-cert.pem --load-ca-privkey ca-key.pem
address@hidden example
+
address@hidden
+To view the certificate information, use:
+
address@hidden
+$ certtool --certificate-info --infile cert.pem
address@hidden example
+
address@hidden
+To generate a @acronym{PKCS} #12 structure using the previous key and
+certificate, use the command:
+
address@hidden
+$ certtool --load-certificate cert.pem --load-privkey key.pem \
+  --to-p12 --outder --outfile key.p12
address@hidden example
+
+Some tools (reportedly web browsers) have problems with that file
+because it does not contain the CA certificate for the certificate.
+To work around that problem in the tool, you can use the
address@hidden parameter as follows:
+
address@hidden
+$ certtool --load-ca-certificate ca.pem \
+  --load-certificate cert.pem --load-privkey key.pem \
+  --to-p12 --outder --outfile key.p12
address@hidden example
+
address@hidden
+Proxy certificate can be used to delegate your credential to a
+temporary, typically short-lived, certificate.  To create one from the
+previously created certificate, first create a temporary key and then
+generate a proxy certificate for it, using the commands:
+
address@hidden
+$ certtool --generate-privkey > proxy-key.pem
+$ certtool --generate-proxy --load-ca-privkey key.pem \
+  --load-privkey proxy-key.pem --load-certificate cert.pem \
+  --outfile proxy-cert.pem
address@hidden example
+
address@hidden
+To create an empty Certificate Revocation List (CRL) do:
+
address@hidden
+$ certtool --generate-crl --load-ca-privkey x509-ca-key.pem 
--load-ca-certificate x509-ca.pem
address@hidden example
+
+To create a CRL that contains some revoked certificates, place the
+certificates in a file and use @code{--load-certificate} as follows:
+
address@hidden
+$ certtool --generate-crl --load-ca-privkey x509-ca-key.pem 
--load-ca-certificate x509-ca.pem --load-certificate revoked-certs.pem
address@hidden example
+
address@hidden
+To verify a Certificate Revocation List (CRL) do:
+
address@hidden
+$ certtool --verify-crl --load-ca-certificate x509-ca.pem < crl.pem
address@hidden example
+
address@hidden itemize
+
+Certtool's template file format:
+
address@hidden
+
address@hidden
+Firstly create a file named 'cert.cfg' that contains the information
+about the certificate. An example file is listed below.
+
address@hidden
+Then execute:
+
address@hidden
+$ certtool --generate-certificate cert.pem --load-privkey key.pem  \
+   --template cert.cfg \
+   --load-ca-certificate ca-cert.pem --load-ca-privkey ca-key.pem
address@hidden example
+
address@hidden itemize
+
+An example certtool template file:
+
address@hidden
+# X.509 Certificate options
+#
+# DN options
+
+# The organization of the subject.
+organization = "Koko inc."
+
+# The organizational unit of the subject.
+unit = "sleeping dept."
+
+# The locality of the subject.
+# locality =
+
+# The state of the certificate owner.
+state = "Attiki"
+
+# The country of the subject. Two letter code.
+country = GR
+
+# The common name of the certificate owner.
+cn = "Cindy Lauper"
+
+# A user id of the certificate owner.
+#uid = "clauper"
+
+# If the supported DN OIDs are not adequate you can set
+# any OID here.
+# For example set the X.520 Title and the X.520 Pseudonym
+# by using OID and string pairs.
+#dn_oid = "2.5.4.12" "Dr." "2.5.4.65" "jackal"
+
+# This is deprecated and should not be used in new
+# certificates.
+# pkcs9_email = "none@@none.org"
+
+# The serial number of the certificate
+serial = 007
+
+# In how many days, counting from today, this certificate will expire.
+expiration_days = 700
+
+# X.509 v3 extensions
+
+# A dnsname in case of a WWW server.
+#dns_name = "www.none.org"
+#dns_name = "www.morethanone.org"
+
+# An IP address in case of a server.
+#ip_address = "192.168.1.1"
+
+# An email in case of a person
+email = "none@@none.org"
+
+# An URL that has CRLs (certificate revocation lists)
+# available. Needed in CA certificates.
+#crl_dist_points = "http://www.getcrl.crl/getcrl/";
+
+# Whether this is a CA certificate or not
+#ca
+
+# Whether this certificate will be used for a TLS client
+#tls_www_client
+
+# Whether this certificate will be used for a TLS server
+#tls_www_server
+
+# Whether this certificate will be used to sign data (needed
+# in TLS DHE ciphersuites).
+signing_key
+
+# Whether this certificate will be used to encrypt data (needed
+# in TLS RSA ciphersuites). Note that it is preferred to use different
+# keys for encryption and signing.
+#encryption_key
+
+# Whether this key will be used to sign other certificates.
+#cert_signing_key
+
+# Whether this key will be used to sign CRLs.
+#crl_signing_key
+
+# Whether this key will be used to sign code.
+#code_signing_key
+
+# Whether this key will be used to sign OCSP data.
+#ocsp_signing_key
+
+# Whether this key will be used for time stamping.
+#time_stamping_key
address@hidden example
+
address@hidden Invoking gnutls-cli
address@hidden Invoking gnutls-cli
address@hidden gnutls-cli
+
+Simple client program to set up a TLS connection to some other
+computer.  It sets up a TLS connection and forwards data from the
+standard input to the secured socket and vice versa.
+
address@hidden
+GnuTLS test client
+Usage:  gnutls-cli [options] hostname
+
+     -d, --debug integer      Enable debugging
+     -r, --resume             Connect, establish a session. Connect
+                              again and resume this session.
+     -s, --starttls           Connect, establish a plain session and
+                              start TLS when EOF or a SIGALRM is
+                              received.
+     --crlf                   Send CR LF instead of LF.
+     --x509fmtder             Use DER format for certificates to read
+                              from.
+     -f, --fingerprint        Send the openpgp fingerprint, instead
+                              of the key.
+     --disable-extensions     Disable all the TLS extensions.
+     --print-cert             Print the certificate in PEM format.
+     --recordsize integer     The maximum record size to advertize.
+     -V, --verbose            More verbose output.
+     --ciphers cipher1 cipher2...
+                              Ciphers to enable.
+     --protocols protocol1 protocol2...
+                              Protocols to enable.
+     --comp comp1 comp2...    Compression methods to enable.
+     --macs mac1 mac2...      MACs to enable.
+     --kx kx1 kx2...          Key exchange methods to enable.
+     --ctypes certType1 certType2...
+                              Certificate types to enable.
+     --priority PRIORITY STRING
+                              Priorities string.
+     --x509cafile FILE        Certificate file to use.
+     --x509crlfile FILE       CRL file to use.
+     --pgpkeyfile FILE        PGP Key file to use.
+     --pgpkeyring FILE        PGP Key ring file to use.
+     --pgpcertfile FILE       PGP Public Key (certificate) file to
+                              use.
+     --pgpsubkey HEX|auto     PGP subkey to use.
+     --x509keyfile FILE       X.509 key file to use.
+     --x509certfile FILE      X.509 Certificate file to use.
+     --srpusername NAME       SRP username to use.
+     --srppasswd PASSWD       SRP password to use.
+     --pskusername NAME       PSK username to use.
+     --pskkey KEY             PSK key (in hex) to use.
+     --opaque-prf-input DATA
+                              Use Opaque PRF Input DATA.
+     -p, --port PORT          The port to connect to.
+     --insecure               Don't abort program if server
+                              certificate can't be validated.
+     -l, --list               Print a list of the supported
+                              algorithms and modes.
+     -h, --help               prints this help
+     -v, --version            prints the program's version number
address@hidden verbatim
+
+To connect to a server using PSK authentication, you may use something
+like:
+
address@hidden
+$ gnutls-cli -p 5556 test.gnutls.org --pskusername jas --pskkey 
9e32cf7786321a828ef7668f09fb35db --priority NORMAL:+PSK:-RSA:-DHE-RSA -d 4711
address@hidden smallexample
+
address@hidden
+* Example client PSK connection::
address@hidden menu
+
address@hidden Example client PSK connection
address@hidden Example client PSK connection
address@hidden PSK client
+
+If your server only supports the PSK ciphersuite, connecting to it
+should be as simple as connecting to the server:
+
address@hidden
+$ ./gnutls-cli -p 5556 localhost
+Resolving 'localhost'...
+Connecting to '127.0.0.1:5556'...
+- PSK client callback. PSK hint 'psk_identity_hint'
+Enter PSK identity: psk_identity
+Enter password: 
+- PSK authentication. PSK hint 'psk_identity_hint'
+- Version: TLS1.1
+- Key Exchange: PSK
+- Cipher: AES-128-CBC
+- MAC: SHA1
+- Compression: NULL
+- Handshake was completed
+
+- Simple Client Mode:
address@hidden smallexample
+
+If the server supports several cipher suites, you may need to force it
+to chose PSK by using a cipher priority parameter such as
address@hidden NORMAL:+PSK:-RSA:-DHE-RSA:-DHE-PSK}.
+
address@hidden Netconf
+Instead of using the Netconf-way to derive the PSK key from a
+password, you can also give the PSK username and key directly on the
+command line:
+
address@hidden
+$ ./gnutls-cli -p 5556 localhost --pskusername psk_identity --pskkey 
88f3824b3e5659f52d00e959bacab954b6540344 
+Resolving 'localhost'...
+Connecting to '127.0.0.1:5556'...
+- PSK authentication. PSK hint 'psk_identity_hint'
+- Version: TLS1.1
+- Key Exchange: PSK
+- Cipher: AES-128-CBC
+- MAC: SHA1
+- Compression: NULL
+- Handshake was completed
+
+- Simple Client Mode:
address@hidden smallexample
+
+By keeping the @code{--pskusername} parameter and removing the
address@hidden parameter, it will query only for the password during
+the handshake.
+
address@hidden Invoking gnutls-cli-debug
address@hidden Invoking gnutls-cli-debug
address@hidden gnutls-cli-debug
+
+This program was created to assist in debugging @acronym{GnuTLS}, but
+it might be useful to extract a @acronym{TLS} server's capabilities.
+It's purpose is to connect onto a @acronym{TLS} server, perform some
+tests and print the server's capabilities. If called with the `-v'
+parameter a more checks will be performed. An example output is:
+
address@hidden
+crystal:/cvs/gnutls/src$ ./gnutls-cli-debug localhost -p 5556
+Resolving 'localhost'...
+Connecting to '127.0.0.1:5556'...
+Checking for TLS 1.1 support... yes
+Checking fallback from TLS 1.1 to... N/A
+Checking for TLS 1.0 support... yes
+Checking for SSL 3.0 support... yes
+Checking for version rollback bug in RSA PMS... no
+Checking for version rollback bug in Client Hello... no
+Checking whether we need to disable TLS 1.0... N/A
+Checking whether the server ignores the RSA PMS version... no
+Checking whether the server can accept Hello Extensions... yes
+Checking whether the server can accept cipher suites not in SSL 3.0 spec... yes
+Checking whether the server can accept a bogus TLS record version in the 
client hello... yes
+Checking for certificate information... N/A
+Checking for trusted CAs... N/A
+Checking whether the server understands TLS closure alerts... yes
+Checking whether the server supports session resumption... yes
+Checking for export-grade ciphersuite support... no
+Checking RSA-export ciphersuite info... N/A
+Checking for anonymous authentication support... no
+Checking anonymous Diffie-Hellman group info... N/A
+Checking for ephemeral Diffie-Hellman support... no
+Checking ephemeral Diffie-Hellman group info... N/A
+Checking for AES cipher support (TLS extension)... yes
+Checking for 3DES cipher support... yes
+Checking for ARCFOUR 128 cipher support... yes
+Checking for ARCFOUR 40 cipher support... no
+Checking for MD5 MAC support... yes
+Checking for SHA1 MAC support... yes
+Checking for ZLIB compression support (TLS extension)... yes
+Checking for LZO compression support (GnuTLS extension)... yes
+Checking for max record size (TLS extension)... yes
+Checking for SRP authentication support (TLS extension)... yes
+Checking for OpenPGP authentication support (TLS extension)... no
address@hidden smallexample
+
address@hidden Invoking gnutls-serv
address@hidden Invoking gnutls-serv
address@hidden gnutls-serv
+
+Simple server program that listens to incoming TLS connections.
+
address@hidden
+GnuTLS test server
+Usage: gnutls-serv [options]
+
+     -d, --debug integer      Enable debugging
+     -g, --generate           Generate Diffie-Hellman Parameters.
+     -p, --port integer       The port to connect to.
+     -q, --quiet              Suppress some messages.
+     --nodb                   Does not use the resume database.
+     --http                   Act as an HTTP Server.
+     --echo                   Act as an Echo Server.
+     --dhparams FILE          DH params file to use.
+     --x509fmtder             Use DER format for certificates
+     --x509cafile FILE        Certificate file to use.
+     --x509crlfile FILE       CRL file to use.
+     --pgpkeyring FILE        PGP Key ring file to use.
+     --pgpkeyfile FILE        PGP Key file to use.
+     --pgpcertfile FILE       PGP Public Key (certificate) file to
+                              use.
+     --pgpsubkey HEX|auto     PGP subkey to use.
+     --x509keyfile FILE       X.509 key file to use.
+     --x509certfile FILE      X.509 Certificate file to use.
+     --x509dsakeyfile FILE    Alternative X.509 key file to use.
+     --x509dsacertfile FILE   Alternative X.509 certificate file to
+                              use.
+     -r, --require-cert       Require a valid certificate.
+     -a, --disable-client-cert
+                              Disable request for a client
+                              certificate.
+     --pskpasswd FILE         PSK password file to use.
+     --pskhint HINT           PSK identity hint to use.
+     --srppasswd FILE         SRP password file to use.
+     --srppasswdconf FILE     SRP password conf file to use.
+     --opaque-prf-input DATA
+                              Use Opaque PRF Input DATA.
+     --ciphers cipher1 cipher2...
+                              Ciphers to enable.
+     --protocols protocol1 protocol2...
+                              Protocols to enable.
+     --comp comp1 comp2...    Compression methods to enable.
+     --macs mac1 mac2...      MACs to enable.
+     --kx kx1 kx2...          Key exchange methods to enable.
+     --ctypes certType1 certType2...
+                              Certificate types to enable.
+     --priority PRIORITY STRING
+                              Priorities string.
+     -l, --list               Print a list of the supported
+                              algorithms  and modes.
+     -h, --help               prints this help
+     -v, --version            prints the program's version number
address@hidden verbatim
+
address@hidden Setting Up a Test HTTPS Server
address@hidden HTTPS server
address@hidden debug server
+
+Running your own TLS server based on GnuTLS can be useful when
+debugging clients and/or GnuTLS itself.  This section describes how to
+use @code{gnutls-serv} as a simple HTTPS server.
+
+The most basic server can be started as:
+
address@hidden
+gnutls-serv --http
address@hidden example
+
+It will only support anonymous ciphersuites, which many TLS clients
+refuse to use.
+
+The next step is to add support for X.509.  First we generate a CA:
+
address@hidden
+certtool --generate-privkey > x509-ca-key.pem
+echo 'cn = GnuTLS test CA' > ca.tmpl
+echo 'ca' >> ca.tmpl
+echo 'cert_signing_key' >> ca.tmpl
+certtool --generate-self-signed --load-privkey x509-ca-key.pem \
+  --template ca.tmpl --outfile x509-ca.pem
+...
address@hidden example
+
+Then generate a server certificate.  Remember to change the dns_name
+value to the name of your server host, or skip that command to avoid
+the field.
+
address@hidden
+certtool --generate-privkey > x509-server-key.pem
+echo 'organization = GnuTLS test server' > server.tmpl
+echo 'cn = test.gnutls.org' >> server.tmpl
+echo 'tls_www_server' >> server.tmpl
+echo 'encryption_key' >> server.tmpl
+echo 'signing_key' >> server.tmpl
+echo 'dns_name = test.gnutls.org' >> server.tmpl
+certtool --generate-certificate --load-privkey x509-server-key.pem \
+  --load-ca-certificate x509-ca.pem --load-ca-privkey x509-ca-key.pem \
+  --template server.tmpl --outfile x509-server.pem
+...
address@hidden example
+
+For use in the client, you may want to generate a client certificate
+as well.
+
address@hidden
+certtool --generate-privkey > x509-client-key.pem
+echo 'cn = GnuTLS test client' > client.tmpl
+echo 'tls_www_client' >> client.tmpl
+echo 'encryption_key' >> client.tmpl
+echo 'signing_key' >> client.tmpl
+certtool --generate-certificate --load-privkey x509-client-key.pem \
+  --load-ca-certificate x509-ca.pem --load-ca-privkey x509-ca-key.pem \
+  --template client.tmpl --outfile x509-client.pem
+...
address@hidden example
+
+To be able to import the client key/certificate into some
+applications, you will need to convert them into a PKCS#12 structure.
+This also encrypts the security sensitive key with a password.
+
address@hidden
+certtool --to-p12 --load-ca-certificate x509-ca.pem --load-privkey 
x509-client-key.pem --load-certificate x509-client.pem --outder --outfile 
x509-client.p12
address@hidden example
+
+For icing, we'll create a proxy certificate for the client too.
+
address@hidden
+certtool --generate-privkey > x509-proxy-key.pem
+echo 'cn = GnuTLS test client proxy' > proxy.tmpl
+certtool --generate-proxy --load-privkey x509-proxy-key.pem \
+  --load-ca-certificate x509-client.pem --load-ca-privkey x509-client-key.pem \
+  --load-certificate x509-client.pem --template proxy.tmpl \
+  --outfile x509-proxy.pem
+...
address@hidden example
+
+Then start the server again:
+
address@hidden
+gnutls-serv --http \
+            --x509cafile x509-ca.pem \
+            --x509keyfile x509-server-key.pem \
+            --x509certfile x509-server.pem
address@hidden example
+
+Try connecting to the server using your web browser.  Note that the
+server listens to port 5556 by default.
+
+While you are at it, to allow connections using DSA, you can also
+create a DSA key and certificate for the server.  These credentials
+will be used in the final example below.
+
address@hidden
+certtool --generate-privkey --dsa > x509-server-key-dsa.pem
+certtool --generate-certificate --load-privkey x509-server-key-dsa.pem \
+  --load-ca-certificate x509-ca.pem --load-ca-privkey x509-ca-key.pem \
+  --template server.tmpl --outfile x509-server-dsa.pem
+...
address@hidden example
+
+The next step is to create OpenPGP credentials for the server.
+
address@hidden
+gpg --gen-key
+...enter whatever details you want, use 'test.gnutls.org' as name...
address@hidden example
+
+Make a note of the OpenPGP key identifier of the newly generated key,
+here it was @code{5D1D14D8}.  You will need to export the key for
+GnuTLS to be able to use it.
+
address@hidden
+gpg -a --export 5D1D14D8 > openpgp-server.txt
+gpg --export 5D1D14D8 > openpgp-server.bin
+gpg --export-secret-keys 5D1D14D8 > openpgp-server-key.bin
+gpg -a --export-secret-keys 5D1D14D8 > openpgp-server-key.txt
address@hidden example
+
+Let's start the server with support for OpenPGP credentials:
+
address@hidden
+gnutls-serv --http \
+            --pgpkeyfile openpgp-server-key.txt \
+            --pgpcertfile openpgp-server.txt
address@hidden example
+
+The next step is to add support for SRP authentication.
+
address@hidden
+srptool --create-conf srp-tpasswd.conf
+srptool --passwd-conf srp-tpasswd.conf --username jas --passwd srp-passwd.txt
+Enter password: [TYPE "foo"]
address@hidden example
+
+Start the server with SRP support:
+
address@hidden
+gnutls-serv --http \
+            --srppasswdconf srp-tpasswd.conf \
+            --srppasswd srp-passwd.txt
address@hidden example
+
+Let's also add support for PSK.
+
address@hidden
+$ psktool --passwd psk-passwd.txt
address@hidden example
+
+Start the server with PSK support:
+
address@hidden
+gnutls-serv --http \
+            --pskpasswd psk-passwd.txt
address@hidden example
+
+Finally, we start the server with all the earlier parameters and you
+get this command:
+
address@hidden
+gnutls-serv --http \
+            --x509cafile x509-ca.pem \
+            --x509keyfile x509-server-key.pem \
+            --x509certfile x509-server.pem \
+            --x509dsakeyfile x509-server-key-dsa.pem \
+            --x509dsacertfile x509-server-dsa.pem \
+            --pgpkeyfile openpgp-server-key.txt \
+            --pgpcertfile openpgp-server.txt \
+            --srppasswdconf srp-tpasswd.conf \
+            --srppasswd srp-passwd.txt \
+            --pskpasswd psk-passwd.txt
address@hidden example
+
address@hidden
+* Example server PSK connection::
address@hidden menu
+
address@hidden Example server PSK connection
address@hidden Example server PSK connection
address@hidden PSK server
+
+To set up a PSK server with @code{gnutls-serv} you need to create PSK
+password file (@pxref{Invoking psktool}).  In the example below, I
+type @code{password} at the prompt.
+
address@hidden
+$ ./psktool -u psk_identity -p psks.txt -n psk_identity_hint
+Enter password:
+Key stored to psks.txt
+$ cat psks.txt
+psk_identity:88f3824b3e5659f52d00e959bacab954b6540344
+$
address@hidden smallexample
+
+After this, start the server pointing to the password file.  We
+disable DHE-PSK.
+
address@hidden
+$ ./gnutls-serv --pskpasswd psks.txt  --pskhint psk_identity_hint --priority 
NORMAL:-DHE-PSK
+Set static Diffie-Hellman parameters, consider --dhparams.
+Echo Server ready. Listening to port '5556'.
address@hidden smallexample
+
+You can now connect to the server using a PSK client (@pxref{Example
+client PSK connection}).
+
address@hidden Invoking psktool
address@hidden Invoking psktool
address@hidden psktool
+
+This is a program to manage @acronym{PSK} username and keys.
+
address@hidden
+PSKtool help
+Usage : psktool [options]
+     -u, --username username
+                              specify username.
+     -p, --passwd FILE        specify a password file.
+     -n, --netconf-hint HINT
+                              derive key from Netconf password, using 
+                              HINT as the psk_identity_hint.
+     -s, --keysize SIZE       specify the key size in bytes.
+     -v, --version            prints the program's version number
+     -h, --help               shows this help text
address@hidden verbatim
+
+Normally the file will generate random keys for the indicate username.
+You may also derive PSK keys from passwords, using the algorithm
+specified in @file{draft-ietf-netconf-tls-02.txt}.  The algorithm
+needs a PSK identity hint, which you specify using
address@hidden  To derive a PSK key from a password with an
+empty PSK identity hint, using @code{--netconf-hint ""}.
+
address@hidden Invoking srptool
address@hidden Invoking srptool
address@hidden
address@hidden srptool
+
+The @file{srptool} is a very simple program that emulates the programs
+in the @emph{Stanford SRP libraries}, see
address@hidden://srp.stanford.edu/}.  It is intended for use in places
+where you don't expect @acronym{SRP} authentication to be the used for
+system users.
+
+Traditionally @emph{libsrp} used two files. One called @code{tpasswd}
+which holds usernames and verifiers, and @code{tpasswd.conf} which
+holds generators and primes.
+
+How to use srptool:
+
address@hidden
+
address@hidden
+To create tpasswd.conf which holds the g and n values for
address@hidden protocol (generator and a large prime), run:
+
address@hidden
+$ srptool --create-conf /etc/tpasswd.conf
address@hidden example
+
address@hidden
+This command will create /etc/tpasswd and will add user 'test' (you
+will also be prompted for a password).  Verifiers are stored by
+default in the way libsrp expects.
+
address@hidden
+$ srptool --passwd /etc/tpasswd \
+    --passwd-conf /etc/tpasswd.conf -u test
address@hidden example
+
address@hidden
+This command will check against a password.  If the password matches
+the one in /etc/tpasswd you will get an ok.
+
address@hidden
+$ srptool --passwd /etc/tpasswd \
+    --passwd-conf /etc/tpasswd.conf --verify -u test
address@hidden example
+
address@hidden itemize
diff --git a/doc/cha-tls-app.texi b/doc/cha-tls-app.texi
new file mode 100644
index 0000000..a34d891
--- /dev/null
+++ b/doc/cha-tls-app.texi
@@ -0,0 +1,130 @@
address@hidden How to use TLS in application protocols
address@hidden How To Use @acronym{TLS} in Application Protocols
+
+This chapter is intended to provide some hints on how to use the
address@hidden over simple custom made application protocols.  The
+discussion below mainly refers to the @emph{TCP/IP} transport layer
+but may be extended to other ones too.
+
address@hidden
+* Separate ports::
+* Upward negotiation::
address@hidden menu
+
address@hidden Separate ports
address@hidden Separate Ports
+
+Traditionally @acronym{SSL} was used in application protocols by
+assigning a new port number for the secure services. That way two
+separate ports were assigned, one for the non secure sessions, and one
+for the secured ones. This has the benefit that if a user requests a
+secure session then the client will try to connect to the secure port
+and fail otherwise. The only possible attack with this method is a
+denial of service one. The most famous example of this method is the
+famous ``HTTP over TLS'' or @acronym{HTTPS} protocol @xcite{RFC2818}.
+
+Despite its wide use, this method is not as good as it seems.  This
+approach starts the @acronym{TLS} Handshake procedure just after the
+client connects on the ---so called--- secure port.  That way the
address@hidden protocol does not know anything about the client, and
+popular methods like the host advertising in HTTP do not
address@hidden also the Server Name Indication extension on
address@hidden  There is no way for the client to say ``I
+connected to YYY server'' before the Handshake starts, so the server
+cannot possibly know which certificate to use.
+
+Other than that it requires two separate ports to run a single
+service, which is unnecessary complication. Due to the fact that there
+is a limitation on the available privileged ports, this approach was
+soon obsoleted.
+
address@hidden Upward negotiation
address@hidden Upward Negotiation
+
+Other application address@hidden LDAP, IMAP etc.}  use a
+different approach to enable the secure layer.  They use something
+called the ``TLS upgrade'' method. This method is quite tricky but it
+is more flexible. The idea is to extend the application protocol to
+have a ``STARTTLS'' request, whose purpose it to start the TLS
+protocols just after the client requests it.  This is a really neat
+idea and does not require an extra port.
+
+This method is used by almost all modern protocols and there is even
+the @xcite{RFC2817} paper which proposes extensions to HTTP to support
+it.
+
+The tricky part, in this method, is that the ``STARTTLS'' request is
+sent in the clear, thus is vulnerable to modifications.  A typical
+attack is to modify the messages in a way that the client is fooled
+and thinks that the server does not have the ``STARTTLS'' capability.
+See a typical conversation of a hypothetical protocol:
+
address@hidden
+(client connects to the server)
+
+CLIENT: HELLO I'M MR. XXX
+
+SERVER: NICE TO MEET YOU XXX
+
+CLIENT: PLEASE START TLS
+
+SERVER: OK
+
+*** TLS STARTS
+
+CLIENT: HERE ARE SOME CONFIDENTIAL DATA
address@hidden quotation
+
+And see an example of a conversation where someone is acting
+in between:
+
address@hidden
+(client connects to the server)
+
+CLIENT: HELLO I'M MR. XXX
+
+SERVER: NICE TO MEET YOU XXX
+
+CLIENT: PLEASE START TLS
+
+(here someone inserts this message)
+
+SERVER: SORRY I DON'T HAVE THIS CAPABILITY
+
+CLIENT: HERE ARE SOME CONFIDENTIAL DATA
address@hidden quotation
+
+As you can see above the client was fooled, and was dummy enough to
+send the confidential data in the clear.
+
+How to avoid the above attack? As you may have already thought this
+one is easy to avoid. The client has to ask the user before it
+connects whether the user requests @acronym{TLS} or not. If the user
+answered that he certainly wants the secure layer the last
+conversation should be:
+
address@hidden
+(client connects to the server)
+
+CLIENT: HELLO I'M MR. XXX
+
+SERVER: NICE TO MEET YOU XXX
+
+CLIENT: PLEASE START TLS
+
+(here someone inserts this message)
+
+SERVER: SORRY I DON'T HAVE THIS CAPABILITY
+
+CLIENT: BYE
+
+(the client notifies the user that the secure connection was not possible)
address@hidden quotation
+
+This method, if implemented properly, is far better than the
+traditional method, and the security properties remain the same, since
+only denial of service is possible. The benefit is that the server may
+request additional data before the @acronym{TLS} Handshake protocol
+starts, in order to send the correct certificate, use the correct
+password address@hidden @acronym{SRP} authentication}, or anything
+else!
diff --git a/doc/credentials/x509-server-dsa.pem 
b/doc/credentials/x509-server-dsa.pem
index e265f53..3eeefee 100644
--- a/doc/credentials/x509-server-dsa.pem
+++ b/doc/credentials/x509-server-dsa.pem
@@ -1,21 +1,29 @@
 -----BEGIN CERTIFICATE-----
-MIIDbzCCAtqgAwIBAgIERiYdRTALBgkqhkiG9w0BAQUwGTEXMBUGA1UEAxMOR251
-VExTIHRlc3QgQ0EwHhcNMDcwNDE4MTMyOTQxWhcNMDgwNDE3MTMyOTQxWjA3MRsw
+MIIE/TCCBGigAwIBAgIES/zFKTALBgkqhkiG9w0BAQUwGTEXMBUGA1UEAxMOR251
+VExTIHRlc3QgQ0EwHhcNMTAwNTI2MDY1MjI1WhcNMTEwNTI2MDY1MjI1WjA3MRsw
 GQYDVQQKExJHbnVUTFMgdGVzdCBzZXJ2ZXIxGDAWBgNVBAMTD3Rlc3QuZ251dGxz
-Lm9yZzCCAbQwggEpBgcqhkjOOAQBMIIBHAKBgLmE9VqBvhoNxYpzjwybL5u2DkvD
-dBp/ZK2d8yjFoEe8m1dW8ZfVfjcD6fJM9OOLfzCjXS+7oaI3wuo1jx+xX6aiXwHx
-IzYr5E8vLd2d1TqmOa96UXzSJY6XdM8exXtLdkOBBx8GFLhuWBLhkOI3b9Ib7GjF
-WOLmMOBqXixjeOwHAhSfVoxIZC/+jap6bZbbBF0W7wilcQKBgGIGfuRcdgi3Rhpd
-15fUKiH7HzHJ0vT6Odgn0Zv8J12nCqca/FPBL0PCN8iFfz1Mq12BMvsdXh5UERYg
-xoBa2YybQ/Dda6D0w/KKnDnSHHsP7/ook4/SoSLr3OCKi60oDs/vCYXpNr2LelDV
-e/clDWxgEcTvcJDP1hvru47GPjqXA4GEAAKBgA+Kh1fy0cLcrN9Liw+Luin34QPk
-VfqymAfW/RKxgLz1urRQ1H+gDkPnn8l4EV/l5Awsa2qkNdy9VOVgNpox0YpZbmsc
-ur0uuut8h+/ayN2h66SD5out+vqOW9c3yDI+lsI+9EPafZECD7e8+O+P90EAXpbf
-DwiW3Oqy6QaCr9Ivo4GTMIGQMAwGA1UdEwEB/wQCMAAwGgYDVR0RBBMwEYIPdGVz
-dC5nbnV0bHMub3JnMBMGA1UdJQQMMAoGCCsGAQUFBwMBMA8GA1UdDwEB/wQFAwMH
-gAAwHQYDVR0OBBYEFL/su87Y6HtwVuzz0SuS1tSZClvzMB8GA1UdIwQYMBaAFOk8
-HPutkm7mBqRWLKLhwFMnyPKVMAsGCSqGSIb3DQEBBQOBgQBCsrnfD1xzh8/Eih1f
-x+M0lPoX1Re5L2ElHI6DJpHYOBPwf9glwxnet2+avzgUQDUFwUSxOhodpyeaACXD
-o0gGVpcH8sOBTQ+aTdM37hGkPxoXjtIkR/LgG5nP2H2JRd5TkW8l13JdM4MJFB4W
-QcDzQ8REwidsfh9uKAluk1c/KQ==
+Lm9yZzCCA0IwggI1BgcqhkjOOAQBMIICKAKCAQEA2WCq/yFVVSGBObDJyPSqhFBb
+0afpzBVCKFssgWYR/1++gEg4h0t2nq3KnIXGr+g/BnCotORdVLSQMIGmTlGlf1Ox
+BwGREF666muCJbcdjFYYWcIsPiP0zZaVQnpbtkLF0ZpVmPYHGGqd/OK3UZjElUrc
+kTf/irRrRTFcPDEh0SNYaTEfLtvL6EG3bcospSYMmCJs/X4MWFodpShAT4wVY+VD
+C5nhD9lEZxO0dCoI7pW0e4Is2hT8cc/MEkRedcL4FDhd5Pp95VPOb1Ihjr9A5GMQ
+Lp2GETVnbOMgbI24BJZGTMqBKWCo/hhheqggLJL/tMVyvHpPBPHbL3GwPtkY1wId
+APRKRttVoI7jrivXwJZcM64YnbxSln7PvdjyP+kCggEATb+OCfC9uIUQ+B6thS3A
+iit46KZVvpG+x4mWlK+ZFyIANq7wRHY22cKtlizmjh7tvhn6jPzjJo9nigEgqOtw
+B2ig6jlRclOcqCgxOGrubxUh7uxKCY77krNet+bMiXwJ6XNoEhcMSq3OrT5AROQU
+q6E/HCz4DLrItVp/1eo1nUshrhAzcLZmqL0Sb7WPd8BshkWKdq1jsLDBSHem9wfq
+Zz3UJAk0Xvslr6SWoAXohwUvxfgazQUS2XGpI7qRoA3/G008jhbzIr+CXNc3JFu1
+A1pgSsZ/hEnvlM/NeqJA2cuFWgR35lR9hmjh3qf6heL0zbpISA9OaoLI3LgZArJo
+8gOCAQUAAoIBACpigcfx8ylgXKNZFK4c8DAGeTYld4z510PA29fYbagZtogyASgy
+DlpMdlNdtZbPZUTjjP2QgqfX00Jfo+Y25cV9qxuMlJJPDQvC5mXJoIooH+yXERQ9
+MghetZWvaxO+lucVaDWjBR6bvfwI1UdEfGBlZVNgxmNOsIWtEk2ecYs8Mlr1b2D6
+WXI45Y7j6ZAXJDqdIhRX53qCJjjJTC/w5lcLxNjP2g0MWXqANEtAqnht5IcUGd3w
++HlMxrQc0vJv+CXrwGH/O8TaNdCMTw2oS+/T34o+A1g7wCCbJy9sfjS7cHXJzi+h
+Oozprf9pQCVXlbheoXY9io19IfEv420nT2ejgZMwgZAwDAYDVR0TAQH/BAIwADAa
+BgNVHREEEzARgg90ZXN0LmdudXRscy5vcmcwEwYDVR0lBAwwCgYIKwYBBQUHAwEw
+DwYDVR0PAQH/BAUDAweAADAdBgNVHQ4EFgQUaMlZ8SavkapRIvMJUWfhbI3seMQw
+HwYDVR0jBBgwFoAU6Twc+62SbuYGpFYsouHAUyfI8pUwCwYJKoZIhvcNAQEFA4GB
+AKG9nyfVLkJ5KPQ2nbD4Jn1EeOGNWESroYJCQZdB/s3yKdNuZFXByr5pY/9RTjVt
+dNyHm7nTqWtDPeeNLelD7R08b5aVDHSn0P1VDZxomtQrUSHvyk8/K+gC7ipj3OcJ
+To7cYX+WY0KCVp++O0nvkVz31tcRTDkd9EHm10Yj3q61
 -----END CERTIFICATE-----
diff --git a/doc/credentials/x509-server-key-dsa.pem 
b/doc/credentials/x509-server-key-dsa.pem
index bfc417c..b103672 100644
--- a/doc/credentials/x509-server-key-dsa.pem
+++ b/doc/credentials/x509-server-key-dsa.pem
@@ -1,12 +1,20 @@
 -----BEGIN DSA PRIVATE KEY-----
-MIIBugIBAAKBgQC5hPVagb4aDcWKc48Mmy+btg5Lw3Qaf2StnfMoxaBHvJtXVvGX
-1X43A+nyTPTji38wo10vu6GiN8LqNY8fsV+mol8B8SM2K+RPLy3dndU6pjmvelF8
-0iWOl3TPHsV7S3ZDgQcfBhS4blgS4ZDiN2/SG+xoxVji5jDgal4sY3jsBwIVAJ9W
-jEhkL/6NqnptltsEXRbvCKVxAoGAYgZ+5Fx2CLdGGl3Xl9QqIfsfMcnS9Po52CfR
-m/wnXacKpxr8U8EvQ8I3yIV/PUyrXYEy+x1eHlQRFiDGgFrZjJtD8N1roPTD8oqc
-OdIcew/v+iiTj9KhIuvc4IqLrSgOz+8Jhek2vYt6UNV79yUNbGARxO9wkM/WG+u7
-jsY+OpcCgYAPiodX8tHC3KzfS4sPi7op9+ED5FX6spgH1v0SsYC89bq0UNR/oA5D
-55/JeBFf5eQMLGtqpDXcvVTlYDaaMdGKWW5rHLq9LrrrfIfv2sjdoeukg+aLrfr6
-jlvXN8gyPpbCPvRD2n2RAg+3vPjvj/dBAF6W3w8IltzqsukGgq/SLwIUS5/r/2ya
-AoNBXjeBjgCGMei2m8E=
+MIIDTQIBAAKCAQEA2WCq/yFVVSGBObDJyPSqhFBb0afpzBVCKFssgWYR/1++gEg4
+h0t2nq3KnIXGr+g/BnCotORdVLSQMIGmTlGlf1OxBwGREF666muCJbcdjFYYWcIs
+PiP0zZaVQnpbtkLF0ZpVmPYHGGqd/OK3UZjElUrckTf/irRrRTFcPDEh0SNYaTEf
+LtvL6EG3bcospSYMmCJs/X4MWFodpShAT4wVY+VDC5nhD9lEZxO0dCoI7pW0e4Is
+2hT8cc/MEkRedcL4FDhd5Pp95VPOb1Ihjr9A5GMQLp2GETVnbOMgbI24BJZGTMqB
+KWCo/hhheqggLJL/tMVyvHpPBPHbL3GwPtkY1wIdAPRKRttVoI7jrivXwJZcM64Y
+nbxSln7PvdjyP+kCggEATb+OCfC9uIUQ+B6thS3Aiit46KZVvpG+x4mWlK+ZFyIA
+Nq7wRHY22cKtlizmjh7tvhn6jPzjJo9nigEgqOtwB2ig6jlRclOcqCgxOGrubxUh
+7uxKCY77krNet+bMiXwJ6XNoEhcMSq3OrT5AROQUq6E/HCz4DLrItVp/1eo1nUsh
+rhAzcLZmqL0Sb7WPd8BshkWKdq1jsLDBSHem9wfqZz3UJAk0Xvslr6SWoAXohwUv
+xfgazQUS2XGpI7qRoA3/G008jhbzIr+CXNc3JFu1A1pgSsZ/hEnvlM/NeqJA2cuF
+WgR35lR9hmjh3qf6heL0zbpISA9OaoLI3LgZArJo8gKCAQAqYoHH8fMpYFyjWRSu
+HPAwBnk2JXeM+ddDwNvX2G2oGbaIMgEoMg5aTHZTXbWWz2VE44z9kIKn19NCX6Pm
+NuXFfasbjJSSTw0LwuZlyaCKKB/slxEUPTIIXrWVr2sTvpbnFWg1owUem738CNVH
+RHxgZWVTYMZjTrCFrRJNnnGLPDJa9W9g+llyOOWO4+mQFyQ6nSIUV+d6giY4yUwv
+8OZXC8TYz9oNDFl6gDRLQKp4beSHFBnd8Ph5TMa0HNLyb/gl68Bh/zvE2jXQjE8N
+qEvv09+KPgNYO8AgmycvbH40u3B1yc4voTqM6a3/aUAlV5W4XqF2PYqNfSHxL+Nt
+J09nAhxknuZfej9TUxehS7vOjMSdoOEaky5AW5ZjuVBy
 -----END DSA PRIVATE KEY-----
diff --git a/doc/credentials/x509/key.pem b/doc/credentials/x509/key.pem
index 1d8521f..1e80b2e 100644
--- a/doc/credentials/x509/key.pem
+++ b/doc/credentials/x509/key.pem
@@ -1,16 +1,15 @@
------BEGIN PRIVATE KEY-----
-MIICcwIBADALBgkqhkiG9w0BAQEEggJfMIICWwIBAAKBgQDVyFSoD2JvxLkYp3b0
-H13WvCBSdwWEk+7T5EryQ7I6xXeoF211Z4FKIZZKjVEeRyZX0GVtS2a4eKgBSRk9
-KjyC2gTLcmlJ6ZbbbUGyPAhOMZ5nFmxv7gL9TZcdQiU76OoErlVhuk1eQ//ah8yR
-ZYBnIqcj48wh8W+/9wBKwjSTjwIDAQABAoGAAn2Ueua++1Vb4K0mxh5NbhCAAeXw
-EwTULfTFaMAgJe4iADvRoyIDEBWHFjRCQyuKB1DetaDAwBprvqQW3q8MyGYD7P9h
-85Wfu/hpIYKTw9hNeph420aE8WXw2yglTkJz3bzkMrXe/WjdhS1kTt8avCNQR/p0
-jM/UHvNze4oLc1ECQQDfammiczQFtj+Fuf3CNcYwp5XNumF+pubdGb+UHUiHyCuV
-Qxvm+LXgq8wXV/uXFLrp7FQFLCDQf0jiKDB2YQvRAkEA9PY/2AaGsU7j8ePwQbxC
-kwuj3hY6O6aNLIGxKxwZrzbob26c+tQk/++e0IXusIscBvcRV1Kg8Ff6fnw7/Adh
-XwJAG8qVbOuRmGk0BkwuFmPoeW3vNQgRX96O7po0qPBqVdRAU2rvzYtkCFxYqq0i
-lI0ekZtAfKxbeykaQaRkkKPaoQJAcifPyWJ/tu8z4DM7Ka+pFqTMwIllM1U3vFtv
-3LXezDE7AGDCyHKdB7MXcPXqj6nmCLMiswwiLLahAOBnUqk6xwJAJQ4pGcFFlCiI
-iVsq0wYSYmZUcRpSIInEQ0f8/xN6J22ZsiP5vnJM3F7R6ciYTt2gzNci/W9cdZI2
-HxskkO5lbQ==
------END PRIVATE KEY-----
+-----BEGIN RSA PRIVATE KEY-----
+MIICWwIBAAKBgQDVyFSoD2JvxLkYp3b0H13WvCBSdwWEk+7T5EryQ7I6xXeoF211
+Z4FKIZZKjVEeRyZX0GVtS2a4eKgBSRk9KjyC2gTLcmlJ6ZbbbUGyPAhOMZ5nFmxv
+7gL9TZcdQiU76OoErlVhuk1eQ//ah8yRZYBnIqcj48wh8W+/9wBKwjSTjwIDAQAB
+AoGAAn2Ueua++1Vb4K0mxh5NbhCAAeXwEwTULfTFaMAgJe4iADvRoyIDEBWHFjRC
+QyuKB1DetaDAwBprvqQW3q8MyGYD7P9h85Wfu/hpIYKTw9hNeph420aE8WXw2ygl
+TkJz3bzkMrXe/WjdhS1kTt8avCNQR/p0jM/UHvNze4oLc1ECQQDfammiczQFtj+F
+uf3CNcYwp5XNumF+pubdGb+UHUiHyCuVQxvm+LXgq8wXV/uXFLrp7FQFLCDQf0ji
+KDB2YQvRAkEA9PY/2AaGsU7j8ePwQbxCkwuj3hY6O6aNLIGxKxwZrzbob26c+tQk
+/++e0IXusIscBvcRV1Kg8Ff6fnw7/AdhXwJAG8qVbOuRmGk0BkwuFmPoeW3vNQgR
+X96O7po0qPBqVdRAU2rvzYtkCFxYqq0ilI0ekZtAfKxbeykaQaRkkKPaoQJAcifP
+yWJ/tu8z4DM7Ka+pFqTMwIllM1U3vFtv3LXezDE7AGDCyHKdB7MXcPXqj6nmCLMi
+swwiLLahAOBnUqk6xwJAJQ4pGcFFlCiIiVsq0wYSYmZUcRpSIInEQ0f8/xN6J22Z
+siP5vnJM3F7R6ciYTt2gzNci/W9cdZI2HxskkO5lbQ==
+-----END RSA PRIVATE KEY-----
diff --git a/doc/examples/Makefile.am b/doc/examples/Makefile.am
index 81548ca..0c055b1 100644
--- a/doc/examples/Makefile.am
+++ b/doc/examples/Makefile.am
@@ -78,4 +78,4 @@ noinst_LTLIBRARIES = libexamples.la
 
 libexamples_la_SOURCES = examples.h ex-alert.c ex-pkcs12.c             \
        ex-rfc2818.c ex-session-info.c ex-x509-info.c ex-verify.c       \
-       tcp.c
+       tcp.c ex-cert-select-pkcs11.c
diff --git a/doc/examples/ex-cert-select-pkcs11.c 
b/doc/examples/ex-cert-select-pkcs11.c
new file mode 100644
index 0000000..741afd3
--- /dev/null
+++ b/doc/examples/ex-cert-select-pkcs11.c
@@ -0,0 +1,272 @@
+/* This example code is placed in the public domain. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
+#include <unistd.h>
+#include <gnutls/gnutls.h>
+#include <gnutls/x509.h>
+#include <gnutls/pkcs11.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+/* A TLS client that loads the certificate and key.
+ */
+
+#define MAX_BUF 1024
+#define MSG "GET / HTTP/1.0\r\n\r\n"
+
+#define CAFILE "ca.pem"
+#define CERT_URL "pkcs11:manufacturer=EnterSafe;object=Certificate" \
+  ";id=db:5b:3e:b5:72:33:92:99:18:ed:bb:eb:74:68:31:bd:b2:23:67:26"
+#define KEY_URL "pkcs11:manufacturer=EnterSafe;object=Certificate" \
+  ";id=db:5b:3e:b5:72:33:92:99:18:ed:bb:eb:74:68:31:bd:b2:23:67:26"
+
+extern int tcp_connect (void);
+extern void tcp_close (int sd);
+
+static int cert_callback (gnutls_session_t session,
+                         const gnutls_datum_t * req_ca_rdn, int nreqs,
+                         const gnutls_pk_algorithm_t * sign_algos,
+                         int sign_algos_length, gnutls_retr2_st * st);
+
+gnutls_x509_crt_t crt;
+gnutls_pkcs11_privkey_t key;
+
+/* Load the certificate and the private key.
+ */
+static void
+load_keys (void)
+{
+  int ret;
+
+  gnutls_x509_crt_init (&crt);
+
+  ret = gnutls_x509_crt_import_pkcs11_url (crt, CERT_URL);
+  if (ret < 0)
+    {
+      fprintf (stderr, "*** Error loading key file: %s\n",
+              gnutls_strerror (ret));
+      exit (1);
+    }
+
+  gnutls_pkcs11_privkey_init (&key);
+
+  ret = gnutls_pkcs11_privkey_import_url (key, KEY_URL, 0);
+  if (ret < 0)
+    {
+      fprintf (stderr, "*** Error loading key file: %s\n",
+              gnutls_strerror (ret));
+      exit (1);
+    }
+
+}
+
+int
+main (void)
+{
+  int ret, sd, ii;
+  gnutls_session_t session;
+  gnutls_priority_t priorities_cache;
+  char buffer[MAX_BUF + 1];
+  gnutls_certificate_credentials_t xcred;
+  /* Allow connections to servers that have OpenPGP keys as well.
+   */
+
+  gnutls_global_init ();
+
+  load_keys ();
+
+  /* X509 stuff */
+  gnutls_certificate_allocate_credentials (&xcred);
+
+  /* priorities */
+  gnutls_priority_init (&priorities_cache, "NORMAL", NULL);
+
+
+  /* sets the trusted cas file
+   */
+  gnutls_certificate_set_x509_trust_file (xcred, CAFILE, GNUTLS_X509_FMT_PEM);
+
+  gnutls_certificate_set_retrieve_function (xcred, cert_callback);
+
+  /* Initialize TLS session
+   */
+  gnutls_init (&session, GNUTLS_CLIENT);
+
+  /* Use default priorities */
+  gnutls_priority_set (session, priorities_cache);
+
+  /* put the x509 credentials to the current session
+   */
+  gnutls_credentials_set (session, GNUTLS_CRD_CERTIFICATE, xcred);
+
+  /* connect to the peer
+   */
+  sd = tcp_connect ();
+
+  gnutls_transport_set_ptr (session, (gnutls_transport_ptr_t) sd);
+
+  /* Perform the TLS handshake
+   */
+  ret = gnutls_handshake (session);
+
+  if (ret < 0)
+    {
+      fprintf (stderr, "*** Handshake failed\n");
+      gnutls_perror (ret);
+      goto end;
+    }
+  else
+    {
+      printf ("- Handshake was completed\n");
+    }
+
+  gnutls_record_send (session, MSG, strlen (MSG));
+
+  ret = gnutls_record_recv (session, buffer, MAX_BUF);
+  if (ret == 0)
+    {
+      printf ("- Peer has closed the TLS connection\n");
+      goto end;
+    }
+  else if (ret < 0)
+    {
+      fprintf (stderr, "*** Error: %s\n", gnutls_strerror (ret));
+      goto end;
+    }
+
+  printf ("- Received %d bytes: ", ret);
+  for (ii = 0; ii < ret; ii++)
+    {
+      fputc (buffer[ii], stdout);
+    }
+  fputs ("\n", stdout);
+
+  gnutls_bye (session, GNUTLS_SHUT_RDWR);
+
+end:
+
+  tcp_close (sd);
+
+  gnutls_deinit (session);
+
+  gnutls_certificate_free_credentials (xcred);
+  gnutls_priority_deinit (priorities_cache);
+
+  gnutls_global_deinit ();
+
+  return 0;
+}
+
+
+
+/* This callback should be associated with a session by calling
+ * gnutls_certificate_client_set_retrieve_function( session, cert_callback),
+ * before a handshake.
+ */
+
+static int
+cert_callback (gnutls_session_t session,
+              const gnutls_datum_t * req_ca_rdn, int nreqs,
+              const gnutls_pk_algorithm_t * sign_algos,
+              int sign_algos_length, gnutls_retr2_st * st)
+{
+  char issuer_dn[256];
+  int i, ret;
+  size_t len;
+  gnutls_certificate_type_t type;
+
+  /* Print the server's trusted CAs
+   */
+  if (nreqs > 0)
+    printf ("- Server's trusted authorities:\n");
+  else
+    printf ("- Server did not send us any trusted authorities names.\n");
+
+  /* print the names (if any) */
+  for (i = 0; i < nreqs; i++)
+    {
+      len = sizeof (issuer_dn);
+      ret = gnutls_x509_rdn_get (&req_ca_rdn[i], issuer_dn, &len);
+      if (ret >= 0)
+       {
+         printf ("   [%d]: ", i);
+         printf ("%s\n", issuer_dn);
+       }
+    }
+
+  /* Select a certificate and return it.
+   * The certificate must be of any of the "sign algorithms"
+   * supported by the server.
+   */
+
+  type = gnutls_certificate_type_get (session);
+  if (type == GNUTLS_CRT_X509)
+    {
+      /* check if the certificate we are sending is signed
+       * with an algorithm that the server accepts */
+      gnutls_sign_algorithm_t cert_algo, req_algo;
+      int i, match = 0;
+
+      ret = gnutls_x509_crt_get_signature_algorithm (crt);
+      if (ret < 0)
+       {
+         /* error reading signature algorithm
+          */
+         return -1;
+       }
+      cert_algo = ret;
+
+      i = 0;
+      do
+       {
+         ret = gnutls_sign_algorithm_get_requested (session, i, &req_algo);
+         if (ret >= 0 && cert_algo == req_algo)
+           {
+             match = 1;
+             break;
+           }
+
+         /* server has not requested anything specific */
+         if (i == 0 && ret == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE)
+           {
+             match = 1;
+             break;
+           }
+         i++;
+       }
+      while (ret >= 0);
+
+      if (match == 0)
+       {
+         printf
+           ("- Could not find a suitable certificate to send to server\n");
+         return -1;
+       }
+
+      st->cert_type = type;
+      st->ncerts = 1;
+
+      st->cert.x509 = &crt;
+      st->key.pkcs11 = key;
+      st->key_type = GNUTLS_PRIVKEY_PKCS11;
+
+      st->deinit_all = 0;
+    }
+  else
+    {
+      return -1;
+    }
+
+  return 0;
+
+}
diff --git a/doc/examples/ex-cert-select.c b/doc/examples/ex-cert-select.c
index fe38ac2..316ca77 100644
--- a/doc/examples/ex-cert-select.c
+++ b/doc/examples/ex-cert-select.c
@@ -33,7 +33,7 @@ extern void tcp_close (int sd);
 static int cert_callback (gnutls_session_t session,
                          const gnutls_datum_t * req_ca_rdn, int nreqs,
                          const gnutls_pk_algorithm_t * sign_algos,
-                         int sign_algos_length, gnutls_retr_st * st);
+                         int sign_algos_length, gnutls_retr2_st * st);
 
 gnutls_x509_crt_t crt;
 gnutls_x509_privkey_t key;
@@ -143,7 +143,7 @@ main (void)
    */
   gnutls_certificate_set_x509_trust_file (xcred, CAFILE, GNUTLS_X509_FMT_PEM);
 
-  gnutls_certificate_client_set_retrieve_function (xcred, cert_callback);
+  gnutls_certificate_set_retrieve_function (xcred, cert_callback);
 
   /* Initialize TLS session 
    */
@@ -225,7 +225,7 @@ static int
 cert_callback (gnutls_session_t session,
               const gnutls_datum_t * req_ca_rdn, int nreqs,
               const gnutls_pk_algorithm_t * sign_algos,
-              int sign_algos_length, gnutls_retr_st * st)
+              int sign_algos_length, gnutls_retr2_st * st)
 {
   char issuer_dn[256];
   int i, ret;
@@ -300,11 +300,12 @@ cert_callback (gnutls_session_t session,
          return -1;
        }
 
-      st->type = type;
+      st->cert_type = type;
       st->ncerts = 1;
 
       st->cert.x509 = &crt;
       st->key.x509 = key;
+      st->key_type = GNUTLS_PRIVKEY_X509;
 
       st->deinit_all = 0;
     }
diff --git a/doc/examples/ex-crq.c b/doc/examples/ex-crq.c
index 9d40e90..f36aece 100644
--- a/doc/examples/ex-crq.c
+++ b/doc/examples/ex-crq.c
@@ -22,6 +22,7 @@ main (void)
   gnutls_x509_privkey_t key;
   unsigned char buffer[10 * 1024];
   size_t buffer_size = sizeof (buffer);
+  unsigned int bits;
 
   gnutls_global_init ();
 
@@ -32,9 +33,10 @@ main (void)
 
   gnutls_x509_privkey_init (&key);
 
-  /* Generate a 1024 bit RSA private key.
+  /* Generate an RSA key of moderate security.
    */
-  gnutls_x509_privkey_generate (key, GNUTLS_PK_RSA, 1024, 0);
+  bits = gnutls_sec_param_to_pk_bits( GNUTLS_PK_RSA, GNUTLS_SEC_PARAM_NORMAL);
+  gnutls_x509_privkey_generate (key, GNUTLS_PK_RSA, bits, 0);
 
   /* Add stuff to the distinguished name
    */
diff --git a/doc/examples/ex-serv-export.c b/doc/examples/ex-serv-export.c
index 33b6d0a..b79ad55 100644
--- a/doc/examples/ex-serv-export.c
+++ b/doc/examples/ex-serv-export.c
@@ -14,7 +14,6 @@
 #include <string.h>
 #include <unistd.h>
 #include <gnutls/gnutls.h>
-#include <gcrypt.h>            /* for gcry_control */
 
 #define KEYFILE "key.pem"
 #define CERTFILE "cert.pem"
@@ -132,10 +131,6 @@ main (void)
 
   strcpy (name, "Echo Server");
 
-  /* to disallow usage of the blocking /dev/random 
-   */
-  gcry_control (GCRYCTL_ENABLE_QUICK_RANDOM, 0);
-
   /* this must be called once in the program
    */
   gnutls_global_init ();
diff --git a/doc/examples/ex-serv-psk.c b/doc/examples/ex-serv-psk.c
index b5768b4..2cb3b98 100644
--- a/doc/examples/ex-serv-psk.c
+++ b/doc/examples/ex-serv-psk.c
@@ -14,7 +14,6 @@
 #include <string.h>
 #include <unistd.h>
 #include <gnutls/gnutls.h>
-#include <gcrypt.h>            /* for gcry_control */
 
 #define KEYFILE "key.pem"
 #define CERTFILE "cert.pem"
@@ -101,10 +100,6 @@ main (void)
   char buffer[MAX_BUF + 1];
   int optval = 1;
 
-  /* to disallow usage of the blocking /dev/random 
-   */
-  gcry_control (GCRYCTL_ENABLE_QUICK_RANDOM, 0);
-
   /* this must be called once in the program
    */
   gnutls_global_init ();
diff --git a/doc/examples/ex-serv1.c b/doc/examples/ex-serv1.c
index 9d43610..f8b91b0 100644
--- a/doc/examples/ex-serv1.c
+++ b/doc/examples/ex-serv1.c
@@ -14,7 +14,6 @@
 #include <string.h>
 #include <unistd.h>
 #include <gnutls/gnutls.h>
-#include <gcrypt.h>            /* for gcry_control */
 
 #define KEYFILE "key.pem"
 #define CERTFILE "cert.pem"
@@ -90,10 +89,6 @@ main (void)
   char buffer[MAX_BUF + 1];
   int optval = 1;
 
-  /* to disallow usage of the blocking /dev/random 
-   */
-  gcry_control (GCRYCTL_ENABLE_QUICK_RANDOM, 0);
-
   /* this must be called once in the program
    */
   gnutls_global_init ();
diff --git a/doc/gnutls.texi b/doc/gnutls.texi
index 7e4c3ca..eb8c1c7 100644
--- a/doc/gnutls.texi
+++ b/doc/gnutls.texi
@@ -90,4278 +90,31 @@ Documentation License''.
 * Bibliography::
 @end menu
 
address@hidden cha-preface.texi
 
address@hidden Preface
address@hidden Preface
address@hidden cha-library.texi
 
-This document tries to demonstrate and explain the @acronym{GnuTLS}
-library API.  A brief introduction to the protocols and the technology
-involved, is also included so that an application programmer can
-better understand the @acronym{GnuTLS} purpose and actual offerings.
-Even if @acronym{GnuTLS} is a typical library software, it operates
-over several security and cryptographic protocols, which require the
-programmer to make careful and correct usage of them, otherwise he
-risks to offer just a false sense of security. Security and the
-network security terms are very general terms even for computer
-software thus cannot be easily restricted to a single cryptographic
-library.  For that reason, do not consider a program secure just
-because it uses @acronym{GnuTLS}; there are several ways to compromise
-a program or a communication line and @acronym{GnuTLS} only helps with
-some of them.
address@hidden cha-intro-tls.texi
 
-Although this document tries to be self contained, basic network
-programming and PKI knowlegde is assumed in most of it. A good
-introduction to networking can be found in @xcite{STEVENS} and for
-Public Key Infrastructure in @xcite{GUTPKI}.
address@hidden cha-auth.texi
 
address@hidden
address@hidden cha-cert-auth.texi
 
-Updated versions of the @acronym{GnuTLS} software and this document
-will be available from @url{http://www.gnutls.org/} and
address@hidden://www.gnu.org/software/gnutls/}.
address@hidden cha-tls-app.texi
 
address@hidden
-* Getting help::
-* Commercial Support::
-* Downloading and Installing::
-* Bug Reports::
-* Contributing::
address@hidden menu
-
address@hidden Getting help
address@hidden Getting Help
-
-A mailing list where users may help each other exists, and you can
-reach it by sending e-mail to @email{help-gnutls@@gnu.org}.  Archives
-of the mailing list discussions, and an interface to manage
-subscriptions, is available through the World Wide Web at
address@hidden://lists.gnu.org/mailman/listinfo/help-gnutls}.
-
-A mailing list for developers are also available, see
address@hidden://www.gnu.org/software/gnutls/lists.html}.
-
-Bug reports should be sent to @email{bug-gnutls@@gnu.org}, see
address@hidden Reports}.
-
address@hidden Commercial Support
address@hidden Commercial Support
-
-Commercial support is available for users of GnuTLS.  The kind of
-support that can be purchased may include:
-
address@hidden
-
address@hidden Implement new features.
-Such as a new TLS extension.
-
address@hidden Port GnuTLS to new platforms.
-This could include porting to an embedded platforms that may need
-memory or size optimization.
-
address@hidden Integrating TLS as a security environment in your existing 
project.
-
address@hidden System design of components related to TLS.
-
address@hidden itemize
-
-If you are interested, please write to:
-
address@hidden
-Simon Josefsson Datakonsult
-Hagagatan 24
-113 47 Stockholm
-Sweden
-
-E-mail: address@hidden
address@hidden verbatim
-
-If your company provides support related to GnuTLS and would like to
-be mentioned here, contact the author (@pxref{Bug Reports}).
-
address@hidden Downloading and Installing
address@hidden Downloading and Installing
address@hidden Installation
address@hidden Download
-
-GnuTLS is available for download from the following URL:
-
address@hidden://www.gnutls.org/download.html}
-
-The latest version is stored in a file, e.g.,
address@hidden@value{VERSION}.tar.gz} where the @address@hidden
-value is the highest version number in the directory.
-
-GnuTLS uses a Linux-like development cycle: even minor version numbers
-indicate a stable release and a odd minor version number indicates a
-development release.  For example, GnuTLS 1.6.3 denote a stable
-release since 6 is even, and GnuTLS 1.7.11 denote a development
-release since 7 is odd.
-
-GnuTLS depends on Libgcrypt,
-and you will need to install Libgcrypt
-before installing GnuTLS.  Libgcrypt is available from
address@hidden://ftp.gnupg.org/gcrypt/libgcrypt}.  Libgcrypt needs another
-library, libgpg-error, and you need to install libgpg-error before
-installing Libgcrypt.  Libgpg-error is available from
address@hidden://ftp.gnupg.org/gcrypt/libgpg-error}.
-
-Don't forget to verify the cryptographic signature after downloading
-source code packages.
-
-The package is then extracted, configured and built like many other
-packages that use Autoconf.  For detailed information on configuring
-and building it, refer to the @file{INSTALL} file that is part of the
-distribution archive.  Typically you invoke @code{./configure} and
-then @code{make check install}.  There are a number of compile-time
-parameters, as discussed below.
-
-The compression libraries (libz and lzo) are optional dependencies.
-You can get libz from @url{http://www.zlib.net/}.  You can get lzo
-from @url{http://www.oberhumer.com/opensource/lzo/}.
-
-The X.509 part of GnuTLS needs ASN.1 functionality, from a library
-called libtasn1.  A copy of libtasn1 is included in GnuTLS.  If you
-want to install it separately (e.g., to make it possibly to use
-libtasn1 in other programs), you can get it from
address@hidden://www.gnu.org/software/gnutls/download.html}.
-
-The OpenPGP part of GnuTLS uses a stripped down version of OpenCDK for
-parsing OpenPGP packets.  It is included GnuTLS.  Use parameter
address@hidden to disable the OpenPGP
-functionality in GnuTLS.  Unfortunately, we didn't have resources to
-maintain the code in a separate library.
-
-Regarding the Guile bindings, there are additional installation
-considerations, see @xref{Guile Preparations}.
-
-A few @code{configure} options may be relevant, summarized in the
-table.
-
address@hidden @code
-
address@hidden --disable-srp-authentication
address@hidden --disable-psk-authentication
address@hidden --disable-anon-authentication
address@hidden --disable-extra-pki
address@hidden --disable-openpgp-authentication
address@hidden --disable-openssl-compatibility
-Disable or enable particular features.  Generally not recommended.
-
address@hidden table
-
-For the complete list, refer to the output from @code{configure
---help}.
-
address@hidden Bug Reports
address@hidden Bug Reports
address@hidden Reporting Bugs
-
-If you think you have found a bug in GnuTLS, please investigate it and
-report it.
-
address@hidden @bullet
-
address@hidden Please make sure that the bug is really in GnuTLS, and
-preferably also check that it hasn't already been fixed in the latest
-version.
-
address@hidden You have to send us a test case that makes it possible for us to
-reproduce the bug.
-
address@hidden You also have to explain what is wrong; if you get a crash, or
-if the results printed are not good and in that case, in what way.
-Make sure that the bug report includes all information you would need
-to fix this kind of bug for someone else.
-
address@hidden itemize
-
-Please make an effort to produce a self-contained report, with
-something definite that can be tested or debugged.  Vague queries or
-piecemeal messages are difficult to act on and don't help the
-development effort.
-
-If your bug report is good, we will do our best to help you to get a
-corrected version of the software; if the bug report is poor, we won't
-do anything about it (apart from asking you to send better bug
-reports).
-
-If you think something in this manual is unclear, or downright
-incorrect, or if the language needs to be improved, please also send a
-note.
-
-Send your bug report to:
-
address@hidden @samp{bug-gnutls@@gnu.org}
-
address@hidden Contributing
address@hidden Contributing
address@hidden Contributing
address@hidden Hacking
-
-If you want to submit a patch for inclusion -- from solve a typo you
-discovered, up to adding support for a new feature -- you should
-submit it as a bug report (@pxref{Bug Reports}).  There are some
-things that you can do to increase the chances for it to be included
-in the official package.
-
-Unless your patch is very small (say, under 10 lines) we require that
-you assign the copyright of your work to the Free Software Foundation.
-This is to protect the freedom of the project.  If you have not
-already signed papers, we will send you the necessary information when
-you submit your contribution.
-
-For contributions that doesn't consist of actual programming code, the
-only guidelines are common sense.  Use it.
-
-For code contributions, a number of style guides will help you:
-
address@hidden @bullet
-
address@hidden Coding Style.
-Follow the GNU Standards document (@pxref{top, GNU Coding Standards,,
-standards}).
-
-If you normally code using another coding standard, there is no
-problem, but you should use @samp{indent} to reformat the code
-(@pxref{top, GNU Indent,, indent}) before submitting your work.
-
address@hidden Use the unified diff format @samp{diff -u}.
-
address@hidden Return errors.
-No reason whatsoever should abort the execution of the library.  Even
-memory allocation errors, e.g. when malloc return NULL, should work
-although result in an error code.
-
address@hidden Design with thread safety in mind.
-Don't use global variables.  Don't even write to per-handle global
-variables unless the documented behaviour of the function you write is
-to write to the per-handle global variable.
-
address@hidden Avoid using the C math library.
-It causes problems for embedded implementations, and in most
-situations it is very easy to avoid using it.
-
address@hidden Document your functions.
-Use comments before each function headers, that, if properly
-formatted, are extracted into Texinfo manuals and GTK-DOC web pages.
-
address@hidden Supply a ChangeLog and NEWS entries, where appropriate.
-
address@hidden itemize
address@hidden The Library
address@hidden The Library
-
-In brief @acronym{GnuTLS} can be described as a library which offers an API
-to access secure communication protocols. These protocols provide
-privacy over insecure lines, and were designed to prevent
-eavesdropping, tampering, or message forgery.
-
-Technically @acronym{GnuTLS} is a portable ANSI C based library which
-implements the TLS 1.1 and SSL 3.0 protocols (@xref{Introduction to
-TLS}, for a more detailed description of the protocols), accompanied
-with the required framework for authentication and public key
-infrastructure.  Important features of the @acronym{GnuTLS} library
-include:
-
address@hidden
-
address@hidden Support for TLS 1.0, TLS 1.1, and SSL 3.0 protocols.
-
address@hidden Support for both @acronym{X.509} and @acronym{OpenPGP} 
certificates.
-
address@hidden Support for handling and verification of certificates.
-
address@hidden Support for @acronym{SRP} for TLS authentication.
-
address@hidden Support for @acronym{PSK} for TLS authentication.
-
address@hidden Support for TLS Extension mechanism.
-
address@hidden Support for TLS Compression Methods.
-
address@hidden itemize
-
-Additionally @acronym{GnuTLS} provides a limited emulation API for the
-widely used address@hidden@url{http://www.openssl.org/}} library,
-to ease integration with existing applications.
-
address@hidden consists of three independent parts, namely the ``TLS
-protocol part'', the ``Certificate part'', and the ``Cryptographic
-backend'' part.  The `TLS protocol part' is the actual protocol
-implementation, and is entirely implemented within the
address@hidden library.  The `Certificate part' consists of the
-certificate parsing, and verification functions which is partially
-implemented in the @acronym{GnuTLS} library.  The
address@hidden@address@hidden://ftp.gnupg.org/gcrypt/alpha/gnutls/libtasn1/}},
-a library which offers @acronym{ASN.1} parsing capabilities, is used
-for the @acronym{X.509} certificate parsing functions.  A smaller
-version of
address@hidden@address@hidden://ftp.gnupg.org/gcrypt/alpha/gnutls/opencdk/}}
-is used for the @acronym{OpenPGP} key support in @acronym{GnuTLS}.
-The ``Cryptographic backend'' is provided by the
address@hidden@address@hidden://ftp.gnupg.org/gcrypt/alpha/libgcrypt/}}
address@hidden current versions of GnuTLS it is possible to
-override the default crypto backend. Check @pxref{Cryptographic
-Backend} for details}.
-
-In order to ease integration in embedded systems, parts of the
address@hidden library can be disabled at compile time. That way a
-small library, with the required features, can be generated.
-
address@hidden
-* General Idea::
-* Error handling::
-* Memory handling::
-* Callback functions::
address@hidden menu
-
address@hidden General Idea
address@hidden General Idea
-
-A brief description of how @acronym{GnuTLS} works internally is shown
-at the figure below. This section may be easier to understand after
-having seen the examples (@pxref{examples}).
-
address@hidden,12cm,8cm}
-
-As shown in the figure, there is a read-only global state that is
-initialized once by the global initialization function.  This global
-structure, among others, contains the memory allocation functions
-used, and some structures needed for the @acronym{ASN.1} parser.  This
-structure is never modified by any @acronym{GnuTLS} function, except
-for the deinitialization function which frees all memory allocated in
-the global structure and is called after the program has permanently
-finished using @acronym{GnuTLS}.
-
-The credentials structure is used by some authentication methods, such
-as certificate authentication (@pxref{Certificate Authentication}).  A
-credentials structure may contain certificates, private keys,
-temporary parameters for Diffie-Hellman or RSA key exchange, and other
-stuff that may be shared between several TLS sessions.
-
-This structure should be initialized using the appropriate
-initialization functions. For example an application which uses
-certificate authentication would probably initialize the credentials,
-using the appropriate functions, and put its trusted certificates in
-this structure. The next step is to associate the credentials
-structure with each @acronym{TLS} session.
-
-A @acronym{GnuTLS} session contains all the required stuff for a
-session to handle one secure connection. This session calls directly
-to the transport layer functions, in order to communicate with the
-peer.  Every session has a unique session ID shared with the peer.
-
-Since TLS sessions can be resumed, servers would probably need a
-database backend to hold the session's parameters.  Every
address@hidden session after a successful handshake calls the
-appropriate backend function (@xref{resume}, for information on
-initialization) to store the newly negotiated session. The session
-database is examined by the server just after having received the
-client address@hidden first message in a @acronym{TLS} handshake},
-and if the session ID sent by the client, matches a stored session,
-the stored session will be retrieved, and the new session will be a
-resumed one, and will share the same session ID with the previous one.
-
address@hidden Error handling
address@hidden Error Handling
-
-In @acronym{GnuTLS} most functions return an integer type as a result.
-In almost all cases a zero or a positive number means success, and a
-negative number indicates failure, or a situation that some action has
-to be taken. Thus negative error codes may be fatal or not.
-
-Fatal errors terminate the connection immediately and further sends
-and receives will be disallowed. An example of a fatal error code is
address@hidden Non-fatal errors may warn about
-something, i.e., a warning alert was received, or indicate the some
-action has to be taken. This is the case with the error code
address@hidden returned by @ref{gnutls_record_recv}.
-This error code indicates that the server requests a re-handshake. The
-client may ignore this request, or may reply with an alert.  You can
-test if an error code is a fatal one by using the
address@hidden
-
-If any non fatal errors, that require an action, are to be returned by
-a function, these error codes will be documented in the function's
-reference.  @xref{Error Codes}, for all the error codes.
-
address@hidden Memory handling
address@hidden Memory Handling
-
address@hidden internally handles heap allocated objects
-differently, depending on the sensitivity of the data they
-contain. However for performance reasons, the default memory functions
-do not overwrite sensitive data from memory, nor protect such objects
-from being written to the swap.  In order to change the default
-behavior the @ref{gnutls_global_set_mem_functions} function is
-available which can be used to set other memory handlers than the
-defaults.
-
-The @acronym{Libgcrypt} library on which @acronym{GnuTLS} depends, has
-such secure memory allocation functions available. These should be
-used in cases where even the system's swap memory is not considered
-secure. See the documentation of @acronym{Libgcrypt} for more
-information.
-
address@hidden Callback functions
address@hidden Callback Functions
address@hidden Callback functions
-
-There are several cases where @acronym{GnuTLS} may need some out of
-band input from your program. This is now implemented using some
-callback functions, which your program is expected to register.
-
-An example of this type of functions are the push and pull callbacks
-which are used to specify the functions that will retrieve and send
-data to the transport layer.
-
address@hidden
-
address@hidden @ref{gnutls_transport_set_push_function}
-
address@hidden @ref{gnutls_transport_set_pull_function}
-
address@hidden itemize
-
-Other callback functions such as the one set by
address@hidden, may require more
-complicated input, including data to be allocated.  These callbacks
-should allocate and free memory using the functions shown below.
-
address@hidden
-
address@hidden @ref{gnutls_malloc}
-
address@hidden @ref{gnutls_free}
-
address@hidden itemize
-
address@hidden Introduction to TLS
address@hidden Introduction to @acronym{TLS}
-
address@hidden stands for ``Transport Layer Security'' and is the
-successor of SSL, the Secure Sockets Layer protocol @xcite{SSL3}
-designed by Netscape.  @acronym{TLS} is an Internet protocol, defined
-by @address@hidden, or Internet Engineering Task Force,
-is a large open international community of network designers,
-operators, vendors, and researchers concerned with the evolution of
-the Internet architecture and the smooth operation of the Internet.
-It is open to any interested individual.}, described in @acronym{RFC}
-4346 and also in @xcite{RESCORLA}.  The protocol provides
-confidentiality, and authentication layers over any reliable transport
-layer.  The description, below, refers to @acronym{TLS} 1.0 but also
-applies to @acronym{TLS} 1.1 @xcite{RFC4346} and @acronym{SSL} 3.0,
-since the differences of these protocols are minor.  Older protocols
-such as @acronym{SSL} 2.0 are not discussed nor implemented in
address@hidden since they are not considered secure today.  GnuTLS
-also supports @acronym{X.509} and @acronym{OpenPGP} @xcite{RFC4880}.
-
address@hidden
-* TLS layers::
-* The transport layer::
-* The TLS record protocol::
-* The TLS Alert Protocol::
-* The TLS Handshake Protocol::
-* TLS Extensions::
-* Selecting cryptographic key sizes::
-* On SSL 2 and older protocols::
-* On Record Padding::
-* Safe Renegotiation::
address@hidden menu
-
address@hidden TLS layers
address@hidden TLS Layers
address@hidden TLS Layers
-
address@hidden is a layered protocol, and consists of the Record
-Protocol, the Handshake Protocol and the Alert Protocol. The Record
-Protocol is to serve all other protocols and is above the transport
-layer.  The Record protocol offers symmetric encryption, data
-authenticity, and optionally compression.
-
-The Alert protocol offers some signaling to the other protocols. It
-can help informing the peer for the cause of failures and other error
-conditions.  @xref{The Alert Protocol}, for more information.  The
-alert protocol is above the record protocol.
-
-The Handshake protocol is responsible for the security parameters'
-negotiation, the initial key exchange and authentication.  @xref{The
-Handshake Protocol}, for more information about the handshake
-protocol.  The protocol layering in TLS is shown in the figure below.
-
address@hidden,12cm,8cm}
-
address@hidden The transport layer
address@hidden The Transport Layer
address@hidden Transport protocol
-
address@hidden is not limited to one transport layer, it can be used
-above any transport layer, as long as it is a reliable one.  A set of
-functions is provided and their purpose is to load to @acronym{GnuTLS} the
-required callbacks to access the transport layer.
-
address@hidden
address@hidden @ref{gnutls_transport_set_push_function}
address@hidden @ref{gnutls_transport_set_pull_function}
address@hidden @ref{gnutls_transport_set_ptr}
address@hidden @ref{gnutls_transport_set_lowat}
address@hidden @ref{gnutls_transport_set_errno}
address@hidden itemize
-
-These functions accept a callback function as a parameter.  The
-callback functions should return the number of bytes written, or -1 on
-error and should set @code{errno} appropriately.
-
-In some environments, setting @code{errno} is unreliable, for example
-Windows have several errno variables in different CRTs, or it may be
-that errno is not a thread-local variable.  If this is a concern to
-you, call @code{gnutls_transport_set_errno} with the intended errno
-value instead of setting @code{errno} directly.
-
address@hidden currently only interprets the EINTR and EAGAIN errno
-values and returns the corresponding @acronym{GnuTLS} error codes
address@hidden and @code{GNUTLS_E_AGAIN}.  These values
-are usually returned by interrupted system calls, or when non blocking
-IO is used.  All @acronym{GnuTLS} functions can be resumed (called
-again), if any of these error codes is returned.  The error codes
-above refer to the system call, not the @acronym{GnuTLS} function,
-since signals do not interrupt @acronym{GnuTLS}' functions.
-
-For non blocking sockets or other custom made pull/push functions
-the @ref{gnutls_transport_set_lowat} must be called, with a zero
-low water mark value.
-
-By default, if the transport functions are not set, @acronym{GnuTLS}
-will use the Berkeley Sockets functions.  In this case
address@hidden will use some hacks in order for @code{select} to
-work, thus making it easy to add @acronym{TLS} support to existing
-TCP/IP servers.
-
address@hidden The TLS record protocol
address@hidden The TLS Record Protocol
address@hidden Record protocol
-
-The Record protocol is the secure communications provider. Its purpose
-is to encrypt, authenticate and ---optionally--- compress packets.
-The following functions are available:
-
address@hidden @asis
-
address@hidden @ref{gnutls_record_send}:
-To send a record packet (with application data).
-
address@hidden @ref{gnutls_record_recv}:
-To receive a record packet (with application data).
-
address@hidden @ref{gnutls_record_get_direction}:
-To get the direction of the last interrupted function call.
address@hidden table
-
-As you may have already noticed, the functions which access the Record
-protocol, are quite limited, given the importance of this protocol in
address@hidden  This is because the Record protocol's parameters are
-all set by the Handshake protocol.
-
-The Record protocol initially starts with NULL parameters, which means
-no encryption, and no MAC is used. Encryption and authentication begin
-just after the handshake protocol has finished.
-
address@hidden
-* Encryption algorithms used in the record layer::
-* Compression algorithms used in the record layer::
-* Weaknesses and countermeasures::
address@hidden menu
-
address@hidden Encryption algorithms used in the record layer
address@hidden Encryption Algorithms Used in the Record Layer
address@hidden Symmetric encryption algorithms
-
-Confidentiality in the record layer is achieved by using symmetric
-block encryption algorithms like @code{3DES}, @address@hidden,
-or Advanced Encryption Standard, is actually the RIJNDAEL algorithm.
-This is the algorithm that replaced DES.}, or stream algorithms like
address@hidden@address@hidden is a compatible
-algorithm with RSA's RC4 algorithm, which is considered to be a trade
-secret.}. Ciphers are encryption algorithms that use a single, secret,
-key to encrypt and decrypt data. Block algorithms in TLS also provide
-protection against statistical analysis of the data.  Thus, if you're
-using the @acronym{TLS} protocol, a random number of blocks will be
-appended to data, to prevent eavesdroppers from guessing the actual
-data size.
-
-Supported cipher algorithms:
-
address@hidden @code
address@hidden 3DES_CBC
address@hidden is the DES block cipher algorithm used with triple
-encryption (EDE). Has 64 bits block size and is used in CBC mode.
-
address@hidden ARCFOUR_128
-ARCFOUR is a fast stream cipher.
-
address@hidden ARCFOUR_40
-This is the ARCFOUR cipher that is fed with a 40 bit key,
-which is considered weak.
-
address@hidden AES_CBC
-AES or RIJNDAEL is the block cipher algorithm that replaces the old
-DES algorithm.  Has 128 bits block size and is used in CBC mode. This
-is not officially supported in TLS.
address@hidden table
-
-Supported MAC algorithms:
-
address@hidden @code
address@hidden MAC_MD5
-MD5 is a cryptographic hash algorithm designed by Ron Rivest. Outputs
-128 bits of data.
-
address@hidden MAC_SHA
-SHA is a cryptographic hash algorithm designed by NSA. Outputs 160
-bits of data.
-
address@hidden table
-
address@hidden Compression algorithms used in the record layer
address@hidden Compression Algorithms Used in the Record Layer
address@hidden Compression algorithms
-
-The TLS record layer also supports compression.  The algorithms
-implemented in @acronym{GnuTLS} can be found in the table below.
-All the algorithms except for DEFLATE which is
-referenced in @xcite{RFC3749}, should be considered as
address@hidden' address@hidden should use
address@hidden to enable private
-extensions.}, and should be advertised only when the peer is known to
-have a compliant client, to avoid interoperability problems.
-
-The included algorithms perform really good when text, or other
-compressible data are to be transfered, but offer nothing on already
-compressed data, such as compressed images, zipped archives etc.
-These compression algorithms, may be useful in high bandwidth TLS
-tunnels, and in cases where network usage has to be minimized. As a
-drawback, compression increases latency.
-
-The record layer compression in @acronym{GnuTLS} is implemented based
-on the proposal @xcite{RFC3749}.
-The supported compression algorithms are:
-
address@hidden @code
address@hidden DEFLATE
-Zlib compression, using the deflate algorithm.
-
address@hidden LZO
-LZO is a very fast compression algorithm.  This algorithm is only
-available if the @acronym{GnuTLS-extra} library has been initialized
-and the private extensions are enabled, and if GnuTLS was built with
-LZO support.
-
address@hidden table
-
address@hidden Weaknesses and countermeasures
address@hidden Weaknesses and Countermeasures
-
-Some weaknesses that may affect the security of the Record layer have
-been found in @acronym{TLS} 1.0 protocol. These weaknesses can be
-exploited by active attackers, and exploit the facts that
-
address@hidden
-
address@hidden
address@hidden has separate alerts for ``decryption_failed'' and
-``bad_record_mac''
-
address@hidden
-The decryption failure reason can be detected by timing the response
-time.
-
address@hidden
-The IV for CBC encrypted packets is the last block of the previous
-encrypted packet.
-
address@hidden enumerate
-
-Those weaknesses were solved in @acronym{TLS} 1.1 @xcite{RFC4346}
-which is implemented in @acronym{GnuTLS}. For a detailed discussion
-see the archives of the TLS Working Group mailing list and the paper
address@hidden
-
address@hidden The TLS Alert Protocol
address@hidden The TLS Alert Protocol
address@hidden Alert Protocol}
address@hidden Alert protocol
-
-The Alert protocol is there to allow signals to be sent between peers.
-These signals are mostly used to inform the peer about the cause of a
-protocol failure. Some of these signals are used internally by the
-protocol and the application protocol does not have to cope with them
-(see @code{GNUTLS_A_CLOSE_NOTIFY}), and others refer to the
-application protocol solely (see @code{GNUTLS_A_USER_CANCELLED}).  An
-alert signal includes a level indication which may be either fatal or
-warning. Fatal alerts always terminate the current connection, and
-prevent future renegotiations using the current session ID.
-
-The alert messages are protected by the record protocol, thus the
-information that is included does not leak. You must take extreme care
-for the alert information not to leak to a possible attacker, via
-public log files etc.
-
address@hidden @asis
address@hidden @ref{gnutls_alert_send}:
-To send an alert signal.
-
address@hidden @ref{gnutls_error_to_alert}:
-To map a gnutls error number to an alert signal.
-
address@hidden @ref{gnutls_alert_get}:
-Returns the last received alert.
-
address@hidden @ref{gnutls_alert_get_name}:
-Returns the name, in a character array, of the given alert.
-
address@hidden table
-
address@hidden The TLS Handshake Protocol
address@hidden The TLS Handshake Protocol
address@hidden Handshake Protocol}
address@hidden Handshake protocol
-
-The Handshake protocol is responsible for the ciphersuite negotiation,
-the initial key exchange, and the authentication of the two peers.
-This is fully controlled by the application layer, thus your program
-has to set up the required parameters. Available functions to control
-the handshake protocol include:
-
address@hidden @asis
address@hidden @ref{gnutls_priority_init}:
-To initialize a priority set of ciphers.
-
address@hidden @ref{gnutls_priority_deinit}:
-To deinitialize a priority set of ciphers.
-
address@hidden @ref{gnutls_priority_set}:
-To associate a priority set with a @acronym{TLS} session.
-
address@hidden @ref{gnutls_priority_set_direct}:
-To directly associate a session with a given priority string.
-
address@hidden @ref{gnutls_credentials_set}:
-To set the appropriate credentials structures.
-
address@hidden @ref{gnutls_certificate_server_set_request}:
-To set whether client certificate is required or not.
-
address@hidden @ref{gnutls_handshake}:
-To initiate the handshake.
address@hidden table
-
address@hidden TLS Cipher Suites
-
-The Handshake Protocol of @acronym{TLS} negotiates cipher suites of
-the form @code{TLS_DHE_RSA_WITH_3DES_CBC_SHA}.  The usual cipher
-suites contain these parameters:
-
address@hidden
-
address@hidden The key exchange algorithm.
address@hidden in the example.
-
address@hidden The Symmetric encryption algorithm and mode
address@hidden in this example.
-
address@hidden The address@hidden stands for Message Authentication Code. It 
can be described as a keyed hash algorithm. See RFC2104.} algorithm used for 
authentication.
address@hidden is used in the above example.
-
address@hidden itemize
-
-The cipher suite negotiated in the handshake protocol will affect the
-Record Protocol, by enabling encryption and data authentication.  Note
-that you should not over rely on @acronym{TLS} to negotiate the
-strongest available cipher suite. Do not enable ciphers and algorithms
-that you consider weak.
-
-The priority functions, dicussed above, allow the application layer to
-enable and set priorities on the individual ciphers. It may imply that
-all combinations of ciphersuites are allowed, but this is not
-true. For several reasons, not discussed here, some combinations were
-not defined in the @acronym{TLS} protocol.  The supported ciphersuites
-are shown in @ref{ciphersuites}.
-
address@hidden Client Authentication
address@hidden Client Certificate authentication
-
-In the case of ciphersuites that use certificate authentication, the
-authentication of the client is optional in @acronym{TLS}.  A server
-may request a certificate from the client --- using the
address@hidden function. If a certificate
-is to be requested from the client during the handshake, the server
-will send a certificate request message that contains a list of
-acceptable certificate signers. In @acronym{GnuTLS} the certificate
-signers list is constructed using the trusted Certificate Authorities
-by the server. That is the ones set using
address@hidden
address@hidden @ref{gnutls_certificate_set_x509_trust_file}
address@hidden @ref{gnutls_certificate_set_x509_trust_mem}
address@hidden itemize
-
-Sending of the names of the CAs can be controlled using
address@hidden The client, then, may
-send a certificate, signed by one of the server's acceptable signers.
-
address@hidden Resuming Sessions
address@hidden
address@hidden Resuming sessions
-
-The @ref{gnutls_handshake} function, is expensive since a lot of
-calculations are performed. In order to support many fast connections
-to the same server a client may use session resuming. @strong{Session
-resuming} is a feature of the @acronym{TLS} protocol which allows a
-client to connect to a server, after a successful handshake, without
-the expensive calculations.  This is achieved by using the previously
-established keys. @acronym{GnuTLS} supports this feature, and the
-example (@pxref{ex:resume-client}) illustrates a typical use of it.
-
-Keep in mind that sessions are expired after some time, for security
-reasons, thus it may be normal for a server not to resume a session
-even if you requested that.  Also note that you must enable, using the
-priority functions, at least the algorithms used in the last session.
-
address@hidden Resuming Internals
-
-The resuming capability, mostly in the server side, is one of the
-problems of a thread-safe TLS implementations. The problem is that all
-threads must share information in order to be able to resume
-sessions. The gnutls approach is, in case of a client, to leave all
-the burden of resuming to the client. I.e., copy and keep the
-necessary parameters. See the functions:
-
address@hidden
-
address@hidden @ref{gnutls_session_get_data}
-
address@hidden @ref{gnutls_session_get_id}
-
address@hidden @ref{gnutls_session_set_data}
-
address@hidden itemize
-
-The server side is different. A server has to specify some callback
-functions which store, retrieve and delete session data. These can be
-registered with:
-
address@hidden
-
address@hidden @ref{gnutls_db_set_remove_function}
-
address@hidden @ref{gnutls_db_set_store_function}
-
address@hidden @ref{gnutls_db_set_retrieve_function}
-
address@hidden @ref{gnutls_db_set_ptr}
-
address@hidden itemize
-
-It might also be useful to be able to check for expired sessions in
-order to remove them, and save space. The function
address@hidden is provided for that reason.
-
address@hidden TLS Extensions
address@hidden TLS Extensions
address@hidden TLS Extensions
-
-A number of extensions to the @acronym{TLS} protocol have been
-proposed mainly in @xcite{TLSEXT}. The extensions supported
-in @acronym{GnuTLS} are:
-
address@hidden
address@hidden Maximum fragment length negotiation
address@hidden Server name indication
address@hidden Session tickets
address@hidden itemize
-
-and they will be discussed in the subsections that follow.
-
address@hidden Maximum Fragment Length Negotiation
address@hidden TLS Extensions
address@hidden Maximum fragment length
-
-This extension allows a @acronym{TLS} implementation to negotiate a
-smaller value for record packet maximum length. This extension may be
-useful to clients with constrained capabilities. See the
address@hidden and the
address@hidden functions.
-
address@hidden Server Name Indication
address@hidden
address@hidden TLS Extensions
address@hidden Server name indication
-
-A common problem in @acronym{HTTPS} servers is the fact that the
address@hidden protocol is not aware of the hostname that a client
-connects to, when the handshake procedure begins. For that reason the
address@hidden server has no way to know which certificate to send.
-
-This extension solves that problem within the @acronym{TLS} protocol,
-and allows a client to send the HTTP hostname before the handshake
-begins within the first handshake packet.  The functions
address@hidden and @ref{gnutls_server_name_get} can be
-used to enable this extension, or to retrieve the name sent by a
-client.
-
address@hidden Session Tickets
address@hidden TLS Extensions
address@hidden Session Tickets
address@hidden Ticket
-
-To resume a TLS session the server normally store some state.  This
-complicates deployment, and typical situations the client can cache
-information and send it to the server instead.  The Session Ticket
-extension implements this idea, and it is documented in
-RFC 5077 @xcite{TLSTKT}.
-
-Clients can enable support for TLS tickets with
address@hidden and servers use
address@hidden to generate a key and
address@hidden to enable the extension.
-Clients resume sessions using the ticket using the normal session
-resume functions, @ref{resume}.
-
address@hidden Selecting cryptographic key sizes
address@hidden Selecting Cryptographic Key Sizes
address@hidden key sizes
-
-In TLS, since a lot of algorithms are involved, it is not easy to set
-a consistent security level.  For this reason this section will
-present some correspondance between key sizes of symmetric algorithms
-and public key algorithms based on the most conservative values of
address@hidden  Those can be used to generate certificates with
-appropriate key sizes as well as parameters for Diffie-Hellman and SRP
-authentication.
-
address@hidden @columnfractions .15 .20 .20 .20
-
address@hidden Year
address@hidden Symmetric key size
address@hidden RSA key size, DH and SRP prime size
address@hidden ECC key size
-
address@hidden 1982
address@hidden 56
address@hidden 417
address@hidden 105
-
address@hidden 1988
address@hidden 61
address@hidden 566
address@hidden 114
-
address@hidden 2002
address@hidden 72
address@hidden 1028
address@hidden 139
-
address@hidden 2015
address@hidden 82
address@hidden 1613
address@hidden 173
-
address@hidden 2028
address@hidden 92
address@hidden 2362
address@hidden 210
-
address@hidden 2040
address@hidden 101
address@hidden 3214
address@hidden 244
-
address@hidden 2050
address@hidden 109
address@hidden 4047
address@hidden 272
-
address@hidden multitable
-
-The first column provides an estimation of the year until these
-parameters are considered safe and the rest of the columns list the
-parameters for the various algorithms.
-
-Note however that the values suggested here are nothing more than an
-educated guess that is valid today. There are no guarrantees that an
-algorithm will remain unbreakable or that these values will remain
-constant in time. There could be scientific breakthroughs that cannot
-be predicted or total failure of the current public key systems by
-quantum computers. On the other hand though the cryptosystems used in
-TLS are selected in a conservative way and such catastrophic
-breakthroughs or failures are believed to be unlikely.
-
-NIST publication SP 800-57 @xcite{NISTSP80057} contains a similar
-table that extends beyond the key sizes given above.
-
address@hidden @columnfractions .15 .20 .20 .20
-
address@hidden Bits of security
address@hidden Symmetric key algorithms
address@hidden RSA key size, DSA, DH and SRP prime size
address@hidden ECC key size
-
address@hidden 80
address@hidden 2TDEA
address@hidden 1024
address@hidden 160-223
-
address@hidden 112
address@hidden 3DES
address@hidden 2048
address@hidden 224-255
-
address@hidden 128
address@hidden AES-128
address@hidden 3072
address@hidden 256-383
-
address@hidden 192
address@hidden AES-192
address@hidden 7680
address@hidden 384-511
-
address@hidden 256
address@hidden AES-256
address@hidden 15360
address@hidden 512+
-
address@hidden multitable
-
-The recommendations are fairly consistent.
-
address@hidden On SSL 2 and older protocols
address@hidden On SSL 2 and Older Protocols
address@hidden SSL 2
-
-One of the initial decisions in the @acronym{GnuTLS} development was
-to implement the known security protocols for the transport layer.
-Initially @acronym{TLS} 1.0 was implemented since it was the latest at
-that time, and was considered to be the most advanced in security
-properties.  Later the @acronym{SSL} 3.0 protocol was implemented
-since it is still the only protocol supported by several servers and
-there are no serious security vulnerabilities known.
-
-One question that may arise is why we didn't implement @acronym{SSL}
-2.0 in the library.  There are several reasons, most important being
-that it has serious security flaws, unacceptable for a modern security
-library.  Other than that, this protocol is barely used by anyone
-these days since it has been deprecated since 1996.  The security
-problems in @acronym{SSL} 2.0 include:
-
address@hidden
-
address@hidden Message integrity compromised.
-The @acronym{SSLv2} message authentication uses the MD5 function, and
-is insecure.
-
address@hidden Man-in-the-middle attack.
-There is no protection of the handshake in @acronym{SSLv2}, which
-permits a man-in-the-middle attack.
-
address@hidden Truncation attack.
address@hidden relies on TCP FIN to close the session, so the
-attacker can forge a TCP FIN, and the peer cannot tell if it was a
-legitimate end of data or not.
-
address@hidden Weak message integrity for export ciphers.
-The cryptographic keys in @acronym{SSLv2} are used for both message
-authentication and encryption, so if weak encryption schemes are
-negotiated (say 40-bit keys) the message authentication code use the
-same weak key, which isn't necessary.
-
address@hidden itemize
-
address@hidden PCT
-Other protocols such as Microsoft's @acronym{PCT} 1 and @acronym{PCT}
-2 were not implemented because they were also abandoned and deprecated
-by @acronym{SSL} 3.0 and later @acronym{TLS} 1.0.
-
address@hidden On Record Padding
address@hidden On Record Padding
address@hidden Record padding
address@hidden Bad record MAC
-
-The TLS protocol allows for random padding of records, to make it more
-difficult to perform analysis on the length of exchanged messages.
-(In RFC 4346 this is specified in section 6.2.3.2.)  GnuTLS appears to
-be one of few implementation that take advantage of this text, and pad
-records by a random length.
-
-The TLS implementation in the Symbian operating system, frequently
-used by Nokia and Sony-Ericsson mobile phones, cannot handle
-non-minimal record padding.  What happens when one of these clients
-handshake with a GnuTLS server is that the client will fail to compute
-the correct MAC for the record.  The client sends a TLS alert
-(@code{bad_record_mac}) and disconnects.  Typically this will result
-in error messages such as 'A TLS fatal alert has been received', 'Bad
-record MAC', or both, on the GnuTLS server side.
-
-GnuTLS implements a work around for this problem.  However, it has to
-be enabled specifically.  It can be enabled by using
address@hidden, or @ref{gnutls_priority_set} with
-the @code{%COMPAT} priority string.
-
-If you implement an application that have a configuration file, we
-recommend that you make it possible for users or administrators to
-specify a GnuTLS protocol priority string, which is used by your
-application via @ref{gnutls_priority_set}.  To allow the best
-flexibility, make it possible to have a different priority string for
-different incoming IP addresses.
-
-To enable the workaround in the @code{gnutls-cli} client or the
address@hidden server, for testing of other implementations, use
-the following parameter: @code{--priority "%COMPAT"}.
-
-This problem has been discussed on mailing lists and in bug reports.
-This section tries to collect all pieces of information that we know
-about the problem.  If you wish to go back to the old discussions,
-here are some links:
-
address@hidden://bugs.debian.org/390712}
-
address@hidden://bugs.debian.org/402861}
-
address@hidden://bugs.debian.org/438137}
-
address@hidden://thread.gmane.org/gmane.ietf.tls/3079}
-
address@hidden Safe Renegotiation
address@hidden Safe Renegotiation
address@hidden renegotiation
-
-Some application protocols and implementations uses the TLS
-renegotiation feature in a manner that enables attackers to insert
-content of his choice in the beginning of a TLS session.
-
-One easy to understand vulnerability is HTTPS when servers request
-client certificates optionally for certain parts of a web site.  The
-attack works by having the attacker simulate a client and connect to a
-server, with server-only authentication, and send some data intended
-to cause harm.  When the proper client attempts to contact the server,
-the attacker hijacks that connection and uses the TLS renegotiation
-feature with the server and splices in the client connection to the
-already established connection between the attacker and server.  The
-attacker will not be able to read the data exchanged between the
-client and the server.  However, the server will (incorrectly) assume
-that the data sent by the attacker was sent by the now authenticated
-client.  The result is a prefix plain-text injection attack.
-
-The above is just one example.  Other vulnerabilities exists that do
-not rely on the TLS renegotiation to change the client's authenticated
-status (either TLS or application layer).
-
-While fixing these application protocols and implementations would be
-one natural reaction, an extension to TLS has been designed that
-cryptographically binds together any renegotiated handshakes with the
-initial negotiation.  When the extension is used, the attack is
-detected and the session can be terminated.  The extension is
-specified in @xcite{RFC5746}.
-
-GnuTLS supports the safe renegotiation extension.  The default
-behavior is as follows.  Clients will attempt to negotiate the safe
-renegotiation extension when talking to servers.  Servers will accept
-the extension when presented by clients.  Clients and servers will
-permit an initial handshake to complete even when the other side does
-not support the safe renegotiation extension.  Clients and servers
-will refuse renegotiation attempts when the extension has not been
-negotiated.
-
-Note that permitting clients to connect to servers even when the safe
-renegotiation extension is not negotiated open up for some attacks.
-Changing this default behaviour would prevent interoperability against
-the majority of deployed servers out there.  We will reconsider this
-default behaviour in the future when more servers have been upgraded.
-Note that it is easy to configure clients to always require the safe
-renegotiation extension from servers (see below on the
-%SAFE_RENEGOTIATION priority string).
-
-To modify the default behaviour, we have introduced some new priority
-strings.  The priority strings can be used by applications
-(@pxref{gnutls_priority_set}) and end users (e.g., @code{--priority}
-parameter to @code{gnutls-cli} and @code{gnutls-serv}).
-
-The @code{%UNSAFE_RENEGOTIATION} priority string permits
-(re-)handshakes even when the safe renegotiation extension was not
-negotiated. The default behavior is @code{%PARTIAL_RENEGOTIATION} that will
-prevent renegotiation with clients and servers not supporting the
-extension. This is secure for servers but leaves clients vulnerable
-to some attacks, but this is a tradeoff between security and compatibility
-with old servers. The @code{%SAFE_RENEGOTIATION} priority string makes
-clients and servers require the extension for every handshake. The latter
-is the most secure option for clients, at the cost of not being able
-to connect to legacy servers. Servers will also deny clients that
-do not support the extension from connecting.
-
-It is possible to disable use of the extension completely, in both
-clients and servers, by using the @code{%DISABLE_SAFE_RENEGOTIATION}
-priority string however we strongly recommend you to only do this for
-debugging and test purposes.
-
-The default values if the flags above are not specified are:
address@hidden @code
-
address@hidden Server:
-%PARTIAL_RENEGOTIATION
-
address@hidden Client:
-%PARTIAL_RENEGOTIATION
-
address@hidden table
-
-For applications we have introduced a new API related to safe
-renegotiation.  The @ref{gnutls_safe_renegotiation_status} function is
-used to check if the extension has been negotiated on a session, and
-can be used both by clients and servers.
-
address@hidden Authentication methods
address@hidden Authentication Methods
-
-The @acronym{TLS} protocol provides confidentiality and encryption,
-but also offers authentication, which is a prerequisite for a secure
-connection. The available authentication methods in @acronym{GnuTLS}
-are:
-
address@hidden
-
address@hidden Certificate authentication
-
address@hidden Anonymous authentication
-
address@hidden @acronym{SRP} authentication
-
address@hidden @acronym{PSK} authentication
-
address@hidden itemize
-
address@hidden
-* Certificate authentication::
-* Anonymous authentication::
-* Authentication using SRP::
-* Authentication using PSK::
-* Authentication and credentials::
-* Parameters stored in credentials::
address@hidden menu
-
address@hidden Certificate authentication
address@hidden Certificate Authentication
-
address@hidden Authentication Using @acronym{X.509} Certificates
address@hidden @acronym{X.509} certificates
-
address@hidden certificates contain the public parameters, of a
-public key algorithm, and an authority's signature, which proves the
-authenticity of the parameters.  @xref{The X.509 trust model}, for
-more information on @acronym{X.509} protocols.
-
address@hidden Authentication Using @acronym{OpenPGP} Keys
address@hidden @acronym{OpenPGP} Keys
-
address@hidden keys also contain public parameters of a public key
-algorithm, and signatures from several other parties. Depending on
-whether a signer is trusted the key is considered trusted or not.
address@hidden's @acronym{OpenPGP} authentication implementation is
-based on the @xcite{TLSPGP} proposal.
-
address@hidden OpenPGP trust model}, for more information about the
address@hidden trust model.  For a more detailed introduction to
address@hidden and @acronym{GnuPG} see @xcite{GPGH}.
-
address@hidden Using Certificate Authentication
-
-In @acronym{GnuTLS} both the @acronym{OpenPGP} and @acronym{X.509}
-certificates are part of the certificate authentication and thus are
-handled using a common API.
-
-When using certificates the server is required to have at least one
-certificate and private key pair. A client may or may not have such a
-pair. The certificate and key pair should be loaded, before any
address@hidden session is initialized, in a certificate credentials
-structure. This should be done by using
address@hidden or
address@hidden depending on the
-certificate type.  In the @acronym{X.509} case, the functions will
-also accept and use a certificate list that leads to a trusted
-authority. The certificate list must be ordered in such way that every
-certificate certifies the one before it. The trusted authority's
-certificate need not to be included, since the peer should possess it
-already.
-
-As an alternative, a callback may be used so the server or the client
-specify the certificate and the key at the handshake time.  That
-callback can be set using the functions:
-
address@hidden
-
address@hidden @ref{gnutls_certificate_server_set_retrieve_function}
-
address@hidden @ref{gnutls_certificate_client_set_retrieve_function}
-
address@hidden itemize
-
-Clients and servers that will select certificates using callback
-functions should select a certificate according the peer's signature
-algorithm preferences. To get those preferences use
address@hidden
-
-Certificate verification is possible by loading the trusted
-authorities into the credentials structure by using
address@hidden or
address@hidden for openpgp
-keys. Note however that the peer's certificate is not automatically
-verified, you should call @ref{gnutls_certificate_verify_peers2},
-after a successful handshake, to verify the signatures of the
-certificate.  An alternative way, which reports a more detailed
-verification output, is to use @ref{gnutls_certificate_get_peers} to
-obtain the raw certificate of the peer and verify it using the
-functions discussed in @ref{The X.509 trust model}.
-
-In a handshake, the negotiated cipher suite depends on the
-certificate's parameters, so not all key exchange methods will be
-available with some certificates. @acronym{GnuTLS} will disable
-ciphersuites that are not compatible with the key, or the enabled
-authentication methods.  For example keys marked as sign-only, will
-not be able to access the plain RSA ciphersuites, but only the
address@hidden ones. It is recommended not to use RSA keys for both
-signing and encryption. If possible use the same key for the
address@hidden and @code{RSA_EXPORT} ciphersuites, which use signing,
-and a different key for the plain RSA ciphersuites, which use
-encryption.  All the key exchange methods shown below are available in
-certificate authentication.
-
-Note that the DHE key exchange methods are generally
address@hidden really depends on the group used.  Primes with
-lesser bits are always faster, but also easier to break.  Values less
-than 768 should not be used today} than plain RSA and require Diffie
-Hellman parameters to be generated and associated with a credentials
-structure, by the server.  The @code{RSA-EXPORT} method also requires
-512 bit RSA parameters, that should also be generated and associated
-with the credentials structure.  See the functions:
-
address@hidden
-
address@hidden @ref{gnutls_dh_params_generate2}
-
address@hidden @ref{gnutls_certificate_set_dh_params}
-
address@hidden @ref{gnutls_rsa_params_generate2}
-
address@hidden @ref{gnutls_certificate_set_rsa_export_params}
-
address@hidden itemize
-
-Sometimes in order to avoid bottlenecks in programs it is usefull to
-store and read parameters from formats that can be generated by
-external programs such as @code{certtool}. This is possible with
address@hidden by using the following functions:
-
address@hidden
-
address@hidden @ref{gnutls_dh_params_import_pkcs3}
-
address@hidden @ref{gnutls_rsa_params_import_pkcs1}
-
address@hidden @ref{gnutls_dh_params_export_pkcs3}
-
address@hidden @ref{gnutls_rsa_params_export_pkcs1}
-
address@hidden itemize
-
-Key exchange algorithms for @acronym{OpenPGP} and @acronym{X.509}
-certificates:
-
address@hidden @code
-
address@hidden RSA:
-The RSA algorithm is used to encrypt a key and send it to the peer.
-The certificate must allow the key to be used for encryption.
-
address@hidden RSA_EXPORT:
-The RSA algorithm is used to encrypt a key and send it to the peer.
-In the EXPORT algorithm, the server signs temporary RSA parameters of
-512 bits --- which are considered weak --- and sends them to the
-client.
-
address@hidden DHE_RSA:
-The RSA algorithm is used to sign Ephemeral Diffie-Hellman parameters
-which are sent to the peer. The key in the certificate must allow the
-key to be used for signing. Note that key exchange algorithms which
-use Ephemeral Diffie-Hellman parameters, offer perfect forward
-secrecy. That means that even if the private key used for signing is
-compromised, it cannot be used to reveal past session data.
-
address@hidden DHE_DSS:
-The DSS algorithm is used to sign Ephemeral Diffie-Hellman parameters
-which are sent to the peer. The certificate must contain DSA
-parameters to use this key exchange algorithm. DSS stands for Digital
-Signature Standard.
-
address@hidden table
-
address@hidden Anonymous authentication
address@hidden Anonymous Authentication
address@hidden Anonymous authentication
-
-The anonymous key exchange performs encryption but there is no
-indication of the identity of the peer.  This kind of authentication
-is vulnerable to a man in the middle attack, but this protocol can be
-used even if there is no prior communication and trusted parties with
-the peer, or when full anonymity is required.  Unless really required,
-do not use anonymous authentication.  Available key exchange methods
-are shown below.
-
-Note that the key exchange methods for anonymous authentication
-require Diffie-Hellman parameters to be generated by the server and
-associated with an anonymous credentials structure.
-
-Supported anonymous key exchange algorithms:
-
address@hidden @code
-
address@hidden ANON_DH:
-This algorithm exchanges Diffie-Hellman parameters.
-
address@hidden table
-
address@hidden Authentication using SRP
address@hidden Authentication using @acronym{SRP}
address@hidden @acronym{SRP} authentication
-
-Authentication via the Secure Remote Password protocol,
address@hidden@address@hidden is described in @xcite{RFC2945}},
-is supported.  The @acronym{SRP} key exchange is an extension to the
address@hidden protocol, and it is a password based authentication
-(unlike @acronym{X.509} or @acronym{OpenPGP} that use certificates).
-The two peers can be identified using a single password, or there can
-be combinations where the client is authenticated using @acronym{SRP}
-and the server using a certificate.
-
-The advantage of @acronym{SRP} authentication, over other proposed
-secure password authentication schemes, is that @acronym{SRP} does not
-require the server to hold the user's password.  This kind of
-protection is similar to the one used traditionally in the @emph{UNIX}
address@hidden/etc/passwd} file, where the contents of this file did not cause
-harm to the system security if they were revealed.  The @acronym{SRP}
-needs instead of the plain password something called a verifier, which
-is calculated using the user's password, and if stolen cannot be used
-to impersonate the user. Check @xcite{TOMSRP} for a detailed
-description of the @acronym{SRP} protocol and the Stanford
address@hidden libraries, which includes a PAM module that synchronizes
-the system's users passwords with the @acronym{SRP} password
-files. That way @acronym{SRP} authentication could be used for all the
-system's users.
-
-The implementation in @acronym{GnuTLS} is based on paper
address@hidden  The supported @acronym{SRP} key exchange methods are:
-
address@hidden @code
-
address@hidden SRP:
-Authentication using the @acronym{SRP} protocol.
-
address@hidden SRP_DSS:
-Client authentication using the @acronym{SRP} protocol. Server is
-authenticated using a certificate with DSA parameters.
-
address@hidden SRP_RSA:
-Client authentication using the @acronym{SRP} protocol. Server is
-authenticated using a certificate with RSA parameters.
-
address@hidden table
-
-If clients supporting @acronym{SRP} know the username and password
-before the connection, should initialize the client credentials and
-call the function @ref{gnutls_srp_set_client_credentials}.
-Alternatively they could specify a callback function by using the
-function @ref{gnutls_srp_set_client_credentials_function}.  This has
-the advantage that allows probing the server for @acronym{SRP}
-support.  In that case the callback function will be called twice per
-handshake.  The first time is before the ciphersuite is negotiated,
-and if the callback returns a negative error code, the callback will
-be called again if @acronym{SRP} has been negotiated.  This uses a
-special @address@hidden handshake idiom in order to avoid,
-in interactive applications, to ask the user for @acronym{SRP}
-password and username if the server does not negotiate an
address@hidden ciphersuite.
-
-In server side the default behaviour of @acronym{GnuTLS} is to read
-the usernames and @acronym{SRP} verifiers from password files. These
-password files are the ones used by the @emph{Stanford srp libraries}
-and can be specified using the
address@hidden  If a different
-password file format is to be used, then the function
address@hidden, should be called,
-in order to set an appropriate callback.
-
-Some helper functions such as
-
address@hidden
-
address@hidden @ref{gnutls_srp_verifier}
-
address@hidden @ref{gnutls_srp_base64_encode}
-
address@hidden @ref{gnutls_srp_base64_decode}
-
address@hidden itemize
-
-are included in @acronym{GnuTLS}, and can be used to generate and
-maintain @acronym{SRP} verifiers and password files.  A program to
-manipulate the required parameters for @acronym{SRP} authentication is
-also included.  @xref{srptool}, for more information.
-
-
address@hidden Authentication using PSK
address@hidden Authentication using @acronym{PSK}
address@hidden @acronym{PSK} authentication
-
-Authentication using Pre-shared keys is a method to authenticate using
-usernames and binary keys. This protocol avoids making use of public
-key infrastructure and expensive calculations, thus it is suitable for
-constraint clients.
-
-The implementation in @acronym{GnuTLS} is based on paper
address@hidden  The supported @acronym{PSK} key exchange methods are:
-
address@hidden @code
-
address@hidden PSK:
-Authentication using the @acronym{PSK} protocol.
-
address@hidden DHE-PSK:
-Authentication using the @acronym{PSK} protocol and Diffie-Hellman key
-exchange.  This method offers perfect forward secrecy.
-
address@hidden table
-
-Clients supporting @acronym{PSK} should supply the username and key
-before the connection to the client credentials by calling the
-function @ref{gnutls_psk_set_client_credentials}.  Alternatively they
-could specify a callback function by using the function
address@hidden  This has the
-advantage that the callback will be called only if @acronym{PSK} has
-been negotiated.
-
-In server side the default behaviour of @acronym{GnuTLS} is to read
-the usernames and @acronym{PSK} keys from a password file. The
-password file should contain usernames and keys in hexadecimal
-format. The name of the password file can be stored to the credentials
-structure by calling @ref{gnutls_psk_set_server_credentials_file}.  If
-a different password file format is to be used, then the function
address@hidden, should be used
-instead.
-
-The server can help the client chose a suitable username and password,
-by sending a hint.  In the server, specify the hint by calling
address@hidden  The client can retrieve
-the hint, for example in the callback function, using
address@hidden
-
-There is no standard mechanism to derive a PSK key from a password
-specified by the TLS PSK document.  However, GnuTLS provides
address@hidden which follows the algorithm
-specified in @file{draft-ietf-netconf-tls-02.txt}.
-
-Some helper functions such as:
-
address@hidden
-
address@hidden @ref{gnutls_hex_encode}
-
address@hidden @ref{gnutls_hex_decode}
-
address@hidden itemize
-
-are included in @acronym{GnuTLS}, and may be used to generate and
-maintain @acronym{PSK} keys.
-
-
address@hidden Authentication and credentials
address@hidden Authentication and Credentials
-
-In @acronym{GnuTLS} every key exchange method is associated with a
-credentials type. So in order to enable to enable a specific method,
-the corresponding credentials type should be initialized and set using
address@hidden  A mapping is shown below.
-
-Key exchange algorithms and the corresponding credential types:
-
address@hidden @columnfractions .3 .3 .3
-
address@hidden Key exchange @tab Client credentials @tab Server credentials
-
address@hidden @code{KX_RSA}
address@hidden @code{KX_DHE_RSA}
address@hidden @code{KX_DHE_DSS}
address@hidden @code{KX_RSA_EXPORT}
address@hidden @code{CRD_CERTIFICATE}
address@hidden @code{CRD_CERTIFICATE}
-
address@hidden @code{KX_SRP_RSA}
address@hidden @code{CRD_SRP}
address@hidden @code{CRD_SRP}
address@hidden @code{KX_SRP_DSS}
address@hidden
address@hidden @code{CRD_CERTIFICATE}
-
address@hidden @code{KX_SRP}
address@hidden @code{CRD_SRP}
address@hidden @code{CRD_SRP}
-
address@hidden @code{KX_ANON_DH}
address@hidden @code{CRD_ANON}
address@hidden @code{CRD_ANON}
-
address@hidden @code{KX_PSK}
address@hidden @code{CRD_PSK}
address@hidden @code{CRD_PSK}
-
address@hidden multitable
-
address@hidden Parameters stored in credentials
address@hidden Parameters Stored in Credentials
-
-Several parameters such as the ones used for Diffie-Hellman
-authentication are stored within the credentials structures, so all
-sessions can access them. Those parameters are stored in structures
-such as @code{gnutls_dh_params_t} and @code{gnutls_rsa_params_t}, and
-functions like @ref{gnutls_certificate_set_dh_params} and
address@hidden can be used to
-associate those parameters with the given credentials structure.
-
-Since those parameters need to be renewed from time to time and a
-global structure such as the credentials, may not be easy to modify
-since it is accessible by all sessions, an alternative interface is
-available using a callback function.  This can be set using the
address@hidden  An example is shown
-below.
-
address@hidden
-#include <gnutls.h>
-
-gnutls_rsa_params_t rsa_params;
-gnutls_dh_params_t dh_params;
-
-/* This function will be called once a session requests DH
- * or RSA parameters. The parameters returned (if any) will
- * be used for the first handshake only.
- */
-static int get_params( gnutls_session_t session,
-        gnutls_params_type_t type,
-        gnutls_params_st *st)
address@hidden
-   if (type == GNUTLS_PARAMS_RSA_EXPORT)
-      st->params.rsa_export = rsa_params;
-   else if (type == GNUTLS_PARAMS_DH)
-      st->params.dh = dh_params;
-   else return -1;
-
-   st->type = type;
-   /* do not deinitialize those parameters.
-    */
-   st->deinit = 0;
-
-   return 0;
address@hidden
-
-int main()
address@hidden
-   gnutls_certificate_credentials_t cert_cred;
-
-   initialize_params();
-
-   /* ...
-    */
-
-   gnutls_certificate_set_params_function( cert_cred, get_params);
address@hidden
address@hidden example
-
address@hidden More on certificate authentication
address@hidden More on Certificate Authentication
address@hidden Authentication}
address@hidden Certificate authentication
-
address@hidden
-* The X.509 trust model::
-* The OpenPGP trust model::
-* Digital signatures::
address@hidden menu
-
address@hidden The X.509 trust model
address@hidden The @acronym{X.509} Trust Model
address@hidden @acronym{X.509} certificates
-
-The @acronym{X.509} protocols rely on a hierarchical trust model. In
-this trust model Certification Authorities (CAs) are used to certify
-entities.  Usually more than one certification authorities exist, and
-certification authorities may certify other authorities to issue
-certificates as well, following a hierarchical model.
-
address@hidden,7cm,9.5cm}
-
-One needs to trust one or more CAs for his secure communications. In
-that case only the certificates issued by the trusted authorities are
-acceptable.  See the figure above for a typical example.  The API for
-handling @acronym{X.509} certificates is described at section
address@hidden:x509api}.  Some examples are listed below.
-
address@hidden
-* X.509 certificates::
-* Verifying X.509 certificate paths::
-* PKCS #10 certificate requests::
-* PKCS #12 structures::
address@hidden menu
-
address@hidden X.509 certificates
address@hidden @acronym{X.509} Certificates
-
-An @acronym{X.509} certificate usually contains information about the
-certificate holder, the signer, a unique serial number, expiration
-dates and some other fields @xcite{PKIX} as shown in the table below.
-
address@hidden @code
-
address@hidden version:
-The field that indicates the version of the certificate.
-
address@hidden serialNumber:
-This field holds a unique serial number per certificate.
-
address@hidden issuer:
-Holds the issuer's distinguished name.
-
address@hidden validity:
-The activation and expiration dates.
-
address@hidden subject:
-The subject's distinguished name of the certificate.
-
address@hidden extensions:
-The extensions are fields only present in version 3 certificates.
-
address@hidden table
-
-The certificate's @emph{subject or issuer name} is not just a single
-string.  It is a Distinguished name and in the @acronym{ASN.1}
-notation is a sequence of several object IDs with their corresponding
-values. Some of available OIDs to be used in an @acronym{X.509}
-distinguished name are defined in @file{gnutls/x509.h}.
-
-The @emph{Version} field in a certificate has values either 1 or 3 for
-version 3 certificates.  Version 1 certificates do not support the
-extensions field so it is not possible to distinguish a CA from a
-person, thus their usage should be avoided.
-
-The @emph{validity} dates are there to indicate the date that the
-specific certificate was activated and the date the certificate's key
-would be considered invalid.
-
-Certificate @emph{extensions} are there to include information about
-the certificate's subject that did not fit in the typical certificate
-fields. Those may be e-mail addresses, flags that indicate whether the
-belongs to a CA etc.  All the supported @acronym{X.509} version 3
-extensions are shown in the table below.
-
address@hidden @code
-
address@hidden subject key id (2.5.29.14):
-An identifier of the key of the subject.
-
address@hidden authority key id (2.5.29.35):
-An identifier of the authority's key used to sign the certificate.
-
address@hidden subject alternative name (2.5.29.17):
-Alternative names to subject's distinguished name.
-
address@hidden key usage (2.5.29.15):
-Constraints the key's usage of the certificate.
-
address@hidden extended key usage (2.5.29.37):
-Constraints the purpose of the certificate.
-
address@hidden basic constraints (2.5.29.19):
-Indicates whether this is a CA certificate or not, and specify the
-maximum path lengths of certificate chains.
-
address@hidden CRL distribution points (2.5.29.31):
-This extension is set by the CA, in order to inform about the issued
-CRLs.
-
address@hidden Proxy Certification Information (1.3.6.1.5.5.7.1.14):
-Proxy Certificates includes this extension that contains the OID of
-the proxy policy language used, and can specify limits on the maximum
-lengths of proxy chains.  Proxy Certificates are specified in
address@hidden
-
address@hidden table
-
-In @acronym{GnuTLS} the @acronym{X.509} certificate structures are
-handled using the @code{gnutls_x509_crt_t} type and the corresponding
-private keys with the @code{gnutls_x509_privkey_t} type.  All the
-available functions for @acronym{X.509} certificate handling have
-their prototypes in @file{gnutls/x509.h}. An example program to
-demonstrate the @acronym{X.509} parsing capabilities can be found at
-section @ref{ex:x509-info}.
-
address@hidden Verifying X.509 certificate paths
address@hidden Verifying @acronym{X.509} Certificate Paths
address@hidden Verifying certificate paths
-
-Verifying certificate paths is important in @acronym{X.509}
-authentication. For this purpose the function
address@hidden is provided. The output of this function
-is the bitwise OR of the elements of the
address@hidden enumeration.  A detailed
-description of these elements can be found in figure below.  The
-function @ref{gnutls_certificate_verify_peers2} is equivalent to the
-previous one, and will verify the peer's certificate in a TLS session.
-
address@hidden @code
-
address@hidden GNUTLS_CERT_INVALID:
-The certificate is not signed by one of the known authorities, or
-the signature is invalid.
-
address@hidden GNUTLS_CERT_REVOKED:
-The certificate has been revoked by its CA.
-
address@hidden GNUTLS_CERT_SIGNER_NOT_FOUND:
-The certificate's issuer is not known. This is the case when the
-issuer is not in the trusted certificates list.
-
address@hidden GNUTLS_CERT_SIGNER_NOT_CA:
-The certificate's signer was not a CA. This may happen if
-this was a version 1 certificate, which is common with some CAs, or
-a version 3 certificate without the basic constrains extension.
-
address@hidden
address@hidden GNUTLS_CERT_INSECURE_ALGORITHM:
-The certificate was signed using an insecure algorithm such as MD2 or
-MD5.  These algorithms have been broken and should not be trusted.
-
address@hidden table
-
-There is also to possibility to pass some input to the verification
-functions in the form of flags. For @ref{gnutls_x509_crt_verify} the
-flags are passed straightforward, but
address@hidden depends on the flags set by
-calling @ref{gnutls_certificate_set_verify_flags}.  All the available
-flags are part of the enumeration
address@hidden and are explained in the table
-below.
-
address@hidden
address@hidden gnutls_certificate_verify_flags
address@hidden @code
address@hidden GNUTLS_VERIFY_DISABLE_CA_SIGN:
-If set a signer does not have to be a certificate authority. This
-flag should normaly be disabled, unless you know what this means.
-
address@hidden GNUTLS_VERIFY_ALLOW_X509_V1_CA_CRT:
-Allow only trusted CA certificates that have version 1.  This is
-safer than GNUTLS_VERIFY_ALLOW_ANY_X509_V1_CA_CRT, and should be
-used instead. That way only signers in your trusted list will be
-allowed to have certificates of version 1.
-
address@hidden GNUTLS_VERIFY_ALLOW_ANY_X509_V1_CA_CRT:
-Allow CA certificates that have version 1 (both root and
-intermediate). This is dangerous since those haven't the
-basicConstraints extension. Must be used in combination with
-GNUTLS_VERIFY_ALLOW_X509_V1_CA_CRT.
-
address@hidden GNUTLS_VERIFY_DO_NOT_ALLOW_SAME:
-If a certificate is not signed by anyone trusted but exists in
-the trusted CA list do not treat it as trusted.
-
address@hidden GNUTLS_VERIFY_ALLOW_SIGN_RSA_MD2:
-Allow certificates to be signed using the old MD2 algorithm.
-
address@hidden GNUTLS_VERIFY_ALLOW_SIGN_RSA_MD5:
-Allow certificates to be signed using the broken MD5 algorithm.
address@hidden table
-
-Although the verification of a certificate path indicates that the
-certificate is signed by trusted authority, does not reveal anything
-about the peer's identity. It is required to verify if the
-certificate's owner is the one you expect. For more information
-consult @xcite{RFC2818} and section @ref{ex:verify} for an example.
-
address@hidden PKCS #10 certificate requests
address@hidden @acronym{PKCS} #10 Certificate Requests
address@hidden Certificate requests
address@hidden @acronym{PKCS} #10
-
-A certificate request is a structure, which contain information about
-an applicant of a certificate service.  It usually contains a private
-key, a distinguished name and secondary data such as a challenge
-password. @acronym{GnuTLS} supports the requests defined in
address@hidden #10 @xcite{RFC2986}. Other certificate request's format
-such as PKIX's @xcite{RFC4211} are not currently supported.
-
-In @acronym{GnuTLS} the @acronym{PKCS} #10 structures are handled
-using the @code{gnutls_x509_crq_t} type.  An example of a certificate
-request generation can be found at section @ref{ex:crq}.
-
address@hidden PKCS #12 structures
address@hidden @acronym{PKCS} #12 Structures
address@hidden @acronym{PKCS} #12
-
-A @acronym{PKCS} #12 structure @xcite{PKCS12} usually contains a user's
-private keys and certificates. It is commonly used in browsers to
-export and import the user's identities.
-
-In @acronym{GnuTLS} the @acronym{PKCS} #12 structures are handled
-using the @code{gnutls_pkcs12_t} type. This is an abstract type that
-may hold several @code{gnutls_pkcs12_bag_t} types.  The Bag types are
-the holders of the actual data, which may be certificates, private
-keys or encrypted data.  An Bag of type encrypted should be decrypted
-in order for its data to be accessed.
-
-An example of a @acronym{PKCS} #12 structure generation can be found
-at section @ref{ex:pkcs12}.
-
address@hidden The OpenPGP trust model
address@hidden The @acronym{OpenPGP} Trust Model
address@hidden @acronym{OpenPGP} Keys
-
-The @acronym{OpenPGP} key authentication relies on a distributed trust
-model, called the ``web of trust''. The ``web of trust'' uses a
-decentralized system of trusted introducers, which are the same as a
-CA. @acronym{OpenPGP} allows anyone to sign anyone's else public
-key. When Alice signs Bob's key, she is introducing Bob's key to
-anyone who trusts Alice. If someone trusts Alice to introduce keys,
-then Alice is a trusted introducer in the mind of that observer.
-
address@hidden,11cm,9cm}
-
-For example: If David trusts Alice to be an introducer, and Alice
-signed Bob's key, Dave also trusts Bob's key to be the real one.
-
-There are some key points that are important in that model. In the
-example Alice has to sign Bob's key, only if she is sure that the key
-belongs to Bob. Otherwise she may also make Dave falsely believe that
-this is Bob's key. Dave has also the responsibility to know who to
-trust.  This model is similar to real life relations.
-
-Just see how Charlie behaves in the previous example. Although he has
-signed Bob's key - because he knows, somehow, that it belongs to Bob -
-he does not trust Bob to be an introducer. Charlie decided to trust
-only Kevin, for some reason. A reason could be that Bob is lazy
-enough, and signs other people's keys without being sure that they
-belong to the actual owner.
-
address@hidden @acronym{OpenPGP} Keys
-
-In @acronym{GnuTLS} the @acronym{OpenPGP} key structures
address@hidden are handled using the @code{gnutls_openpgp_crt_t} type
-and the corresponding private keys with the
address@hidden type. All the prototypes for the key
-handling functions can be found at @file{gnutls/openpgp.h}.
-
address@hidden Verifying an @acronym{OpenPGP} Key
-
-The verification functions of @acronym{OpenPGP} keys, included in
address@hidden, are simple ones, and do not use the features of the
-``web of trust''.  For that reason, if the verification needs are
-complex, the assistance of external tools like @acronym{GnuPG} and
-GPGME (@url{http://www.gnupg.org/related_software/gpgme/}) is
-recommended.
-
-There is one verification function in @acronym{GnuTLS}, the
address@hidden  This checks an
address@hidden key against a given set of public keys (keyring) and
-returns the key status. The key verification status is the same as in
address@hidden certificates, although the meaning and interpretation
-are different. For example an @acronym{OpenPGP} key may be valid, if
-the self signature is ok, even if no signers were found.  The meaning
-of verification status is shown in the figure below.
-
address@hidden @code
-
address@hidden CERT_INVALID:
-A signature on the key is invalid. That means that the key was
-modified by somebody, or corrupted during transport.
-
address@hidden CERT_REVOKED:
-The key has been revoked by its owner.
-
address@hidden CERT_SIGNER_NOT_FOUND:
-The key was not signed by a known signer.
-
address@hidden GNUTLS_CERT_INSECURE_ALGORITHM:
-The certificate was signed using an insecure algorithm such as MD2 or
-MD5.  These algorithms have been broken and should not be trusted.
-
address@hidden 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.
-
-
-
address@hidden How to use TLS in application protocols
address@hidden How To Use @acronym{TLS} in Application Protocols
-
-This chapter is intended to provide some hints on how to use the
address@hidden over simple custom made application protocols.  The
-discussion below mainly refers to the @emph{TCP/IP} transport layer
-but may be extended to other ones too.
-
address@hidden
-* Separate ports::
-* Upward negotiation::
address@hidden menu
-
address@hidden Separate ports
address@hidden Separate Ports
-
-Traditionally @acronym{SSL} was used in application protocols by
-assigning a new port number for the secure services. That way two
-separate ports were assigned, one for the non secure sessions, and one
-for the secured ones. This has the benefit that if a user requests a
-secure session then the client will try to connect to the secure port
-and fail otherwise. The only possible attack with this method is a
-denial of service one. The most famous example of this method is the
-famous ``HTTP over TLS'' or @acronym{HTTPS} protocol @xcite{RFC2818}.
-
-Despite its wide use, this method is not as good as it seems.  This
-approach starts the @acronym{TLS} Handshake procedure just after the
-client connects on the ---so called--- secure port.  That way the
address@hidden protocol does not know anything about the client, and
-popular methods like the host advertising in HTTP do not
address@hidden also the Server Name Indication extension on
address@hidden  There is no way for the client to say ``I
-connected to YYY server'' before the Handshake starts, so the server
-cannot possibly know which certificate to use.
-
-Other than that it requires two separate ports to run a single
-service, which is unnecessary complication. Due to the fact that there
-is a limitation on the available privileged ports, this approach was
-soon obsoleted.
-
address@hidden Upward negotiation
address@hidden Upward Negotiation
-
-Other application address@hidden LDAP, IMAP etc.}  use a
-different approach to enable the secure layer.  They use something
-called the ``TLS upgrade'' method. This method is quite tricky but it
-is more flexible. The idea is to extend the application protocol to
-have a ``STARTTLS'' request, whose purpose it to start the TLS
-protocols just after the client requests it.  This is a really neat
-idea and does not require an extra port.
-
-This method is used by almost all modern protocols and there is even
-the @xcite{RFC2817} paper which proposes extensions to HTTP to support
-it.
-
-The tricky part, in this method, is that the ``STARTTLS'' request is
-sent in the clear, thus is vulnerable to modifications.  A typical
-attack is to modify the messages in a way that the client is fooled
-and thinks that the server does not have the ``STARTTLS'' capability.
-See a typical conversation of a hypothetical protocol:
-
address@hidden
-(client connects to the server)
-
-CLIENT: HELLO I'M MR. XXX
-
-SERVER: NICE TO MEET YOU XXX
-
-CLIENT: PLEASE START TLS
-
-SERVER: OK
-
-*** TLS STARTS
-
-CLIENT: HERE ARE SOME CONFIDENTIAL DATA
address@hidden quotation
-
-And see an example of a conversation where someone is acting
-in between:
-
address@hidden
-(client connects to the server)
-
-CLIENT: HELLO I'M MR. XXX
-
-SERVER: NICE TO MEET YOU XXX
-
-CLIENT: PLEASE START TLS
-
-(here someone inserts this message)
-
-SERVER: SORRY I DON'T HAVE THIS CAPABILITY
-
-CLIENT: HERE ARE SOME CONFIDENTIAL DATA
address@hidden quotation
-
-As you can see above the client was fooled, and was dummy enough to
-send the confidential data in the clear.
-
-How to avoid the above attack? As you may have already thought this
-one is easy to avoid. The client has to ask the user before it
-connects whether the user requests @acronym{TLS} or not. If the user
-answered that he certainly wants the secure layer the last
-conversation should be:
-
address@hidden
-(client connects to the server)
-
-CLIENT: HELLO I'M MR. XXX
-
-SERVER: NICE TO MEET YOU XXX
-
-CLIENT: PLEASE START TLS
-
-(here someone inserts this message)
-
-SERVER: SORRY I DON'T HAVE THIS CAPABILITY
-
-CLIENT: BYE
-
-(the client notifies the user that the secure connection was not possible)
address@hidden quotation
-
-This method, if implemented properly, is far better than the
-traditional method, and the security properties remain the same, since
-only denial of service is possible. The benefit is that the server may
-request additional data before the @acronym{TLS} Handshake protocol
-starts, in order to send the correct certificate, use the correct
-password address@hidden @acronym{SRP} authentication}, or anything
-else!
-
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 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 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}.
-
address@hidden Included programs
address@hidden Included Programs
-
-Included with @acronym{GnuTLS} are also a few command line tools that
-let you use the library for common tasks without writing an
-application.  The applications are discussed in this chapter.
-
address@hidden
-* Invoking certtool::
-* Invoking gnutls-cli::
-* Invoking gnutls-cli-debug::
-* Invoking gnutls-serv::
-* Invoking psktool::
-* Invoking srptool::
address@hidden menu
-
address@hidden Invoking certtool
address@hidden Invoking certtool
address@hidden certtool
-
-This is a program to generate @acronym{X.509} certificates, certificate
-requests, CRLs and private keys.
-
address@hidden
-Certtool help
-Usage: certtool [options]
-     -s, --generate-self-signed
-                              Generate a self-signed certificate.
-     -c, --generate-certificate
-                              Generate a signed certificate.
-     --generate-proxy         Generate a proxy certificate.
-     --generate-crl           Generate a CRL.
-     -u, --update-certificate
-                              Update a signed certificate.
-     -p, --generate-privkey   Generate a private key.
-     -q, --generate-request   Generate a PKCS #10 certificate
-                              request.
-     -e, --verify-chain       Verify a PEM encoded certificate chain.
-                              The last certificate in the chain must
-                              be a self signed one.
-     --verify-crl             Verify a CRL.
-     --generate-dh-params     Generate PKCS #3 encoded Diffie-Hellman
-                              parameters.
-     --get-dh-params          Get the included PKCS #3 encoded Diffie
-                              Hellman parameters.
-     --load-privkey FILE      Private key file to use.
-     --load-request FILE      Certificate request file to use.
-     --load-certificate FILE
-                              Certificate file to use.
-     --load-ca-privkey FILE   Certificate authority's private key
-                              file to use.
-     --load-ca-certificate FILE
-                              Certificate authority's certificate
-                              file to use.
-     --password PASSWORD      Password to use.
-     -i, --certificate-info   Print information on a certificate.
-     -l, --crl-info           Print information on a CRL.
-     --p12-info               Print information on a PKCS #12
-                              structure.
-     --p7-info                Print information on a PKCS #7
-                              structure.
-     --smime-to-p7            Convert S/MIME to PKCS #7 structure.
-     -k, --key-info           Print information on a private key.
-     --fix-key                Regenerate the parameters in a private
-                              key.
-     --to-p12                 Generate a PKCS #12 structure.
-     -8, --pkcs8              Use PKCS #8 format for private keys.
-     --dsa                    Use DSA keys.
-     --hash STR               Hash algorithm to use for signing
-                              (MD5,SHA1,RMD160).
-     --export-ciphers         Use weak encryption algorithms.
-     --inder                  Use DER format for input certificates
-                              and private keys.
-     --outder                 Use DER format for output certificates
-                              and private keys.
-     --bits BITS              specify the number of bits for key
-                              generation.
-     --outfile FILE           Output file.
-     --infile FILE            Input file.
-     --template FILE          Template file to use for non
-                              interactive operation.
-     -d, --debug LEVEL        specify the debug level. Default is 1.
-     -h, --help               shows this help text
-     -v, --version            shows the program's version
address@hidden verbatim
-
-The program can be used interactively or non interactively by
-specifying the @code{--template} command line option. See below for an
-example of a template file.
-
-How to use certtool interactively:
-
address@hidden
address@hidden
-To generate parameters for Diffie-Hellman key exchange, use the command:
address@hidden
-$ certtool --generate-dh-params --outfile dh.pem
address@hidden example
-
address@hidden
-To generate parameters for the RSA-EXPORT key exchange, use the command:
address@hidden
-$ certtool --generate-privkey --bits 512 --outfile rsa.pem
address@hidden example
-
address@hidden itemize
-
address@hidden
-
address@hidden
-To create a self signed certificate, use the command:
address@hidden
-$ certtool --generate-privkey --outfile ca-key.pem
-$ certtool --generate-self-signed --load-privkey ca-key.pem \
-   --outfile ca-cert.pem
address@hidden example
-
-Note that a self-signed certificate usually belongs to a certificate
-authority, that signs other certificates.
-
address@hidden
-To create a private key (RSA by default), run:
-
address@hidden
-$ certtool --generate-privkey --outfile key.pem
address@hidden example
-
-To create a DSA private key, run:
-
address@hidden
-$ certtool --dsa --generate-privkey --outfile key-dsa.pem
address@hidden example
-
address@hidden
-To generate a certificate using the private key, use the command:
-
address@hidden
-$ certtool --generate-certificate --load-privkey key.pem \
-   --outfile cert.pem --load-ca-certificate ca-cert.pem \
-   --load-ca-privkey ca-key.pem
address@hidden example
-
address@hidden
-To create a certificate request (needed when the certificate is issued by
-another party), run:
-
address@hidden
-$ certtool --generate-request --load-privkey key.pem \
-  --outfile request.pem
address@hidden example
-
address@hidden
-To generate a certificate using the previous request, use the command:
-
address@hidden
-$ certtool --generate-certificate --load-request request.pem \
-   --outfile cert.pem \
-   --load-ca-certificate ca-cert.pem --load-ca-privkey ca-key.pem
address@hidden example
-
address@hidden
-To view the certificate information, use:
-
address@hidden
-$ certtool --certificate-info --infile cert.pem
address@hidden example
-
address@hidden
-To generate a @acronym{PKCS} #12 structure using the previous key and
-certificate, use the command:
-
address@hidden
-$ certtool --load-certificate cert.pem --load-privkey key.pem \
-  --to-p12 --outder --outfile key.p12
address@hidden example
-
-Some tools (reportedly web browsers) have problems with that file
-because it does not contain the CA certificate for the certificate.
-To work around that problem in the tool, you can use the
address@hidden parameter as follows:
-
address@hidden
-$ certtool --load-ca-certificate ca.pem \
-  --load-certificate cert.pem --load-privkey key.pem \
-  --to-p12 --outder --outfile key.p12
address@hidden example
-
address@hidden
-Proxy certificate can be used to delegate your credential to a
-temporary, typically short-lived, certificate.  To create one from the
-previously created certificate, first create a temporary key and then
-generate a proxy certificate for it, using the commands:
-
address@hidden
-$ certtool --generate-privkey > proxy-key.pem
-$ certtool --generate-proxy --load-ca-privkey key.pem \
-  --load-privkey proxy-key.pem --load-certificate cert.pem \
-  --outfile proxy-cert.pem
address@hidden example
-
address@hidden
-To create an empty Certificate Revocation List (CRL) do:
-
address@hidden
-$ certtool --generate-crl --load-ca-privkey x509-ca-key.pem 
--load-ca-certificate x509-ca.pem
address@hidden example
-
-To create a CRL that contains some revoked certificates, place the
-certificates in a file and use @code{--load-certificate} as follows:
-
address@hidden
-$ certtool --generate-crl --load-ca-privkey x509-ca-key.pem 
--load-ca-certificate x509-ca.pem --load-certificate revoked-certs.pem
address@hidden example
-
address@hidden
-To verify a Certificate Revocation List (CRL) do:
-
address@hidden
-$ certtool --verify-crl --load-ca-certificate x509-ca.pem < crl.pem
address@hidden example
-
address@hidden itemize
-
-Certtool's template file format:
-
address@hidden
-
address@hidden
-Firstly create a file named 'cert.cfg' that contains the information
-about the certificate. An example file is listed below.
-
address@hidden
-Then execute:
-
address@hidden
-$ certtool --generate-certificate cert.pem --load-privkey key.pem  \
-   --template cert.cfg \
-   --load-ca-certificate ca-cert.pem --load-ca-privkey ca-key.pem
address@hidden example
-
address@hidden itemize
-
-An example certtool template file:
-
address@hidden
-# X.509 Certificate options
-#
-# DN options
-
-# The organization of the subject.
-organization = "Koko inc."
-
-# The organizational unit of the subject.
-unit = "sleeping dept."
-
-# The locality of the subject.
-# locality =
-
-# The state of the certificate owner.
-state = "Attiki"
-
-# The country of the subject. Two letter code.
-country = GR
-
-# The common name of the certificate owner.
-cn = "Cindy Lauper"
-
-# A user id of the certificate owner.
-#uid = "clauper"
-
-# If the supported DN OIDs are not adequate you can set
-# any OID here.
-# For example set the X.520 Title and the X.520 Pseudonym
-# by using OID and string pairs.
-#dn_oid = "2.5.4.12" "Dr." "2.5.4.65" "jackal"
-
-# This is deprecated and should not be used in new
-# certificates.
-# pkcs9_email = "none@@none.org"
-
-# The serial number of the certificate
-serial = 007
-
-# In how many days, counting from today, this certificate will expire.
-expiration_days = 700
-
-# X.509 v3 extensions
-
-# A dnsname in case of a WWW server.
-#dns_name = "www.none.org"
-#dns_name = "www.morethanone.org"
-
-# An IP address in case of a server.
-#ip_address = "192.168.1.1"
-
-# An email in case of a person
-email = "none@@none.org"
-
-# An URL that has CRLs (certificate revocation lists)
-# available. Needed in CA certificates.
-#crl_dist_points = "http://www.getcrl.crl/getcrl/";
-
-# Whether this is a CA certificate or not
-#ca
-
-# Whether this certificate will be used for a TLS client
-#tls_www_client
-
-# Whether this certificate will be used for a TLS server
-#tls_www_server
-
-# Whether this certificate will be used to sign data (needed
-# in TLS DHE ciphersuites).
-signing_key
-
-# Whether this certificate will be used to encrypt data (needed
-# in TLS RSA ciphersuites). Note that it is preferred to use different
-# keys for encryption and signing.
-#encryption_key
-
-# Whether this key will be used to sign other certificates.
-#cert_signing_key
-
-# Whether this key will be used to sign CRLs.
-#crl_signing_key
-
-# Whether this key will be used to sign code.
-#code_signing_key
-
-# Whether this key will be used to sign OCSP data.
-#ocsp_signing_key
-
-# Whether this key will be used for time stamping.
-#time_stamping_key
address@hidden example
-
address@hidden Invoking gnutls-cli
address@hidden Invoking gnutls-cli
address@hidden gnutls-cli
-
-Simple client program to set up a TLS connection to some other
-computer.  It sets up a TLS connection and forwards data from the
-standard input to the secured socket and vice versa.
-
address@hidden
-GnuTLS test client
-Usage:  gnutls-cli [options] hostname
-
-     -d, --debug integer      Enable debugging
-     -r, --resume             Connect, establish a session. Connect
-                              again and resume this session.
-     -s, --starttls           Connect, establish a plain session and
-                              start TLS when EOF or a SIGALRM is
-                              received.
-     --crlf                   Send CR LF instead of LF.
-     --x509fmtder             Use DER format for certificates to read
-                              from.
-     -f, --fingerprint        Send the openpgp fingerprint, instead
-                              of the key.
-     --disable-extensions     Disable all the TLS extensions.
-     --print-cert             Print the certificate in PEM format.
-     --recordsize integer     The maximum record size to advertize.
-     -V, --verbose            More verbose output.
-     --ciphers cipher1 cipher2...
-                              Ciphers to enable.
-     --protocols protocol1 protocol2...
-                              Protocols to enable.
-     --comp comp1 comp2...    Compression methods to enable.
-     --macs mac1 mac2...      MACs to enable.
-     --kx kx1 kx2...          Key exchange methods to enable.
-     --ctypes certType1 certType2...
-                              Certificate types to enable.
-     --priority PRIORITY STRING
-                              Priorities string.
-     --x509cafile FILE        Certificate file to use.
-     --x509crlfile FILE       CRL file to use.
-     --pgpkeyfile FILE        PGP Key file to use.
-     --pgpkeyring FILE        PGP Key ring file to use.
-     --pgpcertfile FILE       PGP Public Key (certificate) file to
-                              use.
-     --pgpsubkey HEX|auto     PGP subkey to use.
-     --x509keyfile FILE       X.509 key file to use.
-     --x509certfile FILE      X.509 Certificate file to use.
-     --srpusername NAME       SRP username to use.
-     --srppasswd PASSWD       SRP password to use.
-     --pskusername NAME       PSK username to use.
-     --pskkey KEY             PSK key (in hex) to use.
-     --opaque-prf-input DATA
-                              Use Opaque PRF Input DATA.
-     -p, --port PORT          The port to connect to.
-     --insecure               Don't abort program if server
-                              certificate can't be validated.
-     -l, --list               Print a list of the supported
-                              algorithms and modes.
-     -h, --help               prints this help
-     -v, --version            prints the program's version number
address@hidden verbatim
-
-To connect to a server using PSK authentication, you may use something
-like:
-
address@hidden
-$ gnutls-cli -p 5556 test.gnutls.org --pskusername jas --pskkey 
9e32cf7786321a828ef7668f09fb35db --priority NORMAL:+PSK:-RSA:-DHE-RSA -d 4711
address@hidden smallexample
-
address@hidden
-* Example client PSK connection::
address@hidden menu
-
address@hidden Example client PSK connection
address@hidden Example client PSK connection
address@hidden PSK client
-
-If your server only supports the PSK ciphersuite, connecting to it
-should be as simple as connecting to the server:
-
address@hidden
-$ ./gnutls-cli -p 5556 localhost
-Resolving 'localhost'...
-Connecting to '127.0.0.1:5556'...
-- PSK client callback. PSK hint 'psk_identity_hint'
-Enter PSK identity: psk_identity
-Enter password: 
-- PSK authentication. PSK hint 'psk_identity_hint'
-- Version: TLS1.1
-- Key Exchange: PSK
-- Cipher: AES-128-CBC
-- MAC: SHA1
-- Compression: NULL
-- Handshake was completed
-
-- Simple Client Mode:
address@hidden smallexample
-
-If the server supports several cipher suites, you may need to force it
-to chose PSK by using a cipher priority parameter such as
address@hidden NORMAL:+PSK:-RSA:-DHE-RSA:-DHE-PSK}.
-
address@hidden Netconf
-Instead of using the Netconf-way to derive the PSK key from a
-password, you can also give the PSK username and key directly on the
-command line:
-
address@hidden
-$ ./gnutls-cli -p 5556 localhost --pskusername psk_identity --pskkey 
88f3824b3e5659f52d00e959bacab954b6540344 
-Resolving 'localhost'...
-Connecting to '127.0.0.1:5556'...
-- PSK authentication. PSK hint 'psk_identity_hint'
-- Version: TLS1.1
-- Key Exchange: PSK
-- Cipher: AES-128-CBC
-- MAC: SHA1
-- Compression: NULL
-- Handshake was completed
-
-- Simple Client Mode:
address@hidden smallexample
-
-By keeping the @code{--pskusername} parameter and removing the
address@hidden parameter, it will query only for the password during
-the handshake.
-
address@hidden Invoking gnutls-cli-debug
address@hidden Invoking gnutls-cli-debug
address@hidden gnutls-cli-debug
-
-This program was created to assist in debugging @acronym{GnuTLS}, but
-it might be useful to extract a @acronym{TLS} server's capabilities.
-It's purpose is to connect onto a @acronym{TLS} server, perform some
-tests and print the server's capabilities. If called with the `-v'
-parameter a more checks will be performed. An example output is:
-
address@hidden
-crystal:/cvs/gnutls/src$ ./gnutls-cli-debug localhost -p 5556
-Resolving 'localhost'...
-Connecting to '127.0.0.1:5556'...
-Checking for TLS 1.1 support... yes
-Checking fallback from TLS 1.1 to... N/A
-Checking for TLS 1.0 support... yes
-Checking for SSL 3.0 support... yes
-Checking for version rollback bug in RSA PMS... no
-Checking for version rollback bug in Client Hello... no
-Checking whether we need to disable TLS 1.0... N/A
-Checking whether the server ignores the RSA PMS version... no
-Checking whether the server can accept Hello Extensions... yes
-Checking whether the server can accept cipher suites not in SSL 3.0 spec... yes
-Checking whether the server can accept a bogus TLS record version in the 
client hello... yes
-Checking for certificate information... N/A
-Checking for trusted CAs... N/A
-Checking whether the server understands TLS closure alerts... yes
-Checking whether the server supports session resumption... yes
-Checking for export-grade ciphersuite support... no
-Checking RSA-export ciphersuite info... N/A
-Checking for anonymous authentication support... no
-Checking anonymous Diffie-Hellman group info... N/A
-Checking for ephemeral Diffie-Hellman support... no
-Checking ephemeral Diffie-Hellman group info... N/A
-Checking for AES cipher support (TLS extension)... yes
-Checking for 3DES cipher support... yes
-Checking for ARCFOUR 128 cipher support... yes
-Checking for ARCFOUR 40 cipher support... no
-Checking for MD5 MAC support... yes
-Checking for SHA1 MAC support... yes
-Checking for ZLIB compression support (TLS extension)... yes
-Checking for LZO compression support (GnuTLS extension)... yes
-Checking for max record size (TLS extension)... yes
-Checking for SRP authentication support (TLS extension)... yes
-Checking for OpenPGP authentication support (TLS extension)... no
address@hidden smallexample
-
address@hidden Invoking gnutls-serv
address@hidden Invoking gnutls-serv
address@hidden gnutls-serv
-
-Simple server program that listens to incoming TLS connections.
-
address@hidden
-GnuTLS test server
-Usage: gnutls-serv [options]
-
-     -d, --debug integer      Enable debugging
-     -g, --generate           Generate Diffie-Hellman Parameters.
-     -p, --port integer       The port to connect to.
-     -q, --quiet              Suppress some messages.
-     --nodb                   Does not use the resume database.
-     --http                   Act as an HTTP Server.
-     --echo                   Act as an Echo Server.
-     --dhparams FILE          DH params file to use.
-     --x509fmtder             Use DER format for certificates
-     --x509cafile FILE        Certificate file to use.
-     --x509crlfile FILE       CRL file to use.
-     --pgpkeyring FILE        PGP Key ring file to use.
-     --pgpkeyfile FILE        PGP Key file to use.
-     --pgpcertfile FILE       PGP Public Key (certificate) file to
-                              use.
-     --pgpsubkey HEX|auto     PGP subkey to use.
-     --x509keyfile FILE       X.509 key file to use.
-     --x509certfile FILE      X.509 Certificate file to use.
-     --x509dsakeyfile FILE    Alternative X.509 key file to use.
-     --x509dsacertfile FILE   Alternative X.509 certificate file to
-                              use.
-     -r, --require-cert       Require a valid certificate.
-     -a, --disable-client-cert
-                              Disable request for a client
-                              certificate.
-     --pskpasswd FILE         PSK password file to use.
-     --pskhint HINT           PSK identity hint to use.
-     --srppasswd FILE         SRP password file to use.
-     --srppasswdconf FILE     SRP password conf file to use.
-     --opaque-prf-input DATA
-                              Use Opaque PRF Input DATA.
-     --ciphers cipher1 cipher2...
-                              Ciphers to enable.
-     --protocols protocol1 protocol2...
-                              Protocols to enable.
-     --comp comp1 comp2...    Compression methods to enable.
-     --macs mac1 mac2...      MACs to enable.
-     --kx kx1 kx2...          Key exchange methods to enable.
-     --ctypes certType1 certType2...
-                              Certificate types to enable.
-     --priority PRIORITY STRING
-                              Priorities string.
-     -l, --list               Print a list of the supported
-                              algorithms  and modes.
-     -h, --help               prints this help
-     -v, --version            prints the program's version number
address@hidden verbatim
-
address@hidden Setting Up a Test HTTPS Server
address@hidden HTTPS server
address@hidden debug server
-
-Running your own TLS server based on GnuTLS can be useful when
-debugging clients and/or GnuTLS itself.  This section describes how to
-use @code{gnutls-serv} as a simple HTTPS server.
-
-The most basic server can be started as:
-
address@hidden
-gnutls-serv --http
address@hidden example
-
-It will only support anonymous ciphersuites, which many TLS clients
-refuse to use.
-
-The next step is to add support for X.509.  First we generate a CA:
-
address@hidden
-certtool --generate-privkey > x509-ca-key.pem
-echo 'cn = GnuTLS test CA' > ca.tmpl
-echo 'ca' >> ca.tmpl
-echo 'cert_signing_key' >> ca.tmpl
-certtool --generate-self-signed --load-privkey x509-ca-key.pem \
-  --template ca.tmpl --outfile x509-ca.pem
-...
address@hidden example
-
-Then generate a server certificate.  Remember to change the dns_name
-value to the name of your server host, or skip that command to avoid
-the field.
-
address@hidden
-certtool --generate-privkey > x509-server-key.pem
-echo 'organization = GnuTLS test server' > server.tmpl
-echo 'cn = test.gnutls.org' >> server.tmpl
-echo 'tls_www_server' >> server.tmpl
-echo 'encryption_key' >> server.tmpl
-echo 'signing_key' >> server.tmpl
-echo 'dns_name = test.gnutls.org' >> server.tmpl
-certtool --generate-certificate --load-privkey x509-server-key.pem \
-  --load-ca-certificate x509-ca.pem --load-ca-privkey x509-ca-key.pem \
-  --template server.tmpl --outfile x509-server.pem
-...
address@hidden example
-
-For use in the client, you may want to generate a client certificate
-as well.
-
address@hidden
-certtool --generate-privkey > x509-client-key.pem
-echo 'cn = GnuTLS test client' > client.tmpl
-echo 'tls_www_client' >> client.tmpl
-echo 'encryption_key' >> client.tmpl
-echo 'signing_key' >> client.tmpl
-certtool --generate-certificate --load-privkey x509-client-key.pem \
-  --load-ca-certificate x509-ca.pem --load-ca-privkey x509-ca-key.pem \
-  --template client.tmpl --outfile x509-client.pem
-...
address@hidden example
-
-To be able to import the client key/certificate into some
-applications, you will need to convert them into a PKCS#12 structure.
-This also encrypts the security sensitive key with a password.
-
address@hidden
-certtool --to-p12 --load-ca-certificate x509-ca.pem --load-privkey 
x509-client-key.pem --load-certificate x509-client.pem --outder --outfile 
x509-client.p12
address@hidden example
-
-For icing, we'll create a proxy certificate for the client too.
-
address@hidden
-certtool --generate-privkey > x509-proxy-key.pem
-echo 'cn = GnuTLS test client proxy' > proxy.tmpl
-certtool --generate-proxy --load-privkey x509-proxy-key.pem \
-  --load-ca-certificate x509-client.pem --load-ca-privkey x509-client-key.pem \
-  --load-certificate x509-client.pem --template proxy.tmpl \
-  --outfile x509-proxy.pem
-...
address@hidden example
-
-Then start the server again:
-
address@hidden
-gnutls-serv --http \
-            --x509cafile x509-ca.pem \
-            --x509keyfile x509-server-key.pem \
-            --x509certfile x509-server.pem
address@hidden example
-
-Try connecting to the server using your web browser.  Note that the
-server listens to port 5556 by default.
-
-While you are at it, to allow connections using DSA, you can also
-create a DSA key and certificate for the server.  These credentials
-will be used in the final example below.
-
address@hidden
-certtool --generate-privkey --dsa > x509-server-key-dsa.pem
-certtool --generate-certificate --load-privkey x509-server-key-dsa.pem \
-  --load-ca-certificate x509-ca.pem --load-ca-privkey x509-ca-key.pem \
-  --template server.tmpl --outfile x509-server-dsa.pem
-...
address@hidden example
-
-The next step is to create OpenPGP credentials for the server.
-
address@hidden
-gpg --gen-key
-...enter whatever details you want, use 'test.gnutls.org' as name...
address@hidden example
-
-Make a note of the OpenPGP key identifier of the newly generated key,
-here it was @code{5D1D14D8}.  You will need to export the key for
-GnuTLS to be able to use it.
-
address@hidden
-gpg -a --export 5D1D14D8 > openpgp-server.txt
-gpg --export 5D1D14D8 > openpgp-server.bin
-gpg --export-secret-keys 5D1D14D8 > openpgp-server-key.bin
-gpg -a --export-secret-keys 5D1D14D8 > openpgp-server-key.txt
address@hidden example
-
-Let's start the server with support for OpenPGP credentials:
-
address@hidden
-gnutls-serv --http \
-            --pgpkeyfile openpgp-server-key.txt \
-            --pgpcertfile openpgp-server.txt
address@hidden example
-
-The next step is to add support for SRP authentication.
-
address@hidden
-srptool --create-conf srp-tpasswd.conf
-srptool --passwd-conf srp-tpasswd.conf --username jas --passwd srp-passwd.txt
-Enter password: [TYPE "foo"]
address@hidden example
-
-Start the server with SRP support:
-
address@hidden
-gnutls-serv --http \
-            --srppasswdconf srp-tpasswd.conf \
-            --srppasswd srp-passwd.txt
address@hidden example
-
-Let's also add support for PSK.
-
address@hidden
-$ psktool --passwd psk-passwd.txt
address@hidden example
-
-Start the server with PSK support:
-
address@hidden
-gnutls-serv --http \
-            --pskpasswd psk-passwd.txt
address@hidden example
-
-Finally, we start the server with all the earlier parameters and you
-get this command:
-
address@hidden
-gnutls-serv --http \
-            --x509cafile x509-ca.pem \
-            --x509keyfile x509-server-key.pem \
-            --x509certfile x509-server.pem \
-            --x509dsakeyfile x509-server-key-dsa.pem \
-            --x509dsacertfile x509-server-dsa.pem \
-            --pgpkeyfile openpgp-server-key.txt \
-            --pgpcertfile openpgp-server.txt \
-            --srppasswdconf srp-tpasswd.conf \
-            --srppasswd srp-passwd.txt \
-            --pskpasswd psk-passwd.txt
address@hidden example
-
address@hidden
-* Example server PSK connection::
address@hidden menu
-
address@hidden Example server PSK connection
address@hidden Example server PSK connection
address@hidden PSK server
-
-To set up a PSK server with @code{gnutls-serv} you need to create PSK
-password file (@pxref{Invoking psktool}).  In the example below, I
-type @code{password} at the prompt.
-
address@hidden
-$ ./psktool -u psk_identity -p psks.txt -n psk_identity_hint
-Enter password:
-Key stored to psks.txt
-$ cat psks.txt
-psk_identity:88f3824b3e5659f52d00e959bacab954b6540344
-$
address@hidden smallexample
-
-After this, start the server pointing to the password file.  We
-disable DHE-PSK.
-
address@hidden
-$ ./gnutls-serv --pskpasswd psks.txt  --pskhint psk_identity_hint --priority 
NORMAL:-DHE-PSK
-Set static Diffie-Hellman parameters, consider --dhparams.
-Echo Server ready. Listening to port '5556'.
address@hidden smallexample
-
-You can now connect to the server using a PSK client (@pxref{Example
-client PSK connection}).
-
address@hidden Invoking psktool
address@hidden Invoking psktool
address@hidden psktool
-
-This is a program to manage @acronym{PSK} username and keys.
-
address@hidden
-PSKtool help
-Usage : psktool [options]
-     -u, --username username
-                              specify username.
-     -p, --passwd FILE        specify a password file.
-     -n, --netconf-hint HINT
-                              derive key from Netconf password, using 
-                              HINT as the psk_identity_hint.
-     -s, --keysize SIZE       specify the key size in bytes.
-     -v, --version            prints the program's version number
-     -h, --help               shows this help text
address@hidden verbatim
-
-Normally the file will generate random keys for the indicate username.
-You may also derive PSK keys from passwords, using the algorithm
-specified in @file{draft-ietf-netconf-tls-02.txt}.  The algorithm
-needs a PSK identity hint, which you specify using
address@hidden  To derive a PSK key from a password with an
-empty PSK identity hint, using @code{--netconf-hint ""}.
-
address@hidden Invoking srptool
address@hidden Invoking srptool
address@hidden
address@hidden srptool
-
-The @file{srptool} is a very simple program that emulates the programs
-in the @emph{Stanford SRP libraries}, see
address@hidden://srp.stanford.edu/}.  It is intended for use in places
-where you don't expect @acronym{SRP} authentication to be the used for
-system users.
-
-Traditionally @emph{libsrp} used two files. One called @code{tpasswd}
-which holds usernames and verifiers, and @code{tpasswd.conf} which
-holds generators and primes.
-
-How to use srptool:
-
address@hidden
-
address@hidden
-To create tpasswd.conf which holds the g and n values for
address@hidden protocol (generator and a large prime), run:
-
address@hidden
-$ srptool --create-conf /etc/tpasswd.conf
address@hidden example
-
address@hidden
-This command will create /etc/tpasswd and will add user 'test' (you
-will also be prompted for a password).  Verifiers are stored by
-default in the way libsrp expects.
-
address@hidden
-$ srptool --passwd /etc/tpasswd \
-    --passwd-conf /etc/tpasswd.conf -u test
address@hidden example
-
address@hidden
-This command will check against a password.  If the password matches
-the one in /etc/tpasswd you will get an ok.
-
address@hidden
-$ srptool --passwd /etc/tpasswd \
-    --passwd-conf /etc/tpasswd.conf --verify -u test
address@hidden example
-
address@hidden itemize
-
address@hidden Function reference
address@hidden Function Reference
address@hidden Function reference
-
address@hidden
-* Core functions::
-* X.509 certificate functions::
-* GnuTLS-extra functions::
-* OpenPGP functions::
-* TLS Inner Application (TLS/IA) functions::
-* Error codes and descriptions::
address@hidden menu
-
address@hidden Core functions
address@hidden Core Functions
-
-The prototypes for the following functions lie in
address@hidden/gnutls.h}.
-
address@hidden gnutls-api.texi
-
address@hidden X.509 certificate functions
address@hidden @acronym{X.509} Certificate Functions
address@hidden:x509api}
address@hidden @acronym{X.509} Functions
-
-The following functions are to be used for @acronym{X.509} certificate 
handling.
-Their prototypes lie in @file{gnutls/x509.h}.
-
address@hidden x509-api.texi
-
address@hidden GnuTLS-extra functions
address@hidden @acronym{GnuTLS-extra} Functions
address@hidden @acronym{GnuTLS-extra} functions
-
-These functions are only available in the GPLv3+ version of the
-library called @code{gnutls-extra}. The prototypes for this library
-lie in @file{gnutls/extra.h}.
-
address@hidden extra-api.texi
-
address@hidden OpenPGP functions
address@hidden @acronym{OpenPGP} Functions
address@hidden @acronym{OpenPGP} functions
address@hidden:openpgpapi}
-
-The following functions are to be used for @acronym{OpenPGP}
-certificate handling.  Their prototypes lie in
address@hidden/openpgp.h}.
-
address@hidden pgp-api.texi
-
address@hidden TLS Inner Application (TLS/IA) functions
address@hidden @acronym{TLS} Inner Application (@acronym{TLS/IA}) Functions
address@hidden @acronym{TLS} Inner Application (@acronym{TLS/IA}) functions
address@hidden Inner Application (@acronym{TLS/IA}) functions
-
-The following functions are used for @acronym{TLS} Inner Application
-(@acronym{TLS/IA}).  Their prototypes lie in @file{gnutls/extra.h}.
-You need to link with @file{libgnutls-extra} to be able to use these
-functions (@pxref{GnuTLS-extra functions}).
-
-The typical control flow in an TLS/IA client (that would not require
-an Application Phase for resumed sessions) would be similar to the
-following:
-
address@hidden
-int client_avp (gnuls_session_t *session, void *ptr,
-                const char *last, size_t lastlen,
-               char **new, size_t *newlen)
address@hidden
-...
address@hidden
-...
-int main ()
address@hidden
-  gnutls_ia_client_credentials_t iacred;
-...
-  gnutls_init (&session, GNUTLS_CLIENT);
-...
-  /* Enable TLS/IA. */
-  gnutls_ia_allocate_client_credentials(&iacred);
-  gnutls_ia_set_client_avp_function(iacred, client_avp);
-  gnutls_credentials_set (session, GNUTLS_CRD_IA, iacred);
-...
-  ret = gnutls_handshake (session);
-  // Error handling...
-...
-  if (gnutls_ia_handshake_p (session))
-    @{
-      ret = gnutls_ia_handshake (session);
-      // Error handling...
-...
address@hidden example
-
-See below for detailed descriptions of all the functions used above.
-
-The function @code{client_avp} would have to be implemented by your
-application.  The function is responsible for handling the AVP data.
-See @code{gnutls_ia_set_client_avp_function} below for more
-information on how that function should be implemented.
-
-The control flow in a typical server is similar to the above, use
address@hidden instead of
address@hidden, and replace the call to the
-client functions with the corresponding server functions.
-
address@hidden ia-api.texi
-
address@hidden Error codes and descriptions
address@hidden Error Codes and Descriptions
address@hidden Codes}
address@hidden Error codes
-
-The error codes used throughout the library are described below.  The
-return code @code{GNUTLS_E_SUCCESS} indicate successful operation, and
-is guaranteed to have the value 0, so you can use it in logical
-expressions.
-
address@hidden error_codes.texi
-
address@hidden All the supported ciphersuites in GnuTLS
address@hidden All the Supported Ciphersuites in @acronym{GnuTLS}
address@hidden
address@hidden Ciphersuites
-
address@hidden algorithms.texi
-
-Some additional information regarding some of the algorithms:
-
address@hidden @code
address@hidden RSA
-RSA is public key cryptosystem designed by Ronald Rivest, Adi Shamir
-and Leonard Adleman.  It can be used with any hash functions.
-
address@hidden DSA
-DSA is the USA's Digital Signature Standard.  It uses only the SHA-1
-hash algorithm.
-
address@hidden MD2
-MD2 is a cryptographic hash algorithm designed by Ron Rivest.  It is
-optimized for 8-bit processors. Outputs 128 bits of data.  There are
-no known weaknesses of this algorithm but since this algorithm is
-rarely used and not really studied it should not be used today.
-
address@hidden MD5
-MD5 is a cryptographic hash algorithm designed by Ron Rivest. Outputs
-128 bits of data.  It is considered to be broken.
-
address@hidden SHA-1
-SHA is a cryptographic hash algorithm designed by NSA. Outputs 160
-bits of data.  It is also considered to be broken, though no practical
-attacks have been found.
-
address@hidden RMD160
-RIPEMD is a cryptographic hash algorithm developed in the framework of
-the EU project RIPE.  Outputs 160 bits of data.
-
address@hidden table
-
address@hidden
address@hidden Guile Bindings
address@hidden
-
address@hidden guile.texi
-
-
address@hidden Internal architecture of GnuTLS
address@hidden Internal Architecture of GnuTLS
address@hidden Internal architecture
-
-This chapter is to give a brief description of the
-way @acronym{GnuTLS} works. The focus is to give an idea
-to potential developers and those who want to know what
-happens inside the black box.
-
address@hidden
-* The TLS Protocol::
-* TLS Handshake Protocol::
-* TLS Authentication Methods::
-* TLS Extension Handling::
-* Certificate Handling::
-* Cryptographic Backend::
address@hidden menu
-
address@hidden The TLS Protocol
address@hidden The TLS Protocol
-The main needs for the TLS protocol to be used are
-shown in the image below.
-
address@hidden,9cm}
-
-This is being accomplished by the following object diagram.
-Note that since @acronym{GnuTLS} is being developed in C
-object are just structures with attributes. The operations listed
-are functions that require the first parameter to be that object.
address@hidden,15cm}
-
address@hidden TLS Handshake Protocol
address@hidden TLS Handshake Protocol
-The @acronym{GnuTLS} handshake protocol is implemented as a state
-machine that waits for input or returns immediately when the non-blocking
-transport layer functions are used. The main idea is shown in the following
-figure.
-
address@hidden,9cm}
-
-Also the way the input is processed varies per ciphersuite. Several 
-implementations of the internal handlers are available and 
address@hidden only multiplexes the input to the appropriate 
-handler. For example a @acronym{PSK} ciphersuite has a different 
-implementation of the @code{process_client_key_exchange} than a
-certificate ciphersuite.
-
address@hidden,12cm}
-
address@hidden TLS Authentication Methods
address@hidden TLS Authentication Methods
-In @acronym{GnuTLS} authentication methods can be implemented quite
-easily.  Since the required changes to add a new authentication method
-affect only the handshake protocol, a simple interface is used. An
-authentication method needs only to implement the functions as seen in
-the figure below.
-
address@hidden,12cm}
-
-The functions that need to be implemented are the ones responsible for
-interpreting the handshake protocol messages. It is common for such
-functions to read data from one or more @code{credentials_t}
address@hidden as the
address@hidden structures} and write data,
-such as certificates, usernames etc. to @code{auth_info_t} structures.
-
-Simple examples of existing authentication methods can be seen in
address@hidden for PSK ciphersuites and @code{auth_srp.c} for SRP
-ciphersuites. After implementing these functions the structure holding
-its pointers has to be registered in @code{gnutls_algorithms.c} in the
address@hidden structure.
-
address@hidden TLS Extension Handling
address@hidden TLS Extension Handling
-As with authentication methods, the TLS extensions handlers can be
-implemented using the following interface.
-
address@hidden,12cm}
-
-Here there are two functions, one for receiving the extension data
-and one for sending. These functions have to check internally whether
-they operate in client or server side. 
-
-A simple example of an extension handler can be seen in
address@hidden After implementing these functions, together with the
-extension number they handle, they have to be registered in
address@hidden in the @code{_gnutls_extensions} structure.
-
address@hidden Adding a New TLS Extension
-
-Adding support for a new TLS extension is done from time to time, and
-the process to do so is not difficult.  Here are the steps you need to
-follow if you wish to do this yourself.  For sake of discussion, let's
-consider adding support for the hypothetical TLS extension
address@hidden
-
address@hidden
-
address@hidden Add @code{configure} option like @code{--enable-foobar} or 
@code{--disable-foobar}.
-
-Which to chose depends on whether you intend to make the extension be
-enabled by default.  Look at existing checks (i.e., SRP, authz) for
-how to model the code.  For example:
-
address@hidden
-AC_MSG_CHECKING([whether to disable foobar support])
-AC_ARG_ENABLE(foobar,
-       AS_HELP_STRING([--disable-foobar],
-               [disable foobar support]),
-       ac_enable_foobar=no)
-if test x$ac_enable_foobar != xno; then
- AC_MSG_RESULT(no)
- AC_DEFINE(ENABLE_FOOBAR, 1, [enable foobar])
-else
- ac_full=0
- AC_MSG_RESULT(yes)
-fi
-AM_CONDITIONAL(ENABLE_FOOBAR, test "$ac_enable_foobar" != "no")
address@hidden example
-
-These lines should go in @code{lib/m4/hooks.m4}.
-
address@hidden Add IANA extension value to @code{extensions_t} in 
@code{gnutls_int.h}.
-
-A good name for the value would be GNUTLS_EXTENSION_FOOBAR.  Check
-with @url{http://www.iana.org/assignments/tls-extensiontype-values}
-for allocated values.  For experiments, you could pick a number but
-remember that some consider it a bad idea to deploy such modified
-version since it will lead to interoperability problems in the future
-when the IANA allocates that number to someone else, or when the
-foobar protocol is allocated another number.
-
address@hidden Add an entry to @code{_gnutls_extensions} in 
@code{gnutls_extensions.c}.
-
-A typical entry would be:
-
address@hidden
-  int ret;
-
-  /* ...
-   */
-
-#if ENABLE_FOOBAR
-  ret = gnutls_ext_register (GNUTLS_EXTENSION_FOOBAR,
-                             "FOOBAR",
-                             GNUTLS_EXT_TLS,
-                             _gnutls_foobar_recv_params,
-                             _gnutls_foobar_send_params);
-  if (ret != GNUTLS_E_SUCCESS)
-    return ret;
-#endif
address@hidden example
-
-The GNUTLS_EXTENSION_FOOBAR is the integer value you added to
address@hidden earlier.  The two functions are new functions that
-you will need to implement, most likely you'll need to add an
address@hidden "ext_foobar.h"} as well.
-
address@hidden Add new files @code{ext_foobar.c} and @code{ext_foobar.h} that 
implements the extension.
-
-The functions you are responsible to add are those mentioned in the
-previous step.  As a starter, you could add this:
-
address@hidden
-int
-_gnutls_foobar_recv_params (gnutls_session_t session,
-                            const opaque * data,
-                            size_t data_size)
address@hidden
-  return 0;
address@hidden
-
-int
-_gnutls_foobar_send_params (gnutls_session_t session,
-                            opaque * data,
-                            size_t _data_size)
address@hidden
-  return 0;
address@hidden
address@hidden example
-
-The @code{_gnutls_foobar_recv_params} function is responsible for
-parsing incoming extension data (both in the client and server).
-
-The @code{_gnutls_foobar_send_params} function is responsible for
-sending extension data (both in the client and server).
-
-If you receive length fields that doesn't match, return
address@hidden  If you receive invalid
-data, return @code{GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER}.  You can use
-other error codes too.  Return 0 on success.
-
-The function typically store some information in the @code{session}
-variable for later usage.  If you need to add new fields there, check
address@hidden in @code{gnutls_int.h} and compare with existing TLS
-extension specific variables.
-
-Recall that both the client and server both send and receives
-parameters, and your code most likely will need to do different things
-depending on which mode it is in.  It may be useful to make this
-distinction explicit in the code.  Thus, for example, a better
-template than above would be:
-
address@hidden
-int
-_gnutls_foobar_recv_params (gnutls_session_t session,
-                            const opaque * data,
-                            size_t data_size)
address@hidden
-  if (session->security_parameters.entity == GNUTLS_CLIENT)
-    return foobar_recv_client (session, data, data_size);
-  else
-    return foobar_recv_server (session, data, data_size);
address@hidden
-
-int
-_gnutls_foobar_send_params (gnutls_session_t session,
-                            opaque * data,
-                            size_t data_size)
address@hidden
-  if (session->security_parameters.entity == GNUTLS_CLIENT)
-    return foobar_send_client (session, data, data_size);
-  else
-    return foobar_send_server (session, data, data_size);
address@hidden
address@hidden example
-
-The functions used would be declared as @code{static} functions, of
-the appropriate prototype, in the same file.
-
-When adding the files, you'll need to add them to @code{Makefile.am}
-as well, for example:
-
address@hidden
-if ENABLE_FOOBAR
-COBJECTS += ext_foobar.c
-HFILES += ext_foobar.h
-endif
address@hidden example
-
address@hidden Add API functions to enable/disable the extension.
-
-Normally the client will have one API to request use of the extension,
-and setting some extension specific data.  The server will have one
-API to let the library know that it is willing to accept the
-extension, often this is implemented through a callback but it doesn't
-have to.
-
-The APIs need to be added to @code{includes/gnutls/gnutls.h} or
address@hidden/gnutls/extra.h} as appropriate.  It is recommended that
-if you don't have a requirement to use the LGPLv2.1+ license for your
-extension, that you place your work under the GPLv3+ license and thus
-in the libgnutls-extra library.
-
-You can implement the API function in the @code{ext_foobar.c} file, or
-if that file ends up becoming rather larger, add a
address@hidden file.
-
-To make the API available in the shared library you need to add the
-symbol in @code{lib/libgnutls.map} or
address@hidden/libgnutls-extra.map} as appropriate, so that the symbol
-is exported properly.
-
-When writing GTK-DOC style documentation for your new APIs, don't
-forget to add @code{Since:} tags to indicate the GnuTLS version the
-API was introduced in.
-
address@hidden enumerate
-
address@hidden Certificate Handling
address@hidden Certificate Handling
-What is provided by the certificate handling functions
-is summarized in the following diagram.
-
address@hidden,12cm}
-
address@hidden Cryptographic Backend
address@hidden Cryptographic Backend
-Several new systems provide hardware assisted cryptographic algorithm
-implementations that offer implementations some orders of magnitude
-faster than the software. For this reason GnuTLS supports by default
-the /dev/crypto device usually found in FreeBSD and OpenBSD system, to
-take advantage of installed hardware. 
-
-In addition it is possible to override parts of the crypto backend or the
-whole. It is possible to override them both at runtime and compile
-time, however here we will discuss the runtime possibility. The API
-available for this functionality is in @code{gnutls/crypto.h} header
-file.
-
address@hidden Override specific algorithms
-When an optimized implementation of a single algorithm is available,
-say a hardware assisted version of @acronym{AES-CBC} then the
-following functions can be used to register those algorithms.
-
address@hidden
-
address@hidden @ref{gnutls_crypto_single_cipher_register2}
-To register a cipher algorithm.
-
address@hidden
-To register a hash (digest) or MAC algorithm.
-
address@hidden itemize
-
-Those registration functions will only replace the specified algorithm
-and leave the rest of subsystem intact.
-
address@hidden Override parts of the backend
-In some systems, such as embedded ones, it might be desirable to
-override big parts of the cryptographic backend, or even all of
-them. For this reason the following functions are provided.
-
address@hidden
-
address@hidden @ref{gnutls_crypto_cipher_register2}
-To override the cryptographic algorithms backend.
-
address@hidden @ref{gnutls_crypto_digest_register2}
-To override the digest algorithms backend.
-
address@hidden @ref{gnutls_crypto_rnd_register2}
-To override the random number generator backend.
-
address@hidden @ref{gnutls_crypto_bigint_register2}
-To override the big number number operations backend.
-
address@hidden @ref{gnutls_crypto_pk_register2}
-To override the public key encryption backend. This is tight to the
-big number operations so either both of them should be updated or care
-must be taken to use the same format.
-
address@hidden itemize
-
-If all of them are used then GnuTLS will no longer use libgcrypt.
-
address@hidden Copying Information
address@hidden Copying Information
-
address@hidden
-* GNU Free Documentation License::   License for copying this manual.
-* GNU LGPL::                     License for copying the core GnuTLS library.
-* GNU GPL::                      License for copying GnuTLS-extra and tools.
address@hidden menu
-
address@hidden GNU Free Documentation License
address@hidden GNU Free Documentation License
-
address@hidden FDL, GNU Free Documentation License
-
address@hidden fdl-1.3.texi
-
address@hidden GNU LGPL
address@hidden GNU Lesser General Public License
address@hidden LGPL, GNU Lesser General Public License
address@hidden License, GNU LGPL
-
address@hidden lgpl-2.1.texi
-
address@hidden GNU GPL
address@hidden GNU General Public License
address@hidden GPL, GNU General Public License
address@hidden License, GNU GPL
-
address@hidden gpl-3.0.texi
-
address@hidden Bibliography
address@hidden Bibliography
-
address@hidden @asis
-
address@hidden @anchor{CBCATT}[CBCATT]
-Bodo Moeller, "Security of CBC Ciphersuites in SSL/TLS: Problems and
-Countermeasures", 2002, available from
address@hidden://www.openssl.org/~bodo/tls-cbc.txt}.
-
address@hidden @anchor{GPGH}[GPGH]
-Mike Ashley, "The GNU Privacy Handbook", 2002, available from
address@hidden://www.gnupg.org/gph/en/manual.pdf}.
-
address@hidden @anchor{GUTPKI}[GUTPKI]
-Peter Gutmann, "Everything you never wanted to know about PKI but were
-forced to find out", Available from
address@hidden://www.cs.auckland.ac.nz/~pgut001/}.
-
address@hidden @anchor{NISTSP80057}[NISTSP80057]
-NIST Special Publication 800-57, "Recommendation for Key Management -
-Part 1: General (Revised)", March 2007, available from
address@hidden://csrc.nist.gov/publications/nistpubs/800-57/sp800-57-Part1-revised2_Mar08-2007.pdf}.
-
address@hidden @anchor{RFC2246}[RFC2246]
-Tim Dierks and Christopher Allen, "The TLS Protocol Version 1.0",
-January 1999, Available from
address@hidden://www.ietf.org/rfc/rfc2246.txt}.
-
address@hidden @anchor{RFC4346}[RFC4346]
-Tim Dierks and Eric Rescorla, "The TLS Protocol Version 1.1", Match
-2006, Available from @url{http://www.ietf.org/rfc/rfc4346.txt}.
-
address@hidden @anchor{RFC2440}[RFC2440]
-Jon Callas, Lutz Donnerhacke, Hal Finney and Rodney Thayer, "OpenPGP
-Message Format", November 1998, Available from
address@hidden://www.ietf.org/rfc/rfc2440.txt}.
-
address@hidden @anchor{RFC4880}[RFC4880]
-Jon Callas, Lutz Donnerhacke, Hal Finney, David Shaw and Rodney
-Thayer, "OpenPGP Message Format", November 2007, Available from
address@hidden://www.ietf.org/rfc/rfc4880.txt}.
-
address@hidden @anchor{RFC4211}[RFC4211]
-J. Schaad, "Internet X.509 Public Key Infrastructure Certificate
-Request Message Format (CRMF)", September 2005, Available from
address@hidden://www.ietf.org/rfc/rfc4211.txt}.
-
address@hidden @anchor{RFC2817}[RFC2817]
-Rohit Khare and Scott Lawrence, "Upgrading to TLS Within HTTP/1.1",
-May 2000, Available from @url{http://www.ietf.org/rfc/rfc2817.txt}
-
address@hidden @anchor{RFC2818}[RFC2818]
-Eric Rescorla, "HTTP Over TLS", May 2000, Available from
address@hidden://www.ietf/rfc/rfc2818.txt}.
-
address@hidden @anchor{RFC2945}[RFC2945]
-Tom Wu, "The SRP Authentication and Key Exchange System", September
-2000, Available from @url{http://www.ietf.org/rfc/rfc2945.txt}.
-
address@hidden @anchor{RFC2986}[RFC2986]
-Magnus Nystrom and Burt Kaliski, "PKCS 10 v1.7: Certification Request
-Syntax Specification", November 2000, Available from
address@hidden://www.ietf.org/rfc/rfc2986.txt}.
-
address@hidden @anchor{PKIX}[PKIX]
-D. Cooper, S. Santesson, S. Farrel, S. Boeyen, R. Housley, W. Polk,
-"Internet X.509 Public Key Infrastructure Certificate and Certificate
-Revocation List (CRL) Profile", May 2008, available from
address@hidden://www.ietf.org/rfc/rfc5280.txt}.
-
address@hidden @anchor{RFC3749}[RFC3749]
-Scott Hollenbeck, "Transport Layer Security Protocol Compression
-Methods", May 2004, available from
address@hidden://www.ietf.org/rfc/rfc3749.txt}.
-
address@hidden @anchor{RFC3820}[RFC3820]
-Steven Tuecke, Von Welch, Doug Engert, Laura Pearlman, and Mary
-Thompson, "Internet X.509 Public Key Infrastructure (PKI) Proxy
-Certificate Profile", June 2004, available from
address@hidden://www.ietf.org/rfc/rfc3820}.
-
address@hidden @anchor{RFC5746}[RFC5746]
-E. Rescorla, M. Ray, S. Dispensa, and N. Oskov, "Transport Layer
-Security (TLS) Renegotiation Indication Extension", February 2010,
-available from @url{http://www.ietf.org/rfc/rfc5746}.
-
address@hidden @anchor{TLSTKT}[TLSTKT]
-Joseph Salowey, Hao Zhou, Pasi Eronen, Hannes Tschofenig, "Transport
-Layer Security (TLS) Session Resumption without Server-Side State",
-January 2008, available from @url{http://www.ietf.org/rfc/rfc5077}.
-
address@hidden @anchor{PKCS12}[PKCS12]
-RSA Laboratories, "PKCS 12 v1.0: Personal Information Exchange
-Syntax", June 1999, Available from @url{http://www.rsa.com}.
-
address@hidden @anchor{RESCORLA}[RESCORLA]
-Eric Rescorla, "SSL and TLS: Designing and Building Secure Systems",
-2001
-
address@hidden @anchor{SELKEY}[SELKEY]
-Arjen Lenstra and Eric Verheul, "Selecting Cryptographic Key Sizes",
-2003, available from @url{http://www.win.tue.nl/~klenstra/key.pdf}.
-
address@hidden @anchor{SSL3}[SSL3]
-Alan Freier, Philip Karlton and Paul Kocher, "The SSL Protocol Version
-3.0", November 1996, Available from
address@hidden://wp.netscape.com/eng/ssl3/draft302.txt}.
-
address@hidden @anchor{STEVENS}[STEVENS]
-Richard Stevens, "UNIX Network Programming, Volume 1", Prentice Hall
-PTR, January 1998
-
address@hidden @anchor{TLSEXT}[TLSEXT]
-Simon Blake-Wilson, Magnus Nystrom, David Hopwood, Jan Mikkelsen and
-Tim Wright, "Transport Layer Security (TLS) Extensions", June 2003,
-Available from @url{http://www.ietf.org/rfc/rfc3546.txt}.
address@hidden cha-gtls-app.texi
 
address@hidden @anchor{TLSPGP}[TLSPGP]
-Nikos Mavrogiannopoulos, "Using OpenPGP keys for TLS authentication",
-April 2004, November 2007. Available from
address@hidden://www.ietf.org/rfc/rfc5081.txt}.
address@hidden cha-programs.texi
 
address@hidden @anchor{TLSSRP}[TLSSRP]
-David Taylor, Trevor Perrin, Tom Wu and Nikos Mavrogiannopoulos,
-"Using SRP for TLS Authentication", November 2007. Available from
address@hidden://www.ietf.org/rfc/rfc5054.txt}.
address@hidden cha-functions.texi
 
address@hidden @anchor{TLSPSK}[TLSPSK]
-Pasi Eronen and Hannes Tschofenig, "Pre-shared key Ciphersuites for
-TLS", December 2005, Available from
address@hidden://www.ietf.org/rfc/rfc4279.txt}.
address@hidden cha-ciphersuites.texi
 
address@hidden @anchor{TOMSRP}[TOMSRP]
-Tom Wu, "The Stanford SRP Authentication Project", Available at
address@hidden://srp.stanford.edu/}.
address@hidden cha-internals.texi
 
address@hidden @anchor{WEGER}[WEGER]
-Arjen Lenstra and Xiaoyun Wang and Benne de Weger, "Colliding X.509
-Certificates", Cryptology ePrint Archive, Report 2005/067, Available
-at @url{http://eprint.iacr.org/}.
address@hidden cha-copying.texi
 
address@hidden table
address@hidden cha-bib.texi
 
 @node Function and Data Index
 @unnumbered Function and Data Index
diff --git a/doc/manpages/Makefile.am b/doc/manpages/Makefile.am
index 6afff0a..49f13fd 100644
--- a/doc/manpages/Makefile.am
+++ b/doc/manpages/Makefile.am
@@ -178,6 +178,7 @@ APIMANS += gnutls_priority_deinit.3
 APIMANS += gnutls_priority_set_direct.3
 APIMANS += gnutls_set_default_priority.3
 APIMANS += gnutls_set_default_export_priority.3
+APIMANS += gnutls_privkey_sign_data.3
 APIMANS += gnutls_psk_free_client_credentials.3
 APIMANS += gnutls_psk_allocate_client_credentials.3
 APIMANS += gnutls_psk_set_client_credentials.3
@@ -273,6 +274,8 @@ APIMANS += gnutls_certificate_set_x509_crl_file.3
 APIMANS += gnutls_certificate_set_x509_simple_pkcs12_file.3
 APIMANS += gnutls_certificate_set_x509_simple_pkcs12_mem.3
 APIMANS += gnutls_certificate_free_crls.3
+APIMANS += gnutls_pkcs11_privkey_sign_data.3
+APIMANS += gnutls_pkcs11_privkey_decrypt_data.3
 APIMANS += gnutls_pem_base64_encode.3
 APIMANS += gnutls_pem_base64_encode_alloc.3
 APIMANS += gnutls_pem_base64_decode.3
@@ -422,8 +425,9 @@ APIMANS += gnutls_x509_privkey_export_rsa_raw.3
 APIMANS += gnutls_x509_privkey_export_dsa_raw.3
 APIMANS += gnutls_x509_privkey_generate.3
 APIMANS += gnutls_x509_privkey_get_key_id.3
-APIMANS += gnutls_x509_privkey_sign_data.3
+APIMANS += gnutls_x509_privkey_sign_data2.3
 APIMANS += gnutls_x509_privkey_sign_hash.3
+APIMANS += gnutls_x509_privkey_sign_data.3
 APIMANS += gnutls_x509_privkey_verify_data.3
 APIMANS += gnutls_x509_privkey_fix.3
 APIMANS += gnutls_x509_privkey_export_pkcs8.3
@@ -523,6 +527,7 @@ APIMANS += gnutls_certificate_set_openpgp_keyring_file.3
 APIMANS += gnutls_certificate_set_openpgp_keyring_mem.3
 APIMANS += gnutls_openpgp_set_recv_key_function.3
 APIMANS += gnutls_openpgp_privkey_sign_hash.3
+APIMANS += gnutls_openpgp_privkey_decrypt_data.3
 APIMANS += gnutls_openpgp_crt_print.3
 APIMANS += gnutls_openpgp_crt_init.3
 APIMANS += gnutls_openpgp_crt_deinit.3
diff --git a/doc/manpages/gnutls-cli.1 b/doc/manpages/gnutls-cli.1
index 9d1208e..3f5dfc8 100644
--- a/doc/manpages/gnutls-cli.1
+++ b/doc/manpages/gnutls-cli.1
@@ -151,13 +151,14 @@ SRP password to use.
 .IP "\-\-srpusername \fINAME\fR"
 SRP username to use.
 .IP "\-\-x509cafile \fIFILE\fR"
-Certificate file to use.
+Certificate file to use. This option accepts PKCS \#11 URLs such as
+pkcs11:token=Root%20CA%20Certificates;serial=1%3AROOTS%3ADEFAULT;model=1%2E0;manufacturer=Gnome%20Keyring
 .IP "\-\-x509certfile \fIFILE\fR"
-X.509 Certificate file to use.
+X.509 Certificate file to use, or a PKCS \#11 URL.
 .IP "\-\-x509fmtder"
 Use DER format for certificates
 .IP "\-\-x509keyfile \fIFILE\fR"
-X.509 key file to use.
+X.509 key file or PKCS \#11 URL to use.
 .IP "\-\-x509crlfile \fIFILE\fR"
 X.509 CRL file to use.
 .IP "\-\-pskusername \fINAME\fR"
diff --git a/doc/pkcs11-vision.dia b/doc/pkcs11-vision.dia
new file mode 100644
index 0000000..c2c7260
Binary files /dev/null and b/doc/pkcs11-vision.dia differ
diff --git a/doc/pkcs11-vision.png b/doc/pkcs11-vision.png
new file mode 100644
index 0000000..15c14f4
Binary files /dev/null and b/doc/pkcs11-vision.png differ
diff --git a/lib/Makefile.am b/lib/Makefile.am
index e90702c..111ba4b 100644
--- a/lib/Makefile.am
+++ b/lib/Makefile.am
@@ -80,9 +80,15 @@ COBJECTS = gnutls_record.c gnutls_compress.c debug.c 
gnutls_cipher.c \
        gnutls_str.c gnutls_state.c gnutls_x509.c ext_cert_type.c       \
        gnutls_rsa_export.c auth_rsa_export.c ext_server_name.c         \
        auth_dh_common.c gnutls_helper.c gnutls_supplemental.c          \
-       crypto.c random.c pk-libgcrypt.c mpi-libgcrypt.c cryptodev.c    \
-       rnd-libgcrypt.c cipher-libgcrypt.c mac-libgcrypt.c ext_signature.c \
-       crypto-api.c ext_safe_renegotiation.c
+       crypto.c random.c cryptodev.c ext_signature.c crypto-api.c \
+       ext_safe_renegotiation.c gnutls_mbuffers.c gnutls_privkey.c pkcs11.c \
+       pkcs11_privkey.c gnutls_pubkey.c pkcs11_write.c
+
+if ENABLE_NETTLE
+SUBDIRS += nettle
+else
+SUBDIRS += gcrypt
+endif
 
 if ENABLE_OPRFI
 COBJECTS += $(OPRFI_COBJECTS)
@@ -105,6 +111,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)   \
@@ -115,7 +126,7 @@ libgnutls_la_LDFLAGS = -no-undefined \
        -version-info $(LT_CURRENT):$(LT_REVISION):$(LT_AGE)
 
 libgnutls_la_LIBADD = gl/liblgnu.la x509/libgnutls_x509.la \
-       $(LTLIBZ) $(LTLIBGCRYPT) $(LTLIBINTL) $(LIBSOCKET)
+       $(LTLIBZ)  $(LTLIBINTL) $(LIBSOCKET)
 
 if ENABLE_OPENPGP
 libgnutls_la_LIBADD += openpgp/libgnutls_openpgp.la
@@ -134,6 +145,16 @@ else
 libgnutls_la_LDFLAGS += $(LTLIBTASN1)
 endif
 
+libgnutls_la_LDFLAGS += $(LTLIBPAKCHOIS)
+
+if ENABLE_NETTLE
+libgnutls_la_LDFLAGS += $(LTLIBNETTLE) -lgmp -lpthread -lhogweed
+libgnutls_la_LIBADD += nettle/libcrypto.la
+else
+libgnutls_la_LDFLAGS += $(LTLIBGCRYPT)
+libgnutls_la_LIBADD += gcrypt/libcrypto.la
+endif
+
 if HAVE_LD_OUTPUT_DEF
 libgnutls_la_LDFLAGS += -Wl,--output-def,libgnutls-$(DLL_VERSION).def
 defexecdir = $(bindir)
@@ -153,7 +174,7 @@ lib_LTLIBRARIES += libgnutlsxx.la
 libgnutlsxx_la_SOURCES = gnutlsxx.cpp libgnutlsxx.map
 
 libgnutlsxx_la_LDFLAGS = -no-undefined \
-       -version-info $(LT_CURRENT):$(LT_REVISION):$(LT_AGE)
+       -version-info $(CXX_LT_CURRENT):$(CXX_LT_REVISION):$(CXX_LT_AGE)
 
 libgnutlsxx_la_LIBADD = libgnutls.la
 
diff --git a/lib/auth_cert.c b/lib/auth_cert.c
index 6ba9394..14344b0 100644
--- a/lib/auth_cert.c
+++ b/lib/auth_cert.c
@@ -45,21 +45,23 @@
 #include <gnutls_state.h>
 #include <gnutls_pk.h>
 #include <gnutls_x509.h>
+#include <gnutls/abstract.h>
 #include "debug.h"
 
 #ifdef ENABLE_OPENPGP
 # include "openpgp/gnutls_openpgp.h"
 
-static gnutls_privkey *alloc_and_load_pgp_key (const gnutls_openpgp_privkey_t
-                                              key);
+static gnutls_privkey_t alloc_and_load_pgp_key (const gnutls_openpgp_privkey_t
+                                              key, int deinit);
 static gnutls_cert *alloc_and_load_pgp_certs (gnutls_openpgp_crt_t cert);
 
 #endif
 
 static gnutls_cert *alloc_and_load_x509_certs (gnutls_x509_crt_t * certs,
                                               unsigned);
-static gnutls_privkey *alloc_and_load_x509_key (gnutls_x509_privkey_t key);
+static gnutls_privkey_t alloc_and_load_x509_key (gnutls_x509_privkey_t key, 
int deinit);
 
+static gnutls_privkey_t alloc_and_load_pkcs11_key ( gnutls_pkcs11_privkey_t 
key, int deinit);
 
 
 /* Copies data from a internal certificate struct (gnutls_cert) to 
@@ -409,21 +411,47 @@ get_issuers (gnutls_session_t session,
   return 0;
 }
 
+static void st_to_st2(gnutls_retr2_st *st2, gnutls_retr_st* st)
+{
+       st2->cert_type = st->type;
+       if (st->type == GNUTLS_CRT_OPENPGP) {
+               st2->key_type = GNUTLS_PRIVKEY_OPENPGP;
+       } else {
+               st2->key_type = GNUTLS_PRIVKEY_X509;
+       }
+       st2->ncerts = st->ncerts;
+       st2->deinit_all = st->deinit_all;
+       
+       switch(st2->cert_type) {
+               case GNUTLS_CRT_OPENPGP:
+                       st2->cert.pgp = st->cert.pgp;
+                       st2->key.pgp = st->key.pgp;
+                       break;
+               case GNUTLS_CRT_X509:
+                       st2->cert.x509 = st->cert.x509;
+                       st2->key.x509 = st->key.x509;
+                       break;
+               default:
+                       return;
+       }
+
+}
+
 /* Calls the client get callback.
  */
 static int
 call_get_cert_callback (gnutls_session_t session,
-                       gnutls_datum_t * issuers_dn,
+                       const gnutls_datum_t * issuers_dn,
                        int issuers_dn_length,
                        gnutls_pk_algorithm_t * pk_algos, int pk_algos_length)
 {
   unsigned i;
   gnutls_cert *local_certs = NULL;
-  gnutls_privkey *local_key = NULL;
-  gnutls_retr_st st;
+  gnutls_privkey_t local_key = NULL;
   int ret = GNUTLS_E_INTERNAL_ERROR;
   gnutls_certificate_type_t type = gnutls_certificate_type_get (session);
   gnutls_certificate_credentials_t cred;
+  gnutls_retr2_st st2;
 
   cred = (gnutls_certificate_credentials_t)
     _gnutls_get_cred (session->key, GNUTLS_CRD_CERTIFICATE, NULL);
@@ -433,29 +461,42 @@ call_get_cert_callback (gnutls_session_t session,
       return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
     }
 
-  memset (&st, 0, sizeof (st));
+  memset (&st2, 0, sizeof (st2));
 
-  if (session->security_parameters.entity == GNUTLS_SERVER)
-    {
-      if (cred->server_get_cert_callback == NULL)
+  if (cred->get_cert_callback)
        {
-         gnutls_assert ();
-         return GNUTLS_E_INTERNAL_ERROR;
+               ret = cred->get_cert_callback( session, issuers_dn, 
issuers_dn_length,
+                                       pk_algos, pk_algos_length, &st2);
+
        }
-      ret = cred->server_get_cert_callback (session, &st);
-    }
   else
-    {                          /* CLIENT */
-      if (cred->client_get_cert_callback == NULL)
-       {
-         gnutls_assert ();
-         return GNUTLS_E_INTERNAL_ERROR;
+    { /* compatibility mode */
+         gnutls_retr_st st;
+         memset (&st, 0, sizeof (st));
+         if (session->security_parameters.entity == GNUTLS_SERVER)
+               {
+                       if (cred->server_get_cert_callback == NULL)
+                               {
+                                 gnutls_assert ();
+                                 return GNUTLS_E_INTERNAL_ERROR;
+                               }
+                       ret = cred->server_get_cert_callback (session, &st);
+                       if (ret >= 0) st_to_st2(&st2, &st);
+               }
+         else
+               {                               /* CLIENT */
+
+                 if (cred->client_get_cert_callback == NULL)
+                       {
+                         gnutls_assert ();
+                         return GNUTLS_E_INTERNAL_ERROR;
+                       }
+                 ret = cred->client_get_cert_callback (session,
+                                               issuers_dn, issuers_dn_length,
+                                               pk_algos, pk_algos_length, &st);
+                 if (ret >= 0) st_to_st2(&st2, &st);
+               }
        }
-      ret =
-       cred->client_get_cert_callback (session,
-                                       issuers_dn, issuers_dn_length,
-                                       pk_algos, pk_algos_length, &st);
-    }
 
   if (ret < 0)
     {
@@ -463,87 +504,119 @@ call_get_cert_callback (gnutls_session_t session,
       return GNUTLS_E_INTERNAL_ERROR;
     }
 
-  if (st.ncerts == 0)
+  if (st2.ncerts == 0)
     return 0;                  /* no certificate was selected */
 
-  if (type != st.type)
+  if (type != st2.cert_type)
     {
       gnutls_assert ();
       ret = GNUTLS_E_INVALID_REQUEST;
       goto cleanup;
     }
 
+
   if (type == GNUTLS_CRT_X509)
     {
-      local_certs = alloc_and_load_x509_certs (st.cert.x509, st.ncerts);
-      if (local_certs != NULL && st.key.x509 != NULL)
-       {
-         local_key = alloc_and_load_x509_key (st.key.x509);
-         if (local_key == NULL)
-           {
-             gnutls_assert ();
-             ret = GNUTLS_E_INTERNAL_ERROR;
-             goto cleanup;
-           }
-       }
-
+      local_certs = alloc_and_load_x509_certs (st2.cert.x509, st2.ncerts);
     }
   else
     {                          /* PGP */
-      if (st.ncerts > 1)
-       {
-         gnutls_assert ();
-         ret = GNUTLS_E_INVALID_REQUEST;
-         goto cleanup;
-       }
-
+      if (st2.ncerts > 1)
+               {
+                 gnutls_assert ();
+                 ret = GNUTLS_E_INVALID_REQUEST;
+                 goto cleanup;
+               }
 #ifdef ENABLE_OPENPGP
-      {
-       local_certs = alloc_and_load_pgp_certs (st.cert.pgp);
-       if (local_certs != NULL && st.key.pgp != NULL)
          {
-           local_key = alloc_and_load_pgp_key (st.key.pgp);
-           if (local_key == NULL)
-             {
-               gnutls_assert ();
-               ret = GNUTLS_E_INTERNAL_ERROR;
-               goto cleanup;
-             }
-         }
+               local_certs = alloc_and_load_pgp_certs (st2.cert.pgp);
       }
+#else
+               ret = GNUTLS_E_UNIMPLEMENTED_FEATURE;
+               goto cleanup;
 #endif
     }
 
+  if (local_certs == NULL) {
+         gnutls_assert();
+         ret = GNUTLS_E_MEMORY_ERROR;
+         goto cleanup;
+  }
+
+  switch(st2.key_type) {
+         case GNUTLS_PRIVKEY_OPENPGP:
+#ifdef ENABLE_OPENPGP
+               if (st2.key.pgp != NULL)
+                 {
+                       local_key = alloc_and_load_pgp_key (st2.key.pgp, 
st2.deinit_all);
+                       if (local_key == NULL)
+                         {
+                               gnutls_assert ();
+                               ret = GNUTLS_E_INTERNAL_ERROR;
+                               goto cleanup;
+                         }
+                 }
+                 break;
+#endif
+         case GNUTLS_PRIVKEY_PKCS11:
+               if (st2.key.pkcs11 != NULL)
+                 {
+                       local_key = alloc_and_load_pkcs11_key (st2.key.pkcs11, 
st2.deinit_all);
+                       if (local_key == NULL)
+                         {
+                               gnutls_assert ();
+                               ret = GNUTLS_E_INTERNAL_ERROR;
+                               goto cleanup;
+                         }
+                 }
+                 break;
+         case GNUTLS_PRIVKEY_X509:
+                 if (st2.key.x509 != NULL)
+                       {
+                         local_key = alloc_and_load_x509_key (st2.key.x509, 
st2.deinit_all);
+                         if (local_key == NULL)
+                               {
+                                 gnutls_assert ();
+                                 ret = GNUTLS_E_INTERNAL_ERROR;
+                                 goto cleanup;
+                               }
+                       }
+                       break;
+       }
+
   _gnutls_selected_certs_set (session, local_certs,
-                             (local_certs != NULL) ? st.ncerts : 0,
+                             (local_certs != NULL) ? st2.ncerts : 0,
                              local_key, 1);
 
   ret = 0;
 
 cleanup:
 
-  if (st.type == GNUTLS_CRT_X509)
+  if (st2.cert_type == GNUTLS_CRT_X509)
     {
-      if (st.deinit_all)
-       {
-         for (i = 0; i < st.ncerts; i++)
-           {
-             gnutls_x509_crt_deinit (st.cert.x509[i]);
-           }
-         gnutls_free (st.cert.x509);
-         gnutls_x509_privkey_deinit (st.key.x509);
-       }
+      if (st2.deinit_all)
+               {
+                 for (i = 0; i < st2.ncerts; i++)
+                       {
+                         gnutls_x509_crt_deinit (st2.cert.x509[i]);
+                       }
+               }
     }
   else
     {
 #ifdef ENABLE_OPENPGP
-      if (st.deinit_all)
-       {
-         gnutls_openpgp_crt_deinit (st.cert.pgp);
-         gnutls_openpgp_privkey_deinit (st.key.pgp);
-       }
+       if (st2.deinit_all)
+               {
+                 gnutls_openpgp_crt_deinit (st2.cert.pgp);
+               }
 #endif
     }
+    
+  if (ret < 0)
+    {
+      if (local_key != NULL)
+        gnutls_privkey_deinit(local_key);
+    }
 
   return ret;
 }
@@ -576,7 +649,7 @@ _select_client_cert (gnutls_session_t session,
       return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
     }
 
-  if (cred->client_get_cert_callback != NULL)
+  if (cred->client_get_cert_callback != NULL || cred->get_cert_callback != 
NULL)
     {
 
       /* use a callback to get certificate 
@@ -646,7 +719,7 @@ _select_client_cert (gnutls_session_t session,
          _gnutls_selected_certs_set (session,
                                      &cred->cert_list[indx][0],
                                      cred->cert_list_length[indx],
-                                     &cred->pkey[indx], 0);
+                                     cred->pkey[indx], 0);
        }
       else
        {
@@ -671,7 +744,7 @@ _gnutls_gen_x509_crt (gnutls_session_t session, opaque ** 
data)
   int ret, i;
   opaque *pdata;
   gnutls_cert *apr_cert_list;
-  gnutls_privkey *apr_pkey;
+  gnutls_privkey_t apr_pkey;
   int apr_cert_list_length;
 
   /* find the appropriate certificate 
@@ -730,7 +803,7 @@ _gnutls_gen_openpgp_certificate (gnutls_session_t session, 
opaque ** data)
   int ret;
   opaque *pdata;
   gnutls_cert *apr_cert_list;
-  gnutls_privkey *apr_pkey;
+  gnutls_privkey_t apr_pkey;
   int apr_cert_list_length;
 
   /* find the appropriate certificate */
@@ -804,7 +877,7 @@ _gnutls_gen_openpgp_certificate_fpr (gnutls_session_t 
session, opaque ** data)
   size_t fpr_size;
   opaque *pdata;
   gnutls_cert *apr_cert_list;
-  gnutls_privkey *apr_pkey;
+  gnutls_privkey_t apr_pkey;
   int apr_cert_list_length;
 
   /* find the appropriate certificate */
@@ -1443,7 +1516,7 @@ _gnutls_gen_cert_client_cert_vrfy (gnutls_session_t 
session, opaque ** data)
 {
   int ret;
   gnutls_cert *apr_cert_list;
-  gnutls_privkey *apr_pkey;
+  gnutls_privkey_t apr_pkey;
   int apr_cert_list_length, size;
   gnutls_datum_t signature;
   int total_data;
@@ -1592,6 +1665,7 @@ _gnutls_proc_cert_client_cert_vrfy (gnutls_session_t 
session,
   return 0;
 }
 
+
 #define CERTTYPE_SIZE 3
 int
 _gnutls_gen_cert_server_cert_req (gnutls_session_t session, opaque ** data)
@@ -1684,7 +1758,7 @@ int
 _gnutls_get_selected_cert (gnutls_session_t session,
                           gnutls_cert ** apr_cert_list,
                           int *apr_cert_list_length,
-                          gnutls_privkey ** apr_pkey)
+                          gnutls_privkey_t * apr_pkey)
 {
   if (session->security_parameters.entity == GNUTLS_SERVER)
     {
@@ -1763,26 +1837,27 @@ alloc_and_load_x509_certs (gnutls_x509_crt_t * certs, 
unsigned ncerts)
 /* converts the given x509 key to gnutls_privkey* and allocates
  * space for it.
  */
-static gnutls_privkey *
-alloc_and_load_x509_key (gnutls_x509_privkey_t key)
+static gnutls_privkey_t
+alloc_and_load_x509_key (gnutls_x509_privkey_t key, int deinit)
 {
-  gnutls_privkey *local_key;
+  gnutls_privkey_t local_key;
   int ret = 0;
 
   if (key == NULL)
     return NULL;
 
-  local_key = gnutls_malloc (sizeof (gnutls_privkey));
-  if (local_key == NULL)
+  ret = gnutls_privkey_init(&local_key);
+  if (ret < 0) 
     {
       gnutls_assert ();
       return NULL;
     }
 
-  ret = _gnutls_x509_privkey_to_gkey (local_key, key);
+  ret = gnutls_privkey_import_x509 (local_key, key, 
deinit?GNUTLS_PRIVKEY_IMPORT_AUTO_RELEASE:0);
   if (ret < 0)
     {
       gnutls_assert ();
+      gnutls_privkey_deinit(local_key);
       return NULL;
     }
 
@@ -1837,26 +1912,27 @@ alloc_and_load_pgp_certs (gnutls_openpgp_crt_t cert)
 /* converts the given raw key to gnutls_privkey* and allocates
  * space for it.
  */
-static gnutls_privkey *
-alloc_and_load_pgp_key (const gnutls_openpgp_privkey_t key)
+static gnutls_privkey_t
+alloc_and_load_pgp_key ( gnutls_openpgp_privkey_t key, int deinit)
 {
-  gnutls_privkey *local_key;
+  gnutls_privkey_t local_key;
   int ret = 0;
 
   if (key == NULL)
     return NULL;
 
-  local_key = gnutls_malloc (sizeof (gnutls_privkey));
-  if (local_key == NULL)
+  ret = gnutls_privkey_init(&local_key);
+  if (ret < 0)
     {
       gnutls_assert ();
       return NULL;
     }
 
-  ret = _gnutls_openpgp_privkey_to_gkey (local_key, key);
+  ret = gnutls_privkey_import_openpgp (local_key, key, 
deinit?GNUTLS_PRIVKEY_IMPORT_AUTO_RELEASE:0);
   if (ret < 0)
     {
       gnutls_assert ();
+      gnutls_privkey_deinit(local_key);
       return NULL;
     }
 
@@ -1864,6 +1940,36 @@ alloc_and_load_pgp_key (const gnutls_openpgp_privkey_t 
key)
 }
 #endif
 
+/* converts the given raw key to gnutls_privkey* and allocates
+ * space for it.
+ */
+static gnutls_privkey_t
+alloc_and_load_pkcs11_key ( gnutls_pkcs11_privkey_t key, int deinit)
+{
+  gnutls_privkey_t local_key;
+  int ret = 0;
+
+  if (key == NULL)
+    return NULL;
+
+  ret = gnutls_privkey_init(&local_key);
+  if (ret < 0)
+    {
+      gnutls_assert ();
+      return NULL;
+    }
+
+  ret = gnutls_privkey_import_pkcs11 (local_key, key, 
deinit?GNUTLS_PRIVKEY_IMPORT_AUTO_RELEASE:0);
+  if (ret < 0)
+    {
+      gnutls_assert ();
+      gnutls_privkey_deinit(local_key);
+      return NULL;
+    }
+
+  return local_key;
+}
+
 void
 _gnutls_selected_certs_deinit (gnutls_session_t session)
 {
@@ -1879,12 +1985,7 @@ _gnutls_selected_certs_deinit (gnutls_session_t session)
       session->internals.selected_cert_list = NULL;
       session->internals.selected_cert_list_length = 0;
 
-      _gnutls_gkey_deinit (session->internals.selected_key);
-      if (session->internals.selected_key)
-       {
-         gnutls_free (session->internals.selected_key);
-         session->internals.selected_key = NULL;
-       }
+      session->internals.selected_key = NULL;
     }
 
   return;
@@ -1893,7 +1994,7 @@ _gnutls_selected_certs_deinit (gnutls_session_t session)
 void
 _gnutls_selected_certs_set (gnutls_session_t session,
                            gnutls_cert * certs, int ncerts,
-                           gnutls_privkey * key, int need_free)
+                           gnutls_privkey_t key, int need_free)
 {
   _gnutls_selected_certs_deinit (session);
 
@@ -1978,7 +2079,7 @@ _gnutls_server_select_cert (gnutls_session_t session,
       _gnutls_selected_certs_set (session,
                                  &cred->cert_list[idx][0],
                                  cred->cert_list_length[idx],
-                                 &cred->pkey[idx], 0);
+                                 cred->pkey[idx], 0);
     }
   else
     /* Certificate does not support REQUESTED_ALGO.  */
diff --git a/lib/auth_cert.h b/lib/auth_cert.h
index cdc91c0..1c1336d 100644
--- a/lib/auth_cert.h
+++ b/lib/auth_cert.h
@@ -30,6 +30,8 @@
 # include "auth_dh_common.h"
 # include "x509/x509_int.h"
 # include "openpgp/openpgp_int.h"
+# include <gnutls/abstract.h>
+# include <gnutls/compat.h>
 
 /* This structure may be complex, but it's the only way to
  * support a server that has multiple certificates
@@ -57,7 +59,7 @@ typedef struct gnutls_certificate_credentials_st
                                 * This is the same with the number of pkeys.
                                 */
 
-  gnutls_privkey *pkey;
+  gnutls_privkey_t *pkey;
   /* private keys. It contains ncerts private
    * keys. pkey[i] corresponds to certificate in
    * cert_list[i][0].
@@ -91,9 +93,11 @@ typedef struct gnutls_certificate_credentials_st
    */
   gnutls_datum_t x509_rdn_sequence;
 
-  gnutls_certificate_client_retrieve_function *client_get_cert_callback;
-  gnutls_certificate_server_retrieve_function *server_get_cert_callback;
+  gnutls_certificate_client_retrieve_function *client_get_cert_callback; /* 
deprecated */
+  gnutls_certificate_server_retrieve_function *server_get_cert_callback; /* 
deprecated */
   gnutls_certificate_verify_function *verify_callback;
+
+  gnutls_certificate_retrieve_function *get_cert_callback;
 } certificate_credentials_st;
 
 typedef struct rsa_info_st
@@ -141,14 +145,14 @@ int _gnutls_proc_cert_server_certificate 
(gnutls_session_t, opaque *, size_t);
 int _gnutls_get_selected_cert (gnutls_session_t session,
                               gnutls_cert ** apr_cert_list,
                               int *apr_cert_list_length,
-                              gnutls_privkey ** apr_pkey);
+                              gnutls_privkey_t * apr_pkey);
 
 int _gnutls_server_select_cert (struct gnutls_session_int *,
                                gnutls_pk_algorithm_t);
 void _gnutls_selected_certs_deinit (gnutls_session_t session);
 void _gnutls_selected_certs_set (gnutls_session_t session,
                                 gnutls_cert * certs, int ncerts,
-                                gnutls_privkey * key, int need_free);
+                                gnutls_privkey_t key, int need_free);
 
 #define _gnutls_proc_cert_client_certificate 
_gnutls_proc_cert_server_certificate
 
@@ -163,4 +167,7 @@ int _gnutls_get_auth_info_gcert (gnutls_cert * gcert,
                                 cert_auth_info_t info,
                                 int flags /* OR of ConvFlags */ );
 
+int certificate_credential_append_crt_list( gnutls_certificate_credentials_t 
res, gnutls_cert *crt, int nr);
+int certificate_credentials_append_pkey( gnutls_certificate_credentials_t res, 
gnutls_privkey_t pkey);
+
 #endif
diff --git a/lib/auth_dh_common.c b/lib/auth_dh_common.c
index c1c62d8..bee2595 100644
--- a/lib/auth_dh_common.c
+++ b/lib/auth_dh_common.c
@@ -95,7 +95,7 @@ _gnutls_proc_dh_common_client_kx (gnutls_session_t session,
     {
       ret = _gnutls_mpi_dprint (session->key->KEY, &session->key->key);
     }
-  else                         /* In DHE_PSK the key is set differently */
+  else /* In DHE_PSK the key is set differently */
     {
       gnutls_datum_t tmp_dh_key;
       ret = _gnutls_mpi_dprint (session->key->KEY, &tmp_dh_key);
@@ -176,7 +176,7 @@ _gnutls_gen_dh_common_client_kx (gnutls_session_t session, 
opaque ** data)
     {
       ret = _gnutls_mpi_dprint (session->key->KEY, &session->key->key);
     }
-  else                         /* In DHE_PSK the key is set differently */
+  else /* In DHE_PSK the key is set differently */
     {
       gnutls_datum_t tmp_dh_key;
       ret = _gnutls_mpi_dprint (session->key->KEY, &tmp_dh_key);
@@ -363,7 +363,12 @@ _gnutls_dh_common_print_server_kx (gnutls_session_t 
session,
 
   _gnutls_write_uint16 (n_X, &pdata[pos]);
 
-  ret = data_size;
+  /* do not use data_size. _gnutls_mpi_print() might
+   * have been pessimist and might have returned initially
+   * more data */
+  ret = n_g + n_p + n_X + 6;
+  if (psk != 0)
+    ret += 2;
 
   return ret;
 }
diff --git a/lib/auth_dhe.c b/lib/auth_dhe.c
index 224adfb..0a3c286 100644
--- a/lib/auth_dhe.c
+++ b/lib/auth_dhe.c
@@ -87,7 +87,7 @@ gen_dhe_server_kx (gnutls_session_t session, opaque ** data)
   const bigint_t *mpis;
   int ret = 0, data_size;
   gnutls_cert *apr_cert_list;
-  gnutls_privkey *apr_pkey;
+  gnutls_privkey_t apr_pkey;
   int apr_cert_list_length;
   gnutls_datum_t signature, ddata;
   gnutls_certificate_credentials_t cred;
diff --git a/lib/auth_rsa.c b/lib/auth_rsa.c
index 7d22a91..2618039 100644
--- a/lib/auth_rsa.c
+++ b/lib/auth_rsa.c
@@ -44,7 +44,7 @@
 #include <gnutls_mpi.h>
 
 int _gnutls_gen_rsa_client_kx (gnutls_session_t, opaque **);
-int _gnutls_proc_rsa_client_kx (gnutls_session_t, opaque *, size_t);
+static int proc_rsa_client_kx (gnutls_session_t, opaque *, size_t);
 
 const mod_auth_st rsa_auth_struct = {
   "RSA",
@@ -58,7 +58,7 @@ const mod_auth_st rsa_auth_struct = {
   _gnutls_proc_cert_server_certificate,
   _gnutls_proc_cert_client_certificate,
   NULL,                                /* proc server kx */
-  _gnutls_proc_rsa_client_kx,  /* proc client kx */
+  proc_rsa_client_kx,  /* proc client kx */
   _gnutls_proc_cert_client_cert_vrfy,  /* proc client cert vrfy */
   _gnutls_proc_cert_cert_req   /* proc server cert request */
 };
@@ -144,76 +144,13 @@ _gnutls_get_public_rsa_params (gnutls_session_t session,
   return 0;
 }
 
-/* This function reads the RSA parameters from the private key
- */
 static int
-_gnutls_get_private_rsa_params (gnutls_session_t session,
-                               bigint_t ** params, int *params_size)
-{
-  int bits;
-  gnutls_certificate_credentials_t cred;
-  gnutls_rsa_params_t rsa_params;
-
-  cred = (gnutls_certificate_credentials_t)
-    _gnutls_get_cred (session->key, GNUTLS_CRD_CERTIFICATE, NULL);
-  if (cred == NULL)
-    {
-      gnutls_assert ();
-      return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
-    }
-
-  if (session->internals.selected_cert_list == NULL)
-    {
-      gnutls_assert ();
-      return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
-    }
-
-  bits =
-    _gnutls_mpi_get_nbits (session->internals.
-                          selected_cert_list[0].params[0]);
-
-  if (_gnutls_cipher_suite_get_kx_algo
-      (&session->security_parameters.current_cipher_suite)
-      == GNUTLS_KX_RSA_EXPORT && bits > 512)
-    {
-
-      rsa_params =
-       _gnutls_certificate_get_rsa_params (cred->rsa_params,
-                                           cred->params_func, session);
-      /* EXPORT case: */
-      if (rsa_params == NULL)
-       {
-         gnutls_assert ();
-         return GNUTLS_E_NO_TEMPORARY_RSA_PARAMS;
-       }
-
-      /* In the export case, we do use temporary RSA params
-       * of 512 bits size. The params in the certificate are
-       * used to sign this temporary stuff.
-       */
-      *params_size = RSA_PRIVATE_PARAMS;
-      *params = rsa_params->params;
-
-      return 0;
-    }
-
-  /* non export cipher suites. */
-
-  *params_size = session->internals.selected_key->params_size;
-  *params = session->internals.selected_key->params;
-
-  return 0;
-}
-
-int
-_gnutls_proc_rsa_client_kx (gnutls_session_t session, opaque * data,
+proc_rsa_client_kx (gnutls_session_t session, opaque * data,
                            size_t _data_size)
 {
   gnutls_datum_t plaintext;
   gnutls_datum_t ciphertext;
   int ret, dsize;
-  bigint_t *params;
-  int params_len;
   int randomize_key = 0;
   ssize_t data_size = _data_size;
 
@@ -240,14 +177,7 @@ _gnutls_proc_rsa_client_kx (gnutls_session_t session, 
opaque * data,
       ciphertext.size = dsize;
     }
 
-  ret = _gnutls_get_private_rsa_params (session, &params, &params_len);
-  if (ret < 0)
-    {
-      gnutls_assert ();
-      return ret;
-    }
-
-  ret = _gnutls_pkcs1_rsa_decrypt (&plaintext, &ciphertext, params, 
params_len, 2);    /* btype==2 */
+  ret = gnutls_privkey_decrypt_data (session->internals.selected_key, 0, 
&ciphertext, &plaintext);
 
   if (ret < 0 || plaintext.size != GNUTLS_MASTER_SIZE)
     {
diff --git a/lib/auth_rsa_export.c b/lib/auth_rsa_export.c
index ba61db6..fc738b7 100644
--- a/lib/auth_rsa_export.c
+++ b/lib/auth_rsa_export.c
@@ -42,11 +42,13 @@
 #include <gnutls_x509.h>
 #include <gnutls_rsa_export.h>
 #include <gnutls_state.h>
+#include <random.h>
 
 int _gnutls_gen_rsa_client_kx (gnutls_session_t, opaque **);
-int _gnutls_proc_rsa_client_kx (gnutls_session_t, opaque *, size_t);
 static int gen_rsa_export_server_kx (gnutls_session_t, opaque **);
 static int proc_rsa_export_server_kx (gnutls_session_t, opaque *, size_t);
+static int proc_rsa_export_client_kx (gnutls_session_t session, opaque * data,
+                           size_t _data_size);
 
 const mod_auth_st rsa_export_auth_struct = {
   "RSA EXPORT",
@@ -60,11 +62,176 @@ const mod_auth_st rsa_export_auth_struct = {
   _gnutls_proc_cert_server_certificate,
   _gnutls_proc_cert_client_certificate,
   proc_rsa_export_server_kx,
-  _gnutls_proc_rsa_client_kx,  /* proc client kx */
+  proc_rsa_export_client_kx,   /* proc client kx */
   _gnutls_proc_cert_client_cert_vrfy,  /* proc client cert vrfy */
   _gnutls_proc_cert_cert_req   /* proc server cert request */
 };
 
+/* This function reads the RSA parameters from the private key
+ */
+static int
+_gnutls_get_private_rsa_params (gnutls_session_t session,
+                               bigint_t ** params, int *params_size)
+{
+  int bits;
+  gnutls_certificate_credentials_t cred;
+  gnutls_rsa_params_t rsa_params;
+
+  cred = (gnutls_certificate_credentials_t)
+    _gnutls_get_cred (session->key, GNUTLS_CRD_CERTIFICATE, NULL);
+  if (cred == NULL)
+    {
+      gnutls_assert ();
+      return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
+    }
+
+  if (session->internals.selected_cert_list == NULL)
+    {
+      gnutls_assert ();
+      return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
+    }
+
+  bits =
+    _gnutls_mpi_get_nbits (session->internals.
+                          selected_cert_list[0].params[0]);
+
+  if (_gnutls_cipher_suite_get_kx_algo
+      (&session->security_parameters.current_cipher_suite)
+      != GNUTLS_KX_RSA_EXPORT || bits < 512)
+    {
+      gnutls_assert();
+      return GNUTLS_E_INVALID_REQUEST;
+    }
+
+  rsa_params =
+      _gnutls_certificate_get_rsa_params (cred->rsa_params,
+                                           cred->params_func, session);
+  /* EXPORT case: */
+  if (rsa_params == NULL)
+    {
+         gnutls_assert ();
+         return GNUTLS_E_NO_TEMPORARY_RSA_PARAMS;
+    }
+
+  /* In the export case, we do use temporary RSA params
+   * of 512 bits size. The params in the certificate are
+   * used to sign this temporary stuff.
+   */
+  *params_size = RSA_PRIVATE_PARAMS;
+  *params = rsa_params->params;
+
+  return 0;
+}
+
+int proc_rsa_export_client_kx (gnutls_session_t session, opaque * data,
+                           size_t _data_size)
+{
+  gnutls_datum_t plaintext;
+  gnutls_datum_t ciphertext;
+  int ret, dsize;
+  bigint_t *params;
+  int params_len;
+  int randomize_key = 0;
+  ssize_t data_size = _data_size;
+
+  if (gnutls_protocol_get_version (session) == GNUTLS_SSL3)
+    {
+      /* SSL 3.0 
+       */
+      ciphertext.data = data;
+      ciphertext.size = data_size;
+    }
+  else
+    {
+      /* TLS 1.0
+       */
+      DECR_LEN (data_size, 2);
+      ciphertext.data = &data[2];
+      dsize = _gnutls_read_uint16 (data);
+
+      if (dsize != data_size)
+       {
+         gnutls_assert ();
+         return GNUTLS_E_UNEXPECTED_PACKET_LENGTH;
+       }
+      ciphertext.size = dsize;
+    }
+
+  ret = _gnutls_get_private_rsa_params (session, &params, &params_len);
+  if (ret < 0)
+    {
+      gnutls_assert ();
+      return ret;
+    }
+
+  ret = _gnutls_pkcs1_rsa_decrypt (&plaintext, &ciphertext, params, 
params_len, 2);    /* btype==2 */
+
+  if (ret < 0 || plaintext.size != GNUTLS_MASTER_SIZE)
+    {
+      /* In case decryption fails then don't inform
+       * the peer. Just use a random key. (in order to avoid
+       * attack against pkcs-1 formating).
+       */
+      gnutls_assert ();
+      _gnutls_x509_log ("auth_rsa: Possible PKCS #1 format attack\n");
+      randomize_key = 1;
+    }
+  else
+    {
+      /* If the secret was properly formatted, then
+       * check the version number.
+       */
+      if (_gnutls_get_adv_version_major (session) != plaintext.data[0]
+         || _gnutls_get_adv_version_minor (session) != plaintext.data[1])
+       {
+         /* No error is returned here, if the version number check
+          * fails. We proceed normally.
+          * That is to defend against the attack described in the paper
+          * "Attacking RSA-based sessions in SSL/TLS" by Vlastimil Klima,
+          * Ondej Pokorny and Tomas Rosa.
+          */
+         gnutls_assert ();
+         _gnutls_x509_log
+           ("auth_rsa: Possible PKCS #1 version check format attack\n");
+       }
+    }
+
+  if (randomize_key != 0)
+    {
+      session->key->key.size = GNUTLS_MASTER_SIZE;
+      session->key->key.data = gnutls_malloc (session->key->key.size);
+      if (session->key->key.data == NULL)
+       {
+         gnutls_assert ();
+         return GNUTLS_E_MEMORY_ERROR;
+       }
+
+      /* we do not need strong random numbers here.
+       */
+      ret = _gnutls_rnd (GNUTLS_RND_NONCE, session->key->key.data,
+                        session->key->key.size);
+      if (ret < 0)
+       {
+         gnutls_assert ();
+         return ret;
+       }
+
+    }
+  else
+    {
+      session->key->key.data = plaintext.data;
+      session->key->key.size = plaintext.size;
+    }
+
+  /* This is here to avoid the version check attack
+   * discussed above.
+   */
+  session->key->key.data[0] = _gnutls_get_adv_version_major (session);
+  session->key->key.data[1] = _gnutls_get_adv_version_minor (session);
+
+  return 0;
+}
+
 static int
 gen_rsa_export_server_kx (gnutls_session_t session, opaque ** data)
 {
@@ -74,11 +241,12 @@ gen_rsa_export_server_kx (gnutls_session_t session, opaque 
** data)
   uint8_t *data_e, *data_m;
   int ret = 0, data_size;
   gnutls_cert *apr_cert_list;
-  gnutls_privkey *apr_pkey;
+  gnutls_privkey_t apr_pkey;
   int apr_cert_list_length;
   gnutls_datum_t signature, ddata;
   gnutls_certificate_credentials_t cred;
   gnutls_sign_algorithm_t sign_algo;
+  unsigned int bits = 0;
 
   cred = (gnutls_certificate_credentials_t)
     _gnutls_get_cred (session->key, GNUTLS_CRD_CERTIFICATE, NULL);
@@ -100,7 +268,8 @@ gen_rsa_export_server_kx (gnutls_session_t session, opaque 
** data)
   /* abort sending this message if we have a certificate
    * of 512 bits or less.
    */
-  if (apr_pkey && _gnutls_mpi_get_nbits (apr_pkey->params[0]) <= 512)
+  gnutls_privkey_get_pk_algorithm(apr_pkey, &bits);
+  if (apr_pkey && bits <= 512)
     {
       gnutls_assert ();
       return GNUTLS_E_INT_RET_0;
diff --git a/lib/auth_srp.c b/lib/auth_srp.c
index d6c401b..8ab237c 100644
--- a/lib/auth_srp.c
+++ b/lib/auth_srp.c
@@ -196,7 +196,7 @@ _gnutls_gen_srp_server_kx (gnutls_session_t session, opaque 
** data)
       return GNUTLS_E_MEMORY_ERROR;
     }
 
-  if (_gnutls_mpi_print (B, NULL, &n_b) != 0)
+  if (_gnutls_mpi_print (B, NULL, &n_b) != GNUTLS_E_SHORT_MEMORY_BUFFER)
     {
       gnutls_assert ();
       return GNUTLS_E_MPI_PRINT_FAILED;
@@ -247,7 +247,7 @@ _gnutls_gen_srp_server_kx (gnutls_session_t session, opaque 
** data)
   _gnutls_write_uint16 (n_b, data_b);
 
   _gnutls_hard_log ("INT: SRP B[%d]: %s\n", (int) n_b,
-                   _gnutls_bin2hex (&data_b[2], n_b, buf, sizeof (buf)));
+                   _gnutls_bin2hex (&data_b[2], n_b, buf, sizeof (buf), NULL));
 
   _gnutls_srp_entry_free (pwd_entry);
 
@@ -344,7 +344,7 @@ _gnutls_gen_srp_client_kx (gnutls_session_t session, opaque 
** data)
       return ret;
     }
 
-  if (_gnutls_mpi_print (A, NULL, &n_a) != 0)
+  if (_gnutls_mpi_print (A, NULL, &n_a) != GNUTLS_E_SHORT_MEMORY_BUFFER)
     {
       gnutls_assert ();
       return GNUTLS_E_MPI_PRINT_FAILED;
@@ -366,7 +366,7 @@ _gnutls_gen_srp_client_kx (gnutls_session_t session, opaque 
** data)
     }
 
   _gnutls_hard_log ("INT: SRP A[%d]: %s\n", (int) n_a,
-                   _gnutls_bin2hex (&data_a[2], n_a, buf, sizeof (buf)));
+                   _gnutls_bin2hex (&data_a[2], n_a, buf, sizeof (buf), NULL));
 
   _gnutls_mpi_release (&A);
 
diff --git a/lib/auth_srp_rsa.c b/lib/auth_srp_rsa.c
index caf84a6..3967c57 100644
--- a/lib/auth_srp_rsa.c
+++ b/lib/auth_srp_rsa.c
@@ -86,7 +86,7 @@ gen_srp_cert_server_kx (gnutls_session_t session, opaque ** 
data)
   gnutls_datum_t signature, ddata;
   gnutls_certificate_credentials_t cred;
   gnutls_cert *apr_cert_list;
-  gnutls_privkey *apr_pkey;
+  gnutls_privkey_t apr_pkey;
   int apr_cert_list_length;
   gnutls_sign_algorithm_t sign_algo;
 
diff --git a/lib/build-aux/config.rpath b/lib/build-aux/config.rpath
index 17298f2..c547c68 100755
--- a/lib/build-aux/config.rpath
+++ b/lib/build-aux/config.rpath
@@ -2,7 +2,7 @@
 # Output a system dependent set of variables, describing how to set the
 # run time search path of shared libraries in an executable.
 #
-#   Copyright 1996-2010 Free Software Foundation, Inc.
+#   Copyright 1996-2007 Free Software Foundation, Inc.
 #   Taken from GNU libtool, 2001
 #   Originally by Gordon Matzigkeit <address@hidden>, 1996
 #
@@ -47,7 +47,7 @@ for cc_temp in $CC""; do
 done
 cc_basename=`echo "$cc_temp" | sed -e 's%^.*/%%'`
 
-# Code taken from libtool.m4's _LT_COMPILER_PIC.
+# Code taken from libtool.m4's AC_LIBTOOL_PROG_COMPILER_PIC.
 
 wl=
 if test "$GCC" = yes; then
@@ -64,7 +64,7 @@ else
           ;;
       esac
       ;;
-    mingw* | cygwin* | pw32* | os2* | cegcc*)
+    mingw* | cygwin* | pw32* | os2*)
       ;;
     hpux9* | hpux10* | hpux11*)
       wl='-Wl,'
@@ -76,13 +76,7 @@ else
       ;;
     linux* | k*bsd*-gnu)
       case $cc_basename in
-        ecc*)
-          wl='-Wl,'
-          ;;
-        icc* | ifort*)
-          wl='-Wl,'
-          ;;
-        lf95*)
+        icc* | ecc*)
           wl='-Wl,'
           ;;
         pgcc | pgf77 | pgf90)
@@ -130,7 +124,7 @@ else
   esac
 fi
 
-# Code taken from libtool.m4's _LT_LINKER_SHLIBS.
+# Code taken from libtool.m4's AC_LIBTOOL_PROG_LD_SHLIBS.
 
 hardcode_libdir_flag_spec=
 hardcode_libdir_separator=
@@ -138,7 +132,7 @@ hardcode_direct=no
 hardcode_minus_L=no
 
 case "$host_os" in
-  cygwin* | mingw* | pw32* | cegcc*)
+  cygwin* | mingw* | pw32*)
     # FIXME: the MSVC++ port hasn't been tested in a loooong time
     # When not using gcc, we currently assume that we are using
     # Microsoft Visual C++.
@@ -164,7 +158,7 @@ if test "$with_gnu_ld" = yes; then
   # option of GNU ld is called -rpath, not --rpath.
   hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
   case "$host_os" in
-    aix[3-9]*)
+    aix3* | aix4* | aix5*)
       # On AIX/PPC, the GNU linker is very broken
       if test "$host_cpu" != ia64; then
         ld_shlibs=no
@@ -188,7 +182,7 @@ if test "$with_gnu_ld" = yes; then
         ld_shlibs=no
       fi
       ;;
-    cygwin* | mingw* | pw32* | cegcc*)
+    cygwin* | mingw* | pw32*)
       # hardcode_libdir_flag_spec is actually meaningless, as there is
       # no search path for DLLs.
       hardcode_libdir_flag_spec='-L$libdir'
@@ -260,7 +254,7 @@ else
         hardcode_direct=unsupported
       fi
       ;;
-    aix[4-9]*)
+    aix4* | aix5*)
       if test "$host_cpu" = ia64; then
         # On IA64, the linker does run time linking by default, so we don't
         # have to do anything special.
@@ -270,7 +264,7 @@ else
         # Test if we are trying to use run time linking or normal
         # AIX style linking. If -brtl is somewhere in LDFLAGS, we
         # need to do runtime linking.
-        case $host_os in aix4.[23]|aix4.[23].*|aix[5-9]*)
+        case $host_os in aix4.[23]|aix4.[23].*|aix5*)
           for ld_flag in $LDFLAGS; do
             if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then
               aix_use_runtimelinking=yes
@@ -332,7 +326,7 @@ else
       ;;
     bsdi[45]*)
       ;;
-    cygwin* | mingw* | pw32* | cegcc*)
+    cygwin* | mingw* | pw32*)
       # When not using gcc, we currently assume that we are using
       # Microsoft Visual C++.
       # hardcode_libdir_flag_spec is actually meaningless, as there is
@@ -500,7 +494,7 @@ else
 fi
 
 # Check dynamic linker characteristics
-# Code taken from libtool.m4's _LT_SYS_DYNAMIC_LINKER.
+# Code taken from libtool.m4's AC_LIBTOOL_SYS_DYNAMIC_LINKER.
 # Unlike libtool.m4, here we don't care about _all_ names of the library, but
 # only about the one the linker finds when passed -lNAME. This is the last
 # element of library_names_spec in libtool.m4, or possibly two of them if the
@@ -511,7 +505,7 @@ case "$host_os" in
   aix3*)
     library_names_spec='$libname.a'
     ;;
-  aix[4-9]*)
+  aix4* | aix5*)
     library_names_spec='$libname$shrext'
     ;;
   amigaos*)
@@ -523,7 +517,7 @@ case "$host_os" in
   bsdi[45]*)
     library_names_spec='$libname$shrext'
     ;;
-  cygwin* | mingw* | pw32* | cegcc*)
+  cygwin* | mingw* | pw32*)
     shrext=.dll
     library_names_spec='$libname.dll.a $libname.lib'
     ;;
diff --git a/lib/configure.ac b/lib/configure.ac
index c28931c..35fa0d4 100644
--- a/lib/configure.ac
+++ b/lib/configure.ac
@@ -107,5 +107,7 @@ AC_CONFIG_FILES([
   openpgp/Makefile
   po/Makefile.in
   x509/Makefile
+  gcrypt/Makefile
+  nettle/Makefile
 ])
 AC_OUTPUT
diff --git a/lib/debug.c b/lib/debug.c
index 037b7fe..726a3d6 100644
--- a/lib/debug.c
+++ b/lib/debug.c
@@ -28,6 +28,19 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include "debug.h"
+#include <gnutls_mpi.h>
+
+void _gnutls_dump_mpi(const char* prefix, bigint_t a)
+{
+        char buf[400];
+        char buf_hex[2*sizeof(buf)];
+        size_t n = sizeof buf;
+
+        if (_gnutls_mpi_print(a, buf, &n))
+                strcpy(buf, "[can't print value]"); /* Flawfinder: ignore */
+        _gnutls_debug_log( "MPI: length: %d\n\t%s%s\n", (int)n, prefix,  
_gnutls_bin2hex(buf, n, buf_hex, sizeof(buf_hex), NULL));
+}
+
 
 const char *
 _gnutls_packet2str (content_type_t packet)
diff --git a/lib/debug.h b/lib/debug.h
index 341f87c..b027921 100644
--- a/lib/debug.h
+++ b/lib/debug.h
@@ -25,3 +25,4 @@
 
 const char *_gnutls_packet2str (content_type_t packet);
 const char *_gnutls_handshake2str (gnutls_handshake_description_t handshake);
+void _gnutls_dump_mpi(const char* prefix, bigint_t a);
diff --git a/lib/ext_session_ticket.c b/lib/ext_session_ticket.c
index 734476e..b3646b3 100644
--- a/lib/ext_session_ticket.c
+++ b/lib/ext_session_ticket.c
@@ -453,6 +453,7 @@ gnutls_session_ticket_enable_server (gnutls_session_t 
session,
 int
 _gnutls_send_new_session_ticket (gnutls_session_t session, int again)
 {
+  mbuffer_st *bufel = NULL;
   uint8_t *data = NULL, *p;
   int data_size = 0;
   int ret;
@@ -522,14 +523,15 @@ _gnutls_send_new_session_ticket (gnutls_session_t 
session, int again)
       ticket_len = KEY_NAME_SIZE + IV_SIZE + 2 + ticket.encrypted_state_len
        + MAC_SIZE;
 
-      data = gnutls_malloc (4 + 2 + ticket_len);
-      if (!data)
+      bufel = _gnutls_handshake_alloc (4 + 2 + ticket_len);
+      if (!bufel)
        {
          gnutls_assert ();
          gnutls_free (ticket.encrypted_state);
          return GNUTLS_E_MEMORY_ERROR;
        }
 
+      data = bufel->msg.data + bufel->mark;
       p = data;
       /* FIXME: ticket lifetime is fixed to 10 days, which should be
          customizable. */
@@ -556,11 +558,11 @@ _gnutls_send_new_session_ticket (gnutls_session_t 
session, int again)
       p += MAC_SIZE;
 
       data_size = p - data;
+      data = _gnutls_handshake_realloc(data, data_size);
     }
 
-  ret = _gnutls_send_handshake (session, data_size ? data : NULL, data_size,
+  ret = _gnutls_send_handshake (session, data_size ? bufel : NULL,
                                GNUTLS_HANDSHAKE_NEW_SESSION_TICKET);
-  gnutls_free (data);
 
   return ret;
 }
diff --git a/lib/gcrypt/Makefile.am b/lib/gcrypt/Makefile.am
new file mode 100644
index 0000000..c7efbe5
--- /dev/null
+++ b/lib/gcrypt/Makefile.am
@@ -0,0 +1,34 @@
+## Process this file with automake to produce Makefile.in
+# Copyright (C) 2004, 2005, 2006, 2007, 2008, 2010 Free Software
+# Foundation, Inc.
+#
+# Author: Nikos Mavroyanopoulos
+#
+# This file is part of GNUTLS.
+#
+# The GNUTLS library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public License
+# as published by the Free Software Foundation; either version 2.1 of
+# the License, or (at your option) any later version.
+#
+# The GNUTLS library is distributed in the hope that it will be
+# useful, but WITHOUT ANY WARRANTY; without even the implied warranty
+# of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with the GNUTLS library; if not, write to the Free
+# Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+# MA 02110-1301, USA
+
+AM_CFLAGS = $(WERROR_CFLAGS) $(WSTACK_CFLAGS) $(WARN_CFLAGS)
+AM_CPPFLAGS = \
+       -I$(srcdir)/../gl               \
+       -I$(builddir)/../gl             \
+       -I$(srcdir)/../includes         \
+       -I$(builddir)/../includes       \
+       -I$(srcdir)/..
+
+noinst_LTLIBRARIES = libcrypto.la
+
+libcrypto_la_SOURCES = pk.c mpi.c mac.c cipher.c rnd.c
diff --git a/lib/cipher-libgcrypt.c b/lib/gcrypt/cipher.c
similarity index 100%
rename from lib/cipher-libgcrypt.c
rename to lib/gcrypt/cipher.c
diff --git a/lib/mac-libgcrypt.c b/lib/gcrypt/mac.c
similarity index 100%
rename from lib/mac-libgcrypt.c
rename to lib/gcrypt/mac.c
diff --git a/lib/gcrypt/mpi.c b/lib/gcrypt/mpi.c
new file mode 100644
index 0000000..30e0d23
--- /dev/null
+++ b/lib/gcrypt/mpi.c
@@ -0,0 +1,415 @@
+/*
+ * Copyright (C) 2001, 2002, 2003, 2004, 2005, 2008, 2009, 2010 Free
+ * Software Foundation, Inc.
+ *
+ * Author: Nikos Mavrogiannopoulos
+ *
+ * This file is part of GnuTLS.
+ *
+ * The GnuTLS is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+ * USA
+ *
+ */
+
+/* Here lie everything that has to do with large numbers, libgcrypt and
+ * other stuff that didn't fit anywhere else.
+ */
+
+#include <gnutls_int.h>
+#include <gnutls_errors.h>
+#include <gnutls_num.h>
+#include <gnutls_mpi.h>
+#include <gcrypt.h>
+
+/* Functions that refer to the libgcrypt library.
+ */
+
+static inline int
+_format_conv (gnutls_bigint_format_t format)
+{
+  if (format == GNUTLS_MPI_FORMAT_USG)
+    return GCRYMPI_FMT_USG;
+  else if (format == GNUTLS_MPI_FORMAT_STD)
+    return GCRYMPI_FMT_STD;
+  else
+    return GCRYMPI_FMT_PGP;
+}
+
+/* returns zero on success
+ */
+static bigint_t
+wrap_gcry_mpi_scan (const void *buffer, size_t nbytes,
+                   gnutls_bigint_format_t format)
+{
+  gcry_mpi_t ret_mpi = NULL;
+  int ret;
+
+  ret = gcry_mpi_scan (&ret_mpi, _format_conv (format), buffer, nbytes, NULL);
+  if (ret != 0)
+    return NULL;
+
+  return ret_mpi;
+}
+
+static int
+wrap_gcry_mpi_print (const bigint_t a, void *buffer, size_t * nbytes,
+                    gnutls_bigint_format_t format)
+{
+  int ret;
+  size_t init_bytes = *nbytes;
+
+  format = _format_conv (format);
+
+  if (nbytes == NULL || a == NULL)
+    return GNUTLS_E_INVALID_REQUEST;
+
+  ret = gcry_mpi_print (format, buffer, *nbytes, nbytes, a);
+  if (!ret) {
+    if (buffer==NULL || init_bytes < *nbytes) {
+
+      /* in STD format we may want to include
+        * an extra byte for zero. Sometimes the gcry_
+        * function doesn't add it.
+        */
+      if (format == GNUTLS_MPI_FORMAT_STD) (*nbytes)++;
+      return GNUTLS_E_SHORT_MEMORY_BUFFER;
+    }
+    return 0;
+  }
+
+  return GNUTLS_E_MPI_PRINT_FAILED;
+}
+
+static bigint_t
+wrap_gcry_mpi_new (int nbits)
+{
+  return gcry_mpi_new (nbits);
+}
+
+static int
+wrap_gcry_mpi_cmp (const bigint_t u, const bigint_t v)
+{
+  return gcry_mpi_cmp (u, v);
+}
+
+static int
+wrap_gcry_mpi_cmp_ui (const bigint_t u, unsigned long v)
+{
+  return gcry_mpi_cmp_ui (u, v);
+}
+
+static bigint_t
+wrap_gcry_mpi_set (bigint_t w, const bigint_t u)
+{
+  return gcry_mpi_set (w, u);
+}
+
+static bigint_t
+wrap_gcry_mpi_set_ui (bigint_t w, unsigned long u)
+{
+  return gcry_mpi_set_ui (w, u);
+}
+
+static unsigned int
+wrap_gcry_mpi_get_nbits (bigint_t a)
+{
+  return gcry_mpi_get_nbits (a);
+}
+
+static void
+wrap_gcry_mpi_release (bigint_t a)
+{
+  gcry_mpi_release (a);
+}
+
+#undef _gnutls_mpi_alloc_like
+#define _gnutls_mpi_alloc_like(x) gcry_mpi_new(gcry_mpi_get_nbits(x))
+
+static bigint_t
+wrap_gcry_mpi_mod (const bigint_t a, const bigint_t b)
+{
+  bigint_t r = _gnutls_mpi_alloc_like (b);
+
+  if (r == NULL)
+    return NULL;
+
+  gcry_mpi_mod (r, a, b);
+
+  return r;
+}
+
+static bigint_t
+wrap_gcry_mpi_powm (bigint_t w, const bigint_t b, const bigint_t e,
+                   const bigint_t m)
+{
+  if (w == NULL)
+    w = _gnutls_mpi_alloc_like (m);
+
+  if (w == NULL)
+    return NULL;
+
+  gcry_mpi_powm (w, b, e, m);
+
+  return w;
+}
+
+static bigint_t
+wrap_gcry_mpi_addm (bigint_t w, const bigint_t a, const bigint_t b,
+                   const bigint_t m)
+{
+  if (w == NULL)
+    w = _gnutls_mpi_alloc_like (m);
+
+  if (w == NULL)
+    return NULL;
+
+  gcry_mpi_addm (w, a, b, m);
+
+  return w;
+}
+
+static bigint_t
+wrap_gcry_mpi_subm (bigint_t w, const bigint_t a, const bigint_t b,
+                   const bigint_t m)
+{
+  if (w == NULL)
+    w = _gnutls_mpi_alloc_like (m);
+
+  if (w == NULL)
+    return NULL;
+
+  gcry_mpi_subm (w, a, b, m);
+
+  return w;
+}
+
+static bigint_t
+wrap_gcry_mpi_mulm (bigint_t w, const bigint_t a, const bigint_t b,
+                   const bigint_t m)
+{
+  if (w == NULL)
+    w = _gnutls_mpi_alloc_like (m);
+
+  if (w == NULL)
+    return NULL;
+
+  gcry_mpi_mulm (w, a, b, m);
+
+  return w;
+}
+
+static bigint_t
+wrap_gcry_mpi_add (bigint_t w, const bigint_t a, const bigint_t b)
+{
+  if (w == NULL)
+    w = _gnutls_mpi_alloc_like (b);
+
+  if (w == NULL)
+    return NULL;
+
+  gcry_mpi_add (w, a, b);
+
+  return w;
+}
+
+static bigint_t
+wrap_gcry_mpi_sub (bigint_t w, const bigint_t a, const bigint_t b)
+{
+  if (w == NULL)
+    w = _gnutls_mpi_alloc_like (b);
+
+  if (w == NULL)
+    return NULL;
+
+  gcry_mpi_sub (w, a, b);
+
+  return w;
+}
+
+static bigint_t
+wrap_gcry_mpi_mul (bigint_t w, const bigint_t a, const bigint_t b)
+{
+  if (w == NULL)
+    w = _gnutls_mpi_alloc_like (b);
+
+  if (w == NULL)
+    return NULL;
+
+  gcry_mpi_mul (w, a, b);
+
+  return w;
+}
+
+/* q = a / b */
+static bigint_t
+wrap_gcry_mpi_div (bigint_t q, const bigint_t a, const bigint_t b)
+{
+  if (q == NULL)
+    q = _gnutls_mpi_alloc_like (a);
+
+  if (q == NULL)
+    return NULL;
+
+  gcry_mpi_div (q, NULL, a, b, 0);
+
+  return q;
+}
+
+static bigint_t
+wrap_gcry_mpi_add_ui (bigint_t w, const bigint_t a, unsigned long b)
+{
+  if (w == NULL)
+    w = _gnutls_mpi_alloc_like (a);
+
+  if (w == NULL)
+    return NULL;
+
+  gcry_mpi_add_ui (w, a, b);
+
+  return w;
+}
+
+static bigint_t
+wrap_gcry_mpi_sub_ui (bigint_t w, const bigint_t a, unsigned long b)
+{
+  if (w == NULL)
+    w = _gnutls_mpi_alloc_like (a);
+
+  if (w == NULL)
+    return NULL;
+
+  gcry_mpi_sub_ui (w, a, b);
+
+  return w;
+}
+
+static bigint_t
+wrap_gcry_mpi_mul_ui (bigint_t w, const bigint_t a, unsigned long b)
+{
+  if (w == NULL)
+    w = _gnutls_mpi_alloc_like (a);
+
+  if (w == NULL)
+    return NULL;
+
+  gcry_mpi_mul_ui (w, a, b);
+
+  return w;
+}
+
+static int
+wrap_gcry_prime_check (bigint_t pp)
+{
+  return gcry_prime_check (pp, 0);
+}
+
+static int
+wrap_gcry_generate_group (gnutls_group_st * group, unsigned int bits)
+{
+  gcry_mpi_t g = NULL, prime = NULL;
+  gcry_error_t err;
+  int times = 0, qbits;
+  gcry_mpi_t *factors = NULL;
+
+  /* Calculate the size of a prime factor of (prime-1)/2.
+   * This is an emulation of the values in "Selecting Cryptographic Key Sizes" 
paper.
+   */
+  if (bits < 256)
+    qbits = bits / 2;
+  else
+    {
+      qbits = (bits / 40) + 105;
+    }
+
+  if (qbits & 1)               /* better have an even number */
+    qbits++;
+
+  /* find a prime number of size bits.
+   */
+  do
+    {
+      if (times)
+       {
+         gcry_mpi_release (prime);
+         gcry_prime_release_factors (factors);
+       }
+
+      err = gcry_prime_generate (&prime, bits, qbits, &factors,
+                                NULL, NULL, GCRY_STRONG_RANDOM,
+                                GCRY_PRIME_FLAG_SPECIAL_FACTOR);
+      if (err != 0)
+       {
+         gnutls_assert ();
+         return GNUTLS_E_INTERNAL_ERROR;
+       }
+
+      err = gcry_prime_check (prime, 0);
+
+      times++;
+    }
+  while (err != 0 && times < 10);
+
+  if (err != 0)
+    {
+      gnutls_assert ();
+      gcry_mpi_release (prime);
+      gcry_prime_release_factors (factors);
+      return GNUTLS_E_INTERNAL_ERROR;
+    }
+
+  /* generate the group generator.
+   */
+  err = gcry_prime_group_generator (&g, prime, factors, NULL);
+  gcry_prime_release_factors (factors);
+  if (err != 0)
+    {
+      gnutls_assert ();
+      gcry_mpi_release (prime);
+      return GNUTLS_E_INTERNAL_ERROR;
+    }
+
+  group->g = g;
+  group->p = prime;
+
+  return 0;
+}
+
+int crypto_bigint_prio = INT_MAX;
+
+gnutls_crypto_bigint_st _gnutls_mpi_ops = {
+  .bigint_new = wrap_gcry_mpi_new,
+  .bigint_cmp = wrap_gcry_mpi_cmp,
+  .bigint_cmp_ui = wrap_gcry_mpi_cmp_ui,
+  .bigint_mod = wrap_gcry_mpi_mod,
+  .bigint_set = wrap_gcry_mpi_set,
+  .bigint_set_ui = wrap_gcry_mpi_set_ui,
+  .bigint_get_nbits = wrap_gcry_mpi_get_nbits,
+  .bigint_powm = wrap_gcry_mpi_powm,
+  .bigint_addm = wrap_gcry_mpi_addm,
+  .bigint_subm = wrap_gcry_mpi_subm,
+  .bigint_add = wrap_gcry_mpi_add,
+  .bigint_sub = wrap_gcry_mpi_sub,
+  .bigint_add_ui = wrap_gcry_mpi_add_ui,
+  .bigint_sub_ui = wrap_gcry_mpi_sub_ui,
+  .bigint_mul = wrap_gcry_mpi_mul,
+  .bigint_mulm = wrap_gcry_mpi_mulm,
+  .bigint_mul_ui = wrap_gcry_mpi_mul_ui,
+  .bigint_div = wrap_gcry_mpi_div,
+  .bigint_prime_check = wrap_gcry_prime_check,
+  .bigint_release = wrap_gcry_mpi_release,
+  .bigint_print = wrap_gcry_mpi_print,
+  .bigint_scan = wrap_gcry_mpi_scan,
+  .bigint_generate_group = wrap_gcry_generate_group
+};
diff --git a/lib/gcrypt/pk.c b/lib/gcrypt/pk.c
new file mode 100644
index 0000000..c0b0005
--- /dev/null
+++ b/lib/gcrypt/pk.c
@@ -0,0 +1,859 @@
+/*
+ * Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2008, 2009, 2010
+ * Free Software Foundation, Inc.
+ *
+ * Author: Nikos Mavrogiannopoulos
+ *
+ * This file is part of GnuTLS.
+ *
+ * The GnuTLS is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+ * USA
+ *
+ */
+
+/* This file contains the functions needed for RSA/DSA public key
+ * encryption and signatures. 
+ */
+
+#include <gnutls_int.h>
+#include <gnutls_mpi.h>
+#include <gnutls_pk.h>
+#include <gnutls_errors.h>
+#include <gnutls_datum.h>
+#include <gnutls_global.h>
+#include <gnutls_num.h>
+#include <x509/x509_int.h>
+#include <x509/common.h>
+#include <random.h>
+#include <gnutls_pk.h>
+#include <gcrypt.h>
+
+/* this is based on code from old versions of libgcrypt (centuries ago)
+ */
+
+int (*generate) (gnutls_pk_algorithm_t, unsigned int level /*bits */ ,
+                gnutls_pk_params_st *);
+
+static int
+_wrap_gcry_pk_encrypt (gnutls_pk_algorithm_t algo,
+                      gnutls_datum_t * ciphertext,
+                      const gnutls_datum_t * plaintext,
+                      const gnutls_pk_params_st * pk_params)
+{
+  gcry_sexp_t s_ciph = NULL, s_data = NULL, s_pkey = NULL;
+  int rc = -1;
+  int ret;
+  bigint_t data, res;
+  gcry_sexp_t list;
+
+  if (_gnutls_mpi_scan_nz (&data, plaintext->data, plaintext->size) != 0)
+    {
+      gnutls_assert ();
+      return GNUTLS_E_MPI_SCAN_FAILED;
+    }
+
+  /* make a sexp from pkey */
+  switch (algo)
+    {
+    case GNUTLS_PK_RSA:
+      if (pk_params->params_nr >= 2)
+       rc = gcry_sexp_build (&s_pkey, NULL,
+                             "(public-key(rsa(n%m)(e%m)))",
+                             pk_params->params[0], pk_params->params[1]);
+      break;
+
+    default:
+      gnutls_assert ();
+      ret = GNUTLS_E_INTERNAL_ERROR;
+      goto cleanup;
+    }
+
+  if (rc != 0)
+    {
+      gnutls_assert ();
+      ret = GNUTLS_E_INTERNAL_ERROR;
+      goto cleanup;
+    }
+
+  /* put the data into a simple list */
+  if (gcry_sexp_build (&s_data, NULL, "%m", data))
+    {
+      gnutls_assert ();
+      ret = GNUTLS_E_MEMORY_ERROR;
+      goto cleanup;
+    }
+
+  /* pass it to libgcrypt */
+  rc = gcry_pk_encrypt (&s_ciph, s_data, s_pkey);
+  if (rc != 0)
+    {
+      gnutls_assert ();
+      ret = GNUTLS_E_PK_ENCRYPTION_FAILED;
+      goto cleanup;
+    }
+
+  list = gcry_sexp_find_token (s_ciph, "a", 0);
+  if (list == NULL)
+    {
+      gnutls_assert ();
+      ret = GNUTLS_E_INTERNAL_ERROR;
+      goto cleanup;
+    }
+
+  res = gcry_sexp_nth_mpi (list, 1, 0);
+  gcry_sexp_release (list);
+  if (res == NULL)
+    {
+      gnutls_assert ();
+      ret = GNUTLS_E_INTERNAL_ERROR;
+      goto cleanup;
+    }
+
+  ret = _gnutls_mpi_dprint_size (res, ciphertext, plaintext->size);
+  _gnutls_mpi_release (&res);
+  if (ret < 0)
+    {
+      gnutls_assert ();
+      goto cleanup;
+    }
+
+  ret = 0;
+
+cleanup:
+  _gnutls_mpi_release (&data);
+  if (s_ciph)
+    gcry_sexp_release (s_ciph);
+  if (s_data)
+    gcry_sexp_release (s_data);
+  if (s_pkey)
+    gcry_sexp_release (s_pkey);
+
+  return ret;
+}
+
+static int
+_wrap_gcry_pk_decrypt (gnutls_pk_algorithm_t algo,
+                      gnutls_datum_t * plaintext,
+                      const gnutls_datum_t * ciphertext,
+                      const gnutls_pk_params_st * pk_params)
+{
+  gcry_sexp_t s_plain = NULL, s_data = NULL, s_pkey = NULL;
+  int rc = -1;
+  int ret;
+  bigint_t data, res;
+
+  if (_gnutls_mpi_scan_nz (&data, ciphertext->data, ciphertext->size) != 0)
+    {
+      gnutls_assert ();
+      return GNUTLS_E_MPI_SCAN_FAILED;
+    }
+
+  /* make a sexp from pkey */
+  switch (algo)
+    {
+    case GNUTLS_PK_RSA:
+      if (pk_params->params_nr >= 6)
+       rc = gcry_sexp_build (&s_pkey, NULL,
+                             
"(private-key(rsa((n%m)(e%m)(d%m)(p%m)(q%m)(u%m))))",
+                             pk_params->params[0], pk_params->params[1],
+                             pk_params->params[2], pk_params->params[3],
+                             pk_params->params[4], pk_params->params[5]);
+      break;
+
+    default:
+      gnutls_assert ();
+      ret = GNUTLS_E_INTERNAL_ERROR;
+      goto cleanup;
+    }
+
+  if (rc != 0)
+    {
+      gnutls_assert ();
+      ret = GNUTLS_E_INTERNAL_ERROR;
+      goto cleanup;
+    }
+
+  /* put the data into a simple list */
+  if (gcry_sexp_build (&s_data, NULL, "(enc-val(rsa(a%m)))", data))
+    {
+      gnutls_assert ();
+      ret = GNUTLS_E_INTERNAL_ERROR;
+      goto cleanup;
+    }
+
+  /* pass it to libgcrypt */
+  rc = gcry_pk_decrypt (&s_plain, s_data, s_pkey);
+  if (rc != 0)
+    {
+      gnutls_assert ();
+      ret = GNUTLS_E_PK_DECRYPTION_FAILED;
+      goto cleanup;
+    }
+
+  res = gcry_sexp_nth_mpi (s_plain, 0, 0);
+  if (res == NULL)
+    {
+      gnutls_assert ();
+      ret = GNUTLS_E_INTERNAL_ERROR;
+      goto cleanup;
+    }
+
+  ret = _gnutls_mpi_dprint_size (res, plaintext, ciphertext->size);
+  _gnutls_mpi_release (&res);
+  if (ret < 0)
+    {
+      gnutls_assert ();
+      goto cleanup;
+    }
+
+  ret = 0;
+
+cleanup:
+  _gnutls_mpi_release (&data);
+  if (s_plain)
+    gcry_sexp_release (s_plain);
+  if (s_data)
+    gcry_sexp_release (s_data);
+  if (s_pkey)
+    gcry_sexp_release (s_pkey);
+
+  return ret;
+
+}
+
+
+/* in case of DSA puts into data, r,s
+ */
+static int
+_wrap_gcry_pk_sign (gnutls_pk_algorithm_t algo, gnutls_datum_t * signature,
+                   const gnutls_datum_t * vdata,
+                   const gnutls_pk_params_st * pk_params)
+{
+  gcry_sexp_t s_hash = NULL, s_key = NULL, s_sig = NULL;
+  gcry_sexp_t list = NULL;
+  int rc = -1, ret;
+  bigint_t hash;
+  bigint_t res[2] = { NULL, NULL };
+
+  if (_gnutls_mpi_scan_nz (&hash, vdata->data, vdata->size) != 0)
+    {
+      gnutls_assert ();
+      return GNUTLS_E_MPI_SCAN_FAILED;
+    }
+
+  /* make a sexp from pkey */
+  switch (algo)
+    {
+    case GNUTLS_PK_DSA:
+      if (pk_params->params_nr >= 5)
+       rc = gcry_sexp_build (&s_key, NULL,
+                             "(private-key(dsa(p%m)(q%m)(g%m)(y%m)(x%m)))",
+                             pk_params->params[0], pk_params->params[1],
+                             pk_params->params[2], pk_params->params[3],
+                             pk_params->params[4]);
+      else
+       {
+         gnutls_assert ();
+       }
+
+      break;
+    case GNUTLS_PK_RSA:
+      if (pk_params->params_nr >= 6)
+       rc = gcry_sexp_build (&s_key, NULL,
+                             
"(private-key(rsa((n%m)(e%m)(d%m)(p%m)(q%m)(u%m))))",
+                             pk_params->params[0], pk_params->params[1],
+                             pk_params->params[2], pk_params->params[3],
+                             pk_params->params[4], pk_params->params[5]);
+      else
+       {
+         gnutls_assert ();
+       }
+      break;
+
+    default:
+      gnutls_assert ();
+      ret = GNUTLS_E_INTERNAL_ERROR;
+      goto cleanup;
+    }
+
+  if (rc != 0)
+    {
+      gnutls_assert ();
+      ret = GNUTLS_E_INTERNAL_ERROR;
+      goto cleanup;
+    }
+
+  /* put the data into a simple list */
+  if (gcry_sexp_build (&s_hash, NULL, "%m", hash))
+    {
+      gnutls_assert ();
+      ret = GNUTLS_E_INTERNAL_ERROR;
+      goto cleanup;
+    }
+
+
+  /* pass it to libgcrypt */
+  rc = gcry_pk_sign (&s_sig, s_hash, s_key);
+  if (rc != 0)
+    {
+      gnutls_assert ();
+      ret = GNUTLS_E_PK_SIGN_FAILED;
+      goto cleanup;
+    }
+
+  ret = GNUTLS_E_INTERNAL_ERROR;
+
+  switch (algo)
+    {
+    case GNUTLS_PK_DSA:
+      {
+       list = gcry_sexp_find_token (s_sig, "r", 0);
+       if (list == NULL)
+         {
+           gnutls_assert ();
+           ret = GNUTLS_E_INTERNAL_ERROR;
+           goto cleanup;
+         }
+
+       res[0] = gcry_sexp_nth_mpi (list, 1, 0);
+       gcry_sexp_release (list);
+
+       list = gcry_sexp_find_token (s_sig, "s", 0);
+       if (list == NULL)
+         {
+           gnutls_assert ();
+           ret = GNUTLS_E_INTERNAL_ERROR;
+           goto cleanup;
+         }
+
+       res[1] = gcry_sexp_nth_mpi (list, 1, 0);
+       gcry_sexp_release (list);
+
+       ret = _gnutls_encode_ber_rs (signature, res[0], res[1]);
+       if (ret < 0)
+         {
+           gnutls_assert ();
+           goto cleanup;
+         }
+      }
+      break;
+
+    case GNUTLS_PK_RSA:
+      {
+       list = gcry_sexp_find_token (s_sig, "s", 0);
+       if (list == NULL)
+         {
+           gnutls_assert ();
+           ret = GNUTLS_E_INTERNAL_ERROR;
+           goto cleanup;
+         }
+
+       res[0] = gcry_sexp_nth_mpi (list, 1, 0);
+       gcry_sexp_release (list);
+
+       ret = _gnutls_mpi_dprint (res[0], signature);
+       if (ret < 0)
+         {
+           gnutls_assert ();
+           goto cleanup;
+         }
+      }
+      break;
+
+    default:
+      gnutls_assert ();
+      ret = GNUTLS_E_INTERNAL_ERROR;
+      goto cleanup;
+    }
+
+  ret = 0;
+
+cleanup:
+  _gnutls_mpi_release (&hash);
+  if (res[0])
+    _gnutls_mpi_release (&res[0]);
+  if (res[1])
+    _gnutls_mpi_release (&res[1]);
+  if (s_sig)
+    gcry_sexp_release (s_sig);
+  if (s_hash)
+    gcry_sexp_release (s_hash);
+  if (s_key)
+    gcry_sexp_release (s_key);
+
+  return ret;
+}
+
+static int
+_wrap_gcry_pk_verify (gnutls_pk_algorithm_t algo,
+                     const gnutls_datum_t * vdata,
+                     const gnutls_datum_t * signature,
+                     const gnutls_pk_params_st * pk_params)
+{
+  gcry_sexp_t s_sig = NULL, s_hash = NULL, s_pkey = NULL;
+  int rc = -1, ret;
+  bigint_t hash;
+  bigint_t tmp[2] = { NULL, NULL };
+
+  if (_gnutls_mpi_scan_nz (&hash, vdata->data, vdata->size) != 0)
+    {
+      gnutls_assert ();
+      return GNUTLS_E_MPI_SCAN_FAILED;
+    }
+
+  /* make a sexp from pkey */
+  switch (algo)
+    {
+    case GNUTLS_PK_DSA:
+      if (pk_params->params_nr >= 4)
+       rc = gcry_sexp_build (&s_pkey, NULL,
+                             "(public-key(dsa(p%m)(q%m)(g%m)(y%m)))",
+                             pk_params->params[0], pk_params->params[1],
+                             pk_params->params[2], pk_params->params[3]);
+      break;
+    case GNUTLS_PK_RSA:
+      if (pk_params->params_nr >= 2)
+       rc = gcry_sexp_build (&s_pkey, NULL,
+                             "(public-key(rsa(n%m)(e%m)))",
+                             pk_params->params[0], pk_params->params[1]);
+      break;
+
+    default:
+      gnutls_assert ();
+      ret = GNUTLS_E_INTERNAL_ERROR;
+      goto cleanup;
+    }
+
+  if (rc != 0)
+    {
+      gnutls_assert ();
+      ret = GNUTLS_E_INTERNAL_ERROR;
+      goto cleanup;
+    }
+
+  /* put the data into a simple list */
+  if (gcry_sexp_build (&s_hash, NULL, "%m", hash))
+    {
+      gnutls_assert ();
+      ret = GNUTLS_E_INTERNAL_ERROR;
+      goto cleanup;
+    }
+
+  switch (algo)
+    {
+    case GNUTLS_PK_DSA:
+      ret = _gnutls_decode_ber_rs (signature, &tmp[0], &tmp[1]);
+      if (ret < 0)
+       {
+         gnutls_assert ();
+         goto cleanup;
+       }
+      rc = gcry_sexp_build (&s_sig, NULL,
+                           "(sig-val(dsa(r%m)(s%m)))", tmp[0], tmp[1]);
+      _gnutls_mpi_release (&tmp[0]);
+      _gnutls_mpi_release (&tmp[1]);
+      break;
+
+    case GNUTLS_PK_RSA:
+      ret = _gnutls_mpi_scan_nz (&tmp[0], signature->data, signature->size);
+      if (ret < 0)
+       {
+         gnutls_assert ();
+         goto cleanup;
+       }
+      rc = gcry_sexp_build (&s_sig, NULL, "(sig-val(rsa(s%m)))", tmp[0]);
+      _gnutls_mpi_release (&tmp[0]);
+      break;
+
+    default:
+      gnutls_assert ();
+      ret = GNUTLS_E_INTERNAL_ERROR;
+      goto cleanup;
+    }
+
+  if (rc != 0)
+    {
+      gnutls_assert ();
+      ret = GNUTLS_E_INTERNAL_ERROR;
+      goto cleanup;
+    }
+
+  rc = gcry_pk_verify (s_sig, s_hash, s_pkey);
+
+  if (rc != 0)
+    {
+      gnutls_assert ();
+      ret = GNUTLS_E_PK_SIG_VERIFY_FAILED;
+      goto cleanup;
+    }
+
+  ret = 0;
+
+cleanup:
+  _gnutls_mpi_release (&hash);
+  if (s_sig)
+    gcry_sexp_release (s_sig);
+  if (s_hash)
+    gcry_sexp_release (s_hash);
+  if (s_pkey)
+    gcry_sexp_release (s_pkey);
+
+  return ret;
+}
+
+static int
+_dsa_generate_params (bigint_t * resarr, int *resarr_len, int bits)
+{
+
+  int ret;
+  gcry_sexp_t parms, key, list;
+
+  /* FIXME: Remove me once we depend on 1.3.1 */
+  if (bits > 1024 && gcry_check_version ("1.3.1") == NULL)
+    {
+      gnutls_assert ();
+      return GNUTLS_E_INVALID_REQUEST;
+    }
+
+  if (bits < 512)
+    {
+      gnutls_assert ();
+      return GNUTLS_E_INVALID_REQUEST;
+    }
+
+  ret = gcry_sexp_build (&parms, NULL, "(genkey(dsa(nbits %d)))", bits);
+  if (ret != 0)
+    {
+      gnutls_assert ();
+      return GNUTLS_E_INTERNAL_ERROR;
+    }
+
+  /* generate the DSA key 
+   */
+  ret = gcry_pk_genkey (&key, parms);
+  gcry_sexp_release (parms);
+
+  if (ret != 0)
+    {
+      gnutls_assert ();
+      return GNUTLS_E_INTERNAL_ERROR;
+    }
+
+  list = gcry_sexp_find_token (key, "p", 0);
+  if (list == NULL)
+    {
+      gnutls_assert ();
+      gcry_sexp_release (key);
+      return GNUTLS_E_INTERNAL_ERROR;
+    }
+
+  resarr[0] = gcry_sexp_nth_mpi (list, 1, 0);
+  gcry_sexp_release (list);
+
+  list = gcry_sexp_find_token (key, "q", 0);
+  if (list == NULL)
+    {
+      gnutls_assert ();
+      gcry_sexp_release (key);
+      return GNUTLS_E_INTERNAL_ERROR;
+    }
+
+  resarr[1] = gcry_sexp_nth_mpi (list, 1, 0);
+  gcry_sexp_release (list);
+
+  list = gcry_sexp_find_token (key, "g", 0);
+  if (list == NULL)
+    {
+      gnutls_assert ();
+      gcry_sexp_release (key);
+      return GNUTLS_E_INTERNAL_ERROR;
+    }
+
+  resarr[2] = gcry_sexp_nth_mpi (list, 1, 0);
+  gcry_sexp_release (list);
+
+  list = gcry_sexp_find_token (key, "y", 0);
+  if (list == NULL)
+    {
+      gnutls_assert ();
+      gcry_sexp_release (key);
+      return GNUTLS_E_INTERNAL_ERROR;
+    }
+
+  resarr[3] = gcry_sexp_nth_mpi (list, 1, 0);
+  gcry_sexp_release (list);
+
+
+  list = gcry_sexp_find_token (key, "x", 0);
+  if (list == NULL)
+    {
+      gnutls_assert ();
+      gcry_sexp_release (key);
+      return GNUTLS_E_INTERNAL_ERROR;
+    }
+
+  resarr[4] = gcry_sexp_nth_mpi (list, 1, 0);
+
+  gcry_sexp_release (list);
+  gcry_sexp_release (key);
+
+  _gnutls_mpi_log ("p: ", resarr[0]);
+  _gnutls_mpi_log ("q: ", resarr[1]);
+  _gnutls_mpi_log ("g: ", resarr[2]);
+  _gnutls_mpi_log ("y: ", resarr[3]);
+  _gnutls_mpi_log ("x: ", resarr[4]);
+
+  *resarr_len = 5;
+
+  return 0;
+
+}
+
+static int
+_rsa_generate_params (bigint_t * resarr, int *resarr_len, int bits)
+{
+
+  int ret, i;
+  gcry_sexp_t parms, key, list;
+  bigint_t tmp;
+
+  if (*resarr_len < RSA_PRIVATE_PARAMS)
+    {
+      gnutls_assert();
+      return GNUTLS_E_INTERNAL_ERROR;
+    }
+
+  ret = gcry_sexp_build (&parms, NULL, "(genkey(rsa(nbits %d)))", bits);
+  if (ret != 0)
+    {
+      gnutls_assert ();
+      return GNUTLS_E_INTERNAL_ERROR;
+    }
+
+  /* generate the RSA key */
+  ret = gcry_pk_genkey (&key, parms);
+  gcry_sexp_release (parms);
+
+  if (ret != 0)
+    {
+      gnutls_assert ();
+      return GNUTLS_E_INTERNAL_ERROR;
+    }
+
+  list = gcry_sexp_find_token (key, "n", 0);
+  if (list == NULL)
+    {
+      gnutls_assert ();
+      gcry_sexp_release (key);
+      return GNUTLS_E_INTERNAL_ERROR;
+    }
+
+  resarr[0] = gcry_sexp_nth_mpi (list, 1, 0);
+  gcry_sexp_release (list);
+
+  list = gcry_sexp_find_token (key, "e", 0);
+  if (list == NULL)
+    {
+      gnutls_assert ();
+      gcry_sexp_release (key);
+      return GNUTLS_E_INTERNAL_ERROR;
+    }
+
+  resarr[1] = gcry_sexp_nth_mpi (list, 1, 0);
+  gcry_sexp_release (list);
+
+  list = gcry_sexp_find_token (key, "d", 0);
+  if (list == NULL)
+    {
+      gnutls_assert ();
+      gcry_sexp_release (key);
+      return GNUTLS_E_INTERNAL_ERROR;
+    }
+
+  resarr[2] = gcry_sexp_nth_mpi (list, 1, 0);
+  gcry_sexp_release (list);
+
+  list = gcry_sexp_find_token (key, "p", 0);
+  if (list == NULL)
+    {
+      gnutls_assert ();
+      gcry_sexp_release (key);
+      return GNUTLS_E_INTERNAL_ERROR;
+    }
+
+  resarr[3] = gcry_sexp_nth_mpi (list, 1, 0);
+  gcry_sexp_release (list);
+
+
+  list = gcry_sexp_find_token (key, "q", 0);
+  if (list == NULL)
+    {
+      gnutls_assert ();
+      gcry_sexp_release (key);
+      return GNUTLS_E_INTERNAL_ERROR;
+    }
+
+  resarr[4] = gcry_sexp_nth_mpi (list, 1, 0);
+  gcry_sexp_release (list);
+
+
+  list = gcry_sexp_find_token (key, "u", 0);
+  if (list == NULL)
+    {
+      gnutls_assert ();
+      gcry_sexp_release (key);
+      return GNUTLS_E_INTERNAL_ERROR;
+    }
+
+  resarr[5] = gcry_sexp_nth_mpi (list, 1, 0);
+
+  gcry_sexp_release (list);
+  gcry_sexp_release (key);
+
+  _gnutls_mpi_log ("n: ", resarr[0]);
+  _gnutls_mpi_log ("e: ", resarr[1]);
+  _gnutls_mpi_log ("d: ", resarr[2]);
+  _gnutls_mpi_log ("p: ", resarr[3]);
+  _gnutls_mpi_log ("q: ", resarr[4]);
+  _gnutls_mpi_log ("u: ", resarr[5]);
+
+  /* generate e1 and e2 */
+
+  *resarr_len = 6;
+       
+  tmp = _gnutls_mpi_alloc_like(resarr[0]);
+  if (tmp == NULL)
+       {
+         gnutls_assert ();
+         ret = GNUTLS_E_MEMORY_ERROR;
+         goto cleanup;
+       }
+
+  ret =  _gnutls_calc_rsa_exp(resarr, 2 + *resarr_len);
+  if (ret < 0)
+    {
+      gnutls_assert();
+      ret= GNUTLS_E_MEMORY_ERROR;
+      goto cleanup;
+    }
+
+  (*resarr_len)+=2;
+
+  return 0;
+
+cleanup:
+  for (i=0;i<*resarr_len;i++)
+       _gnutls_mpi_release(&resarr[i]);
+
+  return ret;
+}
+
+
+static int
+wrap_gcry_pk_generate_params (gnutls_pk_algorithm_t algo,
+                             unsigned int level /*bits */ ,
+                             gnutls_pk_params_st * params)
+{
+
+  switch (algo)
+    {
+
+    case GNUTLS_PK_DSA:
+      params->params_nr = DSA_PRIVATE_PARAMS;
+      if (params->params_nr > GNUTLS_MAX_PK_PARAMS)
+       {
+         gnutls_assert ();
+         return GNUTLS_E_INTERNAL_ERROR;
+       }
+      return _dsa_generate_params (params->params, &params->params_nr, level);
+
+    case GNUTLS_PK_RSA:
+      params->params_nr = RSA_PRIVATE_PARAMS;
+      if (params->params_nr > GNUTLS_MAX_PK_PARAMS)
+       {
+         gnutls_assert ();
+         return GNUTLS_E_INTERNAL_ERROR;
+       }
+      return _rsa_generate_params (params->params, &params->params_nr, level);
+
+    default:
+      gnutls_assert ();
+      return GNUTLS_E_INVALID_REQUEST;
+    }
+}
+
+
+static int
+wrap_gcry_pk_fixup (gnutls_pk_algorithm_t algo,
+                   gnutls_direction_t direction,
+                   gnutls_pk_params_st * params)
+{
+  int ret, result;
+
+  /* only for RSA we invert the coefficient --pgp type */
+
+  if (algo != GNUTLS_PK_RSA)
+    return 0;
+
+  if (params->params[5]==NULL)
+    params->params[5] =
+      _gnutls_mpi_new (_gnutls_mpi_get_nbits (params->params[0]));
+
+  if (params->params[5] == NULL)
+    {
+      gnutls_assert ();
+      return GNUTLS_E_MEMORY_ERROR;
+    }
+
+  ret = 1;
+  if (direction == GNUTLS_IMPORT)
+    {
+         /* calculate exp1 [6] and exp2 [7] */
+      _gnutls_mpi_release(&params->params[6]);
+      _gnutls_mpi_release(&params->params[7]);
+         result = _gnutls_calc_rsa_exp(params->params, RSA_PRIVATE_PARAMS);
+         if (result < 0)
+           {
+                 gnutls_assert();
+                 return result;
+           }
+
+      ret =
+        gcry_mpi_invm (params->params[5], params->params[3], 
params->params[4]);
+
+         params->params_nr = RSA_PRIVATE_PARAMS;
+       }
+  else if (direction == GNUTLS_EXPORT)
+    ret =
+      gcry_mpi_invm (params->params[5], params->params[4], params->params[3]);
+  if (ret == 0)
+    {
+      gnutls_assert ();
+      return GNUTLS_E_INVALID_REQUEST;
+    }
+
+  return 0;
+}
+
+int crypto_pk_prio = INT_MAX;
+
+gnutls_crypto_pk_st _gnutls_pk_ops = {
+  .encrypt = _wrap_gcry_pk_encrypt,
+  .decrypt = _wrap_gcry_pk_decrypt,
+  .sign = _wrap_gcry_pk_sign,
+  .verify = _wrap_gcry_pk_verify,
+  .generate = wrap_gcry_pk_generate_params,
+  .pk_fixup_private_params = wrap_gcry_pk_fixup,
+};
diff --git a/lib/rnd-libgcrypt.c b/lib/gcrypt/rnd.c
similarity index 100%
rename from lib/rnd-libgcrypt.c
rename to lib/gcrypt/rnd.c
diff --git a/lib/gnutls.pc.in b/lib/gnutls.pc.in
index a4a3495..5898ca1 100644
--- a/lib/gnutls.pc.in
+++ b/lib/gnutls.pc.in
@@ -20,5 +20,5 @@ Description: Transport Security Layer implementation for the 
GNU system
 URL: http://www.gnu.org/software/gnutls/
 Version: @VERSION@
 Libs: -L${libdir} -lgnutls
-Libs.private: @LIBGNUTLS_LIBS@ @LTLIBTASN1@
+Libs.private: @LIBGNUTLS_LIBS@ @LTLIBTASN1@ @LTLIBPAKCHOIS@
 Cflags: -I${includedir}
diff --git a/lib/gnutls_algorithms.c b/lib/gnutls_algorithms.c
index 4c4c357..891b2aa 100644
--- a/lib/gnutls_algorithms.c
+++ b/lib/gnutls_algorithms.c
@@ -1279,6 +1279,7 @@ _gnutls_version_has_selectable_prf (gnutls_protocol_t 
version)
   return version == GNUTLS_TLS1_2;
 }
 
+
 /* This function determines if the version specified has selectable
    signature/hash functions for certificate authentification. */
 int
@@ -1287,11 +1288,25 @@ _gnutls_version_has_selectable_sighash 
(gnutls_protocol_t version)
   return version == GNUTLS_TLS1_2;
 }
 
+/* This function determines if the version specified has selectable
+   signature/hash functions for certificate authentification. */
+int
+_gnutls_version_has_selectable_sighash (gnutls_protocol_t version)
+{
+  switch(version) {
+  case GNUTLS_TLS1_2:
+    return 1;
+  default:
+    return 0;
+  }
+}
+
 /* This function determines if the version specified has support for
    TLS extensions. */
 int
 _gnutls_version_has_extensions (gnutls_protocol_t version)
 {
+<<<<<<< HEAD:lib/gnutls_algorithms.c
   switch (version)
     {
     case GNUTLS_TLS1_0:
@@ -1332,6 +1347,44 @@ _gnutls_version_has_variable_padding (gnutls_protocol_t 
version)
     default:
       return 0;
     }
+=======
+  switch(version) {
+  case GNUTLS_TLS1_0:
+  case GNUTLS_TLS1_1:
+  case GNUTLS_TLS1_2:
+    return 1;
+  default:
+    return 0;
+  }
+>>>>>>> Do not rely on version ordering; use switch..case 
instead.:lib/gnutls_algorithms.c
+}
+
+/* This function determines if the version specified has explicit IVs
+   (for CBC attack prevention). */
+int
+_gnutls_version_has_explicit_iv (gnutls_protocol_t version)
+{
+  switch(version) {
+  case GNUTLS_TLS1_1:
+  case GNUTLS_TLS1_2:
+    return 1;
+  default:
+    return 0;
+  }
+}
+
+/* This function determines if the version specified can have
+   non-minimal padding. */
+int _gnutls_version_has_variable_padding (gnutls_protocol_t version)
+{
+  switch(version) {
+  case GNUTLS_TLS1_0:
+  case GNUTLS_TLS1_1:
+  case GNUTLS_TLS1_2:
+    return 1;
+  default:
+    return 0;
+  }
 }
 
 /* Type to KX mappings */
@@ -1908,6 +1961,10 @@ static const gnutls_sign_entry sign_algorithms[] = {
    GNUTLS_MAC_RMD160, TLS_SIGN_AID_UNKNOWN},
   {"DSA-SHA1", SIG_DSA_SHA1_OID, GNUTLS_SIGN_DSA_SHA1, GNUTLS_PK_DSA,
    GNUTLS_MAC_SHA1, {2, 2}},
+  {"DSA-SHA224", SIG_DSA_SHA224_OID, GNUTLS_SIGN_DSA_SHA224, GNUTLS_PK_DSA,
+   GNUTLS_MAC_SHA224, {3, 2}},
+  {"DSA-SHA256", SIG_DSA_SHA256_OID, GNUTLS_SIGN_DSA_SHA256, GNUTLS_PK_DSA,
+   GNUTLS_MAC_SHA256, {4, 2}},
   {"RSA-MD5", SIG_RSA_MD5_OID, GNUTLS_SIGN_RSA_MD5, GNUTLS_PK_RSA,
    GNUTLS_MAC_MD5, {1, 1}},
   {"RSA-MD2", SIG_RSA_MD2_OID, GNUTLS_SIGN_RSA_MD2, GNUTLS_PK_RSA,
@@ -2121,10 +2178,13 @@ struct gnutls_pk_entry
 typedef struct gnutls_pk_entry gnutls_pk_entry;
 
 static const gnutls_pk_entry pk_algorithms[] = {
+  /* having duplicate entries is ok, as long as the one
+   * we want to return OID from is first */
   {"RSA", PK_PKIX1_RSA_OID, GNUTLS_PK_RSA},
+  {"RSA (X.509)", PK_X509_RSA_OID, GNUTLS_PK_RSA},
   {"DSA", PK_DSA_OID, GNUTLS_PK_DSA},
-  {"GOST R 34.10-2001", PK_GOST_R3410_2001_OID, 0},
-  {"GOST R 34.10-94", PK_GOST_R3410_94_OID, 0},
+  {"GOST R 34.10-2001", PK_GOST_R3410_2001_OID, GNUTLS_PK_UNKNOWN},
+  {"GOST R 34.10-94", PK_GOST_R3410_94_OID, GNUTLS_PK_UNKNOWN},
   {0, 0, 0}
 };
 
@@ -2265,3 +2325,119 @@ _gnutls_x509_pk_to_oid (gnutls_pk_algorithm_t algorithm)
 
   return ret;
 }
+
+/**
+ * gnutls_sec_param_to_pk_bits:
+ * @algo: is a public key algorithm
+ * @param: is a security parameter
+ *
+ * When generating private and public key pairs a difficult question
+ * is which size of "bits" the modulus will be in RSA and the group size
+ * in DSA. The easy answer is 1024, which is also wrong. This function
+ * will convert a human understandable security parameter to an
+ * appropriate size for the specific algorithm.
+ *
+ * Returns: The number of bits, or zero.
+ *
+ **/
+unsigned int gnutls_sec_param_to_pk_bits (gnutls_pk_algorithm_t algo,
+                                      gnutls_sec_param_t param)
+{
+
+  switch(algo)
+    {
+      case GNUTLS_PK_RSA:
+      case GNUTLS_PK_DSA:
+        switch(param)
+          {
+            case GNUTLS_SEC_PARAM_LOW:
+              return 1024;
+            case GNUTLS_SEC_PARAM_HIGH:
+              return 3072;
+            case GNUTLS_SEC_PARAM_ULTRA:
+              return 7680;
+            case GNUTLS_SEC_PARAM_NORMAL:
+            default:
+              return 2048;
+          }
+        default:
+          gnutls_assert();
+          return 0;
+    }
+
+}
+
+/**
+ * gnutls_sec_param_get_name:
+ * @param: is a security parameter
+ *
+ * Convert a #gnutls_sec_param_t value to a string.
+ *
+ * Returns: a pointer to a string that contains the name of the
+ *   specified public key algorithm, or %NULL.
+ *
+ **/
+const char *
+gnutls_sec_param_get_name (gnutls_sec_param_t param)
+{
+  const char *p;
+
+  switch (param)
+    {
+    case GNUTLS_SEC_PARAM_WEAK:
+      p = "Weak";
+      break;
+
+    case GNUTLS_SEC_PARAM_LOW:
+      p = "Low";
+      break;
+
+    case GNUTLS_SEC_PARAM_NORMAL:
+      p = "Normal";
+      break;
+
+    case GNUTLS_SEC_PARAM_HIGH:
+      p = "High";
+      break;
+
+    case GNUTLS_SEC_PARAM_ULTRA:
+      p = "Ultra";
+      break;
+
+    default:
+      p = "Unknown";
+      break;
+    }
+
+  return p;
+}
+
+/**
+ * gnutls_pk_bits_to_sec_param:
+ * @algo: is a public key algorithm
+ * @bits: is the number of bits
+ *
+ * This is the inverse of gnutls_sec_param_to_pk_bits(). Given an algorithm
+ * and the number of bits, it will return the security parameter. This is
+ * a rough indication.
+ *
+ * Returns: The security parameter.
+ *
+ **/
+gnutls_sec_param_t gnutls_pk_bits_to_sec_param (gnutls_pk_algorithm_t algo,
+                                      unsigned int bits)
+{
+
+  /* currently we ignore algo */
+  if (bits >= 7680)
+    return GNUTLS_SEC_PARAM_ULTRA;
+  else if (bits >= 3072)
+    return GNUTLS_SEC_PARAM_HIGH;
+  else if (bits >= 2048)
+    return GNUTLS_SEC_PARAM_NORMAL;
+  else if (bits >= 1024)
+    return GNUTLS_SEC_PARAM_LOW;
+  else
+    return GNUTLS_SEC_PARAM_WEAK;
+
+}
diff --git a/lib/gnutls_buffers.c b/lib/gnutls_buffers.c
index 52f1a94..7d5a5d1 100644
--- a/lib/gnutls_buffers.c
+++ b/lib/gnutls_buffers.c
@@ -53,6 +53,7 @@
 #include <gnutls_num.h>
 #include <gnutls_record.h>
 #include <gnutls_buffers.h>
+#include <gnutls_mbuffers.h>
 
 #include <errno.h>
 
@@ -65,6 +66,7 @@
 # define EAGAIN EWOULDBLOCK
 #endif
 
+
 /**
  * gnutls_transport_set_errno:
  * @session: is a #gnutls_session_t structure.
@@ -347,36 +349,69 @@ finish:
 
   if (_gnutls_log_level >= 7)
     {
-      char line[128];
-      char tmp[16];
-
-
       _gnutls_read_log ("READ: read %d bytes from %p\n",
                        (int) (sizeOfPtr - left), fd);
 
-      for (x = 0; x < ((sizeOfPtr - left) / 16) + 1; x++)
-       {
-         line[0] = 0;
+      dump_bytes (ptr, sizeOfPtr - left, 0);
+    }
+
+  return (sizeOfPtr - left);
+}
 
-         sprintf (tmp, "%.4x - ", x);
-         _gnutls_str_cat (line, sizeof (line), tmp);
+static ssize_t
+_gnutls_write (gnutls_session_t session, void *iptr,
+              size_t sizeOfPtr)
+{
+  int i;
+  gnutls_transport_ptr_t fd = session->internals.transport_send_ptr;
 
-         for (j = 0; j < 16; j++)
+  session->internals.errnum = 0;
+
+  if (session->internals._gnutls_push_func == NULL)
+    {
+      i = send (GNUTLS_POINTER_TO_INT (fd), iptr, sizeOfPtr, 0);
+#if HAVE_WINSOCK2_H
+      if (i < 0)
+       {
+         int tmperr = WSAGetLastError ();
+         switch (tmperr)
            {
-             if (sum < (sizeOfPtr - left))
-               {
-                 sprintf (tmp, "%.2x ", ((unsigned char *) ptr)[sum++]);
-                 _gnutls_str_cat (line, sizeof (line), tmp);
-               }
+           case WSAEWOULDBLOCK:
+             session->internals.errnum = EAGAIN;
+             break;
+
+           case WSAEINTR:
+             session->internals.errnum = EINTR;
+             break;
+
+           default:
+             session->internals.errnum = EIO;
+             break;
            }
-         _gnutls_read_log ("%s\n", line);
+         WSASetLastError (tmperr);
        }
+#endif
     }
+  else
+    i = session->internals._gnutls_push_func (fd, iptr, sizeOfPtr);
 
-  return (sizeOfPtr - left);
-}
-
+  if (i == -1)
+    {
+      int err = session->internals.errnum ? session->internals.errnum
+       : errno;
 
+      if (err == EAGAIN)
+       return GNUTLS_E_AGAIN;
+      else if (err == EINTR)
+       return GNUTLS_E_INTERRUPTED;
+      else
+       {
+         gnutls_assert ();
+         return GNUTLS_E_PUSH_ERROR;
+       }
+    }
+  return i;
+}
 #define RCVLOWAT session->internals.lowat
 
 /* This function is only used with berkeley style sockets.
@@ -619,354 +654,158 @@ _gnutls_io_read_buffered (gnutls_session_t session, 
opaque ** iptr,
 /* This function is like write. But it does not return -1 on error.
  * It does return gnutls_errno instead.
  *
- * In case of E_AGAIN and E_INTERRUPTED errors, you must call 
gnutls_write_flush(),
- * until it returns ok (0).
+ * This function takes full responsibility of freeing msg->data.
+ *
+ * In case of E_AGAIN and E_INTERRUPTED errors, you must call
+ * gnutls_write_flush(), until it returns ok (0).
  *
- * We need to push exactly the data in n, since we cannot send less
- * data. In TLS the peer must receive the whole packet in order
- * to decrypt and verify the integrity. 
+ * We need to push exactly the data in msg->size, since we cannot send
+ * less data. In TLS the peer must receive the whole packet in order
+ * to decrypt and verify the integrity.
  *
  */
 ssize_t
 _gnutls_io_write_buffered (gnutls_session_t session,
-                          const void *iptr, size_t n)
+                          mbuffer_st *bufel)
 {
-  size_t left;
-  unsigned j, x, sum = 0;
-  ssize_t retval, i;
-  const opaque *ptr;
-  gnutls_transport_ptr_t fd = session->internals.transport_send_ptr;
-
-  /* to know where the procedure was interrupted.
-   */
-  session->internals.direction = 1;
-
-  ptr = iptr;
+  mbuffer_head_st * const send_buffer = &session->internals.record_send_buffer;
 
-  /* In case the previous write was interrupted, check if the
-   * iptr != NULL and we have data in the buffer.
-   * If this is true then return an error.
-   */
-  if (session->internals.record_send_buffer.length > 0 && iptr != NULL)
-    {
-      gnutls_assert ();
-      return GNUTLS_E_INVALID_REQUEST;
-    }
+  _gnutls_mbuffer_enqueue (send_buffer, bufel);
 
-  /* If data in the buffer exist
-   */
-  if (iptr == NULL)
-    {
-      gnutls_datum_t bdata;
-      /* checking is handled above */
-      _gnutls_buffer_get_datum (&session->internals.record_send_buffer,
-                               &bdata,
-                               session->internals.record_send_buffer.length);
+  _gnutls_write_log
+    ("WRITE: enqueued %d bytes for %p. Total %d bytes.\n",
+     (int)bufel->msg.size, session->internals.transport_recv_ptr,
+     (int)send_buffer->byte_length);
 
-      ptr = bdata.data;
-      n = bdata.size;
+  return _gnutls_io_write_flush (session);
+}
 
-      _gnutls_write_log
-       ("WRITE: Restoring old write. (%d bytes to send)\n", (int) n);
-    }
+/* This function writes the data that are left in the
+ * TLS write buffer (ie. because the previous write was
+ * interrupted.
+ */
+ssize_t
+_gnutls_io_write_flush (gnutls_session_t session)
+{
+  mbuffer_head_st * const send_buffer = &session->internals.record_send_buffer;
+  gnutls_datum_t msg;
+  int ret;
+  ssize_t total = 0;
 
-  _gnutls_write_log ("WRITE: Will write %d bytes to %p.\n", (int) n, fd);
+  _gnutls_write_log ("WRITE FLUSH: %d bytes in buffer.\n",
+                    (int)send_buffer->byte_length);
 
-  left = n;
-  while (left > 0)
+  for (_gnutls_mbuffer_get_head (send_buffer, &msg);
+       msg.data != NULL && msg.size > 0;
+       _gnutls_mbuffer_get_head (send_buffer, &msg))
     {
+      ret = _gnutls_write (session, msg.data, msg.size);
 
-      session->internals.errnum = 0;
-
-      if (session->internals._gnutls_push_func == NULL)
+      if (ret >= 0)
        {
-         i = send (GNUTLS_POINTER_TO_INT (fd), &ptr[n - left], left, 0);
-#if HAVE_WINSOCK2_H
-         if (i < 0)
-           {
-             int tmperr = WSAGetLastError ();
-             switch (tmperr)
-               {
-               case WSAEWOULDBLOCK:
-                 session->internals.errnum = EAGAIN;
-                 break;
+         dump_bytes (msg.data, msg.size, 1);
+         _gnutls_mbuffer_remove_bytes (send_buffer, ret);
 
-               case WSAEINTR:
-                 session->internals.errnum = EINTR;
-                 break;
+         _gnutls_write_log ("WRITE: wrote %d bytes, %d bytes left.\n",
+                            ret, (int)send_buffer->byte_length);
 
-               default:
-                 session->internals.errnum = EIO;
-                 break;
-               }
-             WSASetLastError (tmperr);
-           }
-#endif
+         total += ret;
        }
-      else
-       i = session->internals._gnutls_push_func (fd, &ptr[n - left], left);
-
-      if (i == -1)
+      else if (ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN)
        {
-         int err = session->internals.errnum ? session->internals.errnum
-           : errno;
-
-         if (err == EAGAIN || err == EINTR)
-           {
-             session->internals.record_send_buffer_prev_size += n - left;
-
-             retval =
-               _gnutls_buffer_append (&session->internals.record_send_buffer,
-                                      &ptr[n - left], left);
-             if (retval < 0)
-               {
-                 gnutls_assert ();
-                 return retval;
-               }
-
-             _gnutls_write_log
-               ("WRITE: Interrupted. Stored %d bytes to buffer. Already sent 
%d bytes.\n",
-                (int) left, (int) (n - left));
-
-             if (err == EAGAIN)
-               return GNUTLS_E_AGAIN;
-             return GNUTLS_E_INTERRUPTED;
-           }
-         else
-           {
-             gnutls_assert ();
-             return GNUTLS_E_PUSH_ERROR;
-           }
+         _gnutls_write_log ("WRITE interrupted: %d bytes left.\n",
+                            (int)send_buffer->byte_length);
+         return ret;
        }
-      left -= i;
-
-
-      if (_gnutls_log_level >= 7)
+      else
        {
-         char line[128];
-         char tmp[16];
-
-
-         _gnutls_write_log
-           ("WRITE: wrote %d bytes to %p. Left %d bytes. Total %d bytes.\n",
-            (int) i, fd, (int) left, (int) n);
-         for (x = 0; x < (unsigned) ((i) / 16) + 1; x++)
-           {
-             line[0] = 0;
+         _gnutls_write_log ("WRITE error: code %d, %d bytes left.\n",
+                            ret, (int)send_buffer->byte_length);
 
-             if (sum > n - left)
-               break;
-
-             sprintf (tmp, "%.4x - ", x);
-             _gnutls_str_cat (line, sizeof (line), tmp);
-
-             for (j = 0; j < 16; j++)
-               {
-                 if (sum < n - left)
-                   {
-                     sprintf (tmp, "%.2x ",
-                              ((const unsigned char *) ptr)[sum++]);
-                     _gnutls_str_cat (line, sizeof (line), tmp);
-                   }
-                 else
-                   break;
-               }
-             _gnutls_write_log ("%s\n", line);
-           }
+         gnutls_assert ();
+         return ret;
        }
     }
 
-  retval = n + session->internals.record_send_buffer_prev_size;
-
-  session->internals.record_send_buffer.length = 0;
-  session->internals.record_send_buffer_prev_size = 0;
-
-  return retval;
-
+  return total;
 }
 
 /* This function writes the data that are left in the
- * TLS write buffer (ie. because the previous write was
+ * Handshake write buffer (ie. because the previous write was
  * interrupted.
+ *
+ * FIXME: This is practically the same as _gnutls_io_write_flush.
  */
 ssize_t
-_gnutls_io_write_flush (gnutls_session_t session)
+_gnutls_handshake_io_write_flush (gnutls_session_t session)
 {
-  ssize_t ret;
+  mbuffer_head_st * const send_buffer = 
&session->internals.handshake_send_buffer;
+  gnutls_datum_t msg;
+  int ret;
+  ssize_t total = 0;
 
-  if (session->internals.record_send_buffer.length == 0)
-    return 0;                  /* done */
+  _gnutls_write_log ("HWRITE FLUSH: %d bytes in buffer.\n",
+                    (int)send_buffer->byte_length);
 
-  ret = _gnutls_io_write_buffered (session, NULL, 0);
-  _gnutls_write_log ("WRITE FLUSH: %d [buffer: %d]\n", (int) ret,
-                    (int) session->internals.record_send_buffer.length);
+  for (_gnutls_mbuffer_get_head (send_buffer, &msg);
+       msg.data != NULL && msg.size > 0;
+       _gnutls_mbuffer_get_head (send_buffer, &msg))
+    {
+      ret = _gnutls_send_int (session, GNUTLS_HANDSHAKE,
+                             session->internals.handshake_send_buffer_htype,
+                             msg.data, msg.size);
 
-  return ret;
-}
+      if (ret >= 0)
+       {
+         dump_bytes (msg.data, msg.size, 1);
+         _gnutls_mbuffer_remove_bytes (send_buffer, ret);
 
-/* This function writes the data that are left in the
- * Handshake write buffer (ie. because the previous write was
- * interrupted.
- */
-ssize_t
-_gnutls_handshake_io_write_flush (gnutls_session_t session)
-{
-  ssize_t ret;
-  ret = _gnutls_handshake_io_send_int (session, 0, 0, NULL, 0);
-  if (ret < 0)
-    {
-      gnutls_assert ();
-      return ret;
-    }
+         _gnutls_write_log ("HWRITE: wrote %d bytes, %d bytes left.\n",
+                            ret, (int)send_buffer->byte_length);
 
-  _gnutls_write_log ("HANDSHAKE_FLUSH: written[1] %d bytes\n", (int) ret);
+         total += ret;
+       }
+      else if (ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN)
+       {
+         _gnutls_write_log ("HWRITE interrupted: %d bytes left.\n",
+                            (int)send_buffer->byte_length);
+         return ret;
+       }
+      else
+       {
+         _gnutls_write_log ("HWRITE error: code %d, %d bytes left.\n",
+                            ret, (int)send_buffer->byte_length);
 
-  if (session->internals.handshake_send_buffer.length == 0)
-    {
-      ret = session->internals.handshake_send_buffer_prev_size;        /* done 
*/
-      session->internals.handshake_send_buffer_prev_size = 0;
+         gnutls_assert ();
+         return ret;
+       }
     }
 
-  return ret;
+  return total;
 }
 
 
 /* This is a send function for the gnutls handshake 
  * protocol. Just makes sure that all data have been sent.
+ *
+ * FIXME: This is practically the same as _gnutls_io_write_buffered.
  */
 ssize_t
 _gnutls_handshake_io_send_int (gnutls_session_t session,
-                              content_type_t type,
                               gnutls_handshake_description_t htype,
-                              const void *iptr, size_t n)
+                              mbuffer_st *bufel)
 {
-  size_t left;
-  ssize_t ret = 0;
-  const opaque *ptr;
-  ssize_t retval = 0;
-
-  ptr = iptr;
-
-  if (session->internals.handshake_send_buffer.length > 0 && ptr == NULL
-      && n == 0)
-    {
-      gnutls_datum_t bdata;
-
-      /* resuming previously interrupted write
-       */
-      gnutls_assert ();
-
-      /* checking is handled above */
-      _gnutls_buffer_get_datum (&session->internals.handshake_send_buffer,
-                               &bdata,
-                               session->internals.handshake_send_buffer.
-                               length);
-
-      ptr = bdata.data;
-      n = bdata.size;
-
-      type = session->internals.handshake_send_buffer_type;
-      htype = session->internals.handshake_send_buffer_htype;
-
-    }
-  else if (session->internals.handshake_send_buffer.length > 0)
-    {
-      gnutls_assert ();
-      return GNUTLS_E_INTERNAL_ERROR;
-    }
-#ifdef WRITE_DEBUG
-  else
-    {
-      size_t sum = 0, x, j;
-
-      _gnutls_write_log ("HWRITE: will write %d bytes to %d.\n", n,
-                        gnutls_transport_get_ptr (session));
-      for (x = 0; x < ((n) / 16) + 1; x++)
-       {
-         if (sum > n)
-           break;
-
-         _gnutls_write_log ("%.4x - ", x);
-         for (j = 0; j < 16; j++)
-           {
-             if (sum < n)
-               {
-                 _gnutls_write_log ("%.2x ", ((unsigned char *) ptr)[sum++]);
-               }
-             else
-               break;
-           }
-         _gnutls_write_log ("\n");
-       }
-      _gnutls_write_log ("\n");
-    }
-#endif
-
-  if (n == 0)
-    {                          /* if we have no data to send */
-      gnutls_assert ();
-      return 0;
-    }
-  else if (ptr == NULL)
-    {
-      gnutls_assert ();
-      return GNUTLS_E_INTERNAL_ERROR;
-    }
-
-
-  left = n;
-  while (left > 0)
-    {
-      ret = _gnutls_send_int (session, type, htype, &ptr[n - left], left);
-
-      if (ret <= 0)
-       {
-         if (ret == 0)
-           {
-             gnutls_assert ();
-             ret = GNUTLS_E_INTERNAL_ERROR;
-           }
-
-         if (left > 0
-             && (ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN))
-           {
-             gnutls_assert ();
-
-             retval =
-               _gnutls_buffer_append (&session->
-                                      internals.handshake_send_buffer,
-                                      &ptr[n - left], left);
-             if (retval < 0)
-               {
-                 gnutls_assert ();
-                 return retval;
-               }
-
-             session->internals.handshake_send_buffer_prev_size += n - left;
-
-             session->internals.handshake_send_buffer_type = type;
-             session->internals.handshake_send_buffer_htype = htype;
-
-           }
-         else
-           {
-             session->internals.handshake_send_buffer_prev_size = 0;
-             session->internals.handshake_send_buffer.length = 0;
-           }
-
-         gnutls_assert ();
-         return ret;
-       }
-      left -= ret;
-    }
-
-  retval = n + session->internals.handshake_send_buffer_prev_size;
+  mbuffer_head_st * const send_buffer = 
&session->internals.handshake_send_buffer;
 
-  session->internals.handshake_send_buffer.length = 0;
-  session->internals.handshake_send_buffer_prev_size = 0;
+  _gnutls_mbuffer_enqueue (send_buffer, bufel);
+  session->internals.handshake_send_buffer_htype = htype;
 
-  return retval;
+  _gnutls_write_log
+    ("HWRITE: enqueued %d. Total %d bytes.\n",
+     (int)bufel->msg.size,
+     (int)send_buffer->byte_length);
 
+  return _gnutls_handshake_io_write_flush(session);
 }
 
 /* This is a receive function for the gnutls handshake 
diff --git a/lib/gnutls_buffers.h b/lib/gnutls_buffers.h
index 7c9f174..6d52f4e 100644
--- a/lib/gnutls_buffers.h
+++ b/lib/gnutls_buffers.h
@@ -36,10 +36,8 @@ ssize_t _gnutls_io_read_buffered (gnutls_session_t, opaque 
** iptr,
 void _gnutls_io_clear_read_buffer (gnutls_session_t);
 int _gnutls_io_clear_peeked_data (gnutls_session_t session);
 
-ssize_t _gnutls_io_write_buffered (gnutls_session_t, const void *iptr,
-                                  size_t n);
-ssize_t _gnutls_io_write_buffered2 (gnutls_session_t, const void *iptr,
-                                   size_t n, const void *iptr2, size_t n2);
+ssize_t _gnutls_io_write_buffered (gnutls_session_t session,
+                                  mbuffer_st *bufel);
 
 int _gnutls_handshake_buffer_get_size (gnutls_session_t session);
 int _gnutls_handshake_buffer_put (gnutls_session_t session, opaque * data,
@@ -50,15 +48,14 @@ int _gnutls_handshake_buffer_get_ptr (gnutls_session_t 
session,
                                      opaque ** data_ptr, size_t * length);
 
 #define _gnutls_handshake_io_buffer_clear( session) \
-        _gnutls_buffer_clear( &session->internals.handshake_send_buffer); \
-        _gnutls_buffer_clear( &session->internals.handshake_recv_buffer); \
-        session->internals.handshake_send_buffer_prev_size = 0
+        _gnutls_mbuffer_clear( &session->internals.handshake_send_buffer); \
+        _gnutls_buffer_clear( &session->internals.handshake_recv_buffer);
 
 ssize_t _gnutls_handshake_io_recv_int (gnutls_session_t, content_type_t,
                                       gnutls_handshake_description_t, void *,
                                       size_t);
-ssize_t _gnutls_handshake_io_send_int (gnutls_session_t, content_type_t,
+ssize_t _gnutls_handshake_io_send_int (gnutls_session_t,
                                       gnutls_handshake_description_t,
-                                      const void *, size_t);
+                                      mbuffer_st *bufel);
 ssize_t _gnutls_io_write_flush (gnutls_session_t session);
 ssize_t _gnutls_handshake_io_write_flush (gnutls_session_t session);
diff --git a/lib/gnutls_cert.c b/lib/gnutls_cert.c
index 5072c8e..2f41f28 100644
--- a/lib/gnutls_cert.c
+++ b/lib/gnutls_cert.c
@@ -76,7 +76,7 @@ gnutls_certificate_free_keys 
(gnutls_certificate_credentials_t sc)
 
   for (i = 0; i < sc->ncerts; i++)
     {
-      _gnutls_gkey_deinit (&sc->pkey[i]);
+      gnutls_privkey_deinit (sc->pkey[i]);
     }
 
   gnutls_free (sc->pkey);
@@ -426,6 +426,46 @@ void gnutls_certificate_server_set_retrieve_function
 }
 
 /**
+ * gnutls_certificate_set_retrieve_function:
+ * @cred: is a #gnutls_certificate_credentials_t structure.
+ * @func: is the callback function
+ *
+ * This function sets a callback to be called in order to retrieve the
+ * certificate to be used in the handshake.
+ *
+ * The callback's function prototype is:
+ * int (*callback)(gnutls_session_t, const gnutls_datum_t* req_ca_dn, int 
nreqs,
+ * const gnutls_pk_algorithm_t* pk_algos, int pk_algos_length, 
gnutls_retr2_st* st);
+ *
+ * @req_ca_cert is only used in X.509 certificates.
+ * Contains a list with the CA names that the server considers trusted.
+ * Normally we should send a certificate that is signed
+ * by one of these CAs. These names are DER encoded. To get a more
+ * meaningful value use the function gnutls_x509_rdn_get().
+ *
+ * @pk_algos contains a list with server's acceptable signature algorithms.
+ * The certificate returned should support the server's given algorithms.
+ *
+ * @st should contain the certificates and private keys.
+ *
+ * If the callback function is provided then gnutls will call it, in the
+ * handshake, after the certificate request message has been received.
+ *
+ * In server side pk_algos and req_ca_dn are NULL.
+ *
+ * The callback function should set the certificate list to be sent,
+ * and return 0 on success. If no certificate was selected then the
+ * number of certificates should be set to zero. The value (-1)
+ * indicates error and the handshake will be terminated.
+ **/
+void gnutls_certificate_set_retrieve_function
+  (gnutls_certificate_credentials_t cred,
+   gnutls_certificate_retrieve_function * func)
+{
+  cred->get_cert_callback = func;
+}
+
+/**
  * gnutls_certificate_set_verify_function:
  * @cred: is a #gnutls_certificate_credentials_t structure.
  * @func: is the callback function
diff --git a/lib/gnutls_cert.h b/lib/gnutls_cert.h
index 7280899..4217d29 100644
--- a/lib/gnutls_cert.h
+++ b/lib/gnutls_cert.h
@@ -82,28 +82,6 @@ typedef struct gnutls_cert
 #endif
 } gnutls_cert;
 
-typedef struct gnutls_privkey_int
-{
-  /* the size of params depends on the public
-   * key algorithm
-   * RSA: [0] is modulus
-   *      [1] is public exponent
-   *      [2] is private exponent
-   *      [3] is prime1 (p)
-   *      [4] is prime2 (q)
-   *      [5] is coefficient (u == inverse of p mod q)
-   * DSA: [0] is p
-   *      [1] is q
-   *      [2] is g
-   *      [3] is y (public key)
-   *      [4] is x (private key)
-   */
-  bigint_t params[MAX_PRIV_PARAMS_SIZE];
-  int params_size;             /* holds the number of params */
-
-  gnutls_pk_algorithm_t pk_algorithm;
-} gnutls_privkey;
-
 /* because gnutls_session_t is not defined when this file is included */
 struct gnutls_session_int;
 
@@ -120,7 +98,6 @@ int _gnutls_x509_raw_cert_to_gcert (gnutls_cert * gcert,
 int _gnutls_x509_crt_to_gcert (gnutls_cert * gcert, gnutls_x509_crt_t cert,
                               unsigned int flags);
 
-void _gnutls_gkey_deinit (gnutls_privkey * key);
 void _gnutls_gcert_deinit (gnutls_cert * cert);
 
 int _gnutls_selected_cert_supported_kx (struct gnutls_session_int *session,
diff --git a/lib/gnutls_cipher.c b/lib/gnutls_cipher.c
index e51a477..5e327e2 100644
--- a/lib/gnutls_cipher.c
+++ b/lib/gnutls_cipher.c
@@ -447,6 +447,7 @@ _gnutls_compressed2ciphertext (gnutls_session_t session,
   return length;
 }
 
+
 /* Deciphers the ciphertext packet, and puts the result to compress_data, of 
compress_size.
  * Returns the actual compressed packet size.
  */
diff --git a/lib/gnutls_constate.c b/lib/gnutls_constate.c
index bd3622b..f6d58cc 100644
--- a/lib/gnutls_constate.c
+++ b/lib/gnutls_constate.c
@@ -116,7 +116,7 @@ _gnutls_set_keys (gnutls_session_t session, int hash_size, 
int IV_size,
 
   _gnutls_hard_log ("INT: KEY BLOCK[%d]: %s\n", block_size,
                    _gnutls_bin2hex (key_block, block_size, buf,
-                                    sizeof (buf)));
+                                    sizeof (buf), NULL));
 
   _gnutls_free_datum (&session->cipher_specs.server_write_mac_secret);
   _gnutls_free_datum (&session->cipher_specs.client_write_mac_secret);
@@ -242,7 +242,7 @@ _gnutls_set_keys (gnutls_session_t session, int hash_size, 
int IV_size,
                        client_write_key_size,
                        _gnutls_bin2hex (client_write_key,
                                         client_write_key_size, buf,
-                                        sizeof (buf)));
+                                        sizeof (buf), NULL));
 
       if (_gnutls_sset_datum
          (&session->cipher_specs.server_write_key,
@@ -256,7 +256,7 @@ _gnutls_set_keys (gnutls_session_t session, int hash_size, 
int IV_size,
                        server_write_key_size,
                        _gnutls_bin2hex (server_write_key,
                                         server_write_key_size, buf,
-                                        sizeof (buf)));
+                                        sizeof (buf), NULL));
 
     }
 
diff --git a/lib/gnutls_dh_primes.c b/lib/gnutls_dh_primes.c
index c47237c..194de23 100644
--- a/lib/gnutls_dh_primes.c
+++ b/lib/gnutls_dh_primes.c
@@ -50,9 +50,6 @@ _gnutls_dh_params_to_mpi (gnutls_dh_params_t dh_primes)
 }
 
 
-/* Replaces the prime in the static DH parameters, with a randomly
- * generated one.
- */
 /**
  * gnutls_dh_params_import_raw:
  * @dh_params: Is a structure that will hold the prime numbers
@@ -178,7 +175,8 @@ gnutls_dh_params_cpy (gnutls_dh_params_t dst, 
gnutls_dh_params_t src)
  * gnutls_malloc() and will be stored in the appropriate datum.
  * This function is normally slow.
  *
- * Note that the bits value should be one of 768, 1024, 2048, 3072 or 4096.
+ * Do not set the number of bits directly, use gnutls_sec_param_to_pk_bits() to
+ * get bits for %GNUTLS_PK_DSA.
  * Also note that the DH parameters are only useful to servers.
  * Since clients use the parameters sent by the server, it's of
  * no use to call this in client side.
@@ -355,11 +353,12 @@ gnutls_dh_params_export_pkcs3 (gnutls_dh_params_t params,
     }
 
   p_data = &all_data[0];
-  g_data = &all_data[p_size];
-
   _gnutls_mpi_print_lz (params->params[0], p_data, &p_size);
+
+  g_data = &all_data[p_size];
   _gnutls_mpi_print_lz (params->params[1], g_data, &g_size);
 
+
   /* Ok. Now we have the data. Create the asn1 structures
    */
 
diff --git a/lib/gnutls_errors.c b/lib/gnutls_errors.c
index 8b0afd3..85d4bd6 100644
--- a/lib/gnutls_errors.c
+++ b/lib/gnutls_errors.c
@@ -274,6 +274,17 @@ static const gnutls_error_entry error_algorithms[] = {
   ERROR_ENTRY (N_("Error interfacing with /dev/crypto"),
               GNUTLS_E_CRYPTODEV_IOCTL_ERROR, 1),
 
+  ERROR_ENTRY (N_("PKCS #11 error."),
+              GNUTLS_E_PKCS11_ERROR, 1),
+  ERROR_ENTRY (N_("PKCS #11 initialization error."),
+              GNUTLS_E_PKCS11_LOAD_ERROR, 1),
+  ERROR_ENTRY (N_("Error in parsing."),
+              GNUTLS_E_PARSING_ERROR, 1),
+  ERROR_ENTRY (N_("PKCS #11 error in PIN."),
+              GNUTLS_E_PKCS11_PIN_ERROR, 1),
+  ERROR_ENTRY (N_("PKCS #11 error"),
+              GNUTLS_E_PKCS11_ERROR, 1),
+
   {NULL, NULL, 0, 0}
 };
 
@@ -487,7 +498,7 @@ _gnutls_mpi_log (const char *prefix, bigint_t a)
       return;
     }
 
-  _gnutls_bin2hex (binbuf, binlen, hexbuf, hexlen);
+  _gnutls_bin2hex (binbuf, binlen, hexbuf, hexlen, NULL);
 
   _gnutls_hard_log ("MPI: length: %d\n\t%s%s\n", (int) binlen, prefix,
                    hexbuf);
diff --git a/lib/gnutls_errors.h b/lib/gnutls_errors.h
index e6085ed..8bc0c6f 100644
--- a/lib/gnutls_errors.h
+++ b/lib/gnutls_errors.h
@@ -53,11 +53,11 @@ _gnutls_log (int, const char *fmt, ...)
      void _gnutls_mpi_log (const char *prefix, bigint_t a);
 
 #ifdef C99_MACROS
-#define LEVEL(l, ...) if (_gnutls_log_level >= l || _gnutls_log_level > 9) \
-       _gnutls_log( l, __VA_ARGS__)
+#define LEVEL(l, ...) do { if (_gnutls_log_level >= l || _gnutls_log_level > 
9) \
+      _gnutls_log( l, __VA_ARGS__); } while(0)
 
-#define LEVEL_EQ(l, ...) if (_gnutls_log_level == l || _gnutls_log_level > 9) \
-       _gnutls_log( l, __VA_ARGS__)
+#define LEVEL_EQ(l, ...) do { if (_gnutls_log_level == l || _gnutls_log_level 
> 9) \
+      _gnutls_log( l, __VA_ARGS__); } while(0)
 
 # define _gnutls_debug_log(...) LEVEL(2, __VA_ARGS__)
 # define _gnutls_handshake_log(...) LEVEL(3, __VA_ARGS__)
diff --git a/lib/gnutls_global.c b/lib/gnutls_global.c
index e74c161..69914e3 100644
--- a/lib/gnutls_global.c
+++ b/lib/gnutls_global.c
@@ -28,8 +28,14 @@
 #include <libtasn1.h>
 #include <gnutls_dh.h>
 #include <random.h>
+#ifndef HAVE_LIBNETTLE
 #include <gcrypt.h>
 
+#define GNUTLS_MIN_LIBGCRYPT_VERSION "1.2.4"
+
+#endif
+#include <gnutls/pkcs11.h>
+
 #include <gnutls_extensions.h> /* for _gnutls_ext_init */
 #include <gnutls_cryptodev.h>
 
@@ -37,7 +43,6 @@
 #include "gettext.h"
 
 /* Minimum library versions we accept. */
-#define GNUTLS_MIN_LIBGCRYPT_VERSION "1.2.4"
 #define GNUTLS_MIN_LIBTASN1_VERSION "0.3.4"
 
 /* created by asn1c */
@@ -183,6 +188,7 @@ gnutls_global_init (void)
 
   bindtextdomain (PACKAGE, LOCALEDIR);
 
+#ifndef HAVE_LIBNETTLE
   /* Initialize libgcrypt if it hasn't already been initialized. */
   if (gcry_control (GCRYCTL_ANY_INITIALIZATION_P) == 0)
     {
@@ -203,8 +209,10 @@ gnutls_global_init (void)
       gcry_control (GCRYCTL_DISABLE_SECMEM, NULL, 0);
 
       gcry_control (GCRYCTL_INITIALIZATION_FINISHED, NULL, 0);
+      
+      gcry_control (GCRYCTL_ENABLE_QUICK_RANDOM, 0);
     }
-
+#endif
   /* initialize ASN.1 parser
    * This should not deal with files in the final
    * version.
@@ -249,6 +257,8 @@ gnutls_global_init (void)
       goto out;
     }
 
+  gnutls_pkcs11_init(GNUTLS_PKCS11_FLAG_AUTO, NULL);
+  
   _gnutls_cryptodev_init ();
 
 out:
@@ -276,6 +286,7 @@ gnutls_global_deinit (void)
       asn1_delete_structure (&_gnutls_pkix1_asn);
       _gnutls_crypto_deregister ();
       _gnutls_cryptodev_deinit ();
+      gnutls_pkcs11_deinit();
     }
   _gnutls_init--;
 }
diff --git a/lib/gnutls_handshake.c b/lib/gnutls_handshake.c
index a597254..e03280c 100644
--- a/lib/gnutls_handshake.c
+++ b/lib/gnutls_handshake.c
@@ -34,6 +34,7 @@
 #include "gnutls_compress.h"
 #include "gnutls_cipher.h"
 #include "gnutls_buffers.h"
+#include "gnutls_mbuffers.h"
 #include "gnutls_kx.h"
 #include "gnutls_handshake.h"
 #include "gnutls_num.h"
@@ -75,6 +76,27 @@ _gnutls_handshake_hash_add_recvd (gnutls_session_t session,
                                  opaque * dataptr, uint32_t datalen);
 
 
+mbuffer_st*
+_gnutls_handshake_alloc(size_t size)
+{
+  mbuffer_st *ret = _gnutls_mbuffer_alloc (HANDSHAKE_HEADER_SIZE + size);
+
+  if (!ret)
+    return NULL;
+
+  ret->mark = HANDSHAKE_HEADER_SIZE;
+
+  return ret;
+}
+
+mbuffer_st*
+_gnutls_handshake_realloc(mbuffer_st *bufel, size_t size)
+{
+  mbuffer_st *ret = _gnutls_mbuffer_realloc (bufel, HANDSHAKE_HEADER_SIZE + 
size);
+
+  return ret;
+}
+
 /* Clears the handshake hash buffers and handles.
  */
 void
@@ -646,13 +668,19 @@ _gnutls_handshake_hash_pending (gnutls_session_t session)
 static int
 _gnutls_send_finished (gnutls_session_t session, int again)
 {
-  uint8_t data[MAX_VERIFY_DATA_SIZE];
+  mbuffer_st *bufel;
+  opaque *data;
   int ret;
-  int data_size = 0;
-
 
   if (again == 0)
     {
+      bufel = _gnutls_handshake_alloc (MAX_VERIFY_DATA_SIZE);
+      if (bufel == NULL)
+       {
+         gnutls_assert ();
+         return GNUTLS_E_MEMORY_ERROR;
+       }
+      data = bufel->msg.data + bufel->mark;
 
       /* This is needed in order to hash all the required
        * messages.
@@ -668,13 +696,12 @@ _gnutls_send_finished (gnutls_session_t session, int 
again)
          ret =
            _gnutls_ssl3_finished (session,
                                   session->security_parameters.entity, data);
-         data_size = 36;
        }
       else
        {                       /* TLS 1.0+ */
          ret = _gnutls_finished (session,
                                  session->security_parameters.entity, data);
-         data_size = 12;
+         bufel->msg.size = 12 + bufel->mark;
        }
 
       if (ret < 0)
@@ -684,38 +711,15 @@ _gnutls_send_finished (gnutls_session_t session, int 
again)
        }
 
       if (session->internals.finished_func)
-       session->internals.finished_func (session, data, data_size);
-    }
-
-  /* Save data for safe renegotiation. 
-   */
-  if (data_size > MAX_VERIFY_DATA_SIZE)
-    {
-      gnutls_assert ();
-      return GNUTLS_E_UNEXPECTED_PACKET_LENGTH;
-    }
-
-  if (session->security_parameters.entity == GNUTLS_CLIENT)
-    {
-      session->security_parameters.extensions.client_verify_data_len =
-       data_size;
+       session->internals.finished_func (session, data, bufel->msg.size - 
bufel->mark);
 
-      memcpy (session->security_parameters.extensions.client_verify_data,
-             data, data_size);
+      ret = _gnutls_send_handshake (session, bufel, GNUTLS_HANDSHAKE_FINISHED);
     }
   else
     {
-      session->security_parameters.extensions.server_verify_data_len =
-       data_size;
-
-      memcpy (session->security_parameters.extensions.server_verify_data,
-             data, data_size);
+      ret = _gnutls_send_handshake (session, NULL, GNUTLS_HANDSHAKE_FINISHED);
     }
 
-  ret =
-    _gnutls_send_handshake (session, data_size ? data : NULL, data_size,
-                           GNUTLS_HANDSHAKE_FINISHED);
-
   return ret;
 }
 
@@ -1057,15 +1061,21 @@ static int
 _gnutls_send_empty_handshake (gnutls_session_t session,
                              gnutls_handshake_description_t type, int again)
 {
-  opaque data = 0;
-  opaque *ptr;
+  mbuffer_st *bufel;
 
   if (again == 0)
-    ptr = &data;
+    {
+      bufel = _gnutls_handshake_alloc (0);
+      if (bufel == NULL)
+       {
+         gnutls_assert ();
+         return GNUTLS_E_MEMORY_ERROR;
+       }
+    }
   else
-    ptr = NULL;
+    bufel = NULL;
 
-  return _gnutls_send_handshake (session, ptr, 0, type);
+  return _gnutls_send_handshake (session, bufel, type);
 }
 
 
@@ -1127,8 +1137,7 @@ _gnutls_handshake_hash_add_sent (gnutls_session_t session,
  * (until it returns ok), with NULL parameters.
  */
 int
-_gnutls_send_handshake (gnutls_session_t session, void *i_data,
-                       uint32_t i_datasize,
+_gnutls_send_handshake (gnutls_session_t session, mbuffer_st *bufel,
                        gnutls_handshake_description_t type)
 {
   int ret;
@@ -1136,7 +1145,7 @@ _gnutls_send_handshake (gnutls_session_t session, void 
*i_data,
   uint32_t datasize;
   int pos = 0;
 
-  if (i_data == NULL && i_datasize == 0)
+  if (bufel == NULL)
     {
       /* we are resuming a previously interrupted
        * send.
@@ -1146,27 +1155,15 @@ _gnutls_send_handshake (gnutls_session_t session, void 
*i_data,
 
     }
 
-  if (i_data == NULL && i_datasize > 0)
-    {
-      gnutls_assert ();
-      return GNUTLS_E_INVALID_REQUEST;
-    }
-
   /* first run */
-  datasize = i_datasize + HANDSHAKE_HEADER_SIZE;
-  data = gnutls_malloc (datasize);
-  if (data == NULL)
-    {
-      gnutls_assert ();
-      return GNUTLS_E_MEMORY_ERROR;
-    }
+  data = _mbuffer_get_uhead_ptr(bufel);
+  datasize = _mbuffer_get_udata_size(bufel) + _mbuffer_get_uhead_size(bufel);
 
   data[pos++] = (uint8_t) type;
-  _gnutls_write_uint24 (i_datasize, &data[pos]);
+  _gnutls_write_uint24 (bufel->msg.size - bufel->mark, &data[pos]);
   pos += 3;
 
-  if (i_datasize > 0)
-    memcpy (&data[pos], i_data, i_datasize);
+  bufel->mark = 0;
 
   _gnutls_handshake_log ("HSK[%p]: %s was sent [%ld bytes]\n",
                         session, _gnutls_handshake2str (type),
@@ -1180,17 +1177,13 @@ _gnutls_send_handshake (gnutls_session_t session, void 
*i_data,
         _gnutls_handshake_hash_add_sent (session, type, data, datasize)) < 0)
       {
        gnutls_assert ();
-       gnutls_free (data);
+       gnutls_free (bufel);
        return ret;
       }
 
   session->internals.last_handshake_out = type;
 
-  ret =
-    _gnutls_handshake_io_send_int (session, GNUTLS_HANDSHAKE, type,
-                                  data, datasize);
-
-  gnutls_free (data);
+  ret = _gnutls_handshake_io_send_int (session, type, bufel);
 
   return ret;
 }
@@ -1669,7 +1662,7 @@ _gnutls_client_check_if_resuming (gnutls_session_t 
session,
                         session_id_len);
   _gnutls_handshake_log ("HSK[%p]: SessionID: %s\n", session,
                         _gnutls_bin2hex (session_id, session_id_len, buf,
-                                         sizeof (buf)));
+                                         sizeof (buf), NULL));
 
   if (session_id_len > 0 &&
       session->internals.resumed_security_parameters.session_id_size ==
@@ -1948,6 +1941,7 @@ _gnutls_copy_comp_methods (gnutls_session_t session,
 static int
 _gnutls_send_client_hello (gnutls_session_t session, int again)
 {
+  mbuffer_st *bufel = NULL;
   opaque *data = NULL;
   int extdatalen;
   int pos = 0, type;
@@ -1971,12 +1965,13 @@ _gnutls_send_client_hello (gnutls_session_t session, 
int again)
       /* 2 for version, (4 for unix time + 28 for random 
bytes==GNUTLS_RANDOM_SIZE) 
        */
 
-      data = gnutls_malloc (datalen);
-      if (data == NULL)
+      bufel = _gnutls_handshake_alloc (datalen);
+      if (bufel == NULL)
        {
          gnutls_assert ();
          return GNUTLS_E_MEMORY_ERROR;
        }
+      data = bufel->msg.data + bufel->mark;
 
       extdatalen = MAX_EXT_DATA_LENGTH
        +
@@ -2009,8 +2004,7 @@ _gnutls_send_client_hello (gnutls_session_t session, int 
again)
       if (hver == GNUTLS_VERSION_UNKNOWN || hver == 0)
        {
          gnutls_assert ();
-         gnutls_free (data);
-         gnutls_free (extdata);
+         gnutls_free (bufel);
          return GNUTLS_E_INTERNAL_ERROR;
        }
 
@@ -2021,15 +2015,10 @@ _gnutls_send_client_hello (gnutls_session_t session, 
int again)
        * (RSA uses it).
        */
       _gnutls_set_adv_version (session, hver);
+      _gnutls_set_current_version (session, hver);
 
       if (session->internals.priorities.ssl3_record_version)
        {
-         /* Honor the SSL3_RECORD_VERSION option
-          */
-         _gnutls_set_current_version (session, GNUTLS_SSL3);
-       }
-      else
-       {
          /* Some old implementations do not interoperate if we send a
           * different version in the record layer.
           * It seems they prefer to read the record's version
@@ -2038,7 +2027,7 @@ _gnutls_send_client_hello (gnutls_session_t session, int 
again)
           * handshake packet and ignore the one in the packet's record 
           * header.
           */
-         _gnutls_set_current_version (session, hver);
+         _gnutls_record_set_default_version (session, 3, 0);
        }
 
       /* In order to know when this session was initiated.
@@ -2076,24 +2065,15 @@ _gnutls_send_client_hello (gnutls_session_t session, 
int again)
          session->security_parameters.entity == GNUTLS_CLIENT &&
          gnutls_protocol_get_version (session) == GNUTLS_SSL3)
        {
-         ret =
-           _gnutls_copy_ciphersuites (session, extdata, extdatalen, TRUE);
-         _gnutls_extension_list_add (session,
-                                     GNUTLS_EXTENSION_SAFE_RENEGOTIATION);
-       }
-      else
-       ret = _gnutls_copy_ciphersuites (session, extdata, extdatalen, FALSE);
-
-      if (ret > 0)
-       {
-         datalen += ret;
-         data = gnutls_realloc_fast (data, datalen);
-         if (data == NULL)
+         datalen += extdatalen;
+         bufel = _gnutls_handshake_realloc (bufel, datalen);
+         if (bufel == NULL)
            {
              gnutls_assert ();
              gnutls_free (extdata);
              return GNUTLS_E_MEMORY_ERROR;
            }
+         data = bufel->msg.data + bufel->mark;
 
          memcpy (&data[pos], extdata, ret);
          pos += ret;
@@ -2101,10 +2081,9 @@ _gnutls_send_client_hello (gnutls_session_t session, int 
again)
        }
       else
        {
-         if (ret == 0)
-           ret = GNUTLS_E_INTERNAL_ERROR;
-         gnutls_free (data);
-         gnutls_free (extdata);
+         if (extdatalen == 0)
+           extdatalen = GNUTLS_E_INTERNAL_ERROR;
+         gnutls_free (bufel);
          gnutls_assert ();
          return ret;
        }
@@ -2115,29 +2094,29 @@ _gnutls_send_client_hello (gnutls_session_t session, 
int again)
       ret = _gnutls_copy_comp_methods (session, extdata, extdatalen);
       if (ret > 0)
        {
-         datalen += ret;
-         data = gnutls_realloc_fast (data, datalen);
-         if (data == NULL)
+         datalen += extdatalen;
+         bufel = _gnutls_handshake_realloc (bufel, datalen);
+         if (bufel == NULL)
            {
              gnutls_assert ();
              gnutls_free (extdata);
              return GNUTLS_E_MEMORY_ERROR;
            }
+         data = bufel->msg.data + bufel->mark;
 
-         memcpy (&data[pos], extdata, ret);
-         pos += ret;
-
+         memcpy (&data[pos], extdata, extdatalen);
+         pos += extdatalen;
        }
       else
        {
-         if (ret == 0)
-           ret = GNUTLS_E_INTERNAL_ERROR;
-         gnutls_free (data);
-         gnutls_free (extdata);
+         if (extdatalen == 0)
+           extdatalen = GNUTLS_E_INTERNAL_ERROR;
+         gnutls_free (bufel);
          gnutls_assert ();
          return ret;
        }
 
+
       /* Generate and copy TLS extensions.
        */
       if (_gnutls_version_has_extensions (hver))
@@ -2150,17 +2129,24 @@ _gnutls_send_client_hello (gnutls_session_t session, 
int again)
            type = GNUTLS_EXT_NONE;
        }
 
-      ret = _gnutls_gen_extensions (session, extdata, extdatalen, type);
-
-      if (ret > 0)
-       {
-         datalen += ret;
-         data = gnutls_realloc_fast (data, datalen);
-         if (data == NULL)
+         if (extdatalen > 0)
+           {
+             datalen += extdatalen;
+             bufel = _gnutls_handshake_realloc (bufel, datalen);
+             if (bufel == NULL)
+               {
+                 gnutls_assert ();
+                 return GNUTLS_E_MEMORY_ERROR;
+               }
+             data = bufel->msg.data + bufel->mark;
+
+             memcpy (&data[pos], extdata, extdatalen);
+           }
+         else if (extdatalen < 0)
            {
              gnutls_assert ();
-             gnutls_free (extdata);
-             return GNUTLS_E_MEMORY_ERROR;
+             gnutls_free (bufel);
+             return extdatalen;
            }
 
          memcpy (&data[pos], extdata, ret);
@@ -2175,10 +2161,7 @@ _gnutls_send_client_hello (gnutls_session_t session, int 
again)
 
     }
 
-  ret =
-    _gnutls_send_handshake (session, data, datalen,
-                           GNUTLS_HANDSHAKE_CLIENT_HELLO);
-  gnutls_free (data);
+  ret = _gnutls_send_handshake (session, bufel, GNUTLS_HANDSHAKE_CLIENT_HELLO);
 
   return ret;
 }
@@ -2186,6 +2169,7 @@ _gnutls_send_client_hello (gnutls_session_t session, int 
again)
 static int
 _gnutls_send_server_hello (gnutls_session_t session, int again)
 {
+  mbuffer_st *bufel = NULL;
   opaque *data = NULL;
   opaque extdata[MAX_EXT_DATA_LENGTH];
   int extdatalen;
@@ -2232,12 +2216,13 @@ _gnutls_send_server_hello (gnutls_session_t session, 
int again)
          return extdatalen;
        }
 
-      data = gnutls_malloc (datalen + extdatalen);
-      if (data == NULL)
+      bufel = _gnutls_handshake_alloc (datalen + extdatalen);
+      if (bufel == NULL)
        {
          gnutls_assert ();
          return GNUTLS_E_MEMORY_ERROR;
        }
+      data = bufel->msg.data + bufel->mark;
 
       data[pos++] =
        _gnutls_version_get_major (session->security_parameters.version);
@@ -2259,7 +2244,7 @@ _gnutls_send_server_hello (gnutls_session_t session, int 
again)
       _gnutls_handshake_log ("HSK[%p]: SessionID: %s\n", session,
                             _gnutls_bin2hex (session->security_parameters.
                                              session_id, session_id_len, buf,
-                                             sizeof (buf)));
+                                             sizeof (buf), NULL));
 
       memcpy (&data[pos],
              session->security_parameters.current_cipher_suite.suite, 2);
@@ -2279,10 +2264,7 @@ _gnutls_send_server_hello (gnutls_session_t session, int 
again)
        }
     }
 
-  ret =
-    _gnutls_send_handshake (session, data, datalen,
-                           GNUTLS_HANDSHAKE_SERVER_HELLO);
-  gnutls_free (data);
+  ret = _gnutls_send_handshake (session, bufel, GNUTLS_HANDSHAKE_SERVER_HELLO);
 
   return ret;
 }
@@ -2604,13 +2586,13 @@ _gnutls_handshake_hash_init (gnutls_session_t session)
 static int
 _gnutls_send_supplemental (gnutls_session_t session, int again)
 {
+  mbuffer_st *bufel;
   int ret = 0;
 
   _gnutls_debug_log ("EXT[%p]: Sending supplemental data\n", session);
 
   if (again)
-    ret = _gnutls_send_handshake (session, NULL, 0,
-                                 GNUTLS_HANDSHAKE_SUPPLEMENTAL);
+    ret = _gnutls_send_handshake (session, NULL, 
GNUTLS_HANDSHAKE_SUPPLEMENTAL);
   else
     {
       gnutls_buffer buf;
@@ -2623,9 +2605,18 @@ _gnutls_send_supplemental (gnutls_session_t session, int 
again)
          return ret;
        }
 
-      ret = _gnutls_send_handshake (session, buf.data, buf.length,
-                                   GNUTLS_HANDSHAKE_SUPPLEMENTAL);
+      bufel = _gnutls_handshake_alloc(buf.length);
+      if (bufel == NULL)
+       {
+         gnutls_assert ();
+         return GNUTLS_E_MEMORY_ERROR;
+       }
+
+      memcpy(bufel->msg.data + bufel->mark, buf.data, buf.length);
       _gnutls_buffer_clear (&buf);
+
+      ret = _gnutls_send_handshake (session, bufel,
+                                   GNUTLS_HANDSHAKE_SUPPLEMENTAL);
     }
 
   return ret;
@@ -2662,33 +2653,34 @@ _gnutls_recv_supplemental (gnutls_session_t session)
 }
 
 /**
- * gnutls_handshake:
- * @session: is a #gnutls_session_t structure.
- *
- * This function does the handshake of the TLS/SSL protocol, and
- * initializes the TLS connection.
- *
- * This function will fail if any problem is encountered, and will
- * return a negative error code. In case of a client, if the client
- * has asked to resume a session, but the server couldn't, then a
- * full handshake will be performed.
- *
- * The non-fatal errors such as %GNUTLS_E_AGAIN and
- * %GNUTLS_E_INTERRUPTED interrupt the handshake procedure, which
- * should be later be resumed.  Call this function again, until it
- * returns 0; cf.  gnutls_record_get_direction() and
- * gnutls_error_is_fatal().
- *
- * If this function is called by a server after a rehandshake request
- * then %GNUTLS_E_GOT_APPLICATION_DATA or
- * %GNUTLS_E_WARNING_ALERT_RECEIVED may be returned.  Note that these
- * are non fatal errors, only in the specific case of a rehandshake.
- * Their meaning is that the client rejected the rehandshake request or
- * in the case of %GNUTLS_E_GOT_APPLICATION_DATA it might also mean that
- * some data were pending.
- *
- * Returns: %GNUTLS_E_SUCCESS on success, otherwise an error.
- **/
+  * gnutls_handshake - This is the main function in the handshake protocol.
+  * @session: is a #gnutls_session_t structure.
+  *
+  * This function does the handshake of the TLS/SSL protocol, and
+  * initializes the TLS connection.
+  *
+  * This function will fail if any problem is encountered, and will
+  * return a negative error code. In case of a client, if the client
+  * has asked to resume a session, but the server couldn't, then a
+  * full handshake will be performed.
+  *
+  * The non-fatal errors such as %GNUTLS_E_AGAIN and
+  * %GNUTLS_E_INTERRUPTED interrupt the handshake procedure, which
+  * should be later be resumed.  Call this function again, until it
+  * returns 0; cf.  gnutls_record_get_direction() and
+  * gnutls_error_is_fatal().
+  *
+  * If this function is called by a server after a rehandshake request
+  * then %GNUTLS_E_GOT_APPLICATION_DATA or
+  * %GNUTLS_E_WARNING_ALERT_RECEIVED may be returned.  Note that these
+  * are non fatal errors, only in the specific case of a rehandshake.
+  * Their meaning is that the client rejected the rehandshake request or
+  * in the case of %GNUTLS_E_GOT_APPLICATION_DATA it might also mean that
+  * some data were pending.
+  *
+  * Returns: %GNUTLS_E_SUCCESS on success, otherwise an error.
+  *
+  **/
 int
 gnutls_handshake (gnutls_session_t session)
 {
@@ -2760,7 +2752,7 @@ _gnutls_handshake_client (gnutls_session_t session)
                                            
internals.resumed_security_parameters.session_id,
                                            session->
                                            
internals.resumed_security_parameters.session_id_size,
-                                           buf, sizeof (buf)));
+                                           buf, sizeof (buf), NULL));
 #endif
 
   switch (STATE)
diff --git a/lib/gnutls_handshake.h b/lib/gnutls_handshake.h
index 6a28afb..860afac 100644
--- a/lib/gnutls_handshake.h
+++ b/lib/gnutls_handshake.h
@@ -26,8 +26,10 @@
 typedef enum Optional
 { OPTIONAL_PACKET, MANDATORY_PACKET } Optional;
 
-int _gnutls_send_handshake (gnutls_session_t session, void *i_data,
-                           uint32_t i_datasize,
+mbuffer_st* _gnutls_handshake_alloc(size_t size);
+mbuffer_st* _gnutls_handshake_realloc(mbuffer_st *bufel, size_t size);
+
+int _gnutls_send_handshake (gnutls_session_t session, mbuffer_st *bufel,
                            gnutls_handshake_description_t type);
 int _gnutls_recv_hello_request (gnutls_session_t session, void *data,
                                uint32_t data_size);
diff --git a/lib/gnutls_int.h b/lib/gnutls_int.h
index 3d23f94..1ca2e12 100644
--- a/lib/gnutls_int.h
+++ b/lib/gnutls_int.h
@@ -209,6 +209,28 @@ typedef enum
   HANDSHAKE_MAC_TYPE_12
 } handshake_mac_type_t;
 
+/* Message buffers (mbuffers) structures */
+
+typedef struct mbuffer_st
+{
+  struct mbuffer_st *next;
+
+  gnutls_datum_t msg;
+  /* msg->size - mark = number of bytes left to process in this
+     message. Mark should only be non-zero when this buffer is the
+     head of the queue. */
+  size_t mark;
+} mbuffer_st;
+
+typedef struct mbuffer_head_st
+{
+  mbuffer_st *head;
+  mbuffer_st **tail;
+
+  unsigned int length;
+  size_t byte_length;
+} mbuffer_head_st;
+
 /* Store & Retrieve functions defines: 
  */
 
@@ -567,9 +589,7 @@ typedef struct
   /* These buffers are used in the handshake
    * protocol only. freed using _gnutls_handshake_io_buffer_clear();
    */
-  gnutls_buffer handshake_send_buffer;
-  size_t handshake_send_buffer_prev_size;
-  content_type_t handshake_send_buffer_type;
+  mbuffer_head_st handshake_send_buffer;
   gnutls_handshake_description_t handshake_send_buffer_htype;
   content_type_t handshake_recv_buffer_type;
   gnutls_handshake_description_t handshake_recv_buffer_htype;
@@ -579,17 +599,10 @@ typedef struct
    * non blocking IO.
    */
   gnutls_buffer record_recv_buffer;
-  gnutls_buffer record_send_buffer;    /* holds cached data
+  mbuffer_head_st record_send_buffer;  /* holds cached data
                                         * for the gnutls_io_write_buffered()
                                         * function.
                                         */
-  size_t record_send_buffer_prev_size; /* holds the
-                                        * data written in the previous runs.
-                                        */
-  size_t record_send_buffer_user_size; /* holds the
-                                        * size of the user specified data to
-                                        * send.
-                                        */
 
   /* 0 if no peeked data was kept, 1 otherwise.
    */
@@ -659,7 +672,7 @@ typedef struct
    */
   gnutls_cert *selected_cert_list;
   int selected_cert_list_length;
-  gnutls_privkey *selected_key;
+  struct gnutls_privkey_st *selected_key;
   int selected_need_free;
 
   /* holds the extensions we sent to the peer
diff --git a/lib/gnutls_kx.c b/lib/gnutls_kx.c
index bad1b7a..1173160 100644
--- a/lib/gnutls_kx.c
+++ b/lib/gnutls_kx.c
@@ -39,6 +39,37 @@
 #include <gnutls_datum.h>
 #include <gnutls_rsa_export.h>
 
+/* This is a temporary function to be used before the generate_*
+   internal API is changed to use mbuffers. For now we don't avoid the
+   extra alloc + memcpy. */
+static inline int
+send_handshake (gnutls_session_t session, opaque *data, size_t size,
+               gnutls_handshake_description_t type)
+{
+  mbuffer_st *bufel;
+
+  if(data == NULL && size == 0)
+    return _gnutls_send_handshake(session, NULL, type);
+
+  if (data == NULL && size > 0)
+    {
+      gnutls_assert ();
+      return GNUTLS_E_INVALID_REQUEST;
+    }
+
+  bufel = _gnutls_handshake_alloc(size);
+  if (bufel == NULL)
+    {
+      gnutls_assert ();
+      return GNUTLS_E_MEMORY_ERROR;
+    }
+
+  memcpy(bufel->msg.data + bufel->mark, data, size);
+
+  return _gnutls_send_handshake(session, bufel, type);
+}
+
+
 /* This file contains important thing for the TLS handshake procedure.
  */
 
@@ -64,15 +95,15 @@ generate_normal_master (gnutls_session_t session, int 
keep_premaster)
 
   _gnutls_hard_log ("INT: PREMASTER SECRET[%d]: %s\n", PREMASTER.size,
                    _gnutls_bin2hex (PREMASTER.data, PREMASTER.size, buf,
-                                    sizeof (buf)));
+                                    sizeof (buf), NULL));
   _gnutls_hard_log ("INT: CLIENT RANDOM[%d]: %s\n", 32,
                    _gnutls_bin2hex (session->
                                     security_parameters.client_random, 32,
-                                    buf, sizeof (buf)));
+                                    buf, sizeof (buf), NULL));
   _gnutls_hard_log ("INT: SERVER RANDOM[%d]: %s\n", 32,
                    _gnutls_bin2hex (session->
                                     security_parameters.server_random, 32,
-                                    buf, sizeof (buf)));
+                                    buf, sizeof (buf), NULL));
 
   if (gnutls_protocol_get_version (session) == GNUTLS_SSL3)
     {
@@ -116,7 +147,7 @@ generate_normal_master (gnutls_session_t session, int 
keep_premaster)
                                         session->
                                         security_parameters.extensions.
                                         oprfi_client_len, buf,
-                                        sizeof (buf)));
+                                        sizeof (buf), NULL));
       _gnutls_hard_log ("INT: SERVER OPRFI[%d]: %s\n",
                        session->security_parameters.extensions.
                        oprfi_server_len,
@@ -126,7 +157,7 @@ generate_normal_master (gnutls_session_t session, int 
keep_premaster)
                                         session->
                                         security_parameters.extensions.
                                         oprfi_server_len, buf,
-                                        sizeof (buf)));
+                                        sizeof (buf), NULL));
 
       memcpy (rnd, session->security_parameters.client_random,
              GNUTLS_RANDOM_SIZE);
@@ -178,7 +209,7 @@ generate_normal_master (gnutls_session_t session, int 
keep_premaster)
   _gnutls_hard_log ("INT: MASTER SECRET: %s\n",
                    _gnutls_bin2hex (session->
                                     security_parameters.master_secret,
-                                    GNUTLS_MASTER_SIZE, buf, sizeof (buf)));
+                                    GNUTLS_MASTER_SIZE, buf, sizeof (buf), 
NULL));
 
   return ret;
 }
@@ -220,9 +251,8 @@ _gnutls_send_server_kx_message (gnutls_session_t session, 
int again)
        }
     }
 
-  ret =
-    _gnutls_send_handshake (session, data, data_size,
-                           GNUTLS_HANDSHAKE_SERVER_KEY_EXCHANGE);
+  ret = send_handshake (session, data, data_size,
+                       GNUTLS_HANDSHAKE_SERVER_KEY_EXCHANGE);
   gnutls_free (data);
 
   if (ret < 0)
@@ -266,9 +296,8 @@ _gnutls_send_server_certificate_request (gnutls_session_t 
session, int again)
          return data_size;
        }
     }
-  ret =
-    _gnutls_send_handshake (session, data, data_size,
-                           GNUTLS_HANDSHAKE_CERTIFICATE_REQUEST);
+  ret = send_handshake (session, data, data_size,
+                       GNUTLS_HANDSHAKE_CERTIFICATE_REQUEST);
   gnutls_free (data);
 
   if (ret < 0)
@@ -308,9 +337,8 @@ _gnutls_send_client_kx_message (gnutls_session_t session, 
int again)
          return data_size;
        }
     }
-  ret =
-    _gnutls_send_handshake (session, data, data_size,
-                           GNUTLS_HANDSHAKE_CLIENT_KEY_EXCHANGE);
+  ret =  send_handshake (session, data, data_size,
+                        GNUTLS_HANDSHAKE_CLIENT_KEY_EXCHANGE);
   gnutls_free (data);
 
   if (ret < 0)
@@ -368,9 +396,8 @@ _gnutls_send_client_certificate_verify (gnutls_session_t 
session, int again)
        return 0;
 
     }
-  ret =
-    _gnutls_send_handshake (session, data,
-                           data_size, GNUTLS_HANDSHAKE_CERTIFICATE_VERIFY);
+  ret = send_handshake (session, data, data_size,
+                       GNUTLS_HANDSHAKE_CERTIFICATE_VERIFY);
   gnutls_free (data);
 
   return ret;
@@ -550,9 +577,8 @@ _gnutls_send_client_certificate (gnutls_session_t session, 
int again)
   else
     {                          /* TLS 1.0 or SSL 3.0 with a valid certificate 
                                 */
-      ret =
-       _gnutls_send_handshake (session, data, data_size,
-                               GNUTLS_HANDSHAKE_CERTIFICATE_PKT);
+      ret = send_handshake (session, data, data_size,
+                           GNUTLS_HANDSHAKE_CERTIFICATE_PKT);
       gnutls_free (data);
     }
 
@@ -595,9 +621,8 @@ _gnutls_send_server_certificate (gnutls_session_t session, 
int again)
          return data_size;
        }
     }
-  ret =
-    _gnutls_send_handshake (session, data, data_size,
-                           GNUTLS_HANDSHAKE_CERTIFICATE_PKT);
+  ret = send_handshake (session, data, data_size,
+                       GNUTLS_HANDSHAKE_CERTIFICATE_PKT);
   gnutls_free (data);
 
   if (ret < 0)
diff --git a/lib/gnutls_mbuffers.c b/lib/gnutls_mbuffers.c
new file mode 100644
index 0000000..ace77b9
--- /dev/null
+++ b/lib/gnutls_mbuffers.c
@@ -0,0 +1,169 @@
+/*
+ * Copyright (C) 2009 Free Software Foundation
+ *
+ * Author: Jonathan Bastien-Filiatrault
+ *
+ * This file is part of GNUTLS.
+ *
+ * The GNUTLS library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+ * USA
+ *
+ */
+
+#include "gnutls_mbuffers.h"
+#include "gnutls_errors.h"
+
+/* Here be mbuffers */
+
+void
+_gnutls_mbuffer_init (mbuffer_head_st *buf)
+{
+  buf->head = NULL;
+  buf->tail = &buf->head;
+
+  buf->length = 0;
+  buf->byte_length = 0;
+}
+
+void
+_gnutls_mbuffer_clear (mbuffer_head_st *buf)
+{
+  mbuffer_st *bufel, *next;
+
+  for(bufel = buf->head; bufel != NULL; bufel = next)
+    {
+      next = bufel->next;
+      gnutls_free(bufel);
+    }
+
+  _gnutls_mbuffer_init (buf);
+}
+
+void
+_gnutls_mbuffer_enqueue (mbuffer_head_st *buf, mbuffer_st *bufel)
+{
+  bufel->next = NULL;
+
+  buf->length++;
+  buf->byte_length += bufel->msg.size - bufel->mark;
+
+  *(buf->tail) = bufel;
+  buf->tail = &bufel->next;
+}
+
+void
+_gnutls_mbuffer_get_head (mbuffer_head_st *buf, gnutls_datum_t *msg)
+{
+  mbuffer_st *bufel;
+
+  if (buf->head)
+    {
+      bufel = buf->head;
+      msg->data = bufel->msg.data + bufel->mark;
+      msg->size = bufel->msg.size - bufel->mark;
+    }
+  else
+    {
+      msg->data = NULL;
+      msg->size = 0;
+    }
+}
+
+static inline void
+remove_front (mbuffer_head_st *buf)
+{
+  mbuffer_st *bufel;
+
+  if(!buf->head)
+    return;
+
+  bufel = buf->head;
+  buf->head = bufel->next;
+
+  buf->byte_length -= (bufel->msg.size - bufel->mark);
+  buf->length -= 1;
+  gnutls_free(bufel);
+
+  if (!buf->head)
+    buf->tail = &buf->head;
+}
+
+int
+_gnutls_mbuffer_remove_bytes (mbuffer_head_st *buf, size_t bytes)
+{
+  size_t left = bytes;
+  mbuffer_st *bufel, *next;
+
+  if (bytes > buf->byte_length)
+    return -1;
+
+  for (bufel = buf->head; bufel != NULL && left > 0; bufel = next)
+    {
+      next = bufel->next;
+
+      if(left >= (bufel->msg.size - bufel->mark))
+       {
+         left -= (bufel->msg.size - bufel->mark);
+         remove_front(buf);
+       }
+      else
+       {
+         bufel->mark += left;
+         buf->byte_length -= left;
+         left = 0;
+       }
+    }
+
+  return 0;
+}
+
+mbuffer_st *
+_gnutls_mbuffer_alloc (size_t payload_size)
+{
+  mbuffer_st * st;
+
+  st = gnutls_malloc (payload_size+sizeof (mbuffer_st));
+  if (st == NULL)
+    {
+      gnutls_assert ();
+      return NULL;
+    }
+
+  //payload points after the mbuffer_st structure
+  st->msg.data = (opaque*)st + sizeof (mbuffer_st);
+  st->msg.size = payload_size;
+  st->mark = 0;
+  st->next = NULL;
+
+  return st;
+}
+
+mbuffer_st*
+_gnutls_mbuffer_realloc (mbuffer_st *bufel, size_t payload_size)
+{
+  mbuffer_st *ret;
+
+  ret = gnutls_realloc_fast (bufel, payload_size+sizeof (mbuffer_st));
+  if (ret == NULL)
+    {
+      gnutls_assert ();
+      return NULL;
+    }
+
+  ret->msg.size = payload_size;
+  ret->msg.data = (opaque*)ret + sizeof (mbuffer_st);
+
+  return ret;
+}
diff --git a/lib/gnutls_mbuffers.h b/lib/gnutls_mbuffers.h
new file mode 100644
index 0000000..a1a6065
--- /dev/null
+++ b/lib/gnutls_mbuffers.h
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2009 Free Software Foundation
+ *
+ * Author: Jonathan Bastien-Filiatrault
+ *
+ * This file is part of GNUTLS.
+ *
+ * The GNUTLS library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+ * USA
+ *
+ */
+
+#ifndef GNUTLS_MBUFFERS_H
+# define GNUTLS_MBUFFERS_H
+
+#include "gnutls_int.h"
+
+void _mbuffer_init (mbuffer_head_st *buf);
+void _mbuffer_clear (mbuffer_head_st *buf);
+void _mbuffer_enqueue (mbuffer_head_st *buf, mbuffer_st *bufel);
+void _mbuffer_get_head (mbuffer_head_st *buf, gnutls_datum_t *msg);
+int  _mbuffer_remove_bytes (mbuffer_head_st *buf, size_t bytes);
+mbuffer_st* _mbuffer_alloc (size_t payload_size);
+
+/* This is dangerous since it will replace bufel with a new
+ * one.
+ */
+mbuffer_st* _mbuffer_append_data (mbuffer_st *bufel, void* newdata, size_t 
newdata_size);
+
+
+/* For "user" use. One can have buffer data and header.
+ */
+
+inline static void _mbuffer_set_udata(mbuffer_st *bufel, void* data, size_t 
data_size)
+{
+  memcpy(bufel->msg.data + bufel->user_mark, data, data_size);
+}
+
+inline static void* _mbuffer_get_uhead_ptr(mbuffer_st *bufel)
+{
+  return bufel->msg.data;
+}
+
+inline static void* _mbuffer_get_udata_ptr(mbuffer_st *bufel)
+{
+  return bufel->msg.data + bufel->user_mark;
+}
+
+inline static void _mbuffer_set_udata_size(mbuffer_st *bufel, size_t size)
+{
+  bufel->msg.size = size + bufel->user_mark;
+}
+
+inline static size_t _mbuffer_get_udata_size(mbuffer_st *bufel)
+{
+  return bufel->msg.size - bufel->user_mark;
+}
+
+inline static size_t _mbuffer_get_uhead_size(mbuffer_st *bufel)
+{
+  return bufel->user_mark;
+}
+
+inline static void _mbuffer_set_uhead_size(mbuffer_st *bufel, size_t size)
+{
+  bufel->user_mark = size;
+}
+
+
+
+inline static mbuffer_st* _gnutls_handshake_alloc(size_t size)
+{
+  mbuffer_st *ret = _mbuffer_alloc (HANDSHAKE_HEADER_SIZE + size);
+
+  if (!ret)
+    return NULL;
+
+  _mbuffer_set_uhead_size(ret, HANDSHAKE_HEADER_SIZE);
+
+  return ret;
+}
+
+#endif
diff --git a/lib/gnutls_mpi.c b/lib/gnutls_mpi.c
index 5279014..b3d5760 100644
--- a/lib/gnutls_mpi.c
+++ b/lib/gnutls_mpi.c
@@ -256,8 +256,6 @@ _gnutls_mpi_dprint_size (const bigint_t a, gnutls_datum_t * 
dest, size_t size)
   if (buf == NULL)
     return GNUTLS_E_MEMORY_ERROR;
 
-  dest->size = MAX (size, bytes);
-
   if (bytes <= size)
     {
       size_t diff = size - bytes;
@@ -343,7 +341,7 @@ _gnutls_x509_write_int (ASN1_TYPE node, const char *value, 
bigint_t mpi,
   else
     result = _gnutls_mpi_print (mpi, NULL, &s_len);
 
-  if (result != 0)
+  if (result != GNUTLS_E_SHORT_MEMORY_BUFFER)
     {
       gnutls_assert ();
       return result;
diff --git a/lib/gnutls_pk.c b/lib/gnutls_pk.c
index 77d1434..9739869 100644
--- a/lib/gnutls_pk.c
+++ b/lib/gnutls_pk.c
@@ -609,3 +609,53 @@ gnutls_pk_params_release (gnutls_pk_params_st * p)
       _gnutls_mpi_release (&p->params[i]);
     }
 }
+
+int _gnutls_calc_rsa_exp(bigint_t* params, unsigned int params_size)
+{
+bigint_t tmp = _gnutls_mpi_alloc_like(params[0]);
+
+ if (params_size < RSA_PRIVATE_PARAMS-2)
+   {
+     gnutls_assert();
+     return GNUTLS_E_INTERNAL_ERROR;
+   }
+
+  if (tmp == NULL)
+    {
+      gnutls_assert ();
+      return GNUTLS_E_MEMORY_ERROR;
+    }
+
+  /* [6] = d % p-1, [7] = d % q-1 */
+  _gnutls_mpi_sub_ui(tmp, params[3], 1);
+  params[6] = _gnutls_mpi_mod(params[2]/*d*/, tmp);
+
+  _gnutls_mpi_sub_ui(tmp, params[4], 1);
+  params[7] = _gnutls_mpi_mod(params[2]/*d*/, tmp);
+
+  _gnutls_mpi_release(&tmp);
+
+  if (params[7] == NULL || params[6] == NULL)
+    {
+       gnutls_assert ();
+       return GNUTLS_E_MEMORY_ERROR;
+    }
+
+  return 0;
+}
+
+int _gnutls_pk_get_hash_algorithm(gnutls_pk_algorithm_t pk, bigint_t* params, 
int params_size,
+  gnutls_digest_algorithm_t *dig, unsigned int *mand)
+{
+  if (mand)
+    {
+      if (pk == GNUTLS_PK_DSA)
+        *mand = 1;
+      else
+        *mand = 0;
+    }
+
+  return _gnutls_x509_verify_algorithm ((gnutls_mac_algorithm_t *) dig,
+                       NULL, pk, params, params_size);
+
+}
diff --git a/lib/gnutls_pk.h b/lib/gnutls_pk.h
index 4fc9785..5aa9622 100644
--- a/lib/gnutls_pk.h
+++ b/lib/gnutls_pk.h
@@ -77,4 +77,9 @@ int
 _gnutls_decode_ber_rs (const gnutls_datum_t * sig_value, bigint_t * r,
                       bigint_t * s);
 
+int _gnutls_calc_rsa_exp(bigint_t* params, unsigned int params_size);
+
+int _gnutls_pk_get_hash_algorithm(gnutls_pk_algorithm_t pk, bigint_t* params, 
int params_size,
+  gnutls_digest_algorithm_t *dig, unsigned int *mand);
+
 #endif /* GNUTLS_PK_H */
diff --git a/lib/gnutls_privkey.c b/lib/gnutls_privkey.c
new file mode 100644
index 0000000..185a1e9
--- /dev/null
+++ b/lib/gnutls_privkey.c
@@ -0,0 +1,324 @@
+/*
+ * GnuTLS PKCS#11 support
+ * Copyright (C) 2010 Free Software Foundation
+ * 
+ * Author: Nikos Mavrogiannopoulos
+ *
+ * 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
+*/
+
+#include <gnutls_int.h>
+#include <pakchois/pakchois.h>
+#include <gnutls/pkcs11.h>
+#include <stdio.h>
+#include <stdbool.h>
+#include <string.h>
+#include <gnutls_errors.h>
+#include <gnutls_datum.h>
+#include <pkcs11_int.h>
+#include <gnutls/abstract.h>
+#include <sign.h>
+#include <gnutls_pk.h>
+#include <x509_int.h>
+#include <openpgp/openpgp_int.h>
+
+struct gnutls_privkey_st {
+       gnutls_privkey_type_t type;
+       gnutls_pk_algorithm_t pk_algorithm;
+       
+       union {
+               gnutls_x509_privkey_t x509;
+               gnutls_pkcs11_privkey_t pkcs11;
+               gnutls_openpgp_privkey_t openpgp;
+       } key;
+       
+       unsigned int flags;
+};
+
+/**
+ * gnutls_privkey_get_type:
+ * @key: should contain a #gnutls_privkey_t structure
+ *
+ * This function will return the type of the private key. This is
+ * actually the type of the subsystem used to set this private key.
+ *
+ * Returns: a member of the #gnutls_privkey_type_t enumeration on
+ *   success, or a negative value on error.
+ **/
+gnutls_privkey_type_t gnutls_privkey_get_type (gnutls_privkey_t key)
+{
+       return key->type;
+}
+
+/**
+ * gnutls_privkey_get_pk_algorithm:
+ * @key: should contain a #gnutls_privkey_t structure
+ * @bits: If set will return the number of bits of the parameters (may be NULL)
+ *
+ * This function will return the public key algorithm of a private
+ * key and if possible will return a number of bits that indicates
+ * the security parameter of the key.
+ *
+ * Returns: a member of the #gnutls_pk_algorithm_t enumeration on
+ *   success, or a negative value on error.
+ **/
+int gnutls_privkey_get_pk_algorithm (gnutls_privkey_t key, unsigned int* bits)
+{
+       switch(key->type) {
+               case GNUTLS_PRIVKEY_OPENPGP:
+                       return 
gnutls_openpgp_privkey_get_pk_algorithm(key->key.openpgp, bits);
+               case GNUTLS_PRIVKEY_PKCS11:
+                       return 
gnutls_pkcs11_privkey_get_pk_algorithm(key->key.pkcs11, bits);
+               case GNUTLS_PRIVKEY_X509:
+                        if (bits)
+                                *bits = _gnutls_mpi_get_nbits 
(key->key.x509->params[0]);
+                       return 
gnutls_x509_privkey_get_pk_algorithm(key->key.x509);
+               default:
+                       gnutls_assert();
+                       return GNUTLS_E_INVALID_REQUEST;
+       }
+
+}
+
+/**
+ * gnutls_privkey_init:
+ * @key: The structure to be initialized
+ *
+ * This function will initialize an private key structure.
+ *
+ * Returns: On success, %GNUTLS_E_SUCCESS is returned, otherwise a
+ *   negative error value.
+ **/
+int gnutls_privkey_init(gnutls_privkey_t * key)
+{
+       *key = gnutls_calloc(1, sizeof(struct gnutls_privkey_st));
+       if (*key == NULL) {
+               gnutls_assert();
+               return GNUTLS_E_MEMORY_ERROR;
+       }
+       
+       return 0;
+}
+
+/**
+ * gnutls_privkey_deinit:
+ * @key: The structure to be deinitialized
+ *
+ * This function will deinitialize a private key structure.
+ **/
+void gnutls_privkey_deinit(gnutls_privkey_t key)
+{
+       if (key->flags & GNUTLS_PRIVKEY_IMPORT_AUTO_RELEASE)
+               switch(key->type) {
+                       case GNUTLS_PRIVKEY_OPENPGP:
+                               return 
gnutls_openpgp_privkey_deinit(key->key.openpgp);
+                       case GNUTLS_PRIVKEY_PKCS11:
+                               return 
gnutls_pkcs11_privkey_deinit(key->key.pkcs11);
+                       case GNUTLS_PRIVKEY_X509:
+                               return 
gnutls_x509_privkey_deinit(key->key.x509);
+               }
+       gnutls_free(key);
+}
+
+/**
+ * gnutls_privkey_import_pkcs11:
+ * @pkey: The private key
+ * @key: The private key to be imported
+ * @flags: should be zero
+ *
+ * This function will import the given private key to the abstract
+ * #gnutls_privkey_t structure.
+ *
+ * Returns: On success, %GNUTLS_E_SUCCESS is returned, otherwise a
+ *   negative error value.
+ **/
+int gnutls_privkey_import_pkcs11 (gnutls_privkey_t pkey, 
gnutls_pkcs11_privkey_t key, unsigned int flags)
+{
+       pkey->key.pkcs11 = key;
+       pkey->type = GNUTLS_PRIVKEY_PKCS11;
+       pkey->pk_algorithm = gnutls_pkcs11_privkey_get_pk_algorithm(key, NULL);
+       pkey->flags = flags;
+
+       return 0;
+}
+
+/**
+ * gnutls_privkey_import_x509:
+ * @pkey: The private key
+ * @key: The private key to be imported
+ * @flags: should be zero
+ *
+ * This function will import the given private key to the abstract
+ * #gnutls_privkey_t structure.
+ *
+ * Returns: On success, %GNUTLS_E_SUCCESS is returned, otherwise a
+ *   negative error value.
+ **/
+int gnutls_privkey_import_x509 (gnutls_privkey_t pkey, gnutls_x509_privkey_t 
key, unsigned int flags)
+{
+        pkey->key.x509 = key;
+       pkey->type = GNUTLS_PRIVKEY_X509;
+       pkey->pk_algorithm = gnutls_x509_privkey_get_pk_algorithm(key);
+       pkey->flags = flags;
+
+       return 0;
+}
+
+/**
+ * gnutls_privkey_import_openpgp:
+ * @pkey: The private key
+ * @key: The private key to be imported
+ * @flags: should be zero
+ *
+ * This function will import the given private key to the abstract
+ * #gnutls_privkey_t structure.
+ *
+ * Returns: On success, %GNUTLS_E_SUCCESS is returned, otherwise a
+ *   negative error value.
+ **/
+int gnutls_privkey_import_openpgp (gnutls_privkey_t pkey, 
gnutls_openpgp_privkey_t key, unsigned int flags)
+{
+       pkey->key.openpgp = key;
+       pkey->type = GNUTLS_PRIVKEY_OPENPGP;
+       pkey->pk_algorithm = gnutls_openpgp_privkey_get_pk_algorithm(key, NULL);
+       pkey->flags = flags;
+       
+       return 0;
+}
+
+/**
+ * gnutls_privkey_sign_data:
+ * @signer: Holds the key
+ * @digest: should be a digest algorithm
+ * @flags: should be 0 for now
+ * @data: holds the data to be signed
+ * @signature: will contain the signature allocate with gnutls_malloc()
+ *
+ * This function will sign the given data using a signature algorithm
+ * supported by the private key. Signature algorithms are always used
+ * together with a hash functions.  Different hash functions may be
+ * used for the RSA algorithm, but only SHA-1 for the DSA keys.
+ *
+ * Returns: On success, %GNUTLS_E_SUCCESS is returned, otherwise a
+ * negative error value.
+ **/
+int
+gnutls_privkey_sign_data(gnutls_privkey_t signer,
+                               gnutls_digest_algorithm_t hash,
+                               unsigned int flags,
+                               const gnutls_datum_t * data,
+                               gnutls_datum_t * signature)
+{
+       int ret;
+       gnutls_datum_t digest;
+
+       switch (signer->pk_algorithm) {
+       case GNUTLS_PK_RSA:
+               ret = pk_pkcs1_rsa_hash(hash, data, &digest);
+               if (ret < 0) {
+                       gnutls_assert();
+                       return ret;
+               }
+               break;
+       case GNUTLS_PK_DSA:
+               ret = pk_dsa_hash(hash, data, &digest);
+               if (ret < 0) {
+                       gnutls_assert();
+                       return ret;
+               }
+
+               break;
+       default:
+               gnutls_assert();
+               return GNUTLS_E_INTERNAL_ERROR;
+       }
+
+       ret = gnutls_privkey_sign_hash(signer, &digest, signature);
+       _gnutls_free_datum(&digest);
+
+       if (ret < 0) {
+               gnutls_assert();
+               return ret;
+       }
+
+       return 0;
+}
+
+/**
+ * gnutls_privkey_sign_hash:
+ * @key: Holds the key
+ * @data: holds the data to be signed
+ * @signature: will contain the signature allocate with gnutls_malloc()
+ *
+ * This function will sign the given data using a signature algorithm
+ * supported by the private key.
+ *
+ * Returns: On success, %GNUTLS_E_SUCCESS is returned, otherwise a
+ * negative error value.
+ **/
+int gnutls_privkey_sign_hash (gnutls_privkey_t key,
+                       const gnutls_datum_t * hash,
+                       gnutls_datum_t * signature)
+{
+       switch(key->type) {
+               case GNUTLS_PRIVKEY_OPENPGP:
+                       return 
gnutls_openpgp_privkey_sign_hash(key->key.openpgp, hash, signature);
+               case GNUTLS_PRIVKEY_PKCS11:
+                       return gnutls_pkcs11_privkey_sign_hash(key->key.pkcs11, 
hash, signature);
+               case GNUTLS_PRIVKEY_X509:
+                       return gnutls_x509_privkey_sign_hash(key->key.x509, 
hash, signature);
+               default:
+                       gnutls_assert();
+                       return GNUTLS_E_INVALID_REQUEST;
+       }
+}
+
+/**
+ * gnutls_privkey_decrypt_data:
+ * @key: Holds the key
+ * @flags: zero for now
+ * @ciphertext: holds the data to be decrypted
+ * @plaintext: will contain the decrypted data, allocated with gnutls_malloc()
+ *
+ * This function will decrypt the given data using the algorithm
+ * supported by the private key.
+ *
+ * Returns: On success, %GNUTLS_E_SUCCESS is returned, otherwise a
+ * negative error value.
+ **/
+int gnutls_privkey_decrypt_data(gnutls_privkey_t key,
+                               unsigned int flags,
+                               const gnutls_datum_t * ciphertext,
+                               gnutls_datum_t * plaintext)
+{
+       if (key->pk_algorithm != GNUTLS_PK_RSA) {
+               gnutls_assert();
+               return GNUTLS_E_INVALID_REQUEST;
+       }
+       
+       switch(key->type) {
+               case GNUTLS_PRIVKEY_OPENPGP:
+                       return 
gnutls_openpgp_privkey_decrypt_data(key->key.openpgp, flags, ciphertext, 
plaintext);
+               case GNUTLS_PRIVKEY_X509:
+                       return _gnutls_pkcs1_rsa_decrypt (plaintext, 
ciphertext, key->key.x509->params, key->key.x509->params_size, 2);
+               case GNUTLS_PRIVKEY_PKCS11:
+                       return 
gnutls_pkcs11_privkey_decrypt_data(key->key.pkcs11, flags, ciphertext, 
plaintext);
+               default:
+                       gnutls_assert();
+                       return GNUTLS_E_INVALID_REQUEST;
+       }
+}
+
diff --git a/lib/gnutls_psk.c b/lib/gnutls_psk.c
index 1a8d87d..a1f2774 100644
--- a/lib/gnutls_psk.c
+++ b/lib/gnutls_psk.c
@@ -416,7 +416,7 @@ gnutls_hex_encode (const gnutls_datum_t * data, char 
*result,
       return GNUTLS_E_SHORT_MEMORY_BUFFER;
     }
 
-  _gnutls_bin2hex (data->data, data->size, result, *result_size);
+  _gnutls_bin2hex (data->data, data->size, result, *result_size, NULL);
   *result_size = res;
 
   return 0;
diff --git a/lib/gnutls_pubkey.c b/lib/gnutls_pubkey.c
new file mode 100644
index 0000000..58f93b1
--- /dev/null
+++ b/lib/gnutls_pubkey.c
@@ -0,0 +1,938 @@
+/*
+ * GnuTLS PKCS#11 support
+ * Copyright (C) 2010 Free Software Foundation
+ * 
+ * Author: Nikos Mavrogiannopoulos
+ *
+ * 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
+*/
+
+#include <gnutls_int.h>
+#include <pakchois/pakchois.h>
+#include <gnutls/pkcs11.h>
+#include <stdio.h>
+#include <stdbool.h>
+#include <string.h>
+#include <gnutls_errors.h>
+#include <gnutls_datum.h>
+#include <pkcs11_int.h>
+#include <gnutls/abstract.h>
+#include <sign.h>
+#include <gnutls_pk.h>
+#include <x509_int.h>
+#include <openpgp/openpgp_int.h>
+#include <pkcs11_int.h>
+#include <gnutls_num.h>
+#include <x509/common.h>
+#include <x509_b64.h>
+
+#define PK_PEM_HEADER "PUBLIC KEY"
+
+
+struct gnutls_pubkey_st {
+       gnutls_pk_algorithm_t pk_algorithm;
+       unsigned int bits;      /* an indication of the security parameter */
+
+       /* the size of params depends on the public
+        * key algorithm
+        * RSA: [0] is modulus
+        *      [1] is public exponent
+        * DSA: [0] is p
+        *      [1] is q
+        *      [2] is g
+        *      [3] is public key
+        */
+       bigint_t params[MAX_PUBLIC_PARAMS_SIZE];
+       int params_size;        /* holds the size of MPI params */
+
+       unsigned int key_usage; /* bits from GNUTLS_KEY_* */
+};
+
+/**
+ * gnutls_pubkey_get_pk_algorithm:
+ * @key: should contain a #gnutls_pubkey_t structure
+ * @bits: If set will return the number of bits of the parameters (may be NULL)
+ *
+ * This function will return the public key algorithm of a public
+ * key and if possible will return a number of bits that indicates
+ * the security parameter of the key.
+ *
+ * Returns: a member of the #gnutls_pk_algorithm_t enumeration on
+ *   success, or a negative value on error.
+ **/
+int gnutls_pubkey_get_pk_algorithm(gnutls_pubkey_t key, unsigned int *bits)
+{
+       if (bits)
+               *bits = key->bits;
+
+       return key->pk_algorithm;
+}
+
+/**
+ * gnutls_pubkey_get_key_usage:
+ * @key: should contain a #gnutls_pubkey_t structure
+ * @usage: If set will return the number of bits of the parameters (may be 
NULL)
+ *
+ * This function will return the key usage of the public key.
+ *
+ * Returns: On success, %GNUTLS_E_SUCCESS is returned, otherwise a
+ *   negative error value.
+ **/
+int gnutls_pubkey_get_key_usage(gnutls_pubkey_t key, unsigned int *usage)
+{
+       if (usage)
+               *usage = key->key_usage;
+
+       return 0;
+}
+
+/**
+ * gnutls_pubkey_init:
+ * @key: The structure to be initialized
+ *
+ * This function will initialize an public key structure.
+ *
+ * Returns: On success, %GNUTLS_E_SUCCESS is returned, otherwise a
+ *   negative error value.
+ **/
+int gnutls_pubkey_init(gnutls_pubkey_t * key)
+{
+       *key = gnutls_calloc(1, sizeof(struct gnutls_pubkey_st));
+       if (*key == NULL) {
+               gnutls_assert();
+               return GNUTLS_E_MEMORY_ERROR;
+       }
+
+       return 0;
+}
+
+/**
+ * gnutls_pubkey_deinit:
+ * @key: The structure to be deinitialized
+ *
+ * This function will deinitialize a public key structure.
+ **/
+void gnutls_pubkey_deinit(gnutls_pubkey_t key)
+{
+       gnutls_free(key);
+}
+
+/**
+ * gnutls_pubkey_import_x509:
+ * @key: The public key
+ * @crt: The certificate to be imported
+ * @flags: should be zero
+ *
+ * This function will import the given public key to the abstract
+ * #gnutls_pubkey_t structure.
+ *
+ * Returns: On success, %GNUTLS_E_SUCCESS is returned, otherwise a
+ *   negative error value.
+ **/
+int gnutls_pubkey_import_x509(gnutls_pubkey_t key, gnutls_x509_crt_t crt,
+                             unsigned int flags)
+{
+       int ret;
+
+       key->pk_algorithm =
+           gnutls_x509_crt_get_pk_algorithm(crt, &key->bits);
+
+       ret = gnutls_x509_crt_get_key_usage(crt, &key->key_usage, NULL);
+       if (ret < 0)
+               key->key_usage = 0;
+
+       key->params_size = sizeof(key->params) / sizeof(key->params[0]);
+       switch (key->pk_algorithm) {
+       case GNUTLS_PK_RSA:
+               ret =
+                   _gnutls_x509_crt_get_mpis(crt, key->params,
+                                             &key->params_size);
+               if (ret < 0) {
+                       gnutls_assert();
+                       return ret;
+               }
+               break;
+       case GNUTLS_PK_DSA:
+               ret =
+                   _gnutls_x509_crt_get_mpis(crt, key->params,
+                                             &key->params_size);
+               if (ret < 0) {
+                       gnutls_assert();
+                       return ret;
+               }
+
+               break;
+       default:
+               gnutls_assert();
+               return GNUTLS_E_INVALID_REQUEST;
+       }
+
+       return 0;
+}
+
+/**
+ * gnutls_pubkey_get_preferred_hash_algorithm:
+ * @key: Holds the certificate
+ * @hash: The result of the call with the hash algorithm used for signature
+ * @mand: If non zero it means that the algorithm MUST use this hash. May be 
NULL.
+ *
+ * This function will read the certifcate and return the appropriate digest
+ * algorithm to use for signing with this certificate. Some certificates (i.e.
+ * DSA might not be able to sign without the preferred algorithm).
+ *
+ * Returns: the 0 if the hash algorithm is found. A negative value is
+ * returned on error.
+ *
+ * Since: 2.11.0
+ **/
+int
+gnutls_pubkey_get_preferred_hash_algorithm (gnutls_pubkey_t key,
+                             gnutls_digest_algorithm_t * hash, unsigned int 
*mand)
+{
+  int ret;
+
+  if (key == NULL)
+    {
+      gnutls_assert ();
+      return GNUTLS_E_INVALID_REQUEST;
+    }
+
+  ret = _gnutls_pk_get_hash_algorithm(key->pk_algorithm,
+    key->params, key->params_size, hash, mand);
+
+  return ret;
+}
+
+
+/**
+ * gnutls_pubkey_import_pkcs11:
+ * @key: The public key
+ * @obj: The parameters to be imported
+ * @flags: should be zero
+ *
+ * This function will import the given public key to the abstract
+ * #gnutls_pubkey_t structure.
+ *
+ * Returns: On success, %GNUTLS_E_SUCCESS is returned, otherwise a
+ *   negative error value.
+ **/
+int gnutls_pubkey_import_pkcs11(gnutls_pubkey_t key,
+                               gnutls_pkcs11_obj_t obj,
+                               unsigned int flags)
+{
+       int ret;
+
+       ret = gnutls_pkcs11_obj_get_type(obj);
+       if (ret != GNUTLS_PKCS11_OBJ_PUBKEY) {
+               gnutls_assert();
+               return GNUTLS_E_INVALID_REQUEST;
+       }
+
+       key->key_usage = obj->key_usage;
+
+       switch (obj->pk_algorithm) {
+       case GNUTLS_PK_RSA:
+               ret = gnutls_pubkey_import_rsa_raw(key, &obj->pubkey[0],
+                                                  &obj->pubkey[1]);
+               break;
+       case GNUTLS_PK_DSA:
+               ret = gnutls_pubkey_import_dsa_raw(key, &obj->pubkey[0],
+                                                  &obj->pubkey[1],
+                                                  &obj->pubkey[2],
+                                                  &obj->pubkey[3]);
+               break;
+       default:
+               gnutls_assert();
+               return GNUTLS_E_UNIMPLEMENTED_FEATURE;
+       }
+
+       if (ret < 0) {
+               gnutls_assert();
+               return ret;
+       }
+
+       return 0;
+}
+
+/**
+ * gnutls_pubkey_import_openpgp:
+ * @key: The public key
+ * @crt: The certificate to be imported
+ * @flags: should be zero
+ *
+ * This function will import the given public key to the abstract
+ * #gnutls_pubkey_t structure.
+ *
+ * Returns: On success, %GNUTLS_E_SUCCESS is returned, otherwise a
+ *   negative error value.
+ **/
+int gnutls_pubkey_import_openpgp(gnutls_pubkey_t key,
+                                gnutls_openpgp_crt_t crt,
+                                gnutls_openpgp_keyid_t keyid,
+                                unsigned int flags)
+{
+       int ret;
+       uint32_t kid32[2];
+
+       ret = gnutls_openpgp_crt_get_preferred_key_id(crt, keyid);
+       if (ret < 0) {
+               gnutls_assert();
+               return ret;
+       }
+
+       KEYID_IMPORT(kid32, keyid);
+
+       key->pk_algorithm =
+           gnutls_openpgp_crt_get_pk_algorithm(crt, &key->bits);
+
+       ret = gnutls_openpgp_crt_get_key_usage(crt, &key->key_usage);
+       if (ret < 0)
+               key->key_usage = 0;
+
+       switch (key->pk_algorithm) {
+       case GNUTLS_PK_RSA:
+               ret =
+                   _gnutls_openpgp_crt_get_mpis(crt, kid32, key->params,
+                                                &key->params_size);
+               if (ret < 0) {
+                       gnutls_assert();
+                       return ret;
+               }
+               break;
+       case GNUTLS_PK_DSA:
+               ret =
+                   _gnutls_openpgp_crt_get_mpis(crt, kid32, key->params,
+                                                &key->params_size);
+               if (ret < 0) {
+                       gnutls_assert();
+                       return ret;
+               }
+               break;
+       default:
+               gnutls_assert();
+               return GNUTLS_E_INVALID_REQUEST;
+       }
+
+       return 0;
+}
+
+/**
+ * gnutls_pubkey_export:
+ * @key: Holds the certificate
+ * @format: the format of output params. One of PEM or DER.
+ * @output_data: will contain a certificate PEM or DER encoded
+ * @output_data_size: holds the size of output_data (and will be
+ *   replaced by the actual size of parameters)
+ *
+ * This function will export the certificate to DER or PEM format.
+ *
+ * If the buffer provided is not long enough to hold the output, then
+ * *output_data_size is updated and GNUTLS_E_SHORT_MEMORY_BUFFER will
+ * be returned.
+ *
+ * If the structure is PEM encoded, it will have a header
+ * of "BEGIN CERTIFICATE".
+ *
+ * Return value: In case of failure a negative value will be
+ *   returned, and 0 on success.
+ **/
+int
+gnutls_pubkey_export(gnutls_pubkey_t key,
+                    gnutls_x509_crt_fmt_t format, void *output_data,
+                    size_t * output_data_size)
+{
+       int result;
+       ASN1_TYPE spk = ASN1_TYPE_EMPTY;
+
+       if (key == NULL) {
+               gnutls_assert();
+               return GNUTLS_E_INVALID_REQUEST;
+       }
+
+       if ((result = asn1_create_element
+            (_gnutls_get_pkix(), "PKIX1.SubjectPublicKeyInfo", &spk))
+           != ASN1_SUCCESS) {
+               gnutls_assert();
+               return _gnutls_asn2err(result);
+       }
+
+       result =
+           _gnutls_x509_encode_and_copy_PKI_params(spk, "",
+                                                   key->pk_algorithm,
+                                                   key->params,
+                                                   key->params_size);
+       if (result < 0) {
+               gnutls_assert();
+               goto cleanup;
+       }
+
+       result = _gnutls_x509_export_int_named(spk, "",
+                                              format, PK_PEM_HEADER,
+                                              output_data,
+                                              output_data_size);
+       if (result < 0) {
+               gnutls_assert();
+               goto cleanup;
+       }
+
+       result = 0;
+
+      cleanup:
+       asn1_delete_structure(&spk);
+
+       return result;
+
+}
+
+/**
+ * gnutls_pubkey_get_key_id:
+ * @key: Holds the public key
+ * @flags: should be 0 for now
+ * @output_data: will contain the key ID
+ * @output_data_size: holds the size of output_data (and will be
+ *   replaced by the actual size of parameters)
+ *
+ * This function will return a unique ID the depends on the public
+ * key parameters. This ID can be used in checking whether a
+ * certificate corresponds to the given public key.
+ *
+ * If the buffer provided is not long enough to hold the output, then
+ * *output_data_size is updated and GNUTLS_E_SHORT_MEMORY_BUFFER will
+ * be returned.  The output will normally be a SHA-1 hash output,
+ * which is 20 bytes.
+ *
+ * Return value: In case of failure a negative value will be
+ *   returned, and 0 on success.
+ **/
+int
+gnutls_pubkey_get_key_id(gnutls_pubkey_t key, unsigned int flags,
+                        unsigned char *output_data,
+                        size_t * output_data_size)
+{
+       int ret = 0;
+
+       if (key == NULL) {
+               gnutls_assert();
+               return GNUTLS_E_INVALID_REQUEST;
+       }
+
+       ret =
+           _gnutls_get_key_id(key->pk_algorithm, key->params,
+                              key->params_size, output_data,
+                              output_data_size);
+       if (ret < 0) {
+               gnutls_assert();
+               return ret;
+       }
+
+       return 0;
+}
+
+/**
+ * gnutls_pubkey_get_pk_rsa_raw:
+ * @key: Holds the certificate
+ * @m: will hold the modulus
+ * @e: will hold the public exponent
+ *
+ * This function will export the RSA public key's parameters found in
+ * the given structure.  The new parameters will be allocated using
+ * gnutls_malloc() and will be stored in the appropriate datum.
+ *
+ * Returns: %GNUTLS_E_SUCCESS on success, otherwise an error.
+ **/
+int
+gnutls_pubkey_get_pk_rsa_raw(gnutls_pubkey_t key,
+                            gnutls_datum_t * m, gnutls_datum_t * e)
+{
+       int ret;
+
+       if (key == NULL) {
+               gnutls_assert();
+               return GNUTLS_E_INVALID_REQUEST;
+       }
+
+       if (key->pk_algorithm != GNUTLS_PK_RSA) {
+               gnutls_assert();
+               return GNUTLS_E_INVALID_REQUEST;
+       }
+
+       ret = _gnutls_mpi_dprint(key->params[0], m);
+       if (ret < 0) {
+               gnutls_assert();
+               return ret;
+       }
+
+       ret = _gnutls_mpi_dprint(key->params[1], e);
+       if (ret < 0) {
+               gnutls_assert();
+               _gnutls_free_datum(m);
+               return ret;
+       }
+
+       return 0;
+}
+
+/**
+ * gnutls_pubkey_get_pk_dsa_raw:
+ * @key: Holds the public key
+ * @p: will hold the p
+ * @q: will hold the q
+ * @g: will hold the g
+ * @y: will hold the y
+ *
+ * This function will export the DSA public key's parameters found in
+ * the given certificate.  The new parameters will be allocated using
+ * gnutls_malloc() and will be stored in the appropriate datum.
+ *
+ * Returns: %GNUTLS_E_SUCCESS on success, otherwise an error.
+ **/
+int
+gnutls_pubkey_get_pk_dsa_raw(gnutls_pubkey_t key,
+                            gnutls_datum_t * p, gnutls_datum_t * q,
+                            gnutls_datum_t * g, gnutls_datum_t * y)
+{
+       int ret;
+
+       if (key == NULL) {
+               gnutls_assert();
+               return GNUTLS_E_INVALID_REQUEST;
+       }
+
+       if (key->pk_algorithm != GNUTLS_PK_DSA) {
+               gnutls_assert();
+               return GNUTLS_E_INVALID_REQUEST;
+       }
+
+       /* P */
+       ret = _gnutls_mpi_dprint(key->params[0], p);
+       if (ret < 0) {
+               gnutls_assert();
+               return ret;
+       }
+
+       /* Q */
+       ret = _gnutls_mpi_dprint(key->params[1], q);
+       if (ret < 0) {
+               gnutls_assert();
+               _gnutls_free_datum(p);
+               return ret;
+       }
+
+
+       /* G */
+       ret = _gnutls_mpi_dprint(key->params[2], g);
+       if (ret < 0) {
+               gnutls_assert();
+               _gnutls_free_datum(p);
+               _gnutls_free_datum(q);
+               return ret;
+       }
+
+
+       /* Y */
+       ret = _gnutls_mpi_dprint(key->params[3], y);
+       if (ret < 0) {
+               gnutls_assert();
+               _gnutls_free_datum(p);
+               _gnutls_free_datum(g);
+               _gnutls_free_datum(q);
+               return ret;
+       }
+
+       return 0;
+}
+
+/**
+ * gnutls_pubkey_import:
+ * @key: The structure to store the parsed certificate. 
+ * @data: The DER or PEM encoded certificate. 
+ * @format: One of DER or PEM 
+ * 
+ * This function will convert the given DER or PEM encoded Public key 
+ * to the native gnutls_pubkey_t format.The output will be stored * in @ key. 
+ * If the Certificate is PEM encoded it should have a header of "PUBLIC KEY". 
+ * 
+ * Returns: On success, %GNUTLS_E_SUCCESS is returned, otherwise a
+ * negative error value.
+ **/
+int gnutls_pubkey_import(gnutls_pubkey_t key,
+                        const gnutls_datum_t * data,
+                        gnutls_x509_crt_fmt_t format)
+{
+       int result = 0, need_free = 0;
+       gnutls_datum_t _data;
+       ASN1_TYPE spk;
+
+       if (key == NULL) {
+               gnutls_assert();
+               return GNUTLS_E_INVALID_REQUEST;
+       }
+
+       _data.data = data->data;
+       _data.size = data->size;
+
+       /* If the Certificate is in PEM format then decode it
+        */
+       if (format == GNUTLS_X509_FMT_PEM) {
+               opaque *out;
+
+               /* Try the first header */
+               result =
+                   _gnutls_fbase64_decode(PK_PEM_HEADER, data->data,
+                                          data->size, &out);
+
+               if (result <= 0) {
+                       if (result == 0)
+                               result = GNUTLS_E_INTERNAL_ERROR;
+                       gnutls_assert();
+                       return result;
+               }
+
+               _data.data = out;
+               _data.size = result;
+
+               need_free = 1;
+       }
+
+       if ((result = asn1_create_element
+            (_gnutls_get_pkix(), "PKIX1.SubjectPublicKeyInfo", &spk))
+           != ASN1_SUCCESS) {
+               gnutls_assert();
+               result = _gnutls_asn2err(result);
+               goto cleanup;
+       }
+
+       result = asn1_der_decoding(&spk, _data.data, _data.size, NULL);
+       if (result != ASN1_SUCCESS) {
+               gnutls_assert();
+               result = _gnutls_asn2err(result);
+               goto cleanup;
+       }
+
+       key->params_size = sizeof(key->params) / sizeof(key->params[0]);
+       result =
+           _gnutls_get_asn_mpis(spk, "", key->params, &key->params_size);
+       if (result < 0) {
+               gnutls_assert();
+               goto cleanup;
+       }
+
+       /* this has already been called by get_asn_mpis() thus it cannot
+        * fail.
+        */
+       key->pk_algorithm = _gnutls_x509_get_pk_algorithm(spk, "", NULL);
+
+       result = 0;
+
+      cleanup:
+       asn1_delete_structure(&spk);
+
+       if (need_free)
+               _gnutls_free_datum(&_data);
+       return result;
+}
+
+/**
+ * gnutls_x509_crt_set_pubkey:
+ * @crt: should contain a #gnutls_x509_crt_t structure
+ * @key: holds a public key
+ *
+ * This function will set the public parameters from the given public
+ * key to the request.
+ *
+ * Returns: On success, %GNUTLS_E_SUCCESS is returned, otherwise a
+ *   negative error value.
+ **/
+int gnutls_x509_crt_set_pubkey(gnutls_x509_crt_t crt, gnutls_pubkey_t key)
+{
+       int result;
+
+       if (crt == NULL) {
+               gnutls_assert();
+               return GNUTLS_E_INVALID_REQUEST;
+       }
+
+       result = _gnutls_x509_encode_and_copy_PKI_params(crt->cert,
+                                                        
"tbsCertificate.subjectPublicKeyInfo",
+                                                        key->pk_algorithm,
+                                                        key->params,
+                                                        key->params_size);
+
+       if (result < 0) {
+               gnutls_assert();
+               return result;
+       }
+
+       if (key->key_usage)
+               gnutls_x509_crt_set_key_usage(crt, key->key_usage);
+
+       return 0;
+}
+
+/**
+ * gnutls_x509_crq_set_pubkey:
+ * @crq: should contain a #gnutls_x509_crq_t structure
+ * @key: holds a public key
+ *
+ * This function will set the public parameters from the given public
+ * key to the request.
+ *
+ * Returns: On success, %GNUTLS_E_SUCCESS is returned, otherwise a
+ *   negative error value.
+ **/
+int gnutls_x509_crq_set_pubkey(gnutls_x509_crq_t crq, gnutls_pubkey_t key)
+{
+       int result;
+
+       if (crq == NULL) {
+               gnutls_assert();
+               return GNUTLS_E_INVALID_REQUEST;
+       }
+
+       result = _gnutls_x509_encode_and_copy_PKI_params
+           (crq->crq,
+            "certificationRequestInfo.subjectPKInfo",
+            key->pk_algorithm, key->params, key->params_size);
+
+       if (result < 0) {
+               gnutls_assert();
+               return result;
+       }
+
+       if (key->key_usage)
+               gnutls_x509_crq_set_key_usage(crq, key->key_usage);
+
+       return 0;
+}
+
+/**
+ * gnutls_pubkey_set_key_usage:
+ * @crt: a certificate of type #gnutls_x509_crt_t
+ * @usage: an ORed sequence of the GNUTLS_KEY_* elements.
+ *
+ * This function will set the keyUsage certificate extension.
+ *
+ * Returns: On success, %GNUTLS_E_SUCCESS is returned, otherwise a
+ *   negative error value.
+ **/
+int gnutls_pubkey_set_key_usage(gnutls_pubkey_t key, unsigned int usage)
+{
+       key->key_usage = usage;
+
+       return 0;
+}
+
+int gnutls_pubkey_import_pkcs11_url(gnutls_pubkey_t key, const char *url)
+{
+       gnutls_pkcs11_obj_t pcrt;
+       int ret;
+
+       ret = gnutls_pkcs11_obj_init(&pcrt);
+       if (ret < 0) {
+               gnutls_assert();
+               return ret;
+       }
+
+       ret = gnutls_pkcs11_obj_import_url(pcrt, url);
+       if (ret < 0) {
+               gnutls_assert();
+               goto cleanup;
+       }
+
+       ret = gnutls_pubkey_import_pkcs11(key, pcrt, 0);
+       if (ret < 0) {
+               gnutls_assert();
+               goto cleanup;
+       }
+
+       ret = 0;
+      cleanup:
+
+       gnutls_pkcs11_obj_deinit(pcrt);
+
+       return ret;
+}
+
+/**
+ * gnutls_pubkey_import_rsa_raw:
+ * @key: Is a structure will hold the parameters
+ * @m: holds the modulus
+ * @e: holds the public exponent
+ *
+ * This function will replace the parameters in the given structure.
+ * The new parameters should be stored in the appropriate
+ * gnutls_datum.
+ *
+ * Returns: %GNUTLS_E_SUCCESS on success, or an negative error code.
+ **/
+int
+gnutls_pubkey_import_rsa_raw(gnutls_pubkey_t key,
+                            const gnutls_datum_t * m,
+                            const gnutls_datum_t * e)
+{
+       size_t siz = 0;
+
+       if (key == NULL) {
+               gnutls_assert();
+               return GNUTLS_E_INVALID_REQUEST;
+       }
+
+       siz = m->size;
+       if (_gnutls_mpi_scan_nz(&key->params[0], m->data, siz)) {
+               gnutls_assert();
+               return GNUTLS_E_MPI_SCAN_FAILED;
+       }
+
+       siz = e->size;
+       if (_gnutls_mpi_scan_nz(&key->params[1], e->data, siz)) {
+               gnutls_assert();
+               _gnutls_mpi_release(&key->params[0]);
+               return GNUTLS_E_MPI_SCAN_FAILED;
+       }
+
+       key->params_size = RSA_PUBLIC_PARAMS;
+       key->pk_algorithm = GNUTLS_PK_RSA;
+
+       return 0;
+}
+
+/**
+ * gnutls_pubkey_import_dsa_raw:
+ * @key: The structure to store the parsed key
+ * @p: holds the p
+ * @q: holds the q
+ * @g: holds the g
+ * @y: holds the y
+ *
+ * This function will convert the given DSA raw parameters to the
+ * native #gnutls_pubkey_t format.  The output will be stored
+ * in @key.
+ *
+ * Returns: On success, %GNUTLS_E_SUCCESS is returned, otherwise a
+ *   negative error value.
+ **/
+int
+gnutls_pubkey_import_dsa_raw(gnutls_pubkey_t key,
+                            const gnutls_datum_t * p,
+                            const gnutls_datum_t * q,
+                            const gnutls_datum_t * g,
+                            const gnutls_datum_t * y)
+{
+       size_t siz = 0;
+
+       if (key == NULL) {
+               gnutls_assert();
+               return GNUTLS_E_INVALID_REQUEST;
+       }
+
+       siz = p->size;
+       if (_gnutls_mpi_scan_nz(&key->params[0], p->data, siz)) {
+               gnutls_assert();
+               return GNUTLS_E_MPI_SCAN_FAILED;
+       }
+
+       siz = q->size;
+       if (_gnutls_mpi_scan_nz(&key->params[1], q->data, siz)) {
+               gnutls_assert();
+               _gnutls_mpi_release(&key->params[0]);
+               return GNUTLS_E_MPI_SCAN_FAILED;
+       }
+
+       siz = g->size;
+       if (_gnutls_mpi_scan_nz(&key->params[2], g->data, siz)) {
+               gnutls_assert();
+               _gnutls_mpi_release(&key->params[1]);
+               _gnutls_mpi_release(&key->params[0]);
+               return GNUTLS_E_MPI_SCAN_FAILED;
+       }
+
+       siz = y->size;
+       if (_gnutls_mpi_scan_nz(&key->params[3], y->data, siz)) {
+               gnutls_assert();
+               _gnutls_mpi_release(&key->params[2]);
+               _gnutls_mpi_release(&key->params[1]);
+               _gnutls_mpi_release(&key->params[0]);
+               return GNUTLS_E_MPI_SCAN_FAILED;
+       }
+
+       key->params_size = DSA_PUBLIC_PARAMS;
+       key->pk_algorithm = GNUTLS_PK_DSA;
+
+       return 0;
+
+}
+
+/**
+ * gnutls_pubkey_verify_hash:
+ * @key: Holds the certificate
+ * @flags: should be 0 for now
+ * @hash: holds the hash digest to be verified
+ * @signature: contains the signature
+ *
+ * This function will verify the given signed digest, using the
+ * parameters from the certificate.
+ *
+ * Returns: In case of a verification failure 0 is returned, and 1 on
+ * success.
+ **/
+int
+gnutls_pubkey_verify_hash (gnutls_pubkey_t key, unsigned int flags,
+                            const gnutls_datum_t * hash,
+                            const gnutls_datum_t * signature)
+{
+  int ret;
+
+  if (key == NULL)
+    {
+      gnutls_assert ();
+      return GNUTLS_E_INVALID_REQUEST;
+    }
+
+   ret =
+    pubkey_verify_sig (NULL, hash, signature, key->pk_algorithm,
+               key->params, key->params_size);
+
+  return ret;
+}
+
+/**
+ * gnutls_pubkey_get_verify_algorithm:
+ * @key: Holds the certificate
+ * @signature: contains the signature
+ * @hash: The result of the call with the hash algorithm used for signature
+ *
+ * This function will read the certifcate and the signed data to
+ * determine the hash algorithm used to generate the signature.
+ *
+ * Returns: the 0 if the hash algorithm is found. A negative value is
+ * returned on error.
+ **/
+int
+gnutls_pubkey_get_verify_algorithm (gnutls_pubkey_t key,
+                                     const gnutls_datum_t * signature,
+                                     gnutls_digest_algorithm_t * hash)
+{
+  if (key == NULL)
+    {
+      gnutls_assert ();
+      return GNUTLS_E_INVALID_REQUEST;
+    }
+
+  return _gnutls_x509_verify_algorithm ((gnutls_mac_algorithm_t *) hash,
+                       signature, key->pk_algorithm, key->params,
+                       key->params_size);
+
+}
diff --git a/lib/gnutls_record.c b/lib/gnutls_record.c
index f78a91f..1209e0d 100644
--- a/lib/gnutls_record.c
+++ b/lib/gnutls_record.c
@@ -32,6 +32,7 @@
 #include "gnutls_compress.h"
 #include "gnutls_cipher.h"
 #include "gnutls_buffers.h"
+#include "gnutls_mbuffers.h"
 #include "gnutls_handshake.h"
 #include "gnutls_hash_int.h"
 #include "gnutls_cipher_int.h"
@@ -336,8 +337,8 @@ _gnutls_send_int (gnutls_session_t session, content_type_t 
type,
                  gnutls_handshake_description_t htype, const void *_data,
                  size_t sizeofdata)
 {
-  uint8_t *cipher;
-  int cipher_size;
+  mbuffer_st *bufel;
+  size_t cipher_size;
   int retval, ret;
   int data2send_size;
   uint8_t headers[5];
@@ -347,7 +348,7 @@ _gnutls_send_int (gnutls_session_t session, content_type_t 
type,
    * If the previous send was interrupted then a null pointer is
    * ok, and means to resume.
    */
-  if (session->internals.record_send_buffer.length == 0 &&
+  if (session->internals.record_send_buffer.byte_length == 0 &&
       (sizeofdata == 0 && _data == NULL))
     {
       gnutls_assert ();
@@ -383,7 +384,7 @@ _gnutls_send_int (gnutls_session_t session, content_type_t 
type,
   /* Only encrypt if we don't have data to send 
    * from the previous run. - probably interrupted.
    */
-  if (session->internals.record_send_buffer.length > 0)
+  if (session->internals.record_send_buffer.byte_length > 0)
     {
       ret = _gnutls_io_write_flush (session);
       if (ret > 0)
@@ -391,9 +392,7 @@ _gnutls_send_int (gnutls_session_t session, content_type_t 
type,
       else
        cipher_size = 0;
 
-      cipher = NULL;
-
-      retval = session->internals.record_send_buffer_user_size;
+      retval = session->internals.record_send_buffer.byte_length;
     }
   else
     {
@@ -401,8 +400,8 @@ _gnutls_send_int (gnutls_session_t session, content_type_t 
type,
       /* now proceed to packet encryption
        */
       cipher_size = data2send_size + MAX_RECORD_OVERHEAD;
-      cipher = gnutls_malloc (cipher_size);
-      if (cipher == NULL)
+      bufel = _gnutls_mbuffer_alloc (cipher_size);
+      if (bufel == NULL)
        {
          gnutls_assert ();
          return GNUTLS_E_MEMORY_ERROR;
@@ -410,7 +409,7 @@ _gnutls_send_int (gnutls_session_t session, content_type_t 
type,
 
       cipher_size =
        _gnutls_encrypt (session, headers, RECORD_HEADER_SIZE, data,
-                        data2send_size, cipher, cipher_size, type,
+                        data2send_size, _mbuffer_get_udata_ptr(bufel), 
cipher_size, type,
                         (session->internals.priorities.no_padding ==
                          0) ? 1 : 0);
       if (cipher_size <= 0)
@@ -418,12 +417,11 @@ _gnutls_send_int (gnutls_session_t session, 
content_type_t type,
          gnutls_assert ();
          if (cipher_size == 0)
            cipher_size = GNUTLS_E_ENCRYPTION_FAILED;
-         gnutls_free (cipher);
+         gnutls_free (bufel);
          return cipher_size;   /* error */
        }
 
       retval = data2send_size;
-      session->internals.record_send_buffer_user_size = data2send_size;
 
       /* increase sequence number
        */
@@ -432,12 +430,12 @@ _gnutls_send_int (gnutls_session_t session, 
content_type_t type,
        {
          session_invalidate (session);
          gnutls_assert ();
-         gnutls_free (cipher);
+         gnutls_free (bufel);
          return GNUTLS_E_RECORD_LIMIT_REACHED;
        }
 
-      ret = _gnutls_io_write_buffered (session, cipher, cipher_size);
-      gnutls_free (cipher);
+      _mbuffer_set_udata_size(bufel, cipher_size);
+      ret = _gnutls_io_write_buffered (session, bufel);
     }
 
   if (ret != cipher_size)
@@ -462,8 +460,6 @@ _gnutls_send_int (gnutls_session_t session, content_type_t 
type,
       return ret;
     }
 
-  session->internals.record_send_buffer_user_size = 0;
-
   _gnutls_record_log ("REC[%p]: Sent Packet[%d] %s(%d) with length: %d\n",
                      session,
                      (int)
@@ -744,14 +740,12 @@ record_check_type (gnutls_session_t session,
          if (session->security_parameters.entity == GNUTLS_SERVER)
            {
              gnutls_assert ();
-             ret =
-               _gnutls_record_buffer_put (recv_type, session, (void *) data,
-                                          data_size);
-             if (ret < 0)
-               {
-                 gnutls_assert ();
-                 return ret;
-               }
+             ret = _gnutls_record_buffer_put (recv_type, session, (void *) 
data, data_size);
+             if (ret < 0) 
+               {
+                 gnutls_assert();
+                 return ret;
+                }
              return GNUTLS_E_REHANDSHAKE;
            }
 
diff --git a/lib/gnutls_sig.c b/lib/gnutls_sig.c
index 10ca29b..a262824 100644
--- a/lib/gnutls_sig.c
+++ b/lib/gnutls_sig.c
@@ -43,7 +43,7 @@
 
 static int
 _gnutls_tls_sign (gnutls_session_t session,
-                 gnutls_cert * cert, gnutls_privkey * pkey,
+                 gnutls_cert * cert, gnutls_privkey_t pkey,
                  const gnutls_datum_t * hash_concat,
                  gnutls_datum_t * signature);
 
@@ -127,7 +127,7 @@ _gnutls_rsa_encode_sig (gnutls_mac_algorithm_t algo,
  */
 int
 _gnutls_handshake_sign_data (gnutls_session_t session, gnutls_cert * cert,
-                            gnutls_privkey * pkey, gnutls_datum_t * params,
+                            gnutls_privkey_t pkey, gnutls_datum_t * params,
                             gnutls_datum_t * signature,
                             gnutls_sign_algorithm_t * sign_algo)
 {
@@ -203,13 +203,14 @@ _gnutls_handshake_sign_data (gnutls_session_t session, 
gnutls_cert * cert,
     case GNUTLS_PK_DSA:
       _gnutls_hash_deinit (&td_sha, concat);
 
-      if (hash_algo != GNUTLS_DIG_SHA1)
+      if ((hash_algo != GNUTLS_DIG_SHA1) && (hash_algo != GNUTLS_DIG_SHA224) 
&& \
+        (hash_algo != GNUTLS_DIG_SHA256))
        {
          gnutls_assert ();
          return GNUTLS_E_INTERNAL_ERROR;
        }
       dconcat.data = concat;
-      dconcat.size = 20;
+      dconcat.size = _gnutls_hash_get_algo_len (hash_algo);
       break;
 
     default:
@@ -232,7 +233,7 @@ _gnutls_handshake_sign_data (gnutls_session_t session, 
gnutls_cert * cert,
  * given data. The output will be allocated and be put in signature.
  */
 int
-_gnutls_sign (gnutls_pk_algorithm_t algo, bigint_t * params,
+_gnutls_soft_sign (gnutls_pk_algorithm_t algo, bigint_t * params,
              int params_size, const gnutls_datum_t * data,
              gnutls_datum_t * signature)
 {
@@ -273,7 +274,7 @@ _gnutls_sign (gnutls_pk_algorithm_t algo, bigint_t * params,
  */
 static int
 _gnutls_tls_sign (gnutls_session_t session,
-                 gnutls_cert * cert, gnutls_privkey * pkey,
+                 gnutls_cert * cert, gnutls_privkey_t pkey,
                  const gnutls_datum_t * hash_concat,
                  gnutls_datum_t * signature)
 {
@@ -291,7 +292,7 @@ _gnutls_tls_sign (gnutls_session_t session,
          }
 
       /* External signing. */
-      if (!pkey || pkey->params_size == 0)
+      if (!pkey)
        {
          if (!session->internals.sign_func)
            return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
@@ -302,8 +303,7 @@ _gnutls_tls_sign (gnutls_session_t session,
        }
     }
 
-  return _gnutls_sign (pkey->pk_algorithm, pkey->params,
-                      pkey->params_size, hash_concat, signature);
+  return gnutls_privkey_sign_hash(pkey, hash_concat, signature);
 }
 
 static int
@@ -623,7 +623,7 @@ _gnutls_handshake_verify_cert_vrfy (gnutls_session_t 
session,
  */
 static int
 _gnutls_handshake_sign_cert_vrfy12 (gnutls_session_t session,
-                                   gnutls_cert * cert, gnutls_privkey * pkey,
+                                   gnutls_cert * cert, gnutls_privkey_t pkey,
                                    gnutls_datum_t * signature)
 {
   gnutls_datum_t dconcat;
@@ -694,6 +694,7 @@ _gnutls_handshake_sign_cert_vrfy12 (gnutls_session_t 
session,
   return sign_algo;
 }
 
+
 /* Generates a signature of all the previous sent packets in the 
  * handshake procedure. 
  * 20040227: now it works for SSL 3.0 as well
@@ -704,7 +705,7 @@ _gnutls_handshake_sign_cert_vrfy12 (gnutls_session_t 
session,
  */
 int
 _gnutls_handshake_sign_cert_vrfy (gnutls_session_t session,
-                                 gnutls_cert * cert, gnutls_privkey * pkey,
+                                 gnutls_cert * cert, gnutls_privkey_t pkey,
                                  gnutls_datum_t * signature)
 {
   gnutls_datum_t dconcat;
diff --git a/lib/gnutls_sig.h b/lib/gnutls_sig.h
index f4539fb..b99210e 100644
--- a/lib/gnutls_sig.h
+++ b/lib/gnutls_sig.h
@@ -26,14 +26,16 @@
 #ifndef GNUTLS_SIG_H
 # define GNUTLS_SIG_H
 
+#include <gnutls/abstract.h>
+
 int _gnutls_handshake_sign_cert_vrfy (gnutls_session_t session,
                                      gnutls_cert * cert,
-                                     gnutls_privkey * pkey,
+                                     gnutls_privkey_t pkey,
                                      gnutls_datum_t * signature);
 
 int _gnutls_handshake_sign_data (gnutls_session_t session,
                                 gnutls_cert * cert,
-                                gnutls_privkey * pkey,
+                                gnutls_privkey_t  pkey,
                                 gnutls_datum_t * params,
                                 gnutls_datum_t * signature,
                                 gnutls_sign_algorithm_t * algo);
@@ -49,7 +51,7 @@ int _gnutls_handshake_verify_data (gnutls_session_t session,
                                   gnutls_datum_t * signature,
                                   gnutls_sign_algorithm_t algo);
 
-int _gnutls_sign (gnutls_pk_algorithm_t algo,
+int _gnutls_soft_sign (gnutls_pk_algorithm_t algo,
                  bigint_t * params, int params_size,
                  const gnutls_datum_t * data, gnutls_datum_t * signature);
 
diff --git a/lib/gnutls_srp.c b/lib/gnutls_srp.c
index 927ea83..8a8a844 100644
--- a/lib/gnutls_srp.c
+++ b/lib/gnutls_srp.c
@@ -48,6 +48,7 @@ _gnutls_srp_gx (opaque * text, size_t textsize, opaque ** 
result,
 {
   bigint_t x, e;
   size_t result_size;
+  int ret;
 
   if (_gnutls_mpi_scan_nz (&x, text, textsize))
     {
@@ -67,19 +68,25 @@ _gnutls_srp_gx (opaque * text, size_t textsize, opaque ** 
result,
   _gnutls_mpi_powm (e, g, x, prime);
   _gnutls_mpi_release (&x);
 
-  _gnutls_mpi_print (e, NULL, &result_size);
-  if (result != NULL)
+  ret = _gnutls_mpi_print (e, NULL, &result_size);
+  if (ret != GNUTLS_E_SHORT_MEMORY_BUFFER)
     {
       *result = galloc_func (result_size);
       if ((*result) == NULL)
        return GNUTLS_E_MEMORY_ERROR;
 
       _gnutls_mpi_print (e, *result, &result_size);
+      ret = result_size;
+    }
+  else
+    {
+      gnutls_assert();
+      ret = GNUTLS_E_MPI_PRINT_FAILED;
     }
 
   _gnutls_mpi_release (&e);
 
-  return result_size;
+  return ret;
 
 }
 
diff --git a/lib/gnutls_state.c b/lib/gnutls_state.c
index 0420edf..4dbb815 100644
--- a/lib/gnutls_state.c
+++ b/lib/gnutls_state.c
@@ -38,6 +38,7 @@
 #include <gnutls_handshake.h>
 #include <gnutls_dh.h>
 #include <gnutls_buffers.h>
+#include <gnutls_mbuffers.h>
 #include <gnutls_state.h>
 #include <auth_cert.h>
 #include <auth_anon.h>
@@ -48,9 +49,6 @@
 /* These should really be static, but src/tests.c calls them.  Make
    them public functions?  */
 void
-_gnutls_record_set_default_version (gnutls_session_t session,
-                                   unsigned char major, unsigned char minor);
-void
 _gnutls_rsa_pms_set_version (gnutls_session_t session,
                             unsigned char major, unsigned char minor);
 
@@ -157,7 +155,7 @@ _gnutls_session_cert_type_supported (gnutls_session_t 
session,
       if (cred == NULL)
        return GNUTLS_E_UNSUPPORTED_CERTIFICATE_TYPE;
 
-      if (cred->server_get_cert_callback == NULL)
+      if (cred->server_get_cert_callback == NULL && cred->get_cert_callback == 
NULL)
        {
          for (i = 0; i < cred->ncerts; i++)
            {
@@ -297,10 +295,10 @@ gnutls_init (gnutls_session_t * session, 
gnutls_connection_end_t con_end)
   _gnutls_buffer_init (&(*session)->internals.handshake_hash_buffer);
   _gnutls_buffer_init (&(*session)->internals.ia_data_buffer);
 
-  _gnutls_buffer_init (&(*session)->internals.record_send_buffer);
+  _gnutls_mbuffer_init (&(*session)->internals.record_send_buffer);
   _gnutls_buffer_init (&(*session)->internals.record_recv_buffer);
 
-  _gnutls_buffer_init (&(*session)->internals.handshake_send_buffer);
+  _gnutls_mbuffer_init (&(*session)->internals.handshake_send_buffer);
   _gnutls_buffer_init (&(*session)->internals.handshake_recv_buffer);
 
   (*session)->key = gnutls_calloc (1, sizeof (struct gnutls_key_st));
@@ -396,7 +394,7 @@ gnutls_deinit (gnutls_session_t session)
   _gnutls_buffer_clear (&session->internals.handshake_data_buffer);
   _gnutls_buffer_clear (&session->internals.application_data_buffer);
   _gnutls_buffer_clear (&session->internals.record_recv_buffer);
-  _gnutls_buffer_clear (&session->internals.record_send_buffer);
+  _gnutls_mbuffer_clear (&session->internals.record_send_buffer);
 
   gnutls_credentials_clear (session);
   _gnutls_selected_certs_deinit (session);
@@ -919,6 +917,7 @@ _gnutls_PRF (gnutls_session_t session,
   memcpy (s_seed, label, label_size);
   memcpy (&s_seed[label_size], seed, seed_size);
 
+
   if (_gnutls_version_has_selectable_prf (ver))
     {
       result =
diff --git a/lib/gnutls_state.h b/lib/gnutls_state.h
index 8935c78..b600a2f 100644
--- a/lib/gnutls_state.h
+++ b/lib/gnutls_state.h
@@ -30,6 +30,9 @@
 
 void _gnutls_session_cert_type_set (gnutls_session_t session,
                                    gnutls_certificate_type_t);
+void
+_gnutls_record_set_default_version (gnutls_session_t session,
+                                   unsigned char major, unsigned char minor);
 
 #include <gnutls_auth.h>
 
diff --git a/lib/gnutls_str.c b/lib/gnutls_str.c
index 8e2ef85..c5c8493 100644
--- a/lib/gnutls_str.c
+++ b/lib/gnutls_str.c
@@ -283,6 +283,99 @@ _gnutls_string_append_printf (gnutls_string * dest, const 
char *fmt, ...)
   return len;
 }
 
+static int _gnutls_string_insert_data(gnutls_string * dest, int pos, const 
void* str, size_t str_size)
+{
+        size_t orig_length = dest->length;
+        int ret;
+
+        ret = _gnutls_string_resize(dest, dest->length+str_size); /* resize to 
make space */
+        if (ret < 0)
+                return ret;
+
+        memmove(&dest->data[pos+str_size], &dest->data[pos], orig_length-pos);
+
+        memcpy(&dest->data[pos], str, str_size);
+        dest->length += str_size;
+
+        return 0;
+}
+
+static void _gnutls_string_delete_data(gnutls_string * dest, int pos, size_t 
str_size)
+{
+        memmove(&dest->data[pos], &dest->data[pos+str_size], 
dest->length-pos-str_size);
+
+        dest->length -= str_size;
+
+        return;
+}
+
+
+int _gnutls_string_escape(gnutls_string * dest, const char *const 
invalid_chars)
+{
+        static const char *x = "0123456789ABCDEF";
+        int rv = -1;
+        char t[5];
+        int pos = 0;
+
+        /*_PKCS11H_ASSERT (target!=NULL); Not required*/
+
+        while (pos < dest->length) {
+
+                if (dest->data[pos] == '\\' || strchr(invalid_chars, 
dest->data[pos])
+                    || !isgraph(dest->data[pos])) {
+
+                        t[0] = '%';
+                        t[1] = x[(dest->data[pos] & 0xf0) >> 4];
+                        t[2] = x[(dest->data[pos] & 0x0f) >> 0];
+
+                        _gnutls_string_delete_data(dest, pos, 1);
+
+                        if (_gnutls_string_insert_data(dest, pos, t, 3) < 0) {
+                                        rv = -1;
+                                        goto cleanup;
+                        }
+
+                }
+                pos++;
+        }
+
+        rv = 0;
+
+    cleanup:
+
+        return rv;
+}
+
+int _gnutls_string_unescape(gnutls_string * dest)
+{
+        int rv = -1;
+        int pos = 0;
+
+        /*_PKCS11H_ASSERT (target!=NULL); Not required*/
+
+        while (pos < dest->length) {
+                if (dest->data[pos] == '%') {
+                        char b[3];
+                        unsigned u;
+                        char x;
+                        b[0] = dest->data[pos+1];
+                        b[1] = dest->data[pos+2];
+                        b[2] = '\x0';
+
+                        sscanf(b, "%08x", &u);
+                        x = u & 0xff;
+                        _gnutls_string_delete_data(dest, pos, 3);
+                        _gnutls_string_insert_data(dest, pos, &x, 1);
+                }
+                pos++;
+        }
+
+        rv = 0;
+
+        return rv;
+}
+
+
 /* Converts the given string (old) to hex. A buffer must be provided
  * to hold the new hex string. The new string will be null terminated.
  * If the buffer does not have enough space to hold the string, a
@@ -290,14 +383,26 @@ _gnutls_string_append_printf (gnutls_string * dest, const 
char *fmt, ...)
  */
 char *
 _gnutls_bin2hex (const void *_old, size_t oldlen,
-                char *buffer, size_t buffer_size)
+                char *buffer, size_t buffer_size, const char *separator)
 {
   unsigned int i, j;
   const opaque *old = _old;
+  int step = 2;
+  const char empty[] = "";
+  
+  if (separator != NULL && separator[0] != 0)
+    step = 3;
+  else
+    separator = empty;
+
+  i = j = 0;
+  sprintf (&buffer[j], "%.2x", old[i]);
+  j+=2;
+  i++;
 
-  for (i = j = 0; i < oldlen && j + 2 < buffer_size; j += 2)
+  for (; i < oldlen && j + step < buffer_size; j += step)
     {
-      sprintf (&buffer[j], "%.2x", old[i]);
+      sprintf (&buffer[j], "%s%.2x", separator, old[i]);
       i++;
     }
   buffer[j] = '\0';
@@ -334,29 +439,34 @@ _gnutls_hex2bin (const opaque * hex_data, int hex_size, 
opaque * bin_data,
   opaque hex2_data[3];
   unsigned long val;
 
-  /* FIXME: we don't handle whitespace.
-   */
-  hex_size /= 2;
+  hex2_data[2] = 0;
 
-  if (*bin_size < (size_t) hex_size)
+  for (i = j = 0; i < hex_size;)
     {
-      gnutls_assert ();
-      return GNUTLS_E_SHORT_MEMORY_BUFFER;
-    }
-
-  for (i = j = 0; j < hex_size; i += 2, j++)
-    {
-      hex2_data[0] = hex_data[i];
-      hex2_data[1] = hex_data[i + 1];
-      hex2_data[2] = 0;
-      val = strtoul ((char *) hex2_data, NULL, 16);
-      if (val == ULONG_MAX)
-       {
-         gnutls_assert ();
-         return GNUTLS_E_SRP_PWD_PARSING_ERROR;
-       }
-      bin_data[j] = val;
+        if (!isxdigit(hex_data[i])) /* skip non-hex such as the ':' in 00:FF */
+          {
+            i++;
+            continue;
+          }
+
+        if (j > *bin_size) {
+            gnutls_assert();
+            return GNUTLS_E_SHORT_MEMORY_BUFFER;
+        }
+
+        hex2_data[0] = hex_data[i];
+        hex2_data[1] = hex_data[i + 1];
+        i+=2;
+
+        val = strtoul ((char *) hex2_data, NULL, 16);
+        if (val == ULONG_MAX) {
+            gnutls_assert ();
+            return GNUTLS_E_PARSING_ERROR;
+        }
+        bin_data[j] = val;
+        j++;
     }
+  *bin_size = j;
 
   return 0;
 }
diff --git a/lib/gnutls_str.h b/lib/gnutls_str.h
index 53bd240..a011f4a 100644
--- a/lib/gnutls_str.h
+++ b/lib/gnutls_str.h
@@ -57,6 +57,9 @@ void _gnutls_string_get_data (gnutls_string *, void *, size_t 
* size);
 void _gnutls_string_get_datum (gnutls_string *, gnutls_datum_t *,
                               size_t max_size);
 
+int _gnutls_string_escape(gnutls_string * dest, const char *const 
invalid_chars);
+int _gnutls_string_unescape(gnutls_string * dest);
+
 #ifndef __attribute__
 /* This feature is available in gcc versions 2.5 and later.  */
 # if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 5)
@@ -77,7 +80,7 @@ typedef gnutls_string gnutls_buffer;
 #define _gnutls_buffer_resize _gnutls_string_resize
 
 char *_gnutls_bin2hex (const void *old, size_t oldlen, char *buffer,
-                      size_t buffer_size);
+                      size_t buffer_size, const char* separator);
 int _gnutls_hex2bin (const opaque * hex_data, int hex_size, opaque * bin_data,
                     size_t * bin_size);
 
diff --git a/lib/gnutls_x509.c b/lib/gnutls_x509.c
index d93406a..5d44359 100644
--- a/lib/gnutls_x509.c
+++ b/lib/gnutls_x509.c
@@ -46,6 +46,7 @@
 #include "x509/x509_int.h"
 #include "read-file.h"
 
+
 /*
  * some x509 certificate parsing functions.
  */
@@ -209,127 +210,73 @@ _gnutls_x509_cert_verify_peers (gnutls_session_t session,
 static int
 _gnutls_check_key_cert_match (gnutls_certificate_credentials_t res)
 {
-  gnutls_datum_t cid;
-  gnutls_datum_t kid;
-  unsigned pk = res->cert_list[res->ncerts - 1][0].subject_pk_algorithm;
+  unsigned int pk = res->cert_list[res->ncerts - 1][0].subject_pk_algorithm;
 
-  if (res->pkey[res->ncerts - 1].pk_algorithm != pk)
+  if (gnutls_privkey_get_pk_algorithm(res->pkey[res->ncerts - 1], NULL) != pk)
     {
       gnutls_assert ();
       return GNUTLS_E_CERTIFICATE_KEY_MISMATCH;
     }
 
-  if (pk == GNUTLS_PK_RSA)
-    {
-      _gnutls_x509_write_rsa_params (res->pkey[res->ncerts - 1].params,
-                                    res->pkey[res->ncerts -
-                                              1].params_size, &kid);
-
-
-      _gnutls_x509_write_rsa_params (res->
-                                    cert_list[res->ncerts - 1][0].params,
-                                    res->cert_list[res->ncerts -
-                                                   1][0].params_size, &cid);
-    }
-  else if (pk == GNUTLS_PK_DSA)
-    {
-
-      _gnutls_x509_write_dsa_params (res->pkey[res->ncerts - 1].params,
-                                    res->pkey[res->ncerts -
-                                              1].params_size, &kid);
-
-      _gnutls_x509_write_dsa_params (res->
-                                    cert_list[res->ncerts - 1][0].params,
-                                    res->cert_list[res->ncerts -
-                                                   1][0].params_size, &cid);
-    }
-
-  if (cid.size != kid.size)
-    {
-      gnutls_assert ();
-      _gnutls_free_datum (&kid);
-      _gnutls_free_datum (&cid);
-      return GNUTLS_E_CERTIFICATE_KEY_MISMATCH;
-    }
-
-  if (memcmp (kid.data, cid.data, kid.size) != 0)
-    {
-      gnutls_assert ();
-      _gnutls_free_datum (&kid);
-      _gnutls_free_datum (&cid);
-      return GNUTLS_E_CERTIFICATE_KEY_MISMATCH;
-    }
-
-  _gnutls_free_datum (&kid);
-  _gnutls_free_datum (&cid);
   return 0;
 }
 
 /* Reads a DER encoded certificate list from memory and stores it to a
- * gnutls_cert structure.  Returns the number of certificates parsed.
+ * gnutls_cert structure. Returns the number of certificates parsed.
  */
 static int
-parse_crt_mem (gnutls_cert ** cert_list, unsigned *ncerts,
-              gnutls_x509_crt_t cert)
+parse_der_cert_mem (gnutls_certificate_credentials_t res, 
+                   const void *input_cert, int input_cert_size)
 {
-  int i;
+  gnutls_datum_t tmp;
+  gnutls_x509_crt_t crt;
+  gnutls_cert *ccert;
   int ret;
 
-  i = *ncerts + 1;
-
-  *cert_list =
-    (gnutls_cert *) gnutls_realloc_fast (*cert_list,
-                                        i * sizeof (gnutls_cert));
-
-  if (*cert_list == NULL)
+  ccert = gnutls_malloc(sizeof(*ccert));
+  if (ccert == NULL)
     {
-      gnutls_assert ();
+      gnutls_assert();
       return GNUTLS_E_MEMORY_ERROR;
     }
 
-  ret = _gnutls_x509_crt_to_gcert (&cert_list[0][i - 1], cert, 0);
+  ret = gnutls_x509_crt_init (&crt);
   if (ret < 0)
     {
       gnutls_assert ();
+      gnutls_free(ccert);
       return ret;
     }
 
-  *ncerts = i;
-
-  return 1;                    /* one certificate parsed */
-}
-
-/* Reads a DER encoded certificate list from memory and stores it to a
- * gnutls_cert structure. Returns the number of certificates parsed.
- */
-static int
-parse_der_cert_mem (gnutls_cert ** cert_list, unsigned *ncerts,
-                   const void *input_cert, int input_cert_size)
-{
-  gnutls_datum_t tmp;
-  gnutls_x509_crt_t cert;
-  int ret;
+  tmp.data = (opaque *) input_cert;
+  tmp.size = input_cert_size;
 
-  ret = gnutls_x509_crt_init (&cert);
+  ret = gnutls_x509_crt_import (crt, &tmp, GNUTLS_X509_FMT_DER);
   if (ret < 0)
     {
       gnutls_assert ();
+      gnutls_x509_crt_deinit (crt);
+      gnutls_free(ccert);
       return ret;
     }
 
-  tmp.data = (opaque *) input_cert;
-  tmp.size = input_cert_size;
-
-  ret = gnutls_x509_crt_import (cert, &tmp, GNUTLS_X509_FMT_DER);
+  ret = _gnutls_x509_crt_to_gcert (ccert, crt, 0);
+  gnutls_x509_crt_deinit (crt);
+  
   if (ret < 0)
     {
-      gnutls_assert ();
-      gnutls_x509_crt_deinit (cert);
+      gnutls_assert();
+      gnutls_free(ccert);
+      return ret;
+    }
+  
+  ret = certificate_credential_append_crt_list(res, ccert, 1);
+  if (ret < 0)
+    {
+      gnutls_assert();
+      gnutls_free(ccert);
       return ret;
     }
-
-  ret = parse_crt_mem (cert_list, ncerts, cert);
-  gnutls_x509_crt_deinit (cert);
 
   return ret;
 }
@@ -338,14 +285,15 @@ parse_der_cert_mem (gnutls_cert ** cert_list, unsigned 
*ncerts,
  * a gnutls_cert structure. Returns the number of certificate parsed.
  */
 static int
-parse_pem_cert_mem (gnutls_cert ** cert_list, unsigned *ncerts,
+parse_pem_cert_mem (gnutls_certificate_credentials_t res,
                    const char *input_cert, int input_cert_size)
 {
-  int size, siz2, i;
+  int size, siz2;
   const char *ptr;
   opaque *ptr2;
   gnutls_datum_t tmp;
   int ret, count;
+  gnutls_cert* certs = NULL;
 
   /* move to the certificate
    */
@@ -362,7 +310,6 @@ parse_pem_cert_mem (gnutls_cert ** cert_list, unsigned 
*ncerts,
     }
   size = input_cert_size - (ptr - input_cert);
 
-  i = *ncerts + 1;
   count = 0;
 
   do
@@ -376,11 +323,9 @@ parse_pem_cert_mem (gnutls_cert ** cert_list, unsigned 
*ncerts,
          return GNUTLS_E_BASE64_DECODING_ERROR;
        }
 
-      *cert_list =
-       (gnutls_cert *) gnutls_realloc_fast (*cert_list,
-                                            i * sizeof (gnutls_cert));
+      certs = gnutls_realloc_fast (certs, (count+1) * sizeof (gnutls_cert));
 
-      if (*cert_list == NULL)
+      if (certs == NULL)
        {
          gnutls_assert ();
          return GNUTLS_E_MEMORY_ERROR;
@@ -389,12 +334,14 @@ parse_pem_cert_mem (gnutls_cert ** cert_list, unsigned 
*ncerts,
       tmp.data = ptr2;
       tmp.size = siz2;
 
-      ret = _gnutls_x509_raw_cert_to_gcert (&cert_list[0][i - 1], &tmp, 0);
+      ret = _gnutls_x509_raw_cert_to_gcert (&certs[count], &tmp, 0);
       if (ret < 0)
        {
          gnutls_assert ();
+         gnutls_free(certs);
          return ret;
        }
+
       _gnutls_free_datum (&tmp);       /* free ptr2 */
 
       /* now we move ptr after the pem header 
@@ -418,13 +365,18 @@ parse_pem_cert_mem (gnutls_cert ** cert_list, unsigned 
*ncerts,
       else
        ptr = NULL;
 
-      i++;
       count++;
 
     }
   while (ptr != NULL);
 
-  *ncerts = i - 1;
+  ret = certificate_credential_append_crt_list(res, certs, count);
+  if (ret < 0)
+    {
+      gnutls_assert();
+      gnutls_free(certs);
+      return ret;
+    }
 
   return count;
 }
@@ -439,38 +391,12 @@ read_cert_mem (gnutls_certificate_credentials_t res, 
const void *cert,
 {
   int ret;
 
-  /* allocate space for the certificate to add
-   */
-  res->cert_list = gnutls_realloc_fast (res->cert_list,
-                                       (1 +
-                                        res->ncerts) *
-                                       sizeof (gnutls_cert *));
-  if (res->cert_list == NULL)
-    {
-      gnutls_assert ();
-      return GNUTLS_E_MEMORY_ERROR;
-    }
-
-  res->cert_list_length = gnutls_realloc_fast (res->cert_list_length,
-                                              (1 +
-                                               res->ncerts) * sizeof (int));
-  if (res->cert_list_length == NULL)
-    {
-      gnutls_assert ();
-      return GNUTLS_E_MEMORY_ERROR;
-    }
-
-  res->cert_list[res->ncerts] = NULL;  /* for realloc */
-  res->cert_list_length[res->ncerts] = 0;
-
   if (type == GNUTLS_X509_FMT_DER)
-    ret = parse_der_cert_mem (&res->cert_list[res->ncerts],
-                             &res->cert_list_length[res->ncerts],
+    ret = parse_der_cert_mem (res,
                              cert, cert_size);
   else
-    ret = parse_pem_cert_mem (&res->cert_list[res->ncerts],
-                             &res->cert_list_length[res->ncerts], cert,
-                             cert_size);
+    ret = parse_pem_cert_mem (res,
+                             cert, cert_size);
 
   if (ret < 0)
     {
@@ -481,55 +407,8 @@ read_cert_mem (gnutls_certificate_credentials_t res, const 
void *cert,
   return ret;
 }
 
-
-int
-_gnutls_x509_privkey_to_gkey (gnutls_privkey * dest,
-                             gnutls_x509_privkey_t src)
-{
-  int i, ret;
-
-  memset (dest, 0, sizeof (gnutls_privkey));
-
-  for (i = 0; i < src->params_size; i++)
-    {
-      dest->params[i] = _gnutls_mpi_copy (src->params[i]);
-      if (dest->params[i] == NULL)
-       {
-         gnutls_assert ();
-         ret = GNUTLS_E_MEMORY_ERROR;
-         goto cleanup;
-       }
-    }
-
-  dest->pk_algorithm = src->pk_algorithm;
-  dest->params_size = src->params_size;
-
-  return 0;
-
-cleanup:
-
-  for (i = 0; i < src->params_size; i++)
-    {
-      _gnutls_mpi_release (&dest->params[i]);
-    }
-  return ret;
-}
-
-void
-_gnutls_gkey_deinit (gnutls_privkey * key)
-{
-  int i;
-  if (key == NULL)
-    return;
-
-  for (i = 0; i < key->params_size; i++)
-    {
-      _gnutls_mpi_release (&key->params[i]);
-    }
-}
-
-int
-_gnutls_x509_raw_privkey_to_gkey (gnutls_privkey * privkey,
+static int
+_gnutls_x509_raw_privkey_to_privkey (gnutls_privkey_t *privkey,
                                  const gnutls_datum_t * raw_key,
                                  gnutls_x509_crt_fmt_t type)
 {
@@ -542,7 +421,7 @@ _gnutls_x509_raw_privkey_to_gkey (gnutls_privkey * privkey,
       gnutls_assert ();
       return ret;
     }
-
+    
   ret = gnutls_x509_privkey_import (tmpkey, raw_key, type);
 
 #ifdef ENABLE_PKI
@@ -559,16 +438,23 @@ _gnutls_x509_raw_privkey_to_gkey (gnutls_privkey * 
privkey,
       return ret;
     }
 
-  ret = _gnutls_x509_privkey_to_gkey (privkey, tmpkey);
+  ret = gnutls_privkey_init(privkey);
+  if (ret < 0) 
+    {
+      gnutls_assert();
+      gnutls_x509_privkey_deinit (tmpkey);
+      return ret;
+    }
+
+  ret = gnutls_privkey_import_x509 (*privkey, tmpkey, 
GNUTLS_PRIVKEY_IMPORT_AUTO_RELEASE);
   if (ret < 0)
     {
       gnutls_assert ();
       gnutls_x509_privkey_deinit (tmpkey);
+      gnutls_privkey_deinit (*privkey);
       return ret;
     }
 
-  gnutls_x509_privkey_deinit (tmpkey);
-
   return 0;
 }
 
@@ -582,17 +468,7 @@ read_key_mem (gnutls_certificate_credentials_t res,
 {
   int ret;
   gnutls_datum_t tmp;
-
-  /* allocate space for the pkey list
-   */
-  res->pkey =
-    gnutls_realloc_fast (res->pkey,
-                        (res->ncerts + 1) * sizeof (gnutls_privkey));
-  if (res->pkey == NULL)
-    {
-      gnutls_assert ();
-      return GNUTLS_E_MEMORY_ERROR;
-    }
+  gnutls_privkey_t privkey;
 
   if (key)
     {
@@ -600,18 +476,204 @@ read_key_mem (gnutls_certificate_credentials_t res,
       tmp.size = key_size;
 
       ret =
-       _gnutls_x509_raw_privkey_to_gkey (&res->pkey[res->ncerts], &tmp,
-                                         type);
+       _gnutls_x509_raw_privkey_to_privkey (&privkey, &tmp, type);
+      if (ret < 0)
+       {
+         gnutls_assert ();
+         return ret;
+       }
+
+      ret = certificate_credentials_append_pkey(res, privkey);
       if (ret < 0)
        {
          gnutls_assert ();
+         gnutls_privkey_deinit(privkey);
          return ret;
        }
+      
     }
   else
-    memset (&res->pkey[res->ncerts], 0, sizeof (gnutls_privkey));
+    {
+      gnutls_assert();
+      return GNUTLS_E_INVALID_REQUEST;
+    }
+  
+
+  return 0;
+}
+
+/* Reads a private key from a token.
+ */
+static int read_key_url (gnutls_certificate_credentials_t res, const char* url)
+{
+  int ret;
+  gnutls_pkcs11_privkey_t key1 = NULL;
+  gnutls_privkey_t pkey = NULL;
+
+  /* allocate space for the pkey list
+   */
+  
+  ret = gnutls_pkcs11_privkey_init(&key1);
+  if (ret < 0)
+    {
+      gnutls_assert();
+      return ret;
+    }
+    
+  ret = gnutls_pkcs11_privkey_import_url(key1, url, 0);
+  if (ret < 0)
+    {
+      gnutls_assert();
+      goto cleanup;
+    }
+  
+  ret = gnutls_privkey_init(&pkey);
+  if (ret < 0)
+    {
+      gnutls_assert();
+      goto cleanup;
+    }
+
+  ret = gnutls_privkey_import_pkcs11(pkey, key1, 
GNUTLS_PRIVKEY_IMPORT_AUTO_RELEASE);
+  if (ret < 0)
+    {
+      gnutls_assert();
+      goto cleanup;
+    }
+    
+  ret = certificate_credentials_append_pkey(res, pkey);
+  if (ret < 0)
+    {
+      gnutls_assert();
+      goto cleanup;
+    }  
+
+  return 0;
+
+cleanup:
+  if (pkey)
+    gnutls_privkey_deinit(pkey);
+
+  if (key1)
+    gnutls_pkcs11_privkey_deinit(key1);
+
+  return ret;
+}
+
+/* Reads a private key from a token.
+ */
+static int read_cas_url (gnutls_certificate_credentials_t res, const char* url)
+{
+int ret;
+gnutls_x509_crt_t * xcrt_list = NULL;
+gnutls_pkcs11_obj_t *pcrt_list=NULL;
+unsigned int pcrt_list_size = 0;
+
+       ret = gnutls_pkcs11_obj_list_import_url( NULL, &pcrt_list_size, url, 
GNUTLS_PKCS11_OBJ_ATTR_CRT_TRUSTED);
+       if (ret < 0 && ret != GNUTLS_E_SHORT_MEMORY_BUFFER) {
+               gnutls_assert();
+               return ret;
+       }
+                                                        
+       if (pcrt_list_size == 0) {
+               gnutls_assert();
+               return 0;
+       }
+       
+       pcrt_list = gnutls_malloc(sizeof(*pcrt_list)*pcrt_list_size);
+       if (pcrt_list == NULL) {
+               gnutls_assert();
+               return GNUTLS_E_MEMORY_ERROR;
+       }
+       
+       ret = gnutls_pkcs11_obj_list_import_url( pcrt_list, &pcrt_list_size, 
url, GNUTLS_PKCS11_OBJ_ATTR_CRT_TRUSTED);
+       if (ret < 0) {
+               gnutls_assert();
+               goto cleanup;
+       }
+
+       xcrt_list = gnutls_malloc(sizeof(*xcrt_list)*pcrt_list_size);
+       if (xcrt_list == NULL) {
+               gnutls_assert();
+               ret = GNUTLS_E_MEMORY_ERROR;
+               goto cleanup;
+       }
+       
+       ret = gnutls_x509_crt_list_import_pkcs11(xcrt_list, pcrt_list_size, 
pcrt_list, 0);
+       if (xcrt_list == NULL) {
+               gnutls_assert();
+               ret = GNUTLS_E_MEMORY_ERROR;
+               goto cleanup;
+       }
+
+       res->x509_ca_list = xcrt_list;
+       res->x509_ncas = pcrt_list_size;
+       
+       gnutls_free(pcrt_list);
+       
+       return pcrt_list_size;
+
+cleanup:
+       gnutls_free(xcrt_list);
+       gnutls_free(pcrt_list);
+
+       return ret;
+
+}
+
+
+/* Reads a private key from a token.
+ */
+static int read_cert_url (gnutls_certificate_credentials_t res, const char* 
url)
+{
+int ret;
+gnutls_x509_crt_t crt;
+gnutls_cert * ccert;
+
+  ccert = gnutls_malloc(sizeof(*ccert));
+  if (ccert == NULL)
+    {
+      gnutls_assert();
+      return GNUTLS_E_MEMORY_ERROR;
+    }
+
+  ret = gnutls_x509_crt_init(&crt);
+  if (ret < 0)
+    {
+      gnutls_assert();
+      gnutls_free(ccert);
+      return ret;
+    }
+  
+  ret = gnutls_x509_crt_import_pkcs11_url(crt, url);
+  if (ret < 0)
+    {
+      gnutls_assert();
+      gnutls_free(ccert);
+      gnutls_x509_crt_deinit(crt);
+      return ret;
+    }
+
+  ret = _gnutls_x509_crt_to_gcert (ccert, crt, 0);
+  gnutls_x509_crt_deinit(crt);
+
+  if (ret < 0)
+    {
+      gnutls_assert();
+      gnutls_free(ccert);
+      return ret;
+    }
+  
+  ret = certificate_credential_append_crt_list(res, ccert, 1);
+  if (ret < 0)
+    {
+      gnutls_assert();
+      gnutls_free(ccert);
+      return ret;
+    }
 
   return 0;
+
 }
 
 /* Reads a certificate file
@@ -622,7 +684,13 @@ read_cert_file (gnutls_certificate_credentials_t res,
 {
   int ret;
   size_t size;
-  char *data = read_binary_file (certfile, &size);
+  char *data;
+
+  if (strncmp(certfile, "pkcs11:", 7)==0) {
+    return read_cert_url(res, certfile);
+  }
+
+  data = read_binary_file (certfile, &size);
 
   if (data == NULL)
     {
@@ -648,7 +716,13 @@ read_key_file (gnutls_certificate_credentials_t res,
 {
   int ret;
   size_t size;
-  char *data = read_binary_file (keyfile, &size);
+  char* data;
+  
+  if (strncmp(keyfile, "pkcs11:", 7)==0) {
+    return read_key_url(res, keyfile);
+  }
+  
+  data = read_binary_file (keyfile, &size);
 
   if (data == NULL)
     {
@@ -720,6 +794,50 @@ gnutls_certificate_set_x509_key_mem 
(gnutls_certificate_credentials_t res,
   return 0;
 }
 
+int certificate_credential_append_crt_list( gnutls_certificate_credentials_t 
res, gnutls_cert *crt, int nr)
+{
+  res->cert_list = gnutls_realloc_fast (res->cert_list,
+                                       (1 +
+                                        res->ncerts) *
+                                       sizeof (gnutls_cert *));
+  if (res->cert_list == NULL)
+    {
+      gnutls_assert ();
+      return GNUTLS_E_MEMORY_ERROR;
+    }
+
+  res->cert_list_length = gnutls_realloc_fast (res->cert_list_length,
+                                              (1 +
+                                               res->ncerts) * sizeof (int));
+  if (res->cert_list_length == NULL)
+    {
+      gnutls_assert ();
+      return GNUTLS_E_MEMORY_ERROR;
+    }
+
+  res->cert_list[res->ncerts] = crt;
+  res->cert_list_length[res->ncerts] = nr;
+
+  return 0;
+
+}
+
+int certificate_credentials_append_pkey( gnutls_certificate_credentials_t res, 
gnutls_privkey_t pkey)
+{
+  res->pkey = gnutls_realloc_fast (res->pkey,
+                                       (1 + res->ncerts) *
+                                       sizeof (gnutls_privkey_t));
+  if (res->pkey == NULL)
+    {
+      gnutls_assert ();
+      return GNUTLS_E_MEMORY_ERROR;
+    }
+
+  res->pkey[res->ncerts] = pkey;
+  return 0;
+
+}
+
 /**
  * gnutls_certificate_set_x509_key:
  * @res: is a #gnutls_certificate_credentials_t structure.
@@ -734,6 +852,8 @@ gnutls_certificate_set_x509_key_mem 
(gnutls_certificate_credentials_t res,
  * entity certificate (e.g., also an intermediate CA cert) then put
  * the certificate chain in @cert_list.
  *
+ * 
+ *
  * Returns: %GNUTLS_E_SUCCESS on success, or an error code.
  *
  * Since: 2.4.0
@@ -745,59 +865,57 @@ gnutls_certificate_set_x509_key 
(gnutls_certificate_credentials_t res,
                                 gnutls_x509_privkey_t key)
 {
   int ret, i;
+  gnutls_privkey_t pkey;
+  gnutls_cert* pcerts = NULL;
 
   /* this should be first
    */
-
-  res->pkey =
-    gnutls_realloc_fast (res->pkey,
-                        (res->ncerts + 1) * sizeof (gnutls_privkey));
-  if (res->pkey == NULL)
+  ret = gnutls_privkey_init(&pkey);
+  if (ret < 0)
     {
       gnutls_assert ();
-      return GNUTLS_E_MEMORY_ERROR;
+      return ret;
     }
-
-  ret = _gnutls_x509_privkey_to_gkey (&res->pkey[res->ncerts], key);
+  
+  ret = gnutls_privkey_import_x509 (pkey, key, 0);
   if (ret < 0)
     {
       gnutls_assert ();
       return ret;
     }
-
-  res->cert_list = gnutls_realloc_fast (res->cert_list,
-                                       (1 +
-                                        res->ncerts) *
-                                       sizeof (gnutls_cert *));
-  if (res->cert_list == NULL)
+  
+  ret = certificate_credentials_append_pkey(res, pkey);
+  if (ret < 0)
     {
       gnutls_assert ();
-      return GNUTLS_E_MEMORY_ERROR;
+      return ret;
     }
 
-  res->cert_list_length = gnutls_realloc_fast (res->cert_list_length,
-                                              (1 +
-                                               res->ncerts) * sizeof (int));
-  if (res->cert_list_length == NULL)
+  /* load certificates */
+  pcerts = gnutls_malloc(sizeof(gnutls_cert)*cert_list_size);
+  if (pcerts == NULL)
     {
-      gnutls_assert ();
+      gnutls_assert();
       return GNUTLS_E_MEMORY_ERROR;
     }
 
-  res->cert_list[res->ncerts] = NULL;  /* for realloc */
-  res->cert_list_length[res->ncerts] = 0;
-
-
   for (i = 0; i < cert_list_size; i++)
     {
-      ret = parse_crt_mem (&res->cert_list[res->ncerts],
-                          &res->cert_list_length[res->ncerts], cert_list[i]);
+      ret = _gnutls_x509_crt_to_gcert (&pcerts[i], cert_list[i], 0);
       if (ret < 0)
        {
          gnutls_assert ();
          return ret;
        }
     }
+    
+  ret = certificate_credential_append_crt_list(res, pcerts, cert_list_size);
+  if (ret < 0) 
+    {
+      gnutls_assert();
+      return ret;
+    }
+  
   res->ncerts++;
 
   if ((ret = _gnutls_check_key_cert_match (res)) < 0)
@@ -827,6 +945,9 @@ gnutls_certificate_set_x509_key 
(gnutls_certificate_credentials_t res,
  * Currently only PKCS-1 encoded RSA and DSA private keys are accepted by
  * this function.
  *
+ * This function can also accept PKCS #11 URLs. In that case it
+ * will import the private key and certificate indicated by the urls.
+ *
  * Returns: %GNUTLS_E_SUCCESS on success, or an error code.
  **/
 int
@@ -1229,6 +1350,9 @@ gnutls_certificate_set_x509_trust 
(gnutls_certificate_credentials_t res,
  * the client if a certificate request is sent. This can be disabled
  * using gnutls_certificate_send_x509_rdn_sequence().
  *
+ * This function can also accept PKCS #11 URLs. In that case it
+ * will import all certificates that are marked as trusted.
+ *
  * Returns: number of certificates processed, or a negative value on
  * error.
  **/
@@ -1239,8 +1363,13 @@ gnutls_certificate_set_x509_trust_file 
(gnutls_certificate_credentials_t res,
 {
   int ret, ret2;
   size_t size;
-  char *data = read_binary_file (cafile, &size);
+  char* data;
+  
+  if (strncmp(cafile, "pkcs11:", 7)==0) {
+    return read_cas_url(res, cafile);
+  }
 
+  data = read_binary_file (cafile, &size);
   if (data == NULL)
     {
       gnutls_assert ();
@@ -2021,13 +2150,6 @@ int
        }
     }
 
-  /* check if the key and certificate found match */
-  if (key && (ret = _gnutls_check_key_cert_match (res)) < 0)
-    {
-      gnutls_assert ();
-      goto done;
-    }
-
   ret = 0;
 
 done:
diff --git a/lib/gnutls_x509.h b/lib/gnutls_x509.h
index 0f56063..d1ba1cb 100644
--- a/lib/gnutls_x509.h
+++ b/lib/gnutls_x509.h
@@ -24,6 +24,7 @@
  */
 
 #include <libtasn1.h>
+#include <gnutls/abstract.h>
 
 int _gnutls_x509_cert_verify_peers (gnutls_session_t session,
                                    unsigned int *status);
@@ -39,8 +40,6 @@ int _gnutls_x509_cert_verify_peers (gnutls_session_t session,
 int _gnutls_check_key_usage (const gnutls_cert * cert,
                             gnutls_kx_algorithm_t alg);
 
-int _gnutls_x509_raw_privkey_to_gkey (gnutls_privkey * privkey,
+int _gnutls_x509_raw_privkey_to_gkey (gnutls_privkey_t * privkey,
                                      const gnutls_datum_t * raw_key,
                                      gnutls_x509_crt_fmt_t type);
-int _gnutls_x509_privkey_to_gkey (gnutls_privkey * privkey,
-                                 gnutls_x509_privkey_t);
diff --git a/lib/gnutlsxx.cpp b/lib/gnutlsxx.cpp
index b9f5c3e..400d87b 100644
--- a/lib/gnutlsxx.cpp
+++ b/lib/gnutlsxx.cpp
@@ -716,16 +716,10 @@ namespace gnutls
     RETWRAP (gnutls_certificate_set_x509_crl (cred, crl_list, crl_list_size));
   }
 
-  void certificate_server_credentials::
-    set_retrieve_function (gnutls_certificate_server_retrieve_function * func)
-  {
-    gnutls_certificate_server_set_retrieve_function (cred, func);
-  }
-
-  void certificate_client_credentials::
-    set_retrieve_function (gnutls_certificate_client_retrieve_function * func)
+  void certificate_credentials::
+    set_retrieve_function (gnutls_certificate_retrieve_function * func)
   {
-    gnutls_certificate_client_set_retrieve_function (cred, func);
+    gnutls_certificate_set_retrieve_function (cred, func);
   }
 
 // SRP
diff --git a/lib/includes/Makefile.am b/lib/includes/Makefile.am
index 5c67d43..7798d46 100644
--- a/lib/includes/Makefile.am
+++ b/lib/includes/Makefile.am
@@ -22,7 +22,7 @@
 # MA 02110-1301, USA
 
 nobase_include_HEADERS = gnutls/x509.h gnutls/pkcs12.h gnutls/compat.h \
-       gnutls/openpgp.h gnutls/crypto.h
+       gnutls/openpgp.h gnutls/crypto.h gnutls/pkcs11.h
 
 if ENABLE_CXX
 nobase_include_HEADERS += gnutls/gnutlsxx.h
diff --git a/lib/includes/gnutls/abstract.h b/lib/includes/gnutls/abstract.h
new file mode 100644
index 0000000..77e7994
--- /dev/null
+++ b/lib/includes/gnutls/abstract.h
@@ -0,0 +1,122 @@
+#ifndef __GNUTLS_ABSTRACT_H
+#define __GNUTLS_ABSTRACT_H
+
+#include <stdarg.h>
+#include <gnutls/gnutls.h>
+#include <gnutls/x509.h>
+#include <gnutls/pkcs11.h>
+#include <gnutls/openpgp.h>
+
+/* Public key operations */
+
+struct gnutls_pubkey_st;
+typedef struct gnutls_pubkey_st* gnutls_pubkey_t;
+
+int gnutls_pubkey_init (gnutls_pubkey_t * key);
+void gnutls_pubkey_deinit (gnutls_pubkey_t key);
+int gnutls_pubkey_get_pk_algorithm (gnutls_pubkey_t key, unsigned int* bits);
+
+int gnutls_pubkey_import_x509(gnutls_pubkey_t pkey, gnutls_x509_crt_t crt, 
unsigned int flags);
+int gnutls_pubkey_import_pkcs11(gnutls_pubkey_t pkey, gnutls_pkcs11_obj_t crt, 
unsigned int flags);
+int gnutls_pubkey_import_openpgp(gnutls_pubkey_t pkey,
+                                gnutls_openpgp_crt_t crt,
+                                gnutls_openpgp_keyid_t keyid,
+                                unsigned int flags);
+
+int gnutls_pubkey_get_preferred_hash_algorithm (gnutls_pubkey_t key,
+                             gnutls_digest_algorithm_t * hash, unsigned int 
*mand);
+
+int gnutls_pubkey_get_pk_rsa_raw (gnutls_pubkey_t crt,
+                               gnutls_datum_t * m, gnutls_datum_t * e);
+int gnutls_pubkey_get_pk_dsa_raw (gnutls_pubkey_t crt,
+                               gnutls_datum_t * p, gnutls_datum_t * q,
+                               gnutls_datum_t * g, gnutls_datum_t * y);
+
+int gnutls_pubkey_export (gnutls_pubkey_t key,
+                             gnutls_x509_crt_fmt_t format,
+                             void *output_data, size_t * output_data_size);
+
+int gnutls_pubkey_get_key_id (gnutls_pubkey_t key, unsigned int flags,
+                           unsigned char *output_data,
+                           size_t * output_data_size);
+
+int gnutls_pubkey_get_key_usage(gnutls_pubkey_t key, unsigned int *usage);
+int gnutls_pubkey_set_key_usage (gnutls_pubkey_t key, unsigned int usage);
+
+int gnutls_pubkey_import (gnutls_pubkey_t key,
+                             const gnutls_datum_t * data,
+                             gnutls_x509_crt_fmt_t format);
+
+
+int gnutls_pubkey_import_pkcs11_url( gnutls_pubkey_t key, const char* url);
+int gnutls_pubkey_import_dsa_raw (gnutls_pubkey_t key,
+                                   const gnutls_datum_t * p,
+                                   const gnutls_datum_t * q,
+                                   const gnutls_datum_t * g,
+                                   const gnutls_datum_t * y);
+int gnutls_pubkey_import_rsa_raw (gnutls_pubkey_t pubkey,
+                             const gnutls_datum_t * m,
+                             const gnutls_datum_t * e);
+
+int gnutls_x509_crt_set_pubkey (gnutls_x509_crt_t crt,
+                              gnutls_pubkey_t key);
+
+int gnutls_x509_crq_set_pubkey (gnutls_x509_crq_t crq,
+                              gnutls_pubkey_t key);
+
+int
+gnutls_pubkey_verify_hash (gnutls_pubkey_t key, unsigned int flags,
+                            const gnutls_datum_t * hash,
+                            const gnutls_datum_t * signature);
+int
+gnutls_pubkey_get_verify_algorithm (gnutls_pubkey_t key,
+                                     const gnutls_datum_t * signature,
+                                     gnutls_digest_algorithm_t * hash);
+
+/* Private key operations */
+
+struct gnutls_privkey_st;
+typedef struct gnutls_privkey_st* gnutls_privkey_t;
+
+int gnutls_privkey_init (gnutls_privkey_t * key);
+void gnutls_privkey_deinit (gnutls_privkey_t key);
+int gnutls_privkey_get_pk_algorithm (gnutls_privkey_t key, unsigned int* bits);
+gnutls_privkey_type_t gnutls_privkey_get_type (gnutls_privkey_t key);
+
+
+#define GNUTLS_PRIVKEY_IMPORT_AUTO_RELEASE 1
+int gnutls_privkey_import_pkcs11 (gnutls_privkey_t pkey, 
gnutls_pkcs11_privkey_t key, unsigned int flags);
+int gnutls_privkey_import_x509 (gnutls_privkey_t pkey, gnutls_x509_privkey_t 
key, unsigned int flags);
+int gnutls_privkey_import_openpgp (gnutls_privkey_t pkey, 
gnutls_openpgp_privkey_t key, unsigned int flags);
+
+int gnutls_privkey_sign_data(gnutls_privkey_t signer,
+                               gnutls_digest_algorithm_t hash,
+                               unsigned int flags,
+                               const gnutls_datum_t * data,
+                               gnutls_datum_t * signature);
+int gnutls_privkey_sign_hash (gnutls_privkey_t key,
+                                const gnutls_datum_t * hash,
+                                gnutls_datum_t * signature);
+
+int gnutls_privkey_decrypt_data(gnutls_privkey_t signer,
+                               unsigned int flags,
+                               const gnutls_datum_t * ciphertext,
+                               gnutls_datum_t * plaintext);
+
+int gnutls_x509_crt_privkey_sign (gnutls_x509_crt_t crt, gnutls_x509_crt_t 
issuer,
+                            gnutls_privkey_t issuer_key,
+                            gnutls_digest_algorithm_t dig,
+                            unsigned int flags);
+
+int gnutls_x509_crl_privkey_sign (gnutls_x509_crl_t crl,
+                            gnutls_x509_crt_t issuer,
+                            gnutls_privkey_t issuer_key,
+                            gnutls_digest_algorithm_t dig,
+                            unsigned int flags);
+
+int gnutls_x509_crq_privkey_sign (gnutls_x509_crq_t crq,
+                            gnutls_privkey_t key,
+                            gnutls_digest_algorithm_t dig,
+                            unsigned int flags);
+
+#endif
diff --git a/lib/includes/gnutls/compat.h b/lib/includes/gnutls/compat.h
index 0232103..5cae317 100644
--- a/lib/includes/gnutls/compat.h
+++ b/lib/includes/gnutls/compat.h
@@ -1,7 +1,21 @@
 /* Typedefs for more compatibility with older GnuTLS. */
 
-#ifndef GNUTLS_COMPAT_H
-# define GNUTLS_COMPAT_H
+#ifndef _GNUTLS_COMPAT_H
+# define _GNUTLS_COMPAT_H
+
+#ifdef __GNUC__
+
+#define _GNUTLS_GCC_VERSION (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + 
__GNUC_PATCHLEVEL__)
+
+#if _GNUTLS_GCC_VERSION >= 30100
+#define _GNUTLS_GCC_ATTR_DEPRECATED __attribute__ ((__deprecated__))
+#endif
+
+#endif /* __GNUC__ */
+
+#ifndef _GNUTLS_GCC_ATTR_DEPRECATED
+#define _GNUTLS_GCC_ATTR_DEPRECATED
+#endif
 
 #define gnutls_cipher_algorithm gnutls_cipher_algorithm_t
 #define gnutls_kx_algorithm gnutls_kx_algorithm_t
@@ -98,4 +112,57 @@
 #define LIBGNUTLS_VERSION_NUMBER GNUTLS_VERSION_NUMBER
 #define LIBGNUTLS_EXTRA_VERSION GNUTLS_VERSION
 
-#endif /* GNUTLS_COMPAT_H */
+  typedef struct gnutls_retr_st
+  {
+    gnutls_certificate_type_t type;
+    union
+    {
+      gnutls_x509_crt_t *x509;
+      gnutls_openpgp_crt_t pgp;
+    } cert;
+    unsigned int ncerts;       /* one for pgp keys */
+
+    union
+    {
+      gnutls_x509_privkey_t x509;
+      gnutls_openpgp_privkey_t pgp;
+    } key;
+
+    unsigned int deinit_all;   /* if non zero all keys will be deinited */
+  } gnutls_retr_st;
+
+typedef int gnutls_certificate_client_retrieve_function (gnutls_session_t,
+                                                          const
+                                                          gnutls_datum_t *
+                                                          req_ca_rdn,
+                                                          int nreqs,
+                                                          const
+                                                          gnutls_pk_algorithm_t
+                                                          * pk_algos,
+                                                          int
+                                                          pk_algos_length,
+                                                          gnutls_retr_st *);
+typedef int gnutls_certificate_server_retrieve_function (gnutls_session_t,
+                                                          gnutls_retr_st *);
+
+void gnutls_certificate_client_set_retrieve_function
+    (gnutls_certificate_credentials_t cred,
+     gnutls_certificate_client_retrieve_function * func) 
_GNUTLS_GCC_ATTR_DEPRECATED;
+void gnutls_certificate_server_set_retrieve_function
+    (gnutls_certificate_credentials_t cred,
+     gnutls_certificate_server_retrieve_function * func) 
_GNUTLS_GCC_ATTR_DEPRECATED;
+
+  /* External signing callback.  Experimental. */
+  typedef int (*gnutls_sign_func) (gnutls_session_t session,
+                                  void *userdata,
+                                  gnutls_certificate_type_t cert_type,
+                                  const gnutls_datum_t * cert,
+                                  const gnutls_datum_t * hash,
+                                  gnutls_datum_t * signature);
+
+  void gnutls_sign_callback_set (gnutls_session_t session,
+                                gnutls_sign_func sign_func, void *userdata) 
_GNUTLS_GCC_ATTR_DEPRECATED;
+    gnutls_sign_func
+    gnutls_sign_callback_get (gnutls_session_t session, void **userdata);
+
+#endif /* _GNUTLS_COMPAT_H */
diff --git a/lib/includes/gnutls/crypto.h b/lib/includes/gnutls/crypto.h
index e2cb8f8..31352dd 100644
--- a/lib/includes/gnutls/crypto.h
+++ b/lib/includes/gnutls/crypto.h
@@ -112,6 +112,9 @@ typedef enum gnutls_rnd_level
   GNUTLS_RND_KEY = 2
 } gnutls_rnd_level_t;
 
+int gnutls_rnd (gnutls_rnd_level_t level, void *data, size_t len);
+
+
 /**
  * gnutls_pk_flag_t:
  * @GNUTLS_PK_FLAG_NONE: No flag.
@@ -214,7 +217,7 @@ typedef struct gnutls_crypto_bigint
                       gnutls_bigint_format_t format);
 } gnutls_crypto_bigint_st;
 
-#define GNUTLS_MAX_PK_PARAMS 6
+#define GNUTLS_MAX_PK_PARAMS 16
 
 typedef struct
 {
@@ -234,9 +237,11 @@ void gnutls_pk_params_init (gnutls_pk_params_st * p);
  *  [3] is prime1 (p) (private key only)
  *  [4] is prime2 (q) (private key only)
  *  [5] is coefficient (u == inverse of p mod q) (private key only)
+ *  [6] e1 == d mod (p-1)
+ *  [7] e2 == d mod (q-1)
  *
- *  note that other packages use inverse of q mod p,
- *  so we need to perform conversions using fixup_params().
+ *  note that for libgcrypt that does not use the inverse of q mod p,
+ *  we need to perform conversions using fixup_params().
  *
  * DSA:
  *  [0] is p
diff --git a/lib/includes/gnutls/gnutls.h.in b/lib/includes/gnutls/gnutls.h.in
index 91aa0a4..441b428 100644
--- a/lib/includes/gnutls/gnutls.h.in
+++ b/lib/includes/gnutls/gnutls.h.in
@@ -48,7 +48,6 @@
 #endif
 /* Get time_t. */
 #include <time.h>
-#include <gnutls/compat.h>
 #ifdef __cplusplus
 extern "C"
 {
@@ -570,6 +569,8 @@ extern "C"
    * @GNUTLS_SIGN_RSA_SHA1: Digital signature algorithm RSA with SHA-1
    * @GNUTLS_SIGN_RSA_SHA: Same as %GNUTLS_SIGN_RSA_SHA1.
    * @GNUTLS_SIGN_DSA_SHA1: Digital signature algorithm DSA with SHA-1
+   * @GNUTLS_SIGN_DSA_SHA224: Digital signature algorithm DSA with SHA-224
+   * @GNUTLS_SIGN_DSA_SHA256: Digital signature algorithm DSA with SHA-256
    * @GNUTLS_SIGN_DSA_SHA: Same as %GNUTLS_SIGN_DSA_SHA1.
    * @GNUTLS_SIGN_RSA_MD5: Digital signature algorithm RSA with MD5.
    * @GNUTLS_SIGN_RSA_MD2: Digital signature algorithm RSA with MD2.
@@ -594,11 +595,35 @@ extern "C"
     GNUTLS_SIGN_RSA_SHA256 = 6,
     GNUTLS_SIGN_RSA_SHA384 = 7,
     GNUTLS_SIGN_RSA_SHA512 = 8,
-    GNUTLS_SIGN_RSA_SHA224 = 9
+    GNUTLS_SIGN_RSA_SHA224 = 9,
+    GNUTLS_SIGN_DSA_SHA224 = 10,
+    GNUTLS_SIGN_DSA_SHA256 = 11,
   } gnutls_sign_algorithm_t;
 
   const char *gnutls_sign_algorithm_get_name (gnutls_sign_algorithm_t sign);
 
+  /**
+   * gnutls_sec_param_t:
+   * @GNUTLS_SEC_PARAM_UNKNOWN: Cannot be known
+   * @GNUTLS_SEC_PARAM_WEAK: 50 or less bits of security
+   * @GNUTLS_SEC_PARAM_LOW: 80 bits of security
+   * @GNUTLS_SEC_PARAM_NORMAL: 112 bits of security
+   * @GNUTLS_SEC_PARAM_HIGH: 128 bits of security
+   * @GNUTLS_SEC_PARAM_ULTRA: 192 bits of security
+   *
+   * Enumeration of security parameters for passive attacks
+   */
+  typedef enum
+  {
+    GNUTLS_SEC_PARAM_UNKNOWN,
+    GNUTLS_SEC_PARAM_WEAK,
+    GNUTLS_SEC_PARAM_LOW,
+    GNUTLS_SEC_PARAM_NORMAL,
+    GNUTLS_SEC_PARAM_HIGH,
+    GNUTLS_SEC_PARAM_ULTRA,
+  } gnutls_sec_param_t;
+
+
 /* If you want to change this, then also change the define in
  * gnutls_int.h, and recompile.
  */
@@ -657,6 +682,12 @@ extern "C"
   int gnutls_alert_send_appropriate (gnutls_session_t session, int err);
   const char *gnutls_alert_get_name (gnutls_alert_description_t alert);
 
+  gnutls_sec_param_t gnutls_pk_bits_to_sec_param (gnutls_pk_algorithm_t algo,
+                                      unsigned int bits);
+  const char * gnutls_sec_param_get_name (gnutls_sec_param_t param);
+  unsigned int gnutls_sec_param_to_pk_bits (gnutls_pk_algorithm_t algo,
+                                      gnutls_sec_param_t param);
+
 /* get information on the current session */
   gnutls_cipher_algorithm_t gnutls_cipher_get (gnutls_session_t session);
   gnutls_kx_algorithm_t gnutls_kx_get (gnutls_session_t session);
@@ -1428,40 +1459,36 @@ extern "C"
   struct gnutls_openpgp_privkey_int;
   typedef struct gnutls_openpgp_privkey_int *gnutls_openpgp_privkey_t;
 
-  typedef struct gnutls_retr_st
+  struct gnutls_pkcs11_privkey_st;
+  typedef struct gnutls_pkcs11_privkey_st* gnutls_pkcs11_privkey_t;
+
+  typedef enum {
+        GNUTLS_PRIVKEY_X509, /* gnutls_x509_privkey_t */
+       GNUTLS_PRIVKEY_OPENPGP, /* gnutls_openpgp_privkey_t */
+       GNUTLS_PRIVKEY_PKCS11, /* gnutls_pkcs11_privkey_t */
+  } gnutls_privkey_type_t;
+
+  typedef struct gnutls_retr2_st
   {
-    gnutls_certificate_type_t type;
-    union cert
+    gnutls_certificate_type_t cert_type;
+    gnutls_privkey_type_t key_type;
+    
+    union
     {
       gnutls_x509_crt_t *x509;
       gnutls_openpgp_crt_t pgp;
     } cert;
     unsigned int ncerts;       /* one for pgp keys */
 
-    union key
+    union
     {
       gnutls_x509_privkey_t x509;
       gnutls_openpgp_privkey_t pgp;
+      gnutls_pkcs11_privkey_t pkcs11;
     } key;
 
     unsigned int deinit_all;   /* if non zero all keys will be deinited */
-  } gnutls_retr_st;
-
-  typedef int gnutls_certificate_client_retrieve_function (gnutls_session_t,
-                                                          const
-                                                          gnutls_datum_t *
-                                                          req_ca_rdn,
-                                                          int nreqs,
-                                                          const
-                                                          gnutls_pk_algorithm_t
-                                                          * pk_algos,
-                                                          int
-                                                          pk_algos_length,
-                                                          gnutls_retr_st *);
-  typedef int gnutls_certificate_server_retrieve_function (gnutls_session_t,
-                                                          gnutls_retr_st *);
-
-  typedef int gnutls_certificate_verify_function (gnutls_session_t);
+  } gnutls_retr2_st;
 
 
   /* Functions that allow auth_info_t structures handling
@@ -1493,28 +1520,28 @@ extern "C"
 
   /* X509PKI */
 
-  /* External signing callback.  Experimental. */
-  typedef int (*gnutls_sign_func) (gnutls_session_t session,
-                                  void *userdata,
-                                  gnutls_certificate_type_t cert_type,
-                                  const gnutls_datum_t * cert,
-                                  const gnutls_datum_t * hash,
-                                  gnutls_datum_t * signature);
-
-  void gnutls_sign_callback_set (gnutls_session_t session,
-                                gnutls_sign_func sign_func, void *userdata);
-    gnutls_sign_func
-    gnutls_sign_callback_get (gnutls_session_t session, void **userdata);
 
   /* These are set on the credentials structure.
    */
-  void gnutls_certificate_client_set_retrieve_function
-    (gnutls_certificate_credentials_t cred,
-     gnutls_certificate_client_retrieve_function * func);
-  void gnutls_certificate_server_set_retrieve_function
+
+  typedef int gnutls_certificate_retrieve_function (gnutls_session_t,
+                                                          const
+                                                          gnutls_datum_t *
+                                                          req_ca_rdn,
+                                                          int nreqs,
+                                                          const
+                                                          gnutls_pk_algorithm_t
+                                                          * pk_algos,
+                                                          int
+                                                          pk_algos_length,
+                                                          gnutls_retr2_st *);
+
+
+  void gnutls_certificate_set_retrieve_function
     (gnutls_certificate_credentials_t cred,
-     gnutls_certificate_server_retrieve_function * func);
+     gnutls_certificate_retrieve_function * func);
 
+  typedef int gnutls_certificate_verify_function (gnutls_session_t);
   void
     gnutls_certificate_set_verify_function (gnutls_certificate_credentials_t
                                            cred,
@@ -1728,8 +1755,16 @@ extern "C"
 #define GNUTLS_E_CRYPTODEV_IOCTL_ERROR -211
 #define GNUTLS_E_CRYPTODEV_DEVICE_ERROR -212
 
+/* PKCS11 related */
+#define GNUTLS_E_PKCS11_ERROR -300
+#define GNUTLS_E_PKCS11_LOAD_ERROR -301
+#define GNUTLS_E_PARSING_ERROR -302
+#define GNUTLS_E_PKCS11_PIN_ERROR -303
+
 #define GNUTLS_E_UNIMPLEMENTED_FEATURE -1250
 
+
+
 #define GNUTLS_E_APPLICATION_ERROR_MAX -65000
 #define GNUTLS_E_APPLICATION_ERROR_MIN -65500
 
@@ -1737,4 +1772,6 @@ extern "C"
 }
 #endif
 
+#include <gnutls/compat.h>
+
 #endif                         /* GNUTLS_H */
diff --git a/lib/includes/gnutls/gnutlsxx.h b/lib/includes/gnutls/gnutlsxx.h
index b3013d2..9f88fe8 100644
--- a/lib/includes/gnutls/gnutlsxx.h
+++ b/lib/includes/gnutls/gnutlsxx.h
@@ -310,6 +310,9 @@ namespace gnutls
                                 gnutls_x509_crt_fmt_t type,
                                 const char *password);
 
+    void set_retrieve_function (gnutls_certificate_retrieve_function *
+                               func);
+
   protected:
       gnutls_certificate_credentials_t cred;
   };
@@ -317,16 +320,12 @@ namespace gnutls
   class certificate_server_credentials:public certificate_credentials
   {
   public:
-    void set_retrieve_function (gnutls_certificate_server_retrieve_function *
-                               func);
     void set_params_function (gnutls_params_function * func);
   };
 
   class certificate_client_credentials:public certificate_credentials
   {
   public:
-    void set_retrieve_function (gnutls_certificate_client_retrieve_function *
-                               func);
   };
 
 
diff --git a/lib/includes/gnutls/openpgp.h b/lib/includes/gnutls/openpgp.h
index 78cec82..d45c818 100644
--- a/lib/includes/gnutls/openpgp.h
+++ b/lib/includes/gnutls/openpgp.h
@@ -165,6 +165,10 @@ extern "C"
                                     gnutls_openpgp_crt_fmt_t format,
                                     const char *password,
                                     unsigned int flags);
+
+  int gnutls_openpgp_privkey_decrypt_data (gnutls_openpgp_privkey_t key,
+            unsigned int flags, const gnutls_datum_t * ciphertext,
+                                 gnutls_datum_t * plaintext);
   int gnutls_openpgp_privkey_sign_hash (gnutls_openpgp_privkey_t key,
                                        const gnutls_datum_t * hash,
                                        gnutls_datum_t * signature);
diff --git a/lib/includes/gnutls/pkcs11.h b/lib/includes/gnutls/pkcs11.h
new file mode 100644
index 0000000..f29b7bf
--- /dev/null
+++ b/lib/includes/gnutls/pkcs11.h
@@ -0,0 +1,232 @@
+#ifndef __GNUTLS_PKCS11_H
+#define __GNUTLS_PKCS11_H
+
+/**
+ * @addtogroup gnutls_pkcs11 GnuTLS PKCS#11 interface.
+ *
+ * @{
+ */
+
+/**
+ * @file gnutls-pkcs11.h
+ * @brief gnutls-pkcs11 interface.
+ * @author Alon Bar-Lev <address@hidden>
+ * @see @ref gnutls_pkcs11
+ */
+
+#include <stdarg.h>
+#include <gnutls/gnutls.h>
+#include <gnutls/x509.h>
+
+#define GNUTLS_PKCS11_MAX_PIN_LEN 32
+
+/**
+ * @brief Token prompt callback.
+ * @param global_data  Callback data.
+ * @param label                Token label.
+ * @param retry                Retry counter.
+ * @return none zero on success.
+ */
+typedef int (*gnutls_pkcs11_token_callback_t)(
+       void * const global_data,
+       const char * const label,
+       const unsigned retry
+);
+
+/* flags */
+#define GNUTLS_PKCS11_PIN_FINAL_TRY 1
+#define GNUTLS_PKCS11_PIN_COUNT_LOW 2
+
+/* Callback for PKCS#11 PIN entry.  The callback provides the PIN code
+ * to unlock the token with label 'token_label' in the slot described
+ * by 'slot_descr'.
+ *
+ * The PIN code, as a NUL-terminated ASCII string, should be copied
+ * into the 'pin' buffer (of fixed length NE_SSL_P11PINLEN), and
+ * return 0 to indicate success. Alternatively, the callback may
+ * return -1 to indicate failure and cancel PIN entry (in which case,
+ * the contents of the 'pin' parameter are ignored).
+ *
+ * When a PIN is required, the callback will be invoked repeatedly
+ * (and indefinitely) until either the returned PIN code is correct,
+ * the callback returns failure, or the token refuses login (e.g. when
+ * the token is locked due to too many incorrect PINs!).  For the
+ * first such invocation, the 'attempt' counter will have value zero;
+ * it will increase by one for each subsequent attempt.
+ *
+ * The NE_SSL_P11PIN_COUNT_LOW and/or NE_SSL_P11PIN_FINAL_TRY hints
+ * may be set in the 'flags' argument, if these hints are made
+ * available by the token; not all tokens expose these hints. */
+typedef int (*gnutls_pkcs11_pin_callback_t)(void *userdata, int attempt,
+                                    const char *slot_descr,
+                                    const char *token_label,
+                                    unsigned int flags,
+                                    char *pin, size_t pin_max);
+
+/**
+ * @brief PKCS#11 certificate reference.
+ */
+struct gnutls_pkcs11_obj_st;
+typedef struct gnutls_pkcs11_obj_st* gnutls_pkcs11_obj_t;
+
+
+#define GNUTLS_PKCS11_FLAG_MANUAL 0 /* Manual loading of libraries */
+#define GNUTLS_PKCS11_FLAG_AUTO 1 /* Automatically load libraries by reading 
/etc/gnutls/pkcs11.conf */
+
+/* pkcs11.conf format:
+ * load = /lib/xxx-pkcs11.so
+ * load = /lib/yyy-pkcs11.so
+ */
+
+/**
+ * @brief Initialize gnutls-pkcs11.
+ * @param params       Misc values to use.
+ * @return gnutls status.
+ * @note gnutls-pkcs11 must be uninitialize.
+ * @see gnutls_pkcs11_deinit()
+ * @todo params is not implemented yet.
+ *
+ * params is in the format of:
+ * name=value;name=value;
+ */
+int gnutls_pkcs11_init (unsigned int flags, const char* configfile);
+
+/**
+ * @brief Deinitialize gnutls-pkcs11.
+ * @return gnutls status.
+ */
+void gnutls_pkcs11_deinit (void);
+
+/**
+ * @brief Set token prompt callback.
+ * @param callback     Callback to use.
+ * @param data         Data to use when calling callback.
+ * @return gnutls status.
+ */
+void gnutls_pkcs11_set_token_function(gnutls_pkcs11_token_callback_t fn, void 
*userdata);
+
+/**
+ * @brief Set PIN prompt callback.
+ * @param callback     Callback to use.
+ * @param data         Data to use when calling callback.
+ * @return gnutls status.
+ */
+void gnutls_pkcs11_set_pin_function (gnutls_pkcs11_pin_callback_t callback, 
void * data);
+
+/**
+ * @brief Add PKCS#11 provider.
+ * @param name         Library to load.
+ * @param params       Misc provider parameters.
+ * @return gnutls status.
+ * @todo params is not implemented yet.
+ *
+ * params is in the format of:
+ * name=value;name=value; 
+ */
+int gnutls_pkcs11_add_provider (const char * name, const char * params);
+
+/**
+ * @brief Free certificate reference.
+ * @param certificate  Certificate reference to free.
+ * @return gnutls stauts.
+ */
+int gnutls_pkcs11_obj_init ( gnutls_pkcs11_obj_t *certificate);
+
+int gnutls_pkcs11_obj_import_url (gnutls_pkcs11_obj_t, const char * url);
+int gnutls_pkcs11_obj_export_url (gnutls_pkcs11_obj_t, char** url);
+void gnutls_pkcs11_obj_deinit ( gnutls_pkcs11_obj_t);
+
+int gnutls_pkcs11_obj_export(gnutls_pkcs11_obj_t obj,
+                    void *output_data, size_t * output_data_size);
+
+#define GNUTLS_PKCS11_OBJ_FLAG_TRUSTED 1 /* object marked as trusted */
+
+int gnutls_pkcs11_copy_x509_crt(const char* token_url, gnutls_x509_crt_t crt, 
+       const char* label, unsigned int flags /* GNUTLS_PKCS11_OBJ_FLAG_* */);
+int gnutls_pkcs11_copy_x509_privkey(const char* token_url, 
+       gnutls_x509_privkey_t crt, const char* label, unsigned int key_usage 
/*GNUTLS_KEY_* */);
+int gnutls_pkcs11_delete_url(const char* object_url);
+
+typedef enum {
+       GNUTLS_PKCS11_OBJ_ID_HEX=1,
+       GNUTLS_PKCS11_OBJ_LABEL,
+       GNUTLS_PKCS11_OBJ_TOKEN_LABEL,
+       GNUTLS_PKCS11_OBJ_TOKEN_SERIAL,
+       GNUTLS_PKCS11_OBJ_TOKEN_MANUFACTURER,
+       GNUTLS_PKCS11_OBJ_TOKEN_MODEL,
+       GNUTLS_PKCS11_OBJ_ID,
+} gnutls_pkcs11_obj_info_t;
+
+int gnutls_pkcs11_obj_get_info(gnutls_pkcs11_obj_t crt, 
gnutls_pkcs11_obj_info_t itype, void* output, size_t* output_size);
+
+typedef enum {
+       GNUTLS_PKCS11_OBJ_ATTR_CRT_ALL=1, /* all certificates */
+       GNUTLS_PKCS11_OBJ_ATTR_CRT_TRUSTED, /* certificates marked as trusted */
+       GNUTLS_PKCS11_OBJ_ATTR_CRT_WITH_PRIVKEY, /* certificates with 
corresponding private key */
+       GNUTLS_PKCS11_OBJ_ATTR_PUBKEY, /* public keys */
+       GNUTLS_PKCS11_OBJ_ATTR_ALL, /* everything! */
+} gnutls_pkcs11_obj_attr_t;
+
+/* token info */
+typedef enum {
+       GNUTLS_PKCS11_TOKEN_LABEL,
+       GNUTLS_PKCS11_TOKEN_SERIAL,
+       GNUTLS_PKCS11_TOKEN_MANUFACTURER,
+       GNUTLS_PKCS11_TOKEN_MODEL,
+} gnutls_pkcs11_token_info_t;
+
+typedef enum {
+       GNUTLS_PKCS11_OBJ_UNKNOWN,
+       GNUTLS_PKCS11_OBJ_X509_CRT,
+       GNUTLS_PKCS11_OBJ_PUBKEY,
+       GNUTLS_PKCS11_OBJ_PRIVKEY,
+       GNUTLS_PKCS11_OBJ_SECRET_KEY,
+       GNUTLS_PKCS11_OBJ_DATA,
+} gnutls_pkcs11_obj_type_t;
+
+int gnutls_pkcs11_token_get_url (unsigned int seq, char** url);
+int gnutls_pkcs11_token_get_info(const char* url, gnutls_pkcs11_token_info_t, 
void* output, size_t *output_size);
+
+#define GNUTLS_PKCS11_TOKEN_HW 1
+int gnutls_pkcs11_token_get_flags(const char* url, unsigned int *flags);
+
+int gnutls_pkcs11_obj_list_import_url (gnutls_pkcs11_obj_t * p_list, unsigned 
int *const n_list, const char* url, gnutls_pkcs11_obj_attr_t flags);
+
+int gnutls_x509_crt_import_pkcs11( gnutls_x509_crt_t crt, gnutls_pkcs11_obj_t 
pkcs11_crt);
+int gnutls_x509_crt_import_pkcs11_url( gnutls_x509_crt_t crt, const char* url);
+
+gnutls_pkcs11_obj_type_t gnutls_pkcs11_obj_get_type (gnutls_pkcs11_obj_t 
certificate);
+const char* gnutls_pkcs11_type_get_name (gnutls_pkcs11_obj_type_t);
+
+int gnutls_x509_crt_list_import_pkcs11 (gnutls_x509_crt_t * certs,
+                                   unsigned int cert_max,
+                                   gnutls_pkcs11_obj_t * const pkcs11_certs,
+                                   unsigned int flags);
+
+
+/* private key functions...*/
+int gnutls_pkcs11_privkey_init (gnutls_pkcs11_privkey_t * key);
+void gnutls_pkcs11_privkey_deinit (gnutls_pkcs11_privkey_t key);
+int gnutls_pkcs11_privkey_get_pk_algorithm (gnutls_pkcs11_privkey_t key, 
unsigned int* bits);
+int gnutls_pkcs11_privkey_get_info(gnutls_pkcs11_privkey_t crt, 
gnutls_pkcs11_obj_info_t itype, void* output, size_t* output_size);
+
+int gnutls_pkcs11_privkey_import_url (gnutls_pkcs11_privkey_t key,
+                                 const char* url, unsigned int flags);
+
+int gnutls_pkcs11_privkey_sign_data(gnutls_pkcs11_privkey_t signer,
+                               gnutls_digest_algorithm_t hash,
+                               unsigned int flags,
+                               const gnutls_datum_t * data,
+                               gnutls_datum_t * signature);
+int gnutls_pkcs11_privkey_sign_hash (gnutls_pkcs11_privkey_t key,
+                                const gnutls_datum_t * hash,
+                                gnutls_datum_t * signature);
+int
+gnutls_pkcs11_privkey_decrypt_data(gnutls_pkcs11_privkey_t key,
+                               unsigned int flags, const gnutls_datum_t * 
ciphertext,
+                               gnutls_datum_t * plaintext);
+int gnutls_pkcs11_privkey_export_url (gnutls_pkcs11_privkey_t key, char ** 
url);
+
+/** @} */
+
+#endif
diff --git a/lib/includes/gnutls/x509.h b/lib/includes/gnutls/x509.h
index 7ff7bde..5913898 100644
--- a/lib/includes/gnutls/x509.h
+++ b/lib/includes/gnutls/x509.h
@@ -139,6 +139,8 @@ extern "C"
                                  unsigned int flags,
                                  unsigned char *output_data,
                                  size_t * output_data_size);
+  int gnutls_x509_crt_get_preferred_hash_algorithm (gnutls_x509_crt_t crt,
+                                     gnutls_digest_algorithm_t * hash, 
unsigned int *mand);
 
   int gnutls_x509_crt_set_authority_key_id (gnutls_x509_crt_t cert,
                                            const void *id, size_t id_size);
@@ -633,6 +635,15 @@ extern "C"
                                          const gnutls_datum_t * p,
                                          const gnutls_datum_t * q,
                                          const gnutls_datum_t * u);
+  int gnutls_x509_privkey_import_rsa_raw2 (gnutls_x509_privkey_t key,
+                                         const gnutls_datum_t * m,
+                                         const gnutls_datum_t * e,
+                                         const gnutls_datum_t * d,
+                                         const gnutls_datum_t * p,
+                                         const gnutls_datum_t * q,
+                                         const gnutls_datum_t * u,
+                                         const gnutls_datum_t *exp1,
+                                         const gnutls_datum_t *exp2);
   int gnutls_x509_privkey_fix (gnutls_x509_privkey_t key);
 
   int gnutls_x509_privkey_export_dsa_raw (gnutls_x509_privkey_t key,
@@ -668,6 +679,11 @@ extern "C"
                                        unsigned int flags,
                                        void *output_data,
                                        size_t * output_data_size);
+  int gnutls_x509_privkey_export_rsa_raw2 (gnutls_x509_privkey_t key,
+        gnutls_datum_t * m, gnutls_datum_t * e,
+        gnutls_datum_t * d, gnutls_datum_t * p,
+        gnutls_datum_t * q, gnutls_datum_t * u,
+        gnutls_datum_t* e1, gnutls_datum_t* e2);
   int gnutls_x509_privkey_export_rsa_raw (gnutls_x509_privkey_t key,
                                          gnutls_datum_t * m,
                                          gnutls_datum_t * e,
@@ -684,6 +700,11 @@ extern "C"
                                     const gnutls_datum_t * data,
                                     void *signature,
                                     size_t * signature_size);
+  int gnutls_x509_privkey_sign_data2 (gnutls_x509_privkey_t key,
+                                    gnutls_digest_algorithm_t digest,
+                                    unsigned int flags,
+                                    const gnutls_datum_t * data,
+                                    gnutls_datum_t *signature);
   int gnutls_x509_privkey_verify_data (gnutls_x509_privkey_t key,
                                       unsigned int flags,
                                       const gnutls_datum_t * data,
@@ -720,6 +741,9 @@ extern "C"
   int gnutls_x509_crq_import (gnutls_x509_crq_t crq,
                              const gnutls_datum_t * data,
                              gnutls_x509_crt_fmt_t format);
+  int gnutls_x509_crq_get_preferred_hash_algorithm (gnutls_x509_crq_t crq,
+                             gnutls_digest_algorithm_t * hash, unsigned int* 
mand);
+
   int gnutls_x509_crq_get_dn (gnutls_x509_crq_t crq, char *buf,
                              size_t * sizeof_buf);
   int gnutls_x509_crq_get_dn_oid (gnutls_x509_crq_t crq, int indx,
diff --git a/lib/libgnutls.map b/lib/libgnutls.map
index ad61d61..527c618 100644
--- a/lib/libgnutls.map
+++ b/lib/libgnutls.map
@@ -602,6 +602,86 @@ GNUTLS_2_10
     gnutls_safe_renegotiation_status;
 } GNUTLS_2_8;
 
+GNUTLS_2_11
+{
+  global:
+       gnutls_certificate_set_retrieve_function;
+        gnutls_pkcs11_init;
+        gnutls_pkcs11_deinit;
+        gnutls_pkcs11_set_pin_function;
+       gnutls_pkcs11_set_token_function;
+        gnutls_pkcs11_add_provider;
+        gnutls_pkcs11_obj_init;
+        gnutls_pkcs11_obj_import_url;
+        gnutls_pkcs11_obj_export_url;
+        gnutls_pkcs11_obj_deinit;
+        gnutls_pkcs11_obj_list_import_url;
+        gnutls_x509_crt_import_pkcs11;
+        gnutls_pkcs11_obj_get_type;
+        gnutls_x509_crt_list_import_pkcs11;
+       gnutls_x509_crt_import_pkcs11_url;
+       gnutls_pkcs11_obj_get_info;
+       gnutls_pkcs11_token_get_info;
+       gnutls_pkcs11_token_get_url;
+       gnutls_pkcs11_privkey_init;
+       gnutls_pkcs11_privkey_deinit;
+       gnutls_pkcs11_privkey_get_pk_algorithm;
+       gnutls_pkcs11_privkey_get_info;
+       gnutls_pkcs11_privkey_import_url;
+       gnutls_pkcs11_privkey_sign_data;
+       gnutls_pkcs11_privkey_sign_hash;
+       gnutls_pkcs11_privkey_decrypt_data;
+       gnutls_pkcs11_obj_export;
+       gnutls_pkcs11_type_get_name;
+
+       gnutls_privkey_init;
+       gnutls_privkey_deinit;
+       gnutls_privkey_get_pk_algorithm;
+       gnutls_privkey_get_type;
+       gnutls_privkey_import_pkcs11;
+       gnutls_privkey_import_x509;
+       gnutls_privkey_import_openpgp;
+       gnutls_privkey_sign_data;
+       gnutls_privkey_sign_hash;
+       gnutls_privkey_decrypt_data;
+       gnutls_pkcs11_privkey_export_url;
+       gnutls_x509_crq_privkey_sign;
+       gnutls_x509_crl_privkey_sign;
+       gnutls_x509_crt_privkey_sign;
+       gnutls_pubkey_init;
+       gnutls_pubkey_deinit;
+       gnutls_pubkey_get_pk_algorithm;
+       gnutls_pubkey_import_x509;
+       gnutls_pubkey_import_openpgp;
+       gnutls_pubkey_get_pk_rsa_raw;
+       gnutls_pubkey_get_pk_dsa_raw;
+       gnutls_pubkey_export;
+       gnutls_pubkey_get_key_id;
+       gnutls_pubkey_get_key_usage;
+       gnutls_pubkey_import_pkcs11;
+       gnutls_pubkey_import_dsa_raw;
+       gnutls_pubkey_import_rsa_raw;
+       gnutls_pubkey_import_pkcs11_url;
+       gnutls_pubkey_get_verify_algorithm;
+       gnutls_pubkey_verify_hash;
+       gnutls_pkcs11_obj_export;
+       gnutls_pubkey_import;
+       gnutls_x509_crt_set_pubkey;
+       gnutls_x509_crq_set_pubkey;
+       gnutls_pkcs11_copy_x509_crt;
+       gnutls_pkcs11_copy_x509_privkey;
+       gnutls_pkcs11_delete_url;
+       gnutls_x509_privkey_export_rsa_raw2;
+       gnutls_pubkey_get_preferred_hash_algorithm;
+       gnutls_x509_crt_get_preferred_hash_algorithm;
+
+       gnutls_sec_param_to_pk_bits;
+       gnutls_sec_param_get_name;
+       gnutls_pk_bits_to_sec_param;
+       gnutls_rnd;
+       gnutls_x509_crq_get_preferred_hash_algorithm;
+} GNUTLS_2_10;
+
 GNUTLS_PRIVATE {
   global:
     # Internal symbols needed by libgnutls-extra:
@@ -628,7 +708,7 @@ GNUTLS_PRIVATE {
     _gnutls_hash;
 
     # Internal symbols needed by psktool:
-    _gnutls_rnd;
+
     # Internal symbols needed by gnutls-cli-debug:
     _gnutls_rsa_pms_set_version;
     _gnutls_record_set_default_version;
diff --git a/lib/libgnutlsxx.map b/lib/libgnutlsxx.map
index 3103884..4fd7bfe 100644
--- a/lib/libgnutlsxx.map
+++ b/lib/libgnutlsxx.map
@@ -20,22 +20,13 @@
 # Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 # MA 02110-1301, USA
 
-GNUTLS_1_6
+GNUTLS_2_10
 {
   global:
     extern "C++" {
-      # To specify a class we also need to specify its typeinfo,
-      # typeinfo name and vtable objects.
-      # For example for class gnutls::psk_client_credentials,
-      # we need to declare this 4 lines:
-      #
-      # gnutls::psk_client_credentials::*;
-      # "typeinfo for gnutls::psk_client_credentials";
-      # "typeinfo name for gnutls::psk_client_credentials";
-      # "vtable for gnutls::psk_client_credentials";
+      # Allow all symbols for C++. It has its own way to keep
+      # symbol namespaces.
 
-      *gnutls::*;
+      *;
   };
-
-  local: *;
 };
diff --git a/lib/m4/hooks.m4 b/lib/m4/hooks.m4
index c90bd16..720a675 100644
--- a/lib/m4/hooks.m4
+++ b/lib/m4/hooks.m4
@@ -30,11 +30,38 @@ AC_DEFUN([LIBGNUTLS_HOOKS],
   AC_SUBST(LT_REVISION, 6)
   AC_SUBST(LT_AGE, 16)
 
+  AC_SUBST(CXX_LT_CURRENT, 27)
+  AC_SUBST(CXX_LT_REVISION, 0)
+  AC_SUBST(CXX_LT_AGE, 0)
+
   # Used when creating the Windows libgnutls-XX.def files.
   DLL_VERSION=`expr ${LT_CURRENT} - ${LT_AGE}`
   AC_SUBST(DLL_VERSION)
 
-  AC_LIB_HAVE_LINKFLAGS([gcrypt], [gpg-error], [#include <gcrypt.h>],
+  cryptolib="nettle (unsupported)"
+  AC_ARG_WITH(nettle,
+    AS_HELP_STRING([--with-nettle], [use libnettle 2.x as crypto library]),
+      nettle=$withval,
+      nettle=no)
+    if test "$nettle" = "yes"; then
+    AC_LIB_HAVE_LINKFLAGS([nettle],, [#include <nettle/aes.h>],
+                          [aes_set_encrypt_key (0, 0, 0)])
+    if test "$ac_cv_libnettle" != yes; then
+      nettle=yes
+      AC_MSG_WARN([[
+  *** 
+  *** Libnettle was not found. 
+  ]])
+    fi
+  fi
+
+  AC_MSG_CHECKING([whether to use nettle])
+  AC_MSG_RESULT($nettle)
+  AM_CONDITIONAL(ENABLE_NETTLE, test "$nettle" = "yes")
+
+  if test "$nettle" != "yes";then
+       cryptolib=libgcrypt
+       AC_LIB_HAVE_LINKFLAGS([gcrypt], [gpg-error], [#include <gcrypt.h>],
     [enum gcry_cipher_algos i = GCRY_CIPHER_CAMELLIA128])
   if test "$ac_cv_libgcrypt" != yes; then
     AC_MSG_ERROR([[
@@ -44,6 +71,7 @@ AC_DEFUN([LIBGNUTLS_HOOKS],
 ***
     ]])
   fi
+  fi
 
   AC_ARG_WITH(included-libtasn1,
     AS_HELP_STRING([--with-included-libtasn1], [use the included libtasn1]),
@@ -64,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
+  #not other option for now. The released pakchois cannot open an arbitrary 
PKCS11 module,
+  #and the author is reluctant to add such feature.
+  included_pakchois=yes
+  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])])
+
+  fi
+
   AC_ARG_WITH(lzo,
     AS_HELP_STRING([--with-lzo], [use experimental LZO compression]),
                    use_lzo=$withval, use_lzo=no)
@@ -174,9 +231,14 @@ AC_DEFUN([LIBGNUTLS_HOOKS],
   AM_CONDITIONAL(ENABLE_ANON, test "$ac_enable_anon" != "no")
   
   # Allow disabling Camellia
+  if test "$nettle" != "yes";then
   AC_ARG_ENABLE(camellia,
     AS_HELP_STRING([--disable-camellia], [disable Camellia cipher]),
     enable_camellia=$enableval, enable_camellia=yes)
+  else
+    enable_camellia=no
+  fi
+
   AC_MSG_CHECKING([whether to disable Camellia cipher])
   if test "$enable_camellia" != "no"; then
    AC_MSG_RESULT([no])
diff --git a/lib/mpi-libgcrypt.c b/lib/mpi-libgcrypt.c
deleted file mode 100644
index eec739f..0000000
--- a/lib/mpi-libgcrypt.c
+++ /dev/null
@@ -1,404 +0,0 @@
-/*
- * Copyright (C) 2001, 2002, 2003, 2004, 2005, 2008, 2009, 2010 Free
- * Software Foundation, Inc.
- *
- * Author: Nikos Mavrogiannopoulos
- *
- * This file is part of GnuTLS.
- *
- * The GnuTLS is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public License
- * as published by the Free Software Foundation; either version 2.1 of
- * the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
- * USA
- *
- */
-
-/* Here lie everything that has to do with large numbers, libgcrypt and
- * other stuff that didn't fit anywhere else.
- */
-
-#include <gnutls_int.h>
-#include <gnutls_errors.h>
-#include <gnutls_num.h>
-#include <gnutls_mpi.h>
-#include <gcrypt.h>
-
-/* Functions that refer to the libgcrypt library.
- */
-
-static inline int
-_format_conv (gnutls_bigint_format_t format)
-{
-  if (format == GNUTLS_MPI_FORMAT_USG)
-    return GCRYMPI_FMT_USG;
-  else if (format == GNUTLS_MPI_FORMAT_STD)
-    return GCRYMPI_FMT_STD;
-  else
-    return GCRYMPI_FMT_PGP;
-}
-
-/* returns zero on success
- */
-static bigint_t
-wrap_gcry_mpi_scan (const void *buffer, size_t nbytes,
-                   gnutls_bigint_format_t format)
-{
-  gcry_mpi_t ret_mpi = NULL;
-  int ret;
-
-  ret = gcry_mpi_scan (&ret_mpi, _format_conv (format), buffer, nbytes, NULL);
-  if (ret != 0)
-    return NULL;
-
-  return ret_mpi;
-}
-
-static int
-wrap_gcry_mpi_print (const bigint_t a, void *buffer, size_t * nbytes,
-                    gnutls_bigint_format_t format)
-{
-  int ret;
-
-  format = _format_conv (format);
-
-  if (nbytes == NULL || a == NULL)
-    return GNUTLS_E_INVALID_REQUEST;
-
-  ret = gcry_mpi_print (format, buffer, *nbytes, nbytes, a);
-  if (!ret)
-    return 0;
-
-  return GNUTLS_E_MPI_PRINT_FAILED;
-}
-
-static bigint_t
-wrap_gcry_mpi_new (int nbits)
-{
-  return gcry_mpi_new (nbits);
-}
-
-static int
-wrap_gcry_mpi_cmp (const bigint_t u, const bigint_t v)
-{
-  return gcry_mpi_cmp (u, v);
-}
-
-static int
-wrap_gcry_mpi_cmp_ui (const bigint_t u, unsigned long v)
-{
-  return gcry_mpi_cmp_ui (u, v);
-}
-
-static bigint_t
-wrap_gcry_mpi_set (bigint_t w, const bigint_t u)
-{
-  return gcry_mpi_set (w, u);
-}
-
-static bigint_t
-wrap_gcry_mpi_set_ui (bigint_t w, unsigned long u)
-{
-  return gcry_mpi_set_ui (w, u);
-}
-
-static unsigned int
-wrap_gcry_mpi_get_nbits (bigint_t a)
-{
-  return gcry_mpi_get_nbits (a);
-}
-
-static void
-wrap_gcry_mpi_release (bigint_t a)
-{
-  gcry_mpi_release (a);
-}
-
-#undef _gnutls_mpi_alloc_like
-#define _gnutls_mpi_alloc_like(x) gcry_mpi_new(gcry_mpi_get_nbits(x))
-
-static bigint_t
-wrap_gcry_mpi_mod (const bigint_t a, const bigint_t b)
-{
-  bigint_t r = _gnutls_mpi_alloc_like (b);
-
-  if (r == NULL)
-    return NULL;
-
-  gcry_mpi_mod (r, a, b);
-
-  return r;
-}
-
-static bigint_t
-wrap_gcry_mpi_powm (bigint_t w, const bigint_t b, const bigint_t e,
-                   const bigint_t m)
-{
-  if (w == NULL)
-    w = _gnutls_mpi_alloc_like (m);
-
-  if (w == NULL)
-    return NULL;
-
-  gcry_mpi_powm (w, b, e, m);
-
-  return w;
-}
-
-static bigint_t
-wrap_gcry_mpi_addm (bigint_t w, const bigint_t a, const bigint_t b,
-                   const bigint_t m)
-{
-  if (w == NULL)
-    w = _gnutls_mpi_alloc_like (m);
-
-  if (w == NULL)
-    return NULL;
-
-  gcry_mpi_addm (w, a, b, m);
-
-  return w;
-}
-
-static bigint_t
-wrap_gcry_mpi_subm (bigint_t w, const bigint_t a, const bigint_t b,
-                   const bigint_t m)
-{
-  if (w == NULL)
-    w = _gnutls_mpi_alloc_like (m);
-
-  if (w == NULL)
-    return NULL;
-
-  gcry_mpi_subm (w, a, b, m);
-
-  return w;
-}
-
-static bigint_t
-wrap_gcry_mpi_mulm (bigint_t w, const bigint_t a, const bigint_t b,
-                   const bigint_t m)
-{
-  if (w == NULL)
-    w = _gnutls_mpi_alloc_like (m);
-
-  if (w == NULL)
-    return NULL;
-
-  gcry_mpi_mulm (w, a, b, m);
-
-  return w;
-}
-
-static bigint_t
-wrap_gcry_mpi_add (bigint_t w, const bigint_t a, const bigint_t b)
-{
-  if (w == NULL)
-    w = _gnutls_mpi_alloc_like (b);
-
-  if (w == NULL)
-    return NULL;
-
-  gcry_mpi_add (w, a, b);
-
-  return w;
-}
-
-static bigint_t
-wrap_gcry_mpi_sub (bigint_t w, const bigint_t a, const bigint_t b)
-{
-  if (w == NULL)
-    w = _gnutls_mpi_alloc_like (b);
-
-  if (w == NULL)
-    return NULL;
-
-  gcry_mpi_sub (w, a, b);
-
-  return w;
-}
-
-static bigint_t
-wrap_gcry_mpi_mul (bigint_t w, const bigint_t a, const bigint_t b)
-{
-  if (w == NULL)
-    w = _gnutls_mpi_alloc_like (b);
-
-  if (w == NULL)
-    return NULL;
-
-  gcry_mpi_mul (w, a, b);
-
-  return w;
-}
-
-/* q = a / b */
-static bigint_t
-wrap_gcry_mpi_div (bigint_t q, const bigint_t a, const bigint_t b)
-{
-  if (q == NULL)
-    q = _gnutls_mpi_alloc_like (a);
-
-  if (q == NULL)
-    return NULL;
-
-  gcry_mpi_div (q, NULL, a, b, 0);
-
-  return q;
-}
-
-static bigint_t
-wrap_gcry_mpi_add_ui (bigint_t w, const bigint_t a, unsigned long b)
-{
-  if (w == NULL)
-    w = _gnutls_mpi_alloc_like (a);
-
-  if (w == NULL)
-    return NULL;
-
-  gcry_mpi_add_ui (w, a, b);
-
-  return w;
-}
-
-static bigint_t
-wrap_gcry_mpi_sub_ui (bigint_t w, const bigint_t a, unsigned long b)
-{
-  if (w == NULL)
-    w = _gnutls_mpi_alloc_like (a);
-
-  if (w == NULL)
-    return NULL;
-
-  gcry_mpi_sub_ui (w, a, b);
-
-  return w;
-}
-
-static bigint_t
-wrap_gcry_mpi_mul_ui (bigint_t w, const bigint_t a, unsigned long b)
-{
-  if (w == NULL)
-    w = _gnutls_mpi_alloc_like (a);
-
-  if (w == NULL)
-    return NULL;
-
-  gcry_mpi_mul_ui (w, a, b);
-
-  return w;
-}
-
-static int
-wrap_gcry_prime_check (bigint_t pp)
-{
-  return gcry_prime_check (pp, 0);
-}
-
-static int
-wrap_gcry_generate_group (gnutls_group_st * group, unsigned int bits)
-{
-  gcry_mpi_t g = NULL, prime = NULL;
-  gcry_error_t err;
-  int times = 0, qbits;
-  gcry_mpi_t *factors = NULL;
-
-  /* Calculate the size of a prime factor of (prime-1)/2.
-   * This is an emulation of the values in "Selecting Cryptographic Key Sizes" 
paper.
-   */
-  if (bits < 256)
-    qbits = bits / 2;
-  else
-    {
-      qbits = (bits / 40) + 105;
-    }
-
-  if (qbits & 1)               /* better have an even number */
-    qbits++;
-
-  /* find a prime number of size bits.
-   */
-  do
-    {
-      if (times)
-       {
-         gcry_mpi_release (prime);
-         gcry_prime_release_factors (factors);
-       }
-
-      err = gcry_prime_generate (&prime, bits, qbits, &factors,
-                                NULL, NULL, GCRY_STRONG_RANDOM,
-                                GCRY_PRIME_FLAG_SPECIAL_FACTOR);
-      if (err != 0)
-       {
-         gnutls_assert ();
-         return GNUTLS_E_INTERNAL_ERROR;
-       }
-
-      err = gcry_prime_check (prime, 0);
-
-      times++;
-    }
-  while (err != 0 && times < 10);
-
-  if (err != 0)
-    {
-      gnutls_assert ();
-      gcry_mpi_release (prime);
-      gcry_prime_release_factors (factors);
-      return GNUTLS_E_INTERNAL_ERROR;
-    }
-
-  /* generate the group generator.
-   */
-  err = gcry_prime_group_generator (&g, prime, factors, NULL);
-  gcry_prime_release_factors (factors);
-  if (err != 0)
-    {
-      gnutls_assert ();
-      gcry_mpi_release (prime);
-      return GNUTLS_E_INTERNAL_ERROR;
-    }
-
-  group->g = g;
-  group->p = prime;
-
-  return 0;
-}
-
-int crypto_bigint_prio = INT_MAX;
-
-gnutls_crypto_bigint_st _gnutls_mpi_ops = {
-  .bigint_new = wrap_gcry_mpi_new,
-  .bigint_cmp = wrap_gcry_mpi_cmp,
-  .bigint_cmp_ui = wrap_gcry_mpi_cmp_ui,
-  .bigint_mod = wrap_gcry_mpi_mod,
-  .bigint_set = wrap_gcry_mpi_set,
-  .bigint_set_ui = wrap_gcry_mpi_set_ui,
-  .bigint_get_nbits = wrap_gcry_mpi_get_nbits,
-  .bigint_powm = wrap_gcry_mpi_powm,
-  .bigint_addm = wrap_gcry_mpi_addm,
-  .bigint_subm = wrap_gcry_mpi_subm,
-  .bigint_add = wrap_gcry_mpi_add,
-  .bigint_sub = wrap_gcry_mpi_sub,
-  .bigint_add_ui = wrap_gcry_mpi_add_ui,
-  .bigint_sub_ui = wrap_gcry_mpi_sub_ui,
-  .bigint_mul = wrap_gcry_mpi_mul,
-  .bigint_mulm = wrap_gcry_mpi_mulm,
-  .bigint_mul_ui = wrap_gcry_mpi_mul_ui,
-  .bigint_div = wrap_gcry_mpi_div,
-  .bigint_prime_check = wrap_gcry_prime_check,
-  .bigint_release = wrap_gcry_mpi_release,
-  .bigint_print = wrap_gcry_mpi_print,
-  .bigint_scan = wrap_gcry_mpi_scan,
-  .bigint_generate_group = wrap_gcry_generate_group
-};
diff --git a/lib/nettle/Makefile.am b/lib/nettle/Makefile.am
new file mode 100644
index 0000000..c7efbe5
--- /dev/null
+++ b/lib/nettle/Makefile.am
@@ -0,0 +1,34 @@
+## Process this file with automake to produce Makefile.in
+# Copyright (C) 2004, 2005, 2006, 2007, 2008, 2010 Free Software
+# Foundation, Inc.
+#
+# Author: Nikos Mavroyanopoulos
+#
+# This file is part of GNUTLS.
+#
+# The GNUTLS library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public License
+# as published by the Free Software Foundation; either version 2.1 of
+# the License, or (at your option) any later version.
+#
+# The GNUTLS library is distributed in the hope that it will be
+# useful, but WITHOUT ANY WARRANTY; without even the implied warranty
+# of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with the GNUTLS library; if not, write to the Free
+# Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+# MA 02110-1301, USA
+
+AM_CFLAGS = $(WERROR_CFLAGS) $(WSTACK_CFLAGS) $(WARN_CFLAGS)
+AM_CPPFLAGS = \
+       -I$(srcdir)/../gl               \
+       -I$(builddir)/../gl             \
+       -I$(srcdir)/../includes         \
+       -I$(builddir)/../includes       \
+       -I$(srcdir)/..
+
+noinst_LTLIBRARIES = libcrypto.la
+
+libcrypto_la_SOURCES = pk.c mpi.c mac.c cipher.c rnd.c
diff --git a/lib/nettle/cipher.c b/lib/nettle/cipher.c
new file mode 100644
index 0000000..7773370
--- /dev/null
+++ b/lib/nettle/cipher.c
@@ -0,0 +1,272 @@
+/*
+ * Copyright (C) 2010 Free Software Foundation, Inc.
+ *
+ * Author: Nikos Mavrogiannopoulos
+ *
+ * This file is part of GNUTLS.
+ *
+ * The GNUTLS library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+ * USA
+ *
+ */
+
+/* Here lie nettle's wrappers for cipher support.
+ */
+
+#include <gnutls_int.h>
+#include <gnutls_errors.h>
+#include <gnutls_cipher_int.h>
+#include <nettle/aes.h>
+#include <nettle/arcfour.h>
+#include <nettle/arctwo.h>
+#include <nettle/des.h>
+#include <nettle/nettle-meta.h>
+#include <nettle/cbc.h>
+
+/* Functions that refer to the libgcrypt library.
+ */
+
+#define MAX_BLOCK_SIZE 32
+
+typedef void (*encrypt_func)(void*, nettle_crypt_func, unsigned, uint8_t*, 
unsigned, uint8_t *, const uint8_t *);
+typedef void (*decrypt_func)(void*, nettle_crypt_func, unsigned, uint8_t*, 
unsigned, uint8_t *, const uint8_t *);
+typedef void (*setkey_func)(void*, unsigned, const uint8_t*);
+
+static void stream_encrypt (void* ctx, nettle_crypt_func func, unsigned 
block_size, uint8_t* iv, unsigned length, uint8_t * dst, const uint8_t * src)
+{
+       func(ctx, length, dst, src);
+}
+
+struct aes_bidi_ctx
+{
+       struct aes_ctx encrypt;
+       struct aes_ctx decrypt;
+};
+
+static void aes_bidi_setkey (struct aes_bidi_ctx* ctx, unsigned length, const 
uint8_t *key)
+{
+       aes_set_encrypt_key (&ctx->encrypt, length, key);
+       aes_set_decrypt_key (&ctx->decrypt, length, key);
+}
+
+static void aes_bidi_encrypt(struct aes_bidi_ctx *ctx,
+          unsigned length, uint8_t *dst, const uint8_t *src)
+{
+       aes_encrypt(&ctx->encrypt, length, dst, src);
+}
+
+static void aes_bidi_decrypt(struct aes_bidi_ctx *ctx,
+          unsigned length, uint8_t *dst, const uint8_t *src)
+{
+       aes_decrypt(&ctx->decrypt, length, dst, src);
+}
+
+struct nettle_cipher_ctx {
+    union {
+               struct aes_bidi_ctx aes_bidi;
+               struct arcfour_ctx arcfour;
+               struct arctwo_ctx arctwo;
+               struct des3_ctx des3;
+               struct des_ctx des;
+    } ctx;
+    void *ctx_ptr;
+    uint8_t iv[MAX_BLOCK_SIZE];
+    gnutls_cipher_algorithm_t algo;
+    size_t block_size;
+    nettle_crypt_func* i_encrypt;
+    nettle_crypt_func* i_decrypt;
+    encrypt_func encrypt;
+    decrypt_func decrypt;
+};
+
+
+
+static int
+wrap_nettle_cipher_init (gnutls_cipher_algorithm_t algo, void **_ctx)
+{
+       struct nettle_cipher_ctx* ctx;
+
+    ctx = gnutls_calloc(1, sizeof(*ctx));
+    if (ctx == NULL) {
+               gnutls_assert();
+               return GNUTLS_E_MEMORY_ERROR;
+    }
+
+    ctx->algo = algo;
+
+    switch (algo) {
+    case GNUTLS_CIPHER_AES_128_CBC:
+    case GNUTLS_CIPHER_AES_192_CBC:
+    case GNUTLS_CIPHER_AES_256_CBC:
+               ctx->encrypt = cbc_encrypt;
+               ctx->decrypt = cbc_decrypt;
+               ctx->i_encrypt = (nettle_crypt_func*)aes_bidi_encrypt;
+               ctx->i_decrypt = (nettle_crypt_func*)aes_bidi_decrypt;
+               ctx->ctx_ptr = &ctx->ctx.aes_bidi;
+               ctx->block_size = AES_BLOCK_SIZE;
+               break;
+    case GNUTLS_CIPHER_3DES_CBC:
+               ctx->encrypt = cbc_encrypt;
+               ctx->decrypt = cbc_decrypt;
+               ctx->i_encrypt = (nettle_crypt_func*)des3_encrypt;
+               ctx->i_decrypt = (nettle_crypt_func*)des3_decrypt;
+               ctx->ctx_ptr = &ctx->ctx.des3;
+               ctx->block_size = DES3_BLOCK_SIZE;
+               break;
+    case GNUTLS_CIPHER_DES_CBC:
+               ctx->encrypt = cbc_encrypt;
+               ctx->decrypt = cbc_decrypt;
+               ctx->i_encrypt = (nettle_crypt_func*)des_encrypt;
+               ctx->i_decrypt = (nettle_crypt_func*)des_decrypt;
+               ctx->ctx_ptr = &ctx->ctx.des;
+               ctx->block_size = DES_BLOCK_SIZE;
+               break;
+    case GNUTLS_CIPHER_ARCFOUR_128:
+    case GNUTLS_CIPHER_ARCFOUR_40:
+               ctx->encrypt = stream_encrypt;
+               ctx->decrypt = stream_encrypt;
+               ctx->i_encrypt = (nettle_crypt_func*)arcfour_crypt;
+               ctx->i_decrypt = (nettle_crypt_func*)arcfour_crypt;
+               ctx->ctx_ptr = &ctx->ctx.arcfour;
+               ctx->block_size = 1;
+               break;
+    case GNUTLS_CIPHER_RC2_40_CBC:
+               ctx->encrypt = cbc_encrypt;
+               ctx->decrypt = cbc_decrypt;
+               ctx->i_encrypt = (nettle_crypt_func*)arctwo_encrypt;
+               ctx->i_decrypt = (nettle_crypt_func*)arctwo_decrypt;
+               ctx->ctx_ptr = &ctx->ctx.arctwo;
+               ctx->block_size = ARCTWO_BLOCK_SIZE;
+               break;
+       /* FIXME: Camellia? */
+    default:
+      gnutls_assert ();
+      return GNUTLS_E_INVALID_REQUEST;
+    }
+       
+       *_ctx = ctx;
+
+       return 0;
+}
+
+static int
+wrap_nettle_cipher_setkey (void *_ctx, const void *key, size_t keysize)
+{
+       struct nettle_cipher_ctx* ctx = _ctx;
+       opaque des_key[DES3_KEY_SIZE];
+       
+    switch (ctx->algo) {
+    case GNUTLS_CIPHER_AES_128_CBC:
+    case GNUTLS_CIPHER_AES_192_CBC:
+    case GNUTLS_CIPHER_AES_256_CBC:
+               aes_bidi_setkey(ctx->ctx_ptr, keysize, key);
+               break;
+    case GNUTLS_CIPHER_3DES_CBC:
+               /* why do we have to deal with parity address@hidden(*$# */
+               if (keysize != DES3_KEY_SIZE) {
+                   gnutls_assert();
+                   return GNUTLS_E_INTERNAL_ERROR;
+               }
+
+               des_fix_parity(keysize, des_key, key);
+
+               /* this fails on weak keys */
+               if (des3_set_key(ctx->ctx_ptr, des_key)!=1) {
+                       gnutls_assert();
+                       return GNUTLS_E_INTERNAL_ERROR;
+               }
+               break;
+    case GNUTLS_CIPHER_DES_CBC:
+               if (keysize != DES_KEY_SIZE)
+                 {
+                   gnutls_assert();
+                   return GNUTLS_E_INTERNAL_ERROR;
+                  }
+
+               des_fix_parity(keysize, des_key, key);
+
+               if (des_set_key(ctx->ctx_ptr, des_key)!=1) {
+                       gnutls_assert();
+                       return GNUTLS_E_INTERNAL_ERROR;
+               }
+               break;
+    case GNUTLS_CIPHER_ARCFOUR_128:
+    case GNUTLS_CIPHER_ARCFOUR_40:
+               arcfour_set_key(ctx->ctx_ptr, keysize, key);
+               break;
+    case GNUTLS_CIPHER_RC2_40_CBC:
+               arctwo_set_key(ctx->ctx_ptr, keysize, key);
+               break;
+    default:
+      gnutls_assert ();
+      return GNUTLS_E_INVALID_REQUEST;
+    }
+       
+       return 0;
+}
+
+static int
+wrap_nettle_cipher_setiv (void *_ctx, const void *iv, size_t ivsize)
+{
+       struct nettle_cipher_ctx* ctx = _ctx;
+
+       if (ivsize > ctx->block_size) {
+               gnutls_assert();
+               return GNUTLS_E_INVALID_REQUEST;
+       }
+       memcpy(ctx->iv, iv, ivsize);
+
+       return 0;
+}
+
+static int
+wrap_nettle_cipher_decrypt (void *_ctx, const void *encr, size_t encrsize,
+                         void *plain, size_t plainsize)
+{
+       struct nettle_cipher_ctx* ctx = _ctx;
+
+       ctx->decrypt(ctx->ctx_ptr, ctx->i_decrypt, ctx->block_size, ctx->iv, 
encrsize, plain, encr);
+       
+       return 0;
+}
+
+static int
+wrap_nettle_cipher_encrypt (void *_ctx, const void *plain, size_t plainsize,
+                         void *encr, size_t encrsize)
+{
+       struct nettle_cipher_ctx* ctx = _ctx;
+
+       ctx->encrypt(ctx->ctx_ptr, ctx->i_encrypt, ctx->block_size, ctx->iv, 
plainsize, encr, plain);
+       
+       return 0;
+}
+
+static void
+wrap_nettle_cipher_close (void *h)
+{
+       gnutls_free(h);
+}
+
+
+int crypto_cipher_prio = INT_MAX;
+
+gnutls_crypto_cipher_st _gnutls_cipher_ops = {
+  .init = wrap_nettle_cipher_init,
+  .setkey = wrap_nettle_cipher_setkey,
+  .setiv = wrap_nettle_cipher_setiv,
+  .encrypt = wrap_nettle_cipher_encrypt,
+  .decrypt = wrap_nettle_cipher_decrypt,
+  .deinit = wrap_nettle_cipher_close,
+};
diff --git a/lib/nettle/mac.c b/lib/nettle/mac.c
new file mode 100644
index 0000000..5821843
--- /dev/null
+++ b/lib/nettle/mac.c
@@ -0,0 +1,290 @@
+/*
+ * Copyright (C) 2008, 2010 Free Software Foundation, Inc.
+ *
+ * Author: Nikos Mavrogiannopoulos
+ *
+ * This file is part of GNUTLS.
+ *
+ * The GNUTLS library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+ * USA
+ *
+ */
+
+/* This file provides is the backend hash/mac API for libgcrypt.
+ */
+
+#include <gnutls_int.h>
+#include <gnutls_hash_int.h>
+#include <gnutls_errors.h>
+#include <nettle/md5.h>
+#include <nettle/md2.h>
+#include <nettle/sha.h>
+#include <nettle/hmac.h>
+
+typedef void (*update_func) (void *, unsigned, const uint8_t *);
+typedef void (*digest_func) (void *, unsigned, uint8_t *);
+typedef void (*set_key_func) (void *, unsigned, const uint8_t *);
+
+static int wrap_nettle_hash_init(gnutls_mac_algorithm_t algo, void **_ctx);
+
+struct nettle_hash_ctx {
+    union {
+               struct md5_ctx md5;
+               struct md2_ctx md2;
+               struct sha256_ctx sha256;
+               struct sha1_ctx sha1;
+    } ctx;
+    void *ctx_ptr;
+    gnutls_mac_algorithm_t algo;
+    size_t length;
+    update_func update;
+    digest_func digest;
+};
+
+struct nettle_hmac_ctx {
+    union {
+               struct hmac_md5_ctx md5;
+               struct hmac_sha256_ctx sha256;
+               struct hmac_sha1_ctx sha1;
+    } ctx;
+    void *ctx_ptr;
+    gnutls_mac_algorithm_t algo;
+    size_t length;
+    update_func update;
+    digest_func digest;
+    set_key_func setkey;
+};
+
+static int wrap_nettle_hmac_init(gnutls_mac_algorithm_t algo, void **_ctx)
+{
+       struct nettle_hmac_ctx* ctx;
+
+    ctx = gnutls_malloc(sizeof(struct nettle_hmac_ctx));
+    if (ctx == NULL) {
+               gnutls_assert();
+               return GNUTLS_E_MEMORY_ERROR;
+    }
+
+    ctx->algo = algo;
+
+    switch (algo) {
+    case GNUTLS_MAC_MD5:
+               ctx->update = (update_func)hmac_md5_update;
+               ctx->digest = (digest_func)hmac_md5_digest;
+               ctx->setkey = (set_key_func)hmac_md5_set_key;
+               ctx->ctx_ptr = &ctx->ctx.md5;
+               ctx->length = MD5_DIGEST_SIZE;
+               break;
+    case GNUTLS_MAC_SHA1:
+               ctx->update = (update_func)hmac_sha1_update;
+               ctx->digest = (digest_func)hmac_sha1_digest;
+               ctx->setkey = (set_key_func)hmac_sha1_set_key;
+               ctx->ctx_ptr = &ctx->ctx.sha1;
+               ctx->length = SHA1_DIGEST_SIZE;
+               break;
+    case GNUTLS_MAC_SHA256:
+               ctx->update = (update_func)hmac_sha256_update;
+               ctx->digest = (digest_func)hmac_sha256_digest;
+               ctx->setkey = (set_key_func)hmac_sha256_set_key;
+               ctx->ctx_ptr = &ctx->ctx.sha256;
+               ctx->length = SHA256_DIGEST_SIZE;
+               break;
+       /* FIXME: SHA512/384/224? */
+    default:
+               gnutls_assert();
+               return GNUTLS_E_INVALID_REQUEST;
+    }
+
+       *_ctx = ctx;
+
+    return 0;
+}
+
+static int wrap_nettle_hmac_setkey(void *_ctx, const void *key, size_t keylen)
+{
+    struct nettle_hmac_ctx *ctx = _ctx;
+    
+       ctx->setkey(ctx->ctx_ptr, keylen, key);
+
+    return GNUTLS_E_SUCCESS;
+}
+
+static int
+wrap_nettle_hmac_update(void *_ctx, const void *text, size_t textsize)
+{
+    struct nettle_hmac_ctx *ctx = _ctx;
+
+    ctx->update(ctx->ctx_ptr, textsize, text);
+
+    return GNUTLS_E_SUCCESS;
+}
+
+static int
+wrap_nettle_hash_update(void *_ctx, const void *text, size_t textsize)
+{
+    struct nettle_hash_ctx *ctx = _ctx;
+
+    ctx->update(ctx->ctx_ptr, textsize, text);
+
+    return GNUTLS_E_SUCCESS;
+}
+
+static int wrap_nettle_hash_copy(void **bhd, void *ahd)
+{
+       struct nettle_hash_ctx *ctx = ahd;
+       struct nettle_hash_ctx *dst_ctx;
+       int ret;
+
+       ret = wrap_nettle_hash_init(ctx->algo, bhd);
+       if (ret < 0) {
+               gnutls_assert();
+               return ret;
+       }
+       
+       dst_ctx = *bhd;
+       
+       memcpy(&dst_ctx->ctx, &ctx->ctx, sizeof(ctx->ctx));
+
+       return 0;
+}
+
+static int wrap_nettle_hmac_copy(void **bhd, void *ahd)
+{
+       struct nettle_hmac_ctx *ctx = ahd;
+       struct nettle_hmac_ctx *dst_ctx;
+       int ret;
+
+       ret = wrap_nettle_hmac_init(ctx->algo, bhd);
+       if (ret < 0) {
+               gnutls_assert();
+               return ret;
+       }
+       
+       dst_ctx = *bhd;
+
+       memcpy(&dst_ctx->ctx, &ctx->ctx, sizeof(ctx->ctx));
+       
+       return 0;
+}
+
+static void wrap_nettle_md_close(void *hd)
+{
+    gnutls_free(hd);
+}
+
+static int wrap_nettle_hash_init(gnutls_mac_algorithm_t algo, void **_ctx)
+{
+       struct nettle_hash_ctx* ctx;
+
+    ctx = gnutls_malloc(sizeof(struct nettle_hash_ctx));
+    if (ctx == NULL) {
+               gnutls_assert();
+               return GNUTLS_E_MEMORY_ERROR;
+    }
+
+    ctx->algo = algo;
+
+    switch (algo) {
+    case GNUTLS_DIG_MD5:
+               md5_init(&ctx->ctx.md5);
+               ctx->update = (update_func)md5_update;
+               ctx->digest = (digest_func)md5_digest;
+               ctx->ctx_ptr = &ctx->ctx.md5;
+               ctx->length = MD5_DIGEST_SIZE;
+               break;
+    case GNUTLS_DIG_SHA1:
+               sha1_init(&ctx->ctx.sha1);
+               ctx->update = (update_func)sha1_update;
+               ctx->digest = (digest_func)sha1_digest;
+               ctx->ctx_ptr = &ctx->ctx.sha1;
+               ctx->length = SHA1_DIGEST_SIZE;
+               break;
+    case GNUTLS_DIG_MD2:
+               md2_init(&ctx->ctx.md2);
+               ctx->update = (update_func)md2_update;
+               ctx->digest = (digest_func)md2_digest;
+               ctx->ctx_ptr = &ctx->ctx.md2;
+               ctx->length = MD2_DIGEST_SIZE;
+               break;
+    case GNUTLS_DIG_SHA256:
+               sha256_init(&ctx->ctx.sha256);
+               ctx->update = (update_func)sha256_update;
+               ctx->digest = (digest_func)sha256_digest;
+               ctx->ctx_ptr = &ctx->ctx.sha256;
+               ctx->length = SHA256_DIGEST_SIZE;
+               break;
+       /* FIXME: SHA512/384/224? */
+    default:
+               gnutls_assert();
+               return GNUTLS_E_INVALID_REQUEST;
+    }
+       
+       *_ctx = ctx;
+
+    return 0;
+}
+
+static int
+wrap_nettle_hash_output(void *src_ctx, void *digest, size_t digestsize)
+{
+    struct nettle_hash_ctx *ctx;
+    ctx = src_ctx;
+
+    if (digestsize < ctx->length) {
+               gnutls_assert();
+               return GNUTLS_E_SHORT_MEMORY_BUFFER;
+    }
+
+    ctx->digest(ctx->ctx_ptr, digestsize, digest);
+
+       return 0;
+}
+
+static int
+wrap_nettle_hmac_output(void *src_ctx, void *digest, size_t digestsize)
+{
+    struct nettle_hmac_ctx *ctx;
+    ctx = src_ctx;
+
+    if (digestsize < ctx->length) {
+               gnutls_assert();
+               return GNUTLS_E_SHORT_MEMORY_BUFFER;
+    }
+
+    ctx->digest(ctx->ctx_ptr, digestsize, digest);
+
+       return 0;
+}
+
+int crypto_mac_prio = INT_MAX;
+
+gnutls_crypto_mac_st _gnutls_mac_ops = {
+    .init = wrap_nettle_hmac_init,
+    .setkey = wrap_nettle_hmac_setkey,
+    .hash = wrap_nettle_hmac_update,
+    .copy = wrap_nettle_hmac_copy,
+    .output = wrap_nettle_hmac_output,
+    .deinit = wrap_nettle_md_close,
+};
+
+int crypto_digest_prio = INT_MAX;
+
+gnutls_crypto_digest_st _gnutls_digest_ops = {
+    .init = wrap_nettle_hash_init,
+    .hash = wrap_nettle_hash_update,
+    .copy = wrap_nettle_hash_copy,
+    .output = wrap_nettle_hash_output,
+    .deinit = wrap_nettle_md_close,
+};
diff --git a/lib/nettle/mpi.c b/lib/nettle/mpi.c
new file mode 100644
index 0000000..ef91ffd
--- /dev/null
+++ b/lib/nettle/mpi.c
@@ -0,0 +1,591 @@
+/*
+ * Copyright (C) 2010 Free
+ * Software Foundation, Inc.
+ *
+ * Author: Nikos Mavrogiannopoulos
+ *
+ * This file is part of GNUTLS.
+ *
+ * The GNUTLS library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+ * USA
+ *
+ */
+
+/* Here lie everything that has to do with large numbers, gmp.
+ */
+
+#include <gnutls_int.h>
+#include <gnutls_errors.h>
+#include <gnutls_num.h>
+#include <gnutls_mpi.h>
+#include <gmp.h>
+#include <nettle/bignum.h>
+#include <random.h>
+
+#define TOMPZ(x) (*((mpz_t*)(x)))
+
+static int
+wrap_nettle_mpi_print(const bigint_t a, void *buffer, size_t * nbytes,
+                   gnutls_bigint_format_t format)
+{
+       unsigned int size;
+       mpz_t *p = (void*)a;
+
+       if (format == GNUTLS_MPI_FORMAT_USG) {
+               size =  nettle_mpz_sizeinbase_256_u(*p);
+       } else if (format == GNUTLS_MPI_FORMAT_STD) {
+               size =  nettle_mpz_sizeinbase_256_s(*p);
+       } else if (format == GNUTLS_MPI_FORMAT_PGP) {
+               size = nettle_mpz_sizeinbase_256_u(*p) + 2;
+       } else {
+               gnutls_assert();
+               return GNUTLS_E_INVALID_REQUEST;
+       }
+
+       if (buffer==NULL || size > *nbytes) {
+               *nbytes=size;
+               return GNUTLS_E_SHORT_MEMORY_BUFFER;
+       }
+       
+       if (format == GNUTLS_MPI_FORMAT_PGP) {
+               opaque *buf = buffer;
+               unsigned int nbits = _gnutls_mpi_get_nbits(a);
+               buf[0] = (nbits >> 8) & 0xff;
+               buf[1] = (nbits) & 0xff;
+               nettle_mpz_get_str_256(size-2, buf+2, *p);
+       } else {
+               nettle_mpz_get_str_256(size, buffer, *p);
+       }
+       *nbytes=size;
+
+       return 0;
+}
+
+static bigint_t wrap_nettle_mpi_new(int nbits)
+{
+       mpz_t *p;
+
+       p = gnutls_malloc(sizeof(*p));
+       if (p == NULL) {
+               gnutls_assert();
+               return NULL;
+       }
+       mpz_init2(*p, nbits);
+
+       return p;
+}
+
+static bigint_t
+wrap_nettle_mpi_scan(const void *buffer, size_t nbytes,
+                  gnutls_bigint_format_t format)
+{
+       bigint_t r = wrap_nettle_mpi_new(nbytes*8);
+       
+       if (r==NULL) {
+               gnutls_assert();
+               return r;
+       }
+
+       if (format == GNUTLS_MPI_FORMAT_USG) {
+               nettle_mpz_set_str_256_u(TOMPZ(r), nbytes, buffer);
+       } else if (format == GNUTLS_MPI_FORMAT_STD) {
+               nettle_mpz_set_str_256_s(TOMPZ(r), nbytes, buffer);
+       } else if (format == GNUTLS_MPI_FORMAT_PGP) {
+               const opaque *buf = buffer;
+               size_t size;
+
+               if (nbytes < 3) {
+                       gnutls_assert();
+                       goto fail;
+               }
+
+               size = (buf[0] << 8) | buf[1];
+               size = (size+7) / 8;
+
+               if (size > nbytes-2) {
+                       gnutls_assert();
+                       goto fail;
+               }
+               nettle_mpz_set_str_256_u(TOMPZ(r), size, buf+2);
+       } else {
+               gnutls_assert();
+               goto fail;
+       }
+       
+       return r;
+fail:
+       _gnutls_mpi_release(&r);
+       return NULL;
+
+}
+
+static int wrap_nettle_mpi_cmp(const bigint_t u, const bigint_t v)
+{
+       mpz_t *i1 = u, *i2 = v;
+
+       return mpz_cmp(*i1, *i2);
+}
+
+static int wrap_nettle_mpi_cmp_ui(const bigint_t u, unsigned long v)
+{
+       mpz_t *i1 = u;
+
+       return mpz_cmp_ui(*i1, v);
+}
+
+static bigint_t wrap_nettle_mpi_set(bigint_t w, const bigint_t u)
+{
+       mpz_t *i1, *i2 = u;
+
+       if (w == NULL)
+               w = _gnutls_mpi_alloc_like(u);
+       i1 = w;
+
+       mpz_set(*i1, *i2);
+       
+       return i1;
+}
+
+static bigint_t wrap_nettle_mpi_set_ui(bigint_t w, unsigned long u)
+{
+       mpz_t *i1;
+
+       if (w == NULL)
+               w = wrap_nettle_mpi_new(32);
+
+       i1 = w;
+
+       mpz_set_ui(*i1, u);
+       
+       return i1;
+}
+
+static unsigned int wrap_nettle_mpi_get_nbits(bigint_t a)
+{
+       return mpz_sizeinbase(*((mpz_t *) a), 2);
+}
+
+static void wrap_nettle_mpi_release(bigint_t a)
+{
+       mpz_clear(*((mpz_t *) a));
+       gnutls_free(a);
+}
+
+static bigint_t wrap_nettle_mpi_mod(const bigint_t a, const bigint_t b)
+{
+       bigint_t r = wrap_nettle_mpi_new(wrap_nettle_mpi_get_nbits(b));
+
+       if (r == NULL)
+               return NULL;
+
+       mpz_mod(*((mpz_t *) r), *((mpz_t *) a), *((mpz_t *) b));
+
+       return r;
+}
+
+static bigint_t
+wrap_nettle_mpi_powm(bigint_t w, const bigint_t b, const bigint_t e,
+                  const bigint_t m)
+{
+       if (w == NULL)
+               w = wrap_nettle_mpi_new(wrap_nettle_mpi_get_nbits(m));
+
+       if (w == NULL)
+               return NULL;
+
+       mpz_powm(*((mpz_t *) w), *((mpz_t *) b), *((mpz_t *) e),
+                *((mpz_t *) m));
+
+       return w;
+}
+
+static bigint_t
+wrap_nettle_mpi_addm(bigint_t w, const bigint_t a, const bigint_t b,
+                  const bigint_t m)
+{
+       if (w == NULL)
+               w = wrap_nettle_mpi_new(wrap_nettle_mpi_get_nbits(a));
+
+       if (w == NULL)
+               return NULL;
+
+       mpz_add(*((mpz_t *) w), *((mpz_t *) b), *((mpz_t *) a));
+       mpz_fdiv_r(*((mpz_t *) w), *((mpz_t *) w), *((mpz_t *) m));
+
+       return w;
+}
+
+static bigint_t
+wrap_nettle_mpi_subm(bigint_t w, const bigint_t a, const bigint_t b,
+                  const bigint_t m)
+{
+       if (w == NULL)
+               w = wrap_nettle_mpi_new(wrap_nettle_mpi_get_nbits(a));
+
+       if (w == NULL)
+               return NULL;
+
+       mpz_sub(*((mpz_t *) w), *((mpz_t *) a), *((mpz_t *) b));
+       mpz_fdiv_r(*((mpz_t *) w), *((mpz_t *) w), *((mpz_t *) m));
+
+       return w;
+}
+
+static bigint_t
+wrap_nettle_mpi_mulm(bigint_t w, const bigint_t a, const bigint_t b,
+                  const bigint_t m)
+{
+       if (w == NULL)
+               w = wrap_nettle_mpi_new(wrap_nettle_mpi_get_nbits(m));
+
+       if (w == NULL)
+               return NULL;
+
+       mpz_mul(*((mpz_t *) w), *((mpz_t *) a), *((mpz_t *) b));
+       mpz_fdiv_r(*((mpz_t *) w), *((mpz_t *) w), *((mpz_t *) m));
+
+       return w;
+}
+
+static bigint_t
+wrap_nettle_mpi_add(bigint_t w, const bigint_t a, const bigint_t b)
+{
+       if (w == NULL)
+               w = wrap_nettle_mpi_new(wrap_nettle_mpi_get_nbits(b));
+
+       if (w == NULL)
+               return NULL;
+
+       mpz_add(*((mpz_t *) w), *((mpz_t *) a), *((mpz_t *) b));
+
+       return w;
+}
+
+static bigint_t
+wrap_nettle_mpi_sub(bigint_t w, const bigint_t a, const bigint_t b)
+{
+       if (w == NULL)
+               w = wrap_nettle_mpi_new(wrap_nettle_mpi_get_nbits(a));
+
+       if (w == NULL)
+               return NULL;
+
+       mpz_sub(*((mpz_t *) w), *((mpz_t *) a), *((mpz_t *) b));
+
+       return w;
+}
+
+static bigint_t
+wrap_nettle_mpi_mul(bigint_t w, const bigint_t a, const bigint_t b)
+{
+       if (w == NULL)
+               w = wrap_nettle_mpi_new(wrap_nettle_mpi_get_nbits(a));
+
+       if (w == NULL)
+               return NULL;
+
+       mpz_mul(*((mpz_t *) w), *((mpz_t *) a), *((mpz_t *) b));
+
+       return w;
+}
+
+/* q = a / b */
+static bigint_t
+wrap_nettle_mpi_div(bigint_t q, const bigint_t a, const bigint_t b)
+{
+       if (q == NULL)
+               q = wrap_nettle_mpi_new(wrap_nettle_mpi_get_nbits(a));
+
+       if (q == NULL)
+               return NULL;
+
+       mpz_cdiv_q(*((mpz_t *) q), *((mpz_t *) a), *((mpz_t *) b));
+
+       return q;
+}
+
+static bigint_t
+wrap_nettle_mpi_add_ui(bigint_t w, const bigint_t a, unsigned long b)
+{
+       if (w == NULL)
+               w = wrap_nettle_mpi_new(wrap_nettle_mpi_get_nbits(a));
+
+       if (w == NULL)
+               return NULL;
+
+       mpz_add_ui(*((mpz_t *) w), *((mpz_t *) a), b);
+
+       return w;
+}
+
+static bigint_t
+wrap_nettle_mpi_sub_ui(bigint_t w, const bigint_t a, unsigned long b)
+{
+       if (w == NULL)
+               w = wrap_nettle_mpi_new(wrap_nettle_mpi_get_nbits(a));
+
+       if (w == NULL)
+               return NULL;
+
+       mpz_sub_ui(*((mpz_t *) w), *((mpz_t *) a), b);
+
+       return w;
+
+}
+
+static bigint_t
+wrap_nettle_mpi_mul_ui(bigint_t w, const bigint_t a, unsigned long b)
+{
+       if (w == NULL)
+               w = wrap_nettle_mpi_new(wrap_nettle_mpi_get_nbits(a));
+
+       if (w == NULL)
+               return NULL;
+
+       mpz_mul_ui(*((mpz_t *) w), *((mpz_t *) a), b);
+
+       return w;
+
+}
+
+#define PRIME_CHECK_PARAM 18
+static int wrap_nettle_prime_check(bigint_t pp)
+{
+       int ret;
+       ret = mpz_probab_prime_p(*((mpz_t *) pp), PRIME_CHECK_PARAM);
+
+       if (ret > 0) {
+               return 0;
+       }
+
+       return GNUTLS_E_INTERNAL_ERROR; /* ignored */
+}
+
+
+/* generate a prime of the form p=2qw+1
+ * The algorithm is simple but probably it has to be modified to gcrypt's
+ * since it is really really slow. Nature did not want 2qw+1 to be prime.
+ * The generator will be the generator of a subgroup of order q-1.
+ */
+inline static int gen_group (mpz_t *prime, mpz_t* generator, unsigned int 
nbits)
+{
+       mpz_t q, w;
+       unsigned int p_bytes = nbits/8;
+       opaque *buffer= NULL;
+       unsigned int q_bytes, w_bytes, r_bytes, w_bits;
+       int ret;
+
+       mpz_init(*prime);
+       mpz_init(*generator);
+
+       /* security level enforcement. "Check Fine-tuned implementation of an
+        * efficient secure profile matching protocol", p.61, El-gamal key 
generation.
+        */
+       if (nbits <= 1024) {
+               q_bytes = 160/8;
+       } else if (nbits <=2644) {
+               q_bytes = 256/8;
+       } else if (nbits <= 6897) {
+               q_bytes = 384/8;
+       } else {
+               q_bytes = 512/8;
+       }
+       
+       if (nbits%8 != 0)
+               p_bytes++;
+       
+       _gnutls_debug_log("Generating group of prime of %u bits and format of 
2wq+1. q_size=%u bits\n", nbits, q_bytes*8);
+       buffer = gnutls_malloc(p_bytes); /* p_bytes > q_bytes */
+       if (buffer == NULL) {
+               gnutls_assert();
+               return GNUTLS_E_MEMORY_ERROR;
+       }
+
+       mpz_init2(*prime, nbits);
+       mpz_init(*generator);
+       mpz_init(q);
+       mpz_init(w);
+
+       /* search for a prime. We are not that unlucky so search
+        * forever.
+        */
+       for (;;) {
+               ret = _gnutls_rnd(GNUTLS_RND_RANDOM, buffer, q_bytes);
+               if (ret < 0) {
+                       gnutls_assert();
+                       goto fail;
+               }
+               
+               nettle_mpz_set_str_256_u(q, q_bytes, buffer);
+               /* always odd */
+               mpz_setbit(q, 0);
+               
+               ret = mpz_probab_prime_p(q, PRIME_CHECK_PARAM);
+               if (ret > 0) {
+                       break;
+               }
+       }
+       
+       /* now generate w of size p_bytes - q_bytes */
+
+       w_bits = nbits - wrap_nettle_mpi_get_nbits(&q);
+
+       _gnutls_debug_log("Found prime q of %u bits. Will look for w of %u 
bits...\n", wrap_nettle_mpi_get_nbits(&q), w_bits);
+
+       w_bytes = w_bits/8;
+       if (w_bits % 8 != 0)
+               w_bytes++;
+
+       for (;;) {
+               ret = _gnutls_rnd(GNUTLS_RND_RANDOM, buffer, w_bytes);
+               if (ret < 0) {
+                       gnutls_assert();
+                       return ret;
+               }
+               
+               nettle_mpz_set_str_256_u(w, w_bytes, buffer);
+               /* always odd */
+               mpz_setbit(w, 0);
+               
+               ret = mpz_probab_prime_p(w, PRIME_CHECK_PARAM);
+               if (ret == 0) {
+                       continue;
+               }
+               
+               /* check if 2wq+1 is prime */
+               mpz_mul_ui(*prime, w, 2);
+               mpz_mul(*prime, *prime, q);
+               mpz_add_ui(*prime, *prime, 1);
+
+               ret = mpz_probab_prime_p(*prime, PRIME_CHECK_PARAM);
+               if (ret > 0) {
+                       break;
+               }
+       }
+       
+       _gnutls_debug_log("Found prime w of %u bits. Looking for 
generator...\n", wrap_nettle_mpi_get_nbits(&w));
+
+       /* finally a prime! Let calculate generator
+        */
+       
+       /* c = r^((p-1)/q), r == random
+        * c = r^(2w)
+        * if c!=1 c is the generator for the subgroup of order q-1
+        * 
+        * (here we reuse q as r)
+        */
+       r_bytes = p_bytes;
+
+       mpz_mul_ui(w, w, 2); /* w = w*2 */
+       mpz_fdiv_r(w, w, *prime);
+
+       for (;;) {
+               ret = _gnutls_rnd(GNUTLS_RND_RANDOM, buffer, r_bytes);
+               if (ret < 0) {
+                       gnutls_assert();
+                       return ret;
+               }
+               
+               nettle_mpz_set_str_256_u(q, r_bytes, buffer);
+               mpz_fdiv_r(q, q, *prime);
+
+               /* check if r^w mod n != 1 mod n */
+               mpz_powm(*generator, q, w, *prime);
+               
+               if (mpz_cmp_ui(*generator,1)==0)
+                       continue;
+               else break;
+       }
+       
+       _gnutls_debug_log("Found generator g of %u bits\n", 
wrap_nettle_mpi_get_nbits(generator));
+       _gnutls_debug_log("Prime n is of %u bits\n", 
wrap_nettle_mpi_get_nbits(prime));
+
+       mpz_clear(q);
+       mpz_clear(w);
+       gnutls_free(buffer);
+       
+       return 0;
+
+fail:
+       mpz_clear(q);
+       mpz_clear(w);
+       mpz_clear(*prime);
+       mpz_clear(*generator);
+       gnutls_free(buffer);
+       
+       return ret;
+}
+
+static int
+wrap_nettle_generate_group(gnutls_group_st * group, unsigned int bits)
+{
+int ret;
+bigint_t p = wrap_nettle_mpi_new(bits);
+bigint_t g;
+
+       if (p == NULL) {
+               gnutls_assert();
+               return GNUTLS_E_MEMORY_ERROR;
+       }
+
+       g = wrap_nettle_mpi_new(bits);
+       if (g == NULL) {
+               gnutls_assert();
+               _gnutls_mpi_release(&p);
+               return GNUTLS_E_MEMORY_ERROR;
+       }
+       
+       ret = gen_group(p, g, bits);
+       if (ret < 0) {
+               _gnutls_mpi_release(&g);
+               _gnutls_mpi_release(&p);
+               gnutls_assert();
+               return ret;
+       }
+       
+       group->p = p;
+       group->g = g;
+       
+       return 0;
+}
+
+
+int crypto_bigint_prio = INT_MAX;
+
+gnutls_crypto_bigint_st _gnutls_mpi_ops = {
+       .bigint_new = wrap_nettle_mpi_new,
+       .bigint_cmp = wrap_nettle_mpi_cmp,
+       .bigint_cmp_ui = wrap_nettle_mpi_cmp_ui,
+       .bigint_mod = wrap_nettle_mpi_mod,
+       .bigint_set = wrap_nettle_mpi_set,
+       .bigint_set_ui = wrap_nettle_mpi_set_ui,
+       .bigint_get_nbits = wrap_nettle_mpi_get_nbits,
+       .bigint_powm = wrap_nettle_mpi_powm,
+       .bigint_addm = wrap_nettle_mpi_addm,
+       .bigint_subm = wrap_nettle_mpi_subm,
+       .bigint_add = wrap_nettle_mpi_add,
+       .bigint_sub = wrap_nettle_mpi_sub,
+       .bigint_add_ui = wrap_nettle_mpi_add_ui,
+       .bigint_sub_ui = wrap_nettle_mpi_sub_ui,
+       .bigint_mul = wrap_nettle_mpi_mul,
+       .bigint_mulm = wrap_nettle_mpi_mulm,
+       .bigint_mul_ui = wrap_nettle_mpi_mul_ui,
+       .bigint_div = wrap_nettle_mpi_div,
+       .bigint_prime_check = wrap_nettle_prime_check,
+       .bigint_release = wrap_nettle_mpi_release,
+       .bigint_print = wrap_nettle_mpi_print,
+       .bigint_scan = wrap_nettle_mpi_scan,
+       .bigint_generate_group = wrap_nettle_generate_group
+};
diff --git a/lib/nettle/pk.c b/lib/nettle/pk.c
new file mode 100644
index 0000000..b264afd
--- /dev/null
+++ b/lib/nettle/pk.c
@@ -0,0 +1,546 @@
+/*
+ * Copyright (C) 2010
+ * Free Software Foundation, Inc.
+ *
+ * Author: Nikos Mavrogiannopoulos
+ *
+ * This file is part of GNUTLS.
+ *
+ * The GNUTLS library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+ * USA
+ *
+ */
+
+/* This file contains the functions needed for RSA/DSA public key
+ * encryption and signatures. 
+ */
+
+#include <gnutls_int.h>
+#include <gnutls_mpi.h>
+#include <gnutls_pk.h>
+#include <gnutls_errors.h>
+#include <gnutls_datum.h>
+#include <gnutls_global.h>
+#include <gnutls_num.h>
+#include <x509/x509_int.h>
+#include <x509/common.h>
+#include <random.h>
+#include <gnutls_pk.h>
+#include <nettle/dsa.h>
+#include <nettle/rsa.h>
+#include <random.h>
+#include <gnutls/crypto.h>
+
+#define TOMPZ(x) (*((mpz_t*)(x)))
+
+static void rnd_func(void *_ctx, unsigned length, uint8_t * data)
+{
+       _gnutls_rnd(GNUTLS_RND_RANDOM, data, length);
+}
+
+static void _dsa_params_to_pubkey(const gnutls_pk_params_st * pk_params, 
struct dsa_public_key *pub)
+{
+       memcpy(&pub->p, pk_params->params[0], sizeof(mpz_t));
+       memcpy(&pub->q, pk_params->params[1], sizeof(mpz_t));
+       memcpy(&pub->g, pk_params->params[2], sizeof(mpz_t));
+       memcpy(&pub->y, pk_params->params[3], sizeof(mpz_t));
+}
+
+static void _dsa_params_to_privkey(const gnutls_pk_params_st * pk_params, 
struct  dsa_private_key *pub)
+{
+       memcpy(&pub->x, pk_params->params[4], sizeof(mpz_t));
+}
+
+static void _rsa_params_to_privkey(const gnutls_pk_params_st * pk_params, 
struct rsa_private_key *priv)
+{
+       memcpy(&priv->d, pk_params->params[2], sizeof(mpz_t));
+       memcpy(&priv->p, pk_params->params[3], sizeof(mpz_t));
+       memcpy(&priv->q, pk_params->params[4], sizeof(mpz_t));
+       memcpy(&priv->c, pk_params->params[5], sizeof(mpz_t));
+       memcpy(&priv->a, pk_params->params[6], sizeof(mpz_t));
+       memcpy(&priv->b, pk_params->params[7], sizeof(mpz_t));
+
+}
+
+static int
+_wrap_nettle_pk_encrypt(gnutls_pk_algorithm_t algo,
+                       gnutls_datum_t * ciphertext,
+                       const gnutls_datum_t * plaintext,
+                       const gnutls_pk_params_st * pk_params)
+{
+       int ret;
+
+       /* make a sexp from pkey */
+       switch (algo) {
+       case GNUTLS_PK_RSA: {
+               bigint_t p;
+               
+               if (_gnutls_mpi_scan_nz(&p, plaintext->data, plaintext->size) 
!= 0) {
+                       gnutls_assert();
+                       return GNUTLS_E_MPI_SCAN_FAILED;
+               }
+
+               mpz_powm(p, p, TOMPZ(pk_params->params[1])/*e*/, 
TOMPZ(pk_params->params[0]/*m*/));
+
+               ret = _gnutls_mpi_dprint_size(p, ciphertext, plaintext->size);
+               _gnutls_mpi_release(&p);
+
+               if (ret < 0) {
+                       gnutls_assert();
+                       goto cleanup;
+               }
+
+               break;
+       }
+       default:
+               gnutls_assert();
+               ret = GNUTLS_E_INTERNAL_ERROR;
+               goto cleanup;
+       }
+
+       ret = 0;
+
+cleanup:
+
+       return ret;
+}
+
+/* returns the blinded c and the inverse of a random
+ * number r;
+ */
+static bigint_t rsa_blind(bigint_t c, bigint_t e, bigint_t n, bigint_t *_ri)
+{
+bigint_t nc = NULL, r = NULL, ri = NULL;
+
+       /* nc = c*(r^e)
+        * ri = r^(-1)
+        */
+       nc = _gnutls_mpi_alloc_like(n);
+       if (nc == NULL) {
+               gnutls_assert();
+               return NULL;
+       }
+
+       ri = _gnutls_mpi_alloc_like(n);
+       if (nc == NULL) {
+               gnutls_assert();
+               goto fail;
+       }
+
+       r = _gnutls_mpi_randomize (NULL, _gnutls_mpi_get_nbits(n),
+               GNUTLS_RND_NONCE);
+       if (r == NULL) {
+               gnutls_assert();
+               goto fail;
+       }
+
+       /* invert r */
+       if (mpz_invert(ri, r, n)==0) {
+               gnutls_assert();
+               goto fail;
+       }
+
+       /* r = r^e */
+
+       _gnutls_mpi_powm(r, r, e, n);
+
+       _gnutls_mpi_mulm(nc, c, r, n);
+
+       *_ri = ri;
+
+       _gnutls_mpi_release(&r);
+
+       return nc;
+fail:
+       _gnutls_mpi_release(&nc);
+       _gnutls_mpi_release(&r);
+       return NULL;
+}
+
+/* c = c*ri mod n
+ */
+static inline void rsa_unblind(bigint_t c, bigint_t ri, bigint_t n)
+{
+       _gnutls_mpi_mulm(c, c, ri, n);
+}
+
+static int
+_wrap_nettle_pk_decrypt(gnutls_pk_algorithm_t algo,
+                       gnutls_datum_t * plaintext,
+                       const gnutls_datum_t * ciphertext,
+                       const gnutls_pk_params_st * pk_params)
+{
+       int ret;
+
+       /* make a sexp from pkey */
+       switch (algo) {
+       case GNUTLS_PK_RSA: {
+               struct rsa_private_key priv;
+               bigint_t c, ri, nc;
+               
+               if (_gnutls_mpi_scan_nz(&c, ciphertext->data, ciphertext->size) 
!= 0) {
+                       gnutls_assert();
+                       return GNUTLS_E_MPI_SCAN_FAILED;
+               }
+
+               nc = rsa_blind(c, pk_params->params[1]/*e*/,
+                       pk_params->params[0]/*m*/, &ri);
+               _gnutls_mpi_release(&c);
+               if (nc == NULL) {
+                       gnutls_assert();
+                       return GNUTLS_E_MEMORY_ERROR;
+               }
+
+               rsa_private_key_init(&priv);
+               _rsa_params_to_privkey(pk_params, &priv);
+
+               rsa_compute_root(&priv, TOMPZ(nc), TOMPZ(nc));
+
+               rsa_unblind(nc, ri, pk_params->params[0]/*m*/);
+
+               ret = _gnutls_mpi_dprint_size(nc, plaintext, ciphertext->size);
+
+               _gnutls_mpi_release(&nc);
+               _gnutls_mpi_release(&ri);
+
+               if (ret < 0) {
+                       gnutls_assert();
+                       goto cleanup;
+               }
+
+               break;
+       }
+       default:
+               gnutls_assert();
+               ret = GNUTLS_E_INTERNAL_ERROR;
+               goto cleanup;
+       }
+
+       ret = 0;
+
+cleanup:
+
+       return ret;
+}
+
+/* in case of DSA puts into data, r,s
+ */
+static int
+_wrap_nettle_pk_sign(gnutls_pk_algorithm_t algo,
+                    gnutls_datum_t * signature,
+                    const gnutls_datum_t * vdata,
+                    const gnutls_pk_params_st * pk_params)
+{
+       int ret;
+
+       switch (algo) {
+
+       case GNUTLS_PK_DSA: {
+               struct dsa_public_key pub;
+               struct dsa_private_key priv;
+               struct dsa_signature sig;
+                               
+               dsa_public_key_init(&pub);
+               dsa_private_key_init(&priv);
+               _dsa_params_to_pubkey(pk_params, &pub);
+               _dsa_params_to_privkey(pk_params, &priv);
+
+               dsa_signature_init(&sig);
+
+               dsa_sign_digest(&pub, &priv, NULL, rnd_func, vdata->data, &sig);
+
+               ret =
+                       _gnutls_encode_ber_rs(signature, &sig.r,
+                                         &sig.s);
+                                         
+               dsa_signature_clear(&sig);
+
+               if (ret < 0) {
+                       gnutls_assert();
+                       goto cleanup;
+               }
+               break;
+       }
+       case GNUTLS_PK_RSA: {
+               struct rsa_private_key priv;
+               bigint_t hash;
+               
+               if (_gnutls_mpi_scan_nz(&hash, vdata->data, vdata->size) != 0) {
+                       gnutls_assert();
+                       return GNUTLS_E_MPI_SCAN_FAILED;
+               }
+
+               rsa_private_key_init(&priv);
+               _rsa_params_to_privkey(pk_params, &priv);
+
+               rsa_compute_root(&priv, TOMPZ(hash), TOMPZ(hash));
+
+               ret = _gnutls_mpi_dprint(hash, signature);
+               _gnutls_mpi_release(&hash);
+
+               if (ret < 0) {
+                       gnutls_assert();
+                       goto cleanup;
+               }
+
+               break;
+       }
+       default:
+               gnutls_assert();
+               ret = GNUTLS_E_INTERNAL_ERROR;
+               goto cleanup;
+       }
+
+       ret = 0;
+
+cleanup:
+
+       return ret;
+}
+
+static int
+_int_rsa_verify(const gnutls_pk_params_st * pk_params,
+            bigint_t m,
+            bigint_t s)
+{
+  int res;
+
+  mpz_t m1;
+
+  if ( (mpz_sgn(TOMPZ(s)) <= 0)
+       || (mpz_cmp(TOMPZ(s), TOMPZ(pk_params->params[0])) >= 0) )
+    return GNUTLS_E_PK_SIG_VERIFY_FAILED;
+
+  mpz_init(m1);
+
+  mpz_powm(m1, TOMPZ(s), TOMPZ(pk_params->params[1]), 
TOMPZ(pk_params->params[0]));
+
+  res = !mpz_cmp(TOMPZ(m), m1);
+
+  mpz_clear(m1);
+
+  if (res == 0)
+       res = GNUTLS_E_PK_SIG_VERIFY_FAILED;
+  else res = 0;
+  
+  return res;
+}
+
+static int
+_wrap_nettle_pk_verify(gnutls_pk_algorithm_t algo,
+                      const gnutls_datum_t * vdata,
+                      const gnutls_datum_t * signature,
+                      const gnutls_pk_params_st * pk_params)
+{
+       int ret;
+       bigint_t tmp[2] = { NULL, NULL };
+
+       switch (algo) {
+       case GNUTLS_PK_DSA: {
+               struct dsa_public_key pub;
+               struct dsa_signature sig;
+                               
+               ret = _gnutls_decode_ber_rs(signature, &tmp[0], &tmp[1]);
+               if (ret < 0) {
+                       gnutls_assert();
+                       goto cleanup;
+               }
+               dsa_public_key_init(&pub);
+               _dsa_params_to_pubkey(pk_params, &pub);
+               memcpy(&sig.r, tmp[0], sizeof(sig.r));
+               memcpy(&sig.s, tmp[1], sizeof(sig.s));
+
+               ret = dsa_verify_digest(&pub, vdata->data, &sig);
+               if (ret == 0)
+                       ret = GNUTLS_E_PK_SIG_VERIFY_FAILED;
+               else
+                       ret = 0;
+
+               _gnutls_mpi_release(&tmp[0]);
+               _gnutls_mpi_release(&tmp[1]);
+               break;
+       }
+       case GNUTLS_PK_RSA: {
+               bigint_t hash;
+               
+               if (_gnutls_mpi_scan_nz(&hash, vdata->data, vdata->size) != 0) {
+                       gnutls_assert();
+                       return GNUTLS_E_MPI_SCAN_FAILED;
+               }
+
+               ret =
+                   _gnutls_mpi_scan_nz(&tmp[0], signature->data,
+                                       signature->size);
+               if (ret < 0) {
+                       gnutls_assert();
+                       goto cleanup;
+               }
+
+               ret = _int_rsa_verify(pk_params, hash, tmp[0]);
+               _gnutls_mpi_release(&tmp[0]);
+               _gnutls_mpi_release(&hash);
+               break;
+       }
+       default:
+               gnutls_assert();
+               ret = GNUTLS_E_INTERNAL_ERROR;
+               goto cleanup;
+       }
+
+cleanup:
+
+       return ret;
+}
+
+static int
+wrap_nettle_pk_generate_params(gnutls_pk_algorithm_t algo,
+                              unsigned int level /*bits */ ,
+                              gnutls_pk_params_st * params)
+{
+int ret, i;
+
+       switch (algo) {
+
+       case GNUTLS_PK_DSA: {
+               struct dsa_public_key pub;
+               struct dsa_private_key priv;
+       
+               dsa_public_key_init(&pub);
+               dsa_private_key_init(&priv);
+
+               ret = dsa_generate_keypair (&pub, &priv, NULL, rnd_func, NULL, 
NULL, level);
+               if (ret != 1) {
+                       gnutls_assert();
+                       return GNUTLS_E_INTERNAL_ERROR;
+               }
+               
+               params->params_nr = 0;
+               for (i=0;i<DSA_PRIVATE_PARAMS;i++) {
+                       params->params[i] = _gnutls_mpi_alloc_like(&pub.p);
+                       if (params->params[i] == NULL) {
+                               ret = GNUTLS_E_MEMORY_ERROR;
+                               dsa_private_key_clear(&priv);
+                               dsa_public_key_clear(&pub);
+                               goto fail;
+                       }
+                       params->params_nr++;
+               }
+               _gnutls_mpi_set(params->params[0], pub.p);
+               _gnutls_mpi_set(params->params[1], pub.q);
+               _gnutls_mpi_set(params->params[2], pub.g);
+               _gnutls_mpi_set(params->params[3], pub.y);
+               _gnutls_mpi_set(params->params[4], priv.x);
+
+               dsa_private_key_clear(&priv);
+               dsa_public_key_clear(&pub);
+  
+               break;
+       }
+       case GNUTLS_PK_RSA: {
+               struct rsa_public_key pub;
+               struct rsa_private_key priv;
+       
+               rsa_public_key_init(&pub);
+               rsa_private_key_init(&priv);
+
+               ret = rsa_generate_keypair (&pub, &priv, NULL, rnd_func, NULL, 
NULL, level, 64);
+               if (ret != 1) {
+                       gnutls_assert();
+                       return GNUTLS_E_INTERNAL_ERROR;
+               }
+               
+               params->params_nr = 0;
+               for (i=0;i<RSA_PRIVATE_PARAMS;i++) {
+                       params->params[i] = _gnutls_mpi_alloc_like(&pub.n);
+                       if (params->params[i] == NULL) {
+                               ret = GNUTLS_E_MEMORY_ERROR;
+                               rsa_private_key_clear(&priv);
+                               rsa_public_key_clear(&pub);
+                               goto fail;
+                       }
+                       params->params_nr++;
+                       
+               }
+               _gnutls_mpi_set(params->params[0], pub.n);
+               _gnutls_mpi_set(params->params[1], pub.e);
+               _gnutls_mpi_set(params->params[2], priv.d);
+               _gnutls_mpi_set(params->params[3], priv.p);
+               _gnutls_mpi_set(params->params[4], priv.q);
+               _gnutls_mpi_set(params->params[5], priv.c);
+               _gnutls_mpi_set(params->params[6], priv.a);
+               _gnutls_mpi_set(params->params[7], priv.b);
+               rsa_private_key_clear(&priv);
+               rsa_public_key_clear(&pub);
+               
+               break;
+       }
+       default:
+               gnutls_assert();
+               return GNUTLS_E_INVALID_REQUEST;
+       }
+       
+       return 0;
+
+fail:
+
+       for (i=0;i<params->params_nr;i++) {
+               _gnutls_mpi_release(&params->params[i]);
+       }
+       params->params_nr=0;
+       
+       return ret;
+}
+
+
+static int
+wrap_nettle_pk_fixup(gnutls_pk_algorithm_t algo,
+                    gnutls_direction_t direction,
+                    gnutls_pk_params_st * params)
+{
+int result;
+
+       if (direction == GNUTLS_IMPORT) {
+               /* do not trust the generated values. Some old private keys
+                * generated by us have mess on the values. Those were very
+                * old but it seemed some of the shipped example private
+                * keys were as old.
+                */
+               mpz_invert(TOMPZ(params->params[5]), TOMPZ(params->params[4]), 
TOMPZ(params->params[3]));
+
+        /* calculate exp1 [6] and exp2 [7] */
+               _gnutls_mpi_release(&params->params[6]);
+               _gnutls_mpi_release(&params->params[7]);
+
+        result = _gnutls_calc_rsa_exp(params->params, RSA_PRIVATE_PARAMS-2);
+        if (result < 0) {
+            gnutls_assert();
+            return result;
+               }
+               params->params_nr = RSA_PRIVATE_PARAMS;
+       }
+
+       return 0;
+}
+
+int crypto_pk_prio = INT_MAX;
+
+gnutls_crypto_pk_st _gnutls_pk_ops = {
+       .encrypt = _wrap_nettle_pk_encrypt,
+       .decrypt = _wrap_nettle_pk_decrypt,
+       .sign = _wrap_nettle_pk_sign,
+       .verify = _wrap_nettle_pk_verify,
+       .generate = wrap_nettle_pk_generate_params,
+       .pk_fixup_private_params = wrap_nettle_pk_fixup,
+};
diff --git a/lib/nettle/rnd.c b/lib/nettle/rnd.c
new file mode 100644
index 0000000..0a1066f
--- /dev/null
+++ b/lib/nettle/rnd.c
@@ -0,0 +1,210 @@
+/*
+ * Copyright (C) 2008, 2010 Free Software Foundation, Inc.
+ *
+ * Author: Nikos Mavrogiannopoulos
+ *
+ * This file is part of GNUTLS.
+ *
+ * The GNUTLS library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+ * USA
+ *
+ */
+
+/* Here is the libgcrypt random generator layer.
+ */
+
+#include <gnutls_int.h>
+#include <gnutls_errors.h>
+#include <gnutls_num.h>
+#include <nettle/yarrow.h>
+#include <time.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <fcntl.h>
+
+#include <pthread.h>
+
+#define SOURCES 2
+
+static pthread_mutex_t rnd_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+#define RND_LOCK_INIT
+#define RND_LOCK if (pthread_mutex_lock(&rnd_mutex)!=0) abort()
+#define RND_UNLOCK if (pthread_mutex_unlock(&rnd_mutex)!=0) abort()
+
+enum {
+       RANDOM_SOURCE_TRIVIA=0,
+       RANDOM_SOURCE_DEVICE,
+};
+
+static struct yarrow256_ctx yctx;
+static struct yarrow_source ysources[SOURCES];
+static time_t device_last_read = 0;
+static int device_fd;
+
+static time_t trivia_previous_time = 0;
+static time_t trivia_time_count = 0;
+
+static int do_trivia_source(int init)
+{
+    struct {
+               struct timeval now;
+#ifdef HAVE_GETRUSAGE
+               struct rusage rusage;
+#endif
+               unsigned count;
+               pid_t pid;
+    } event;
+
+    unsigned entropy = 0;
+
+    if (gettimeofday(&event.now, NULL) < 0) {
+               _gnutls_debug_log("gettimeofday failed: %s\n", strerror(errno));
+               abort();
+       }
+#ifdef HAVE_GETRUSAGE
+    if (getrusage(RUSAGE_SELF, &event.rusage) < 0) {
+               _gnutls_debug_log("getrusage failed: %s\n", strerror(errno));
+               abort();
+       }
+#endif
+
+    event.count = 0;
+    if (init) {
+               trivia_time_count = 0;
+    } else {
+               event.count = trivia_time_count++;
+
+               if (event.now.tv_sec != trivia_previous_time) {
+                       /* Count one bit of entropy if we either have more than 
two
+                        * invocations in one second, or more than two seconds
+                        * between invocations. */
+                       if ((trivia_time_count > 2)
+                       || ((event.now.tv_sec - trivia_previous_time) > 2))
+                               entropy++;
+
+                       trivia_time_count = 0;
+               }
+    }
+    trivia_previous_time = event.now.tv_sec;
+    event.pid = getpid();
+
+    return yarrow256_update(&yctx, RANDOM_SOURCE_TRIVIA, entropy,
+                           sizeof(event), (const uint8_t *) &event);
+}
+
+#define DEVICE_READ_SIZE 16
+#define DEVICE_READ_SIZE_MAX 32
+#define DEVICE_READ_INTERVAL 360
+static int do_device_source(int init)
+{
+    time_t now = time(NULL);
+       int read_size = DEVICE_READ_SIZE;
+
+    if (init) {
+               int old;
+               
+               device_fd = open("/dev/urandom", O_RDONLY);
+               if (device_fd < 0) {
+                       _gnutls_debug_log("Cannot open urandom!\n");
+                       abort();
+               }
+
+               old = fcntl(device_fd, F_GETFD);
+               fcntl(device_fd, F_SETFD, old | 1);
+               device_last_read = now;
+               
+               read_size = DEVICE_READ_SIZE_MAX; /* initially read more data */
+    }
+
+    if ((device_fd > 0)
+               && (init || ((now - device_last_read) > DEVICE_READ_INTERVAL))) 
{
+
+               /* More than a minute since we last read the device */
+               uint8_t buf[DEVICE_READ_SIZE_MAX];
+               uint32_t done;
+
+               for (done = 0; done < read_size;) {
+                       int res;
+                       do
+                       res =
+                               read(device_fd, buf + done, sizeof(buf) - done);
+                       while (res < 0 && errno == EINTR);
+
+                       if (res <= 0) {
+                               if (res < 0) {
+                                       _gnutls_debug_log("Failed to read 
/dev/urandom: %s\n",
+                                                         strerror(errno));
+                               } else {
+                                       _gnutls_debug_log
+                                       ("Failed to read /dev/urandom: end of 
file\n");
+                               }
+
+                               return 0;
+                       }
+
+                       done += res;
+               }
+
+               device_last_read = now;
+               return yarrow256_update(&yctx, RANDOM_SOURCE_DEVICE, 
read_size*8/3 /* be more conservative */,
+                                       read_size, buf);
+    }
+    return 0;
+}
+
+static void wrap_nettle_rnd_deinit(void* ctx)
+{
+       RND_LOCK;
+       close(device_fd);
+       RND_UNLOCK;
+}
+
+static int wrap_nettle_rnd_init(void **ctx)
+{
+       RND_LOCK_INIT;
+       
+    yarrow256_init(&yctx, SOURCES, ysources);
+       do_device_source(1);
+       do_trivia_source(1);
+
+       yarrow256_slow_reseed(&yctx);
+
+    return 0;
+}
+
+
+
+static int
+wrap_nettle_rnd(void *_ctx, int level, void *data, size_t datasize)
+{
+       RND_LOCK;
+       do_trivia_source( 0);
+       do_device_source( 0);
+
+    yarrow256_random(&yctx, datasize, data);
+       RND_UNLOCK;
+       return 0;
+}
+
+int crypto_rnd_prio = INT_MAX;
+
+gnutls_crypto_rnd_st _gnutls_rnd_ops = {
+    .init = wrap_nettle_rnd_init,
+    .deinit = wrap_nettle_rnd_deinit,
+    .rnd = wrap_nettle_rnd,
+};
diff --git a/lib/opencdk/armor.c b/lib/opencdk/armor.c
index ad8c165..07d24b9 100644
--- a/lib/opencdk/armor.c
+++ b/lib/opencdk/armor.c
@@ -283,7 +283,7 @@ compress_get_algo (cdk_stream_t inp, int *r_zipalgo)
          pkttype = *plain & 0x40 ? (*plain & 0x3f) : ((*plain >> 2) & 0xf);
          if (pkttype == CDK_PKT_COMPRESSED && r_zipalgo)
            {
-             _cdk_log_debug ("armor compressed (algo=%d)\n", *(plain + 1));
+             _gnutls_buffers_log ("armor compressed (algo=%d)\n", *(plain + 
1));
              *r_zipalgo = *(plain + 1);
            }
          break;
@@ -380,7 +380,7 @@ armor_encode (void *data, FILE * in, FILE * out)
       return CDK_Inv_Value;
     }
 
-  _cdk_log_debug ("armor filter: encode\n");
+  _gnutls_buffers_log ("armor filter: encode\n");
 
   memset (crcbuf, 0, sizeof (crcbuf));
 
@@ -499,7 +499,7 @@ armor_decode (void *data, FILE * in, FILE * out)
       return CDK_Inv_Value;
     }
 
-  _cdk_log_debug ("armor filter: decode\n");
+  _gnutls_buffers_log ("armor filter: decode\n");
 
   fseek (in, 0, SEEK_SET);
   /* Search the begin of the message */
@@ -596,7 +596,7 @@ armor_decode (void *data, FILE * in, FILE * out)
   afx->crc_okay = (afx->crc == crc2) ? 1 : 0;
   if (!afx->crc_okay && !rc)
     {
-      _cdk_log_debug ("file crc=%08X afx_crc=%08X\n", (unsigned int) crc2,
+      _gnutls_buffers_log ("file crc=%08X afx_crc=%08X\n", (unsigned int) crc2,
                      (unsigned int) afx->crc);
       rc = CDK_Armor_CRC_Error;
     }
@@ -724,7 +724,7 @@ _cdk_filter_armor (void *data, int ctl, FILE * in, FILE * 
out)
       armor_filter_t *afx = data;
       if (afx)
        {
-         _cdk_log_debug ("free armor filter\n");
+         _gnutls_buffers_log ("free armor filter\n");
          afx->idx = afx->idx2 = 0;
          afx->crc = afx->crc_okay = 0;
          return 0;
diff --git a/lib/opencdk/pubkey.c b/lib/opencdk/pubkey.c
index d9f66f2..99779e4 100644
--- a/lib/opencdk/pubkey.c
+++ b/lib/opencdk/pubkey.c
@@ -193,7 +193,7 @@ cdk_pk_get_nskey (int algo)
   int ret;
 
   if (is_RSA (algo))
-    ret = RSA_PRIVATE_PARAMS;
+    ret = RSA_PRIVATE_PARAMS-2; /* we don't have exp1 and exp2 */
   else if (is_DSA (algo))
     ret = DSA_PRIVATE_PARAMS;
   else if (is_ELG (algo))
@@ -437,7 +437,10 @@ cdk_pk_get_fingerprint (cdk_pubkey_t pk, byte * fpr)
   dlen = _gnutls_hash_get_algo_len (md_algo);
   err = _gnutls_hash_init (&hd, md_algo);
   if (err < 0)
-    return map_gnutls_error (err);
+    {
+      gnutls_assert();
+      return map_gnutls_error (err);
+    }
   _cdk_hash_pubkey (pk, &hd, 1);
   _gnutls_hash_deinit (&hd, fpr);
   if (dlen == 16)
diff --git a/lib/opencdk/read-packet.c b/lib/opencdk/read-packet.c
index c957a73..21067c1 100644
--- a/lib/opencdk/read-packet.c
+++ b/lib/opencdk/read-packet.c
@@ -129,14 +129,14 @@ read_mpi (cdk_stream_t inp, bigint_t * ret_m, int secure)
 
   if (nbits > MAX_MPI_BITS || nbits == 0)
     {
-      _cdk_log_debug ("read_mpi: too large %d bits\n", (int) nbits);
+      _gnutls_write_log ("read_mpi: too large %d bits\n", (int) nbits);
       return CDK_MPI_Error;    /* Sanity check */
     }
 
   rc = stream_read (inp, buf + 2, nread, &nread);
   if (!rc && nread != ((nbits + 7) / 8))
     {
-      _cdk_log_debug ("read_mpi: too short %d < %d\n", (int) nread,
+      _gnutls_write_log ("read_mpi: too short %d < %d\n", (int) nread,
                      (int) ((nbits + 7) / 8));
       return CDK_MPI_Error;
     }
@@ -198,7 +198,7 @@ read_pubkey_enc (cdk_stream_t inp, size_t pktlen, 
cdk_pkt_pubkey_enc_t pke)
     return CDK_Inv_Value;
 
   if (DEBUG_PKT)
-    _cdk_log_debug ("read_pubkey_enc: %d octets\n", (int) pktlen);
+    _gnutls_write_log ("read_pubkey_enc: %d octets\n", (int) pktlen);
 
   if (pktlen < 12)
     return CDK_Inv_Packet;
@@ -235,7 +235,7 @@ read_mdc (cdk_stream_t inp, cdk_pkt_mdc_t mdc)
     return CDK_Inv_Value;
 
   if (DEBUG_PKT)
-    _cdk_log_debug ("read_mdc:\n");
+    _gnutls_write_log ("read_mdc:\n");
 
   rc = stream_read (inp, mdc->hash, DIM (mdc->hash), &n);
   if (rc)
@@ -252,7 +252,7 @@ read_compressed (cdk_stream_t inp, size_t pktlen, 
cdk_pkt_compressed_t c)
     return CDK_Inv_Value;
 
   if (DEBUG_PKT)
-    _cdk_log_debug ("read_compressed: %d octets\n", (int) pktlen);
+    _gnutls_write_log ("read_compressed: %d octets\n", (int) pktlen);
 
   c->algorithm = cdk_stream_getc (inp);
   if (c->algorithm > 3)
@@ -279,7 +279,7 @@ read_public_key (cdk_stream_t inp, size_t pktlen, 
cdk_pkt_pubkey_t pk)
     return CDK_Inv_Value;
 
   if (DEBUG_PKT)
-    _cdk_log_debug ("read_public_key: %d octets\n", (int) pktlen);
+    _gnutls_write_log ("read_public_key: %d octets\n", (int) pktlen);
 
   pk->is_invalid = 1;          /* default to detect missing self signatures */
   pk->is_revoked = 0;
@@ -301,7 +301,7 @@ read_public_key (cdk_stream_t inp, size_t pktlen, 
cdk_pkt_pubkey_t pk)
   if (!npkey)
     {
       gnutls_assert ();
-      _cdk_log_debug ("invalid public key algorithm %d\n", pk->pubkey_algo);
+      _gnutls_write_log ("invalid public key algorithm %d\n", pk->pubkey_algo);
       return CDK_Inv_Algo;
     }
   for (i = 0; i < npkey; i++)
@@ -337,7 +337,7 @@ read_secret_key (cdk_stream_t inp, size_t pktlen, 
cdk_pkt_seckey_t sk)
     return CDK_Inv_Value;
 
   if (DEBUG_PKT)
-    _cdk_log_debug ("read_secret_key: %d octets\n", (int) pktlen);
+    _gnutls_write_log ("read_secret_key: %d octets\n", (int) pktlen);
 
   p1 = cdk_stream_tell (inp);
   rc = read_public_key (inp, pktlen, sk->pk);
@@ -484,7 +484,7 @@ read_attribute (cdk_stream_t inp, size_t pktlen, 
cdk_pkt_userid_t attr)
     return CDK_Inv_Value;
 
   if (DEBUG_PKT)
-    _cdk_log_debug ("read_attribute: %d octets\n", (int) pktlen);
+    _gnutls_write_log ("read_attribute: %d octets\n", (int) pktlen);
 
   strcpy (attr->name, "[attribute]");
   attr->len = strlen (attr->name);
@@ -553,7 +553,7 @@ read_user_id (cdk_stream_t inp, size_t pktlen, 
cdk_pkt_userid_t user_id)
     return CDK_Inv_Packet;
 
   if (DEBUG_PKT)
-    _cdk_log_debug ("read_user_id: %lu octets\n", pktlen);
+    _gnutls_write_log ("read_user_id: %lu octets\n", pktlen);
 
   user_id->len = pktlen;
   rc = stream_read (inp, user_id->name, pktlen, &nread);
@@ -578,7 +578,7 @@ read_subpkt (cdk_stream_t inp, cdk_subpkt_t * r_ctx, size_t 
* r_nbytes)
     return CDK_Inv_Value;
 
   if (DEBUG_PKT)
-    _cdk_log_debug ("read_subpkt:\n");
+    _gnutls_write_log ("read_subpkt:\n");
 
   n = 0;
   *r_nbytes = 0;
@@ -608,7 +608,7 @@ read_subpkt (cdk_stream_t inp, cdk_subpkt_t * r_ctx, size_t 
* r_nbytes)
   node->size = size;
   node->type = cdk_stream_getc (inp);
   if (DEBUG_PKT)
-    _cdk_log_debug (" %d octets %d type\n", node->size, node->type);
+    _gnutls_write_log (" %d octets %d type\n", node->size, node->type);
   n++;
   node->size--;
   rc = stream_read (inp, node->d, node->size, &nread);
@@ -631,7 +631,7 @@ read_onepass_sig (cdk_stream_t inp, size_t pktlen, 
cdk_pkt_onepass_sig_t sig)
     return CDK_Inv_Value;
 
   if (DEBUG_PKT)
-    _cdk_log_debug ("read_onepass_sig: %d octets\n", (int) pktlen);
+    _gnutls_write_log ("read_onepass_sig: %d octets\n", (int) pktlen);
 
   if (pktlen != 13)
     return CDK_Inv_Packet;
@@ -730,7 +730,7 @@ read_signature (cdk_stream_t inp, size_t pktlen, 
cdk_pkt_signature_t sig)
     return CDK_Inv_Value;
 
   if (DEBUG_PKT)
-    _cdk_log_debug ("read_signature: %d octets\n", (int) pktlen);
+    _gnutls_write_log ("read_signature: %d octets\n", (int) pktlen);
 
   if (pktlen < 16)
     return CDK_Inv_Packet;
@@ -822,7 +822,7 @@ read_literal (cdk_stream_t inp, size_t pktlen,
     return CDK_Inv_Value;
 
   if (DEBUG_PKT)
-    _cdk_log_debug ("read_literal: %d octets\n", (int) pktlen);
+    _gnutls_write_log ("read_literal: %d octets\n", (int) pktlen);
 
   pt->mode = cdk_stream_getc (inp);
   if (pt->mode != 0x62 && pt->mode != 0x74 && pt->mode != 0x75)
diff --git a/lib/opencdk/sig-check.c b/lib/opencdk/sig-check.c
index 5c7a0d5..003ae5a 100644
--- a/lib/opencdk/sig-check.c
+++ b/lib/opencdk/sig-check.c
@@ -33,7 +33,6 @@
 #include "main.h"
 #include "packet.h"
 
-
 /* Hash all multi precision integers of the key PK with the given
    message digest context MD. */
 static int
@@ -52,8 +51,13 @@ hash_mpibuf (cdk_pubkey_t pk, digest_hd_st * md, int usefpr)
     {
       nbytes = MAX_MPI_BYTES;
       err = _gnutls_mpi_print_pgp (pk->mpi[i], buf, &nbytes);
+
       if (err < 0)
-       return map_gnutls_error (err);
+        {
+          gnutls_assert();
+         return map_gnutls_error (err);
+        }
+
       if (!usefpr || pk->version == 4)
        _gnutls_hash (md, buf, nbytes);
       else                     /* without the prefix. */
diff --git a/lib/opencdk/stream.c b/lib/opencdk/stream.c
index 4dfa8f1..23931a8 100644
--- a/lib/opencdk/stream.c
+++ b/lib/opencdk/stream.c
@@ -84,7 +84,7 @@ _cdk_stream_open_mode (const char *file, const char *mode,
       return CDK_Inv_Value;
     }
 
-  _cdk_log_debug ("open stream `%s'\n", file);
+  _gnutls_read_log ("open stream `%s'\n", file);
   *ret_s = NULL;
   s = cdk_calloc (1, sizeof *s);
   if (!s)
@@ -107,7 +107,7 @@ _cdk_stream_open_mode (const char *file, const char *mode,
       gnutls_assert ();
       return CDK_File_Error;
     }
-  _cdk_log_debug ("open stream fd=%d\n", fileno (s->fp));
+  _gnutls_read_log ("open stream fd=%d\n", fileno (s->fp));
   s->flags.write = 0;
   *ret_s = s;
   return 0;
@@ -177,7 +177,7 @@ cdk_stream_new (const char *file, cdk_stream_t * ret_s)
       return CDK_Inv_Value;
     }
 
-  _cdk_log_debug ("new stream `%s'\n", file ? file : "[temp]");
+  _gnutls_read_log ("new stream `%s'\n", file ? file : "[temp]");
   *ret_s = NULL;
   s = cdk_calloc (1, sizeof *s);
   if (!s)
@@ -206,7 +206,7 @@ cdk_stream_new (const char *file, cdk_stream_t * ret_s)
       gnutls_assert ();
       return CDK_File_Error;
     }
-  _cdk_log_debug ("new stream fd=%d\n", fileno (s->fp));
+  _gnutls_read_log ("new stream fd=%d\n", fileno (s->fp));
   *ret_s = s;
   return 0;
 }
@@ -231,7 +231,7 @@ cdk_stream_create (const char *file, cdk_stream_t * ret_s)
       return CDK_Inv_Value;
     }
 
-  _cdk_log_debug ("create stream `%s'\n", file);
+  _gnutls_read_log ("create stream `%s'\n", file);
   *ret_s = NULL;
   s = cdk_calloc (1, sizeof *s);
   if (!s)
@@ -256,7 +256,7 @@ cdk_stream_create (const char *file, cdk_stream_t * ret_s)
       gnutls_assert ();
       return CDK_File_Error;
     }
-  _cdk_log_debug ("stream create fd=%d\n", fileno (s->fp));
+  _gnutls_read_log ("stream create fd=%d\n", fileno (s->fp));
   *ret_s = s;
   return 0;
 }
@@ -325,7 +325,7 @@ _cdk_stream_fpopen (FILE * fp, unsigned write_mode, 
cdk_stream_t * ret_out)
       return CDK_Out_Of_Core;
     }
 
-  _cdk_log_debug ("stream ref fd=%d\n", fileno (fp));
+  _gnutls_read_log ("stream ref fd=%d\n", fileno (fp));
   s->fp = fp;
   s->fp_ref = 1;
   s->flags.filtrated = 1;
@@ -459,7 +459,7 @@ cdk_stream_close (cdk_stream_t s)
       return CDK_Inv_Value;
     }
 
-  _cdk_log_debug ("close stream ref=%d `%s'\n",
+  _gnutls_read_log ("close stream ref=%d `%s'\n",
                  s->fp_ref, s->fname ? s->fname : "[temp]");
 
   /* In the user callback mode, we call the release cb if possible
@@ -483,7 +483,7 @@ cdk_stream_close (cdk_stream_t s)
     {
       int err;
 
-      _cdk_log_debug ("close stream fd=%d\n", fileno (s->fp));
+      _gnutls_read_log ("close stream fd=%d\n", fileno (s->fp));
       err = fclose (s->fp);
       s->fp = NULL;
       if (err)
@@ -756,7 +756,7 @@ stream_fp_replace (cdk_stream_t s, FILE ** tmp)
 
   assert (s);
 
-  _cdk_log_debug ("replace stream fd=%d with fd=%d\n",
+  _gnutls_read_log ("replace stream fd=%d with fd=%d\n",
                  fileno (s->fp), fileno (*tmp));
   rc = fclose (s->fp);
   if (rc)
@@ -792,7 +792,7 @@ stream_filter_write (cdk_stream_t s)
       if (!f->flags.enabled)
        continue;
       /* if there is no next filter, create the final output file */
-      _cdk_log_debug ("filter [write]: last filter=%d fname=%s\n",
+      _gnutls_read_log ("filter [write]: last filter=%d fname=%s\n",
                      f->next ? 1 : 0, s->fname);
       if (!f->next && s->fname)
        f->tmp = fopen (s->fname, "w+b");
@@ -813,14 +813,14 @@ stream_filter_write (cdk_stream_t s)
            break;
        }
       rc = f->fnct (f->opaque, f->ctl, s->fp, f->tmp);
-      _cdk_log_debug ("filter [write]: type=%d rc=%d\n", f->type, rc);
+      _gnutls_read_log ("filter [write]: type=%d rc=%d\n", f->type, rc);
       if (!rc)
        rc = stream_fp_replace (s, &f->tmp);
       if (!rc)
        rc = cdk_stream_seek (s, 0);
       if (rc)
        {
-         _cdk_log_debug ("filter [close]: fd=%d\n", fileno (f->tmp));
+         _gnutls_read_log ("filter [close]: fd=%d\n", fileno (f->tmp));
          fclose (f->tmp);
          break;
        }
@@ -851,7 +851,7 @@ stream_filter_read (cdk_stream_t s)
        continue;
       if (f->flags.error)
        {
-         _cdk_log_debug ("filter %s [read]: has the error flag; skipped\n",
+         _gnutls_read_log ("filter %s [read]: has the error flag; skipped\n",
                          s->fname ? s->fname : "[temp]");
          continue;
        }
@@ -863,7 +863,7 @@ stream_filter_read (cdk_stream_t s)
          break;
        }
       rc = f->fnct (f->opaque, f->ctl, s->fp, f->tmp);
-      _cdk_log_debug ("filter %s [read]: type=%d rc=%d\n",
+      _gnutls_read_log ("filter %s [read]: type=%d rc=%d\n",
                      s->fname ? s->fname : "[temp]", f->type, rc);
       if (rc)
        {
@@ -1059,7 +1059,7 @@ cdk_stream_write (cdk_stream_t s, const void *buf, size_t 
count)
          s->cache.alloced += (count + STREAM_BUFSIZE);
          memcpy (s->cache.buf, old, s->cache.size);
          cdk_free (old);
-         _cdk_log_debug ("stream: enlarge cache to %d octets\n",
+         _gnutls_read_log ("stream: enlarge cache to %d octets\n",
                          (int) s->cache.alloced);
        }
       memcpy (s->cache.buf + s->cache.size, buf, count);
@@ -1197,7 +1197,7 @@ cdk_stream_set_literal_flag (cdk_stream_t s, 
cdk_lit_format_t mode,
   struct stream_filter_s *f;
   const char *orig_fname;
 
-  _cdk_log_debug ("stream: enable literal mode.\n");
+  _gnutls_read_log ("stream: enable literal mode.\n");
 
   if (!s)
     {
@@ -1349,7 +1349,7 @@ cdk_stream_enable_cache (cdk_stream_t s, int val)
     {
       s->cache.buf = cdk_calloc (1, STREAM_BUFSIZE);
       s->cache.alloced = STREAM_BUFSIZE;
-      _cdk_log_debug ("stream: allocate cache of %d octets\n",
+      _gnutls_read_log ("stream: allocate cache of %d octets\n",
                      STREAM_BUFSIZE);
     }
   return 0;
@@ -1455,7 +1455,7 @@ cdk_stream_mmap_part (cdk_stream_t s, off_t off, size_t 
len,
   /* Memory mapping is not supported on custom I/O objects. */
   if (s->cbs_hd)
     {
-      _cdk_log_debug ("cdk_stream_mmap_part: not supported on callbacks\n");
+      _gnutls_read_log ("cdk_stream_mmap_part: not supported on callbacks\n");
       gnutls_assert ();
       return CDK_Inv_Mode;
     }
@@ -1477,7 +1477,7 @@ cdk_stream_mmap_part (cdk_stream_t s, off_t off, size_t 
len,
     len = cdk_stream_get_length (s);
   if (!len)
     {
-      _cdk_log_debug ("cdk_stream_mmap_part: invalid file size %lu\n", len);
+      _gnutls_read_log ("cdk_stream_mmap_part: invalid file size %lu\n", len);
       gnutls_assert ();
       return s->error;
     }
@@ -1579,7 +1579,7 @@ _cdk_stream_set_blockmode (cdk_stream_t s, size_t nbytes)
 {
   assert (s);
 
-  _cdk_log_debug ("stream: activate block mode with blocksize %d\n",
+  _gnutls_read_log ("stream: activate block mode with blocksize %d\n",
                  (int) nbytes);
   s->blkmode = nbytes;
   return 0;
diff --git a/lib/opencdk/verify.c b/lib/opencdk/verify.c
index ab1638d..7826114 100644
--- a/lib/opencdk/verify.c
+++ b/lib/opencdk/verify.c
@@ -245,6 +245,7 @@ file_verify_clearsign (cdk_ctx_t hd, const char *file, 
const char *output)
   err = _gnutls_hash_init (&md, digest_algo);
   if (err < 0)
     {
+      gnutls_assert();
       rc = map_gnutls_error (err);
       goto leave;
     }
diff --git a/lib/opencdk/write-packet.c b/lib/opencdk/write-packet.c
index 2c8e713..265c40d 100644
--- a/lib/opencdk/write-packet.c
+++ b/lib/opencdk/write-packet.c
@@ -268,7 +268,7 @@ write_pubkey_enc (cdk_stream_t out, cdk_pkt_pubkey_enc_t 
pke, int old_ctb)
     return CDK_Inv_Algo;
 
   if (DEBUG_PKT)
-    _cdk_log_debug ("write_pubkey_enc:\n");
+    _gnutls_write_log ("write_pubkey_enc:\n");
 
   nenc = cdk_pk_get_nenc (pke->pubkey_algo);
   size = 10 + calc_mpisize (pke->mpi, nenc);
@@ -298,7 +298,7 @@ write_mdc (cdk_stream_t out, cdk_pkt_mdc_t mdc)
   assert (out);
 
   if (DEBUG_PKT)
-    _cdk_log_debug ("write_mdc:\n");
+    _gnutls_write_log ("write_mdc:\n");
 
   /* This packet requires a fixed header encoding */
   rc = stream_putc (out, 0xD3);        /* packet ID and 1 byte length */
@@ -374,7 +374,7 @@ write_signature (cdk_stream_t out, cdk_pkt_signature_t sig, 
int old_ctb)
     return CDK_Inv_Packet;
 
   if (DEBUG_PKT)
-    _cdk_log_debug ("write_signature:\n");
+    _gnutls_write_log ("write_signature:\n");
 
   nsig = cdk_pk_get_nsig (sig->pubkey_algo);
   if (!nsig)
@@ -438,7 +438,7 @@ write_public_key (cdk_stream_t out, cdk_pkt_pubkey_t pk,
     return CDK_Inv_Packet;
 
   if (DEBUG_PKT)
-    _cdk_log_debug ("write_public_key: subkey=%d\n", is_subkey);
+    _gnutls_write_log ("write_public_key: subkey=%d\n", is_subkey);
 
   pkttype = is_subkey ? CDK_PKT_PUBLIC_SUBKEY : CDK_PKT_PUBLIC_KEY;
   npkey = cdk_pk_get_npkey (pk->pubkey_algo);
@@ -515,7 +515,7 @@ write_secret_key (cdk_stream_t out, cdk_pkt_seckey_t sk,
     return CDK_Inv_Packet;
 
   if (DEBUG_PKT)
-    _cdk_log_debug ("write_secret_key:\n");
+    _gnutls_write_log ("write_secret_key:\n");
 
   npkey = cdk_pk_get_npkey (pk->pubkey_algo);
   nskey = cdk_pk_get_nskey (pk->pubkey_algo);
@@ -629,7 +629,7 @@ write_compressed (cdk_stream_t out, cdk_pkt_compressed_t cd)
   assert (cd);
 
   if (DEBUG_PKT)
-    _cdk_log_debug ("packet: write_compressed\n");
+    _gnutls_write_log ("packet: write_compressed\n");
 
   /* Use an old (RFC1991) header for this packet. */
   rc = pkt_write_head (out, 1, 0, CDK_PKT_COMPRESSED);
@@ -655,7 +655,7 @@ write_literal (cdk_stream_t out, cdk_pkt_literal_t pt, int 
old_ctb)
     return CDK_Inv_Packet;
 
   if (DEBUG_PKT)
-    _cdk_log_debug ("write_literal:\n");
+    _gnutls_write_log ("write_literal:\n");
 
   size = 6 + pt->namelen + pt->len;
   rc = pkt_write_head (out, old_ctb, size, CDK_PKT_LITERAL);
@@ -700,7 +700,7 @@ write_onepass_sig (cdk_stream_t out, cdk_pkt_onepass_sig_t 
sig)
     return CDK_Inv_Packet;
 
   if (DEBUG_PKT)
-    _cdk_log_debug ("write_onepass_sig:\n");
+    _gnutls_write_log ("write_onepass_sig:\n");
 
   rc = pkt_write_head (out, 0, 13, CDK_PKT_ONEPASS_SIG);
   if (!rc)
@@ -773,7 +773,7 @@ cdk_pkt_write (cdk_stream_t out, cdk_packet_t pkt)
   if (!out || !pkt)
     return CDK_Inv_Value;
 
-  _cdk_log_debug ("write packet pkttype=%d\n", pkt->pkttype);
+  _gnutls_write_log ("write packet pkttype=%d\n", pkt->pkttype);
   switch (pkt->pkttype)
     {
     case CDK_PKT_LITERAL:
@@ -816,7 +816,7 @@ cdk_pkt_write (cdk_stream_t out, cdk_packet_t pkt)
     }
 
   if (DEBUG_PKT)
-    _cdk_log_debug ("write_packet rc=%d pkttype=%d\n", rc, pkt->pkttype);
+    _gnutls_write_log ("write_packet rc=%d pkttype=%d\n", rc, pkt->pkttype);
   return rc;
 }
 
diff --git a/lib/openpgp/gnutls_openpgp.c b/lib/openpgp/gnutls_openpgp.c
index 90246f8..7c1dc01 100644
--- a/lib/openpgp/gnutls_openpgp.c
+++ b/lib/openpgp/gnutls_openpgp.c
@@ -137,57 +137,51 @@ gnutls_certificate_set_openpgp_key 
(gnutls_certificate_credentials_t res,
                                    gnutls_openpgp_privkey_t pkey)
 {
   int ret;
-
+  gnutls_privkey_t privkey;
+  gnutls_cert *ccert;
   /* this should be first */
 
-  res->pkey = gnutls_realloc_fast (res->pkey,
-                                  (res->ncerts + 1) *
-                                  sizeof (gnutls_privkey));
-  if (res->pkey == NULL)
+  ret = gnutls_privkey_init(&privkey);
+  if (ret < 0) 
     {
-      gnutls_assert ();
-      return GNUTLS_E_MEMORY_ERROR;
+      gnutls_assert();
+      return ret;
     }
 
-  ret = _gnutls_openpgp_privkey_to_gkey (&res->pkey[res->ncerts], pkey);
+  ret = gnutls_privkey_import_openpgp (privkey, pkey, 
GNUTLS_PRIVKEY_IMPORT_AUTO_RELEASE);
   if (ret < 0)
     {
+      gnutls_privkey_deinit(privkey);
       gnutls_assert ();
       return ret;
     }
 
-  res->cert_list = gnutls_realloc_fast (res->cert_list,
-                                       (1 +
-                                        res->ncerts) *
-                                       sizeof (gnutls_cert *));
-  if (res->cert_list == NULL)
-    {
-      gnutls_assert ();
-      return GNUTLS_E_MEMORY_ERROR;
-    }
 
-  res->cert_list_length = gnutls_realloc_fast (res->cert_list_length,
-                                              (1 +
-                                               res->ncerts) * sizeof (int));
-  if (res->cert_list_length == NULL)
+  ccert = gnutls_calloc (1, sizeof (gnutls_cert));
+  if (ccert == NULL)
     {
       gnutls_assert ();
+      gnutls_privkey_deinit(privkey);
       return GNUTLS_E_MEMORY_ERROR;
     }
 
-  res->cert_list[res->ncerts] = gnutls_calloc (1, sizeof (gnutls_cert));
-  if (res->cert_list[res->ncerts] == NULL)
+  ret = _gnutls_openpgp_crt_to_gcert (ccert, crt);
+  if (ret < 0)
     {
       gnutls_assert ();
-      return GNUTLS_E_MEMORY_ERROR;
+      gnutls_free(ccert);
+      gnutls_privkey_deinit(privkey);
+      return ret;
     }
 
-  res->cert_list_length[res->ncerts] = 1;
+  ret = certificate_credentials_append_pkey(res, privkey);
+  if (ret >=0) ret = certificate_credential_append_crt_list(res, ccert, 1);
 
-  ret = _gnutls_openpgp_crt_to_gcert (res->cert_list[res->ncerts], crt);
   if (ret < 0)
     {
-      gnutls_assert ();
+      gnutls_assert();
+      gnutls_free(ccert);
+      gnutls_privkey_deinit(privkey);
       return ret;
     }
 
@@ -371,6 +365,7 @@ gnutls_certificate_set_openpgp_key_mem2 
(gnutls_certificate_credentials_t res,
   gnutls_openpgp_privkey_t pkey;
   gnutls_openpgp_crt_t crt;
   int ret;
+  gnutls_openpgp_keyid_t keyid;
 
   ret = gnutls_openpgp_privkey_init (&pkey);
   if (ret < 0)
@@ -406,32 +401,32 @@ gnutls_certificate_set_openpgp_key_mem2 
(gnutls_certificate_credentials_t res,
 
   if (subkey_id != NULL)
     {
-      gnutls_openpgp_keyid_t keyid;
-
       if (strcasecmp (subkey_id, "auto") == 0)
-       ret = gnutls_openpgp_crt_get_auth_subkey (crt, keyid, 1);
+        ret = gnutls_openpgp_crt_get_auth_subkey (crt, keyid, 1);
       else
-       ret = get_keyid (keyid, subkey_id);
+        ret = get_keyid (keyid, subkey_id);
+
+      if (ret < 0)
+        gnutls_assert();
 
       if (ret >= 0)
-       {
-         ret = gnutls_openpgp_crt_set_preferred_key_id (crt, keyid);
-         if (ret >= 0)
-           ret = gnutls_openpgp_privkey_set_preferred_key_id (pkey, keyid);
-       }
+        {
+          ret = gnutls_openpgp_crt_set_preferred_key_id (crt, keyid);
+          if (ret >= 0)
+            ret = gnutls_openpgp_privkey_set_preferred_key_id (pkey, keyid);
+        }
 
       if (ret < 0)
-       {
-         gnutls_assert ();
-         gnutls_openpgp_privkey_deinit (pkey);
-         gnutls_openpgp_crt_deinit (crt);
-         return ret;
-       }
+        {
+          gnutls_assert ();
+          gnutls_openpgp_privkey_deinit (pkey);
+          gnutls_openpgp_crt_deinit (crt);
+          return ret;
+        }
     }
 
   ret = gnutls_certificate_set_openpgp_key (res, crt, pkey);
 
-  gnutls_openpgp_privkey_deinit (pkey);
   gnutls_openpgp_crt_deinit (crt);
 
   return ret;
@@ -720,73 +715,6 @@ gnutls_openpgp_set_recv_key_function (gnutls_session_t 
session,
 }
 
 
-/* Copies a gnutls_openpgp_privkey_t to a gnutls_privkey structure. */
-int
-_gnutls_openpgp_privkey_to_gkey (gnutls_privkey * dest,
-                                gnutls_openpgp_privkey_t src)
-{
-  int ret = 0;
-  gnutls_openpgp_keyid_t keyid;
-  char err_buf[33];
-
-  if (dest == NULL || src == NULL)
-    {
-      gnutls_assert ();
-      return GNUTLS_E_CERTIFICATE_ERROR;
-    }
-
-  dest->params_size = MAX_PRIV_PARAMS_SIZE;
-
-  ret = gnutls_openpgp_privkey_get_preferred_key_id (src, keyid);
-
-  if (ret == 0)
-    {
-      int idx;
-      uint32_t kid32[2];
-
-      _gnutls_debug_log
-       ("Importing Openpgp key and using openpgp sub key: %s\n",
-        _gnutls_bin2hex (keyid, sizeof (keyid), err_buf, sizeof (err_buf)));
-
-      KEYID_IMPORT (kid32, keyid);
-
-      idx = gnutls_openpgp_privkey_get_subkey_idx (src, keyid);
-      if (idx < 0)
-       {
-         gnutls_assert ();
-         return idx;
-       }
-
-      dest->pk_algorithm =
-       gnutls_openpgp_privkey_get_subkey_pk_algorithm (src, idx, NULL);
-
-      ret =
-       _gnutls_openpgp_privkey_get_mpis (src, kid32, dest->params,
-                                         &dest->params_size);
-    }
-  else
-    {
-      _gnutls_debug_log
-       ("Importing Openpgp key and using main openpgp key.\n");
-
-      dest->pk_algorithm =
-       gnutls_openpgp_privkey_get_pk_algorithm (src, NULL);
-      ret =
-       _gnutls_openpgp_privkey_get_mpis (src, NULL, dest->params,
-                                         &dest->params_size);
-    }
-
-
-  if (ret < 0)
-    {
-      gnutls_assert ();
-      return ret;
-    }
-
-  return 0;
-
-}
-
 /* Converts a parsed gnutls_openpgp_crt_t to a gnutls_cert structure.
  */
 int
@@ -812,7 +740,7 @@ _gnutls_openpgp_crt_to_gcert (gnutls_cert * gcert, 
gnutls_openpgp_crt_t cert)
 
       _gnutls_debug_log
        ("Importing Openpgp cert and using openpgp sub key: %s\n",
-        _gnutls_bin2hex (keyid, sizeof (keyid), err_buf, sizeof (err_buf)));
+        _gnutls_bin2hex (keyid, sizeof (keyid), err_buf, sizeof (err_buf), 
NULL));
 
       KEYID_IMPORT (kid32, keyid);
 
@@ -927,6 +855,78 @@ gnutls_openpgp_privkey_sign_hash (gnutls_openpgp_privkey_t 
key,
                                  gnutls_datum_t * signature)
 {
   int result, i;
+  bigint_t params[MAX_PRIV_PARAMS_SIZE];
+  int params_size = MAX_PRIV_PARAMS_SIZE;
+  int pk_algorithm;
+  gnutls_openpgp_keyid_t keyid;
+
+  if (key == NULL)
+    {
+      gnutls_assert ();
+      return GNUTLS_E_INVALID_REQUEST;
+    }
+
+  result = gnutls_openpgp_privkey_get_preferred_key_id (key, keyid);
+  if (result == 0)
+    {
+      uint32_t kid[2];
+      int idx;
+
+      KEYID_IMPORT (kid, keyid);
+
+      idx = gnutls_openpgp_privkey_get_subkey_idx(key, keyid);
+      pk_algorithm = gnutls_openpgp_privkey_get_subkey_pk_algorithm (key, idx, 
NULL);
+      result = _gnutls_openpgp_privkey_get_mpis (key, kid,
+                                                params, &params_size);
+    }
+  else
+    {
+      pk_algorithm = gnutls_openpgp_privkey_get_pk_algorithm (key, NULL);
+      result = _gnutls_openpgp_privkey_get_mpis (key, NULL,
+                                                params, &params_size);
+    }
+
+  if (result < 0)
+    {
+      gnutls_assert ();
+      return result;
+    }
+
+
+  result = _gnutls_soft_sign (pk_algorithm, params, params_size, hash, 
signature);
+
+  for (i = 0; i < params_size; i++)
+    _gnutls_mpi_release (&params[i]);
+
+  if (result < 0)
+    {
+      gnutls_assert ();
+      return result;
+    }
+
+  return 0;
+}
+
+/**
+ * gnutls_openpgp_privkey_decrypt_data:
+ * @key: Holds the key
+ * @flags: zero for now
+ * @ciphertext: holds the data to be decrypted
+ * @plaintext: will contain newly allocated plaintext
+ *
+ * This function will sign the given hash using the private key.  You
+ * should use gnutls_openpgp_privkey_set_preferred_key_id() before
+ * calling this function to set the subkey to use.
+ *
+ * Returns: On success, %GNUTLS_E_SUCCESS is returned, otherwise a
+ *   negative error value.
+ **/
+int
+gnutls_openpgp_privkey_decrypt_data (gnutls_openpgp_privkey_t key,
+      unsigned int flags, const gnutls_datum_t * ciphertext,
+                                 gnutls_datum_t * plaintext)
+{
+  int result, i;
   bigint_t params[MAX_PUBLIC_PARAMS_SIZE];
   int params_size = MAX_PUBLIC_PARAMS_SIZE;
   int pk_algorithm;
@@ -937,7 +937,7 @@ gnutls_openpgp_privkey_sign_hash (gnutls_openpgp_privkey_t 
key,
       gnutls_assert ();
       return GNUTLS_E_INVALID_REQUEST;
     }
-
+  
   result = gnutls_openpgp_privkey_get_preferred_key_id (key, keyid);
   if (result == 0)
     {
@@ -961,7 +961,13 @@ gnutls_openpgp_privkey_sign_hash (gnutls_openpgp_privkey_t 
key,
 
   pk_algorithm = gnutls_openpgp_privkey_get_pk_algorithm (key, NULL);
 
-  result = _gnutls_sign (pk_algorithm, params, params_size, hash, signature);
+  if (pk_algorithm != GNUTLS_PK_RSA)
+    {
+      gnutls_assert();
+      return GNUTLS_E_INVALID_REQUEST;
+    }
+
+  result = _gnutls_pkcs1_rsa_decrypt (plaintext, ciphertext, params, 
params_size, 2);
 
   for (i = 0; i < params_size; i++)
     _gnutls_mpi_release (&params[i]);
diff --git a/lib/openpgp/gnutls_openpgp.h b/lib/openpgp/gnutls_openpgp.h
index 36ab853..b5f67d4 100644
--- a/lib/openpgp/gnutls_openpgp.h
+++ b/lib/openpgp/gnutls_openpgp.h
@@ -7,6 +7,7 @@
 
 #include <auth_cert.h>
 #include <opencdk.h>
+#include <gnutls/abstract.h>
 
 /* OpenCDK compatible */
 typedef enum
@@ -29,7 +30,7 @@ int _gnutls_openpgp_raw_crt_to_gcert (gnutls_cert * cert,
                                      const gnutls_openpgp_keyid_t);
 
 int
-_gnutls_openpgp_raw_privkey_to_gkey (gnutls_privkey * pkey,
+_gnutls_openpgp_raw_privkey_to_gkey (gnutls_privkey_t * pkey,
                                     const gnutls_datum_t * raw_key);
 
 int
diff --git a/lib/openpgp/openpgp_int.h b/lib/openpgp/openpgp_int.h
index d5eb139..8071aa0 100644
--- a/lib/openpgp/openpgp_int.h
+++ b/lib/openpgp/openpgp_int.h
@@ -45,8 +45,6 @@ int _gnutls_openpgp_export (cdk_kbnode_t node,
 
 int _gnutls_openpgp_crt_to_gcert (gnutls_cert * gcert,
                                  gnutls_openpgp_crt_t cert);
-int _gnutls_openpgp_privkey_to_gkey (gnutls_privkey * dest,
-                                    gnutls_openpgp_privkey_t src);
 
 cdk_packet_t _gnutls_get_valid_subkey (cdk_kbnode_t knode, int key_type);
 
diff --git a/lib/openpgp/output.c b/lib/openpgp/output.c
index 982a6a6..20d2855 100644
--- a/lib/openpgp/output.c
+++ b/lib/openpgp/output.c
@@ -237,6 +237,8 @@ print_key_info (gnutls_string * str, gnutls_openpgp_crt_t 
cert, int idx)
        name = _("unknown");
 
       addf (str, _("\tPublic Key Algorithm: %s\n"), name);
+      addf (str, _("\tKey Security Level: %s\n"), 
gnutls_sec_param_get_name(gnutls_pk_bits_to_sec_param(err, bits)));
+
       switch (err)
        {
        case GNUTLS_PK_RSA:
diff --git a/lib/openpgp/pgp.c b/lib/openpgp/pgp.c
index 3483243..2dede0e 100644
--- a/lib/openpgp/pgp.c
+++ b/lib/openpgp/pgp.c
@@ -773,6 +773,8 @@ _gnutls_openpgp_find_subkey_idx (cdk_kbnode_t knode, 
uint32_t keyid[2],
   int i = 0;
   uint32_t local_keyid[2];
 
+  _gnutls_hard_log("Looking keyid: %x.%x\n", keyid[0], keyid[1]);
+
   ctx = NULL;
   while ((p = cdk_kbnode_walk (knode, &ctx, 0)))
     {
@@ -786,6 +788,7 @@ _gnutls_openpgp_find_subkey_idx (cdk_kbnode_t knode, 
uint32_t keyid[2],
          else
            cdk_pk_get_keyid (pkt->pkt.secret_key->pk, local_keyid);
 
+          _gnutls_hard_log("Found keyid: %x.%x\n", local_keyid[0], 
local_keyid[1]);
          if (local_keyid[0] == keyid[0] && local_keyid[1] == keyid[1])
            {
              return i;
diff --git a/lib/openpgp/privkey.c b/lib/openpgp/privkey.c
index bc4c635..71c17c4 100644
--- a/lib/openpgp/privkey.c
+++ b/lib/openpgp/privkey.c
@@ -688,9 +688,12 @@ _gnutls_openpgp_privkey_get_mpis (gnutls_openpgp_privkey_t 
pkey,
                                  bigint_t * params, int *params_size)
 {
   int result, i;
-  int pk_algorithm, local_params;
+  int pk_algorithm;
+  gnutls_pk_params_st pk_params;
   cdk_packet_t pkt;
 
+  memset(&pk_params, 0, sizeof(pk_params));
+
   if (keyid == NULL)
     pkt = cdk_kbnode_find_packet (pkey->knode, CDK_PKT_SECRET_KEY);
   else
@@ -708,28 +711,21 @@ _gnutls_openpgp_privkey_get_mpis 
(gnutls_openpgp_privkey_t pkey,
   switch (pk_algorithm)
     {
     case GNUTLS_PK_RSA:
-      local_params = RSA_PRIVATE_PARAMS;
+      /* openpgp does not hold all parameters as in PKCS #1
+       */
+      pk_params.params_nr = RSA_PRIVATE_PARAMS-2;
       break;
     case GNUTLS_PK_DSA:
-      local_params = DSA_PRIVATE_PARAMS;
+      pk_params.params_nr = DSA_PRIVATE_PARAMS;
       break;
     default:
       gnutls_assert ();
       return GNUTLS_E_UNSUPPORTED_CERTIFICATE_TYPE;
     }
 
-  if (*params_size < local_params)
+  for (i = 0; i < pk_params.params_nr; i++)
     {
-      gnutls_assert ();
-      return GNUTLS_E_INTERNAL_ERROR;
-    }
-
-  *params_size = local_params;
-
-
-  for (i = 0; i < local_params; i++)
-    {
-      result = _gnutls_read_pgp_mpi (pkt, 1, i, &params[i]);
+      result = _gnutls_read_pgp_mpi (pkt, 1, i, &pk_params.params[i]);
       if (result < 0)
        {
          gnutls_assert ();
@@ -737,13 +733,33 @@ _gnutls_openpgp_privkey_get_mpis 
(gnutls_openpgp_privkey_t pkey,
        }
     }
 
+    /* fixup will generate exp1 and exp2 that are not
+     * available here.
+     */
+  result = _gnutls_pk_fixup (pk_algorithm, GNUTLS_IMPORT, &pk_params);
+  if (result < 0)
+    {
+      gnutls_assert ();
+      goto error;
+    }
+
+  if (*params_size < pk_params.params_nr)
+    {
+      gnutls_assert ();
+      return GNUTLS_E_INTERNAL_ERROR;
+    }
+
+  *params_size = pk_params.params_nr;
+  for(i=0;i<pk_params.params_nr;i++)
+    params[i] = pk_params.params[i];
+
   return 0;
 
 error:
   {
     int j;
     for (j = 0; j < i; j++)
-      _gnutls_mpi_release (&params[j]);
+      _gnutls_mpi_release (&pk_params.params[j]);
   }
 
   return result;
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..daca322
--- /dev/null
+++ b/lib/pakchois/pakchois.c
@@ -0,0 +1,985 @@
+/* 
+   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 '/'
+
+static 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[] =
+#ifdef PAKCHOIS_MODPATH
+    PAKCHOIS_MODPATH;
+#else
+    "";
+#endif
+    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;
+    }
+
+    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)
+{
+    while (mod->slots) {
+        struct slot *slot = mod->slots;
+        pakchois_close_all_sessions(mod, slot->id);
+        mod->slots = slot->next;
+        free(slot);
+    }
+    provider_unref(mod->provider);
+
+    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/pk-libgcrypt.c b/lib/pk-libgcrypt.c
deleted file mode 100644
index 5e0b159..0000000
--- a/lib/pk-libgcrypt.c
+++ /dev/null
@@ -1,812 +0,0 @@
-/*
- * Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2008, 2009, 2010
- * Free Software Foundation, Inc.
- *
- * Author: Nikos Mavrogiannopoulos
- *
- * This file is part of GnuTLS.
- *
- * The GnuTLS is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public License
- * as published by the Free Software Foundation; either version 2.1 of
- * the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
- * USA
- *
- */
-
-/* This file contains the functions needed for RSA/DSA public key
- * encryption and signatures. 
- */
-
-#include <gnutls_int.h>
-#include <gnutls_mpi.h>
-#include <gnutls_pk.h>
-#include <gnutls_errors.h>
-#include <gnutls_datum.h>
-#include <gnutls_global.h>
-#include <gnutls_num.h>
-#include <x509/x509_int.h>
-#include <x509/common.h>
-#include <random.h>
-#include <gnutls_pk.h>
-#include <gcrypt.h>
-
-/* this is based on code from old versions of libgcrypt (centuries ago)
- */
-
-int (*generate) (gnutls_pk_algorithm_t, unsigned int level /*bits */ ,
-                gnutls_pk_params_st *);
-
-static int
-_wrap_gcry_pk_encrypt (gnutls_pk_algorithm_t algo,
-                      gnutls_datum_t * ciphertext,
-                      const gnutls_datum_t * plaintext,
-                      const gnutls_pk_params_st * pk_params)
-{
-  gcry_sexp_t s_ciph = NULL, s_data = NULL, s_pkey = NULL;
-  int rc = -1;
-  int ret;
-  bigint_t data, res;
-  gcry_sexp_t list;
-
-  if (_gnutls_mpi_scan_nz (&data, plaintext->data, plaintext->size) != 0)
-    {
-      gnutls_assert ();
-      return GNUTLS_E_MPI_SCAN_FAILED;
-    }
-
-  /* make a sexp from pkey */
-  switch (algo)
-    {
-    case GNUTLS_PK_RSA:
-      if (pk_params->params_nr >= 2)
-       rc = gcry_sexp_build (&s_pkey, NULL,
-                             "(public-key(rsa(n%m)(e%m)))",
-                             pk_params->params[0], pk_params->params[1]);
-      break;
-
-    default:
-      gnutls_assert ();
-      ret = GNUTLS_E_INTERNAL_ERROR;
-      goto cleanup;
-    }
-
-  if (rc != 0)
-    {
-      gnutls_assert ();
-      ret = GNUTLS_E_INTERNAL_ERROR;
-      goto cleanup;
-    }
-
-  /* put the data into a simple list */
-  if (gcry_sexp_build (&s_data, NULL, "%m", data))
-    {
-      gnutls_assert ();
-      ret = GNUTLS_E_MEMORY_ERROR;
-      goto cleanup;
-    }
-
-  /* pass it to libgcrypt */
-  rc = gcry_pk_encrypt (&s_ciph, s_data, s_pkey);
-  if (rc != 0)
-    {
-      gnutls_assert ();
-      ret = GNUTLS_E_PK_ENCRYPTION_FAILED;
-      goto cleanup;
-    }
-
-  list = gcry_sexp_find_token (s_ciph, "a", 0);
-  if (list == NULL)
-    {
-      gnutls_assert ();
-      ret = GNUTLS_E_INTERNAL_ERROR;
-      goto cleanup;
-    }
-
-  res = gcry_sexp_nth_mpi (list, 1, 0);
-  gcry_sexp_release (list);
-  if (res == NULL)
-    {
-      gnutls_assert ();
-      ret = GNUTLS_E_INTERNAL_ERROR;
-      goto cleanup;
-    }
-
-  ret = _gnutls_mpi_dprint_size (res, ciphertext, plaintext->size);
-  _gnutls_mpi_release (&res);
-  if (ret < 0)
-    {
-      gnutls_assert ();
-      goto cleanup;
-    }
-
-  ret = 0;
-
-cleanup:
-  _gnutls_mpi_release (&data);
-  if (s_ciph)
-    gcry_sexp_release (s_ciph);
-  if (s_data)
-    gcry_sexp_release (s_data);
-  if (s_pkey)
-    gcry_sexp_release (s_pkey);
-
-  return ret;
-}
-
-static int
-_wrap_gcry_pk_decrypt (gnutls_pk_algorithm_t algo,
-                      gnutls_datum_t * plaintext,
-                      const gnutls_datum_t * ciphertext,
-                      const gnutls_pk_params_st * pk_params)
-{
-  gcry_sexp_t s_plain = NULL, s_data = NULL, s_pkey = NULL;
-  int rc = -1;
-  int ret;
-  bigint_t data, res;
-
-  if (_gnutls_mpi_scan_nz (&data, ciphertext->data, ciphertext->size) != 0)
-    {
-      gnutls_assert ();
-      return GNUTLS_E_MPI_SCAN_FAILED;
-    }
-
-  /* make a sexp from pkey */
-  switch (algo)
-    {
-    case GNUTLS_PK_RSA:
-      if (pk_params->params_nr >= 6)
-       rc = gcry_sexp_build (&s_pkey, NULL,
-                             
"(private-key(rsa((n%m)(e%m)(d%m)(p%m)(q%m)(u%m))))",
-                             pk_params->params[0], pk_params->params[1],
-                             pk_params->params[2], pk_params->params[3],
-                             pk_params->params[4], pk_params->params[5]);
-      break;
-
-    default:
-      gnutls_assert ();
-      ret = GNUTLS_E_INTERNAL_ERROR;
-      goto cleanup;
-    }
-
-  if (rc != 0)
-    {
-      gnutls_assert ();
-      ret = GNUTLS_E_INTERNAL_ERROR;
-      goto cleanup;
-    }
-
-  /* put the data into a simple list */
-  if (gcry_sexp_build (&s_data, NULL, "(enc-val(rsa(a%m)))", data))
-    {
-      gnutls_assert ();
-      ret = GNUTLS_E_INTERNAL_ERROR;
-      goto cleanup;
-    }
-
-  /* pass it to libgcrypt */
-  rc = gcry_pk_decrypt (&s_plain, s_data, s_pkey);
-  if (rc != 0)
-    {
-      gnutls_assert ();
-      ret = GNUTLS_E_PK_DECRYPTION_FAILED;
-      goto cleanup;
-    }
-
-  res = gcry_sexp_nth_mpi (s_plain, 0, 0);
-  if (res == NULL)
-    {
-      gnutls_assert ();
-      ret = GNUTLS_E_INTERNAL_ERROR;
-      goto cleanup;
-    }
-
-  ret = _gnutls_mpi_dprint_size (res, plaintext, ciphertext->size);
-  _gnutls_mpi_release (&res);
-  if (ret < 0)
-    {
-      gnutls_assert ();
-      goto cleanup;
-    }
-
-  ret = 0;
-
-cleanup:
-  _gnutls_mpi_release (&data);
-  if (s_plain)
-    gcry_sexp_release (s_plain);
-  if (s_data)
-    gcry_sexp_release (s_data);
-  if (s_pkey)
-    gcry_sexp_release (s_pkey);
-
-  return ret;
-
-}
-
-
-/* in case of DSA puts into data, r,s
- */
-static int
-_wrap_gcry_pk_sign (gnutls_pk_algorithm_t algo, gnutls_datum_t * signature,
-                   const gnutls_datum_t * vdata,
-                   const gnutls_pk_params_st * pk_params)
-{
-  gcry_sexp_t s_hash = NULL, s_key = NULL, s_sig = NULL;
-  gcry_sexp_t list = NULL;
-  int rc = -1, ret;
-  bigint_t hash;
-  bigint_t res[2] = { NULL, NULL };
-
-  if (_gnutls_mpi_scan_nz (&hash, vdata->data, vdata->size) != 0)
-    {
-      gnutls_assert ();
-      return GNUTLS_E_MPI_SCAN_FAILED;
-    }
-
-  /* make a sexp from pkey */
-  switch (algo)
-    {
-    case GNUTLS_PK_DSA:
-      if (pk_params->params_nr >= 5)
-       rc = gcry_sexp_build (&s_key, NULL,
-                             "(private-key(dsa(p%m)(q%m)(g%m)(y%m)(x%m)))",
-                             pk_params->params[0], pk_params->params[1],
-                             pk_params->params[2], pk_params->params[3],
-                             pk_params->params[4]);
-      else
-       {
-         gnutls_assert ();
-       }
-
-      break;
-    case GNUTLS_PK_RSA:
-      if (pk_params->params_nr >= 6)
-       rc = gcry_sexp_build (&s_key, NULL,
-                             
"(private-key(rsa((n%m)(e%m)(d%m)(p%m)(q%m)(u%m))))",
-                             pk_params->params[0], pk_params->params[1],
-                             pk_params->params[2], pk_params->params[3],
-                             pk_params->params[4], pk_params->params[5]);
-      else
-       {
-         gnutls_assert ();
-       }
-      break;
-
-    default:
-      gnutls_assert ();
-      ret = GNUTLS_E_INTERNAL_ERROR;
-      goto cleanup;
-    }
-
-  if (rc != 0)
-    {
-      gnutls_assert ();
-      ret = GNUTLS_E_INTERNAL_ERROR;
-      goto cleanup;
-    }
-
-  /* put the data into a simple list */
-  if (gcry_sexp_build (&s_hash, NULL, "%m", hash))
-    {
-      gnutls_assert ();
-      ret = GNUTLS_E_INTERNAL_ERROR;
-      goto cleanup;
-    }
-
-
-  /* pass it to libgcrypt */
-  rc = gcry_pk_sign (&s_sig, s_hash, s_key);
-  if (rc != 0)
-    {
-      gnutls_assert ();
-      ret = GNUTLS_E_PK_SIGN_FAILED;
-      goto cleanup;
-    }
-
-  ret = GNUTLS_E_INTERNAL_ERROR;
-
-  switch (algo)
-    {
-    case GNUTLS_PK_DSA:
-      {
-       list = gcry_sexp_find_token (s_sig, "r", 0);
-       if (list == NULL)
-         {
-           gnutls_assert ();
-           ret = GNUTLS_E_INTERNAL_ERROR;
-           goto cleanup;
-         }
-
-       res[0] = gcry_sexp_nth_mpi (list, 1, 0);
-       gcry_sexp_release (list);
-
-       list = gcry_sexp_find_token (s_sig, "s", 0);
-       if (list == NULL)
-         {
-           gnutls_assert ();
-           ret = GNUTLS_E_INTERNAL_ERROR;
-           goto cleanup;
-         }
-
-       res[1] = gcry_sexp_nth_mpi (list, 1, 0);
-       gcry_sexp_release (list);
-
-       ret = _gnutls_encode_ber_rs (signature, res[0], res[1]);
-       if (ret < 0)
-         {
-           gnutls_assert ();
-           goto cleanup;
-         }
-      }
-      break;
-
-    case GNUTLS_PK_RSA:
-      {
-       list = gcry_sexp_find_token (s_sig, "s", 0);
-       if (list == NULL)
-         {
-           gnutls_assert ();
-           ret = GNUTLS_E_INTERNAL_ERROR;
-           goto cleanup;
-         }
-
-       res[0] = gcry_sexp_nth_mpi (list, 1, 0);
-       gcry_sexp_release (list);
-
-       ret = _gnutls_mpi_dprint (res[0], signature);
-       if (ret < 0)
-         {
-           gnutls_assert ();
-           goto cleanup;
-         }
-      }
-      break;
-
-    default:
-      gnutls_assert ();
-      ret = GNUTLS_E_INTERNAL_ERROR;
-      goto cleanup;
-    }
-
-  ret = 0;
-
-cleanup:
-  _gnutls_mpi_release (&hash);
-  if (res[0])
-    _gnutls_mpi_release (&res[0]);
-  if (res[1])
-    _gnutls_mpi_release (&res[1]);
-  if (s_sig)
-    gcry_sexp_release (s_sig);
-  if (s_hash)
-    gcry_sexp_release (s_hash);
-  if (s_key)
-    gcry_sexp_release (s_key);
-
-  return ret;
-}
-
-static int
-_wrap_gcry_pk_verify (gnutls_pk_algorithm_t algo,
-                     const gnutls_datum_t * vdata,
-                     const gnutls_datum_t * signature,
-                     const gnutls_pk_params_st * pk_params)
-{
-  gcry_sexp_t s_sig = NULL, s_hash = NULL, s_pkey = NULL;
-  int rc = -1, ret;
-  bigint_t hash;
-  bigint_t tmp[2] = { NULL, NULL };
-
-  if (_gnutls_mpi_scan_nz (&hash, vdata->data, vdata->size) != 0)
-    {
-      gnutls_assert ();
-      return GNUTLS_E_MPI_SCAN_FAILED;
-    }
-
-  /* make a sexp from pkey */
-  switch (algo)
-    {
-    case GNUTLS_PK_DSA:
-      if (pk_params->params_nr >= 4)
-       rc = gcry_sexp_build (&s_pkey, NULL,
-                             "(public-key(dsa(p%m)(q%m)(g%m)(y%m)))",
-                             pk_params->params[0], pk_params->params[1],
-                             pk_params->params[2], pk_params->params[3]);
-      break;
-    case GNUTLS_PK_RSA:
-      if (pk_params->params_nr >= 2)
-       rc = gcry_sexp_build (&s_pkey, NULL,
-                             "(public-key(rsa(n%m)(e%m)))",
-                             pk_params->params[0], pk_params->params[1]);
-      break;
-
-    default:
-      gnutls_assert ();
-      ret = GNUTLS_E_INTERNAL_ERROR;
-      goto cleanup;
-    }
-
-  if (rc != 0)
-    {
-      gnutls_assert ();
-      ret = GNUTLS_E_INTERNAL_ERROR;
-      goto cleanup;
-    }
-
-  /* put the data into a simple list */
-  if (gcry_sexp_build (&s_hash, NULL, "%m", hash))
-    {
-      gnutls_assert ();
-      ret = GNUTLS_E_INTERNAL_ERROR;
-      goto cleanup;
-    }
-
-  switch (algo)
-    {
-    case GNUTLS_PK_DSA:
-      ret = _gnutls_decode_ber_rs (signature, &tmp[0], &tmp[1]);
-      if (ret < 0)
-       {
-         gnutls_assert ();
-         goto cleanup;
-       }
-      rc = gcry_sexp_build (&s_sig, NULL,
-                           "(sig-val(dsa(r%m)(s%m)))", tmp[0], tmp[1]);
-      _gnutls_mpi_release (&tmp[0]);
-      _gnutls_mpi_release (&tmp[1]);
-      break;
-
-    case GNUTLS_PK_RSA:
-      ret = _gnutls_mpi_scan_nz (&tmp[0], signature->data, signature->size);
-      if (ret < 0)
-       {
-         gnutls_assert ();
-         goto cleanup;
-       }
-      rc = gcry_sexp_build (&s_sig, NULL, "(sig-val(rsa(s%m)))", tmp[0]);
-      _gnutls_mpi_release (&tmp[0]);
-      break;
-
-    default:
-      gnutls_assert ();
-      ret = GNUTLS_E_INTERNAL_ERROR;
-      goto cleanup;
-    }
-
-  if (rc != 0)
-    {
-      gnutls_assert ();
-      ret = GNUTLS_E_INTERNAL_ERROR;
-      goto cleanup;
-    }
-
-  rc = gcry_pk_verify (s_sig, s_hash, s_pkey);
-
-  if (rc != 0)
-    {
-      gnutls_assert ();
-      ret = GNUTLS_E_PK_SIG_VERIFY_FAILED;
-      goto cleanup;
-    }
-
-  ret = 0;
-
-cleanup:
-  _gnutls_mpi_release (&hash);
-  if (s_sig)
-    gcry_sexp_release (s_sig);
-  if (s_hash)
-    gcry_sexp_release (s_hash);
-  if (s_pkey)
-    gcry_sexp_release (s_pkey);
-
-  return ret;
-}
-
-static int
-_dsa_generate_params (bigint_t * resarr, int *resarr_len, int bits)
-{
-
-  int ret;
-  gcry_sexp_t parms, key, list;
-
-  /* FIXME: Remove me once we depend on 1.3.1 */
-  if (bits > 1024 && gcry_check_version ("1.3.1") == NULL)
-    {
-      gnutls_assert ();
-      return GNUTLS_E_INVALID_REQUEST;
-    }
-
-  if (bits < 512)
-    {
-      gnutls_assert ();
-      return GNUTLS_E_INVALID_REQUEST;
-    }
-
-  ret = gcry_sexp_build (&parms, NULL, "(genkey(dsa(nbits %d)))", bits);
-  if (ret != 0)
-    {
-      gnutls_assert ();
-      return GNUTLS_E_INTERNAL_ERROR;
-    }
-
-  /* generate the DSA key 
-   */
-  ret = gcry_pk_genkey (&key, parms);
-  gcry_sexp_release (parms);
-
-  if (ret != 0)
-    {
-      gnutls_assert ();
-      return GNUTLS_E_INTERNAL_ERROR;
-    }
-
-  list = gcry_sexp_find_token (key, "p", 0);
-  if (list == NULL)
-    {
-      gnutls_assert ();
-      gcry_sexp_release (key);
-      return GNUTLS_E_INTERNAL_ERROR;
-    }
-
-  resarr[0] = gcry_sexp_nth_mpi (list, 1, 0);
-  gcry_sexp_release (list);
-
-  list = gcry_sexp_find_token (key, "q", 0);
-  if (list == NULL)
-    {
-      gnutls_assert ();
-      gcry_sexp_release (key);
-      return GNUTLS_E_INTERNAL_ERROR;
-    }
-
-  resarr[1] = gcry_sexp_nth_mpi (list, 1, 0);
-  gcry_sexp_release (list);
-
-  list = gcry_sexp_find_token (key, "g", 0);
-  if (list == NULL)
-    {
-      gnutls_assert ();
-      gcry_sexp_release (key);
-      return GNUTLS_E_INTERNAL_ERROR;
-    }
-
-  resarr[2] = gcry_sexp_nth_mpi (list, 1, 0);
-  gcry_sexp_release (list);
-
-  list = gcry_sexp_find_token (key, "y", 0);
-  if (list == NULL)
-    {
-      gnutls_assert ();
-      gcry_sexp_release (key);
-      return GNUTLS_E_INTERNAL_ERROR;
-    }
-
-  resarr[3] = gcry_sexp_nth_mpi (list, 1, 0);
-  gcry_sexp_release (list);
-
-
-  list = gcry_sexp_find_token (key, "x", 0);
-  if (list == NULL)
-    {
-      gnutls_assert ();
-      gcry_sexp_release (key);
-      return GNUTLS_E_INTERNAL_ERROR;
-    }
-
-  resarr[4] = gcry_sexp_nth_mpi (list, 1, 0);
-
-  gcry_sexp_release (list);
-  gcry_sexp_release (key);
-
-  _gnutls_mpi_log ("p: ", resarr[0]);
-  _gnutls_mpi_log ("q: ", resarr[1]);
-  _gnutls_mpi_log ("g: ", resarr[2]);
-  _gnutls_mpi_log ("y: ", resarr[3]);
-  _gnutls_mpi_log ("x: ", resarr[4]);
-
-  *resarr_len = 5;
-
-  return 0;
-
-}
-
-static int
-_rsa_generate_params (bigint_t * resarr, int *resarr_len, int bits)
-{
-
-  int ret;
-  gcry_sexp_t parms, key, list;
-
-  ret = gcry_sexp_build (&parms, NULL, "(genkey(rsa(nbits %d)))", bits);
-  if (ret != 0)
-    {
-      gnutls_assert ();
-      return GNUTLS_E_INTERNAL_ERROR;
-    }
-
-  /* generate the RSA key */
-  ret = gcry_pk_genkey (&key, parms);
-  gcry_sexp_release (parms);
-
-  if (ret != 0)
-    {
-      gnutls_assert ();
-      return GNUTLS_E_INTERNAL_ERROR;
-    }
-
-  list = gcry_sexp_find_token (key, "n", 0);
-  if (list == NULL)
-    {
-      gnutls_assert ();
-      gcry_sexp_release (key);
-      return GNUTLS_E_INTERNAL_ERROR;
-    }
-
-  resarr[0] = gcry_sexp_nth_mpi (list, 1, 0);
-  gcry_sexp_release (list);
-
-  list = gcry_sexp_find_token (key, "e", 0);
-  if (list == NULL)
-    {
-      gnutls_assert ();
-      gcry_sexp_release (key);
-      return GNUTLS_E_INTERNAL_ERROR;
-    }
-
-  resarr[1] = gcry_sexp_nth_mpi (list, 1, 0);
-  gcry_sexp_release (list);
-
-  list = gcry_sexp_find_token (key, "d", 0);
-  if (list == NULL)
-    {
-      gnutls_assert ();
-      gcry_sexp_release (key);
-      return GNUTLS_E_INTERNAL_ERROR;
-    }
-
-  resarr[2] = gcry_sexp_nth_mpi (list, 1, 0);
-  gcry_sexp_release (list);
-
-  list = gcry_sexp_find_token (key, "p", 0);
-  if (list == NULL)
-    {
-      gnutls_assert ();
-      gcry_sexp_release (key);
-      return GNUTLS_E_INTERNAL_ERROR;
-    }
-
-  resarr[3] = gcry_sexp_nth_mpi (list, 1, 0);
-  gcry_sexp_release (list);
-
-
-  list = gcry_sexp_find_token (key, "q", 0);
-  if (list == NULL)
-    {
-      gnutls_assert ();
-      gcry_sexp_release (key);
-      return GNUTLS_E_INTERNAL_ERROR;
-    }
-
-  resarr[4] = gcry_sexp_nth_mpi (list, 1, 0);
-  gcry_sexp_release (list);
-
-
-  list = gcry_sexp_find_token (key, "u", 0);
-  if (list == NULL)
-    {
-      gnutls_assert ();
-      gcry_sexp_release (key);
-      return GNUTLS_E_INTERNAL_ERROR;
-    }
-
-  resarr[5] = gcry_sexp_nth_mpi (list, 1, 0);
-
-  gcry_sexp_release (list);
-  gcry_sexp_release (key);
-
-  _gnutls_mpi_log ("n: ", resarr[0]);
-  _gnutls_mpi_log ("e: ", resarr[1]);
-  _gnutls_mpi_log ("d: ", resarr[2]);
-  _gnutls_mpi_log ("p: ", resarr[3]);
-  _gnutls_mpi_log ("q: ", resarr[4]);
-  _gnutls_mpi_log ("u: ", resarr[5]);
-
-  *resarr_len = 6;
-
-  return 0;
-}
-
-
-static int
-wrap_gcry_pk_generate_params (gnutls_pk_algorithm_t algo,
-                             unsigned int level /*bits */ ,
-                             gnutls_pk_params_st * params)
-{
-
-  switch (algo)
-    {
-
-    case GNUTLS_PK_DSA:
-      params->params_nr = DSA_PRIVATE_PARAMS;
-      if (params->params_nr > GNUTLS_MAX_PK_PARAMS)
-       {
-         gnutls_assert ();
-         return GNUTLS_E_INTERNAL_ERROR;
-       }
-      return _dsa_generate_params (params->params, &params->params_nr, level);
-
-    case GNUTLS_PK_RSA:
-      params->params_nr = RSA_PRIVATE_PARAMS;
-      if (params->params_nr > GNUTLS_MAX_PK_PARAMS)
-       {
-         gnutls_assert ();
-         return GNUTLS_E_INTERNAL_ERROR;
-       }
-      return _rsa_generate_params (params->params, &params->params_nr, level);
-
-    default:
-      gnutls_assert ();
-      return GNUTLS_E_INVALID_REQUEST;
-    }
-}
-
-
-static int
-wrap_gcry_pk_fixup (gnutls_pk_algorithm_t algo,
-                   gnutls_direction_t direction,
-                   gnutls_pk_params_st * params)
-{
-  int ret;
-
-  /* only for RSA we invert the coefficient --pgp type */
-
-  if (algo != GNUTLS_PK_RSA)
-    return 0;
-
-  if (params->params[5])
-    _gnutls_mpi_release (&params->params[5]);
-  params->params[5] =
-    _gnutls_mpi_new (_gnutls_mpi_get_nbits (params->params[0]));
-
-  if (params->params[5] == NULL)
-    {
-      gnutls_assert ();
-      return GNUTLS_E_MEMORY_ERROR;
-    }
-
-  if (direction == GNUTLS_IMPORT)
-    ret =
-      gcry_mpi_invm (params->params[5], params->params[3], params->params[4]);
-  else
-    ret =
-      gcry_mpi_invm (params->params[5], params->params[4], params->params[3]);
-  if (ret == 0)
-    {
-      gnutls_assert ();
-      return GNUTLS_E_INVALID_REQUEST;
-    }
-
-  return 0;
-}
-
-int crypto_pk_prio = INT_MAX;
-
-gnutls_crypto_pk_st _gnutls_pk_ops = {
-  .encrypt = _wrap_gcry_pk_encrypt,
-  .decrypt = _wrap_gcry_pk_decrypt,
-  .sign = _wrap_gcry_pk_sign,
-  .verify = _wrap_gcry_pk_verify,
-  .generate = wrap_gcry_pk_generate_params,
-  .pk_fixup_private_params = wrap_gcry_pk_fixup,
-};
diff --git a/lib/pkcs11.c b/lib/pkcs11.c
new file mode 100644
index 0000000..fbdab0f
--- /dev/null
+++ b/lib/pkcs11.c
@@ -0,0 +1,2150 @@
+/*
+ * GnuTLS PKCS#11 support
+ * Copyright (C) 2010 Free Software Foundation
+ * 
+ * Author: Nikos Mavrogiannopoulos
+ *
+ * Inspired and some parts based on neon PKCS #11 support by Joe Orton.
+ * More ideas came from the pkcs11-helper library.
+ *
+ * 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
+*/
+
+#include <gnutls_int.h>
+#include <gnutls/pkcs11.h>
+#include <stdio.h>
+#include <string.h>
+#include <gnutls_errors.h>
+#include <gnutls_datum.h>
+#include <pkcs11_int.h>
+
+#define MAX_PROVIDERS 16
+
+/* XXX: try to eliminate this */
+#define MAX_CERT_SIZE 8*1024
+
+struct gnutls_pkcs11_provider_s {
+    pakchois_module_t *module;
+    unsigned long nslots;
+    ck_slot_id_t *slots;
+};
+
+struct flags_find_data_st {
+    struct pkcs11_url_info info;
+    unsigned int slot_flags;
+};
+
+struct url_find_data_st {
+    gnutls_pkcs11_obj_t crt;
+};
+
+struct crt_find_data_st {
+    gnutls_pkcs11_obj_t *p_list;
+    unsigned int* n_list;
+    unsigned int current;
+    gnutls_pkcs11_obj_attr_t flags;
+    struct pkcs11_url_info info;
+};
+
+
+static struct gnutls_pkcs11_provider_s providers[MAX_PROVIDERS];
+static int active_providers = 0;
+
+static gnutls_pkcs11_pin_callback_t pin_func;
+static void* pin_data;
+
+gnutls_pkcs11_token_callback_t token_func;
+void* token_data;
+
+/* Fake scan */
+void pkcs11_rescan_slots(void)
+{
+unsigned long slots;
+
+    pakchois_get_slot_list(providers[active_providers-1].module, 0, NULL, 
&slots);
+}
+
+/**
+ * gnutls_pkcs11_add_provider:
+ * @name: The filename of the module
+ * @params: should be NULL
+ *
+ * This function will load and add a PKCS 11 module to the module
+ * list used in gnutls. After this function is called the module will
+ * be used for PKCS 11 operations.
+ *
+ * Returns: On success, %GNUTLS_E_SUCCESS is returned, otherwise a
+ *   negative error value.
+ **/
+int gnutls_pkcs11_add_provider (const char * name, const char * params)
+{
+
+    if (active_providers >= MAX_PROVIDERS) {
+        gnutls_assert();
+        return GNUTLS_E_CONSTRAINT_ERROR;
+    }
+
+    active_providers++;
+    if (pakchois_module_load(&providers[active_providers-1].module, name) != 
CKR_OK) {
+        gnutls_assert();
+        _gnutls_debug_log("p11: Cannot load provider %s\n", name);
+        active_providers--;
+        return GNUTLS_E_PKCS11_LOAD_ERROR;
+    }
+
+    /* cache the number of slots in this module */
+    if (pakchois_get_slot_list(providers[active_providers-1].module, 0, NULL, 
&providers[active_providers-1].nslots) != CKR_OK) {
+        gnutls_assert();
+        goto fail;
+    }
+    
+    providers[active_providers-1].slots = 
gnutls_malloc(sizeof(*providers[active_providers-1].slots)*providers[active_providers-1].nslots);
+    if (providers[active_providers-1].slots==NULL) {
+        gnutls_assert();
+        goto fail;
+    }
+
+    if (pakchois_get_slot_list(providers[active_providers-1].module, 0, 
providers[active_providers-1].slots, &providers[active_providers-1].nslots) != 
CKR_OK)  {
+        gnutls_assert();
+        gnutls_free(providers[active_providers-1].slots);
+        goto fail;
+    }
+    
+    _gnutls_debug_log("p11: loaded provider '%s' with %d slots\n", name, 
(int)providers[active_providers-1].nslots);
+
+    return 0;
+
+fail:
+    pakchois_module_destroy(providers[active_providers-1].module);
+    active_providers--;
+    return GNUTLS_E_PKCS11_LOAD_ERROR;
+
+}
+
+
+/**
+ * gnutls_pkcs11_obj_get_info:
+ * @crt: should contain a #gnutls_pkcs11_obj_t structure
+ * @itype: Denotes the type of information requested
+ * @output: where output will be stored
+ * @output_size: contains the maximum size of the output and will be 
overwritten with actual
+ *
+ * This function will return information about the PKCS 11 certificatesuch
+ * as the label, id as well as token information where the key is stored. When
+ * output is text it returns null terminated string although %output_size 
contains
+ * the size of the actual data only.
+ *
+ * Returns: zero on success or a negative value on error.
+ **/
+int gnutls_pkcs11_obj_get_info(gnutls_pkcs11_obj_t crt, 
gnutls_pkcs11_obj_info_t itype, 
+    void* output, size_t* output_size)
+{
+    return pkcs11_get_info(&crt->info, itype, output, output_size);
+}
+
+int pkcs11_get_info(struct pkcs11_url_info *info, gnutls_pkcs11_obj_info_t 
itype,
+    void* output, size_t* output_size)
+{
+    const char* str = NULL;
+    size_t len;
+
+    switch(itype) {
+        case GNUTLS_PKCS11_OBJ_ID:
+            if (*output_size < info->certid_raw_size) {
+                *output_size = info->certid_raw_size;
+                return GNUTLS_E_SHORT_MEMORY_BUFFER;
+            }
+            if (output) memcpy(output, info->certid_raw, 
info->certid_raw_size);
+            *output_size = info->certid_raw_size;
+            
+            return 0;
+        case GNUTLS_PKCS11_OBJ_ID_HEX:
+            str = info->id;
+            break;
+        case GNUTLS_PKCS11_OBJ_LABEL:
+            str = info->label;
+            break;
+        case GNUTLS_PKCS11_OBJ_TOKEN_LABEL:
+            str = info->token;
+            break;
+        case GNUTLS_PKCS11_OBJ_TOKEN_SERIAL:
+            str = info->serial;
+            break;
+        case GNUTLS_PKCS11_OBJ_TOKEN_MANUFACTURER:
+            str = info->manufacturer;
+            break;
+        case GNUTLS_PKCS11_OBJ_TOKEN_MODEL:
+            str = info->model;
+            break;
+        default:
+            gnutls_assert();
+            return GNUTLS_E_INVALID_REQUEST;
+    }
+
+    len = strlen(str);
+
+    if (len+1>*output_size) {
+        *output_size = len+1;
+        return GNUTLS_E_SHORT_MEMORY_BUFFER;
+    }
+
+    strcpy(output, str);
+
+    *output_size = len;
+
+    return 0;
+}
+
+static int init = 0;
+
+
+/**
+ * gnutls_pkcs11_init:
+ * @flags: GNUTLS_PKCS11_FLAG_MANUAL or GNUTLS_PKCS11_FLAG_AUTO
+ * @configfile: either NULL or the location of a configuration file
+ *
+ * This function will initialize the PKCS 11 subsystem in gnutls. It will
+ * read a configuration file if %GNUTLS_PKCS11_FLAG_AUTO is used or allow
+ * you to independently load PKCS 11 modules using gnutls_pkcs11_add_provider()
+ * if %GNUTLS_PKCS11_FLAG_MANUAL is specified.
+ *
+ * Normally you don't need to call this function since it is being called
+ * by gnutls_global_init(). Otherwise you must call it before it.
+ *
+ * Returns: On success, %GNUTLS_E_SUCCESS is returned, otherwise a
+ *   negative error value.
+ **/
+int gnutls_pkcs11_init(unsigned int flags, const char* configfile)
+{
+    int ret;
+    
+    if (init != 0) {
+        init++;
+        return 0;
+    }
+    init++;
+
+    if (flags == GNUTLS_PKCS11_FLAG_MANUAL)
+        return 0;
+    else {
+        FILE *fp;
+        char line[512];
+        const char* library;
+        
+        if (configfile == NULL)
+            configfile = "/etc/gnutls/pkcs11.conf";
+        
+        fp = fopen(configfile, "r");
+        if (fp == NULL) {
+            gnutls_assert();
+            _gnutls_debug_log("Cannot load %s\n", configfile);
+            return GNUTLS_E_FILE_ERROR;
+        }
+        
+        while (fgets (line, sizeof (line), fp) != NULL) {
+            if (strncmp(line, "load", sizeof("load")-1) == 0) {
+                char* p;
+                p = strchr(line, '=');
+                if (p==NULL) continue;
+                
+                library = ++p;
+                
+                p = strchr(line, '\n');
+                if (p!=NULL) {
+                    *p=0;
+                }
+
+                ret = gnutls_pkcs11_add_provider(library, NULL);
+                if (ret < 0) {
+                    gnutls_assert();
+                    _gnutls_debug_log("Cannot load provider: %s\n", library);
+                    continue;
+                }
+            }
+        }
+    }
+    
+    return 0;
+}
+
+/**
+ * gnutls_pkcs11_deinit:
+ *
+ * This function will deinitialize the PKCS 11 subsystem in gnutls.
+ *
+ **/
+void gnutls_pkcs11_deinit (void)
+{
+    int i;
+
+    init--;
+    if (init > 0)
+        return;
+    if (init < 0)
+      {
+        init = 0;
+        return;
+      }
+    
+    for (i=0;i<active_providers;i++) {
+        pakchois_module_destroy(providers[i].module);
+    }
+    active_providers = 0;
+}
+
+/**
+ * gnutls_pkcs11_set_pin_function:
+ * @fn: The PIN callback
+ * @userdata: data to be supplied to callback
+ *
+ * This function will set a callback function to be used when a PIN
+ * is required for PKCS 11 operations.
+ *
+ * Returns: On success, %GNUTLS_E_SUCCESS is returned, otherwise a
+ *   negative error value.
+ **/
+void gnutls_pkcs11_set_pin_function(gnutls_pkcs11_pin_callback_t fn,
+                                void *userdata)
+{
+    pin_func = fn;
+    pin_data = userdata;
+}
+
+/**
+ * gnutls_pkcs11_set_token_function:
+ * @fn: The PIN callback
+ * @userdata: data to be supplied to callback
+ *
+ * This function will set a callback function to be used when a token
+ * needs to be inserted to continue PKCS 11 operations.
+ *
+ * Returns: On success, %GNUTLS_E_SUCCESS is returned, otherwise a
+ *   negative error value.
+ **/
+void gnutls_pkcs11_set_token_function(gnutls_pkcs11_token_callback_t fn,
+                                void *userdata)
+{
+    token_func = fn;
+    token_data = userdata;
+}
+
+static int unescape_string (char* output, const char* input, size_t* size, 
char terminator)
+{
+    gnutls_string str;
+    int ret = 0;
+    char* p;
+    int len;
+    
+    _gnutls_string_init(&str, gnutls_malloc, gnutls_realloc, gnutls_free);
+    
+    /* find terminator */
+    p = strchr(input, terminator);
+    if (p!=NULL)
+        len = p-input;
+    else
+        len = strlen(input);
+
+    ret = _gnutls_string_append_data(&str, input, len);
+    if (ret < 0) {
+        gnutls_assert();
+        return ret;
+    }
+
+    ret = _gnutls_string_unescape(&str);
+    if (ret < 0) {
+        gnutls_assert();
+        return ret;
+    }
+
+    ret = _gnutls_string_append_data(&str, "", 1);
+    if (ret < 0) {
+        gnutls_assert();
+        return ret;
+    }
+
+    _gnutls_string_get_data(&str, output, size);
+
+    _gnutls_string_clear(&str);
+
+    return ret;
+}
+
+int pkcs11_url_to_info(const char* url, struct pkcs11_url_info* info)
+{
+int ret;
+char* p1, *p2;
+size_t l;
+
+    memset( info, 0, sizeof(*info));
+
+    if (strstr(url, "pkcs11:")==NULL) {
+        ret = GNUTLS_E_PARSING_ERROR;
+        goto cleanup;
+    }
+
+    if ((p1=strstr(url, "manufacturer="))!= NULL) {
+        p1+=sizeof("manufacturer=")-1;
+        l=sizeof (info->manufacturer);
+
+        ret = unescape_string(info->manufacturer, p1, &l, ';');
+        if (ret < 0) {
+                goto cleanup;
+        }
+    }
+
+    if ((p1=strstr(url, "token="))!= NULL) {
+        p1+=sizeof("token=")-1;
+        l=sizeof (info->token);
+
+        ret = unescape_string(info->token, p1, &l, ';');
+        if (ret < 0) {
+                goto cleanup;
+        }
+    }
+
+    if ((p1=strstr(url, "object="))!= NULL) {
+        p1+=sizeof("object=")-1;
+        l=sizeof (info->label);
+
+        ret = unescape_string(info->label, p1, &l, ';');
+        if (ret < 0) {
+                goto cleanup;
+        }
+    }
+
+    if ((p1=strstr(url, "serial="))!= NULL) {
+        p1+=sizeof("serial=")-1;
+        l=sizeof (info->serial);
+
+        ret = unescape_string (info->serial, p1, &l, ';');
+        if (ret < 0) {
+                goto cleanup;
+        }
+    }
+
+    if ((p1=strstr(url, "model="))!= NULL) {
+        p1+=sizeof("model=")-1;
+        l=sizeof (info->model);
+
+        ret = unescape_string (info->model,
+                        p1, &l, ';');
+        if (ret < 0) {
+                goto cleanup;
+        }
+    }
+
+    if ((p1=strstr(url, "objecttype="))!= NULL) {
+        p1+=sizeof("objecttype=")-1;
+        l=sizeof (info->model);
+
+        ret = unescape_string (info->type,
+                        p1, &l, ';');
+        if (ret < 0) {
+                goto cleanup;
+        }
+    }
+
+    if (((p1=strstr(url, ";id="))!= NULL) || ((p1=strstr(url, ":id="))!= 
NULL)) {
+        p1+=sizeof(";id=")-1;
+
+        if ((p2=strchr(p1, ';'))== NULL) {
+            l = strlen(p1);
+        } else {
+            l = p2 - p1;
+        }
+
+        if (l > sizeof(info->id)-1) {
+            gnutls_assert();
+            ret = GNUTLS_E_PARSING_ERROR;
+        }
+
+        memcpy(info->id, p1, l);
+        info->id[l] = 0;
+
+        /* convert to raw */
+        info->certid_raw_size = sizeof(info->certid_raw);
+        ret = _gnutls_hex2bin(info->id, strlen(info->id), info->certid_raw, 
&info->certid_raw_size);
+        if (ret < 0) {
+            gnutls_assert();
+            goto cleanup;
+        }
+    }
+    
+    ret = 0;
+   
+cleanup:
+
+    return ret;
+
+}
+
+#define INVALID_CHARS       "\\/\"'%&address@hidden <>{}[]()`|:;,.+-"
+
+static int append(gnutls_string* dest, const char* tname, const char* p11name, 
int init)
+{
+        gnutls_string tmpstr;
+        int ret;
+
+        _gnutls_string_init(&tmpstr, gnutls_malloc, gnutls_realloc, 
gnutls_free);
+        if ((ret=_gnutls_string_append_str(&tmpstr, tname))<0) {
+                gnutls_assert();
+                goto cleanup;
+        }
+
+        ret = _gnutls_string_escape(&tmpstr, INVALID_CHARS);
+        if (ret < 0) {
+                gnutls_assert();
+                goto cleanup;
+        }
+
+        if ((ret=_gnutls_string_append_data(&tmpstr, "", 1)) < 0) {
+                gnutls_assert();
+                goto cleanup;
+        }
+
+        if ((ret=_gnutls_string_append_printf(dest, "%s%s=%s", 
(init!=0)?";":"", p11name, tmpstr.data)) < 0) {
+                gnutls_assert();
+                goto cleanup;
+        }
+
+        ret = 0;
+
+cleanup:
+        _gnutls_string_clear(&tmpstr);
+
+        return ret;
+
+}
+
+
+int pkcs11_info_to_url(const struct pkcs11_url_info* info, char** url)
+{
+    gnutls_string str;
+    int init = 0;
+    int ret;
+    
+    _gnutls_string_init (&str, gnutls_malloc, gnutls_realloc, gnutls_free);
+
+    _gnutls_string_append_str(&str, "pkcs11:");
+
+    if (info->token[0]) {
+        ret = append(&str, info->token, "token", init);
+        if (ret < 0) {
+                gnutls_assert();
+                goto cleanup;
+        }
+        init = 1;
+    }
+
+    if (info->serial[0]) {
+        ret = append(&str, info->serial, "serial", init);
+        if (ret < 0) {
+                gnutls_assert();
+                goto cleanup;
+        }
+        init = 1;
+    }
+
+    if (info->model[0]) {
+        ret = append(&str, info->model, "model", init);
+        if (ret < 0) {
+                gnutls_assert();
+                goto cleanup;
+        }
+        init = 1;
+    }
+
+
+    if (info->manufacturer[0]) {
+        ret = append(&str, info->manufacturer, "manufacturer", init);
+        if (ret < 0) {
+                gnutls_assert();
+                goto cleanup;
+        }
+        init = 1;
+    }
+
+    if (info->label[0]) {
+        ret = append(&str, info->label, "object", init);
+        if (ret < 0) {
+                gnutls_assert();
+                goto cleanup;
+        }
+        init = 1;
+    }
+
+    if (info->type[0]) {
+        ret = append(&str, info->type, "objecttype", init);
+        if (ret < 0) {
+                gnutls_assert();
+                goto cleanup;
+        }
+        init = 1;
+    }
+
+    if (info->id[0] != 0) {
+        ret = _gnutls_string_append_printf(&str, ";id=%s", info->id);
+        if (ret < 0) {
+            gnutls_assert();
+            return ret;
+        }
+    }
+    
+    _gnutls_string_append_data(&str, "", 1);
+
+    *url = str.data;
+    
+    return 0;
+
+cleanup:
+    _gnutls_string_clear(&str);
+    return ret;
+}
+
+/**
+ * gnutls_pkcs11_obj_init:
+ * @crt: The structure to be initialized
+ *
+ * This function will initialize a pkcs11 certificate structure.
+ *
+ * Returns: On success, %GNUTLS_E_SUCCESS is returned, otherwise a
+ *   negative error value.
+ **/
+int gnutls_pkcs11_obj_init(gnutls_pkcs11_obj_t * crt)
+{
+    *crt = gnutls_calloc(1, sizeof(struct gnutls_pkcs11_obj_st));
+    if (*crt == NULL) {
+        gnutls_assert();
+        return GNUTLS_E_MEMORY_ERROR;
+    }
+ 
+    return 0;
+}
+
+/**
+ * gnutls_pkcs11_obj_deinit:
+ * @key: The structure to be initialized
+ *
+ * This function will deinitialize a certificate structure.
+ **/
+void gnutls_pkcs11_obj_deinit(gnutls_pkcs11_obj_t crt)
+{
+    _gnutls_free_datum(&crt->raw);
+    free(crt);
+}
+
+/**
+ * gnutls_pkcs11_obj_export:
+ * @key: Holds the object
+ * @output_data: will contain a certificate PEM or DER encoded
+ * @output_data_size: holds the size of output_data (and will be
+ *   replaced by the actual size of parameters)
+ *
+ * This function will export the pkcs11 object data. It is normal
+ * for PKCS #11 data to be inaccesible and in that case 
%GNUTLS_E_INVALID_REQUEST
+ * will be returned.
+ *
+ * If the buffer provided is not long enough to hold the output, then
+ * *output_data_size is updated and GNUTLS_E_SHORT_MEMORY_BUFFER will
+ * be returned.
+ *
+ * If the structure is PEM encoded, it will have a header
+ * of "BEGIN CERTIFICATE".
+ *
+ * Return value: In case of failure a negative value will be
+ *   returned, and 0 on success.
+ **/
+int
+gnutls_pkcs11_obj_export(gnutls_pkcs11_obj_t obj,
+                    void *output_data,
+                    size_t * output_data_size)
+{
+       if (obj == NULL || obj->raw.data == NULL) {
+               gnutls_assert();
+               return GNUTLS_E_INVALID_REQUEST;
+       }
+
+    if (output_data==NULL || *output_data_size < obj->raw.size) {
+        *output_data_size = obj->raw.size;
+        gnutls_assert();
+        return GNUTLS_E_SHORT_MEMORY_BUFFER;
+    }
+    *output_data_size = obj->raw.size;
+
+    memcpy(output_data, obj->raw.data, obj->raw.size);
+    return 0;
+}
+
+static void terminate_string(unsigned char *str, size_t len)
+{
+    unsigned char *ptr = str + len - 1;
+
+    while ((*ptr == ' ' || *ptr == '\t' || *ptr == '\0') && ptr >= str)
+        ptr--;
+
+    if (ptr == str - 1)
+        str[0] = '\0';
+    else if (ptr == str + len - 1)
+        str[len-1] = '\0';
+    else
+        ptr[1] = '\0';
+}
+
+int pkcs11_find_object (pakchois_session_t** _pks, ck_object_handle_t* _obj,
+    struct pkcs11_url_info *info, unsigned int flags)
+{
+int ret;
+pakchois_session_t *pks;
+ck_object_handle_t obj;
+ck_object_class_t class;
+struct ck_attribute a[4];
+int a_vals = 0;
+unsigned long count;
+ck_rv_t rv;
+
+    class = pkcs11_strtype_to_class(info->type);
+    if (class == -1) {
+        gnutls_assert();
+        return GNUTLS_E_INVALID_REQUEST;
+    }
+
+    ret = pkcs11_open_session (&pks, info, flags);
+    if (ret < 0) {
+        gnutls_assert();
+        return ret;
+    }
+
+       a[a_vals].type = CKA_CLASS;
+       a[a_vals].value = &class;
+       a[a_vals].value_len = sizeof class;
+    a_vals++;
+
+    if (info->certid_raw_size > 0) {
+        a[a_vals].type = CKA_ID;
+        a[a_vals].value = info->certid_raw;
+        a[a_vals].value_len = info->certid_raw_size;
+        a_vals++;
+    }
+
+       rv = pakchois_find_objects_init(pks, a, a_vals);
+       if (rv != CKR_OK) {
+               gnutls_assert();
+               _gnutls_debug_log("pk11: FindObjectsInit failed.\n");
+               ret = GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
+               goto fail;
+       }
+
+    if (pakchois_find_objects(pks, &obj, 1, &count) == CKR_OK
+              && count == 1) {
+            *_obj = obj;
+            *_pks = pks;
+            pakchois_find_objects_final(pks);
+            return 0;
+
+    }
+
+    pakchois_find_objects_final(pks);
+fail:
+    pakchois_close_session(pks);
+
+    return ret;
+}
+
+int pkcs11_open_session (pakchois_session_t** _pks, struct pkcs11_url_info 
*info, unsigned int flags)
+{
+    ck_rv_t rv;
+    int x, z, ret;
+    pakchois_session_t *pks = NULL;
+
+    for (x=0;x<active_providers;x++) {
+        for (z=0;z<providers[x].nslots;z++) {
+            struct token_info tinfo;
+
+            rv = pakchois_open_session(providers[x].module, 
providers[x].slots[z], 
+                ((flags&SESSION_WRITE)?CKF_RW_SESSION:0)|CKF_SERIAL_SESSION, 
NULL, NULL, &pks);
+            if (rv != CKR_OK) {
+                continue;
+            }
+
+            if (pakchois_get_token_info(providers[x].module, 
providers[x].slots[z], &tinfo.tinfo) != CKR_OK) {
+                goto next;
+            }
+            tinfo.sid = providers[x].slots[z];
+            tinfo.prov = &providers[x];
+
+            if (pakchois_get_slot_info(providers[x].module, 
providers[x].slots[z], &tinfo.sinfo) != CKR_OK) {
+                goto next;
+            }
+
+            /* XXX make wrapper for token_info? */
+            terminate_string(tinfo.tinfo.manufacturer_id, sizeof 
tinfo.tinfo.manufacturer_id);
+            terminate_string(tinfo.tinfo.label, sizeof tinfo.tinfo.label);
+            terminate_string(tinfo.tinfo.model, sizeof tinfo.tinfo.model);
+            terminate_string(tinfo.tinfo.serial_number, sizeof 
tinfo.tinfo.serial_number);
+
+            if (pkcs11_token_matches_info( info, &tinfo.tinfo) < 0) {
+                goto next;
+            }
+
+            if (flags&SESSION_LOGIN) {
+                ret = pkcs11_login(pks, &tinfo);
+                if (ret < 0) {
+                    gnutls_assert();
+                    pakchois_close_session(pks);
+                    return ret;
+                }
+            }
+
+            /* ok found */
+            *_pks = pks;
+            return 0;
+            
+next:
+            pakchois_close_session(pks);
+        }
+    }
+
+    return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
+}
+
+
+int _pkcs11_traverse_tokens (find_func_t find_func, void* input, 
+    unsigned int flags)
+{
+    ck_rv_t rv;
+    int found = 0, x, z, ret;
+    pakchois_session_t *pks = NULL;
+
+    for (x=0;x<active_providers;x++) {
+        for (z=0;z<providers[x].nslots;z++) {
+            struct token_info info;
+
+            ret = GNUTLS_E_PKCS11_ERROR;
+
+            rv = pakchois_open_session(providers[x].module, 
providers[x].slots[z], 
+                ((flags&SESSION_WRITE)?CKF_RW_SESSION:0)|CKF_SERIAL_SESSION, 
NULL, NULL, &pks);
+            if (rv != CKR_OK) {
+                continue;
+            }
+
+            if (pakchois_get_token_info(providers[x].module, 
providers[x].slots[z], &info.tinfo) != CKR_OK) {
+                goto next;
+            }
+            info.sid = providers[x].slots[z];
+            info.prov = &providers[x];
+
+            if (pakchois_get_slot_info(providers[x].module, 
providers[x].slots[z], &info.sinfo) != CKR_OK) {
+                goto next;
+            }
+
+            /* XXX make wrapper for token_info? */
+            terminate_string(info.tinfo.manufacturer_id, sizeof 
info.tinfo.manufacturer_id);
+            terminate_string(info.tinfo.label, sizeof info.tinfo.label);
+            terminate_string(info.tinfo.model, sizeof info.tinfo.model);
+            terminate_string(info.tinfo.serial_number, sizeof 
info.tinfo.serial_number);
+
+            ret = find_func(pks, &info, input);
+            
+            next:
+            
+            if (ret == 0) {
+                found = 1;
+                goto finish;
+            } else {
+                pakchois_close_session(pks);
+                pks = NULL;
+            }
+        }
+    }
+
+finish:
+    /* final call */
+
+    if (found == 0) {
+        ret = find_func(pks, NULL, input);
+    } else {
+        ret = 0;
+    }
+
+    if (pks != NULL) {
+        pakchois_close_session(pks);
+    }
+   
+    return ret;
+}
+
+static const char* pkcs11_obj_type_to_str(gnutls_pkcs11_obj_type_t type)
+{
+    switch(type) {
+        case GNUTLS_PKCS11_OBJ_X509_CRT:
+            return "cert";
+        case GNUTLS_PKCS11_OBJ_PUBKEY:
+            return "public";
+        case GNUTLS_PKCS11_OBJ_PRIVKEY:
+            return "private";
+        case GNUTLS_PKCS11_OBJ_SECRET_KEY:
+            return "secretkey";
+        case GNUTLS_PKCS11_OBJ_DATA:
+            return "data";
+        case GNUTLS_PKCS11_OBJ_UNKNOWN:
+        default:
+            return "unknown";
+    }
+}
+
+/* imports a raw certificate from a token to a pkcs11_obj_t structure.
+ */
+static int pkcs11_obj_import(unsigned int class, gnutls_pkcs11_obj_t crt, 
const gnutls_datum_t* data, 
+   const gnutls_datum_t * id, const gnutls_datum_t * label, struct 
ck_token_info* tinfo)
+{
+    char *s;
+    int ret;
+
+    switch(class) {
+        case CKO_CERTIFICATE:
+            crt->type = GNUTLS_PKCS11_OBJ_X509_CRT;
+            break;
+        case CKO_PUBLIC_KEY:
+            crt->type = GNUTLS_PKCS11_OBJ_PUBKEY;
+            break;
+        case CKO_PRIVATE_KEY:
+            crt->type = GNUTLS_PKCS11_OBJ_PRIVKEY;
+            break;
+        case CKO_SECRET_KEY:
+            crt->type = GNUTLS_PKCS11_OBJ_SECRET_KEY;
+            break;
+        case CKO_DATA:
+            crt->type = GNUTLS_PKCS11_OBJ_DATA;
+            break;
+        default:
+            crt->type = GNUTLS_PKCS11_OBJ_UNKNOWN;
+    }
+
+    if (crt->type != GNUTLS_PKCS11_OBJ_UNKNOWN)
+        strcpy(crt->info.type, pkcs11_obj_type_to_str(crt->type));
+
+    if (data && data->data) {
+        ret = _gnutls_set_datum(&crt->raw, data->data, data->size);
+        if (ret < 0) {
+            gnutls_assert();
+            return ret;
+        }
+    }
+
+    terminate_string(tinfo->manufacturer_id, sizeof tinfo->manufacturer_id);
+    terminate_string(tinfo->label, sizeof tinfo->label);
+    terminate_string(tinfo->model, sizeof tinfo->model);
+    terminate_string(tinfo->serial_number, sizeof tinfo->serial_number);
+
+    /* write data */
+    snprintf(crt->info.manufacturer, sizeof(crt->info.manufacturer), "%s", 
tinfo->manufacturer_id);
+    snprintf(crt->info.token, sizeof(crt->info.token), "%s", tinfo->label);
+    snprintf(crt->info.model, sizeof(crt->info.model), "%s", tinfo->model);
+    snprintf(crt->info.serial, sizeof(crt->info.serial), "%s", 
tinfo->serial_number);
+
+    if (label && label->data) {
+        memcpy(crt->info.label, label->data, label->size);
+        crt->info.label[label->size] = 0;
+    }
+
+    if (id && id->data) {
+        s = _gnutls_bin2hex(id->data, id->size, crt->info.id, 
sizeof(crt->info.id), ":");
+        if (s == NULL) {
+            gnutls_assert();
+            return GNUTLS_E_PKCS11_ERROR;
+        }
+    
+        memmove(crt->info.certid_raw, id->data, id->size);
+        crt->info.certid_raw_size = id->size;
+    }
+
+    return 0;
+}
+
+static int pkcs11_obj_import_pubkey(pakchois_session_t *pks, 
ck_object_handle_t obj,
+    gnutls_pkcs11_obj_t crt, const gnutls_datum_t * id,
+    const gnutls_datum_t* label, struct ck_token_info* tinfo)
+{
+
+    struct ck_attribute a[4];
+    ck_key_type_t key_type;
+    opaque tmp1[2048];
+    opaque tmp2[2048];
+    int ret;
+    unsigned int tval;
+
+    a[0].type = CKA_KEY_TYPE;
+    a[0].value = &key_type;
+    a[0].value_len = sizeof(key_type);
+
+    if (pakchois_get_attribute_value(pks, obj, a, 1) == CKR_OK) {
+        switch(key_type) {
+            case CKK_RSA:
+                a[0].type = CKA_MODULUS;
+                a[0].value = tmp1;
+                a[0].value_len = sizeof(tmp1);
+                a[1].type = CKA_PUBLIC_EXPONENT;
+                a[1].value = tmp2;
+                a[1].value_len = sizeof(tmp2);
+
+                if (pakchois_get_attribute_value(pks, obj, a, 2) == CKR_OK) {
+
+                    ret = _gnutls_set_datum(&crt->pubkey[0], a[0].value, 
a[0].value_len);
+
+                    if (ret >= 0)
+                        ret = _gnutls_set_datum(&crt->pubkey[1], a[1].value, 
a[1].value_len);
+
+                    if (ret < 0) {
+                        gnutls_assert();
+                        _gnutls_free_datum(&crt->pubkey[1]);
+                        _gnutls_free_datum(&crt->pubkey[0]);
+                        return GNUTLS_E_MEMORY_ERROR;
+                    }
+                } else {
+                    gnutls_assert();
+                    return GNUTLS_E_PKCS11_ERROR;
+                }
+                crt->pk_algorithm = GNUTLS_PK_RSA;
+                break;
+            case CKK_DSA:
+                a[0].type = CKA_PRIME;
+                a[0].value = tmp1;
+                a[0].value_len = sizeof(tmp1);
+                a[1].type = CKA_SUBPRIME;
+                a[1].value = tmp2;
+                a[1].value_len = sizeof(tmp2);
+
+                if (pakchois_get_attribute_value(pks, obj, a, 2) == CKR_OK) {
+                    ret = _gnutls_set_datum(&crt->pubkey[0], a[0].value, 
a[0].value_len);
+
+                    if (ret >= 0)
+                        ret = _gnutls_set_datum(&crt->pubkey[1], a[1].value, 
a[1].value_len);
+
+                    if (ret < 0) {
+                        gnutls_assert();
+                        _gnutls_free_datum(&crt->pubkey[1]);
+                        _gnutls_free_datum(&crt->pubkey[0]);
+                        return GNUTLS_E_MEMORY_ERROR;
+                    }
+                } else {
+                    gnutls_assert();
+                    return GNUTLS_E_PKCS11_ERROR;
+                }
+
+                a[0].type = CKA_BASE;
+                a[0].value = tmp1;
+                a[0].value_len = sizeof(tmp1);
+                a[1].type = CKA_VALUE;
+                a[1].value = tmp2;
+                a[1].value_len = sizeof(tmp2);
+
+                if (pakchois_get_attribute_value(pks, obj, a, 2) == CKR_OK) {
+                    ret = _gnutls_set_datum(&crt->pubkey[2], a[0].value, 
a[0].value_len);
+
+                    if (ret >= 0)
+                        ret = _gnutls_set_datum(&crt->pubkey[3], a[1].value, 
a[1].value_len);
+
+                    if (ret < 0) {
+                        gnutls_assert();
+                        _gnutls_free_datum(&crt->pubkey[0]);
+                        _gnutls_free_datum(&crt->pubkey[1]);
+                        _gnutls_free_datum(&crt->pubkey[2]);
+                        _gnutls_free_datum(&crt->pubkey[3]);
+                        return GNUTLS_E_MEMORY_ERROR;
+                    }
+                } else {
+                    gnutls_assert();
+                    return GNUTLS_E_PKCS11_ERROR;
+                }
+                crt->pk_algorithm = GNUTLS_PK_RSA;
+                break;
+            default:
+                gnutls_assert();
+                return GNUTLS_E_UNIMPLEMENTED_FEATURE;
+        }
+    }
+
+    /* read key usage flags */
+    a[0].type = CKA_ENCRYPT;
+    a[0].value = &tval;
+    a[0].value_len = sizeof(tval);
+
+    if (pakchois_get_attribute_value(pks, obj, a, 1) == CKR_OK) {
+        if (tval != 0) {
+            crt->key_usage |= GNUTLS_KEY_DATA_ENCIPHERMENT;
+        }
+    }
+
+    a[0].type = CKA_VERIFY;
+    a[0].value = &tval;
+    a[0].value_len = sizeof(tval);
+
+    if (pakchois_get_attribute_value(pks, obj, a, 1) == CKR_OK) {
+        if (tval != 0) {
+            crt->key_usage |= GNUTLS_KEY_DIGITAL_SIGNATURE| \
+            
GNUTLS_KEY_KEY_CERT_SIGN|GNUTLS_KEY_CRL_SIGN|GNUTLS_KEY_NON_REPUDIATION;
+        }
+    }
+
+    a[0].type = CKA_VERIFY_RECOVER;
+    a[0].value = &tval;
+    a[0].value_len = sizeof(tval);
+
+    if (pakchois_get_attribute_value(pks, obj, a, 1) == CKR_OK) {
+        if (tval != 0) {
+            crt->key_usage |= GNUTLS_KEY_DIGITAL_SIGNATURE| \
+            
GNUTLS_KEY_KEY_CERT_SIGN|GNUTLS_KEY_CRL_SIGN|GNUTLS_KEY_NON_REPUDIATION;
+        }
+    }
+
+    a[0].type = CKA_DERIVE;
+    a[0].value = &tval;
+    a[0].value_len = sizeof(tval);
+
+    if (pakchois_get_attribute_value(pks, obj, a, 1) == CKR_OK) {
+        if (tval != 0) {
+            crt->key_usage |= GNUTLS_KEY_KEY_AGREEMENT;
+        }
+    }
+
+    a[0].type = CKA_WRAP;
+    a[0].value = &tval;
+    a[0].value_len = sizeof(tval);
+
+    if (pakchois_get_attribute_value(pks, obj, a, 1) == CKR_OK) {
+        if (tval != 0) {
+            crt->key_usage |= GNUTLS_KEY_KEY_ENCIPHERMENT;
+        }
+    }
+
+    return pkcs11_obj_import(CKO_PUBLIC_KEY, crt, NULL, id, label, tinfo);
+}
+
+ck_object_class_t pkcs11_strtype_to_class(const char* type)
+{
+    ck_object_class_t class;
+    
+    if (strcmp(type, "cert") == 0) {
+        class = CKO_CERTIFICATE;
+    } else if (strcmp(type, "public") == 0) {
+        class = CKO_PUBLIC_KEY;
+    } else if (strcmp(type, "private") == 0) {
+        class = CKO_PRIVATE_KEY;
+    } else if (strcmp(type, "secretkey") == 0) {
+        class = CKO_SECRET_KEY;
+    } else if (strcmp(type, "data") == 0) {
+        class = CKO_DATA;
+    } else {
+        class = -1;
+    }
+    
+    return class;
+}
+
+
+static int find_obj_url(pakchois_session_t *pks, struct token_info *info, 
void* input)
+{
+    struct url_find_data_st* find_data = input;
+    struct ck_attribute a[4];
+    ck_object_class_t class = -1;
+    ck_certificate_type_t type = -1;
+    ck_rv_t rv;
+    ck_object_handle_t obj;
+    unsigned long count, a_vals;
+    int found = 0, ret;
+    opaque* cert_data = NULL;
+    char label_tmp[PKCS11_LABEL_SIZE];
+    
+    if (info == NULL) { /* we don't support multiple calls */
+        gnutls_assert();
+        return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
+    }
+    
+    /* do not bother reading the token if basic fields do not match
+     */
+    if (pkcs11_token_matches_info( &find_data->crt->info, &info->tinfo) < 0) {
+               gnutls_assert();
+               return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
+       }
+
+    if (find_data->crt->info.type[0] != 0) {
+        class = pkcs11_strtype_to_class(find_data->crt->info.type);
+        if (class == CKO_CERTIFICATE)
+            type = CKC_X_509;
+
+        if (class == -1) {
+            gnutls_assert();
+            return GNUTLS_E_INVALID_REQUEST;
+        }
+    }
+
+    /* search the token for the id */
+    
+    cert_data = gnutls_malloc(MAX_CERT_SIZE);
+    if (cert_data == NULL) {
+        gnutls_assert();
+        return GNUTLS_E_MEMORY_ERROR;
+    }
+    
+    /* Find objects with given class and type */
+
+    a[0].type = CKA_ID;
+    a[0].value = find_data->crt->info.certid_raw;
+    a[0].value_len = find_data->crt->info.certid_raw_size;
+    
+    a_vals = 1;
+
+    if (class != -1) {
+        a[a_vals].type = CKA_CLASS;
+        a[a_vals].value = &class;
+        a[a_vals].value_len = sizeof class;
+        a_vals++;
+    }
+    
+    if (type != -1) {
+        a[a_vals].type = CKA_CERTIFICATE_TYPE;
+        a[a_vals].value = &type;
+        a[a_vals].value_len = sizeof type;
+        a_vals++;
+    }
+
+    rv = pakchois_find_objects_init(pks, a, a_vals);
+    if (rv != CKR_OK) {
+        gnutls_assert();
+        _gnutls_debug_log("pk11: FindObjectsInit failed.\n");
+        ret = GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
+        goto cleanup;
+    }
+
+    while (pakchois_find_objects(pks, &obj, 1, &count) == CKR_OK
+           && count == 1) {
+
+        a[0].type = CKA_VALUE;
+        a[0].value = cert_data;
+        a[0].value_len = MAX_CERT_SIZE;
+        a[1].type = CKA_LABEL;
+        a[1].value = label_tmp;
+        a[1].value_len = sizeof(label_tmp);
+
+        if (pakchois_get_attribute_value(pks, obj, a, 2) == CKR_OK) {
+            gnutls_datum_t id = { find_data->crt->info.certid_raw, 
find_data->crt->info.certid_raw_size };
+            gnutls_datum_t data = { a[0].value, a[0].value_len };
+            gnutls_datum_t label = { a[1].value, a[1].value_len };
+            
+            if (class == CKO_PUBLIC_KEY) {
+                ret = pkcs11_obj_import_pubkey(pks, obj, find_data->crt, &id, 
&label, &info->tinfo);
+            } else {
+                ret = pkcs11_obj_import(class, find_data->crt, &data, &id, 
&label, &info->tinfo);
+            }
+            if (ret < 0) {
+                gnutls_assert();
+                goto cleanup;
+            }
+
+            found = 1;
+            break;
+        }
+        else {
+            _gnutls_debug_log("pk11: Skipped cert, missing attrs.\n");
+        }
+    }
+
+    if (found == 0) {
+        gnutls_assert();
+        ret = GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
+    } else {
+        ret = 0;
+    }
+
+cleanup:
+    gnutls_free(cert_data);
+    pakchois_find_objects_final(pks);
+    
+    return ret;
+}
+
+/**
+ * gnutls_pkcs11_privkey_import_url:
+ * @cert: The structure to store the parsed certificate
+ * @url: a PKCS 11 url identifying the key
+ *
+ * This function will "import" a PKCS 11 URL identifying a certificate
+ * key to the #gnutls_pkcs11_obj_t structure. This does not involve any
+ * parsing (such as X.509 or OpenPGP) since the #gnutls_pkcs11_obj_t is
+ * format agnostic. Only data are transferred.
+ *
+ * Returns: On success, %GNUTLS_E_SUCCESS is returned, otherwise a
+ *   negative error value.
+ **/
+int gnutls_pkcs11_obj_import_url (gnutls_pkcs11_obj_t cert, const char * url)
+{
+    int ret;
+    struct url_find_data_st find_data;
+    
+    /* fill in the find data structure */
+    find_data.crt = cert;
+
+    ret = pkcs11_url_to_info(url, &cert->info);
+    if (ret < 0) {
+        gnutls_assert();
+        return ret;
+    }
+
+    ret = _pkcs11_traverse_tokens(find_obj_url, &find_data, 0);
+    if (ret < 0) {
+        gnutls_assert();
+        return ret;
+    }
+    
+    return 0;
+}
+
+struct token_num {
+    struct pkcs11_url_info info;
+    unsigned int seq; /* which one we are looking for */
+    unsigned int current; /* which one are we now */
+};
+
+static int find_token_num(pakchois_session_t *pks, struct token_info *tinfo, 
void* input)
+{
+    struct token_num* find_data = input;
+
+    if (tinfo == NULL) { /* we don't support multiple calls */
+        gnutls_assert();
+        return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
+    }
+
+    if (find_data->current == find_data->seq) {
+        strcpy(find_data->info.manufacturer, tinfo->tinfo.manufacturer_id);
+        strcpy(find_data->info.token, tinfo->tinfo.label);
+        strcpy(find_data->info.model, tinfo->tinfo.model);
+        strcpy(find_data->info.serial, tinfo->tinfo.serial_number);
+
+        return 0;
+    }
+
+    find_data->current++;
+    /* search the token for the id */
+
+
+    return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE; /* non zero is enough */
+}
+
+/**
+ * gnutls_pkcs11_token_get_url:
+ * @seq: sequence number starting from 0
+ * @url: will contain an allocated url
+ *
+ * This function will return the URL for each token available
+ * in system. The url has to be released using gnutls_free()
+ *
+ * Returns: On success, %GNUTLS_E_SUCCESS is returned, 
%GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE
+ * if the sequence number exceeds the available tokens, otherwise a negative 
error value.
+ **/
+
+int gnutls_pkcs11_token_get_url (unsigned int seq, char** url)
+{
+    int ret;
+    struct token_num tn;
+
+    memset(&tn, 0, sizeof(tn));
+    tn.seq = seq;
+    
+    ret = _pkcs11_traverse_tokens(find_token_num, &tn, 0);
+    if (ret < 0) {
+        gnutls_assert();
+        return ret;
+    }
+
+    ret = pkcs11_info_to_url(&tn.info, url);
+    if (ret < 0) {
+        gnutls_assert();
+        return ret;
+    }
+
+    return 0;
+
+}
+
+/**
+ * gnutls_pkcs11_token_get_info:
+ * @url: should contain a PKCS 11 URL
+ * @itype: Denotes the type of information requested
+ * @output: where output will be stored
+ * @output_size: contains the maximum size of the output and will be 
overwritten with actual
+ *
+ * This function will return information about the PKCS 11 token such
+ * as the label, id as well as token information where the key is stored.
+ *
+ * Returns: zero on success or a negative value on error.
+ **/
+int gnutls_pkcs11_token_get_info(const char* url, gnutls_pkcs11_token_info_t 
ttype, void* output, size_t *output_size)
+{
+    const char* str;
+    size_t len;
+    struct pkcs11_url_info info;
+    int ret;
+
+    ret = pkcs11_url_to_info(url, &info);
+    if (ret < 0) {
+        gnutls_assert();
+        return ret;
+    }
+
+    switch(ttype) {
+        case GNUTLS_PKCS11_TOKEN_LABEL:
+            str = info.token;
+            break;
+        case GNUTLS_PKCS11_TOKEN_SERIAL:
+            str = info.serial;
+            break;
+        case GNUTLS_PKCS11_TOKEN_MANUFACTURER:
+            str = info.manufacturer;
+            break;
+        case GNUTLS_PKCS11_TOKEN_MODEL:
+            str = info.model;
+            break;
+        default:
+            gnutls_assert();
+            return GNUTLS_E_INVALID_REQUEST;
+    }
+
+    len = strlen(str);
+
+    if (len+1>*output_size) {
+        *output_size = len+1;
+        return GNUTLS_E_SHORT_MEMORY_BUFFER;
+    }
+
+    strcpy(output, str);
+
+    *output_size = len;
+
+    return 0;
+}
+
+/**
+ * gnutls_pkcs11_obj_export_url:
+ * @crt: Holds the PKCS 11 certificate
+ * @url: will contain an allocated url
+ *
+ * This function will export a URL identifying the given certificate.
+ *
+ * Returns: On success, %GNUTLS_E_SUCCESS is returned, otherwise a
+ *   negative error value.
+ **/
+int gnutls_pkcs11_obj_export_url (gnutls_pkcs11_obj_t cert, char ** url)
+{
+int ret;
+
+    ret = pkcs11_info_to_url(&cert->info, url);
+    if (ret < 0) {
+        gnutls_assert();
+        return ret;
+    }
+    
+    return 0;
+}
+
+/**
+ * gnutls_pkcs11_obj_get_type:
+ * @certificate: Holds the PKCS 11 certificate
+ *
+ * This function will return the type of the certificate being
+ * stored in the structure.
+ *
+ * Returns: The type of the certificate.
+ **/
+gnutls_pkcs11_obj_type_t gnutls_pkcs11_obj_get_type (gnutls_pkcs11_obj_t obj)
+{
+    return obj->type;
+}
+
+struct pkey_list {
+    gnutls_string *key_ids;
+    size_t key_ids_size;
+};
+
+int pkcs11_login(pakchois_session_t *pks, struct token_info *info)
+{
+    int attempt = 0;
+    ck_rv_t rv;
+
+    if (pakchois_get_token_info(info->prov->module, info->sid, &info->tinfo) 
!= CKR_OK) {
+        gnutls_assert();
+        _gnutls_debug_log( "pk11: GetTokenInfo failed\n");
+        return GNUTLS_E_PKCS11_ERROR;
+    }
+
+    /* force login on HW tokens. Some tokens will not list private keys
+     * if login has not been performed.
+     */
+    if ((info->tinfo.flags & CKF_LOGIN_REQUIRED) == 0) {
+        gnutls_assert();
+        _gnutls_debug_log( "pk11: No login required.\n");
+        return 0;
+    }
+
+    /* For a token with a "protected" (out-of-band) authentication
+     * path, calling login with a NULL username is all that is
+     * required. */
+    if (info->tinfo.flags & CKF_PROTECTED_AUTHENTICATION_PATH) {
+        if (pakchois_login(pks, CKU_USER, NULL, 0) == CKR_OK) {
+            return 0;
+        }
+        else {
+            gnutls_assert();
+            _gnutls_debug_log( "pk11: Protected login failed.\n");
+            return GNUTLS_E_PKCS11_ERROR;
+        }
+    }
+
+    /* Otherwise, PIN entry is necessary for login, so fail if there's
+     * no callback. */
+    if (!pin_func) {
+        gnutls_assert();
+        _gnutls_debug_log("pk11: No pin callback but login required.\n");
+        return GNUTLS_E_PKCS11_ERROR;
+    }
+
+    terminate_string(info->sinfo.slot_description, sizeof 
info->sinfo.slot_description);
+
+    do {
+        char pin[GNUTLS_PKCS11_MAX_PIN_LEN];
+        unsigned int flags = 0;
+
+        /* If login has been attempted once already, check the token
+         * status again, the flags might change. */
+        if (attempt) {
+            if (pakchois_get_token_info(info->prov->module, info->sid,
+                                        &info->tinfo) != CKR_OK) {
+                gnutls_assert();
+                _gnutls_debug_log( "pk11: GetTokenInfo failed\n");
+                return GNUTLS_E_PKCS11_ERROR;
+            }
+        }
+
+        if (info->tinfo.flags & CKF_USER_PIN_COUNT_LOW)
+            flags |= GNUTLS_PKCS11_PIN_COUNT_LOW;
+        if (info->tinfo.flags & CKF_USER_PIN_FINAL_TRY)
+            flags |= GNUTLS_PKCS11_PIN_FINAL_TRY;
+
+        terminate_string(info->tinfo.label, sizeof info->tinfo.label);
+
+        if (pin_func(pin_data, attempt++,
+                         (char *)info->sinfo.slot_description,
+                         (char *)info->tinfo.label, flags, pin, sizeof(pin))) {
+            gnutls_assert();
+            return GNUTLS_E_PKCS11_PIN_ERROR;
+        }
+
+        rv = pakchois_login(pks, CKU_USER, (unsigned char *)pin, strlen(pin));
+        /* Try to scrub the pin off the stack.  Clever compilers will
+         * probably optimize this away, oh well. */
+        memset(pin, 0, sizeof pin);
+    } while (rv == CKR_PIN_INCORRECT);
+
+    _gnutls_debug_log("pk11: Login result = %lu\n", rv);
+
+    return (rv == CKR_OK || rv == CKR_USER_ALREADY_LOGGED_IN) ? 0 : 
GNUTLS_E_PKCS11_ERROR;
+}
+
+static int find_privkeys(pakchois_session_t *pks, struct token_info* info, 
struct pkey_list *list)
+{
+    struct ck_attribute a[3];
+    ck_object_class_t class;
+    ck_rv_t rv;
+    ck_object_handle_t obj;
+    unsigned long count, current;
+    char certid_tmp[PKCS11_ID_SIZE];
+
+    class = CKO_PRIVATE_KEY;
+
+    /* Find an object with private key class and a certificate ID
+     * which matches the certificate. */
+    /* FIXME: also match the cert subject. */
+    a[0].type = CKA_CLASS;
+    a[0].value = &class;
+    a[0].value_len = sizeof class;
+
+    rv = pakchois_find_objects_init(pks, a, 1);
+    if (rv != CKR_OK) {
+        gnutls_assert();
+        return GNUTLS_E_PKCS11_ERROR;
+    }
+
+    list->key_ids_size = 0;
+    while (pakchois_find_objects(pks, &obj, 1, &count) == CKR_OK
+           && count == 1) {
+        list->key_ids_size++;
+    }
+
+    pakchois_find_objects_final(pks);
+
+    if (list->key_ids_size == 0) {
+        gnutls_assert();
+        return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
+    }
+
+    list->key_ids = gnutls_malloc(sizeof(gnutls_string)*list->key_ids_size);
+    if (list->key_ids == NULL) {
+        gnutls_assert();
+        return GNUTLS_E_MEMORY_ERROR;
+    }
+
+    /* actual search */
+    a[0].type = CKA_CLASS;
+    a[0].value = &class;
+    a[0].value_len = sizeof class;
+
+    rv = pakchois_find_objects_init(pks, a, 1);
+    if (rv != CKR_OK) {
+        gnutls_assert();
+        return GNUTLS_E_PKCS11_ERROR;
+    }
+
+    current = 0;
+    while (pakchois_find_objects(pks, &obj, 1, &count) == CKR_OK
+           && count == 1) {
+
+        a[0].type = CKA_ID;
+        a[0].value = certid_tmp;
+        a[0].value_len = sizeof(certid_tmp);
+
+        _gnutls_string_init(&list->key_ids[current], gnutls_malloc, 
gnutls_realloc, gnutls_free);
+
+        if (pakchois_get_attribute_value(pks, obj, a, 1) == CKR_OK) {
+            _gnutls_string_append_data(&list->key_ids[current], a[0].value, 
a[0].value_len);
+            current++;
+        }
+
+        if (current > list->key_ids_size)
+            break;
+    }
+
+    pakchois_find_objects_final(pks);
+
+    list->key_ids_size = current-1;
+
+    return 0;
+}
+
+/* Recover certificate list from tokens */
+
+
+static int find_objs(pakchois_session_t *pks, struct token_info *info, void* 
input)
+{
+    struct crt_find_data_st* find_data = input;
+    struct ck_attribute a[4];
+    ck_object_class_t class=-1;
+    ck_certificate_type_t type=-1;
+    unsigned int trusted;
+    ck_rv_t rv;
+    ck_object_handle_t obj;
+    unsigned long count;
+    opaque *cert_data;
+    char certid_tmp[PKCS11_ID_SIZE];
+    char label_tmp[PKCS11_LABEL_SIZE];
+    int ret, i;
+    struct pkey_list plist; /* private key holder */
+    int tot_values = 0;
+
+    if (info == NULL) { /* final call */
+        if (find_data->current <= *find_data->n_list)
+            ret = 0;
+        else
+            ret = GNUTLS_E_SHORT_MEMORY_BUFFER;
+
+        *find_data->n_list = find_data->current;
+        
+        return ret;
+    }
+
+    /* do not bother reading the token if basic fields do not match
+     */
+    if (pkcs11_token_matches_info( &find_data->info, &info->tinfo) < 0) {
+               gnutls_assert();
+               return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
+       }
+
+    if (find_data->info.type[0] != 0) {
+        class = pkcs11_strtype_to_class(find_data->info.type);
+        if (class == CKO_CERTIFICATE)
+            type = CKC_X_509;
+        else
+            type = -1;
+
+        if (class == -1) {
+            gnutls_assert();
+            return GNUTLS_E_INVALID_REQUEST;
+        }
+    }
+    
+
+    memset(&plist, 0, sizeof(plist));
+
+    if (find_data->flags==GNUTLS_PKCS11_OBJ_ATTR_CRT_WITH_PRIVKEY) {
+        ret = pkcs11_login(pks, info);
+        if (ret < 0) {
+            gnutls_assert();
+            return ret;
+        }
+
+        ret = find_privkeys(pks, info, &plist);
+        if (ret < 0) {
+            gnutls_assert();
+            return ret;
+        }
+
+        if (plist.key_ids_size == 0) {
+            gnutls_assert();
+            return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
+        }
+    } else if (find_data->flags==GNUTLS_PKCS11_OBJ_ATTR_ALL) {
+        ret = pkcs11_login(pks, info);
+        if (ret < 0) {
+            gnutls_assert();
+            return ret;
+        }
+    }
+
+    cert_data = gnutls_malloc(MAX_CERT_SIZE);
+    if (cert_data == NULL) {
+        gnutls_assert();
+        return GNUTLS_E_MEMORY_ERROR;
+    }
+
+    /* Find objects with cert class and X.509 cert type. */
+    
+    tot_values = 0;
+
+    if (find_data->flags == GNUTLS_PKCS11_OBJ_ATTR_CRT_ALL || 
find_data->flags==GNUTLS_PKCS11_OBJ_ATTR_CRT_WITH_PRIVKEY) {
+        class = CKO_CERTIFICATE;
+        type = CKC_X_509;
+        trusted = 1;
+
+        a[tot_values].type = CKA_CLASS;
+        a[tot_values].value = &class;
+        a[tot_values].value_len = sizeof class;
+        tot_values++;
+
+        a[tot_values].type = CKA_CERTIFICATE_TYPE;
+        a[tot_values].value = &type;
+        a[tot_values].value_len = sizeof type;
+        tot_values++;
+        
+    } else if (find_data->flags == GNUTLS_PKCS11_OBJ_ATTR_CRT_TRUSTED) {
+        class = CKO_CERTIFICATE;
+        type = CKC_X_509;
+        trusted = 1;
+
+        a[tot_values].type = CKA_CLASS;
+        a[tot_values].value = &class;
+        a[tot_values].value_len = sizeof class;
+        tot_values++;
+        
+        a[tot_values].type = CKA_TRUSTED;
+        a[tot_values].value = &trusted;
+        a[tot_values].value_len = sizeof trusted;
+        tot_values++;
+        
+    } else if (find_data->flags == GNUTLS_PKCS11_OBJ_ATTR_PUBKEY) {
+        class = CKO_PUBLIC_KEY;
+
+        a[tot_values].type = CKA_CLASS;
+        a[tot_values].value = &class;
+        a[tot_values].value_len = sizeof class;
+        tot_values++;
+    } else if (find_data->flags == GNUTLS_PKCS11_OBJ_ATTR_ALL) {
+        if (class != -1) {
+            a[tot_values].type = CKA_CLASS;
+            a[tot_values].value = &class;
+            a[tot_values].value_len = sizeof class;
+            tot_values++;
+        }
+        if (type != -1) {
+            a[tot_values].type = CKA_CERTIFICATE_TYPE;
+            a[tot_values].value = &type;
+            a[tot_values].value_len = sizeof type;
+            tot_values++;
+        }
+    } else {
+        gnutls_assert();
+        ret = GNUTLS_E_INVALID_REQUEST;
+        goto fail;
+    }
+    
+    if (find_data->info.certid_raw_size != 0) {
+        a[tot_values].type = CKA_ID;
+        a[tot_values].value = find_data->info.certid_raw;
+        a[tot_values].value_len = find_data->info.certid_raw_size;
+        tot_values++;
+    }
+
+    rv = pakchois_find_objects_init(pks, a, tot_values);
+    if (rv != CKR_OK) {
+        gnutls_assert();
+        _gnutls_debug_log("pk11: FindObjectsInit failed.\n");
+        return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
+    }
+
+    while (pakchois_find_objects(pks, &obj, 1, &count) == CKR_OK
+           && count == 1) {
+        gnutls_datum_t label, id, value;
+
+        a[0].type = CKA_LABEL;
+        a[0].value = label_tmp;
+        a[0].value_len = sizeof label_tmp;
+
+        if (pakchois_get_attribute_value(pks, obj, a, 1) == CKR_OK) {
+            label.data = a[0].value;
+            label.size = a[0].value_len;
+        } else {
+            label.data = NULL;
+            label.size = 0;
+        }
+
+        a[0].type = CKA_ID;
+        a[0].value = certid_tmp;
+        a[0].value_len = sizeof certid_tmp;
+
+        if (pakchois_get_attribute_value(pks, obj, a, 1) == CKR_OK) {
+            id.data = a[0].value;
+            id.size = a[0].value_len;
+        } else {
+            id.data = NULL;
+            id.size = 0;
+        }        
+
+        a[0].type = CKA_VALUE;
+        a[0].value = cert_data;
+        a[0].value_len = MAX_CERT_SIZE;
+        if (pakchois_get_attribute_value(pks, obj, a, 1) == CKR_OK) {
+            value.data = a[0].value;
+            value.size = a[0].value_len;
+        } else {
+            value.data = NULL;
+            value.size = 0;
+        }        
+
+        if (find_data->flags == GNUTLS_PKCS11_OBJ_ATTR_ALL) {
+            a[0].type = CKA_CLASS;
+            a[0].value = &class;
+            a[0].value_len = sizeof class;
+
+            pakchois_get_attribute_value(pks, obj, a, 1);
+        }
+
+        if (find_data->flags == GNUTLS_PKCS11_OBJ_ATTR_CRT_WITH_PRIVKEY) {
+            for (i=0;i<plist.key_ids_size;i++) {
+                if (plist.key_ids[i].length != a[1].value_len || 
memcmp(plist.key_ids[i].data, a[1].value, a[1].value_len)!=0) {
+                    /* not found */
+                    continue;
+                }
+            }
+        }
+
+        if (find_data->current < *find_data->n_list) {
+            ret = 
gnutls_pkcs11_obj_init(&find_data->p_list[find_data->current]);
+            if (ret < 0) {
+                gnutls_assert();
+                goto fail;
+            }
+
+           if (class == CKO_PUBLIC_KEY) {
+                ret = pkcs11_obj_import_pubkey(pks, obj, 
find_data->p_list[find_data->current], &id, &label, &info->tinfo);
+            } else {
+                ret = pkcs11_obj_import(class, 
find_data->p_list[find_data->current], &value, &id, &label, &info->tinfo);
+            }
+            if (ret < 0) {
+                gnutls_assert();
+                goto fail;
+            }
+        }
+                
+        find_data->current++;
+
+    }
+
+    gnutls_free(cert_data);
+    pakchois_find_objects_final(pks);
+   
+    return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE; /* continue until all tokens 
have been checked */
+
+fail:
+    gnutls_free(cert_data);
+    pakchois_find_objects_final(pks);
+    if (plist.key_ids != NULL) {
+        for (i=0;i<plist.key_ids_size;i++) {
+            _gnutls_string_clear(&plist.key_ids[i]);
+        }
+        gnutls_free( plist.key_ids);
+    }
+    for (i=0;i<find_data->current;i++) {
+        gnutls_pkcs11_obj_deinit(find_data->p_list[i]);
+    }
+    find_data->current = 0;
+
+    return ret;
+}
+
+/**
+ * gnutls_pkcs11_obj_list_import_url:
+ * @p_list: An uninitialized certificate list (may be NULL)
+ * @n_list: initially should hold the maximum size of the list. Will contain 
the actual size.
+ * @url: A PKCS 11 url identifying a set of certificates
+ * @flags: Attributes of type #gnutls_pkcs11_obj_attr_t that can be used to 
limit output
+ *
+ * This function will initialize and set value to a certificate list
+ * specified by a PKCS 11 URL.
+ *
+ * Returns: On success, %GNUTLS_E_SUCCESS is returned, otherwise a
+ *   negative error value.
+ **/
+int gnutls_pkcs11_obj_list_import_url (gnutls_pkcs11_obj_t * p_list, unsigned 
int *n_list, const char* url, gnutls_pkcs11_obj_attr_t flags)
+{
+    int ret;
+    struct crt_find_data_st find_data;
+
+    /* fill in the find data structure */
+    find_data.p_list = p_list;
+    find_data.n_list = n_list;
+    find_data.flags = flags;
+    find_data.current = 0;
+
+    if (url == NULL || url[0] == 0) {
+        url = "pkcs11:";
+    }
+
+    ret = pkcs11_url_to_info(url, &find_data.info);
+    if (ret < 0) {
+        gnutls_assert();
+        return ret;
+    }
+
+    ret = _pkcs11_traverse_tokens(find_objs, &find_data, 0);
+    if (ret < 0) {
+        gnutls_assert();
+        return ret;
+    }
+    
+    return 0;
+}
+
+/**
+ * gnutls_x509_crt_import_pkcs11_url:
+ * @crt: A certificate of type #gnutls_x509_crt_t
+ * @url: A PKCS 11 url
+ *
+ * This function will import a PKCS 11 certificate directly from a token
+ * without involving the #gnutls_pkcs11_obj_t structure. This function will
+ * fail if the certificate stored is not of X.509 type.
+ *
+ * Returns: On success, %GNUTLS_E_SUCCESS is returned, otherwise a
+ *   negative error value.
+ **/
+int gnutls_x509_crt_import_pkcs11_url( gnutls_x509_crt_t crt, const char* url)
+{
+    gnutls_pkcs11_obj_t pcrt;
+    int ret;
+    
+    ret = gnutls_pkcs11_obj_init ( &pcrt);
+    if (ret < 0) {
+        gnutls_assert();
+        return ret;
+    }
+
+    ret = gnutls_pkcs11_obj_import_url (pcrt, url);
+    if (ret < 0) {
+        gnutls_assert();
+        goto cleanup;
+    }
+
+    ret = gnutls_x509_crt_import(crt, &pcrt->raw, GNUTLS_X509_FMT_DER);
+    if (ret < 0) {
+        gnutls_assert();
+        goto cleanup;
+    }
+
+    ret = 0;
+cleanup:
+
+    gnutls_pkcs11_obj_deinit(pcrt);
+    
+    return ret;
+}
+
+
+/**
+ * gnutls_x509_crt_import_pkcs11:
+ * @crt: A certificate of type #gnutls_x509_crt_t
+ * @pkcs11_obj: A PKCS 11 object that contains a certificate
+ *
+ * This function will import a PKCS 11 certificate to a #gnutls_x509_crt_t
+ * structure.
+ *
+ * Returns: On success, %GNUTLS_E_SUCCESS is returned, otherwise a
+ *   negative error value.
+ **/
+int gnutls_x509_crt_import_pkcs11( gnutls_x509_crt_t crt, gnutls_pkcs11_obj_t 
pkcs11_crt)
+{
+    return gnutls_x509_crt_import(crt, &pkcs11_crt->raw, GNUTLS_X509_FMT_DER);
+}
+
+/**
+ * gnutls_x509_crt_list_import_pkcs11:
+ * @cert: A list of certificates of type #gnutls_x509_crt_t
+ * @cert_max: The maximum size of the list
+ * @objs: A list of PKCS 11 objects
+ *
+ * This function will import a PKCS 11 certificate list to a list of 
+ * #gnutls_x509_crt_t structure. These must not be initialized.
+ *
+ * Returns: On success, %GNUTLS_E_SUCCESS is returned, otherwise a
+ *   negative error value.
+ **/
+int gnutls_x509_crt_list_import_pkcs11 (gnutls_x509_crt_t * certs,
+    unsigned int cert_max, gnutls_pkcs11_obj_t * const objs,
+    unsigned int flags)
+{
+    int i, j;
+    int ret;
+    
+    for (i=0;i<cert_max;i++) {
+        ret = gnutls_x509_crt_init(&certs[i]);
+        if (ret < 0) {
+            gnutls_assert();
+            goto cleanup;
+        }
+        
+        ret = gnutls_x509_crt_import_pkcs11( certs[i], objs[i]);
+        if (ret < 0) {
+            gnutls_assert();
+            goto cleanup;
+        }
+    }
+    
+    return 0;
+    
+cleanup:
+    for (j=0;j<i;j++) {
+        gnutls_x509_crt_deinit(certs[j]);
+    }
+    
+    return ret;
+}
+
+static int find_flags(pakchois_session_t *pks, struct token_info *info, void* 
input)
+{
+    struct flags_find_data_st* find_data = input;
+
+    if (info == NULL) { /* we don't support multiple calls */
+        gnutls_assert();
+        return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
+    }
+
+    /* do not bother reading the token if basic fields do not match
+     */
+    if (pkcs11_token_matches_info( &find_data->info, &info->tinfo) < 0) {
+               gnutls_assert();
+               return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
+       }
+
+    /* found token! */
+
+    find_data->slot_flags = info->sinfo.flags;
+
+    return 0;
+}
+
+/**
+ * gnutls_pkcs11_token_get_flags:
+ * @url: should contain a PKCS 11 URL
+ * @flags: The output flags
+ *
+ * This function will return information about the PKCS 11 token flags.
+ *
+ * Returns: zero on success or a negative value on error.
+ **/
+int gnutls_pkcs11_token_get_flags(const char* url, unsigned int *flags)
+{
+    struct flags_find_data_st find_data;
+    int ret;
+
+    ret = pkcs11_url_to_info(url, &find_data.info);
+    if (ret < 0) {
+        gnutls_assert();
+        return ret;
+    }
+
+    ret = _pkcs11_traverse_tokens(find_flags, &find_data, 0);
+    if (ret < 0) {
+        gnutls_assert();
+        return ret;
+    }
+
+    *flags = 0;
+    if (find_data.slot_flags & CKF_HW_SLOT)
+        *flags |= GNUTLS_PKCS11_TOKEN_HW;
+
+    return 0;
+
+}
+
+
+const char* gnutls_pkcs11_type_get_name (gnutls_pkcs11_obj_type_t type)
+{
+    switch(type) {
+        case GNUTLS_PKCS11_OBJ_X509_CRT:
+            return "X.509 Certificate";
+        case GNUTLS_PKCS11_OBJ_PUBKEY:
+            return "Public key";
+        case GNUTLS_PKCS11_OBJ_PRIVKEY:
+            return "Private key";
+        case GNUTLS_PKCS11_OBJ_SECRET_KEY:
+            return "Secret key";
+        case GNUTLS_PKCS11_OBJ_DATA:
+            return "Data";
+        case GNUTLS_PKCS11_OBJ_UNKNOWN:
+        default:
+            return "Unknown";
+    }
+}
+
+int pkcs11_token_matches_info( struct pkcs11_url_info* info, struct 
ck_token_info* tinfo)
+{
+    if (info->manufacturer[0] != 0) {
+        if (strcmp(info->manufacturer, tinfo->manufacturer_id) != 0)
+            return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
+    }
+
+    if (info->token[0] != 0) {
+        if (strcmp(info->token, tinfo->label) != 0)
+            return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
+    }
+
+    if (info->model[0] != 0) {
+        if (strcmp(info->model, tinfo->model) != 0)
+            return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
+    }
+
+    if (info->serial[0] != 0) {
+        if (strcmp(info->serial, tinfo->serial_number) != 0)
+            return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
+    }
+
+    return 0;
+}
diff --git a/lib/pkcs11_int.h b/lib/pkcs11_int.h
new file mode 100644
index 0000000..63e73e0
--- /dev/null
+++ b/lib/pkcs11_int.h
@@ -0,0 +1,74 @@
+#ifndef PKCS11_INT_H
+# define PKCS11_INT_H
+
+#include <pakchois/pakchois.h>
+#include <gnutls/pkcs11.h>
+
+#define PKCS11_ID_SIZE 128
+#define PKCS11_LABEL_SIZE 128
+
+struct token_info {
+    struct ck_token_info tinfo;
+    struct ck_slot_info sinfo;
+    ck_slot_id_t sid;
+    struct gnutls_pkcs11_provider_s* prov;
+};
+
+struct pkcs11_url_info
+{
+    /* everything here is null terminated strings */
+    opaque id[PKCS11_ID_SIZE*3+1]; /* hex with delimiters */
+    opaque type[16]; /* cert/key etc. */
+    opaque manufacturer[sizeof (((struct ck_token_info 
*)NULL)->manufacturer_id)+1];
+    opaque token[sizeof (((struct ck_token_info *)NULL)->label)+1];
+    opaque serial[sizeof (((struct ck_token_info *)NULL)->serial_number)+1];
+    opaque model[sizeof (((struct ck_token_info *)NULL)->model)+1];
+    opaque label[PKCS11_LABEL_SIZE+1];
+    
+    opaque certid_raw[PKCS11_ID_SIZE]; /* same as ID but raw */
+    size_t certid_raw_size;
+};
+
+struct gnutls_pkcs11_obj_st {
+    gnutls_datum_t raw;
+    gnutls_pkcs11_obj_type_t type;
+    struct pkcs11_url_info info;
+
+    /* only when pubkey */
+    gnutls_datum_t pubkey[MAX_PUBLIC_PARAMS_SIZE];
+    gnutls_pk_algorithm pk_algorithm;
+    unsigned int key_usage;
+};
+
+/* thus function is called for every token in the traverse_tokens
+ * function. Once everything is traversed it is called with NULL tinfo.
+ * It should return 0 if found what it was looking for.
+ */
+typedef int (*find_func_t)(pakchois_session_t *pks, struct token_info* tinfo, 
void* input);
+
+
+int pkcs11_url_to_info(const char* url, struct pkcs11_url_info* info);
+
+int pkcs11_get_info(struct pkcs11_url_info *info, gnutls_pkcs11_obj_info_t 
itype, 
+    void* output, size_t* output_size);
+int pkcs11_login(pakchois_session_t *pks, struct token_info *info);
+
+extern gnutls_pkcs11_token_callback_t token_func;
+extern void* token_data;
+
+void pkcs11_rescan_slots(void);
+int pkcs11_info_to_url(const struct pkcs11_url_info* info, char** url);
+
+#define SESSION_WRITE 1
+#define SESSION_LOGIN 2
+int pkcs11_open_session (pakchois_session_t** _pks, struct pkcs11_url_info 
*info, unsigned int flags);
+int _pkcs11_traverse_tokens (find_func_t find_func, void* input, unsigned int 
flags);
+ck_object_class_t pkcs11_strtype_to_class(const char* type);
+
+int pkcs11_token_matches_info( struct pkcs11_url_info* info, struct 
ck_token_info* tinfo);
+
+/* flags are SESSION_* */
+int pkcs11_find_object (pakchois_session_t** _pks, ck_object_handle_t* _obj,
+    struct pkcs11_url_info *info, unsigned int flags);
+
+#endif
diff --git a/lib/pkcs11_privkey.c b/lib/pkcs11_privkey.c
new file mode 100644
index 0000000..6423839
--- /dev/null
+++ b/lib/pkcs11_privkey.c
@@ -0,0 +1,396 @@
+/*
+ * GnuTLS PKCS#11 support
+ * Copyright (C) 2010 Free Software Foundation
+ * 
+ * Author: Nikos Mavrogiannopoulos
+ *
+ * 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
+*/
+
+#include <gnutls_int.h>
+#include <pakchois/pakchois.h>
+#include <gnutls/pkcs11.h>
+#include <stdio.h>
+#include <stdbool.h>
+#include <string.h>
+#include <gnutls_errors.h>
+#include <gnutls_datum.h>
+#include <pkcs11_int.h>
+#include <sign.h>
+
+struct gnutls_pkcs11_privkey_st {
+       pakchois_session_t *pks;
+       ck_object_handle_t obj;
+       gnutls_pk_algorithm_t pk_algorithm;
+       unsigned int flags;
+       struct pkcs11_url_info info;
+};
+
+/**
+ * gnutls_pkcs11_privkey_init:
+ * @key: The structure to be initialized
+ *
+ * This function will initialize an private key structure.
+ *
+ * Returns: On success, %GNUTLS_E_SUCCESS is returned, otherwise a
+ *   negative error value.
+ **/
+int gnutls_pkcs11_privkey_init(gnutls_pkcs11_privkey_t * key)
+{
+       *key = gnutls_calloc(1, sizeof(struct gnutls_pkcs11_privkey_st));
+       if (*key == NULL) {
+               gnutls_assert();
+               return GNUTLS_E_MEMORY_ERROR;
+       }
+       (*key)->obj = CK_INVALID_HANDLE;
+       
+       return 0;
+}
+
+/**
+ * gnutls_pkcs11_privkey_deinit:
+ * @key: The structure to be initialized
+ *
+ * This function will deinitialize a private key structure.
+ **/
+void gnutls_pkcs11_privkey_deinit(gnutls_pkcs11_privkey_t key)
+{
+       if (key->pks) {
+               pakchois_close_session(key->pks);
+    }
+       gnutls_free(key);
+}
+
+/**
+ * gnutls_pkcs11_privkey_get_pk_algorithm:
+ * @key: should contain a #gnutls_pkcs11_privkey_t structure
+ *
+ * This function will return the public key algorithm of a private
+ * key.
+ *
+ * Returns: a member of the #gnutls_pk_algorithm_t enumeration on
+ *   success, or a negative value on error.
+ **/
+int gnutls_pkcs11_privkey_get_pk_algorithm(gnutls_pkcs11_privkey_t key, 
unsigned int *bits)
+{
+        if (bits)
+          *bits = 0; /* FIXME */
+       return key->pk_algorithm;
+}
+
+/**
+ * gnutls_pkcs11_privkey_get_info:
+ * @key: should contain a #gnutls_pkcs11_privkey_t structure
+ * @itype: Denotes the type of information requested
+ * @output: where output will be stored
+ * @output_size: contains the maximum size of the output and will be 
overwritten with actual
+ *
+ * This function will return information about the PKCS 11 private key such
+ * as the label, id as well as token information where the key is stored. When
+ * output is text it returns null terminated string although #output_size 
contains
+ * the size of the actual data only.
+ *
+ * Returns: zero on success or a negative value on error.
+ **/
+int gnutls_pkcs11_privkey_get_info(gnutls_pkcs11_privkey_t pkey,
+                                  gnutls_pkcs11_obj_info_t itype,
+                                  void *output, size_t * output_size)
+{
+       return pkcs11_get_info(&pkey->info, itype, output, output_size);
+}
+
+#define RETRY_BLOCK_START int retries = 0; retry:
+
+
+/* the rescan_slots() here is a dummy but if not
+ * called my card fails to work when removed and inserted.
+ * May have to do with the pkcs11 library I use.
+ */
+#define RETRY_CHECK(rv, key) { \
+               if (token_func && (rv == 
CKR_SESSION_HANDLE_INVALID||rv==CKR_DEVICE_REMOVED)) { \
+                       pkcs11_rescan_slots(); \
+                       pakchois_close_session(key->pks); \
+                       pkcs11_rescan_slots(); \
+                       key->pks = NULL; \
+                       key->obj = CK_INVALID_HANDLE; \
+                       ret = token_func(token_data, key->info.label, 
retries++); \
+                       if (ret == 0) { \
+                               pkcs11_find_object (&key->pks, &key->obj, 
&key->info, SESSION_LOGIN); \
+                               goto retry; \
+                       } \
+               } \
+       }
+
+/**
+ * gnutls_pkcs11_privkey_sign_data:
+ * @signer: Holds the key
+ * @digest: should be MD5 or SHA1
+ * @flags: should be 0 for now
+ * @data: holds the data to be signed
+ * @signature: will contain the signature allocated with gnutls_malloc()
+ *
+ * This function will sign the given data using a signature algorithm
+ * supported by the private key. Signature algorithms are always used
+ * together with a hash functions.  Different hash functions may be
+ * used for the RSA algorithm, but only SHA-1 for the DSA keys.
+ *
+ * Returns: On success, %GNUTLS_E_SUCCESS is returned, otherwise a
+ *   negative error value.
+ **/
+int
+gnutls_pkcs11_privkey_sign_data(gnutls_pkcs11_privkey_t signer,
+                               gnutls_digest_algorithm_t hash,
+                               unsigned int flags,
+                               const gnutls_datum_t * data,
+                               gnutls_datum_t * signature)
+{
+       int ret;
+       gnutls_datum_t digest;
+
+       switch (signer->pk_algorithm) {
+       case GNUTLS_PK_RSA:
+               ret = pk_pkcs1_rsa_hash(hash, data, &digest);
+               if (ret < 0) {
+                       gnutls_assert();
+                       return ret;
+               }
+               break;
+       case GNUTLS_PK_DSA:
+               ret = pk_dsa_hash(hash, data, &digest);
+               if (ret < 0) {
+                       gnutls_assert();
+                       return ret;
+               }
+
+               break;
+       default:
+               gnutls_assert();
+               return GNUTLS_E_INTERNAL_ERROR;
+       }
+
+       ret = gnutls_pkcs11_privkey_sign_hash(signer, &digest, signature);
+       _gnutls_free_datum(&digest);
+
+       if (ret < 0) {
+               gnutls_assert();
+               return ret;
+       }
+
+       return 0;
+
+}
+
+/**
+ * gnutls_pkcs11_privkey_sign_hash:
+ * @key: Holds the key
+ * @hash: holds the data to be signed (should be output of a hash)
+ * @signature: will contain the signature allocated with gnutls_malloc()
+ *
+ * This function will sign the given data using a signature algorithm
+ * supported by the private key. It is assumed that the given data
+ * are the output of a hash function.
+ *
+ * Returns: On success, %GNUTLS_E_SUCCESS is returned, otherwise a
+ *   negative error value.
+ **/
+int gnutls_pkcs11_privkey_sign_hash(gnutls_pkcs11_privkey_t key,
+                                   const gnutls_datum_t * hash,
+                                   gnutls_datum_t * signature)
+{
+       ck_rv_t rv;
+       int ret;
+       struct ck_mechanism mech;
+       unsigned long siglen;
+
+       RETRY_BLOCK_START;
+
+       if (key->obj == CK_INVALID_HANDLE || key->pks == NULL) {
+               gnutls_assert();
+               return GNUTLS_E_PKCS11_ERROR;
+       }
+
+       mech.mechanism =
+           key->pk_algorithm == GNUTLS_PK_DSA ? CKM_DSA : CKM_RSA_PKCS;
+       mech.parameter = NULL;
+       mech.parameter_len = 0;
+
+       /* Initialize signing operation; using the private key discovered
+        * earlier. */
+       rv = pakchois_sign_init(key->pks, &mech, key->obj);
+       if (rv != CKR_OK) {
+               RETRY_CHECK(rv, key);
+               gnutls_assert();
+               return GNUTLS_E_PK_SIGN_FAILED;
+       }
+
+       /* Work out how long the signature must be: */
+       rv = pakchois_sign(key->pks, hash->data, hash->size, NULL,
+                          &siglen);
+       if (rv != CKR_OK) {
+               RETRY_CHECK(rv, key);
+               gnutls_assert();
+               return GNUTLS_E_PK_SIGN_FAILED;
+       }
+
+       signature->data = gnutls_malloc(siglen);
+       signature->size = siglen;
+
+       rv = pakchois_sign(key->pks, hash->data, hash->size,
+                          signature->data, &siglen);
+       if (rv != CKR_OK) {
+               gnutls_free(signature->data);
+               RETRY_CHECK(rv, key);
+               gnutls_assert();
+               return GNUTLS_E_PK_SIGN_FAILED;
+       }
+
+       signature->size = siglen;
+
+       return 0;
+}
+
+
+/**
+ * gnutls_pkcs11_privkey_import_url:
+ * @pkey: The structure to store the parsed key
+ * @url: a PKCS 11 url identifying the key
+ * @flags: sequence of GNUTLS_PKCS_PRIVKEY_*
+ *
+ * This function will "import" a PKCS 11 URL identifying a private
+ * key to the #gnutls_pkcs11_privkey_t structure. In reality since
+ * in most cases keys cannot be exported, the private key structure
+ * is being associated with the available operations on the token.
+ *
+ * Returns: On success, %GNUTLS_E_SUCCESS is returned, otherwise a
+ *   negative error value.
+ **/
+int gnutls_pkcs11_privkey_import_url(gnutls_pkcs11_privkey_t pkey,
+                                    const char *url, unsigned int flags)
+{
+       int ret;
+
+       ret = pkcs11_url_to_info(url, &pkey->info);
+       if (ret < 0) {
+               gnutls_assert();
+               return ret;
+       }
+
+       if (pkey->info.id[0] == 0) {
+               gnutls_assert();
+               return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
+       }
+
+       ret = pkcs11_find_object (&pkey->pks, &pkey->obj, &pkey->info, 
SESSION_LOGIN);
+       if (ret < 0) {
+               gnutls_assert();
+               return ret;
+       }
+       pkey->flags = flags;
+
+       return 0;
+}
+
+/**
+ * gnutls_pkcs11_privkey_decrypt_data:
+ * @key: Holds the key
+ * @flags: should be 0 for now
+ * @ciphertext: holds the data to be signed
+ * @plaintext: will contain the plaintext, allocated with gnutls_malloc()
+ *
+ * This function will decrypt the given data using the public key algorithm
+ * supported by the private key. 
+ *
+ * Returns: On success, %GNUTLS_E_SUCCESS is returned, otherwise a
+ *   negative error value.
+ **/
+int
+gnutls_pkcs11_privkey_decrypt_data(gnutls_pkcs11_privkey_t key,
+  unsigned int flags, const gnutls_datum_t * ciphertext,
+                               gnutls_datum_t * plaintext)
+{
+       ck_rv_t rv;
+       int ret;
+       struct ck_mechanism mech;
+       unsigned long siglen;
+
+       RETRY_BLOCK_START;
+
+       if (key->obj == CK_INVALID_HANDLE) {
+               gnutls_assert();
+               return GNUTLS_E_PKCS11_ERROR;
+       }
+
+       mech.mechanism =
+           key->pk_algorithm == GNUTLS_PK_DSA ? CKM_DSA : CKM_RSA_PKCS;
+       mech.parameter = NULL;
+       mech.parameter_len = 0;
+
+       /* Initialize signing operation; using the private key discovered
+        * earlier. */
+       rv = pakchois_decrypt_init(key->pks, &mech, key->obj);
+       if (rv != CKR_OK) {
+               RETRY_CHECK(rv, key);
+               gnutls_assert();
+               return GNUTLS_E_PK_DECRYPTION_FAILED;
+       }
+
+       /* Work out how long the plaintext must be: */
+       rv = pakchois_decrypt(key->pks, ciphertext->data, ciphertext->size, 
NULL,
+                          &siglen);
+       if (rv != CKR_OK) {
+               RETRY_CHECK(rv, key);
+               gnutls_assert();
+               return GNUTLS_E_PK_DECRYPTION_FAILED;
+       }
+
+       plaintext->data = gnutls_malloc(siglen);
+       plaintext->size = siglen;
+
+       rv = pakchois_decrypt(key->pks, ciphertext->data, ciphertext->size,
+                          plaintext->data, &siglen);
+       if (rv != CKR_OK) {
+               gnutls_free(plaintext->data);
+               gnutls_assert();
+               return GNUTLS_E_PK_DECRYPTION_FAILED;
+       }
+
+       plaintext->size = siglen;
+
+       return 0;
+}
+
+/**
+ * gnutls_pkcs11_privkey_export_url:
+ * @key: Holds the PKCS 11 key
+ * @url: will contain an allocated url
+ *
+ * This function will export a URL identifying the given key.
+ *
+ * Returns: On success, %GNUTLS_E_SUCCESS is returned, otherwise a
+ *   negative error value.
+ **/
+int gnutls_pkcs11_privkey_export_url (gnutls_pkcs11_privkey_t key, char ** url)
+{
+int ret;
+
+    ret = pkcs11_info_to_url(&key->info, url);
+    if (ret < 0) {
+        gnutls_assert();
+        return ret;
+    }
+
+    return 0;
+}
diff --git a/lib/pkcs11_write.c b/lib/pkcs11_write.c
new file mode 100644
index 0000000..87bcbd0
--- /dev/null
+++ b/lib/pkcs11_write.c
@@ -0,0 +1,511 @@
+/*
+ * GnuTLS PKCS#11 support
+ * Copyright (C) 2010 Free Software Foundation
+ * 
+ * Author: Nikos Mavrogiannopoulos
+ *
+ * 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
+*/
+
+#include <gnutls_int.h>
+#include <gnutls/pkcs11.h>
+#include <stdio.h>
+#include <string.h>
+#include <gnutls_errors.h>
+#include <gnutls_datum.h>
+#include <pkcs11_int.h>
+
+/**
+ * gnutls_pkcs11_copy_x509_crt:
+ * @token_url: A PKCS #11 URL specifying a token
+ * @crt: A certificate
+ * @label: A name to be used for the stored data
+ * @flags: One of GNUTLS_PKCS11_OBJ_FLAG_*
+ *
+ * This function will copy a certificate into a PKCS #11 token specified by
+ * a URL. The certificate can be marked as trusted or not.
+ *
+ * Returns: On success, %GNUTLS_E_SUCCESS is returned, otherwise a
+ *   negative error value.
+ **/
+int gnutls_pkcs11_copy_x509_crt(const char* token_url, gnutls_x509_crt_t crt, 
+       const char* label, unsigned int flags)
+{
+    int ret;
+    pakchois_session_t *pks;
+    struct pkcs11_url_info info;
+    ck_rv_t rv;
+    size_t der_size, id_size;
+    opaque* der = NULL;
+    opaque id[20];
+    struct ck_attribute a[8];
+    ck_object_class_t class = CKO_CERTIFICATE;
+    ck_certificate_type_t type = CKC_X_509;
+    ck_object_handle_t obj;
+    unsigned int tval = 1;
+    int a_val;
+    
+    ret = pkcs11_url_to_info(token_url, &info);
+       if (ret < 0) {
+               gnutls_assert();
+               return ret;
+       }
+       
+       ret = pkcs11_open_session (&pks, &info, SESSION_WRITE|SESSION_LOGIN);
+       if (ret < 0) {
+               gnutls_assert();
+               return ret;
+       }
+       
+       ret = gnutls_x509_crt_export (crt,
+                        GNUTLS_X509_FMT_DER, NULL, 
+                        &der_size);
+       if (ret < 0 && ret != GNUTLS_E_SHORT_MEMORY_BUFFER) {
+               gnutls_assert();
+               goto cleanup;
+       }
+       
+       der = gnutls_malloc(der_size);
+       if (der == NULL) {
+               gnutls_assert();
+               ret = GNUTLS_E_MEMORY_ERROR;
+               goto cleanup;
+       }
+
+       ret = gnutls_x509_crt_export (crt,
+                        GNUTLS_X509_FMT_DER, der, 
+                        &der_size);
+       if (ret < 0) {
+               gnutls_assert();
+               goto cleanup;
+       }
+       
+       id_size = sizeof(id);
+       ret = gnutls_x509_crt_get_key_id (crt, 0, id, &id_size);
+       if (ret < 0) {
+               gnutls_assert();
+               goto cleanup;
+       }
+       
+    /* 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_VALUE;
+    a[2].value = der;
+    a[2].value_len = der_size;
+    a[3].type = CKA_TOKEN;
+    a[3].value = &tval;
+    a[3].value_len = sizeof(tval);
+    a[4].type = CKA_CERTIFICATE_TYPE;
+    a[4].value = &type;
+    a[4].value_len = sizeof(type);
+
+    a_val = 5;
+    
+    if (label) {
+               a[a_val].type = CKA_LABEL;
+               a[a_val].value = (void*)label;
+               a[a_val].value_len = strlen(label);
+               a_val++;
+       }
+       
+       if (flags & GNUTLS_PKCS11_OBJ_FLAG_TRUSTED) {
+               a[a_val].type = CKA_TRUSTED;
+               a[a_val].value = &tval;
+               a[a_val].value_len = sizeof(tval);
+               a_val++;
+       }
+       
+       rv = pakchois_create_object(pks, a, a_val, &obj);
+       if (rv != CKR_OK) {
+               gnutls_assert();
+               _gnutls_debug_log("pkcs11: %s\n", pakchois_error(rv));
+               ret = GNUTLS_E_PKCS11_ERROR;
+               goto  cleanup;
+       }
+       
+       /* generated! 
+        */
+
+       ret = 0;
+    
+cleanup:
+       gnutls_free(der);
+       pakchois_close_session(pks);
+       
+       return ret;
+   
+}
+
+/**
+ * gnutls_pkcs11_copy_x509_privkey:
+ * @token_url: A PKCS #11 URL specifying a token
+ * @key: A private key
+ * @label: A name to be used for the stored data
+ * @key_usage: One of GNUTLS_KEY_*
+ *
+ * This function will copy a private key into a PKCS #11 token specified by
+ * a URL. 
+ *
+ * Returns: On success, %GNUTLS_E_SUCCESS is returned, otherwise a
+ *   negative error value.
+ **/
+int gnutls_pkcs11_copy_x509_privkey(const char* token_url, 
+       gnutls_x509_privkey_t key, const char* label, unsigned int key_usage)
+{
+    int ret;
+    pakchois_session_t *pks;
+    struct pkcs11_url_info info;
+    ck_rv_t rv;
+    size_t id_size;
+    opaque id[20];
+    struct ck_attribute a[16];
+    ck_object_class_t class = CKO_PRIVATE_KEY;
+    ck_object_handle_t obj;
+    ck_key_type_t type;
+    unsigned int tval = 1;
+    int a_val;
+    gnutls_pk_algorithm_t pk;
+    gnutls_datum_t p, q, g, y, x;
+    gnutls_datum_t m, e, d, u, exp1, exp2;
+       
+    
+    ret = pkcs11_url_to_info(token_url, &info);
+       if (ret < 0) {
+               gnutls_assert();
+               return ret;
+       }
+
+       id_size = sizeof(id);
+       ret = gnutls_x509_privkey_get_key_id (key, 0, id, &id_size);
+       if (ret < 0) {
+               gnutls_assert();
+               goto cleanup;
+       }
+
+       ret = pkcs11_open_session (&pks, &info, SESSION_WRITE|SESSION_LOGIN);
+       if (ret < 0) {
+               gnutls_assert();
+               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_val = 4;
+
+       pk = gnutls_x509_privkey_get_pk_algorithm(key);
+       switch(pk) {
+               case GNUTLS_PK_RSA: {
+                   
+                   ret = gnutls_x509_privkey_export_rsa_raw2(key, &m, &e,
+                               &d, &p, &q, &u, &exp1, &exp2);
+                       if (ret < 0) {
+                               gnutls_assert();
+                               goto cleanup;
+                       }
+                       
+                       type = CKK_RSA;
+                       
+                       a[a_val].type = CKA_MODULUS;
+                       a[a_val].value = m.data;
+                       a[a_val].value_len = m.size;
+                       a_val++;
+
+                       a[a_val].type = CKA_PUBLIC_EXPONENT;
+                       a[a_val].value = e.data;
+                       a[a_val].value_len = e.size;
+                       a_val++;
+
+                       a[a_val].type = CKA_PRIVATE_EXPONENT;
+                       a[a_val].value = d.data;
+                       a[a_val].value_len = d.size;
+                       a_val++;
+
+                       a[a_val].type = CKA_PRIME_1;
+                       a[a_val].value = p.data;
+                       a[a_val].value_len = p.size;
+                       a_val++;
+
+                       a[a_val].type = CKA_PRIME_2;
+                       a[a_val].value = q.data;
+                       a[a_val].value_len = q.size;
+                       a_val++;
+
+                       a[a_val].type = CKA_COEFFICIENT;
+                       a[a_val].value = u.data;
+                       a[a_val].value_len = u.size;
+                       a_val++;
+
+                       a[a_val].type = CKA_EXPONENT_1;
+                       a[a_val].value = exp1.data;
+                       a[a_val].value_len = exp1.size;
+                       a_val++;
+
+                       a[a_val].type = CKA_EXPONENT_2;
+                       a[a_val].value = exp2.data;
+                       a[a_val].value_len = exp2.size;
+                       a_val++;
+
+                       break;
+               }
+               case GNUTLS_PK_DSA: {
+                   ret = gnutls_x509_privkey_export_dsa_raw(key, &p, &q,
+                               &g, &y, &x);
+                       if (ret < 0) {
+                               gnutls_assert();
+                               goto cleanup;
+                       }
+
+                       type = CKK_DSA;
+                       
+                       a[a_val].type = CKA_PRIME;
+                       a[a_val].value = p.data;
+                       a[a_val].value_len = p.size;
+                       a_val++;
+
+                       a[a_val].type = CKA_SUBPRIME;
+                       a[a_val].value = q.data;
+                       a[a_val].value_len = q.size;
+                       a_val++;
+
+                       a[a_val].type = CKA_BASE;
+                       a[a_val].value = g.data;
+                       a[a_val].value_len = g.size;
+                       a_val++;
+
+                       a[a_val].type = CKA_VALUE;
+                       a[a_val].value = x.data;
+                       a[a_val].value_len = x.size;
+                       a_val++;
+
+                       break;
+               }
+               default:
+                       gnutls_assert();
+                       ret = GNUTLS_E_INVALID_REQUEST;
+                       goto cleanup;
+       }
+       
+       rv = pakchois_create_object(pks, a, a_val, &obj);
+       if (rv != CKR_OK) {
+               gnutls_assert();
+               _gnutls_debug_log("pkcs11: %s\n", pakchois_error(rv));
+               ret = GNUTLS_E_PKCS11_ERROR;
+               goto  cleanup;
+       }
+
+       /* generated! 
+        */
+
+       switch(pk) {
+               case GNUTLS_PK_RSA: {
+                   gnutls_free(m.data);
+                   gnutls_free(e.data);
+                   gnutls_free(d.data);
+                   gnutls_free(p.data);
+                   gnutls_free(q.data);
+                   gnutls_free(u.data);
+                   gnutls_free(exp1.data);
+                   gnutls_free(exp2.data);
+                       break;
+               }
+               case GNUTLS_PK_DSA: {
+                       gnutls_free(p.data);
+                       gnutls_free(q.data);
+                       gnutls_free(g.data);
+                       gnutls_free(y.data);
+                       gnutls_free(x.data);
+                       break;
+               }
+               default:
+                       gnutls_assert();
+                       ret = GNUTLS_E_INVALID_REQUEST;
+                       goto cleanup;
+       }
+
+       ret = 0;
+    
+cleanup:
+       pakchois_close_session(pks);
+       
+       return ret;
+       
+}
+
+struct delete_data_st {
+       struct pkcs11_url_info info;
+       unsigned int deleted; /* how many */
+};
+
+static int delete_obj_url(pakchois_session_t *pks, struct token_info *info, 
void* input)
+{
+    struct delete_data_st* find_data = input;
+    struct ck_attribute a[4];
+    ck_object_class_t class;
+    ck_certificate_type_t type = -1;
+    ck_rv_t rv;
+    ck_object_handle_t obj;
+    unsigned long count, a_vals;
+    int found = 0, ret;
+
+    
+    if (info == NULL) { /* we don't support multiple calls */
+        gnutls_assert();
+        return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
+    }
+    
+    /* do not bother reading the token if basic fields do not match
+     */
+    if (pkcs11_token_matches_info( &find_data->info, &info->tinfo) < 0) {
+               gnutls_assert();
+               return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
+       }
+
+    class = CKO_CERTIFICATE; /* default  */
+
+    if (find_data->info.type[0] != 0) {
+        class = pkcs11_strtype_to_class(find_data->info.type);
+        if (class == CKO_CERTIFICATE)
+            type = CKC_X_509;
+
+        if (class == -1) {
+            gnutls_assert();
+            return GNUTLS_E_INVALID_REQUEST;
+        }
+    }
+
+       ret = pkcs11_login(pks, info);
+       if (ret < 0) {
+               gnutls_assert();
+               return ret;
+       }
+
+       a_vals = 0;
+       
+    /* Find objects with given class and type */
+       if (find_data->info.certid_raw_size > 0) {
+               a[a_vals].type = CKA_ID;
+               a[a_vals].value = find_data->info.certid_raw;
+               a[a_vals].value_len = find_data->info.certid_raw_size;
+               a_vals++;
+       }
+
+       if (class != -1) {
+               a[a_vals].type = CKA_CLASS;
+               a[a_vals].value = &class;
+               a[a_vals].value_len = sizeof class;
+               a_vals++;    
+       }
+
+    if (type != -1) {
+        a[a_vals].type = CKA_CERTIFICATE_TYPE;
+        a[a_vals].value = &type;
+        a[a_vals].value_len = sizeof type;
+        a_vals++;
+    }
+    
+    if (find_data->info.label[0] != 0) {
+        a[a_vals].type = CKA_LABEL;
+        a[a_vals].value = find_data->info.label;
+        a[a_vals].value_len = strlen(find_data->info.label);
+        a_vals++;
+       }
+
+    rv = pakchois_find_objects_init(pks, a, a_vals);
+    if (rv != CKR_OK) {
+        gnutls_assert();
+        _gnutls_debug_log("pk11: FindObjectsInit failed.\n");
+        ret = GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
+        goto cleanup;
+    }
+
+    while (pakchois_find_objects(pks, &obj, 1, &count) == CKR_OK
+           && count == 1) {
+               
+               rv = pakchois_destroy_object(pks, obj);
+               if (rv != CKR_OK) {
+            _gnutls_debug_log("pkcs11: Cannot destroy object: %s\n", 
pakchois_error(rv));
+        } else {
+                       find_data->deleted++;
+               }
+        
+        found = 1;
+    }
+
+    if (found == 0) {
+        gnutls_assert();
+        ret = GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
+    } else {
+        ret = 0;
+    }
+
+cleanup:
+    pakchois_find_objects_final(pks);
+    
+    return ret;
+}
+
+
+/**
+ * gnutls_pkcs11_delete_url:
+ * @object_url: The URL of the object to delete.
+ * 
+ * This function will delete objects matching the given URL.
+ *
+ * Returns: On success, the number of objects deleted is returned, otherwise a
+ *   negative error value.
+ **/
+int gnutls_pkcs11_delete_url(const char* object_url)
+{
+    int ret;
+    struct delete_data_st find_data;
+
+       memset(&find_data, 0, sizeof(find_data));
+
+    ret = pkcs11_url_to_info(object_url, &find_data.info);
+    if (ret < 0) {
+        gnutls_assert();
+        return ret;
+    }
+
+    ret = _pkcs11_traverse_tokens(delete_obj_url, &find_data, SESSION_WRITE);
+    if (ret < 0) {
+        gnutls_assert();
+        return ret;
+    }
+    
+    return find_data.deleted;
+       
+}
+    
diff --git a/lib/pkix.asn b/lib/pkix.asn
index e105aae..e805fb7 100644
--- a/lib/pkix.asn
+++ b/lib/pkix.asn
@@ -169,74 +169,8 @@ id-at           OBJECT IDENTIFIER ::= {joint-iso-ccitt(2) 
ds(5) 4}
 -- Maybe this is inefficient and memory consuming. Should we replace with
 -- a table that maps OIDs to structures?
 
-id-at-initials          AttributeType ::= { id-at 43 }
-X520initials ::= DirectoryString
-
-id-at-generationQualifier AttributeType ::= { id-at 44 }
-X520generationQualifier ::= DirectoryString
-
-id-at-surname           AttributeType ::= { id-at 4 }
-X520surName ::= DirectoryString
-
-id-at-givenName         AttributeType ::= { id-at 42 }
-X520givenName ::= DirectoryString
-
-id-at-name              AttributeType ::= { id-at 41 }
-X520name        ::= DirectoryString
-
-id-at-commonName        AttributeType   ::=     {id-at 3}
-X520CommonName  ::=      DirectoryString
-
-id-at-localityName      AttributeType   ::=     {id-at 7}
-X520LocalityName ::= DirectoryString
-
-id-at-stateOrProvinceName       AttributeType   ::=     {id-at 8}
-X520StateOrProvinceName         ::= DirectoryString
-
-id-at-organizationName          AttributeType   ::=     {id-at 10}
-X520OrganizationName ::= DirectoryString
-
-id-at-organizationalUnitName    AttributeType   ::=     {id-at 11}
-X520OrganizationalUnitName ::= DirectoryString
-
-id-at-title     AttributeType   ::=     {id-at 12}
-X520Title ::=   DirectoryString
-
-id-at-description     AttributeType   ::=     {id-at 13}
-X520Description ::=   DirectoryString
-
-id-at-dnQualifier       AttributeType   ::=     {id-at 46}
-X520dnQualifier ::=     PrintableString
-
-id-at-countryName       AttributeType   ::=     {id-at 6}
-X520countryName ::=     PrintableString (SIZE (2)) -- IS 3166 codes
-
-id-at-serialNumber       AttributeType   ::=     {id-at 5}
-X520serialNumber ::=     PrintableString
-
-id-at-telephoneNumber       AttributeType   ::=     {id-at 20}
-X520telephoneNumber ::=     PrintableString
-
-id-at-facsimileTelephoneNumber       AttributeType   ::=     {id-at 23}
-X520facsimileTelephoneNumber ::=     PrintableString
-
-id-at-pseudonym         AttributeType   ::=     {id-at 65}
-X520pseudonym ::=       DirectoryString
-
-id-at-name      AttributeType   ::=     {id-at 41}
-X520name ::=    DirectoryString
-
-id-at-streetAddress     AttributeType   ::=     {id-at 9}
-X520streetAddress ::=   DirectoryString
- 
-id-at-postalAddress     AttributeType   ::=     {id-at 16}
-X520postalAddress ::= PostalAddress
-
 PostalAddress ::= SEQUENCE OF DirectoryString
 
-id-at-postalCode     AttributeType   ::=     {id-at 17}
-X520postalCode ::= DirectoryString
-
  -- Legacy attributes
 
 emailAddress AttributeType      ::= { iso(1) member-body(2) us(840) 
rsadsi(113549) pkcs(1) 9 1 }
@@ -479,13 +413,8 @@ pkcs-9-challengePassword        ::= CHOICE {
       printableString       PrintableString,
       utf8String            UTF8String }
 
-pkcs-9-at-localKeyId OBJECT IDENTIFIER ::= {iso(1) member-body(2) us(840) 
rsadsi(113549) pkcs(1) 9 21}
-
 pkcs-9-localKeyId ::= OCTET STRING
 
-pkcs-9-at-friendlyName             OBJECT IDENTIFIER ::= {iso(1) 
member-body(2) us(840) rsadsi(113549) pkcs(1) 9 20}
-pkcs-9-friendlyName ::= BMPString      (SIZE (1..255))
-
 -- PKCS #8 stuff
 
 -- Private-key information syntax
@@ -624,33 +553,6 @@ pkcs-7-EncryptedContent ::= OCTET STRING
 
 pkcs-7-UnprotectedAttributes ::= SET SIZE (1..MAX) OF Attribute
 
--- LDAP stuff
-
-id-at-ldap-DC AttributeType ::= { 0 9 2342 19200300 100 1 25 }
-ldap-DC ::= IA5String
-
-id-at-ldap-UID AttributeType ::= { 0 9 2342 19200300 100 1 1 }
-ldap-UID ::= DirectoryString
-
--- rfc3039
-
-id-pda-dateOfBirth          AttributeType ::= { id-pkix 9  1 }
-DateOfBirth ::=             GeneralizedTime
-
-id-pda-placeOfBirth         AttributeType ::= { id-pkix 9  2 }
-PlaceOfBirth ::=            DirectoryString
-
-id-pda-gender               AttributeType ::= { id-pkix 9  3 }
-Gender ::=                  PrintableString (SIZE(1))
-
-id-pda-countryOfCitizenship AttributeType ::= { id-pkix 9  4 }
-CountryOfCitizenship ::=    PrintableString (SIZE (2))
-                            -- ISO 3166 Country Code
-
-id-pda-countryOfResidence   AttributeType ::= { id-pkix 9  5 }
-CountryOfResidence ::=      PrintableString (SIZE (2))
-                            -- ISO 3166 Country Code
-
 -- rfc3820
 
 ProxyCertInfo ::= SEQUENCE {
@@ -661,10 +563,4 @@ ProxyPolicy ::= SEQUENCE {
   policyLanguage   OBJECT IDENTIFIER,
   policy           OCTET STRING OPTIONAL }
 
--- rfc3920 section 5.1.1
-
-id-on-xmppAddr  OBJECT IDENTIFIER ::= { id-pkix 8 5 }
-
-XmppAddr ::= UTF8String
-
 END
diff --git a/lib/pkix_asn1_tab.c b/lib/pkix_asn1_tab.c
index e1296d0..d5d5cc4 100644
--- a/lib/pkix_asn1_tab.c
+++ b/lib/pkix_asn1_tab.c
@@ -123,97 +123,8 @@ const ASN1_ARRAY_TYPE pkix_asn1_tab[] = {
   { "joint-iso-ccitt", 1073741825, "2"},
   { "ds", 1073741825, "5"},
   { NULL, 1, "4"},
-  { "id-at-initials", 1880096780, "AttributeType"},
-  { NULL, 1073741825, "id-at"},
-  { NULL, 1, "43"},
-  { "X520initials", 1073741826, "DirectoryString"},
-  { "id-at-generationQualifier", 1880096780, "AttributeType"},
-  { NULL, 1073741825, "id-at"},
-  { NULL, 1, "44"},
-  { "X520generationQualifier", 1073741826, "DirectoryString"},
-  { "id-at-surname", 1880096780, "AttributeType"},
-  { NULL, 1073741825, "id-at"},
-  { NULL, 1, "4"},
-  { "X520surName", 1073741826, "DirectoryString"},
-  { "id-at-givenName", 1880096780, "AttributeType"},
-  { NULL, 1073741825, "id-at"},
-  { NULL, 1, "42"},
-  { "X520givenName", 1073741826, "DirectoryString"},
-  { "id-at-name", 1880096780, "AttributeType"},
-  { NULL, 1073741825, "id-at"},
-  { NULL, 1, "41"},
-  { "X520name", 1073741826, "DirectoryString"},
-  { "id-at-commonName", 1880096780, "AttributeType"},
-  { NULL, 1073741825, "id-at"},
-  { NULL, 1, "3"},
-  { "X520CommonName", 1073741826, "DirectoryString"},
-  { "id-at-localityName", 1880096780, "AttributeType"},
-  { NULL, 1073741825, "id-at"},
-  { NULL, 1, "7"},
-  { "X520LocalityName", 1073741826, "DirectoryString"},
-  { "id-at-stateOrProvinceName", 1880096780, "AttributeType"},
-  { NULL, 1073741825, "id-at"},
-  { NULL, 1, "8"},
-  { "X520StateOrProvinceName", 1073741826, "DirectoryString"},
-  { "id-at-organizationName", 1880096780, "AttributeType"},
-  { NULL, 1073741825, "id-at"},
-  { NULL, 1, "10"},
-  { "X520OrganizationName", 1073741826, "DirectoryString"},
-  { "id-at-organizationalUnitName", 1880096780, "AttributeType"},
-  { NULL, 1073741825, "id-at"},
-  { NULL, 1, "11"},
-  { "X520OrganizationalUnitName", 1073741826, "DirectoryString"},
-  { "id-at-title", 1880096780, "AttributeType"},
-  { NULL, 1073741825, "id-at"},
-  { NULL, 1, "12"},
-  { "X520Title", 1073741826, "DirectoryString"},
-  { "id-at-description", 1880096780, "AttributeType"},
-  { NULL, 1073741825, "id-at"},
-  { NULL, 1, "13"},
-  { "X520Description", 1073741826, "DirectoryString"},
-  { "id-at-dnQualifier", 1880096780, "AttributeType"},
-  { NULL, 1073741825, "id-at"},
-  { NULL, 1, "46"},
-  { "X520dnQualifier", 1073741826, "PrintableString"},
-  { "id-at-countryName", 1880096780, "AttributeType"},
-  { NULL, 1073741825, "id-at"},
-  { NULL, 1, "6"},
-  { "X520countryName", 1612709890, "PrintableString"},
-  { NULL, 1048586, "2"},
-  { "id-at-serialNumber", 1880096780, "AttributeType"},
-  { NULL, 1073741825, "id-at"},
-  { NULL, 1, "5"},
-  { "X520serialNumber", 1073741826, "PrintableString"},
-  { "id-at-telephoneNumber", 1880096780, "AttributeType"},
-  { NULL, 1073741825, "id-at"},
-  { NULL, 1, "20"},
-  { "X520telephoneNumber", 1073741826, "PrintableString"},
-  { "id-at-facsimileTelephoneNumber", 1880096780, "AttributeType"},
-  { NULL, 1073741825, "id-at"},
-  { NULL, 1, "23"},
-  { "X520facsimileTelephoneNumber", 1073741826, "PrintableString"},
-  { "id-at-pseudonym", 1880096780, "AttributeType"},
-  { NULL, 1073741825, "id-at"},
-  { NULL, 1, "65"},
-  { "X520pseudonym", 1073741826, "DirectoryString"},
-  { "id-at-name", 1880096780, "AttributeType"},
-  { NULL, 1073741825, "id-at"},
-  { NULL, 1, "41"},
-  { "X520name", 1073741826, "DirectoryString"},
-  { "id-at-streetAddress", 1880096780, "AttributeType"},
-  { NULL, 1073741825, "id-at"},
-  { NULL, 1, "9"},
-  { "X520streetAddress", 1073741826, "DirectoryString"},
-  { "id-at-postalAddress", 1880096780, "AttributeType"},
-  { NULL, 1073741825, "id-at"},
-  { NULL, 1, "16"},
-  { "X520postalAddress", 1073741826, "PostalAddress"},
   { "PostalAddress", 1610612747, NULL },
   { NULL, 2, "DirectoryString"},
-  { "id-at-postalCode", 1880096780, "AttributeType"},
-  { NULL, 1073741825, "id-at"},
-  { NULL, 1, "17"},
-  { "X520postalCode", 1073741826, "DirectoryString"},
   { "emailAddress", 1880096780, "AttributeType"},
   { "iso", 1073741825, "1"},
   { "member-body", 1073741825, "2"},
@@ -392,25 +303,7 @@ const ASN1_ARRAY_TYPE pkix_asn1_tab[] = {
   { "pkcs-9-challengePassword", 1610612754, NULL },
   { "printableString", 1073741826, "PrintableString"},
   { "utf8String", 2, "UTF8String"},
-  { "pkcs-9-at-localKeyId", 1879048204, NULL },
-  { "iso", 1073741825, "1"},
-  { "member-body", 1073741825, "2"},
-  { "us", 1073741825, "840"},
-  { "rsadsi", 1073741825, "113549"},
-  { "pkcs", 1073741825, "1"},
-  { NULL, 1073741825, "9"},
-  { NULL, 1, "21"},
   { "pkcs-9-localKeyId", 1073741831, NULL },
-  { "pkcs-9-at-friendlyName", 1879048204, NULL },
-  { "iso", 1073741825, "1"},
-  { "member-body", 1073741825, "2"},
-  { "us", 1073741825, "840"},
-  { "rsadsi", 1073741825, "113549"},
-  { "pkcs", 1073741825, "1"},
-  { NULL, 1073741825, "9"},
-  { NULL, 1, "20"},
-  { "pkcs-9-friendlyName", 1612709890, "BMPString"},
-  { "255", 524298, "1"},
   { "pkcs-8-PrivateKeyInfo", 1610612741, NULL },
   { "version", 1073741826, "pkcs-8-Version"},
   { "privateKeyAlgorithm", 1073741826, "AlgorithmIdentifier"},
@@ -504,63 +397,12 @@ const ASN1_ARRAY_TYPE pkix_asn1_tab[] = {
   { "pkcs-7-UnprotectedAttributes", 1612709903, NULL },
   { "MAX", 1074266122, "1"},
   { NULL, 2, "Attribute"},
-  { "id-at-ldap-DC", 1880096780, "AttributeType"},
-  { NULL, 1073741825, "0"},
-  { NULL, 1073741825, "9"},
-  { NULL, 1073741825, "2342"},
-  { NULL, 1073741825, "19200300"},
-  { NULL, 1073741825, "100"},
-  { NULL, 1073741825, "1"},
-  { NULL, 1, "25"},
-  { "ldap-DC", 1073741826, "IA5String"},
-  { "id-at-ldap-UID", 1880096780, "AttributeType"},
-  { NULL, 1073741825, "0"},
-  { NULL, 1073741825, "9"},
-  { NULL, 1073741825, "2342"},
-  { NULL, 1073741825, "19200300"},
-  { NULL, 1073741825, "100"},
-  { NULL, 1073741825, "1"},
-  { NULL, 1, "1"},
-  { "ldap-UID", 1073741826, "DirectoryString"},
-  { "id-pda-dateOfBirth", 1880096780, "AttributeType"},
-  { NULL, 1073741825, "id-pkix"},
-  { NULL, 1073741825, "9"},
-  { NULL, 1, "1"},
-  { "DateOfBirth", 1082130449, NULL },
-  { "id-pda-placeOfBirth", 1880096780, "AttributeType"},
-  { NULL, 1073741825, "id-pkix"},
-  { NULL, 1073741825, "9"},
-  { NULL, 1, "2"},
-  { "PlaceOfBirth", 1073741826, "DirectoryString"},
-  { "id-pda-gender", 1880096780, "AttributeType"},
-  { NULL, 1073741825, "id-pkix"},
-  { NULL, 1073741825, "9"},
-  { NULL, 1, "3"},
-  { "Gender", 1612709890, "PrintableString"},
-  { NULL, 1048586, "1"},
-  { "id-pda-countryOfCitizenship", 1880096780, "AttributeType"},
-  { NULL, 1073741825, "id-pkix"},
-  { NULL, 1073741825, "9"},
-  { NULL, 1, "4"},
-  { "CountryOfCitizenship", 1612709890, "PrintableString"},
-  { NULL, 1048586, "2"},
-  { "id-pda-countryOfResidence", 1880096780, "AttributeType"},
-  { NULL, 1073741825, "id-pkix"},
-  { NULL, 1073741825, "9"},
-  { NULL, 1, "5"},
-  { "CountryOfResidence", 1612709890, "PrintableString"},
-  { NULL, 1048586, "2"},
   { "ProxyCertInfo", 1610612741, NULL },
   { "pCPathLenConstraint", 1611153411, NULL },
   { "0", 10, "MAX"},
   { "proxyPolicy", 2, "ProxyPolicy"},
-  { "ProxyPolicy", 1610612741, NULL },
+  { "ProxyPolicy", 536870917, NULL },
   { "policyLanguage", 1073741836, NULL },
   { "policy", 16391, NULL },
-  { "id-on-xmppAddr", 1879048204, NULL },
-  { NULL, 1073741825, "id-pkix"},
-  { NULL, 1073741825, "8"},
-  { NULL, 1, "5"},
-  { "XmppAddr", 2, "UTF8String"},
   { NULL, 0, NULL }
 };
diff --git a/lib/random.c b/lib/random.c
index 8721459..9acbe1f 100644
--- a/lib/random.c
+++ b/lib/random.c
@@ -57,8 +57,20 @@ _gnutls_rnd_deinit (void)
   return;
 }
 
-int
-_gnutls_rnd (int level, void *data, size_t len)
+/**
+ * gnutls_rnd:
+ * @level: a security level
+ * @data: place to store random bytes
+ * @len: The requested size
+ *
+ * This function will generate random data and store it
+ * to output buffer.
+ *
+ * Returns: Zero or a negative value on error.
+ *
+ **/
+
+int gnutls_rnd (gnutls_rnd_level_t level, void *data, size_t len)
 {
   if (len > 0)
     {
diff --git a/lib/random.h b/lib/random.h
index 7a3a361..8859f8a 100644
--- a/lib/random.h
+++ b/lib/random.h
@@ -30,7 +30,8 @@
 extern int crypto_rnd_prio;
 extern gnutls_crypto_rnd_st _gnutls_rnd_ops;
 
-int _gnutls_rnd (int level, void *data, size_t len);
+int _gnutls_rnd (gnutls_rnd_level_t level, void *data, size_t len);
+#define _gnutls_rnd gnutls_rnd
 void _gnutls_rnd_deinit (void);
 int _gnutls_rnd_init (void);
 
diff --git a/lib/x509/common.c b/lib/x509/common.c
index ce29bff..e0b137e 100644
--- a/lib/x509/common.c
+++ b/lib/x509/common.c
@@ -42,6 +42,7 @@ struct oid2string
   const char *ldap_desc;
   int choice;                  /* of type DirectoryString */
   int printable;
+  const char* asn_desc; /* description in the pkix file */
 };
 
 /* This list contains all the OIDs that may be
@@ -50,43 +51,56 @@ struct oid2string
 static const struct oid2string _oid2str[] = {
   /* PKIX
    */
-  {"1.3.6.1.5.5.7.9.1", "dateOfBirth", 0, 1},
-  {"1.3.6.1.5.5.7.9.2", "placeOfBirth", 0, 1},
-  {"1.3.6.1.5.5.7.9.3", "gender", 0, 1},
-  {"1.3.6.1.5.5.7.9.4", "countryOfCitizenship", 0, 1},
-  {"1.3.6.1.5.5.7.9.5", "countryOfResidence", 0, 1},
-
-  {"2.5.4.6", "C", 0, 1},
-  {"2.5.4.9", "STREET", 1, 1},
-  {"2.5.4.12", "T", 1, 1},
-  {"2.5.4.10", "O", 1, 1},
-  {"2.5.4.11", "OU", 1, 1},
-  {"2.5.4.3", "CN", 1, 1},
-  {"2.5.4.7", "L", 1, 1},
-  {"2.5.4.8", "ST", 1, 1},
-
-  {"2.5.4.5", "serialNumber", 0, 1},
-  {"2.5.4.20", "telephoneNumber", 0, 1},
-  {"2.5.4.4", "surName", 1, 1},
-  {"2.5.4.43", "initials", 1, 1},
-  {"2.5.4.44", "generationQualifier", 1, 1},
-  {"2.5.4.42", "givenName", 1, 1},
-  {"2.5.4.65", "pseudonym", 1, 1},
-  {"2.5.4.46", "dnQualifier", 0, 1},
-  {"2.5.4.17", "postalCode", 1, 1},
-  {"2.5.4.41", "Name", 1, 1},
-
-  {"0.9.2342.19200300.100.1.25", "DC", 0, 1},
-  {"0.9.2342.19200300.100.1.1", "UID", 1, 1},
+  {"1.3.6.1.5.5.7.9.1", "dateOfBirth", 0, 1, "PKIX1.GeneralizedTime"},
+  {"1.3.6.1.5.5.7.9.2", "placeOfBirth", 0, 1, "PKIX1.DirectoryString"},
+  {"1.3.6.1.5.5.7.9.3", "gender", 0, 1, "PKIX1.PrintableString"},
+  {"1.3.6.1.5.5.7.9.4", "countryOfCitizenship", 0, 1, "PKIX1.PrintableString"},
+  {"1.3.6.1.5.5.7.9.5", "countryOfResidence", 0, 1, "PKIX1.PrintableString"},
+
+  {"2.5.4.6", "C", 0, 1, "PKIX1.PrintableString"},
+  {"2.5.4.9", "STREET", 1, 1, "PKIX1.DirectoryString"},
+  {"2.5.4.12", "T", 1, 1, "PKIX1.DirectoryString"},
+  {"2.5.4.10", "O", 1, 1, "PKIX1.DirectoryString"},
+  {"2.5.4.11", "OU", 1, 1, "PKIX1.DirectoryString"},
+  {"2.5.4.3", "CN", 1, 1, "PKIX1.DirectoryString"},
+  {"2.5.4.7", "L", 1, 1, "PKIX1.DirectoryString"},
+  {"2.5.4.8", "ST", 1, 1, "PKIX1.DirectoryString"},
+
+  {"2.5.4.5", "serialNumber", 0, 1, "PKIX1.PrintableString"},
+  {"2.5.4.20", "telephoneNumber", 0, 1, "PKIX1.PrintableString"},
+  {"2.5.4.4", "surName", 1, 1, "PKIX1.DirectoryString"},
+  {"2.5.4.43", "initials", 1, 1, "PKIX1.DirectoryString"},
+  {"2.5.4.44", "generationQualifier", 1, 1, "PKIX1.DirectoryString"},
+  {"2.5.4.42", "givenName", 1, 1, "PKIX1.DirectoryString"},
+  {"2.5.4.65", "pseudonym", 1, 1, "PKIX1.DirectoryString"},
+  {"2.5.4.46", "dnQualifier", 0, 1, "PKIX1.PrintableString"},
+  {"2.5.4.17", "postalCode", 1, 1, "PKIX1.DirectoryString"},
+  {"2.5.4.41", "Name", 1, 1, "PKIX1.DirectoryString"},
+  {"2.5.4.15", "businessCategory", 1, 1, "PKIX1.DirectoryString"},
+
+  {"0.9.2342.19200300.100.1.25", "DC", 0, 1, "PKIX1.IA5String"},
+  {"0.9.2342.19200300.100.1.1", "UID", 1, 1, "PKIX1.DirectoryString"},
+
+  /* Extended validation
+   */
+  {"1.3.6.1.4.1.311.60.2.1.1", "jurisdictionOfIncorporationLocalityName", 1, 
1, "PKIX1.DirectoryString"},
+  {"1.3.6.1.4.1.311.60.2.1.2", 
"jurisdictionOfIncorporationStateOrProvinceName", 1, 1, 
"PKIX1.DirectoryString"},
+  {"1.3.6.1.4.1.311.60.2.1.3", "jurisdictionOfIncorporationCountryName", 0, 1, 
"PKIX1.PrintableString"},
 
   /* PKCS #9
    */
-  {"1.2.840.113549.1.9.1", "EMAIL", 0, 1},
-  {"1.2.840.113549.1.9.7", NULL, 1, 1},
+  {"1.2.840.113549.1.9.1", "EMAIL", 0, 1, "PKIX1.IA5String"},
+  {"1.2.840.113549.1.9.7", NULL, 1, 1, "PKIX1.pkcs-9-challengePassword"},
 
   /* friendly name */
-  {"1.2.840.113549.1.9.20", NULL, 0, 1},
-  {NULL, NULL, 0, 0}
+  {"1.2.840.113549.1.9.20", NULL, 0, 1, "PKIX1.BMPString"},
+  /* local key id */
+  {"1.2.840.113549.1.9.21", NULL, 0, 1, "PKIX1.pkcs-9-localKeyId"},
+
+  /* rfc3920 section 5.1.1 */
+  {"1.3.6.1.5.5.7.8.5", "XmppAddr", 0, 1, "PKIX1.UTF8String"},
+
+  {NULL, NULL, 0, 0, ""}
 };
 
 /* Returns 1 if the data defined by the OID are printable.
@@ -172,6 +186,23 @@ _gnutls_x509_oid2ldap_string (const char *oid)
   return NULL;
 }
 
+const char *
+_gnutls_x509_oid2asn_string (const char *oid)
+{
+  int i = 0;
+
+  do
+    {
+      if (strcmp (_oid2str[i].oid, oid) == 0)
+       return _oid2str[i].asn_desc;
+      i++;
+    }
+  while (_oid2str[i].oid != NULL);
+
+  return NULL;
+}
+
+
 /* This function will convert an attribute value, specified by the OID,
  * to a string. The result will be a null terminated string.
  *
@@ -200,7 +231,7 @@ _gnutls_x509_oid_data2string (const char *oid, void *value,
       return GNUTLS_E_INTERNAL_ERROR;
     }
 
-  ANAME = asn1_find_structure_from_oid (_gnutls_get_pkix (), oid);
+  ANAME = _gnutls_x509_oid2asn_string(oid);
   CHOICE = _gnutls_x509_oid_data_choice (oid);
 
   if (ANAME == NULL)
@@ -209,11 +240,8 @@ _gnutls_x509_oid_data2string (const char *oid, void *value,
       return GNUTLS_E_INTERNAL_ERROR;
     }
 
-  _gnutls_str_cpy (str, sizeof (str), "PKIX1.");
-  _gnutls_str_cat (str, sizeof (str), ANAME);
-
   if ((result =
-       asn1_create_element (_gnutls_get_pkix (), str,
+       asn1_create_element (_gnutls_get_pkix (), ANAME,
                            &tmpasn)) != ASN1_SUCCESS)
     {
       gnutls_assert ();
@@ -342,7 +370,7 @@ _gnutls_x509_data2hex (const opaque * data, size_t 
data_size,
       return GNUTLS_E_INTERNAL_ERROR;
     }
 
-  res = _gnutls_bin2hex (data, data_size, escaped, sizeof (escaped));
+  res = _gnutls_bin2hex (data, data_size, escaped, sizeof (escaped), NULL);
   if (!res)
     {
       gnutls_assert ();
@@ -1138,6 +1166,18 @@ cleanup:
   return result;
 }
 
+void _asnstr_append_name(char* name, size_t name_size, const char* part1, 
const char* part2)
+{
+  if (part1[0] != 0) 
+    {
+         _gnutls_str_cpy (name, name_size, part1);
+         _gnutls_str_cat (name, name_size, part2);
+    }
+  else
+         _gnutls_str_cpy (name, name_size, part2+1 /* remove initial dot */);
+}
+
+
 /* Encodes and copies the private key parameters into a
  * subjectPublicKeyInfo structure.
  *
@@ -1163,8 +1203,8 @@ _gnutls_x509_encode_and_copy_PKI_params (ASN1_TYPE dst,
 
   /* write the OID
    */
-  _gnutls_str_cpy (name, sizeof (name), dst_name);
-  _gnutls_str_cat (name, sizeof (name), ".algorithm.algorithm");
+  _asnstr_append_name(name, sizeof(name), dst_name, ".algorithm.algorithm");
+
   result = asn1_write_value (dst, name, pk, 1);
   if (result != ASN1_SUCCESS)
     {
@@ -1176,8 +1216,8 @@ _gnutls_x509_encode_and_copy_PKI_params (ASN1_TYPE dst,
     {
       /* disable parameters, which are not used in RSA.
        */
-      _gnutls_str_cpy (name, sizeof (name), dst_name);
-      _gnutls_str_cat (name, sizeof (name), ".algorithm.parameters");
+         _asnstr_append_name(name, sizeof(name), dst_name, 
".algorithm.parameters");
+
       result = asn1_write_value (dst, name, NULL, 0);
       if (result != ASN1_SUCCESS)
        {
@@ -1194,8 +1234,7 @@ _gnutls_x509_encode_and_copy_PKI_params (ASN1_TYPE dst,
 
       /* Write the DER parameters. (in bits)
        */
-      _gnutls_str_cpy (name, sizeof (name), dst_name);
-      _gnutls_str_cat (name, sizeof (name), ".subjectPublicKey");
+         _asnstr_append_name(name, sizeof(name), dst_name, 
".subjectPublicKey");
       result = asn1_write_value (dst, name, der.data, der.size * 8);
 
       _gnutls_free_datum (&der);
@@ -1218,8 +1257,7 @@ _gnutls_x509_encode_and_copy_PKI_params (ASN1_TYPE dst,
 
       /* Write the DER parameters.
        */
-      _gnutls_str_cpy (name, sizeof (name), dst_name);
-      _gnutls_str_cat (name, sizeof (name), ".algorithm.parameters");
+         _asnstr_append_name(name, sizeof(name), dst_name, 
".algorithm.parameters");
       result = asn1_write_value (dst, name, der.data, der.size);
 
       _gnutls_free_datum (&der);
@@ -1237,8 +1275,7 @@ _gnutls_x509_encode_and_copy_PKI_params (ASN1_TYPE dst,
          return result;
        }
 
-      _gnutls_str_cpy (name, sizeof (name), dst_name);
-      _gnutls_str_cat (name, sizeof (name), ".subjectPublicKey");
+         _asnstr_append_name(name, sizeof(name), dst_name, 
".subjectPublicKey");
       result = asn1_write_value (dst, name, der.data, der.size * 8);
 
       _gnutls_free_datum (&der);
@@ -1271,9 +1308,8 @@ _gnutls_x509_get_pk_algorithm (ASN1_TYPE src, const char 
*src_name,
   bigint_t params[MAX_PUBLIC_PARAMS_SIZE];
   char name[128];
 
-  _gnutls_str_cpy (name, sizeof (name), src_name);
-  _gnutls_str_cat (name, sizeof (name), ".algorithm.algorithm");
 
+  _asnstr_append_name(name, sizeof(name), src_name, ".algorithm.algorithm");
   len = sizeof (oid);
   result = asn1_read_value (src, name, oid, &len);
 
@@ -1284,17 +1320,20 @@ _gnutls_x509_get_pk_algorithm (ASN1_TYPE src, const 
char *src_name,
     }
 
   algo = _gnutls_x509_oid2pk_algorithm (oid);
+  if (algo == GNUTLS_PK_UNKNOWN)
+    {
+      _gnutls_x509_log
+       ("%s: unknown public key algorithm: %s\n", __func__, oid);
+    }
 
   if (bits == NULL)
     {
-      gnutls_free (str);
       return algo;
     }
 
   /* Now read the parameters' bits 
    */
-  _gnutls_str_cpy (name, sizeof (name), src_name);
-  _gnutls_str_cat (name, sizeof (name), ".subjectPublicKey");
+  _asnstr_append_name(name, sizeof(name), src_name, ".subjectPublicKey");
 
   len = 0;
   result = asn1_read_value (src, name, NULL, &len);
@@ -1319,8 +1358,7 @@ _gnutls_x509_get_pk_algorithm (ASN1_TYPE src, const char 
*src_name,
       return GNUTLS_E_MEMORY_ERROR;
     }
 
-  _gnutls_str_cpy (name, sizeof (name), src_name);
-  _gnutls_str_cat (name, sizeof (name), ".subjectPublicKey");
+  _asnstr_append_name(name, sizeof(name), src_name, ".subjectPublicKey");
 
   result = asn1_read_value (src, name, str, &len);
 
@@ -1363,9 +1401,6 @@ _gnutls_x509_get_pk_algorithm (ASN1_TYPE src, const char 
*src_name,
        _gnutls_mpi_release (&params[3]);
       }
       break;
-    default:
-      _gnutls_x509_log
-       ("_gnutls_x509_get_pk_algorithm: unhandled algorithm %d\n", algo);
     }
 
   gnutls_free (str);
diff --git a/lib/x509/common.h b/lib/x509/common.h
index a2a94fe..3ab4644 100644
--- a/lib/x509/common.h
+++ b/lib/x509/common.h
@@ -41,6 +41,7 @@
 /* public key algorithm's OIDs
  */
 #define PK_PKIX1_RSA_OID "1.2.840.113549.1.1.1"
+#define PK_X509_RSA_OID "2.5.8.1.1"
 #define PK_DSA_OID "1.2.840.10040.4.1"
 #define PK_GOST_R3410_94_OID "1.2.643.2.2.20"
 #define PK_GOST_R3410_2001_OID "1.2.643.2.2.19"
@@ -48,6 +49,10 @@
 /* signature OIDs
  */
 #define SIG_DSA_SHA1_OID "1.2.840.10040.4.3"
+/* those two from draft-ietf-pkix-sha2-dsa-ecdsa-06 */
+#define SIG_DSA_SHA224_OID "2.16.840.1.101.3.4.3.1"
+#define SIG_DSA_SHA256_OID "2.16.840.1.101.3.4.3.2"
+
 #define SIG_RSA_MD5_OID "1.2.840.113549.1.1.4"
 #define SIG_RSA_MD2_OID "1.2.840.113549.1.1.2"
 #define SIG_RSA_SHA1_OID "1.2.840.113549.1.1.5"
@@ -69,6 +74,8 @@ int _gnutls_x509_oid_data2string (const char *OID, void 
*value,
 int _gnutls_x509_data2hex (const opaque * data, size_t data_size,
                           opaque * out, size_t * sizeof_out);
 
+const char * _gnutls_x509_oid2asn_string (const char *oid);
+
 const char *_gnutls_x509_oid2ldap_string (const char *OID);
 
 int _gnutls_x509_oid_data_choice (const char *OID);
@@ -130,4 +137,18 @@ int _gnutls_x509_get_signature (ASN1_TYPE src, const char 
*src_name,
 
 gnutls_digest_algorithm_t _gnutls_dsa_q_to_hash(bigint_t q);
 
+int _gnutls_get_asn_mpis (ASN1_TYPE asn, const char *root,
+          bigint_t * params, int *params_size);
+
+int _gnutls_get_key_id (gnutls_pk_algorithm_t pk, bigint_t* params, int 
params_size,
+                   unsigned char *output_data, size_t * output_data_size);
+
+void _asnstr_append_name(char* name, size_t name_size, const char* part1, 
const char* part2);
+
+int pubkey_verify_sig (const gnutls_datum_t * tbs,
+           const gnutls_datum_t * hash,
+           const gnutls_datum_t * signature,
+           gnutls_pk_algorithm_t pk, bigint_t * issuer_params,
+           int issuer_params_size);
+
 #endif
diff --git a/lib/x509/crl_write.c b/lib/x509/crl_write.c
index d355c4f..c9c784d 100644
--- a/lib/x509/crl_write.c
+++ b/lib/x509/crl_write.c
@@ -101,6 +101,7 @@ gnutls_x509_crl_sign2 (gnutls_x509_crl_t crl, 
gnutls_x509_crt_t issuer,
                       gnutls_digest_algorithm_t dig, unsigned int flags)
 {
   int result;
+  gnutls_privkey_t privkey;
 
   if (crl == NULL || issuer == NULL)
     {
@@ -108,19 +109,33 @@ gnutls_x509_crl_sign2 (gnutls_x509_crl_t crl, 
gnutls_x509_crt_t issuer,
       return GNUTLS_E_INVALID_REQUEST;
     }
 
-  /* disable all the unneeded OPTIONAL fields.
-   */
-  disable_optional_stuff (crl);
-
-  result = _gnutls_x509_pkix_sign (crl->crl, "tbsCertList",
-                                  dig, issuer, issuer_key);
+  result = gnutls_privkey_init(&privkey);
   if (result < 0)
     {
       gnutls_assert ();
       return result;
     }
 
-  return 0;
+  result = gnutls_privkey_import_x509(privkey, issuer_key, 0);
+  if (result < 0)
+    {
+      gnutls_assert ();
+      goto fail;
+    }
+
+  result = gnutls_x509_crl_privkey_sign (crl, issuer, privkey, dig, flags);
+  if (result < 0)
+    {
+      gnutls_assert ();
+      goto fail;
+    }
+
+  result = 0;
+
+fail:
+  gnutls_privkey_deinit(privkey);
+
+  return result;
 }
 
 /**
@@ -441,4 +456,49 @@ gnutls_x509_crl_set_number (gnutls_x509_crl_t crl,
   return 0;
 }
 
+/**
+ * gnutls_x509_crl_privkey_sign:
+ * @crl: should contain a gnutls_x509_crl_t structure
+ * @issuer: is the certificate of the certificate issuer
+ * @issuer_key: holds the issuer's private key
+ * @dig: The message digest to use. GNUTLS_DIG_SHA1 is the safe choice unless 
you know what you're doing.
+ * @flags: must be 0
+ *
+ * This function will sign the CRL with the issuer's private key, and
+ * will copy the issuer's information into the CRL.
+ *
+ * This must be the last step in a certificate CRL since all
+ * the previously set parameters are now signed.
+ *
+ * Returns: On success, %GNUTLS_E_SUCCESS is returned, otherwise a
+ *   negative error value.
+ **/
+int
+gnutls_x509_crl_privkey_sign (gnutls_x509_crl_t crl, gnutls_x509_crt_t issuer,
+                      gnutls_privkey_t issuer_key,
+                      gnutls_digest_algorithm_t dig, unsigned int flags)
+{
+  int result;
+
+  if (crl == NULL || issuer == NULL)
+    {
+      gnutls_assert ();
+      return GNUTLS_E_INVALID_REQUEST;
+    }
+
+  /* disable all the unneeded OPTIONAL fields.
+   */
+  disable_optional_stuff (crl);
+
+  result = _gnutls_x509_pkix_sign (crl->crl, "tbsCertList",
+                                  dig, issuer, issuer_key);
+  if (result < 0)
+    {
+      gnutls_assert ();
+      return result;
+    }
+
+  return 0;
+}
+
 #endif /* ENABLE_PKI */
diff --git a/lib/x509/crq.c b/lib/x509/crq.c
index 6a9113b..f80c280 100644
--- a/lib/x509/crq.c
+++ b/lib/x509/crq.c
@@ -999,6 +999,10 @@ gnutls_x509_crq_set_challenge_password (gnutls_x509_crq_t 
crq,
  * This must be the last step in a certificate request generation
  * since all the previously set parameters are now signed.
  *
+ * Use gnutls_x509_crq_get_preferred_hash_algorithm() to obtain
+ * the digest algorithm to use with the specified public key
+ * algorithm.
+ *
  * Returns: %GNUTLS_E_SUCCESS on success, otherwise an error.
  *   %GNUTLS_E_ASN1_VALUE_NOT_FOUND is returned if you didn't set all
  *   information in the certificate request (e.g., the version using
@@ -1010,7 +1014,7 @@ gnutls_x509_crq_sign2 (gnutls_x509_crq_t crq, 
gnutls_x509_privkey_t key,
                       gnutls_digest_algorithm_t dig, unsigned int flags)
 {
   int result;
-  gnutls_datum_t signature;
+  gnutls_privkey_t privkey;
 
   if (crq == NULL)
     {
@@ -1018,55 +1022,33 @@ gnutls_x509_crq_sign2 (gnutls_x509_crq_t crq, 
gnutls_x509_privkey_t key,
       return GNUTLS_E_INVALID_REQUEST;
     }
 
-  /* Make sure version field is set. */
-  if (gnutls_x509_crq_get_version (crq) == GNUTLS_E_ASN1_VALUE_NOT_FOUND)
-    {
-      result = gnutls_x509_crq_set_version (crq, 1);
-      if (result < 0)
-       {
-         gnutls_assert ();
-         return result;
-       }
-    }
-
-  /* Step 1. Self sign the request.
-   */
-  result =
-    _gnutls_x509_sign_tbs (crq->crq, "certificationRequestInfo",
-                          dig, key, &signature);
-
+  result = gnutls_privkey_init(&privkey);
   if (result < 0)
     {
       gnutls_assert ();
       return result;
     }
 
-  /* Step 2. write the signature (bits)
-   */
-  result =
-    asn1_write_value (crq->crq, "signature", signature.data,
-                     signature.size * 8);
-
-  _gnutls_free_datum (&signature);
-
-  if (result != ASN1_SUCCESS)
+  result = gnutls_privkey_import_x509(privkey, key, 0);
+  if (result < 0)
     {
       gnutls_assert ();
-      return _gnutls_asn2err (result);
+      goto fail;
     }
 
-  /* Step 3. Write the signatureAlgorithm field.
-   */
-  result = _gnutls_x509_write_sig_params (crq->crq, "signatureAlgorithm",
-                                         key->pk_algorithm, dig, key->params,
-                                         key->params_size);
+  result = gnutls_x509_crq_privkey_sign (crq, privkey, dig, flags);
   if (result < 0)
     {
       gnutls_assert ();
-      return result;
+      goto fail;
     }
 
-  return 0;
+  result = 0;
+
+fail:
+  gnutls_privkey_deinit(privkey);
+
+  return result;
 }
 
 /**
@@ -1083,7 +1065,16 @@ gnutls_x509_crq_sign2 (gnutls_x509_crq_t crq, 
gnutls_x509_privkey_t key,
 int
 gnutls_x509_crq_sign (gnutls_x509_crq_t crq, gnutls_x509_privkey_t key)
 {
-  return gnutls_x509_crq_sign2 (crq, key, GNUTLS_DIG_SHA1, 0);
+gnutls_digest_algorithm_t dig;
+int ret = gnutls_x509_crq_get_preferred_hash_algorithm (crq, &dig, NULL);
+
+  if (ret < 0)
+    {
+      gnutls_assert();
+      return ret;
+    }
+
+  return gnutls_x509_crq_sign2 (crq, key, dig, 0);
 }
 
 /**
@@ -2286,6 +2277,56 @@ gnutls_x509_crq_set_key_purpose_oid (gnutls_x509_crq_t 
crq,
   return 0;
 }
 
+/**
+ * gnutls_x509_crq_get_preferred_hash_algorithm:
+ * @crq: Holds the certificate
+ * @hash: The result of the call with the hash algorithm used for signature
+ * @mand: If non zero it means that the algorithm MUST use this hash. May be 
NULL.
+ *
+ * This function will read the certifcate and return the appropriate digest
+ * algorithm to use for signing with this certificate. Some certificates (i.e.
+ * DSA might not be able to sign without the preferred algorithm).
+ *
+ * Returns: the 0 if the hash algorithm is found. A negative value is
+ * returned on error.
+ *
+ * Since: 2.11.0
+ **/
+int
+gnutls_x509_crq_get_preferred_hash_algorithm (gnutls_x509_crq_t crq,
+                                     gnutls_digest_algorithm_t * hash, 
unsigned int *mand)
+{
+  bigint_t params[MAX_PUBLIC_PARAMS_SIZE];
+  int params_size;
+  int ret, i;
+
+  if (crq == NULL)
+    {
+      gnutls_assert ();
+      return GNUTLS_E_INVALID_REQUEST;
+    }
+
+  params_size = MAX_PUBLIC_PARAMS_SIZE;
+  ret = _gnutls_x509_crq_get_mpis (crq, params, &params_size);
+  if (ret < 0)
+    {
+      gnutls_assert ();
+      return ret;
+    }
+
+  ret = _gnutls_pk_get_hash_algorithm(gnutls_x509_crq_get_pk_algorithm (crq, 
NULL),
+    params, params_size, hash, mand);
+
+  /* release allocated mpis */
+  for (i = 0; i < params_size; i++)
+    {
+      _gnutls_mpi_release (&params[i]);
+    }
+
+  return ret;
+}
+
+
 static int
 rsadsa_crq_get_key_id (gnutls_x509_crq_t crq, int pk,
                       unsigned char *output_data, size_t * output_data_size)
@@ -2445,5 +2486,100 @@ gnutls_x509_crq_get_key_id (gnutls_x509_crq_t crq, 
unsigned int flags,
   return result;
 }
 
+/**
+ * gnutls_x509_crq_privkey_sign:
+ * @crq: should contain a #gnutls_x509_crq_t structure
+ * @key: holds a private key
+ * @dig: The message digest to use, i.e., %GNUTLS_DIG_SHA1
+ * @flags: must be 0
+ *
+ * This function will sign the certificate request with a private key.
+ * This must be the same key as the one used in
+ * gnutls_x509_crt_set_key() since a certificate request is self
+ * signed.
+ *
+ * This must be the last step in a certificate request generation
+ * since all the previously set parameters are now signed.
+ *
+ * Returns: %GNUTLS_E_SUCCESS on success, otherwise an error.
+ *   %GNUTLS_E_ASN1_VALUE_NOT_FOUND is returned if you didn't set all
+ *   information in the certificate request (e.g., the version using
+ *   gnutls_x509_crq_set_version()).
+ *
+ **/
+int
+gnutls_x509_crq_privkey_sign (gnutls_x509_crq_t crq, gnutls_privkey_t key,
+                      gnutls_digest_algorithm_t dig, unsigned int flags)
+{
+  int result;
+  gnutls_datum_t signature;
+  gnutls_datum_t tbs;
+
+  if (crq == NULL)
+    {
+      gnutls_assert ();
+      return GNUTLS_E_INVALID_REQUEST;
+    }
+
+  /* Make sure version field is set. */
+  if (gnutls_x509_crq_get_version (crq) == GNUTLS_E_ASN1_VALUE_NOT_FOUND)
+    {
+      result = gnutls_x509_crq_set_version (crq, 1);
+      if (result < 0)
+       {
+         gnutls_assert ();
+         return result;
+       }
+    }
+
+  /* Step 1. Self sign the request.
+   */
+  result =
+    _gnutls_x509_get_tbs (crq->crq, "certificationRequestInfo",
+                          &tbs);
+
+  if (result < 0)
+    {
+      gnutls_assert ();
+      return result;
+    }
+
+  result = gnutls_privkey_sign_data (key, dig, 0, &tbs, &signature);
+  gnutls_free(tbs.data);
+
+  if (result < 0)
+    {
+      gnutls_assert ();
+      return result;
+    }
+
+  /* Step 2. write the signature (bits)
+   */
+  result =
+    asn1_write_value (crq->crq, "signature", signature.data,
+                     signature.size * 8);
+
+  _gnutls_free_datum (&signature);
+
+  if (result != ASN1_SUCCESS)
+    {
+      gnutls_assert ();
+      return _gnutls_asn2err (result);
+    }
+
+  /* Step 3. Write the signatureAlgorithm field.
+   */
+  result = _gnutls_x509_write_sig_params (crq->crq, "signatureAlgorithm",
+                                         gnutls_privkey_get_pk_algorithm(key, 
NULL), dig);
+  if (result < 0)
+    {
+      gnutls_assert ();
+      return result;
+    }
+
+  return 0;
+}
+
+
 
 #endif /* ENABLE_PKI */
diff --git a/lib/x509/dn.c b/lib/x509/dn.c
index 726d3e4..d9e1592 100644
--- a/lib/x509/dn.c
+++ b/lib/x509/dn.c
@@ -281,7 +281,7 @@ _gnutls_x509_parse_dn (ASN1_TYPE asn1_struct,
              gnutls_assert ();
              _gnutls_x509_log
                ("Found OID: '%s' with value '%s'\n",
-                oid, _gnutls_bin2hex (value2, len, escaped, sizeof_escaped));
+                oid, _gnutls_bin2hex (value2, len, escaped, sizeof_escaped, 
NULL));
              goto cleanup;
            }
          STR_APPEND (str_escape (string, escaped, sizeof_escaped));
@@ -655,7 +655,7 @@ _gnutls_x509_encode_and_write_attribute (const char 
*given_oid,
 
   /* Find how to encode the data.
    */
-  val_name = asn1_find_structure_from_oid (_gnutls_get_pkix (), given_oid);
+  val_name = _gnutls_x509_oid2asn_string(given_oid);
   if (val_name == NULL)
     {
       gnutls_assert ();
@@ -663,10 +663,7 @@ _gnutls_x509_encode_and_write_attribute (const char 
*given_oid,
       return GNUTLS_E_X509_UNSUPPORTED_OID;
     }
 
-  _gnutls_str_cpy (tmp, sizeof (tmp), "PKIX1.");
-  _gnutls_str_cat (tmp, sizeof (tmp), val_name);
-
-  result = asn1_create_element (_gnutls_get_pkix (), tmp, &c2);
+  result = asn1_create_element (_gnutls_get_pkix (), val_name, &c2);
   if (result != ASN1_SUCCESS)
     {
       gnutls_assert ();
diff --git a/lib/x509/mpi.c b/lib/x509/mpi.c
index 76747f2..0190480 100644
--- a/lib/x509/mpi.c
+++ b/lib/x509/mpi.c
@@ -206,23 +206,32 @@ _gnutls_x509_read_dsa_pubkey (opaque * der, int dersize, 
bigint_t * params)
 
 /* Extracts DSA and RSA parameters from a certificate.
  */
-static int
-get_mpis (int pk_algorithm, ASN1_TYPE asn, const char *root,
+int
+_gnutls_get_asn_mpis (ASN1_TYPE asn, const char *root,
          bigint_t * params, int *params_size)
 {
   int result;
   char name[256];
   gnutls_datum_t tmp = { NULL, 0 };
+  gnutls_pk_algorithm pk_algorithm;
+
+  result = _gnutls_x509_get_pk_algorithm(asn, root, NULL);
+  if (result < 0)
+    {
+      gnutls_assert();
+      return result;
+    }
+  
+  pk_algorithm = result;
 
   /* Read the algorithm's parameters
    */
-  snprintf (name, sizeof (name), "%s.subjectPublicKey", root);
+  _asnstr_append_name(name, sizeof(name), root, ".subjectPublicKey");
   result = _gnutls_x509_read_value (asn, name, &tmp, 2);
 
   if (result < 0)
     {
       gnutls_assert ();
-      fprintf (stderr, "name: %s\n", name);
       return result;
     }
 
@@ -275,7 +284,7 @@ get_mpis (int pk_algorithm, ASN1_TYPE asn, const char *root,
        */
       _gnutls_free_datum (&tmp);
 
-      snprintf (name, sizeof (name), "%s.algorithm.parameters", root);
+      _asnstr_append_name(name, sizeof(name), root, ".algorithm.parameters");
       result = _gnutls_x509_read_value (asn, name, &tmp, 0);
 
       /* FIXME: If the parameters are not included in the certificate
@@ -321,13 +330,9 @@ int
 _gnutls_x509_crt_get_mpis (gnutls_x509_crt_t cert,
                           bigint_t * params, int *params_size)
 {
-  int pk_algorithm;
-
   /* Read the algorithm's OID
    */
-  pk_algorithm = gnutls_x509_crt_get_pk_algorithm (cert, NULL);
-
-  return get_mpis (pk_algorithm, cert->cert,
+  return _gnutls_get_asn_mpis (cert->cert,
                   "tbsCertificate.subjectPublicKeyInfo", params,
                   params_size);
 }
@@ -340,13 +345,9 @@ int
 _gnutls_x509_crq_get_mpis (gnutls_x509_crq_t cert,
                           bigint_t * params, int *params_size)
 {
-  int pk_algorithm;
-
   /* Read the algorithm's OID
    */
-  pk_algorithm = gnutls_x509_crq_get_pk_algorithm (cert, NULL);
-
-  return get_mpis (pk_algorithm, cert->crq,
+  return _gnutls_get_asn_mpis (cert->crq,
                   "certificationRequestInfo.subjectPKInfo", params,
                   params_size);
 }
@@ -422,8 +423,7 @@ cleanup:
 int
 _gnutls_x509_write_sig_params (ASN1_TYPE dst, const char *dst_name,
                               gnutls_pk_algorithm_t pk_algorithm,
-                              gnutls_digest_algorithm_t dig,
-                              bigint_t * params, int params_size)
+                              gnutls_digest_algorithm_t dig)
 {
   int result;
   char name[128];
@@ -436,6 +436,7 @@ _gnutls_x509_write_sig_params (ASN1_TYPE dst, const char 
*dst_name,
   if (pk == NULL)
     {
       gnutls_assert ();
+      _gnutls_debug_log("Cannot find OID for sign algorithm pk: %d dig: %d\n", 
(int)pk_algorithm, (int)dig);
       return GNUTLS_E_INVALID_REQUEST;
     }
 
diff --git a/lib/x509/output.c b/lib/x509/output.c
index f4ea366..126b88c 100644
--- a/lib/x509/output.c
+++ b/lib/x509/output.c
@@ -1096,6 +1096,8 @@ print_cert (gnutls_string * str, gnutls_x509_crt_t cert, 
int notsigned)
          name = _("unknown");
 
        addf (str, _("\tSubject Public Key Algorithm: %s\n"), name);
+       addf (str, _("\tCertificate Security Level: %s\n"), 
gnutls_sec_param_get_name(gnutls_pk_bits_to_sec_param(err, bits)));
+
 #ifdef ENABLE_PKI
        switch (err)
          {
diff --git a/lib/x509/privkey.c b/lib/x509/privkey.c
index f493804..2b8e213 100644
--- a/lib/x509/privkey.c
+++ b/lib/x509/privkey.c
@@ -34,6 +34,8 @@
 #include <x509_b64.h>
 #include <x509_int.h>
 #include <gnutls_pk.h>
+#include <sign.h>
+#include <gnutls_mpi.h>
 
 static int _gnutls_asn1_encode_rsa (ASN1_TYPE * c2, bigint_t * params);
 
@@ -63,7 +65,7 @@ gnutls_x509_privkey_init (gnutls_x509_privkey_t * key)
 
 /**
  * gnutls_x509_privkey_deinit:
- * @key: The structure to be initialized
+ * @key: The structure to be deinitialized
  *
  * This function will deinitialize a private key structure.
  **/
@@ -90,7 +92,7 @@ gnutls_x509_privkey_deinit (gnutls_x509_privkey_t key)
  * @src: The source key
  *
  * This function will copy a private key from source to destination
- * key.
+ * key. Destination has to be initialized.
  *
  * Returns: On success, %GNUTLS_E_SUCCESS is returned, otherwise a
  *   negative error value.
@@ -217,6 +219,20 @@ _gnutls_privkey_decode_pkcs1_rsa_key (const gnutls_datum_t 
* raw_key,
       goto error;
     }
 
+  if ((result = _gnutls_x509_read_int (pkey_asn, "exponent1",
+                                      &pk_params.params[6])) < 0)
+    {
+      gnutls_assert ();
+      goto error;
+    }
+
+  if ((result = _gnutls_x509_read_int (pkey_asn, "exponent2",
+                                      &pk_params.params[7])) < 0)
+    {
+      gnutls_assert ();
+      goto error;
+    }
+
 
   result = _gnutls_pk_fixup (GNUTLS_PK_RSA, GNUTLS_IMPORT, &pk_params);
   if (result < 0)
@@ -231,6 +247,8 @@ _gnutls_privkey_decode_pkcs1_rsa_key (const gnutls_datum_t 
* raw_key,
   pkey->params[3] = pk_params.params[3];
   pkey->params[4] = pk_params.params[4];
   pkey->params[5] = pk_params.params[5];
+  pkey->params[6] = pk_params.params[6];
+  pkey->params[7] = pk_params.params[7];
   pkey->params_size = pk_params.params_nr;
 
   return pkey_asn;
@@ -464,8 +482,42 @@ gnutls_x509_privkey_import_rsa_raw (gnutls_x509_privkey_t 
key,
                                    const gnutls_datum_t * q,
                                    const gnutls_datum_t * u)
 {
+  return gnutls_x509_privkey_import_rsa_raw2( key, m, e, d, p, q, u, NULL, 
NULL);
+}
+
+/**
+ * gnutls_x509_privkey_import_rsa_raw2:
+ * @key: The structure to store the parsed key
+ * @m: holds the modulus
+ * @e: holds the public exponent
+ * @d: holds the private exponent
+ * @p: holds the first prime (p)
+ * @q: holds the second prime (q)
+ * @u: holds the coefficient
+ *
+ * This function will convert the given RSA raw parameters to the
+ * native #gnutls_x509_privkey_t format.  The output will be stored in
+ * @key.
+ *
+ * Returns: On success, %GNUTLS_E_SUCCESS is returned, otherwise a
+ *   negative error value.
+ **/
+int
+gnutls_x509_privkey_import_rsa_raw2 (gnutls_x509_privkey_t key,
+                                   const gnutls_datum_t * m,
+                                   const gnutls_datum_t * e,
+                                   const gnutls_datum_t * d,
+                                   const gnutls_datum_t * p,
+                                   const gnutls_datum_t * q,
+                                   const gnutls_datum_t * u,
+                                   const gnutls_datum_t * e1,
+                                   const gnutls_datum_t * e2)
+{
   int i = 0, ret;
   size_t siz = 0;
+  gnutls_pk_params_st pk_params;
+
+  memset(&pk_params, 0, sizeof(pk_params));
 
   if (key == NULL)
     {
@@ -473,6 +525,8 @@ gnutls_x509_privkey_import_rsa_raw (gnutls_x509_privkey_t 
key,
       return GNUTLS_E_INVALID_REQUEST;
     }
 
+  key->params_size = 0;
+
   siz = m->size;
   if (_gnutls_mpi_scan_nz (&key->params[0], m->data, siz))
     {
@@ -480,6 +534,7 @@ gnutls_x509_privkey_import_rsa_raw (gnutls_x509_privkey_t 
key,
       FREE_RSA_PRIVATE_PARAMS;
       return GNUTLS_E_MPI_SCAN_FAILED;
     }
+  key->params_size++;
 
   siz = e->size;
   if (_gnutls_mpi_scan_nz (&key->params[1], e->data, siz))
@@ -488,6 +543,7 @@ gnutls_x509_privkey_import_rsa_raw (gnutls_x509_privkey_t 
key,
       FREE_RSA_PRIVATE_PARAMS;
       return GNUTLS_E_MPI_SCAN_FAILED;
     }
+  key->params_size++;
 
   siz = d->size;
   if (_gnutls_mpi_scan_nz (&key->params[2], d->data, siz))
@@ -496,6 +552,7 @@ gnutls_x509_privkey_import_rsa_raw (gnutls_x509_privkey_t 
key,
       FREE_RSA_PRIVATE_PARAMS;
       return GNUTLS_E_MPI_SCAN_FAILED;
     }
+  key->params_size++;
 
   siz = p->size;
   if (_gnutls_mpi_scan_nz (&key->params[3], p->data, siz))
@@ -504,6 +561,7 @@ gnutls_x509_privkey_import_rsa_raw (gnutls_x509_privkey_t 
key,
       FREE_RSA_PRIVATE_PARAMS;
       return GNUTLS_E_MPI_SCAN_FAILED;
     }
+  key->params_size++;
 
   siz = q->size;
   if (_gnutls_mpi_scan_nz (&key->params[4], q->data, siz))
@@ -512,6 +570,7 @@ gnutls_x509_privkey_import_rsa_raw (gnutls_x509_privkey_t 
key,
       FREE_RSA_PRIVATE_PARAMS;
       return GNUTLS_E_MPI_SCAN_FAILED;
     }
+  key->params_size++;
 
   siz = u->size;
   if (_gnutls_mpi_scan_nz (&key->params[5], u->data, siz))
@@ -520,16 +579,59 @@ gnutls_x509_privkey_import_rsa_raw (gnutls_x509_privkey_t 
key,
       FREE_RSA_PRIVATE_PARAMS;
       return GNUTLS_E_MPI_SCAN_FAILED;
     }
+  key->params_size++;
+
+  if (e1 && e2)
+    {
+      siz = e1->size;
+      if (_gnutls_mpi_scan_nz (&key->params[6], e1->data, siz))
+        {
+          gnutls_assert ();
+          FREE_RSA_PRIVATE_PARAMS;
+          return GNUTLS_E_MPI_SCAN_FAILED;
+        }
+      key->params_size++;
+
+      siz = e2->size;
+      if (_gnutls_mpi_scan_nz (&key->params[7], e2->data, siz))
+        {
+          gnutls_assert ();
+          FREE_RSA_PRIVATE_PARAMS;
+          return GNUTLS_E_MPI_SCAN_FAILED;
+        }
+       key->params_size++;
+    } 
+
+  for(i=0;i<key->params_size;i++)
+    {
+      pk_params.params[i] = key->params[i];
+    }
+
+  pk_params.params_nr = key->params_size;
+
+  ret = _gnutls_pk_fixup (GNUTLS_PK_RSA, GNUTLS_IMPORT, &pk_params);
+  if (ret < 0)
+    {
+      gnutls_assert ();
+      FREE_RSA_PRIVATE_PARAMS;
+      return ret;
+    }
+
+  for(i=0;i<pk_params.params_nr;i++)
+    {
+      key->params[i] = pk_params.params[i];
+    }
+  key->params_size = pk_params.params_nr;
 
   if (!key->crippled)
     {
       ret = _gnutls_asn1_encode_rsa (&key->key, key->params);
       if (ret < 0)
-       {
-         gnutls_assert ();
-         FREE_RSA_PRIVATE_PARAMS;
-         return ret;
-       }
+               {
+                 gnutls_assert ();
+                 FREE_RSA_PRIVATE_PARAMS;
+                 return ret;
+               }
     }
 
   key->params_size = RSA_PRIVATE_PARAMS;
@@ -750,9 +852,41 @@ gnutls_x509_privkey_export_rsa_raw (gnutls_x509_privkey_t 
key,
                                    gnutls_datum_t * d, gnutls_datum_t * p,
                                    gnutls_datum_t * q, gnutls_datum_t * u)
 {
+
+  return gnutls_x509_privkey_export_rsa_raw2(key, m, e, d, p, q, u, NULL, 
NULL);
+}
+
+/**
+ * gnutls_x509_privkey_export_rsa_raw2:
+ * @key: a structure that holds the rsa parameters
+ * @m: will hold the modulus
+ * @e: will hold the public exponent
+ * @d: will hold the private exponent
+ * @p: will hold the first prime (p)
+ * @q: will hold the second prime (q)
+ * @u: will hold the coefficient
+ * @e1: will hold the exponent 1
+ * @e2: will hold the exponent 2
+ *
+ * This function will export the RSA private key's parameters found
+ * in the given structure. The new parameters will be allocated using
+ * gnutls_malloc() and will be stored in the appropriate datum.
+ *
+ * Returns: On success, %GNUTLS_E_SUCCESS is returned, otherwise a
+ *   negative error value.
+ **/
+int
+gnutls_x509_privkey_export_rsa_raw2 (gnutls_x509_privkey_t key,
+                                   gnutls_datum_t * m, gnutls_datum_t * e,
+                                   gnutls_datum_t * d, gnutls_datum_t * p,
+                                   gnutls_datum_t * q, gnutls_datum_t * u,
+                                   gnutls_datum_t* e1, gnutls_datum_t* e2)
+{
   int ret;
   gnutls_pk_params_st pk_params;
 
+  memset (&pk_params, 0, sizeof (pk_params));
+
   if (key == NULL)
     {
       gnutls_assert ();
@@ -823,6 +957,28 @@ gnutls_x509_privkey_export_rsa_raw (gnutls_x509_privkey_t 
key,
       goto error;
     }
 
+  /* E1 */
+  if (e1)
+    {
+      ret = _gnutls_mpi_dprint (key->params[6], e1);
+      if (ret < 0)
+        {
+          gnutls_assert ();
+          goto error;
+        }
+    }
+
+  /* E2 */
+  if (e2)
+    {
+      ret = _gnutls_mpi_dprint (key->params[7], e2);
+      if (ret < 0)
+        {
+          gnutls_assert ();
+          goto error;
+        }
+    }
+
   gnutls_pk_params_release (&pk_params);
 
   return 0;
@@ -929,22 +1085,21 @@ gnutls_x509_privkey_export_dsa_raw 
(gnutls_x509_privkey_t key,
 static int
 _gnutls_asn1_encode_rsa (ASN1_TYPE * c2, bigint_t * params)
 {
-  int result, i;
-  size_t size[8], total;
-  opaque *m_data, *pube_data, *prie_data;
-  opaque *p1_data, *p2_data, *u_data, *exp1_data, *exp2_data;
-  opaque *all_data = NULL, *p;
-  bigint_t exp1 = NULL, exp2 = NULL, q1 = NULL, p1 = NULL;
+  int result;
   opaque null = '\0';
   gnutls_pk_params_st pk_params;
+  gnutls_datum_t m, e, d, p, q, u, exp1, exp2;
 
-  /* Read all the sizes */
-  total = 0;
-  for (i = 0; i < RSA_PRIVATE_PARAMS; i++)
-    {
-      _gnutls_mpi_print_lz (params[i], NULL, &size[i]);
-      total += size[i];
-    }
+  memset (&pk_params, 0, sizeof (pk_params));
+
+  memset(&m, 0, sizeof(m));
+  memset(&p, 0, sizeof(e));
+  memset(&q, 0, sizeof(d));
+  memset(&p, 0, sizeof(p));
+  memset(&q, 0, sizeof(q));
+  memset(&u, 0, sizeof(u));
+  memset(&exp1, 0, sizeof(exp1));
+  memset(&exp2, 0, sizeof(exp2));
 
   result = _gnutls_pk_params_copy (&pk_params, params, RSA_PRIVATE_PARAMS);
   if (result < 0)
@@ -960,88 +1115,63 @@ _gnutls_asn1_encode_rsa (ASN1_TYPE * c2, bigint_t * 
params)
       goto cleanup;
     }
 
-  q1 = _gnutls_mpi_alloc_like (pk_params.params[4]);
-  if (q1 == NULL)
+  /* retrieve as data */
+
+  result = _gnutls_mpi_dprint_lz( pk_params.params[0], &m);
+  if (result < 0)
     {
-      gnutls_assert ();
-      result = GNUTLS_E_MEMORY_ERROR;
+      gnutls_assert();
       goto cleanup;
     }
 
-  p1 = _gnutls_mpi_alloc_like (pk_params.params[3]);
-  if (p1 == NULL)
+  result = _gnutls_mpi_dprint_lz( pk_params.params[1], &e);
+  if (result < 0)
     {
-      gnutls_assert ();
-      result = GNUTLS_E_MEMORY_ERROR;
+      gnutls_assert();
       goto cleanup;
     }
 
-  /* inverse of q mod p */
-  _gnutls_mpi_print_lz (pk_params.params[5], NULL, &size[5]);
-  total += size[5];
-
-  _gnutls_mpi_sub_ui (p1, pk_params.params[3], 1);
-  _gnutls_mpi_sub_ui (q1, pk_params.params[4], 1);
-
-  exp1 = _gnutls_mpi_mod (pk_params.params[2], p1);
-  if (exp1 == NULL)
+  result = _gnutls_mpi_dprint_lz( pk_params.params[2], &d);
+  if (result < 0)
     {
-      gnutls_assert ();
-      result = GNUTLS_E_MEMORY_ERROR;
+      gnutls_assert();
       goto cleanup;
     }
 
-  exp2 = _gnutls_mpi_mod (pk_params.params[2], q1);
-  if (exp2 == NULL)
+  result = _gnutls_mpi_dprint_lz( pk_params.params[3], &p);
+  if (result < 0)
     {
-      gnutls_assert ();
-      result = GNUTLS_E_MEMORY_ERROR;
+      gnutls_assert();
       goto cleanup;
     }
 
-  /* calculate exp's size */
-  _gnutls_mpi_print_lz (exp1, NULL, &size[6]);
-  total += size[6];
+  result = _gnutls_mpi_dprint_lz( pk_params.params[4], &q);
+  if (result < 0)
+    {
+      gnutls_assert();
+      goto cleanup;
+    }
 
-  _gnutls_mpi_print_lz (exp2, NULL, &size[7]);
-  total += size[7];
+  result = _gnutls_mpi_dprint_lz( pk_params.params[5], &u);
+  if (result < 0)
+    {
+      gnutls_assert();
+      goto cleanup;
+    }
 
-  /* Encoding phase.
-   * allocate data enough to hold everything
-   */
-  all_data = gnutls_secure_malloc (total);
-  if (all_data == NULL)
+  result = _gnutls_mpi_dprint_lz( pk_params.params[6], &exp1);
+  if (result < 0)
     {
-      gnutls_assert ();
-      result = GNUTLS_E_MEMORY_ERROR;
+      gnutls_assert();
       goto cleanup;
     }
 
-  p = all_data;
-  m_data = p;
-  p += size[0];
-  pube_data = p;
-  p += size[1];
-  prie_data = p;
-  p += size[2];
-  p1_data = p;
-  p += size[3];
-  p2_data = p;
-  p += size[4];
-  u_data = p;
-  p += size[5];
-  exp1_data = p;
-  p += size[6];
-  exp2_data = p;
-
-  _gnutls_mpi_print_lz (pk_params.params[0], m_data, &size[0]);
-  _gnutls_mpi_print_lz (pk_params.params[1], pube_data, &size[1]);
-  _gnutls_mpi_print_lz (pk_params.params[2], prie_data, &size[2]);
-  _gnutls_mpi_print_lz (pk_params.params[3], p1_data, &size[3]);
-  _gnutls_mpi_print_lz (pk_params.params[4], p2_data, &size[4]);
-  _gnutls_mpi_print_lz (pk_params.params[5], u_data, &size[5]);
-  _gnutls_mpi_print_lz (exp1, exp1_data, &size[6]);
-  _gnutls_mpi_print_lz (exp2, exp2_data, &size[7]);
+  result = _gnutls_mpi_dprint_lz( pk_params.params[7], &exp2);
+  if (result < 0)
+    {
+      gnutls_assert();
+      goto cleanup;
+    }
 
   /* Ok. Now we have the data. Create the asn1 structures
    */
@@ -1065,7 +1195,7 @@ _gnutls_asn1_encode_rsa (ASN1_TYPE * c2, bigint_t * 
params)
   /* Write PRIME 
    */
   if ((result = asn1_write_value (*c2, "modulus",
-                                 m_data, size[0])) != ASN1_SUCCESS)
+                                 m.data, m.size)) != ASN1_SUCCESS)
     {
       gnutls_assert ();
       result = _gnutls_asn2err (result);
@@ -1073,7 +1203,7 @@ _gnutls_asn1_encode_rsa (ASN1_TYPE * c2, bigint_t * 
params)
     }
 
   if ((result = asn1_write_value (*c2, "publicExponent",
-                                 pube_data, size[1])) != ASN1_SUCCESS)
+                                 e.data, e.size)) != ASN1_SUCCESS)
     {
       gnutls_assert ();
       result = _gnutls_asn2err (result);
@@ -1081,7 +1211,7 @@ _gnutls_asn1_encode_rsa (ASN1_TYPE * c2, bigint_t * 
params)
     }
 
   if ((result = asn1_write_value (*c2, "privateExponent",
-                                 prie_data, size[2])) != ASN1_SUCCESS)
+                                 d.data, d.size)) != ASN1_SUCCESS)
     {
       gnutls_assert ();
       result = _gnutls_asn2err (result);
@@ -1089,7 +1219,7 @@ _gnutls_asn1_encode_rsa (ASN1_TYPE * c2, bigint_t * 
params)
     }
 
   if ((result = asn1_write_value (*c2, "prime1",
-                                 p1_data, size[3])) != ASN1_SUCCESS)
+                                 p.data, p.size)) != ASN1_SUCCESS)
     {
       gnutls_assert ();
       result = _gnutls_asn2err (result);
@@ -1097,44 +1227,38 @@ _gnutls_asn1_encode_rsa (ASN1_TYPE * c2, bigint_t * 
params)
     }
 
   if ((result = asn1_write_value (*c2, "prime2",
-                                 p2_data, size[4])) != ASN1_SUCCESS)
+                                 q.data, q.size)) != ASN1_SUCCESS)
     {
       gnutls_assert ();
       result = _gnutls_asn2err (result);
       goto cleanup;
     }
 
-  if ((result = asn1_write_value (*c2, "exponent1",
-                                 exp1_data, size[6])) != ASN1_SUCCESS)
+  if ((result = asn1_write_value (*c2, "coefficient",
+                                 u.data, u.size)) != ASN1_SUCCESS)
     {
       gnutls_assert ();
       result = _gnutls_asn2err (result);
+
       goto cleanup;
     }
 
-  if ((result = asn1_write_value (*c2, "exponent2",
-                                 exp2_data, size[7])) != ASN1_SUCCESS)
+  if ((result = asn1_write_value (*c2, "exponent1",
+                                 exp1.data, exp1.size)) != ASN1_SUCCESS)
     {
       gnutls_assert ();
       result = _gnutls_asn2err (result);
       goto cleanup;
     }
 
-  if ((result = asn1_write_value (*c2, "coefficient",
-                                 u_data, size[5])) != ASN1_SUCCESS)
+  if ((result = asn1_write_value (*c2, "exponent2",
+                                 exp2.data, exp2.size)) != ASN1_SUCCESS)
     {
       gnutls_assert ();
       result = _gnutls_asn2err (result);
       goto cleanup;
     }
 
-  _gnutls_mpi_release (&exp1);
-  _gnutls_mpi_release (&exp2);
-  _gnutls_mpi_release (&q1);
-  _gnutls_mpi_release (&p1);
-  gnutls_pk_params_release (&pk_params);
-  gnutls_free (all_data);
-
   if ((result = asn1_write_value (*c2, "otherPrimeInfos",
                                  NULL, 0)) != ASN1_SUCCESS)
     {
@@ -1150,16 +1274,22 @@ _gnutls_asn1_encode_rsa (ASN1_TYPE * c2, bigint_t * 
params)
       goto cleanup;
     }
 
-  return 0;
+  result = 0;
 
 cleanup:
-  _gnutls_mpi_release (&exp1);
-  _gnutls_mpi_release (&exp2);
-  _gnutls_mpi_release (&q1);
-  _gnutls_mpi_release (&p1);
+  if (result != 0)
+    asn1_delete_structure (c2);
+
   gnutls_pk_params_release (&pk_params);
-  asn1_delete_structure (c2);
-  gnutls_free (all_data);
+
+  _gnutls_free_datum(&m);
+  _gnutls_free_datum(&d);
+  _gnutls_free_datum(&e);
+  _gnutls_free_datum(&p);
+  _gnutls_free_datum(&q);
+  _gnutls_free_datum(&u);
+  _gnutls_free_datum(&exp1);
+  _gnutls_free_datum(&exp2);
 
   return result;
 }
@@ -1297,6 +1427,8 @@ cleanup:
  * This function will generate a random private key. Note that this
  * function must be called on an empty private key.
  *
+ * Do not set the number of bits directly, use gnutls_sec_param_to_pk_bits().
+ *
  * Returns: On success, %GNUTLS_E_SUCCESS is returned, otherwise a
  *   negative error value.
  **/
@@ -1319,6 +1451,12 @@ gnutls_x509_privkey_generate (gnutls_x509_privkey_t key,
     {
     case GNUTLS_PK_DSA:
       ret = _gnutls_dsa_generate_params (key->params, &params_len, bits);
+         if (params_len != DSA_PRIVATE_PARAMS)
+           {
+                       gnutls_assert();
+                       ret = GNUTLS_E_INTERNAL_ERROR;
+               }
+
       if (ret < 0)
        {
          gnutls_assert ();
@@ -1340,6 +1478,11 @@ gnutls_x509_privkey_generate (gnutls_x509_privkey_t key,
       break;
     case GNUTLS_PK_RSA:
       ret = _gnutls_rsa_generate_params (key->params, &params_len, bits);
+         if (params_len != RSA_PRIVATE_PARAMS)
+           {
+                       gnutls_assert();
+                       ret = GNUTLS_E_INTERNAL_ERROR;
+               }
       if (ret < 0)
        {
          gnutls_assert ();
@@ -1463,17 +1606,14 @@ cleanup:
   return result;
 }
 
-#ifdef ENABLE_PKI
 
 /**
- * gnutls_x509_privkey_sign_data:
- * @key: Holds the key
- * @digest: should be MD5 or SHAx. May be ignored.
+ * gnutls_x509_privkey_sign_data2:
+ * @signer: Holds the key
+ * @digest: should be MD5 or SHA1
  * @flags: should be 0 for now
  * @data: holds the data to be signed
- * @signature: will contain the signature
- * @signature_size: holds the size of signature (and will be replaced
- *   by the new size)
+ * @signature: will contain the signature allocate with gnutls_malloc()
  *
  * This function will sign the given data using a signature algorithm
  * supported by the private key. Signature algorithms are always used
@@ -1484,45 +1624,59 @@ cleanup:
  * address@hidden is updated and %GNUTLS_E_SHORT_MEMORY_BUFFER will
  * be returned.
  *
+ * Use gnutls_x509_crt_get_preferred_hash_algorithm() to determine
+ * the hash algorithm.
+ *
  * Returns: On success, %GNUTLS_E_SUCCESS is returned, otherwise a
  *   negative error value.
  **/
 int
-gnutls_x509_privkey_sign_data (gnutls_x509_privkey_t key,
-                              gnutls_digest_algorithm_t digest,
+gnutls_x509_privkey_sign_data2 (gnutls_x509_privkey_t signer,
+                              gnutls_digest_algorithm_t hash,
                               unsigned int flags,
                               const gnutls_datum_t * data,
-                              void *signature, size_t * signature_size)
+                              gnutls_datum_t * signature)
 {
-  int result;
-  gnutls_datum_t sig = { NULL, 0 };
-
-  if (key == NULL)
+  int ret;
+  gnutls_datum_t digest;
+  
+  switch (signer->pk_algorithm)
     {
-      gnutls_assert ();
-      return GNUTLS_E_INVALID_REQUEST;
-    }
+    case GNUTLS_PK_RSA:
+      ret =
+       pk_pkcs1_rsa_hash (hash, data, &digest);
+      if (ret < 0)
+       {
+         gnutls_assert ();
+         return ret;
+       }
+      break;
+    case GNUTLS_PK_DSA:
+      /* override hash for DSA */
+      ret = pk_dsa_hash (_gnutls_dsa_q_to_hash(signer->params[1]), data,  
&digest);
+      if (ret < 0)
+       {
+         gnutls_assert ();
+         return ret;
+       }
 
-  result = _gnutls_x509_sign (data, digest, key, &sig);
-  if (result < 0)
-    {
+      break;
+    default:
       gnutls_assert ();
-      return result;
+      return GNUTLS_E_INTERNAL_ERROR;
     }
-
-  if (*signature_size < sig.size)
+    
+  ret = gnutls_x509_privkey_sign_hash(signer, &digest, signature);
+  _gnutls_free_datum (&digest);
+                    
+  if (ret < 0)
     {
-      *signature_size = sig.size;
-      _gnutls_free_datum (&sig);
-      return GNUTLS_E_SHORT_MEMORY_BUFFER;
+      gnutls_assert ();
+      return ret;
     }
 
-  *signature_size = sig.size;
-  memcpy (signature, sig.data, sig.size);
-
-  _gnutls_free_datum (&sig);
-
   return 0;
+
 }
 
 /**
@@ -1552,7 +1706,7 @@ gnutls_x509_privkey_sign_hash (gnutls_x509_privkey_t key,
       return GNUTLS_E_INVALID_REQUEST;
     }
 
-  result = _gnutls_sign (key->pk_algorithm, key->params,
+  result = _gnutls_soft_sign (key->pk_algorithm, key->params,
                         key->params_size, hash, signature);
   if (result < 0)
     {
@@ -1563,6 +1717,71 @@ gnutls_x509_privkey_sign_hash (gnutls_x509_privkey_t key,
   return 0;
 }
 
+#ifdef ENABLE_PKI
+/**
+ * gnutls_x509_privkey_sign_data:
+ * @key: Holds the key
+ * @digest: should be MD5 or SHA1
+ * @flags: should be 0 for now
+ * @data: holds the data to be signed
+ * @signature: will contain the signature
+ * @signature_size: holds the size of signature (and will be replaced
+ *   by the new size)
+ *
+ * This function will sign the given data using a signature algorithm
+ * supported by the private key. Signature algorithms are always used
+ * together with a hash functions.  Different hash functions may be
+ * used for the RSA algorithm, but only SHA-1 for the DSA keys.
+ *
+ * If the buffer provided is not long enough to hold the output, then
+ * address@hidden is updated and %GNUTLS_E_SHORT_MEMORY_BUFFER will
+ * be returned.
+ *
+ * Use gnutls_x509_crt_get_preferred_hash_algorithm() to determine
+ * the hash algorithm.
+ *
+ * Returns: On success, %GNUTLS_E_SUCCESS is returned, otherwise a
+ *   negative error value.
+ **/
+int
+gnutls_x509_privkey_sign_data (gnutls_x509_privkey_t key,
+                              gnutls_digest_algorithm_t digest,
+                              unsigned int flags,
+                              const gnutls_datum_t * data,
+                              void *signature, size_t * signature_size)
+{
+  int result;
+  gnutls_datum_t sig = { NULL, 0 };
+
+  if (key == NULL)
+    {
+      gnutls_assert ();
+      return GNUTLS_E_INVALID_REQUEST;
+    }
+
+  result = gnutls_x509_privkey_sign_data2(key, digest, flags, data, &sig);
+  if (result < 0)
+    {
+      gnutls_assert ();
+      return result;
+    }
+
+  if (*signature_size < sig.size)
+    {
+      *signature_size = sig.size;
+      _gnutls_free_datum (&sig);
+      return GNUTLS_E_SHORT_MEMORY_BUFFER;
+    }
+
+  *signature_size = sig.size;
+  memcpy (signature, sig.data, sig.size);
+
+  _gnutls_free_datum (&sig);
+
+  return 0;
+}
+
+
 /**
  * gnutls_x509_privkey_verify_data:
  * @key: Holds the key
diff --git a/lib/x509/sign.c b/lib/x509/sign.c
index e74c48f..ca0f768 100644
--- a/lib/x509/sign.c
+++ b/lib/x509/sign.c
@@ -41,13 +41,15 @@
 #include <gnutls_datum.h>
 #include <x509_int.h>
 #include <common.h>
+#include <sign.h>
+#include <gnutls/abstract.h>
 
 /* Writes the digest information and the digest in a DER encoded
  * structure. The digest info is allocated and stored into the info structure.
  */
 static int
 encode_ber_digest_info (gnutls_digest_algorithm_t hash,
-                       const gnutls_datum_t * digest, gnutls_datum_t * info)
+                       const gnutls_datum_t * digest, gnutls_datum_t * output)
 {
   ASN1_TYPE dinfo = ASN1_TYPE_EMPTY;
   int result;
@@ -99,18 +101,18 @@ encode_ber_digest_info (gnutls_digest_algorithm_t hash,
       return _gnutls_asn2err (result);
     }
 
-  info->size = 0;
-  asn1_der_coding (dinfo, "", NULL, &info->size, NULL);
+  output->size = 0;
+  asn1_der_coding (dinfo, "", NULL, &output->size, NULL);
 
-  info->data = gnutls_malloc (info->size);
-  if (info->data == NULL)
+  output->data = gnutls_malloc (output->size);
+  if (output->data == NULL)
     {
       gnutls_assert ();
       asn1_delete_structure (&dinfo);
       return GNUTLS_E_MEMORY_ERROR;
     }
 
-  result = asn1_der_coding (dinfo, "", info->data, &info->size, NULL);
+  result = asn1_der_coding (dinfo, "", output->data, &output->size, NULL);
   if (result != ASN1_SUCCESS)
     {
       gnutls_assert ();
@@ -128,14 +130,13 @@ encode_ber_digest_info (gnutls_digest_algorithm_t hash,
  * params[0] is modulus
  * params[1] is public key
  */
-static int
-pkcs1_rsa_sign (gnutls_digest_algorithm_t hash, const gnutls_datum_t * text,
-               bigint_t * params, int params_len, gnutls_datum_t * signature)
+int
+pk_pkcs1_rsa_hash (gnutls_digest_algorithm_t hash, const gnutls_datum_t * 
text, gnutls_datum_t * output)
 {
   int ret;
   opaque _digest[MAX_HASH_SIZE];
   digest_hd_st hd;
-  gnutls_datum_t digest, info;
+  gnutls_datum_t digest;
 
   ret = _gnutls_hash_init (&hd, HASH2MAC (hash));
   if (ret < 0)
@@ -152,104 +153,53 @@ pkcs1_rsa_sign (gnutls_digest_algorithm_t hash, const 
gnutls_datum_t * text,
 
   /* Encode the digest as a DigestInfo
    */
-  if ((ret = encode_ber_digest_info (hash, &digest, &info)) != 0)
+  if ((ret = encode_ber_digest_info (hash, &digest, output)) != 0)
     {
       gnutls_assert ();
       return ret;
     }
 
-  if ((ret =
-       _gnutls_sign (GNUTLS_PK_RSA, params, params_len, &info,
-                    signature)) < 0)
-    {
-      gnutls_assert ();
-      _gnutls_free_datum (&info);
-      return ret;
-    }
-
-  _gnutls_free_datum (&info);
-
   return 0;
 }
 
-static int
-dsa_sign (const gnutls_datum_t * text,
-         bigint_t * params, int params_len, gnutls_datum_t * signature)
+int
+pk_dsa_hash (gnutls_digest_algorithm_t hash, const gnutls_datum_t * text, 
gnutls_datum_t * digest)
 {
   int ret;
-  opaque _digest[MAX_HASH_SIZE];
   digest_hd_st hd;
-  gnutls_datum_t digest;
-  gnutls_digest_algorithm_t hash = _gnutls_dsa_q_to_hash(params[1]);
+
+  if (hash != GNUTLS_DIG_SHA1 && hash != GNUTLS_DIG_SHA224 &&
+    hash != GNUTLS_DIG_SHA256)
+    {
+      gnutls_assert();
+      return GNUTLS_E_INVALID_REQUEST;
+    }
+
+  digest->size = _gnutls_hash_get_algo_len(hash);
+  digest->data = gnutls_malloc( digest->size);
+  if (digest->data == NULL)
+    {
+      gnutls_assert();
+      return GNUTLS_E_MEMORY_ERROR;
+    }
 
   ret = _gnutls_hash_init (&hd, hash);
   if (ret < 0)
     {
       gnutls_assert ();
-      return ret;
+      goto fail;
     }
 
   _gnutls_hash (&hd, text->data, text->size);
-  _gnutls_hash_deinit (&hd, _digest);
 
-  digest.data = _digest;
-  digest.size = _gnutls_hash_get_algo_len(hash);
-
-  if ((ret =
-       _gnutls_sign (GNUTLS_PK_DSA, params, params_len, &digest,
-                    signature)) < 0)
-    {
-      gnutls_assert ();
-      return ret;
-    }
+  _gnutls_hash_deinit (&hd, digest->data);
 
   return 0;
-}
-
-/* Signs the given data using the parameters from the signer's
- * private key.
- *
- * returns 0 on success.
- * 
- * 'tbs' is the data to be signed
- * 'signature' will hold the signature!
- * 'hash' is only used in PKCS1 RSA signing.
- */
-int
-_gnutls_x509_sign (const gnutls_datum_t * tbs,
-                  gnutls_digest_algorithm_t hash,
-                  gnutls_x509_privkey_t signer, gnutls_datum_t * signature)
-{
-  int ret;
 
-  switch (signer->pk_algorithm)
-    {
-    case GNUTLS_PK_RSA:
-      ret =
-       pkcs1_rsa_sign (hash, tbs, signer->params, signer->params_size,
-                       signature);
-      if (ret < 0)
-       {
-         gnutls_assert ();
-         return ret;
-       }
-      return 0;
-      break;
-    case GNUTLS_PK_DSA:
-      ret = dsa_sign (tbs, signer->params, signer->params_size, signature);
-      if (ret < 0)
-       {
-         gnutls_assert ();
-         return ret;
-       }
-
-      return 0;
-      break;
-    default:
-      gnutls_assert ();
-      return GNUTLS_E_INTERNAL_ERROR;
-    }
+fail:
+  gnutls_free(digest->data);
 
+  return ret;
 }
 
 /* This is the same as the _gnutls_x509_sign, but this one will decode
@@ -257,15 +207,12 @@ _gnutls_x509_sign (const gnutls_datum_t * tbs,
  * of the TBS and sign it on the fly.
  */
 int
-_gnutls_x509_sign_tbs (ASN1_TYPE cert, const char *tbs_name,
-                      gnutls_digest_algorithm_t hash,
-                      gnutls_x509_privkey_t signer,
-                      gnutls_datum_t * signature)
+_gnutls_x509_get_tbs (ASN1_TYPE cert, const char *tbs_name,
+                      gnutls_datum_t * tbs)
 {
   int result;
   opaque *buf;
   int buf_size;
-  gnutls_datum_t tbs;
 
   buf_size = 0;
   asn1_der_coding (cert, tbs_name, NULL, &buf_size, NULL);
@@ -286,13 +233,10 @@ _gnutls_x509_sign_tbs (ASN1_TYPE cert, const char 
*tbs_name,
       return _gnutls_asn2err (result);
     }
 
-  tbs.data = buf;
-  tbs.size = buf_size;
-
-  result = _gnutls_x509_sign (&tbs, hash, signer, signature);
-  gnutls_free (buf);
+  tbs->data = buf;
+  tbs->size = buf_size;
 
-  return result;
+  return 0;
 }
 
 /*-
@@ -311,10 +255,11 @@ int
 _gnutls_x509_pkix_sign (ASN1_TYPE src, const char *src_name,
                        gnutls_digest_algorithm_t dig,
                        gnutls_x509_crt_t issuer,
-                       gnutls_x509_privkey_t issuer_key)
+                       gnutls_privkey_t issuer_key)
 {
   int result;
   gnutls_datum_t signature;
+  gnutls_datum_t tbs;
   char name[128];
 
   /* Step 1. Copy the issuer's name into the certificate.
@@ -335,9 +280,7 @@ _gnutls_x509_pkix_sign (ASN1_TYPE src, const char *src_name,
   _gnutls_str_cat (name, sizeof (name), ".signature");
 
   result = _gnutls_x509_write_sig_params (src, name,
-                                         issuer_key->pk_algorithm, dig,
-                                         issuer_key->params,
-                                         issuer_key->params_size);
+                                         
gnutls_privkey_get_pk_algorithm(issuer_key, NULL), dig);
   if (result < 0)
     {
       gnutls_assert ();
@@ -346,7 +289,16 @@ _gnutls_x509_pkix_sign (ASN1_TYPE src, const char 
*src_name,
 
   /* Step 2. Sign the certificate.
    */
-  result = _gnutls_x509_sign_tbs (src, src_name, dig, issuer_key, &signature);
+  result = _gnutls_x509_get_tbs (src, src_name, &tbs);
+
+  if (result < 0)
+    {
+      gnutls_assert ();
+      return result;
+    }
+
+  result = gnutls_privkey_sign_data (issuer_key, dig, 0, &tbs, &signature);
+  gnutls_free(tbs.data);
 
   if (result < 0)
     {
@@ -372,9 +324,7 @@ _gnutls_x509_pkix_sign (ASN1_TYPE src, const char *src_name,
    */
 
   result = _gnutls_x509_write_sig_params (src, "signatureAlgorithm",
-                                         issuer_key->pk_algorithm, dig,
-                                         issuer_key->params,
-                                         issuer_key->params_size);
+                                         
gnutls_privkey_get_pk_algorithm(issuer_key, NULL), dig);
   if (result < 0)
     {
       gnutls_assert ();
diff --git a/lib/x509/sign.h b/lib/x509/sign.h
new file mode 100644
index 0000000..cce2ca8
--- /dev/null
+++ b/lib/x509/sign.h
@@ -0,0 +1,7 @@
+#ifndef GNUTLS_SIGN_H
+# define GNUTLS_SIGN_H
+
+int pk_pkcs1_rsa_hash (gnutls_digest_algorithm_t hash, const gnutls_datum_t * 
text, gnutls_datum_t * output);
+int pk_dsa_hash (gnutls_digest_algorithm_t hash, const gnutls_datum_t * text, 
gnutls_datum_t * output);
+
+#endif
diff --git a/lib/x509/verify.c b/lib/x509/verify.c
index 8ef697b..8efc3a4 100644
--- a/lib/x509/verify.c
+++ b/lib/x509/verify.c
@@ -53,15 +53,38 @@ static int _gnutls_verify_crl2 (gnutls_x509_crl_t crl,
                                int tcas_size, unsigned int flags,
                                unsigned int *output);
 
-/* Checks if two certs are identical.  Return 0 onn match. */
+/* Checks if two certs are identical.  Return 0 on match. */
 static int
 check_if_same_cert (gnutls_x509_crt_t cert1, gnutls_x509_crt_t cert2)
 {
   gnutls_datum_t cert1bin = { NULL, 0 }, cert2bin =
-  {
-  NULL, 0};
+  {NULL, 0};
   int result;
+  opaque serial1[128], serial2[128];
+  size_t serial1_size, serial2_size;
+
+  serial1_size = sizeof (serial1);
+  result = gnutls_x509_crt_get_serial (cert1, serial1, &serial1_size);
+  if (result < 0)
+    {
+      gnutls_assert ();
+      goto cmp;
+    }
+
+  serial2_size = sizeof (serial2);
+  result = gnutls_x509_crt_get_serial (cert2, serial2, &serial2_size);
+  if (result < 0)
+    {
+      gnutls_assert ();
+      goto cmp;
+    }
 
+  if (serial2_size != serial1_size || memcmp(serial1, serial2, serial1_size) 
!= 0)
+    {
+      return 1;
+    }
+
+cmp:
   result = _gnutls_x509_der_encode (cert1->cert, "", &cert1bin, 0);
   if (result < 0)
     {
@@ -800,8 +823,8 @@ dsa_verify_sig (const gnutls_datum_t * text,
 /* Verifies the signature data, and returns 0 if not verified,
  * or 1 otherwise.
  */
-static int
-verify_sig (const gnutls_datum_t * tbs,
+int
+pubkey_verify_sig (const gnutls_datum_t * tbs,
            const gnutls_datum_t * hash,
            const gnutls_datum_t * signature,
            gnutls_pk_algorithm_t pk, bigint_t * issuer_params,
@@ -852,29 +875,22 @@ gnutls_digest_algorithm_t _gnutls_dsa_q_to_hash(bigint_t 
q)
   }
 }
 
+/* This will return the appropriate hash to verify the given signature.
+ * If signature is NULL it will return an (or the) appropriate hash for
+ * the given parameters.
+ */
 int
 _gnutls_x509_verify_algorithm (gnutls_mac_algorithm_t * hash,
                               const gnutls_datum_t * signature,
-                              const gnutls_x509_crt_t issuer)
+                              gnutls_pk_algorithm pk,
+                              bigint_t* issuer_params, unsigned int 
issuer_params_size)
 {
-  bigint_t issuer_params[MAX_PUBLIC_PARAMS_SIZE];
   opaque digest[MAX_HASH_SIZE];
   gnutls_datum_t decrypted;
-  int issuer_params_size;
   int digest_size;
-  int ret, i;
-
-  issuer_params_size = MAX_PUBLIC_PARAMS_SIZE;
-  ret =
-    _gnutls_x509_crt_get_mpis (issuer, issuer_params,
-                                  &issuer_params_size);
-  if (ret < 0)
-    {
-      gnutls_assert ();
-      return ret;
-    }
+  int ret;
 
-  switch (gnutls_x509_crt_get_pk_algorithm (issuer, NULL))
+  switch(pk)
     {
     case GNUTLS_PK_DSA:
       
@@ -883,8 +899,12 @@ _gnutls_x509_verify_algorithm (gnutls_mac_algorithm_t * 
hash,
 
       ret = 0;
       break;
-
     case GNUTLS_PK_RSA:
+      if (signature == NULL) {/* return a sensible algorithm */
+        if (hash)
+          *hash = GNUTLS_DIG_SHA256;
+        return 0;
+      }
 
       ret =
        _gnutls_pkcs1_rsa_decrypt (&decrypted, signature,
@@ -924,11 +944,6 @@ _gnutls_x509_verify_algorithm (gnutls_mac_algorithm_t * 
hash,
     }
 
 cleanup:
-    /* release allocated mpis */
-  for (i = 0; i < issuer_params_size; i++)
-    {
-      _gnutls_mpi_release (&issuer_params[i]);
-    }
 
   return ret;
 
@@ -961,7 +976,7 @@ _gnutls_x509_verify_signature (const gnutls_datum_t * tbs,
     }
 
   ret =
-    verify_sig (tbs, hash, signature,
+    pubkey_verify_sig (tbs, hash, signature,
                gnutls_x509_crt_get_pk_algorithm (issuer, NULL),
                issuer_params, issuer_params_size);
   if (ret < 0)
@@ -992,7 +1007,7 @@ _gnutls_x509_privkey_verify_signature (const 
gnutls_datum_t * tbs,
 {
   int ret;
 
-  ret = verify_sig (tbs, NULL, signature, issuer->pk_algorithm,
+  ret = pubkey_verify_sig (tbs, NULL, signature, issuer->pk_algorithm,
                    issuer->params, issuer->params_size);
   if (ret < 0)
     {
diff --git a/lib/x509/x509.c b/lib/x509/x509.c
index 94a8b81..acca0d1 100644
--- a/lib/x509/x509.c
+++ b/lib/x509/x509.c
@@ -465,7 +465,8 @@ gnutls_x509_crt_get_dn_oid (gnutls_x509_crt_t cert,
  * @cert: should contain a #gnutls_x509_crt_t structure
  *
  * This function will return a value of the #gnutls_sign_algorithm_t
- * enumeration that is the signature algorithm.
+ * enumeration that is the signature algorithm that has been used to
+ * sign this certificate.
  *
  * Returns: a #gnutls_sign_algorithm_t value, or a negative value on
  *   error.
@@ -2184,22 +2185,19 @@ gnutls_x509_crt_export (gnutls_x509_crt_t cert,
                                  output_data, output_data_size);
 }
 
-
-static int
-rsadsa_get_key_id (gnutls_x509_crt_t crt, int pk,
+int
+_gnutls_get_key_id (gnutls_pk_algorithm_t pk, bigint_t* params, int 
params_size,
                   unsigned char *output_data, size_t * output_data_size)
 {
-  bigint_t params[MAX_PUBLIC_PARAMS_SIZE];
-  int params_size = MAX_PUBLIC_PARAMS_SIZE;
-  int i, result = 0;
+  int result = 0;
   gnutls_datum_t der = { NULL, 0 };
   digest_hd_st hd;
 
-  result = _gnutls_x509_crt_get_mpis (crt, params, &params_size);
-  if (result < 0)
+  if (output_data==NULL || *output_data_size < 20)
     {
-      gnutls_assert ();
-      return result;
+      gnutls_assert();
+      *output_data_size = 20;
+      return GNUTLS_E_SHORT_MEMORY_BUFFER;
     }
 
   if (pk == GNUTLS_PK_RSA)
@@ -2240,6 +2238,35 @@ rsadsa_get_key_id (gnutls_x509_crt_t crt, int pk,
 cleanup:
 
   _gnutls_free_datum (&der);
+  return result;
+}
+
+
+static int
+rsadsa_get_key_id (gnutls_x509_crt_t crt, int pk,
+                  unsigned char *output_data, size_t * output_data_size)
+{
+  bigint_t params[MAX_PUBLIC_PARAMS_SIZE];
+  int params_size = MAX_PUBLIC_PARAMS_SIZE;
+  int i, result = 0;
+
+  result = _gnutls_x509_crt_get_mpis (crt, params, &params_size);
+  if (result < 0)
+    {
+      gnutls_assert ();
+      return result;
+    }
+
+  result = _gnutls_get_key_id(pk, params, params_size, output_data, 
output_data_size);
+  if (result < 0)
+    {
+      gnutls_assert ();
+      goto cleanup;
+    }
+
+  result = 0;
+
+cleanup:
 
   /* release all allocated MPIs
    */
@@ -2308,6 +2335,9 @@ gnutls_x509_crt_get_key_id (gnutls_x509_crt_t crt, 
unsigned int flags,
       return rsadsa_get_key_id (crt, pk, output_data, output_data_size);
     }
 
+  /* FIXME: what does this code do here? Isn't identical to the code
+   * in rsadsa_get_key_id?
+   */
   pubkey.size = 0;
   result = asn1_der_coding (crt->cert, "tbsCertificate.subjectPublicKeyInfo",
                            NULL, &pubkey.size, NULL);
@@ -2470,14 +2500,90 @@ gnutls_x509_crt_get_verify_algorithm (gnutls_x509_crt_t 
crt,
                                      const gnutls_datum_t * signature,
                                      gnutls_digest_algorithm_t * hash)
 {
+  bigint_t issuer_params[MAX_PUBLIC_PARAMS_SIZE];
+  int issuer_params_size;
+  int ret, i;
+
   if (crt == NULL)
     {
       gnutls_assert ();
       return GNUTLS_E_INVALID_REQUEST;
     }
 
-  return _gnutls_x509_verify_algorithm ((gnutls_mac_algorithm_t *) hash,
-                                       signature, crt);
+  issuer_params_size = MAX_PUBLIC_PARAMS_SIZE;
+  ret =
+       _gnutls_x509_crt_get_mpis (crt, issuer_params,
+                                  &issuer_params_size);
+  if (ret < 0)
+    {
+      gnutls_assert ();
+      return ret;
+    }
+
+  ret = _gnutls_x509_verify_algorithm ((gnutls_mac_algorithm_t *) hash,
+                       signature, gnutls_x509_crt_get_pk_algorithm (crt, NULL),
+                       issuer_params, issuer_params_size);
+
+  /* release allocated mpis */
+  for (i = 0; i < issuer_params_size; i++)
+    {
+      _gnutls_mpi_release (&issuer_params[i]);
+    }
+
+  return ret;
+}
+
+
+
+/**
+ * gnutls_x509_crt_get_preferred_hash_algorithm:
+ * @crt: Holds the certificate
+ * @hash: The result of the call with the hash algorithm used for signature
+ * @mand: If non zero it means that the algorithm MUST use this hash. May be 
NULL.
+ *
+ * This function will read the certifcate and return the appropriate digest
+ * algorithm to use for signing with this certificate. Some certificates (i.e.
+ * DSA might not be able to sign without the preferred algorithm).
+ *
+ * Returns: the 0 if the hash algorithm is found. A negative value is
+ * returned on error.
+ *
+ * Since: 2.11.0
+ **/
+int
+gnutls_x509_crt_get_preferred_hash_algorithm (gnutls_x509_crt_t crt,
+                                     gnutls_digest_algorithm_t * hash, 
unsigned int *mand)
+{
+  bigint_t issuer_params[MAX_PUBLIC_PARAMS_SIZE];
+  int issuer_params_size;
+  int ret, i;
+
+  if (crt == NULL)
+    {
+      gnutls_assert ();
+      return GNUTLS_E_INVALID_REQUEST;
+    }
+
+  issuer_params_size = MAX_PUBLIC_PARAMS_SIZE;
+  ret =
+       _gnutls_x509_crt_get_mpis (crt, issuer_params,
+                                  &issuer_params_size);
+  if (ret < 0)
+    {
+      gnutls_assert ();
+      return ret;
+    }
+
+  ret = _gnutls_pk_get_hash_algorithm(gnutls_x509_crt_get_pk_algorithm (crt, 
NULL),
+    issuer_params, issuer_params_size, hash, mand);
+
+  /* release allocated mpis */
+  for (i = 0; i < issuer_params_size; i++)
+    {
+      _gnutls_mpi_release (&issuer_params[i]);
+    }
+
+  return ret;
 }
 
 /**
diff --git a/lib/x509/x509_int.h b/lib/x509/x509_int.h
index 6ea8ee8..b29b732 100644
--- a/lib/x509/x509_int.h
+++ b/lib/x509/x509_int.h
@@ -27,6 +27,7 @@
 # define X509_H
 
 #include <gnutls/x509.h>
+#include <gnutls/abstract.h>
 
 #include <libtasn1.h>
 
@@ -71,12 +72,12 @@ typedef struct gnutls_pkcs7_int
   ASN1_TYPE pkcs7;
 } gnutls_pkcs7_int;
 
-#define MAX_PRIV_PARAMS_SIZE GNUTLS_MAX_PK_PARAMS      /* ok for RSA and DSA */
+#define MAX_PRIV_PARAMS_SIZE GNUTLS_MAX_PK_PARAMS /* ok for RSA and DSA */
 
 /* parameters should not be larger than this limit */
 #define DSA_PRIVATE_PARAMS 5
 #define DSA_PUBLIC_PARAMS 4
-#define RSA_PRIVATE_PARAMS 6
+#define RSA_PRIVATE_PARAMS 8
 #define RSA_PUBLIC_PARAMS 2
 
 #if MAX_PRIV_PARAMS_SIZE - RSA_PRIVATE_PARAMS < 0
@@ -102,7 +103,12 @@ typedef struct gnutls_x509_privkey_int
    *      [4] is prime2 (q)
    *      [5] is coefficient (u == inverse of p mod q)
    *          note that other packages used inverse of q mod p,
-   *          so we need to perform conversions.
+   *          so we need to perform conversions on import/export
+   *          using fixup.
+   *      The following two are also not always available thus fixup
+   *      will generate them.
+   *     [6] e1 == d mod (p-1)
+   *     [7] e2 == d mod (q-1)
    * DSA: [0] is p
    *      [1] is q
    *      [2] is g
@@ -134,18 +140,12 @@ int _gnutls_x509_crl_get_raw_issuer_dn (gnutls_x509_crl_t 
crl,
                                        gnutls_datum_t * dn);
 
 /* sign.c */
-int _gnutls_x509_sign (const gnutls_datum_t * tbs,
-                      gnutls_digest_algorithm_t hash,
-                      gnutls_x509_privkey_t signer,
-                      gnutls_datum_t * signature);
-int _gnutls_x509_sign_tbs (ASN1_TYPE cert, const char *tbs_name,
-                          gnutls_digest_algorithm_t hash,
-                          gnutls_x509_privkey_t signer,
-                          gnutls_datum_t * signature);
+int _gnutls_x509_get_tbs (ASN1_TYPE cert, const char *tbs_name,
+                          gnutls_datum_t * tbs);
 int _gnutls_x509_pkix_sign (ASN1_TYPE src, const char *src_name,
                            gnutls_digest_algorithm_t,
                            gnutls_x509_crt_t issuer,
-                           gnutls_x509_privkey_t issuer_key);
+                           gnutls_privkey_t issuer_key);
 
 /* dn.c */
 #define OID_X520_COUNTRY_NAME          "2.5.4.6"
@@ -185,9 +185,13 @@ int _gnutls_parse_general_name (ASN1_TYPE src, const char 
*src_name,
 /* verify.c */
 int gnutls_x509_crt_is_issuer (gnutls_x509_crt_t cert,
                               gnutls_x509_crt_t issuer);
-int _gnutls_x509_verify_algorithm (gnutls_mac_algorithm_t * hash,
-                                  const gnutls_datum_t * signature,
-                                  const gnutls_x509_crt_t crt);
+
+int
+_gnutls_x509_verify_algorithm (gnutls_mac_algorithm_t * hash,
+                              const gnutls_datum_t * signature,
+                              gnutls_pk_algorithm pk,
+                              bigint_t* issuer_params, unsigned int 
issuer_params_size);
+
 int _gnutls_x509_verify_signature (const gnutls_datum_t * tbs,
                                   const gnutls_datum_t * hash,
                                   const gnutls_datum_t * signature,
@@ -307,8 +311,8 @@ int _gnutls_x509_write_uint32 (ASN1_TYPE node, const char 
*value,
 
 int _gnutls_x509_write_sig_params (ASN1_TYPE dst, const char *dst_name,
                                   gnutls_pk_algorithm_t pk_algorithm,
-                                  gnutls_digest_algorithm_t,
-                                  bigint_t * params, int params_size);
+                                  gnutls_digest_algorithm_t);
+
 /* pkcs12.h */
 #include <gnutls/pkcs12.h>
 
diff --git a/lib/x509/x509_write.c b/lib/x509/x509_write.c
index f65e7af..dc47af2 100644
--- a/lib/x509/x509_write.c
+++ b/lib/x509/x509_write.c
@@ -752,6 +752,7 @@ gnutls_x509_crt_sign2 (gnutls_x509_crt_t crt, 
gnutls_x509_crt_t issuer,
                       gnutls_digest_algorithm_t dig, unsigned int flags)
 {
   int result;
+  gnutls_privkey_t privkey;
 
   if (crt == NULL || issuer == NULL || issuer_key == NULL)
     {
@@ -759,19 +760,33 @@ gnutls_x509_crt_sign2 (gnutls_x509_crt_t crt, 
gnutls_x509_crt_t issuer,
       return GNUTLS_E_INVALID_REQUEST;
     }
 
-  /* disable all the unneeded OPTIONAL fields.
-   */
-  disable_optional_stuff (crt);
-
-  result = _gnutls_x509_pkix_sign (crt->cert, "tbsCertificate",
-                                  dig, issuer, issuer_key);
+  result = gnutls_privkey_init(&privkey);
   if (result < 0)
     {
       gnutls_assert ();
       return result;
     }
 
-  return 0;
+  result = gnutls_privkey_import_x509(privkey, issuer_key, 0);
+  if (result < 0)
+    {
+      gnutls_assert ();
+      goto fail;
+    }
+
+  result = gnutls_x509_crt_privkey_sign (crt, issuer, privkey, dig, flags);
+  if (result < 0)
+    {
+      gnutls_assert ();
+      goto fail;
+    }
+
+  result = 0;
+
+fail:
+  gnutls_privkey_deinit(privkey);
+
+  return result;
 }
 
 /**
@@ -1279,4 +1294,50 @@ gnutls_x509_crt_set_key_purpose_oid (gnutls_x509_crt_t 
cert,
 
 }
 
+/**
+ * gnutls_x509_crt_privkey_sign:
+ * @crt: a certificate of type #gnutls_x509_crt_t
+ * @issuer: is the certificate of the certificate issuer
+ * @issuer_key: holds the issuer's private key
+ * @dig: The message digest to use, %GNUTLS_DIG_SHA1 is a safe choice
+ * @flags: must be 0
+ *
+ * This function will sign the certificate with the issuer's private key, and
+ * will copy the issuer's information into the certificate.
+ *
+ * This must be the last step in a certificate generation since all
+ * the previously set parameters are now signed.
+ *
+ * Returns: On success, %GNUTLS_E_SUCCESS is returned, otherwise a
+ *   negative error value.
+ **/
+int
+gnutls_x509_crt_privkey_sign (gnutls_x509_crt_t crt, gnutls_x509_crt_t issuer,
+                      gnutls_privkey_t issuer_key,
+                      gnutls_digest_algorithm_t dig, unsigned int flags)
+{
+  int result;
+
+  if (crt == NULL || issuer == NULL || issuer_key == NULL)
+    {
+      gnutls_assert ();
+      return GNUTLS_E_INVALID_REQUEST;
+    }
+
+  /* disable all the unneeded OPTIONAL fields.
+   */
+  disable_optional_stuff (crt);
+
+  result = _gnutls_x509_pkix_sign (crt->cert, "tbsCertificate",
+                                  dig, issuer, issuer_key);
+  if (result < 0)
+    {
+      gnutls_assert ();
+      return result;
+    }
+
+  return 0;
+}
+
+
 #endif /* ENABLE_PKI */
diff --git a/src/Makefile.am b/src/Makefile.am
index f518dc9..edd7223 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -80,7 +80,7 @@ noinst_LTLIBRARIES += libcmd-cli-debug.la
 libcmd_cli_debug_la_CFLAGS =
 libcmd_cli_debug_la_SOURCES = tls_test.gaa tls_test-gaa.h tls_test-gaa.c
 
-certtool_SOURCES = certtool.c prime.c
+certtool_SOURCES = certtool.c prime.c pkcs11.c
 certtool_LDADD = ../lib/libgnutls.la ../libextra/libgnutls-extra.la
 certtool_LDADD += libcmd-certtool.la ../gl/libgnu.la
 certtool_LDADD += $(LTLIBGCRYPT)
diff --git a/src/certtool-common.h b/src/certtool-common.h
index cb2e9ab..f937f95 100644
--- a/src/certtool-common.h
+++ b/src/certtool-common.h
@@ -1,3 +1,6 @@
+#include <gnutls/x509.h>
+#include <stdio.h>
+
 enum
 {
   ACTION_SELF_SIGNED,
@@ -22,10 +25,46 @@ enum
   ACTION_PGP_INFO,
   ACTION_PGP_PRIVKEY_INFO,
   ACTION_RING_INFO,
-  ACTION_REQUEST
+  ACTION_REQUEST,
+  ACTION_PKCS11_LIST,
+  ACTION_PKCS11_TOKENS,
+  ACTION_PKCS11_EXPORT_URL,
+  ACTION_PKCS11_WRITE_URL,
+  ACTION_PKCS11_DELETE_URL,
+  ACTION_PUBKEY_INFO,
 };
 
 #define TYPE_CRT 1
 #define TYPE_CRQ 2
 
 void certtool_version (void);
+void pkcs11_list( FILE*outfile, const char* url, int type);
+void pkcs11_export(FILE* outfile, const char *pkcs11_url);
+void pkcs11_token_list(FILE* outfile);
+void pkcs11_write(FILE* outfile, const char *pkcs11_url, const char* label, 
int trusted);
+void pkcs11_delete(FILE* outfile, const char *pkcs11_url, int batch);
+
+#define PKCS11_TYPE_CRT_ALL 1
+#define PKCS11_TYPE_TRUSTED 2
+#define PKCS11_TYPE_PK 3
+#define PKCS11_TYPE_ALL 4
+
+extern unsigned char buffer[];
+extern const int buffer_size;
+
+#include <gnutls/x509.h>
+#include <gnutls/abstract.h>
+
+gnutls_x509_privkey_t load_private_key (int mand);
+gnutls_x509_crq_t load_request (void);
+gnutls_x509_privkey_t load_ca_private_key (void);
+gnutls_x509_crt_t load_ca_cert (void);
+gnutls_x509_crt_t load_cert (int mand);
+gnutls_pubkey_t load_pubkey (int mand);
+
+/* returns the bits specified in cmd */
+int get_bits(gnutls_pk_algorithm_t);
+
+/* prime.c */
+int generate_prime (int how);
+
diff --git a/src/certtool-gaa.c b/src/certtool-gaa.c
index 8ff1d81..c8c761c 100644
--- a/src/certtool-gaa.c
+++ b/src/certtool-gaa.c
@@ -141,6 +141,7 @@ void gaa_help(void)
        __gaa_helpsingle(0, "generate-dh-params", "", "Generate PKCS #3 encoded 
Diffie-Hellman parameters.");
        __gaa_helpsingle(0, "get-dh-params", "", "Get the included PKCS #3 
encoded Diffie-Hellman parameters.");
        __gaa_helpsingle(0, "load-privkey", "FILE ", "Private key file to 
use.");
+       __gaa_helpsingle(0, "load-pubkey", "FILE ", "Private key file to use.");
        __gaa_helpsingle(0, "load-request", "FILE ", "Certificate request file 
to use.");
        __gaa_helpsingle(0, "load-certificate", "FILE ", "Certificate file to 
use.");
        __gaa_helpsingle(0, "load-ca-privkey", "FILE ", "Certificate 
authority's private key file to use.");
@@ -157,6 +158,7 @@ void gaa_help(void)
        __gaa_helpsingle(0, "smime-to-p7", "", "Convert S/MIME to PKCS #7 
structure.");
        __gaa_helpsingle('k', "key-info", "", "Print information on a private 
key.");
        __gaa_helpsingle(0, "pgp-key-info", "", "Print information on a OpenPGP 
private key.");
+       __gaa_helpsingle(0, "pubkey-info", "", "Print information on a public 
key.");
        __gaa_helpsingle(0, "fix-key", "", "Regenerate the parameters in a 
private key.");
        __gaa_helpsingle(0, "v1", "", "Generate an X.509 version 1 certificate 
(no extensions).");
        __gaa_helpsingle(0, "to-p12", "", "Generate a PKCS #12 structure.");
@@ -170,11 +172,23 @@ void gaa_help(void)
        __gaa_helpsingle(0, "outder", "", "Use DER format for output 
certificates and private keys.");
        __gaa_helpsingle(0, "outraw", "", "Use RAW/DER format for output 
certificates and private keys.");
        __gaa_helpsingle(0, "bits", "BITS ", "specify the number of bits for 
key generation.");
+       __gaa_helpsingle(0, "sec-param", "PARAM ", "specify the security level 
[low|normal|high|ultra].");
        __gaa_helpsingle(0, "disable-quick-random", "", "Use /dev/random for 
key generationg, thus increasing the quality of randomness used.");
        __gaa_helpsingle(0, "outfile", "FILE ", "Output file.");
        __gaa_helpsingle(0, "infile", "FILE ", "Input file.");
        __gaa_helpsingle(0, "template", "FILE ", "Template file to use for non 
interactive operation.");
        __gaa_helpsingle(0, "pkcs-cipher", "CIPHER ", "Cipher to use for pkcs 
operations (3des,aes-128,aes-192,aes-256,rc2-40).");
+       __gaa_helpsingle(0, "pkcs11-provider", "Library ", "Specify the pkcs11 
provider library");
+       __gaa_helpsingle(0, "pkcs11-export-url", "URL ", "Export data specified 
a pkcs11 URL");
+       __gaa_helpsingle(0, "pkcs11-list-certs", "", "List certificates that 
have a private key specified by a PKCS#11 URL");
+       __gaa_helpsingle(0, "pkcs11-list-trusted", "", "List certificates 
marked as trusted, specified by a PKCS#11 URL");
+       __gaa_helpsingle(0, "pkcs11-list-all-certs", "", "List all certificates 
specified by a PKCS#11 URL");
+       __gaa_helpsingle(0, "pkcs11-list-all", "", "List all objects specified 
by a PKCS#11 URL");
+       __gaa_helpsingle(0, "pkcs11-list-tokens", "", "List all available 
tokens");
+       __gaa_helpsingle(0, "pkcs11-write", "URL ", "Writes loaded certificates 
or private keys to a PKCS11 token.");
+       __gaa_helpsingle(0, "pkcs11-write-label", "label ", "Sets a label for 
the write operation.");
+       __gaa_helpsingle(0, "pkcs11-write-trusted", "", "Marks the certificate 
to be imported as trusted.");
+       __gaa_helpsingle(0, "pkcs11-delete-url", "URL ", "Deletes objects 
matching the URL.");
        __gaa_helpsingle('d', "debug", "LEVEL ", "specify the debug level. 
Default is 1.");
        __gaa_helpsingle('h', "help", "", "shows this help text");
        __gaa_helpsingle('v', "version", "", "shows the program's version");
@@ -192,48 +206,62 @@ typedef struct _gaainfo gaainfo;
 
 struct _gaainfo
 {
-#line 131 "certtool.gaa"
+#line 159 "certtool.gaa"
        int debug;
-#line 127 "certtool.gaa"
+#line 154 "certtool.gaa"
+       int pkcs11_trusted;
+#line 151 "certtool.gaa"
+       char* pkcs11_label;
+#line 144 "certtool.gaa"
+       int pkcs11_type;
+#line 141 "certtool.gaa"
+       char* pkcs11_url;
+#line 138 "certtool.gaa"
+       char* pkcs11_provider;
+#line 135 "certtool.gaa"
        char *pkcs_cipher;
-#line 124 "certtool.gaa"
+#line 132 "certtool.gaa"
        char *template;
-#line 121 "certtool.gaa"
+#line 129 "certtool.gaa"
        char *infile;
-#line 118 "certtool.gaa"
+#line 126 "certtool.gaa"
        char *outfile;
-#line 115 "certtool.gaa"
+#line 123 "certtool.gaa"
        int quick_random;
-#line 112 "certtool.gaa"
+#line 120 "certtool.gaa"
+       char* sec_param;
+#line 117 "certtool.gaa"
        int bits;
-#line 108 "certtool.gaa"
+#line 113 "certtool.gaa"
        int outcert_format;
-#line 104 "certtool.gaa"
+#line 109 "certtool.gaa"
        int incert_format;
-#line 101 "certtool.gaa"
+#line 106 "certtool.gaa"
        int export;
-#line 98 "certtool.gaa"
+#line 103 "certtool.gaa"
        char *hash;
-#line 95 "certtool.gaa"
+#line 100 "certtool.gaa"
        int dsa;
-#line 92 "certtool.gaa"
+#line 97 "certtool.gaa"
        int pkcs8;
-#line 85 "certtool.gaa"
+#line 90 "certtool.gaa"
        int v1_cert;
-#line 82 "certtool.gaa"
+#line 87 "certtool.gaa"
        int fix_key;
-#line 67 "certtool.gaa"
+#line 70 "certtool.gaa"
        int crq_extensions;
-#line 54 "certtool.gaa"
+#line 57 "certtool.gaa"
        char *pass;
-#line 51 "certtool.gaa"
+#line 54 "certtool.gaa"
        char *ca;
-#line 48 "certtool.gaa"
+#line 51 "certtool.gaa"
        char *ca_privkey;
-#line 45 "certtool.gaa"
+#line 48 "certtool.gaa"
        char *cert;
-#line 42 "certtool.gaa"
+#line 45 "certtool.gaa"
        char *request;
+#line 42 "certtool.gaa"
+       char *pubkey;
 #line 39 "certtool.gaa"
        char *privkey;
 #line 17 "certtool.gaa"
@@ -294,56 +322,70 @@ static int gaa_error = 0;
 #define GAA_MULTIPLE_OPTION     3
 
 #define GAA_REST                0
-#define GAA_NB_OPTION           49
+#define GAA_NB_OPTION           63
 #define GAAOPTID_version       1
 #define GAAOPTID_help  2
 #define GAAOPTID_debug 3
-#define GAAOPTID_pkcs_cipher   4
-#define GAAOPTID_template      5
-#define GAAOPTID_infile        6
-#define GAAOPTID_outfile       7
-#define GAAOPTID_disable_quick_random  8
-#define GAAOPTID_bits  9
-#define GAAOPTID_outraw        10
-#define GAAOPTID_outder        11
-#define GAAOPTID_inraw 12
-#define GAAOPTID_inder 13
-#define GAAOPTID_export_ciphers        14
-#define GAAOPTID_hash  15
-#define GAAOPTID_dsa   16
-#define GAAOPTID_pkcs8 17
-#define GAAOPTID_to_p8 18
-#define GAAOPTID_to_p12        19
-#define GAAOPTID_v1    20
-#define GAAOPTID_fix_key       21
-#define GAAOPTID_pgp_key_info  22
-#define GAAOPTID_key_info      23
-#define GAAOPTID_smime_to_p7   24
-#define GAAOPTID_p7_info       25
-#define GAAOPTID_p12_info      26
-#define GAAOPTID_no_crq_extensions     27
-#define GAAOPTID_crq_info      28
-#define GAAOPTID_crl_info      29
-#define GAAOPTID_pgp_ring_info 30
-#define GAAOPTID_pgp_certificate_info  31
-#define GAAOPTID_certificate_info      32
-#define GAAOPTID_password      33
-#define GAAOPTID_load_ca_certificate   34
-#define GAAOPTID_load_ca_privkey       35
-#define GAAOPTID_load_certificate      36
-#define GAAOPTID_load_request  37
-#define GAAOPTID_load_privkey  38
-#define GAAOPTID_get_dh_params 39
-#define GAAOPTID_generate_dh_params    40
-#define GAAOPTID_verify_crl    41
-#define GAAOPTID_verify_chain  42
-#define GAAOPTID_generate_request      43
-#define GAAOPTID_generate_privkey      44
-#define GAAOPTID_update_certificate    45
-#define GAAOPTID_generate_crl  46
-#define GAAOPTID_generate_proxy        47
-#define GAAOPTID_generate_certificate  48
-#define GAAOPTID_generate_self_signed  49
+#define GAAOPTID_pkcs11_delete_url     4
+#define GAAOPTID_pkcs11_write_trusted  5
+#define GAAOPTID_pkcs11_write_label    6
+#define GAAOPTID_pkcs11_write  7
+#define GAAOPTID_pkcs11_list_tokens    8
+#define GAAOPTID_pkcs11_list_all       9
+#define GAAOPTID_pkcs11_list_all_certs 10
+#define GAAOPTID_pkcs11_list_trusted   11
+#define GAAOPTID_pkcs11_list_certs     12
+#define GAAOPTID_pkcs11_export_url     13
+#define GAAOPTID_pkcs11_provider       14
+#define GAAOPTID_pkcs_cipher   15
+#define GAAOPTID_template      16
+#define GAAOPTID_infile        17
+#define GAAOPTID_outfile       18
+#define GAAOPTID_disable_quick_random  19
+#define GAAOPTID_sec_param     20
+#define GAAOPTID_bits  21
+#define GAAOPTID_outraw        22
+#define GAAOPTID_outder        23
+#define GAAOPTID_inraw 24
+#define GAAOPTID_inder 25
+#define GAAOPTID_export_ciphers        26
+#define GAAOPTID_hash  27
+#define GAAOPTID_dsa   28
+#define GAAOPTID_pkcs8 29
+#define GAAOPTID_to_p8 30
+#define GAAOPTID_to_p12        31
+#define GAAOPTID_v1    32
+#define GAAOPTID_fix_key       33
+#define GAAOPTID_pubkey_info   34
+#define GAAOPTID_pgp_key_info  35
+#define GAAOPTID_key_info      36
+#define GAAOPTID_smime_to_p7   37
+#define GAAOPTID_p7_info       38
+#define GAAOPTID_p12_info      39
+#define GAAOPTID_no_crq_extensions     40
+#define GAAOPTID_crq_info      41
+#define GAAOPTID_crl_info      42
+#define GAAOPTID_pgp_ring_info 43
+#define GAAOPTID_pgp_certificate_info  44
+#define GAAOPTID_certificate_info      45
+#define GAAOPTID_password      46
+#define GAAOPTID_load_ca_certificate   47
+#define GAAOPTID_load_ca_privkey       48
+#define GAAOPTID_load_certificate      49
+#define GAAOPTID_load_request  50
+#define GAAOPTID_load_pubkey   51
+#define GAAOPTID_load_privkey  52
+#define GAAOPTID_get_dh_params 53
+#define GAAOPTID_generate_dh_params    54
+#define GAAOPTID_verify_crl    55
+#define GAAOPTID_verify_chain  56
+#define GAAOPTID_generate_request      57
+#define GAAOPTID_generate_privkey      58
+#define GAAOPTID_update_certificate    59
+#define GAAOPTID_generate_crl  60
+#define GAAOPTID_generate_proxy        61
+#define GAAOPTID_generate_certificate  62
+#define GAAOPTID_generate_self_signed  63
 
 #line 168 "gaa.skel"
 
@@ -503,12 +545,31 @@ static int gaa_getint(char *arg)
     return tmp;
 }
 
+static char gaa_getchar(char *arg)
+{
+    if(strlen(arg) != 1)
+    {
+        printf("Option %s: '%s' isn't an character\n", gaa_current_option, 
arg);
+        GAAERROR(-1);
+    }
+    return arg[0];
+}
 
 static char* gaa_getstr(char *arg)
 {
     return arg;
 }
-
+static float gaa_getfloat(char *arg)
+{
+    float tmp;
+    char a;
+    if(sscanf(arg, "%f%c", &tmp, &a) < 1)
+    {
+        printf("Option %s: '%s' isn't a float number\n", gaa_current_option, 
arg);
+        GAAERROR(-1);
+    }
+    return tmp;
+}
 /* option structures */
 
 struct GAAOPTION_debug 
@@ -517,6 +578,36 @@ struct GAAOPTION_debug
        int size1;
 };
 
+struct GAAOPTION_pkcs11_delete_url 
+{
+       char* arg1;
+       int size1;
+};
+
+struct GAAOPTION_pkcs11_write_label 
+{
+       char* arg1;
+       int size1;
+};
+
+struct GAAOPTION_pkcs11_write 
+{
+       char* arg1;
+       int size1;
+};
+
+struct GAAOPTION_pkcs11_export_url 
+{
+       char* arg1;
+       int size1;
+};
+
+struct GAAOPTION_pkcs11_provider 
+{
+       char* arg1;
+       int size1;
+};
+
 struct GAAOPTION_pkcs_cipher 
 {
        char* arg1;
@@ -541,6 +632,12 @@ struct GAAOPTION_outfile
        int size1;
 };
 
+struct GAAOPTION_sec_param
+{
+       char* arg1;
+       int size1;
+};
+
 struct GAAOPTION_bits 
 {
        int arg1;
@@ -583,6 +680,12 @@ struct GAAOPTION_load_request
        int size1;
 };
 
+struct GAAOPTION_load_pubkey 
+{
+       char* arg1;
+       int size1;
+};
+
 struct GAAOPTION_load_privkey 
 {
        char* arg1;
@@ -619,10 +722,16 @@ static int gaa_get_option_num(char *str, int status)
         {
         case GAA_LETTER_OPTION:
                        GAA_CHECK1STR("d", GAAOPTID_debug);
+                       GAA_CHECK1STR("", GAAOPTID_pkcs11_delete_url);
+                       GAA_CHECK1STR("", GAAOPTID_pkcs11_write_label);
+                       GAA_CHECK1STR("", GAAOPTID_pkcs11_write);
+                       GAA_CHECK1STR("", GAAOPTID_pkcs11_export_url);
+                       GAA_CHECK1STR("", GAAOPTID_pkcs11_provider);
                        GAA_CHECK1STR("", GAAOPTID_pkcs_cipher);
                        GAA_CHECK1STR("", GAAOPTID_template);
                        GAA_CHECK1STR("", GAAOPTID_infile);
                        GAA_CHECK1STR("", GAAOPTID_outfile);
+                       GAA_CHECK1STR("", GAAOPTID_sec_param);
                        GAA_CHECK1STR("", GAAOPTID_bits);
                        GAA_CHECK1STR("", GAAOPTID_hash);
                        GAA_CHECK1STR("", GAAOPTID_password);
@@ -630,11 +739,18 @@ static int gaa_get_option_num(char *str, int status)
                        GAA_CHECK1STR("", GAAOPTID_load_ca_privkey);
                        GAA_CHECK1STR("", GAAOPTID_load_certificate);
                        GAA_CHECK1STR("", GAAOPTID_load_request);
+                       GAA_CHECK1STR("", GAAOPTID_load_pubkey);
                        GAA_CHECK1STR("", GAAOPTID_load_privkey);
         case GAA_MULTIPLE_OPTION:
 #line 375 "gaa.skel"
                        GAA_CHECK1STR("v", GAAOPTID_version);
                        GAA_CHECK1STR("h", GAAOPTID_help);
+                       GAA_CHECK1STR("", GAAOPTID_pkcs11_write_trusted);
+                       GAA_CHECK1STR("", GAAOPTID_pkcs11_list_tokens);
+                       GAA_CHECK1STR("", GAAOPTID_pkcs11_list_all);
+                       GAA_CHECK1STR("", GAAOPTID_pkcs11_list_all_certs);
+                       GAA_CHECK1STR("", GAAOPTID_pkcs11_list_trusted);
+                       GAA_CHECK1STR("", GAAOPTID_pkcs11_list_certs);
                        GAA_CHECK1STR("", GAAOPTID_disable_quick_random);
                        GAA_CHECK1STR("", GAAOPTID_outraw);
                        GAA_CHECK1STR("", GAAOPTID_outder);
@@ -647,6 +763,7 @@ static int gaa_get_option_num(char *str, int status)
                        GAA_CHECK1STR("", GAAOPTID_to_p12);
                        GAA_CHECK1STR("", GAAOPTID_v1);
                        GAA_CHECK1STR("", GAAOPTID_fix_key);
+                       GAA_CHECK1STR("", GAAOPTID_pubkey_info);
                        GAA_CHECK1STR("", GAAOPTID_pgp_key_info);
                        GAA_CHECK1STR("k", GAAOPTID_key_info);
                        GAA_CHECK1STR("", GAAOPTID_smime_to_p7);
@@ -676,11 +793,23 @@ static int gaa_get_option_num(char *str, int status)
                        GAA_CHECKSTR("version", GAAOPTID_version);
                        GAA_CHECKSTR("help", GAAOPTID_help);
                        GAA_CHECKSTR("debug", GAAOPTID_debug);
+                       GAA_CHECKSTR("pkcs11-delete-url", 
GAAOPTID_pkcs11_delete_url);
+                       GAA_CHECKSTR("pkcs11-write-trusted", 
GAAOPTID_pkcs11_write_trusted);
+                       GAA_CHECKSTR("pkcs11-write-label", 
GAAOPTID_pkcs11_write_label);
+                       GAA_CHECKSTR("pkcs11-write", GAAOPTID_pkcs11_write);
+                       GAA_CHECKSTR("pkcs11-list-tokens", 
GAAOPTID_pkcs11_list_tokens);
+                       GAA_CHECKSTR("pkcs11-list-all", 
GAAOPTID_pkcs11_list_all);
+                       GAA_CHECKSTR("pkcs11-list-all-certs", 
GAAOPTID_pkcs11_list_all_certs);
+                       GAA_CHECKSTR("pkcs11-list-trusted", 
GAAOPTID_pkcs11_list_trusted);
+                       GAA_CHECKSTR("pkcs11-list-certs", 
GAAOPTID_pkcs11_list_certs);
+                       GAA_CHECKSTR("pkcs11-export-url", 
GAAOPTID_pkcs11_export_url);
+                       GAA_CHECKSTR("pkcs11-provider", 
GAAOPTID_pkcs11_provider);
                        GAA_CHECKSTR("pkcs-cipher", GAAOPTID_pkcs_cipher);
                        GAA_CHECKSTR("template", GAAOPTID_template);
                        GAA_CHECKSTR("infile", GAAOPTID_infile);
                        GAA_CHECKSTR("outfile", GAAOPTID_outfile);
                        GAA_CHECKSTR("disable-quick-random", 
GAAOPTID_disable_quick_random);
+                       GAA_CHECKSTR("sec-param", GAAOPTID_sec_param);
                        GAA_CHECKSTR("bits", GAAOPTID_bits);
                        GAA_CHECKSTR("outraw", GAAOPTID_outraw);
                        GAA_CHECKSTR("outder", GAAOPTID_outder);
@@ -694,6 +823,7 @@ static int gaa_get_option_num(char *str, int status)
                        GAA_CHECKSTR("to-p12", GAAOPTID_to_p12);
                        GAA_CHECKSTR("v1", GAAOPTID_v1);
                        GAA_CHECKSTR("fix-key", GAAOPTID_fix_key);
+                       GAA_CHECKSTR("pubkey-info", GAAOPTID_pubkey_info);
                        GAA_CHECKSTR("pgp-key-info", GAAOPTID_pgp_key_info);
                        GAA_CHECKSTR("key-info", GAAOPTID_key_info);
                        GAA_CHECKSTR("smime-to-p7", GAAOPTID_smime_to_p7);
@@ -710,6 +840,7 @@ static int gaa_get_option_num(char *str, int status)
                        GAA_CHECKSTR("load-ca-privkey", 
GAAOPTID_load_ca_privkey);
                        GAA_CHECKSTR("load-certificate", 
GAAOPTID_load_certificate);
                        GAA_CHECKSTR("load-request", GAAOPTID_load_request);
+                       GAA_CHECKSTR("load-pubkey", GAAOPTID_load_pubkey);
                        GAA_CHECKSTR("load-privkey", GAAOPTID_load_privkey);
                        GAA_CHECKSTR("get-dh-params", GAAOPTID_get_dh_params);
                        GAA_CHECKSTR("generate-dh-params", 
GAAOPTID_generate_dh_params);
@@ -735,10 +866,16 @@ static int gaa_try(int gaa_num, int gaa_index, gaainfo 
*gaaval, char *opt_list)
     int OK = 0;
     int gaa_last_non_option;
        struct GAAOPTION_debug GAATMP_debug;
+       struct GAAOPTION_pkcs11_delete_url GAATMP_pkcs11_delete_url;
+       struct GAAOPTION_pkcs11_write_label GAATMP_pkcs11_write_label;
+       struct GAAOPTION_pkcs11_write GAATMP_pkcs11_write;
+       struct GAAOPTION_pkcs11_export_url GAATMP_pkcs11_export_url;
+       struct GAAOPTION_pkcs11_provider GAATMP_pkcs11_provider;
        struct GAAOPTION_pkcs_cipher GAATMP_pkcs_cipher;
        struct GAAOPTION_template GAATMP_template;
        struct GAAOPTION_infile GAATMP_infile;
        struct GAAOPTION_outfile GAATMP_outfile;
+       struct GAAOPTION_sec_param GAATMP_sec_param;
        struct GAAOPTION_bits GAATMP_bits;
        struct GAAOPTION_hash GAATMP_hash;
        struct GAAOPTION_password GAATMP_password;
@@ -746,6 +883,7 @@ static int gaa_try(int gaa_num, int gaa_index, gaainfo 
*gaaval, char *opt_list)
        struct GAAOPTION_load_ca_privkey GAATMP_load_ca_privkey;
        struct GAAOPTION_load_certificate GAATMP_load_certificate;
        struct GAAOPTION_load_request GAATMP_load_request;
+       struct GAAOPTION_load_pubkey GAATMP_load_pubkey;
        struct GAAOPTION_load_privkey GAATMP_load_privkey;
 
 #line 393 "gaa.skel"
@@ -769,14 +907,14 @@ static int gaa_try(int gaa_num, int gaa_index, gaainfo 
*gaaval, char *opt_list)
     {
        case GAAOPTID_version:
        OK = 0;
-#line 136 "certtool.gaa"
+#line 164 "certtool.gaa"
 { certtool_version(); exit(0); ;};
 
                return GAA_OK;
                break;
        case GAAOPTID_help:
        OK = 0;
-#line 134 "certtool.gaa"
+#line 162 "certtool.gaa"
 { gaa_help(); exit(0); ;};
 
                return GAA_OK;
@@ -786,17 +924,109 @@ static int gaa_try(int gaa_num, int gaa_index, gaainfo 
*gaaval, char *opt_list)
                GAA_TESTMOREARGS;
                GAA_FILL(GAATMP_debug.arg1, gaa_getint, GAATMP_debug.size1);
                gaa_index++;
-#line 132 "certtool.gaa"
+#line 160 "certtool.gaa"
 { gaaval->debug = GAATMP_debug.arg1 ;};
 
                return GAA_OK;
                break;
+       case GAAOPTID_pkcs11_delete_url:
+       OK = 0;
+               GAA_TESTMOREARGS;
+               GAA_FILL(GAATMP_pkcs11_delete_url.arg1, gaa_getstr, 
GAATMP_pkcs11_delete_url.size1);
+               gaa_index++;
+#line 157 "certtool.gaa"
+{ gaaval->action = ACTION_PKCS11_DELETE_URL; gaaval->pkcs11_url = 
GAATMP_pkcs11_delete_url.arg1; ;};
+
+               return GAA_OK;
+               break;
+       case GAAOPTID_pkcs11_write_trusted:
+       OK = 0;
+#line 155 "certtool.gaa"
+{ gaaval->pkcs11_trusted = 1; ;};
+
+               return GAA_OK;
+               break;
+       case GAAOPTID_pkcs11_write_label:
+       OK = 0;
+               GAA_TESTMOREARGS;
+               GAA_FILL(GAATMP_pkcs11_write_label.arg1, gaa_getstr, 
GAATMP_pkcs11_write_label.size1);
+               gaa_index++;
+#line 153 "certtool.gaa"
+{ gaaval->pkcs11_label = GAATMP_pkcs11_write_label.arg1; ;};
+
+               return GAA_OK;
+               break;
+       case GAAOPTID_pkcs11_write:
+       OK = 0;
+               GAA_TESTMOREARGS;
+               GAA_FILL(GAATMP_pkcs11_write.arg1, gaa_getstr, 
GAATMP_pkcs11_write.size1);
+               gaa_index++;
+#line 152 "certtool.gaa"
+{ gaaval->action = ACTION_PKCS11_WRITE_URL; gaaval->pkcs11_url = 
GAATMP_pkcs11_write.arg1; ;};
+
+               return GAA_OK;
+               break;
+       case GAAOPTID_pkcs11_list_tokens:
+       OK = 0;
+#line 149 "certtool.gaa"
+{ gaaval->action = ACTION_PKCS11_TOKENS; ;};
+
+               return GAA_OK;
+               break;
+       case GAAOPTID_pkcs11_list_all:
+       OK = 0;
+#line 148 "certtool.gaa"
+{ gaaval->action = ACTION_PKCS11_LIST; gaaval->pkcs11_type=PKCS11_TYPE_ALL; ;};
+
+               return GAA_OK;
+               break;
+       case GAAOPTID_pkcs11_list_all_certs:
+       OK = 0;
+#line 147 "certtool.gaa"
+{ gaaval->action = ACTION_PKCS11_LIST; 
gaaval->pkcs11_type=PKCS11_TYPE_CRT_ALL; ;};
+
+               return GAA_OK;
+               break;
+       case GAAOPTID_pkcs11_list_trusted:
+       OK = 0;
+#line 146 "certtool.gaa"
+{ gaaval->action = ACTION_PKCS11_LIST; 
gaaval->pkcs11_type=PKCS11_TYPE_TRUSTED; ;};
+
+               return GAA_OK;
+               break;
+       case GAAOPTID_pkcs11_list_certs:
+       OK = 0;
+#line 145 "certtool.gaa"
+{ gaaval->action = ACTION_PKCS11_LIST; gaaval->pkcs11_type=PKCS11_TYPE_PK; ;};
+
+               return GAA_OK;
+               break;
+       case GAAOPTID_pkcs11_export_url:
+       OK = 0;
+               GAA_TESTMOREARGS;
+               GAA_FILL(GAATMP_pkcs11_export_url.arg1, gaa_getstr, 
GAATMP_pkcs11_export_url.size1);
+               gaa_index++;
+#line 142 "certtool.gaa"
+{ gaaval->action = ACTION_PKCS11_EXPORT_URL; gaaval->pkcs11_url = 
GAATMP_pkcs11_export_url.arg1; ;};
+
+               return GAA_OK;
+               break;
+       case GAAOPTID_pkcs11_provider:
+       OK = 0;
+               GAA_TESTMOREARGS;
+               GAA_FILL(GAATMP_pkcs11_provider.arg1, gaa_getstr, 
GAATMP_pkcs11_provider.size1);
+               gaa_index++;
+#line 139 "certtool.gaa"
+{ gaaval->pkcs11_provider = GAATMP_pkcs11_provider.arg1 ;};
+
+               return GAA_OK;
+               break;
        case GAAOPTID_pkcs_cipher:
        OK = 0;
                GAA_TESTMOREARGS;
                GAA_FILL(GAATMP_pkcs_cipher.arg1, gaa_getstr, 
GAATMP_pkcs_cipher.size1);
                gaa_index++;
-#line 128 "certtool.gaa"
+#line 136 "certtool.gaa"
 { gaaval->pkcs_cipher = GAATMP_pkcs_cipher.arg1 ;};
 
                return GAA_OK;
@@ -806,7 +1036,7 @@ static int gaa_try(int gaa_num, int gaa_index, gaainfo 
*gaaval, char *opt_list)
                GAA_TESTMOREARGS;
                GAA_FILL(GAATMP_template.arg1, gaa_getstr, 
GAATMP_template.size1);
                gaa_index++;
-#line 125 "certtool.gaa"
+#line 133 "certtool.gaa"
 { gaaval->template = GAATMP_template.arg1 ;};
 
                return GAA_OK;
@@ -816,7 +1046,7 @@ static int gaa_try(int gaa_num, int gaa_index, gaainfo 
*gaaval, char *opt_list)
                GAA_TESTMOREARGS;
                GAA_FILL(GAATMP_infile.arg1, gaa_getstr, GAATMP_infile.size1);
                gaa_index++;
-#line 122 "certtool.gaa"
+#line 130 "certtool.gaa"
 { gaaval->infile = GAATMP_infile.arg1 ;};
 
                return GAA_OK;
@@ -826,59 +1056,69 @@ static int gaa_try(int gaa_num, int gaa_index, gaainfo 
*gaaval, char *opt_list)
                GAA_TESTMOREARGS;
                GAA_FILL(GAATMP_outfile.arg1, gaa_getstr, GAATMP_outfile.size1);
                gaa_index++;
-#line 119 "certtool.gaa"
+#line 127 "certtool.gaa"
 { gaaval->outfile = GAATMP_outfile.arg1 ;};
 
                return GAA_OK;
                break;
        case GAAOPTID_disable_quick_random:
        OK = 0;
-#line 116 "certtool.gaa"
+#line 124 "certtool.gaa"
 { gaaval->quick_random = 0; ;};
 
                return GAA_OK;
                break;
+       case GAAOPTID_sec_param:
+       OK = 0;
+               GAA_TESTMOREARGS;
+               GAA_FILL(GAATMP_sec_param.arg1, gaa_getstr, 
GAATMP_sec_param.size1);
+               gaa_index++;
+#line 121 "certtool.gaa"
+{ gaaval->sec_param = GAATMP_sec_param.arg1 ;};
+
+               return GAA_OK;
+               break;
        case GAAOPTID_bits:
        OK = 0;
                GAA_TESTMOREARGS;
                GAA_FILL(GAATMP_bits.arg1, gaa_getint, GAATMP_bits.size1);
                gaa_index++;
-#line 113 "certtool.gaa"
+#line 118 "certtool.gaa"
 { gaaval->bits = GAATMP_bits.arg1 ;};
 
                return GAA_OK;
                break;
        case GAAOPTID_outraw:
        OK = 0;
-#line 110 "certtool.gaa"
+#line 115 "certtool.gaa"
 { gaaval->outcert_format=1 ;};
 
                return GAA_OK;
                break;
        case GAAOPTID_outder:
        OK = 0;
-#line 109 "certtool.gaa"
+#line 114 "certtool.gaa"
 { gaaval->outcert_format=1 ;};
 
                return GAA_OK;
                break;
        case GAAOPTID_inraw:
        OK = 0;
-#line 106 "certtool.gaa"
+#line 111 "certtool.gaa"
 { gaaval->incert_format=1 ;};
 
                return GAA_OK;
                break;
        case GAAOPTID_inder:
        OK = 0;
-#line 105 "certtool.gaa"
+#line 110 "certtool.gaa"
 { gaaval->incert_format=1 ;};
 
                return GAA_OK;
                break;
        case GAAOPTID_export_ciphers:
        OK = 0;
-#line 102 "certtool.gaa"
+#line 107 "certtool.gaa"
 { gaaval->export=1 ;};
 
                return GAA_OK;
@@ -888,126 +1128,133 @@ static int gaa_try(int gaa_num, int gaa_index, gaainfo 
*gaaval, char *opt_list)
                GAA_TESTMOREARGS;
                GAA_FILL(GAATMP_hash.arg1, gaa_getstr, GAATMP_hash.size1);
                gaa_index++;
-#line 99 "certtool.gaa"
+#line 104 "certtool.gaa"
 { gaaval->hash = GAATMP_hash.arg1 ;};
 
                return GAA_OK;
                break;
        case GAAOPTID_dsa:
        OK = 0;
-#line 96 "certtool.gaa"
+#line 101 "certtool.gaa"
 { gaaval->dsa=1 ;};
 
                return GAA_OK;
                break;
        case GAAOPTID_pkcs8:
        OK = 0;
-#line 93 "certtool.gaa"
+#line 98 "certtool.gaa"
 { gaaval->pkcs8=1 ;};
 
                return GAA_OK;
                break;
        case GAAOPTID_to_p8:
        OK = 0;
-#line 90 "certtool.gaa"
+#line 95 "certtool.gaa"
 { gaaval->action = ACTION_GENERATE_PKCS8; ;};
 
                return GAA_OK;
                break;
        case GAAOPTID_to_p12:
        OK = 0;
-#line 88 "certtool.gaa"
+#line 93 "certtool.gaa"
 { gaaval->action = ACTION_TO_PKCS12; ;};
 
                return GAA_OK;
                break;
        case GAAOPTID_v1:
        OK = 0;
-#line 86 "certtool.gaa"
+#line 91 "certtool.gaa"
 { gaaval->v1_cert = 1; ;};
 
                return GAA_OK;
                break;
        case GAAOPTID_fix_key:
        OK = 0;
-#line 83 "certtool.gaa"
+#line 88 "certtool.gaa"
 { gaaval->privkey_op=1; gaaval->fix_key = 1; ;};
 
                return GAA_OK;
                break;
+       case GAAOPTID_pubkey_info:
+       OK = 0;
+#line 85 "certtool.gaa"
+{ gaaval->action = ACTION_PUBKEY_INFO; ;};
+
+               return GAA_OK;
+               break;
        case GAAOPTID_pgp_key_info:
        OK = 0;
-#line 80 "certtool.gaa"
+#line 83 "certtool.gaa"
 { gaaval->privkey_op=1; gaaval->action = ACTION_PGP_PRIVKEY_INFO; ;};
 
                return GAA_OK;
                break;
        case GAAOPTID_key_info:
        OK = 0;
-#line 78 "certtool.gaa"
+#line 81 "certtool.gaa"
 { gaaval->privkey_op=1; gaaval->action = ACTION_PRIVKEY_INFO; ;};
 
                return GAA_OK;
                break;
        case GAAOPTID_smime_to_p7:
        OK = 0;
-#line 74 "certtool.gaa"
+#line 77 "certtool.gaa"
 { gaaval->action = ACTION_SMIME_TO_P7; ;};
 
                return GAA_OK;
                break;
        case GAAOPTID_p7_info:
        OK = 0;
-#line 72 "certtool.gaa"
+#line 75 "certtool.gaa"
 { gaaval->action = ACTION_P7_INFO; ;};
 
                return GAA_OK;
                break;
        case GAAOPTID_p12_info:
        OK = 0;
-#line 70 "certtool.gaa"
+#line 73 "certtool.gaa"
 { gaaval->action = ACTION_PKCS12_INFO; ;};
 
                return GAA_OK;
                break;
        case GAAOPTID_no_crq_extensions:
        OK = 0;
-#line 68 "certtool.gaa"
+#line 71 "certtool.gaa"
 { gaaval->crq_extensions = 0; ;};
 
                return GAA_OK;
                break;
        case GAAOPTID_crq_info:
        OK = 0;
-#line 65 "certtool.gaa"
+#line 68 "certtool.gaa"
 { gaaval->action = ACTION_REQUEST; ;};
 
                return GAA_OK;
                break;
        case GAAOPTID_crl_info:
        OK = 0;
-#line 63 "certtool.gaa"
+#line 66 "certtool.gaa"
 { gaaval->action = ACTION_CRL_INFO; ;};
 
                return GAA_OK;
                break;
        case GAAOPTID_pgp_ring_info:
        OK = 0;
-#line 61 "certtool.gaa"
+#line 64 "certtool.gaa"
 { gaaval->action = ACTION_RING_INFO; ;};
 
                return GAA_OK;
                break;
        case GAAOPTID_pgp_certificate_info:
        OK = 0;
-#line 59 "certtool.gaa"
+#line 62 "certtool.gaa"
 { gaaval->action = ACTION_PGP_INFO; ;};
 
                return GAA_OK;
                break;
        case GAAOPTID_certificate_info:
        OK = 0;
-#line 57 "certtool.gaa"
+#line 60 "certtool.gaa"
 { gaaval->action = ACTION_CERT_INFO; ;};
 
                return GAA_OK;
@@ -1017,7 +1264,7 @@ static int gaa_try(int gaa_num, int gaa_index, gaainfo 
*gaaval, char *opt_list)
                GAA_TESTMOREARGS;
                GAA_FILL(GAATMP_password.arg1, gaa_getstr, 
GAATMP_password.size1);
                gaa_index++;
-#line 55 "certtool.gaa"
+#line 58 "certtool.gaa"
 { gaaval->pass = GAATMP_password.arg1 ;};
 
                return GAA_OK;
@@ -1027,7 +1274,7 @@ static int gaa_try(int gaa_num, int gaa_index, gaainfo 
*gaaval, char *opt_list)
                GAA_TESTMOREARGS;
                GAA_FILL(GAATMP_load_ca_certificate.arg1, gaa_getstr, 
GAATMP_load_ca_certificate.size1);
                gaa_index++;
-#line 52 "certtool.gaa"
+#line 55 "certtool.gaa"
 { gaaval->ca = GAATMP_load_ca_certificate.arg1 ;};
 
                return GAA_OK;
@@ -1037,7 +1284,7 @@ static int gaa_try(int gaa_num, int gaa_index, gaainfo 
*gaaval, char *opt_list)
                GAA_TESTMOREARGS;
                GAA_FILL(GAATMP_load_ca_privkey.arg1, gaa_getstr, 
GAATMP_load_ca_privkey.size1);
                gaa_index++;
-#line 49 "certtool.gaa"
+#line 52 "certtool.gaa"
 { gaaval->ca_privkey = GAATMP_load_ca_privkey.arg1 ;};
 
                return GAA_OK;
@@ -1047,7 +1294,7 @@ static int gaa_try(int gaa_num, int gaa_index, gaainfo 
*gaaval, char *opt_list)
                GAA_TESTMOREARGS;
                GAA_FILL(GAATMP_load_certificate.arg1, gaa_getstr, 
GAATMP_load_certificate.size1);
                gaa_index++;
-#line 46 "certtool.gaa"
+#line 49 "certtool.gaa"
 { gaaval->cert = GAATMP_load_certificate.arg1 ;};
 
                return GAA_OK;
@@ -1057,11 +1304,21 @@ static int gaa_try(int gaa_num, int gaa_index, gaainfo 
*gaaval, char *opt_list)
                GAA_TESTMOREARGS;
                GAA_FILL(GAATMP_load_request.arg1, gaa_getstr, 
GAATMP_load_request.size1);
                gaa_index++;
-#line 43 "certtool.gaa"
+#line 46 "certtool.gaa"
 { gaaval->request = GAATMP_load_request.arg1 ;};
 
                return GAA_OK;
                break;
+       case GAAOPTID_load_pubkey:
+       OK = 0;
+               GAA_TESTMOREARGS;
+               GAA_FILL(GAATMP_load_pubkey.arg1, gaa_getstr, 
GAATMP_load_pubkey.size1);
+               gaa_index++;
+#line 43 "certtool.gaa"
+{ gaaval->pubkey = GAATMP_load_pubkey.arg1 ;};
+
+               return GAA_OK;
+               break;
        case GAAOPTID_load_privkey:
        OK = 0;
                GAA_TESTMOREARGS;
@@ -1159,29 +1416,28 @@ static int gaa_try(int gaa_num, int gaa_index, gaainfo 
*gaaval, char *opt_list)
 int gaa(int argc, char **argv, gaainfo *gaaval)
 {
     int tmp1, tmp2;
-    int l;
-    size_t i, j;
+    int i, j;
     char *opt_list;
 
-    i = 0;
-
     GAAargv = argv;
     GAAargc = argc;
 
     opt_list = (char*) gaa_malloc(GAA_NB_OPTION + 1);
 
-    for(l = 0; l < GAA_NB_OPTION + 1; l++)
-        opt_list[l] = 0;
+    for(i = 0; i < GAA_NB_OPTION + 1; i++)
+        opt_list[i] = 0;
     /* initialization */
     if(inited == 0)
     {
 
-#line 138 "certtool.gaa"
-{ gaaval->bits = 2048; gaaval->pkcs8 = 0; gaaval->privkey = NULL; 
gaaval->ca=NULL; gaaval->ca_privkey = NULL; 
+#line 166 "certtool.gaa"
+{ gaaval->bits = 0; gaaval->pkcs8 = 0; gaaval->privkey = NULL; 
gaaval->ca=NULL; gaaval->ca_privkey = NULL;
        gaaval->debug=1; gaaval->request = NULL; gaaval->infile = NULL; 
gaaval->outfile = NULL; gaaval->cert = NULL; 
        gaaval->incert_format = 0; gaaval->outcert_format = 0; 
gaaval->action=-1; gaaval->pass = NULL; gaaval->v1_cert = 0;
        gaaval->export = 0; gaaval->template = NULL; gaaval->hash=NULL; 
gaaval->fix_key = 0; gaaval->quick_random=1; 
-       gaaval->privkey_op = 0; gaaval->pkcs_cipher = "3des"; 
gaaval->crq_extensions=1; ;};
+       gaaval->privkey_op = 0; gaaval->pkcs_cipher = "3des"; 
gaaval->crq_extensions=1; gaaval->pkcs11_provider= NULL;
+       gaaval->pkcs11_url = NULL; gaaval->pkcs11_type = PKCS11_TYPE_PK; 
gaaval->pubkey=NULL; gaaval->pkcs11_label = NULL; 
+       gaaval->pkcs11_trusted=0; gaaval->sec_param = NULL; ;};
 
     }
     inited = 1;
@@ -1192,27 +1448,27 @@ int gaa(int argc, char **argv, gaainfo *gaaval)
       gaa_arg_used = gaa_malloc(argc * sizeof(char));
     }
 
-    for(l = 1; l < argc; l++)
-        gaa_arg_used[l] = 0;
-    for(l = 1; l < argc; l++)
+    for(i = 1; i < argc; i++)
+        gaa_arg_used[i] = 0;
+    for(i = 1; i < argc; i++)
     {
-        if(gaa_arg_used[l] == 0)
+        if(gaa_arg_used[i] == 0)
         {
             j = 0;
-            tmp1 = gaa_is_an_argument(GAAargv[l]);
+            tmp1 = gaa_is_an_argument(GAAargv[i]);
             switch(tmp1)
             {
             case GAA_WORD_OPTION:
                 j++;
             case GAA_LETTER_OPTION:
                 j++;
-                tmp2 = gaa_get_option_num(argv[l]+j, tmp1);
+                tmp2 = gaa_get_option_num(argv[i]+j, tmp1);
                 if(tmp2 == GAA_ERROR_NOMATCH)
                 {
-                    printf("Invalid option '%s'\n", argv[l]+j);
+                    printf("Invalid option '%s'\n", argv[i]+j);
                     return 0;
                 }
-                switch(gaa_try(tmp2, l+1, gaaval, opt_list))
+                switch(gaa_try(tmp2, i+1, gaaval, opt_list))
                 {
                 case GAA_ERROR_NOTENOUGH_ARGS:
                     printf("'%s': not enough arguments\n",gaa_current_option);
@@ -1225,18 +1481,18 @@ int gaa(int argc, char **argv, gaainfo *gaaval)
                 default:
                     printf("Unknown error\n");
                 }
-                gaa_arg_used[l] = 1;
+                gaa_arg_used[i] = 1;
                 break;
             case GAA_MULTIPLE_OPTION:
-                for(j = 1; j < strlen(argv[l]); j++)
+                for(j = 1; j < strlen(argv[i]); j++)
                 {
-                    tmp2 = gaa_get_option_num(argv[l]+j, tmp1);
+                    tmp2 = gaa_get_option_num(argv[i]+j, tmp1);
                     if(tmp2 == GAA_ERROR_NOMATCH)
                     {
-                        printf("Invalid option '%c'\n", *(argv[l]+j));
+                        printf("Invalid option '%c'\n", *(argv[i]+j));
                         return 0;
                     }
-                    switch(gaa_try(tmp2, l+1, gaaval, opt_list))
+                    switch(gaa_try(tmp2, i+1, gaaval, opt_list))
                     {
                     case GAA_ERROR_NOTENOUGH_ARGS:
                         printf("'%s': not enough 
arguments\n",gaa_current_option);
@@ -1250,7 +1506,7 @@ int gaa(int argc, char **argv, gaainfo *gaaval)
                         printf("Unknown error\n");
                     }
                 }
-                gaa_arg_used[l] = 1;
+                gaa_arg_used[i] = 1;
                 break;
             default: break;
             }
@@ -1276,9 +1532,9 @@ if(gaa_processing_file == 0)
     }
 #endif
 }
-    for(l = 1; l < argc; l++)
+    for(i = 1; i < argc; i++)
     {
-        if(gaa_arg_used[l] == 0)
+        if(gaa_arg_used[i] == 0)
         {
             printf("Too many arguments\n");
             return 0;
@@ -1329,7 +1585,7 @@ static int gaa_internal_get_next_str(FILE *file, 
gaa_str_node *tmp_str, int argc
 
         len++;
         a = fgetc( file);
-        if(a==EOF) return 0; /* a = ' '; */
+        if(a==EOF) return 0; //a = ' ';
     }
 
     len += 1;
diff --git a/src/certtool-gaa.h b/src/certtool-gaa.h
index 3d4ee83..647e512 100644
--- a/src/certtool-gaa.h
+++ b/src/certtool-gaa.h
@@ -8,48 +8,62 @@ typedef struct _gaainfo gaainfo;
 
 struct _gaainfo
 {
-#line 131 "certtool.gaa"
+#line 159 "certtool.gaa"
        int debug;
-#line 127 "certtool.gaa"
+#line 154 "certtool.gaa"
+       int pkcs11_trusted;
+#line 151 "certtool.gaa"
+       char* pkcs11_label;
+#line 144 "certtool.gaa"
+       int pkcs11_type;
+#line 141 "certtool.gaa"
+       char* pkcs11_url;
+#line 138 "certtool.gaa"
+       char* pkcs11_provider;
+#line 135 "certtool.gaa"
        char *pkcs_cipher;
-#line 124 "certtool.gaa"
+#line 132 "certtool.gaa"
        char *template;
-#line 121 "certtool.gaa"
+#line 129 "certtool.gaa"
        char *infile;
-#line 118 "certtool.gaa"
+#line 126 "certtool.gaa"
        char *outfile;
-#line 115 "certtool.gaa"
+#line 123 "certtool.gaa"
        int quick_random;
-#line 112 "certtool.gaa"
+#line 120 "certtool.gaa"
+       char* sec_param;
+#line 117 "certtool.gaa"
        int bits;
-#line 108 "certtool.gaa"
+#line 113 "certtool.gaa"
        int outcert_format;
-#line 104 "certtool.gaa"
+#line 109 "certtool.gaa"
        int incert_format;
-#line 101 "certtool.gaa"
+#line 106 "certtool.gaa"
        int export;
-#line 98 "certtool.gaa"
+#line 103 "certtool.gaa"
        char *hash;
-#line 95 "certtool.gaa"
+#line 100 "certtool.gaa"
        int dsa;
-#line 92 "certtool.gaa"
+#line 97 "certtool.gaa"
        int pkcs8;
-#line 85 "certtool.gaa"
+#line 90 "certtool.gaa"
        int v1_cert;
-#line 82 "certtool.gaa"
+#line 87 "certtool.gaa"
        int fix_key;
-#line 67 "certtool.gaa"
+#line 70 "certtool.gaa"
        int crq_extensions;
-#line 54 "certtool.gaa"
+#line 57 "certtool.gaa"
        char *pass;
-#line 51 "certtool.gaa"
+#line 54 "certtool.gaa"
        char *ca;
-#line 48 "certtool.gaa"
+#line 51 "certtool.gaa"
        char *ca_privkey;
-#line 45 "certtool.gaa"
+#line 48 "certtool.gaa"
        char *cert;
-#line 42 "certtool.gaa"
+#line 45 "certtool.gaa"
        char *request;
+#line 42 "certtool.gaa"
+       char *pubkey;
 #line 39 "certtool.gaa"
        char *privkey;
 #line 17 "certtool.gaa"
diff --git a/src/certtool.c b/src/certtool.c
index 860ab90..87c3a13 100644
--- a/src/certtool.c
+++ b/src/certtool.c
@@ -25,6 +25,8 @@
 #include <gnutls/x509.h>
 #include <gnutls/openpgp.h>
 #include <gnutls/pkcs12.h>
+#include <gnutls/pkcs11.h>
+#include <gnutls/abstract.h>
 
 #include <gcrypt.h>
 
@@ -50,7 +52,6 @@
 #include "certtool-common.h"
 
 static void print_crl_info (gnutls_x509_crl_t crl, FILE * out);
-int generate_prime (int bits, int how);
 void pkcs7_info (void);
 void crq_info (void);
 void smime_to_pkcs7 (void);
@@ -59,31 +60,25 @@ void generate_pkcs12 (void);
 void generate_pkcs8 (void);
 void verify_chain (void);
 void verify_crl (void);
+void pubkey_info (void);
 void pgp_privkey_info (void);
 void pgp_ring_info (void);
-gnutls_x509_privkey_t load_private_key (int mand);
-gnutls_x509_crq_t load_request (void);
-gnutls_x509_privkey_t load_ca_private_key (void);
-gnutls_x509_crt_t load_ca_cert (void);
-gnutls_x509_crt_t load_cert (int mand);
 void certificate_info (void);
 void pgp_certificate_info (void);
 void crl_info (void);
 void privkey_info (void);
-static void print_certificate_info (gnutls_x509_crt_t crt, FILE * out,
-                                   unsigned int);
 static void gaa_parser (int argc, char **argv);
 void generate_self_signed (void);
 void generate_request (void);
 gnutls_x509_crt_t *load_cert_list (int mand, size_t * size);
+static void print_certificate_info (gnutls_x509_crt_t crt, FILE * out, 
unsigned int all);
 
 static void print_hex_datum (gnutls_datum_t * dat);
 
-
 static gaainfo info;
 FILE *outfile;
 FILE *infile;
-gnutls_digest_algorithm_t dig = GNUTLS_DIG_SHA1;
+gnutls_digest_algorithm_t default_dig;
 
 /* non interactive operation if set
  */
@@ -133,8 +128,11 @@ static void
 print_dsa_pkey (gnutls_datum_t * x, gnutls_datum_t * y, gnutls_datum_t * p,
                gnutls_datum_t * q, gnutls_datum_t * g)
 {
-  fprintf (outfile, "private key:");
-  print_hex_datum (x);
+  if (x) 
+    {
+      fprintf (outfile, "private key:");
+      print_hex_datum (x);
+    }
   fprintf (outfile, "public key:");
   print_hex_datum (y);
   fprintf (outfile, "p:");
@@ -147,34 +145,90 @@ print_dsa_pkey (gnutls_datum_t * x, gnutls_datum_t * y, 
gnutls_datum_t * p,
 
 static void
 print_rsa_pkey (gnutls_datum_t * m, gnutls_datum_t * e, gnutls_datum_t * d,
-               gnutls_datum_t * p, gnutls_datum_t * q, gnutls_datum_t * u)
+               gnutls_datum_t * p, gnutls_datum_t * q, gnutls_datum_t * u,
+               gnutls_datum_t * exp1, gnutls_datum_t *exp2)
 {
   fprintf (outfile, "modulus:");
   print_hex_datum (m);
   fprintf (outfile, "public exponent:");
   print_hex_datum (e);
-  fprintf (outfile, "private exponent:");
-  print_hex_datum (d);
-  fprintf (outfile, "prime1:");
-  print_hex_datum (p);
-  fprintf (outfile, "prime2:");
-  print_hex_datum (q);
-  fprintf (outfile, "coefficient:");
-  print_hex_datum (u);
+  if (d) 
+    {
+      fprintf (outfile, "private exponent:");
+      print_hex_datum (d);
+      fprintf (outfile, "prime1:");
+      print_hex_datum (p);
+      fprintf (outfile, "prime2:");
+      print_hex_datum (q);
+      fprintf (outfile, "coefficient:");
+      print_hex_datum (u);
+      if (exp1 && exp2)
+        {
+          fprintf (outfile, "exp1:");
+          print_hex_datum (exp1);
+          fprintf (outfile, "exp2:");
+          print_hex_datum (exp2);
+        }
+    }
 }
 
+static gnutls_sec_param_t str_to_sec_param(const char* str)
+{
+  if (strcasecmp(str, "low")==0)
+    {
+      return GNUTLS_SEC_PARAM_LOW;
+    }
+  else if (strcasecmp(str, "normal")==0)
+    {
+      return GNUTLS_SEC_PARAM_NORMAL;
+    }
+  else if (strcasecmp(str, "high")==0)
+    {
+      return GNUTLS_SEC_PARAM_HIGH;
+    }
+  else if (strcasecmp(str, "ultra")==0)
+    {
+      return GNUTLS_SEC_PARAM_ULTRA;
+    }
+  else
+    {
+      fprintf(stderr, "Unknown security parameter string: %s\n", str);
+      exit(1);
+    }
+
+}
+
+int get_bits(gnutls_pk_algorithm_t key_type)
+{
+int bits;
+
+  if (info.bits != 0)
+    {
+      fprintf(stderr, "** Note: Please use the --sec-param instead of 
--bits\n");
+      bits = info.bits;
+    }
+  else
+    {
+      if (info.sec_param)
+        {
+          bits = gnutls_sec_param_to_pk_bits(key_type, 
str_to_sec_param(info.sec_param));
+        }
+      else bits = gnutls_sec_param_to_pk_bits(key_type, 
GNUTLS_SEC_PARAM_NORMAL);
+    }
+
+  return bits;
+}
+
+
 static gnutls_x509_privkey_t
 generate_private_key_int (void)
 {
   gnutls_x509_privkey_t key;
-  int ret, key_type;
+  int ret, key_type, bits;
 
   if (info.dsa)
     {
       key_type = GNUTLS_PK_DSA;
-      /* FIXME: Remove me once we depend on 1.3.x */
-      if (info.bits > 1024 && gcry_check_version ("1.3.1") == NULL)
-       info.bits = 1024;
     }
   else
     key_type = GNUTLS_PK_RSA;
@@ -183,7 +237,9 @@ generate_private_key_int (void)
   if (ret < 0)
     error (EXIT_FAILURE, 0, "privkey_init: %s", gnutls_strerror (ret));
 
-  fprintf (stderr, "Generating a %d bit %s private key...\n", info.bits,
+  bits = get_bits(key_type);
+
+  fprintf (stderr, "Generating a %d bit %s private key...\n", 
get_bits(key_type),
           gnutls_pk_algorithm_get_name (key_type));
 
   if (info.quick_random == 0)
@@ -191,7 +247,7 @@ generate_private_key_int (void)
             "This might take several minutes depending on availability of 
randomness"
             " in /dev/random.\n");
 
-  ret = gnutls_x509_privkey_generate (key, key_type, info.bits, 0);
+  ret = gnutls_x509_privkey_generate (key, key_type, get_bits(key_type), 0);
   if (ret < 0)
     error (EXIT_FAILURE, 0, "privkey_generate: %s", gnutls_strerror (ret));
 
@@ -641,8 +697,27 @@ generate_crl (gnutls_x509_crt_t ca_crt)
   return crl;
 }
 
-void
-generate_self_signed (void)
+static gnutls_digest_algorithm_t get_dig(gnutls_x509_crt crt)
+{
+gnutls_digest_algorithm_t dig;
+int result;
+unsigned int mand;
+
+  result = gnutls_x509_crt_get_preferred_hash_algorithm(crt, &dig, &mand);
+  if (result < 0)
+    {
+           error (EXIT_FAILURE, 0, "crl_preferred_hash_algorithm: %s",
+              gnutls_strerror (result));
+    }
+
+  /* if algorithm allows alternatives */
+  if (mand == 0 && default_dig != GNUTLS_DIG_UNKNOWN)
+    dig = default_dig;
+
+  return dig;
+}
+
+void generate_self_signed (void)
 {
   gnutls_x509_crt_t crt;
   gnutls_x509_privkey_t key;
@@ -672,7 +747,7 @@ generate_self_signed (void)
 
   fprintf (stderr, "\n\nSigning certificate...\n");
 
-  result = gnutls_x509_crt_sign2 (crt, crt, key, dig, 0);
+  result = gnutls_x509_crt_sign2 (crt, crt, key, get_dig(crt), 0);
   if (result < 0)
     error (EXIT_FAILURE, 0, "crt_sign: %s", gnutls_strerror (result));
 
@@ -714,7 +789,7 @@ generate_signed_certificate (void)
 
   fprintf (stderr, "\n\nSigning certificate...\n");
 
-  result = gnutls_x509_crt_sign2 (crt, ca_crt, ca_key, dig, 0);
+  result = gnutls_x509_crt_sign2 (crt, ca_crt, ca_key, get_dig(ca_crt), 0);
   if (result < 0)
     error (EXIT_FAILURE, 0, "crt_sign: %s", gnutls_strerror (result));
 
@@ -748,7 +823,7 @@ generate_proxy_certificate (void)
 
   fprintf (stderr, "\n\nSigning certificate...\n");
 
-  result = gnutls_x509_crt_sign2 (crt, eecrt, eekey, dig, 0);
+  result = gnutls_x509_crt_sign2 (crt, eecrt, eekey, get_dig(eecrt), 0);
   if (result < 0)
     error (EXIT_FAILURE, 0, "crt_sign: %s", gnutls_strerror (result));
 
@@ -817,7 +892,7 @@ update_signed_certificate (void)
 
   fprintf (stderr, "\n\nSigning certificate...\n");
 
-  result = gnutls_x509_crt_sign2 (crt, ca_crt, ca_key, dig, 0);
+  result = gnutls_x509_crt_sign2 (crt, ca_crt, ca_key, get_dig(ca_crt), 0);
   if (result < 0)
     error (EXIT_FAILURE, 0, "crt_sign: %s", gnutls_strerror (result));
 
@@ -892,24 +967,25 @@ gaa_parser (int argc, char **argv)
   else
     info.outcert_format = GNUTLS_X509_FMT_PEM;
 
+  default_dig = GNUTLS_DIG_UNKNOWN;
   if (info.hash != NULL)
     {
       if (strcasecmp (info.hash, "md5") == 0)
        {
          fprintf (stderr,
                   "Warning: MD5 is broken, and should not be used any more for 
digital signatures.\n");
-         dig = GNUTLS_DIG_MD5;
+         default_dig = GNUTLS_DIG_MD5;
        }
       else if (strcasecmp (info.hash, "sha1") == 0)
-       dig = GNUTLS_DIG_SHA1;
+       default_dig = GNUTLS_DIG_SHA1;
       else if (strcasecmp (info.hash, "sha256") == 0)
-       dig = GNUTLS_DIG_SHA256;
+       default_dig = GNUTLS_DIG_SHA256;
       else if (strcasecmp (info.hash, "sha384") == 0)
-       dig = GNUTLS_DIG_SHA384;
+       default_dig = GNUTLS_DIG_SHA384;
       else if (strcasecmp (info.hash, "sha512") == 0)
-       dig = GNUTLS_DIG_SHA512;
+       default_dig = GNUTLS_DIG_SHA512;
       else if (strcasecmp (info.hash, "rmd160") == 0)
-       dig = GNUTLS_DIG_RMD160;
+       default_dig = GNUTLS_DIG_RMD160;
       else
        error (EXIT_FAILURE, 0, "invalid hash: %s", info.hash);
     }
@@ -921,19 +997,6 @@ gaa_parser (int argc, char **argv)
       template_parse (info.template);
     }
 
-#ifdef gcry_fips_mode_active
-  /* Libgcrypt manual says that gcry_version_check must be called
-     before calling gcry_fips_mode_active. */
-  gcry_check_version (NULL);
-  if (gcry_fips_mode_active ())
-    {
-      ret = gnutls_register_md5_handler ();
-      if (ret)
-       fprintf (stderr, "gnutls_register_md5_handler: %s\n",
-                gnutls_strerror (ret));
-    }
-#endif
-
   gnutls_global_set_log_function (tls_log_func);
   gnutls_global_set_log_level (info.debug);
   if (info.debug > 1)
@@ -941,13 +1004,29 @@ gaa_parser (int argc, char **argv)
 
   if ((ret = gnutls_global_init ()) < 0)
     error (EXIT_FAILURE, 0, "global_init: %s", gnutls_strerror (ret));
+    
+  if (info.pkcs11_provider != NULL)
+    {
+      ret = gnutls_pkcs11_init(GNUTLS_PKCS11_FLAG_MANUAL, NULL);
+      if (ret < 0)
+        fprintf (stderr, "pkcs11_init: %s", gnutls_strerror (ret));
+      else {
+        ret = gnutls_pkcs11_add_provider(info.pkcs11_provider, NULL);
+        if (ret < 0)
+          error (EXIT_FAILURE, 0, "pkcs11_add_provider: %s", gnutls_strerror 
(ret));
+      }
+    }
+  else
+    {
+      ret = gnutls_pkcs11_init(GNUTLS_PKCS11_FLAG_AUTO, NULL);
+      if (ret < 0)
+        fprintf (stderr, "pkcs11_init: %s", gnutls_strerror (ret));
+    }
+      
 
   if ((ret = gnutls_global_init_extra ()) < 0)
     error (EXIT_FAILURE, 0, "global_init_extra: %s", gnutls_strerror (ret));
 
-  if (info.quick_random != 0)
-    gcry_control (GCRYCTL_ENABLE_QUICK_RANDOM, 0);
-
   switch (info.action)
     {
     case ACTION_SELF_SIGNED:
@@ -971,6 +1050,9 @@ gaa_parser (int argc, char **argv)
     case ACTION_PRIVKEY_INFO:
       privkey_info ();
       break;
+    case ACTION_PUBKEY_INFO:
+      pubkey_info ();
+      break;
     case ACTION_UPDATE_CERTIFICATE:
       update_signed_certificate ();
       break;
@@ -981,10 +1063,10 @@ gaa_parser (int argc, char **argv)
       pkcs12_info ();
       break;
     case ACTION_GENERATE_DH:
-      generate_prime (info.bits, 1);
+      generate_prime (1);
       break;
     case ACTION_GET_DH:
-      generate_prime (info.bits, 0);
+      generate_prime (0);
       break;
     case ACTION_CRL_INFO:
       crl_info ();
@@ -1007,6 +1089,21 @@ gaa_parser (int argc, char **argv)
     case ACTION_GENERATE_PKCS8:
       generate_pkcs8 ();
       break;
+    case ACTION_PKCS11_LIST:
+      pkcs11_list(outfile, info.pkcs11_url, info.pkcs11_type);
+      break;
+    case ACTION_PKCS11_TOKENS:
+      pkcs11_token_list(outfile);
+      break;
+    case ACTION_PKCS11_EXPORT_URL:
+      pkcs11_export(outfile, info.pkcs11_url);
+      break;
+    case ACTION_PKCS11_WRITE_URL:
+      pkcs11_write(outfile, info.pkcs11_url, info.pkcs11_label, 
info.pkcs11_trusted);
+      break;
+    case ACTION_PKCS11_DELETE_URL:
+      pkcs11_delete(outfile, info.pkcs11_url, batch);
+      break;
 #ifdef ENABLE_OPENPGP
     case ACTION_PGP_INFO:
       pgp_certificate_info ();
@@ -1026,6 +1123,9 @@ gaa_parser (int argc, char **argv)
       exit (0);
     }
   fclose (outfile);
+  
+  gnutls_pkcs11_deinit();
+  gnutls_global_deinit();
 }
 
 #define MAX_CRTS 500
@@ -1220,7 +1320,7 @@ pgp_privkey_info (void)
            fprintf (stderr, "Error in key RSA data export: %s\n",
                     gnutls_strerror (ret));
          else
-           print_rsa_pkey (&m, &e, &d, &p, &q, &u);
+           print_rsa_pkey (&m, &e, &d, &p, &q, &u, NULL, NULL);
 
        }
       else if (ret == GNUTLS_PK_DSA)
@@ -1532,21 +1632,23 @@ privkey_info (void)
    */
   if (ret == GNUTLS_PK_RSA)
     {
-      gnutls_datum_t m, e, d, p, q, u;
+      gnutls_datum_t m, e, d, p, q, u, exp1, exp2;
 
-      ret = gnutls_x509_privkey_export_rsa_raw (key, &m, &e, &d, &p, &q, &u);
+      ret = gnutls_x509_privkey_export_rsa_raw2 (key, &m, &e, &d, &p, &q, &u, 
&exp1, &exp2);
       if (ret < 0)
        fprintf (stderr, "Error in key RSA data export: %s\n",
                 gnutls_strerror (ret));
       else
        {
-         print_rsa_pkey (&m, &e, &d, &p, &q, &u);
+         print_rsa_pkey (&m, &e, &d, &p, &q, &u, &exp1, &exp2);
          gnutls_free (m.data);
          gnutls_free (e.data);
          gnutls_free (d.data);
          gnutls_free (p.data);
          gnutls_free (q.data);
          gnutls_free (u.data);
+         gnutls_free (exp1.data);
+         gnutls_free (exp2.data);
        }
     }
   else if (ret == GNUTLS_PK_DSA)
@@ -1598,6 +1700,51 @@ privkey_info (void)
   gnutls_x509_privkey_deinit (key);
 }
 
+/* Load a public key.
+ * @mand should be non zero if it is required to read a public key.
+ */
+gnutls_pubkey_t
+load_pubkey (int mand)
+{
+  gnutls_pubkey_t key;
+  int ret;
+  gnutls_datum_t dat;
+  size_t size;
+
+  if (!info.pubkey && !mand)
+    return NULL;
+
+  if (info.pubkey == NULL)
+    error (EXIT_FAILURE, 0, "missing --load-pubkey");
+
+  ret = gnutls_pubkey_init (&key);
+  if (ret < 0)
+    error (EXIT_FAILURE, 0, "privkey_init: %s", gnutls_strerror (ret));
+
+  dat.data = read_binary_file (info.pubkey, &size);
+  dat.size = size;
+
+  if (!dat.data)
+    error (EXIT_FAILURE, errno, "reading --load-pubkey: %s", info.pubkey);
+
+  ret = gnutls_pubkey_import (key, &dat, info.incert_format);
+
+  free (dat.data);
+
+  if (ret == GNUTLS_E_BASE64_UNEXPECTED_HEADER_ERROR)
+    {
+      error (EXIT_FAILURE, 0,
+            "import error: could not find a valid PEM header; "
+            "check if your key has the PUBLIC KEY header");
+    }
+
+  if (ret < 0)
+    error (EXIT_FAILURE, 0, "importing --load-pubkey: %s: %s",
+          info.pubkey, gnutls_strerror (ret));
+
+  return key;
+}
+
 
 /* Load the private key.
  * @mand should be non zero if it is required to read a private key.
@@ -2966,3 +3113,141 @@ certtool_version (void)
   version_etc (stdout, program_name, p, gnutls_check_version (NULL),
               "Nikos Mavrogiannopoulos", "Simon Josefsson", (char *) NULL);
 }
+
+static void print_key_usage(FILE* outfile, unsigned int usage)
+{
+  if (usage & GNUTLS_KEY_DIGITAL_SIGNATURE) {
+    fprintf(outfile, "\tDigital signature.\n");
+  }
+
+  if (usage & GNUTLS_KEY_NON_REPUDIATION) {
+    fprintf(outfile, "\tNon repudiation.\n");
+  }
+
+  if (usage & GNUTLS_KEY_KEY_ENCIPHERMENT) {
+    fprintf(outfile, "\tKey encipherment.\n");
+  }
+
+  if (usage & GNUTLS_KEY_DATA_ENCIPHERMENT) {
+    fprintf(outfile, "\tData encipherment.\n");
+  }
+
+  if (usage & GNUTLS_KEY_KEY_AGREEMENT) {
+    fprintf(outfile, "\tKey agreement.\n");
+  }
+
+  if (usage & GNUTLS_KEY_KEY_CERT_SIGN) {
+    fprintf(outfile, "\tCertificate signing.\n");
+  }
+
+  if (usage & GNUTLS_KEY_NON_REPUDIATION) {
+    fprintf(outfile, "\tCRL signing.\n");  
+  }
+
+  if (usage & GNUTLS_KEY_ENCIPHER_ONLY) {
+    fprintf(outfile, "\tKey encipher only.\n");
+  }
+
+  if (usage & GNUTLS_KEY_DECIPHER_ONLY) {
+    fprintf(outfile, "\tKey decipher only.\n");
+  }
+}
+
+void pubkey_info (void)
+{
+  gnutls_x509_crt_t crt;
+  gnutls_pubkey_t pubkey;
+  unsigned int bits, usage;
+  int ret;
+  size_t size;
+  const char* cprint;
+
+  ret = gnutls_pubkey_init(&pubkey);
+  if (ret < 0) {
+    error (EXIT_FAILURE, 0, "pubkey_init: %s", gnutls_strerror (ret));
+  }
+
+  crt = load_cert(0);
+  
+  if (crt != NULL) {
+    ret = gnutls_pubkey_import_x509(pubkey, crt, 0);
+    if (ret < 0) {
+      error (EXIT_FAILURE, 0, "pubkey_import_x509: %s", gnutls_strerror (ret));
+    }
+  } else {
+    pubkey = load_pubkey(1);
+  }
+
+  fprintf (outfile, "Public Key Info:\n\n");
+  ret = gnutls_pubkey_get_pk_algorithm (pubkey, &bits);
+  fprintf (outfile, "Public Key Algorithm: ");
+
+  cprint = gnutls_pk_algorithm_get_name (ret);
+  fprintf (outfile, "%s (%u bits)\n", cprint ? cprint : "Unknown", bits);
+
+
+  /* Print the raw public and private keys
+   */
+  if (ret == GNUTLS_PK_RSA)
+    {
+      gnutls_datum_t m, e;
+
+      ret = gnutls_pubkey_get_pk_rsa_raw (pubkey, &m, &e);
+      if (ret < 0)
+       fprintf (stderr, "Error in key RSA data export: %s\n",
+                gnutls_strerror (ret));
+      else
+       {
+         print_rsa_pkey (&m, &e, NULL, NULL, NULL, NULL, NULL, NULL);
+         gnutls_free (m.data);
+         gnutls_free (e.data);
+       }
+    }
+  else if (ret == GNUTLS_PK_DSA)
+    {
+      gnutls_datum_t p, q, g, y;
+
+      ret = gnutls_pubkey_get_pk_dsa_raw (pubkey, &p, &q, &g, &y);
+      if (ret < 0)
+       fprintf (stderr, "Error in key DSA data export: %s\n",
+                gnutls_strerror (ret));
+      else
+       {
+         print_dsa_pkey (NULL, &y, &p, &q, &g);
+         gnutls_free (y.data);
+         gnutls_free (p.data);
+         gnutls_free (q.data);
+         gnutls_free (g.data);
+       }
+    }
+
+  ret = gnutls_pubkey_get_key_usage (pubkey, &usage);
+  if (ret < 0) {
+    error (EXIT_FAILURE, 0, "pubkey_get_key_usage: %s", gnutls_strerror (ret));
+  }
+  
+  fprintf (outfile, "Public Key Usage:\n");
+  print_key_usage(outfile, usage);
+
+  fprintf (outfile, "\n");
+
+  size = sizeof (buffer);
+  if ((ret = gnutls_pubkey_get_key_id (pubkey, 0, buffer, &size)) < 0)
+    {
+      fprintf (stderr, "Error in key id calculation: %s\n",
+              gnutls_strerror (ret));
+    }
+  else
+    {
+      fprintf (outfile, "Public Key ID: %s\n", raw_to_string (buffer, size));
+    }
+
+  size = sizeof (buffer);
+  ret = gnutls_pubkey_export (pubkey, GNUTLS_X509_FMT_PEM, buffer, &size);
+  if (ret < 0)
+    error (EXIT_FAILURE, 0, "export error: %s", gnutls_strerror (ret));
+
+  fprintf (outfile, "\n%s\n", buffer);
+
+  gnutls_pubkey_deinit (pubkey);
+}
diff --git a/src/certtool.gaa b/src/certtool.gaa
index 096f119..9b77864 100644
--- a/src/certtool.gaa
+++ b/src/certtool.gaa
@@ -39,6 +39,9 @@ option (get-dh-params) { $action=ACTION_GET_DH; } "Get the 
included PKCS #3 enco
 #char *privkey;
 option (load-privkey) STR "FILE" { $privkey = $1 } "Private key file to use."
 
+#char *pubkey;
+option (load-pubkey) STR "FILE" { $pubkey = $1 } "Private key file to use."
+
 #char *request;
 option (load-request) STR "FILE" { $request = $1 } "Certificate request file 
to use."
 
@@ -79,6 +82,8 @@ option (k, key-info) { $privkey_op=1; $action = 
ACTION_PRIVKEY_INFO; } "Print in
 
 option (pgp-key-info) { $privkey_op=1; $action = ACTION_PGP_PRIVKEY_INFO; } 
"Print information on a OpenPGP private key."
 
+option (pubkey-info) { $action = ACTION_PUBKEY_INFO; } "Print information on a 
public key."
+
 #int fix_key;
 option (fix-key) { $privkey_op=1; $fix_key = 1; } "Regenerate the parameters 
in a private key."
 
@@ -112,6 +117,9 @@ option (outraw) { $outcert_format=1 } "Use RAW/DER format 
for output certificate
 #int bits;
 option (bits) INT "BITS" { $bits = $1 } "specify the number of bits for key 
generation."
 
+#char* sec_param;
+option (sec-param) STR "PARAM" { $sec_param = $1 } "specify the security level 
[low|normal|high|ultra]."
+
 #int quick_random;
 option (disable-quick-random) { $quick_random = 0; } "Use /dev/random for key 
generationg, thus increasing the quality of randomness used."
 
@@ -127,6 +135,26 @@ option (template) STR "FILE" { $template = $1 } "Template 
file to use for non in
 #char *pkcs_cipher;
 option (pkcs-cipher) STR "CIPHER" { $pkcs_cipher = $1 } "Cipher to use for 
pkcs operations (3des,aes-128,aes-192,aes-256,rc2-40)."
 
+#char* pkcs11_provider;
+option (pkcs11-provider) STR "Library" { $pkcs11_provider = $1 } "Specify the 
pkcs11 provider library"
+
+#char* pkcs11_url;
+option (pkcs11-export-url) STR "URL" { $action = ACTION_PKCS11_EXPORT_URL; 
$pkcs11_url = $1; } "Export data specified a pkcs11 URL"
+
+#int pkcs11_type;
+option (pkcs11-list-certs) { $action = ACTION_PKCS11_LIST; 
$pkcs11_type=PKCS11_TYPE_PK; } "List certificates that have a private key 
specified by a PKCS#11 URL"
+option (pkcs11-list-trusted) { $action = ACTION_PKCS11_LIST; 
$pkcs11_type=PKCS11_TYPE_TRUSTED; } "List certificates marked as trusted, 
specified by a PKCS#11 URL"
+option (pkcs11-list-all-certs) { $action = ACTION_PKCS11_LIST; 
$pkcs11_type=PKCS11_TYPE_CRT_ALL; } "List all certificates specified by a 
PKCS#11 URL"
+option (pkcs11-list-all) { $action = ACTION_PKCS11_LIST; 
$pkcs11_type=PKCS11_TYPE_ALL; } "List all objects specified by a PKCS#11 URL"
+option (pkcs11-list-tokens) { $action = ACTION_PKCS11_TOKENS; } "List all 
available tokens"
+
+#char* pkcs11_label;
+option (pkcs11-write) STR "URL" { $action = ACTION_PKCS11_WRITE_URL; 
$pkcs11_url = $1; } "Writes loaded certificates or private keys to a PKCS11 
token."
+option (pkcs11-write-label) STR "label" { $pkcs11_label = $1; } "Sets a label 
for the write operation."
+#int pkcs11_trusted;
+option (pkcs11-write-trusted) { $pkcs11_trusted = 1; } "Marks the certificate 
to be imported as trusted."
+
+option (pkcs11-delete-url) STR "URL" { $action = ACTION_PKCS11_DELETE_URL; 
$pkcs11_url = $1; } "Deletes objects matching the URL."
 
 #int debug;
 option (d, debug) INT "LEVEL" { $debug = $1 } "specify the debug level. 
Default is 1."
@@ -135,8 +163,10 @@ option (h, help) { gaa_help(); exit(0); } "shows this help 
text"
 
 option (v, version) { certtool_version(); exit(0); } "shows the program's 
version"
 
-init { $bits = 2048; $pkcs8 = 0; $privkey = NULL; $ca=NULL; $ca_privkey = 
NULL; 
+init { $bits = 0; $pkcs8 = 0; $privkey = NULL; $ca=NULL; $ca_privkey = NULL;
        $debug=1; $request = NULL; $infile = NULL; $outfile = NULL; $cert = 
NULL; 
        $incert_format = 0; $outcert_format = 0; $action=-1; $pass = NULL; 
$v1_cert = 0;
        $export = 0; $template = NULL; $hash=NULL; $fix_key = 0; 
$quick_random=1; 
-       $privkey_op = 0; $pkcs_cipher = "3des"; $crq_extensions=1; }
+       $privkey_op = 0; $pkcs_cipher = "3des"; $crq_extensions=1; 
$pkcs11_provider= NULL;
+       $pkcs11_url = NULL; $pkcs11_type = PKCS11_TYPE_PK; $pubkey=NULL; 
$pkcs11_label = NULL; 
+       $pkcs11_trusted=0; $sec_param = NULL; }
diff --git a/src/cli-gaa.c b/src/cli-gaa.c
index 40c8447..1d633ca 100644
--- a/src/cli-gaa.c
+++ b/src/cli-gaa.c
@@ -146,14 +146,14 @@ void gaa_help(void)
        __gaa_helpsingle(0, "kx", "kx1 kx2... ", "Key exchange methods to 
enable.");
        __gaa_helpsingle(0, "ctypes", "certType1 certType2... ", "Certificate 
types to enable.");
        __gaa_helpsingle(0, "priority", "PRIORITY STRING ", "Priorities 
string.");
-       __gaa_helpsingle(0, "x509cafile", "FILE ", "Certificate file to use.");
+       __gaa_helpsingle(0, "x509cafile", "FILE ", "Certificate file or PKCS 
#11 URL to use.");
        __gaa_helpsingle(0, "x509crlfile", "FILE ", "CRL file to use.");
        __gaa_helpsingle(0, "pgpkeyfile", "FILE ", "PGP Key file to use.");
        __gaa_helpsingle(0, "pgpkeyring", "FILE ", "PGP Key ring file to use.");
        __gaa_helpsingle(0, "pgpcertfile", "FILE ", "PGP Public Key 
(certificate) file to use.");
        __gaa_helpsingle(0, "pgpsubkey", "HEX|auto ", "PGP subkey to use.");
-       __gaa_helpsingle(0, "x509keyfile", "FILE ", "X.509 key file to use.");
-       __gaa_helpsingle(0, "x509certfile", "FILE ", "X.509 Certificate file to 
use.");
+       __gaa_helpsingle(0, "x509keyfile", "FILE ", "X.509 key file or PKCS #11 
URL to use.");
+       __gaa_helpsingle(0, "x509certfile", "FILE ", "X.509 Certificate file or 
PKCS #11 URL to use.");
        __gaa_helpsingle(0, "srpusername", "NAME ", "SRP username to use.");
        __gaa_helpsingle(0, "srppasswd", "PASSWD ", "SRP password to use.");
        __gaa_helpsingle(0, "pskusername", "NAME ", "PSK username to use.");
diff --git a/src/cli.c b/src/cli.c
index 0e53bdc..4d90b43 100644
--- a/src/cli.c
+++ b/src/cli.c
@@ -37,7 +37,7 @@
 #include <gnutls/extra.h>
 #include <gnutls/x509.h>
 #include <gnutls/openpgp.h>
-#include <gcrypt.h>
+#include <gnutls/pkcs11.h>
 
 /* Gnulib portability files. */
 #include <progname.h>
@@ -144,6 +144,8 @@ static unsigned int x509_crt_size;
 static gnutls_x509_crt_t x509_crt[MAX_CRT];
 static gnutls_x509_privkey_t x509_key = NULL;
 
+static gnutls_pkcs11_privkey_t pkcs11_key = NULL;
+
 static gnutls_openpgp_crt_t pgp_crt = NULL;
 static gnutls_openpgp_privkey_t pgp_key = NULL;
 
@@ -179,58 +181,86 @@ load_keys (void)
 
   if (x509_certfile != NULL && x509_keyfile != NULL)
     {
-      data = load_file (x509_certfile);
-      if (data.data == NULL)
+      if (strncmp (x509_certfile, "pkcs11:", 7) == 0)
        {
-         fprintf (stderr, "*** Error loading cert file.\n");
-         exit (1);
-       }
+         crt_num = 1;
+         gnutls_x509_crt_init (&x509_crt[0]);
 
-      crt_num = MAX_CRT;
-      ret =
-       gnutls_x509_crt_list_import (x509_crt, &crt_num, &data,
-                                    GNUTLS_X509_FMT_PEM,
-                                    
GNUTLS_X509_CRT_LIST_IMPORT_FAIL_IF_EXCEED);
-      if (ret < 0)
-       {
-         if (ret == GNUTLS_E_SHORT_MEMORY_BUFFER)
+         ret =
+           gnutls_x509_crt_import_pkcs11_url (x509_crt[0], x509_certfile);
+         if (ret < 0)
            {
-             fprintf (stderr,
-                      "*** Error loading cert file: Too many certs %d\n",
-                      crt_num);
+             fprintf (stderr, "*** Error loading cert file.\n");
+             exit (1);
+           }
+         x509_crt_size = 1;
+       }
+      else
+       {
 
+         data = load_file (x509_certfile);
+         if (data.data == NULL)
+           {
+             fprintf (stderr, "*** Error loading cert file.\n");
+             exit (1);
            }
-         else
+
+         crt_num = MAX_CRT;
+         ret =
+           gnutls_x509_crt_list_import (x509_crt, &crt_num, &data,
+                                        GNUTLS_X509_FMT_PEM,
+                                        
GNUTLS_X509_CRT_LIST_IMPORT_FAIL_IF_EXCEED);
+         if (ret < 0)
            {
-             fprintf (stderr,
-                      "*** Error loading cert file: %s\n",
-                      gnutls_strerror (ret));
+             if (ret == GNUTLS_E_SHORT_MEMORY_BUFFER)
+               {
+                 fprintf (stderr,
+                          "*** Error loading cert file: Too many certs %d\n",
+                          crt_num);
+
+               }
+             else
+               {
+                 fprintf (stderr,
+                          "*** Error loading cert file: %s\n",
+                          gnutls_strerror (ret));
+               }
+             exit (1);
            }
-         exit (1);
+         x509_crt_size = ret;
        }
-      x509_crt_size = ret;
       fprintf (stderr, "Processed %d client certificates...\n", ret);
 
       unload_file (data);
 
-      data = load_file (x509_keyfile);
-      if (data.data == NULL)
+      if (strncmp (x509_keyfile, "pkcs11:", 7) == 0)
        {
-         fprintf (stderr, "*** Error loading key file.\n");
-         exit (1);
+         gnutls_pkcs11_privkey_init (&pkcs11_key);
+
+         ret = gnutls_pkcs11_privkey_import_url (pkcs11_key, x509_keyfile, 0);
        }
+      else
+       {
+         data = load_file (x509_keyfile);
+         if (data.data == NULL)
+           {
+             fprintf (stderr, "*** Error loading key file.\n");
+             exit (1);
+           }
 
-      gnutls_x509_privkey_init (&x509_key);
+         gnutls_x509_privkey_init (&x509_key);
 
-      ret = gnutls_x509_privkey_import (x509_key, &data, GNUTLS_X509_FMT_PEM);
-      if (ret < 0)
-       {
-         fprintf (stderr, "*** Error loading key file: %s\n",
-                  gnutls_strerror (ret));
-         exit (1);
-       }
+         ret =
+           gnutls_x509_privkey_import (x509_key, &data, GNUTLS_X509_FMT_PEM);
+         if (ret < 0)
+           {
+             fprintf (stderr, "*** Error loading key file: %s\n",
+                      gnutls_strerror (ret));
+             exit (1);
+           }
 
-      unload_file (data);
+         unload_file (data);
+       }
 
       fprintf (stderr, "Processed %d client X.509 certificates...\n",
               x509_crt_size);
@@ -259,27 +289,38 @@ load_keys (void)
 
       unload_file (data);
 
-      data = load_file (pgp_keyfile);
-      if (data.data == NULL)
+      if (strncmp (pgp_keyfile, "pkcs11:", 7) == 0)
        {
-         fprintf (stderr, "*** Error loading PGP key file.\n");
-         exit (1);
+         gnutls_pkcs11_privkey_init (&pkcs11_key);
+
+         ret = gnutls_pkcs11_privkey_import_url (pkcs11_key, pgp_keyfile, 0);
        }
+      else
+       {
 
-      gnutls_openpgp_privkey_init (&pgp_key);
+         data = load_file (pgp_keyfile);
+         if (data.data == NULL)
+           {
+             fprintf (stderr, "*** Error loading PGP key file.\n");
+             exit (1);
+           }
 
-      ret =
-       gnutls_openpgp_privkey_import (pgp_key, &data,
-                                      GNUTLS_OPENPGP_FMT_BASE64, NULL, 0);
-      if (ret < 0)
-       {
-         fprintf (stderr,
-                  "*** Error loading PGP key file: %s\n",
-                  gnutls_strerror (ret));
-         exit (1);
-       }
+         gnutls_openpgp_privkey_init (&pgp_key);
 
-      unload_file (data);
+         ret =
+           gnutls_openpgp_privkey_import (pgp_key, &data,
+                                          GNUTLS_OPENPGP_FMT_BASE64, NULL,
+                                          0);
+         if (ret < 0)
+           {
+             fprintf (stderr,
+                      "*** Error loading PGP key file: %s\n",
+                      gnutls_strerror (ret));
+             exit (1);
+           }
+
+         unload_file (data);
+       }
 
       if (info.pgp_subkey != NULL)
        {
@@ -347,7 +388,7 @@ static int
 cert_callback (gnutls_session_t session,
               const gnutls_datum_t * req_ca_rdn, int nreqs,
               const gnutls_pk_algorithm_t * sign_algos,
-              int sign_algos_length, gnutls_retr_st * st)
+              int sign_algos_length, gnutls_retr2_st * st)
 {
   char issuer_dn[256];
   int i, ret;
@@ -355,7 +396,6 @@ cert_callback (gnutls_session_t session,
 
   if (verbose)
     {
-
       /* Print the server's trusted CAs
        */
       if (nreqs > 0)
@@ -381,17 +421,16 @@ cert_callback (gnutls_session_t session,
    * supported by the server.
    */
 
-  st->type = gnutls_certificate_type_get (session);
-
+  st->cert_type = gnutls_certificate_type_get (session);
 
   st->ncerts = 0;
 
-  if (st->type == GNUTLS_CRT_X509)
+  if (st->cert_type == GNUTLS_CRT_X509)
     {
       gnutls_sign_algorithm_t cert_algo, req_algo;
       int i, match = 0;
 
-      if (x509_crt[0] != NULL)
+      if (x509_crt_size > 0)
        {
          ret = gnutls_x509_crt_get_signature_algorithm (x509_crt[0]);
          if (ret < 0)
@@ -428,28 +467,57 @@ cert_callback (gnutls_session_t session,
                ("- Could not find a suitable certificate to send to server\n");
              return -1;
            }
-       }
 
-      if (x509_crt != NULL && x509_key != NULL)
-       {
+          if (x509_key != NULL)
+            {
+             st->key.x509 = x509_key;
+             st->key_type = GNUTLS_PRIVKEY_X509;
+            }
+          else if (pkcs11_key != NULL)
+            {
+              st->key.pkcs11 = pkcs11_key;
+              st->key_type = GNUTLS_PRIVKEY_PKCS11;
+            }
+          else
+            {
+              printf ("- Could not find a suitable key to send to server\n");
+              return -1;
+            }
+
          st->ncerts = x509_crt_size;
 
          st->cert.x509 = x509_crt;
-         st->key.x509 = x509_key;
 
          st->deinit_all = 0;
 
          return 0;
        }
+
     }
-  else if (st->type == GNUTLS_CRT_OPENPGP)
+  else if (st->cert_type == GNUTLS_CRT_OPENPGP)
     {
-      if (pgp_key != NULL && pgp_crt != NULL)
+      if (pgp_crt != NULL)
        {
+
+          if (pgp_key != NULL)
+            {
+              st->key.pgp = pgp_key;
+              st->key_type = GNUTLS_PRIVKEY_OPENPGP;
+            }
+          else if (pkcs11_key != NULL)
+            {
+              st->key.pkcs11 = pkcs11_key;
+              st->key_type = GNUTLS_PRIVKEY_PKCS11;
+            }
+          else
+            {
+              printf ("- Could not find a suitable key to send to server\n");
+              return -1;
+            }
+
          st->ncerts = 1;
 
          st->cert.pgp = pgp_crt;
-         st->key.pgp = pgp_key;
 
          st->deinit_all = 0;
 
@@ -510,8 +578,9 @@ init_tls_session (const char *hostname)
     gnutls_credentials_set (session, GNUTLS_CRD_PSK, psk_cred);
   gnutls_credentials_set (session, GNUTLS_CRD_CERTIFICATE, xcred);
 
-  gnutls_certificate_client_set_retrieve_function (xcred, cert_callback);
+  gnutls_certificate_set_retrieve_function (xcred, cert_callback);
   gnutls_certificate_set_verify_function (xcred, cert_verify_callback);
+  gnutls_certificate_set_verify_flags(xcred, 
GNUTLS_VERIFY_ALLOW_X509_V1_CA_CRT);
 
   /* send the fingerprint */
 #ifdef ENABLE_OPENPGP
@@ -629,21 +698,6 @@ main (int argc, char **argv)
 
   set_program_name (argv[0]);
 
-  gcry_control (GCRYCTL_ENABLE_QUICK_RANDOM, 0);
-
-#ifdef gcry_fips_mode_active
-  /* Libgcrypt manual says that gcry_version_check must be called
-     before calling gcry_fips_mode_active. */
-  gcry_check_version (NULL);
-  if (gcry_fips_mode_active ())
-    {
-      ret = gnutls_register_md5_handler ();
-      if (ret)
-       fprintf (stderr, "gnutls_register_md5_handler: %s\n",
-                gnutls_strerror (ret));
-    }
-#endif
-
   if ((ret = gnutls_global_init ()) < 0)
     {
       fprintf (stderr, "global_init: %s\n", gnutls_strerror (ret));
@@ -656,6 +710,7 @@ main (int argc, char **argv)
       exit (1);
     }
 
+  pkcs11_common ();
   gaa_parser (argc, argv);
   if (hostname == NULL)
     {
@@ -886,9 +941,6 @@ after_handshake:
        }
     }
 
-  if (info.debug)
-    gcry_control (GCRYCTL_DUMP_RANDOM_STATS);
-
   if (user_term != 0)
     socket_bye (&hd);
   else
@@ -1293,7 +1345,7 @@ socket_bye (socket_st * socket)
   if (socket->secure)
     {
       do
-       ret = gnutls_bye (socket->session, GNUTLS_SHUT_RDWR);
+       ret = gnutls_bye (socket->session, GNUTLS_SHUT_WR);
       while (ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN);
       if (ret < 0)
        fprintf (stderr, "*** gnutls_bye() error: %s\n",
diff --git a/src/cli.gaa b/src/cli.gaa
index 79866f4..7cd0084 100644
--- a/src/cli.gaa
+++ b/src/cli.gaa
@@ -75,7 +75,7 @@ option (ctypes) *STR "certType1 certType2..." { $ctype = $1; 
$nctype = @1 } "Cer
 option (priority) STR "PRIORITY STRING" { $priorities = $1 } "Priorities 
string."
 
 #char *x509_cafile;
-option (x509cafile) STR "FILE" { $x509_cafile = $1 } "Certificate file to use."
+option (x509cafile) STR "FILE" { $x509_cafile = $1 } "Certificate file or PKCS 
#11 URL to use."
 
 #char *x509_crlfile;
 option (x509crlfile) STR "FILE" { $x509_crlfile = $1 } "CRL file to use."
@@ -93,10 +93,10 @@ option (pgpcertfile) STR "FILE" { $pgp_certfile = $1 } "PGP 
Public Key (certific
 option (pgpsubkey) STR "HEX|auto" { $pgp_subkey = $1 } "PGP subkey to use."
 
 #char *x509_keyfile;
-option (x509keyfile) STR "FILE" { $x509_keyfile = $1 } "X.509 key file to use."
+option (x509keyfile) STR "FILE" { $x509_keyfile = $1 } "X.509 key file or PKCS 
#11 URL to use."
 
 #char *x509_certfile;
-option (x509certfile) STR "FILE" { $x509_certfile = $1 } "X.509 Certificate 
file to use."
+option (x509certfile) STR "FILE" { $x509_certfile = $1 } "X.509 Certificate 
file or PKCS #11 URL to use."
 
 #char *srp_username;
 option (srpusername) STR "NAME" { $srp_username = $1 } "SRP username to use."
diff --git a/src/common.c b/src/common.c
index 5de7473..3a7ded6 100644
--- a/src/common.c
+++ b/src/common.c
@@ -36,8 +36,10 @@
 #include <gnutls/openpgp.h>
 #include <time.h>
 #include <common.h>
+#include <gnutls/pkcs11.h>
 
 #define SU(x) (x!=NULL?x:"Unknown")
+#define MIN(x,y) ((x)<(y))?(x):(y)
 
 int print_cert;
 extern int verbose;
@@ -858,3 +860,51 @@ service_to_port (const char *service)
 
   return ntohs (server_port->s_port);
 }
+
+static int pin_callback(void* user, int attempt, const char *slot_descr,
+       const char *token_label, unsigned int flags, char* pin, size_t pin_max)
+{
+const char* password;
+int len;
+
+       printf("PIN required for token '%s' in slot '%s'\n", token_label, 
slot_descr);
+       if (flags & GNUTLS_PKCS11_PIN_FINAL_TRY)
+               printf("*** This is the final try before locking!\n");
+       if (flags & GNUTLS_PKCS11_PIN_COUNT_LOW)
+               printf("*** Only few tries left before locking!\n");
+       
+       password = getpass("Enter pin: ");
+       if (password==NULL || password[0] == 0) {
+               fprintf(stderr, "No password given\n");
+               exit(1);
+       }
+       
+       len = MIN(pin_max,strlen(password));
+       memcpy(pin, password, len);
+       pin[len] = 0;
+       
+       return 0;
+}
+
+static int token_callback(void* user, const char* label, const unsigned retry)
+{
+char buf[32];
+char *p;
+
+       if (retry > 0) {
+               fprintf(stderr, "Could not find token %s\n", label);
+               return -1;
+       }
+       printf("Please insert token '%s' in slot and press enter\n", label);
+       p = fgets(buf, sizeof(buf), stdin);
+
+       return 0;
+}
+
+void pkcs11_common(void)
+{
+
+       gnutls_pkcs11_set_pin_function (pin_callback, NULL);
+       gnutls_pkcs11_set_token_function(token_callback, NULL);
+
+}
diff --git a/src/common.h b/src/common.h
index 29a68a5..fb04fed 100644
--- a/src/common.h
+++ b/src/common.h
@@ -40,5 +40,5 @@ void parse_protocols (char **protocols, int protocols_size,
                      int *protocol_priority);
 const char *raw_to_string (const unsigned char *raw, size_t raw_size);
 int service_to_port (const char *service);
-
+void pkcs11_common(void);
 void sockets_init (void);
diff --git a/src/crypt-gaa.c b/src/crypt-gaa.c
index 8ec3b03..3375cf9 100644
--- a/src/crypt-gaa.c
+++ b/src/crypt-gaa.c
@@ -389,12 +389,31 @@ static int gaa_getint(char *arg)
     return tmp;
 }
 
+static char gaa_getchar(char *arg)
+{
+    if(strlen(arg) != 1)
+    {
+        printf("Option %s: '%s' isn't an character\n", gaa_current_option, 
arg);
+        GAAERROR(-1);
+    }
+    return arg[0];
+}
 
 static char* gaa_getstr(char *arg)
 {
     return arg;
 }
-
+static float gaa_getfloat(char *arg)
+{
+    float tmp;
+    char a;
+    if(sscanf(arg, "%f%c", &tmp, &a) < 1)
+    {
+        printf("Option %s: '%s' isn't a float number\n", gaa_current_option, 
arg);
+        GAAERROR(-1);
+    }
+    return tmp;
+}
 /* option structures */
 
 struct GAAOPTION_create_conf 
@@ -615,19 +634,16 @@ static int gaa_try(int gaa_num, int gaa_index, gaainfo 
*gaaval, char *opt_list)
 int gaa(int argc, char **argv, gaainfo *gaaval)
 {
     int tmp1, tmp2;
-    int l;
-    size_t i, j;
+    int i, j;
     char *opt_list;
 
-    i = 0;
-
     GAAargv = argv;
     GAAargc = argc;
 
     opt_list = (char*) gaa_malloc(GAA_NB_OPTION + 1);
 
-    for(l = 0; l < GAA_NB_OPTION + 1; l++)
-        opt_list[l] = 0;
+    for(i = 0; i < GAA_NB_OPTION + 1; i++)
+        opt_list[i] = 0;
     /* initialization */
     if(inited == 0)
     {
@@ -646,27 +662,27 @@ int gaa(int argc, char **argv, gaainfo *gaaval)
       gaa_arg_used = gaa_malloc(argc * sizeof(char));
     }
 
-    for(l = 1; l < argc; l++)
-        gaa_arg_used[l] = 0;
-    for(l = 1; l < argc; l++)
+    for(i = 1; i < argc; i++)
+        gaa_arg_used[i] = 0;
+    for(i = 1; i < argc; i++)
     {
-        if(gaa_arg_used[l] == 0)
+        if(gaa_arg_used[i] == 0)
         {
             j = 0;
-            tmp1 = gaa_is_an_argument(GAAargv[l]);
+            tmp1 = gaa_is_an_argument(GAAargv[i]);
             switch(tmp1)
             {
             case GAA_WORD_OPTION:
                 j++;
             case GAA_LETTER_OPTION:
                 j++;
-                tmp2 = gaa_get_option_num(argv[l]+j, tmp1);
+                tmp2 = gaa_get_option_num(argv[i]+j, tmp1);
                 if(tmp2 == GAA_ERROR_NOMATCH)
                 {
-                    printf("Invalid option '%s'\n", argv[l]+j);
+                    printf("Invalid option '%s'\n", argv[i]+j);
                     return 0;
                 }
-                switch(gaa_try(tmp2, l+1, gaaval, opt_list))
+                switch(gaa_try(tmp2, i+1, gaaval, opt_list))
                 {
                 case GAA_ERROR_NOTENOUGH_ARGS:
                     printf("'%s': not enough arguments\n",gaa_current_option);
@@ -679,18 +695,18 @@ int gaa(int argc, char **argv, gaainfo *gaaval)
                 default:
                     printf("Unknown error\n");
                 }
-                gaa_arg_used[l] = 1;
+                gaa_arg_used[i] = 1;
                 break;
             case GAA_MULTIPLE_OPTION:
-                for(j = 1; j < strlen(argv[l]); j++)
+                for(j = 1; j < strlen(argv[i]); j++)
                 {
-                    tmp2 = gaa_get_option_num(argv[l]+j, tmp1);
+                    tmp2 = gaa_get_option_num(argv[i]+j, tmp1);
                     if(tmp2 == GAA_ERROR_NOMATCH)
                     {
-                        printf("Invalid option '%c'\n", *(argv[l]+j));
+                        printf("Invalid option '%c'\n", *(argv[i]+j));
                         return 0;
                     }
-                    switch(gaa_try(tmp2, l+1, gaaval, opt_list))
+                    switch(gaa_try(tmp2, i+1, gaaval, opt_list))
                     {
                     case GAA_ERROR_NOTENOUGH_ARGS:
                         printf("'%s': not enough 
arguments\n",gaa_current_option);
@@ -704,7 +720,7 @@ int gaa(int argc, char **argv, gaainfo *gaaval)
                         printf("Unknown error\n");
                     }
                 }
-                gaa_arg_used[l] = 1;
+                gaa_arg_used[i] = 1;
                 break;
             default: break;
             }
@@ -730,9 +746,9 @@ if(gaa_processing_file == 0)
     }
 #endif
 }
-    for(l = 1; l < argc; l++)
+    for(i = 1; i < argc; i++)
     {
-        if(gaa_arg_used[l] == 0)
+        if(gaa_arg_used[i] == 0)
         {
             printf("Too many arguments\n");
             return 0;
@@ -783,7 +799,7 @@ static int gaa_internal_get_next_str(FILE *file, 
gaa_str_node *tmp_str, int argc
 
         len++;
         a = fgetc( file);
-        if(a==EOF) return 0; /* a = ' '; */
+        if(a==EOF) return 0; //a = ' ';
     }
 
     len += 1;
diff --git a/src/crypt.c b/src/crypt.c
index 0f5c5f7..1553b43 100644
--- a/src/crypt.c
+++ b/src/crypt.c
@@ -477,7 +477,7 @@ _srp_crypt (const char *username, const char *passwd, int 
salt_size,
 
   /* generate the salt
    */
-  if (_gnutls_rnd (GNUTLS_RND_NONCE, salt, salt_size) < 0)
+  if (gnutls_rnd (GNUTLS_RND_NONCE, salt, salt_size) < 0)
     {
       fprintf (stderr, "Could not create nonce\n");
       return NULL;
diff --git a/src/pkcs11.c b/src/pkcs11.c
new file mode 100644
index 0000000..dc3e8a3
--- /dev/null
+++ b/src/pkcs11.c
@@ -0,0 +1,408 @@
+#include <config.h>
+
+#include <gnutls/gnutls.h>
+#include <gnutls/extra.h>
+#include <gnutls/pkcs11.h>
+#include <gnutls/abstract.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include "certtool-common.h"
+#include "certtool-cfg.h"
+#include <string.h>
+
+#define MIN(x,y) ((x)<(y))?(x):(y)
+
+static int pin_callback(void* user, int attempt, const char *slot_descr,
+       const char *token_label, unsigned int flags, char* pin, size_t pin_max)
+{
+const char* password;
+int len;
+
+       printf("PIN required for token '%s' in slot '%s'\n", token_label, 
slot_descr);
+       if (flags & GNUTLS_PKCS11_PIN_FINAL_TRY)
+               printf("*** This is the final try before locking!\n");
+       if (flags & GNUTLS_PKCS11_PIN_COUNT_LOW)
+               printf("*** Only few tries left before locking!\n");
+
+       password = get_pass();
+       if (password==NULL) {
+               fprintf(stderr, "No password given\n");
+               exit(1);
+       }
+
+       len = MIN(pin_max,strlen(password));
+       memcpy(pin, password, len);
+       pin[len] = 0;
+       
+       return 0;
+}
+
+static void pkcs11_common(void)
+{
+
+       gnutls_pkcs11_set_pin_function (pin_callback, NULL);
+
+}
+
+void pkcs11_delete(FILE* outfile, const char* url, int batch)
+{
+int ret;
+       if (!batch) {
+               pkcs11_list(outfile, url, PKCS11_TYPE_ALL);
+               ret = read_yesno("Are you sure you want to delete those 
objects? (Y/N): ");
+               if (ret == 0) {
+                       exit(1);
+               }
+       }
+       
+       ret = gnutls_pkcs11_delete_url(url);
+       if (ret < 0) {
+               fprintf(stderr, "Error in %s:%d: %s\n", __func__, __LINE__, 
gnutls_strerror(ret));
+               exit(1);
+       }
+       
+       fprintf(outfile, "\n%d objects deleted\n", ret);
+       
+       return;
+}
+                                                                               
                                                                 
+/* lists certificates from a token
+ */
+void pkcs11_list( FILE* outfile, const char* url, int type)
+{
+gnutls_pkcs11_obj_t *crt_list;
+gnutls_x509_crt_t xcrt;
+unsigned int crt_list_size = 0;
+int ret;
+char* output;
+int i, flags;
+
+       pkcs11_common();
+
+       if (url == NULL)
+               url = "pkcs11:";
+
+       if (type == PKCS11_TYPE_TRUSTED) {
+               flags = GNUTLS_PKCS11_OBJ_ATTR_CRT_TRUSTED;
+       } else if (type == PKCS11_TYPE_PK) {
+               flags = GNUTLS_PKCS11_OBJ_ATTR_CRT_WITH_PRIVKEY;
+       } else if (type == PKCS11_TYPE_CRT_ALL) {
+               flags = GNUTLS_PKCS11_OBJ_ATTR_CRT_ALL;
+       } else {
+               flags = GNUTLS_PKCS11_OBJ_ATTR_ALL;
+       }
+               
+       /* give some initial value to avoid asking for the pkcs11 pin twice.
+        */
+       crt_list_size = 128;
+       crt_list = malloc(sizeof(*crt_list)*crt_list_size);
+       if (crt_list == NULL) {
+               fprintf(stderr, "Memory error\n");
+               exit(1);
+       }
+
+       ret = gnutls_pkcs11_obj_list_import_url( crt_list, &crt_list_size, url, 
flags);
+       if (ret < 0 && ret != GNUTLS_E_SHORT_MEMORY_BUFFER) {
+               fprintf(stderr, "Error in crt_list_import (1): %s\n", 
gnutls_strerror(ret));
+               exit(1);
+       }
+       
+       if (crt_list_size == 0) {
+               fprintf(stderr, "No matching objects found\n");
+               exit(0);
+       }
+       
+       if (ret == GNUTLS_E_SHORT_MEMORY_BUFFER) {
+               crt_list = realloc(crt_list, sizeof(*crt_list)*crt_list_size);
+               if (crt_list == NULL) {
+                       fprintf(stderr, "Memory error\n");
+                       exit(1);
+               }
+
+               ret = gnutls_pkcs11_obj_list_import_url( crt_list, 
&crt_list_size, url, flags);
+               if (ret < 0) {
+                       fprintf(stderr, "Error in crt_list_import: %s\n", 
gnutls_strerror(ret));
+                       exit(1);
+               }
+       }
+       
+       for (i=0;i<crt_list_size;i++) {
+               char buf[128];
+               size_t size;
+               
+               ret = gnutls_pkcs11_obj_export_url(crt_list[i], &output);
+               if (ret < 0) {
+                       fprintf(stderr, "Error in %s:%d: %s\n", __func__, 
__LINE__, gnutls_strerror(ret));
+                       exit(1);
+               }
+
+               fprintf(outfile, "Object %d:\n\tURL: %s\n", i, output);
+
+               fprintf(outfile, "\tType: %s\n", 
gnutls_pkcs11_type_get_name(gnutls_pkcs11_obj_get_type( crt_list[i])));
+               
+               size = sizeof(buf);
+               ret = gnutls_pkcs11_obj_get_info( crt_list[i], 
GNUTLS_PKCS11_OBJ_LABEL, buf, &size);
+               if (ret < 0) {
+                       fprintf(stderr, "Error in %s:%d: %s\n", __func__, 
__LINE__, gnutls_strerror(ret));
+                       exit(1);
+               }
+               fprintf(outfile, "\tLabel: %s\n", buf);
+
+               size = sizeof(buf);
+               ret = gnutls_pkcs11_obj_get_info( crt_list[i], 
GNUTLS_PKCS11_OBJ_ID_HEX, buf, &size);
+               if (ret < 0) {
+                       fprintf(stderr, "Error in %s:%d: %s\n", __func__, 
__LINE__, gnutls_strerror(ret));
+                       exit(1);
+               }
+               fprintf(outfile, "\tID: %s\n\n", buf);
+               
+               
+
+               if (flags == GNUTLS_PKCS11_OBJ_ATTR_ALL)
+                       continue;
+
+               ret = gnutls_x509_crt_init(&xcrt);
+               if (ret < 0) {
+                       fprintf(stderr, "Error in %s:%d: %s\n", __func__, 
__LINE__, gnutls_strerror(ret));
+                       exit(1);
+               }
+
+               ret = gnutls_x509_crt_import_pkcs11(xcrt, crt_list[i]);
+               if (ret < 0) {
+                       fprintf(stderr, "Error in %s:%d: %s\n", __func__, 
__LINE__, gnutls_strerror(ret));
+                       exit(1);
+               }
+
+#if 0
+               size = buffer_size;
+               ret = gnutls_x509_crt_export (xcrt, GNUTLS_X509_FMT_PEM, 
buffer, &size);
+               if (ret < 0) {
+                       fprintf(stderr, "Error in %s:%d: %s\n", __func__, 
__LINE__, gnutls_strerror(ret));
+                       exit(1);
+               }
+
+               fwrite (buffer, 1, size, outfile);
+               fputs("\n\n", outfile);
+#endif
+
+               gnutls_x509_crt_deinit(xcrt);
+
+
+       }
+       
+       return;
+}
+
+void pkcs11_export(FILE* outfile, const char* url)
+{
+gnutls_pkcs11_obj_t crt;
+gnutls_x509_crt_t xcrt;
+gnutls_pubkey_t pubkey;
+int ret;
+size_t size;
+
+       pkcs11_common();
+
+       if (url == NULL)
+               url = "pkcs11:";
+
+       ret = gnutls_pkcs11_obj_init(&crt);
+       if (ret < 0) {
+               fprintf(stderr, "Error in %s:%d: %s\n", __func__, __LINE__, 
gnutls_strerror(ret));
+               exit(1);
+       }
+
+       ret = gnutls_pkcs11_obj_import_url( crt, url);
+       if (ret < 0) {
+               fprintf(stderr, "Error in %s:%d: %s\n", __func__, __LINE__, 
gnutls_strerror(ret));
+               exit(1);
+       }
+
+       switch(gnutls_pkcs11_obj_get_type(crt)) {
+               case GNUTLS_PKCS11_OBJ_X509_CRT:
+                       ret = gnutls_x509_crt_init(&xcrt);
+                       if (ret < 0) {
+                               fprintf(stderr, "Error in %s:%d: %s\n", 
__func__, __LINE__, gnutls_strerror(ret));
+                               exit(1);
+                       }
+
+                       ret = gnutls_x509_crt_import_pkcs11(xcrt, crt);
+                       if (ret < 0) {
+                               fprintf(stderr, "Error in %s:%d: %s\n", 
__func__, __LINE__, gnutls_strerror(ret));
+                               exit(1);
+                       }
+
+                       size = buffer_size;
+                       ret = gnutls_x509_crt_export (xcrt, 
GNUTLS_X509_FMT_PEM, buffer, &size);
+                       if (ret < 0) {
+                               fprintf(stderr, "Error in %s:%d: %s\n", 
__func__, __LINE__, gnutls_strerror(ret));
+                               exit(1);
+                       }
+                       fwrite (buffer, 1, size, outfile);
+
+                       gnutls_x509_crt_deinit(xcrt);
+                       break;
+               case GNUTLS_PKCS11_OBJ_PUBKEY:
+                       ret = gnutls_pubkey_init(&pubkey);
+                       if (ret < 0) {
+                               fprintf(stderr, "Error in %s:%d: %s\n", 
__func__, __LINE__, gnutls_strerror(ret));
+                               exit(1);
+                       }
+
+                       ret = gnutls_pubkey_import_pkcs11(pubkey, crt, 0);
+                       if (ret < 0) {
+                               fprintf(stderr, "Error in %s:%d: %s\n", 
__func__, __LINE__, gnutls_strerror(ret));
+                               exit(1);
+                       }
+
+                       size = buffer_size;
+                       ret = gnutls_pubkey_export (pubkey, 
GNUTLS_X509_FMT_PEM, buffer, &size);
+                       if (ret < 0) {
+                               fprintf(stderr, "Error in %s:%d: %s\n", 
__func__, __LINE__, gnutls_strerror(ret));
+                               exit(1);
+                       }
+                       fwrite (buffer, 1, size, outfile);
+
+                       gnutls_pubkey_deinit(pubkey);
+                       break;
+               default: {
+                       gnutls_datum data, enc;
+
+                       size = buffer_size;
+                       ret = gnutls_pkcs11_obj_export (crt, buffer, &size);
+                       if (ret < 0) {
+                               break;
+                       }
+
+                       data.data = buffer;
+                       data.size = size;
+
+                       ret = gnutls_pem_base64_encode_alloc("DATA", &data, 
&enc);
+                       if (ret < 0) {
+                               fprintf(stderr, "Error in %s:%d: %s\n", 
__func__, __LINE__, gnutls_strerror(ret));
+                               exit(1);
+                       }
+
+                       fwrite (enc.data, 1, enc.size, outfile);
+
+                       gnutls_free(enc.data);
+                       break;
+               }
+       }
+       fputs("\n\n", outfile);
+
+
+       gnutls_pkcs11_obj_deinit(crt);
+
+       return;
+
+}
+
+void pkcs11_token_list(FILE* outfile)
+{
+int ret;
+int i;
+char *url;
+char buf[128];
+size_t size;
+
+       pkcs11_common();
+
+       for (i=0;;i++) {
+               ret = gnutls_pkcs11_token_get_url(i, &url);
+               if (ret == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE)
+                       break;
+
+               if (ret < 0) {
+                       fprintf(stderr, "Error in %s:%d: %s\n", __func__, 
__LINE__, gnutls_strerror(ret));
+                       exit(1);
+               }
+
+               fprintf(outfile, "Token %d:\n\tURL: %s\n", i, url);
+
+               size = sizeof(buf);
+               ret = gnutls_pkcs11_token_get_info(url, 
GNUTLS_PKCS11_TOKEN_LABEL, buf, &size);
+               if (ret < 0) {
+                       fprintf(stderr, "Error in %s:%d: %s\n", __func__, 
__LINE__, gnutls_strerror(ret));
+                       exit(1);
+               }
+
+               fprintf(outfile, "\tLabel: %s\n", buf);
+
+               size = sizeof(buf);
+               ret = gnutls_pkcs11_token_get_info(url, 
GNUTLS_PKCS11_TOKEN_MANUFACTURER, buf, &size);
+               if (ret < 0) {
+                       fprintf(stderr, "Error in %s:%d: %s\n", __func__, 
__LINE__, gnutls_strerror(ret));
+                       exit(1);
+               }
+
+               fprintf(outfile, "\tManufacturer: %s\n", buf);
+
+               size = sizeof(buf);
+               ret = gnutls_pkcs11_token_get_info(url, 
GNUTLS_PKCS11_TOKEN_MODEL, buf, &size);
+               if (ret < 0) {
+                       fprintf(stderr, "Error in %s:%d: %s\n", __func__, 
__LINE__, gnutls_strerror(ret));
+                       exit(1);
+               }
+
+               fprintf(outfile, "\tModel: %s\n", buf);
+
+               size = sizeof(buf);
+               ret = gnutls_pkcs11_token_get_info(url, 
GNUTLS_PKCS11_TOKEN_SERIAL, buf, &size);
+               if (ret < 0) {
+                       fprintf(stderr, "Error in %s:%d: %s\n", __func__, 
__LINE__, gnutls_strerror(ret));
+                       exit(1);
+               }
+
+               fprintf(outfile, "\tSerial: %s\n", buf);
+               fprintf(outfile, "\n\n");
+
+               gnutls_free(url);
+
+       }
+
+       return;
+}
+
+void pkcs11_write(FILE* outfile, const char* url, const char* label, int 
trusted)
+{
+gnutls_x509_crt_t xcrt;
+gnutls_x509_privkey_t xkey;
+int ret;
+unsigned int flags = 0;
+unsigned int key_usage;
+
+       pkcs11_common();
+
+       if (url == NULL)
+               url = "pkcs11:";
+
+       xcrt = load_cert(0);
+       if (xcrt != NULL) {
+               if (trusted)
+                       flags |= GNUTLS_PKCS11_OBJ_FLAG_TRUSTED;
+               ret = gnutls_pkcs11_copy_x509_crt(url, xcrt, label, flags);
+               if (ret < 0) {
+                       fprintf(stderr, "Error in %s:%d: %s\n", __func__, 
__LINE__, gnutls_strerror(ret));
+                       exit(1);
+               }
+
+               gnutls_x509_crt_get_key_usage(xcrt, &key_usage, NULL);
+       }
+
+       xkey = load_private_key(0);
+       if (xkey != NULL) {
+               ret = gnutls_pkcs11_copy_x509_privkey(url, xkey, label, 
key_usage);
+               if (ret < 0) {
+                       fprintf(stderr, "Error in %s:%d: %s\n", __func__, 
__LINE__, gnutls_strerror(ret));
+                       exit(1);
+               }
+       }
+
+       if (xkey == NULL && xcrt == NULL) {
+               fprintf(stderr, "You must use --load-privkey or 
--load-certificate to load the file to be copied\n");
+               exit (1);
+       }
+
+       return;
+}
diff --git a/src/prime.c b/src/prime.c
index 03356eb..2d2107d 100644
--- a/src/prime.c
+++ b/src/prime.c
@@ -28,6 +28,7 @@
 #include <stdlib.h>
 #include <unistd.h>
 #include <gnutls/gnutls.h>
+#include <certtool-common.h>
 
 /* Generates Diffie-Hellman parameters (a prime and a generator
  * of the group). Exports them in PKCS #3 format. Used by certtool.
@@ -35,22 +36,19 @@
 
 extern FILE *outfile;
 extern FILE *infile;
-extern unsigned char buffer[];
-extern const int buffer_size;
 
 static int cparams = 0;
 
-int generate_prime (int bits, int how);
-
 /* If how is zero then the included parameters are used.
  */
 int
-generate_prime (int bits, int how)
+generate_prime (int how)
 {
   unsigned int i;
   int ret;
   gnutls_dh_params_t dh_params;
   gnutls_datum_t p, g;
+  int bits = get_bits(GNUTLS_PK_DSA);
 
   gnutls_dh_params_init (&dh_params);
 
diff --git a/src/psk.c b/src/psk.c
index b963eb4..7e82979 100644
--- a/src/psk.c
+++ b/src/psk.c
@@ -152,7 +152,7 @@ main (int argc, char **argv)
 
       printf ("Generating a random key for user '%s'\n", info.username);
 
-      ret = _gnutls_rnd (GNUTLS_RND_RANDOM, (char *) key, info.key_size);
+      ret = gnutls_rnd (GNUTLS_RND_RANDOM, (char *) key, info.key_size);
       if (ret < 0)
        {
          fprintf (stderr, "Not enough randomness\n");
diff --git a/src/serv-gaa.c b/src/serv-gaa.c
index ab7472b..7e502aa 100644
--- a/src/serv-gaa.c
+++ b/src/serv-gaa.c
@@ -135,14 +135,14 @@ void gaa_help(void)
        __gaa_helpsingle(0, "echo", "", "Act as an Echo Server.");
        __gaa_helpsingle(0, "dhparams", "FILE ", "DH params file to use.");
        __gaa_helpsingle(0, "x509fmtder", "", "Use DER format for 
certificates");
-       __gaa_helpsingle(0, "x509cafile", "FILE ", "Certificate file to use.");
+       __gaa_helpsingle(0, "x509cafile", "FILE ", "Certificate file or PKCS 
#11 URL to use.");
        __gaa_helpsingle(0, "x509crlfile", "FILE ", "CRL file to use.");
        __gaa_helpsingle(0, "pgpkeyring", "FILE ", "PGP Key ring file to use.");
        __gaa_helpsingle(0, "pgpkeyfile", "FILE ", "PGP Key file to use.");
        __gaa_helpsingle(0, "pgpcertfile", "FILE ", "PGP Public Key 
(certificate) file to use.");
        __gaa_helpsingle(0, "pgpsubkey", "HEX|auto ", "PGP subkey to use.");
-       __gaa_helpsingle(0, "x509keyfile", "FILE ", "X.509 key file to use.");
-       __gaa_helpsingle(0, "x509certfile", "FILE ", "X.509 Certificate file to 
use.");
+       __gaa_helpsingle(0, "x509keyfile", "FILE ", "X.509 key file or PKCS #11 
URL to use.");
+       __gaa_helpsingle(0, "x509certfile", "FILE ", "X.509 Certificate file or 
PKCS #11 URL to use.");
        __gaa_helpsingle(0, "x509dsakeyfile", "FILE ", "Alternative X.509 key 
file to use.");
        __gaa_helpsingle(0, "x509dsacertfile", "FILE ", "Alternative X.509 
certificate file to use.");
        __gaa_helpsingle('r', "require-cert", "", "Require a valid 
certificate.");
diff --git a/src/serv.c b/src/serv.c
index 0e95fcf..a2457ea 100644
--- a/src/serv.c
+++ b/src/serv.c
@@ -34,7 +34,6 @@
 #include <sys/types.h>
 #include <string.h>
 #include <gnutls/gnutls.h>
-#include <gcrypt.h>
 #include <gnutls/extra.h>
 #include <gnutls/openpgp.h>
 #include <sys/time.h>
@@ -865,19 +864,6 @@ main (int argc, char **argv)
 
   set_program_name (argv[0]);
 
-#ifdef gcry_fips_mode_active
-  /* Libgcrypt manual says that gcry_version_check must be called
-     before calling gcry_fips_mode_active. */
-  gcry_check_version (NULL);
-  if (gcry_fips_mode_active ())
-    {
-      ret = gnutls_register_md5_handler ();
-      if (ret)
-       fprintf (stderr, "gnutls_register_md5_handler: %s\n",
-                gnutls_strerror (ret));
-    }
-#endif
-
 #ifndef _WIN32
   signal (SIGPIPE, SIG_IGN);
   signal (SIGHUP, SIG_IGN);
@@ -902,8 +888,6 @@ main (int argc, char **argv)
       strcpy (name, "Echo Server");
     }
 
-  gcry_control (GCRYCTL_ENABLE_QUICK_RANDOM, 0);
-
   if ((ret = gnutls_global_init ()) < 0)
     {
       fprintf (stderr, "global_init: %s\n", gnutls_strerror (ret));
@@ -916,6 +900,7 @@ main (int argc, char **argv)
       exit (1);
     }
 
+  pkcs11_common();
   gnutls_global_set_log_function (tls_log_func);
   gnutls_global_set_log_level (debug);
 
diff --git a/src/serv.gaa b/src/serv.gaa
index f4607f0..37130cc 100644
--- a/src/serv.gaa
+++ b/src/serv.gaa
@@ -38,7 +38,7 @@ option (dhparams) STR "FILE" { $dh_params_file = $1 } "DH 
params file to use."
 option (x509fmtder) { $fmtder = 1 } "Use DER format for certificates"
 
 #char *x509_cafile;
-option (x509cafile) STR "FILE" { $x509_cafile = $1 } "Certificate file to use."
+option (x509cafile) STR "FILE" { $x509_cafile = $1 } "Certificate file or PKCS 
#11 URL to use."
 
 #char *x509_crlfile;
 option (x509crlfile) STR "FILE" { $x509_crlfile = $1 } "CRL file to use."
@@ -56,10 +56,10 @@ option (pgpcertfile) STR "FILE" { $pgp_certfile = $1 } "PGP 
Public Key (certific
 option (pgpsubkey) STR "HEX|auto" { $pgp_subkey = $1 } "PGP subkey to use."
 
 #char *x509_keyfile;
-option (x509keyfile) STR "FILE" { $x509_keyfile = $1 } "X.509 key file to use."
+option (x509keyfile) STR "FILE" { $x509_keyfile = $1 } "X.509 key file or PKCS 
#11 URL to use."
 
 #char *x509_certfile;
-option (x509certfile) STR "FILE" { $x509_certfile = $1 } "X.509 Certificate 
file to use."
+option (x509certfile) STR "FILE" { $x509_certfile = $1 } "X.509 Certificate 
file or PKCS #11 URL to use."
 
 #char *x509_dsakeyfile;
 option (x509dsakeyfile) STR "FILE" { $x509_dsakeyfile = $1 } "Alternative 
X.509 key file to use."
diff --git a/src/tests.c b/src/tests.c
index f9d10f5..2382d8b 100644
--- a/src/tests.c
+++ b/src/tests.c
@@ -975,7 +975,7 @@ static int
 cert_callback (gnutls_session_t session,
               const gnutls_datum_t * req_ca_rdn, int nreqs,
               const gnutls_pk_algorithm_t * sign_algos,
-              int sign_algos_length, gnutls_retr_st * st)
+              int sign_algos_length, gnutls_retr2_st * st)
 {
   char issuer_dn[256];
   int i, ret;
@@ -1025,10 +1025,10 @@ test_server_cas (gnutls_session_t session)
   _gnutls_priority_set_direct (session, prio_str);
 
   gnutls_credentials_set (session, GNUTLS_CRD_CERTIFICATE, xcred);
-  gnutls_certificate_client_set_retrieve_function (xcred, cert_callback);
+  gnutls_certificate_set_retrieve_function (xcred, cert_callback);
 
   ret = do_handshake (session);
-  gnutls_certificate_client_set_retrieve_function (xcred, NULL);
+  gnutls_certificate_set_retrieve_function (xcred, NULL);
 
   if (ret == TEST_FAILED)
     return ret;
diff --git a/tests/Makefile.am b/tests/Makefile.am
index f7fc65e..165370a 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -73,7 +73,7 @@ openpgp_keyring_LDADD = $(LDADD) 
../libextra/libgnutls-extra.la
 endif
 
 if HAVE_FORK
-ctests += x509self x509signself x509dn anonself pskself dhepskself     \
+ctests += x509self x509dn anonself pskself dhepskself  \
        tlsia resume netconf-psk setcredcrash
 
 if ENABLE_OPENPGP
diff --git a/tests/chainverify.c b/tests/chainverify.c
index 5aa4b88..1ddc209 100644
--- a/tests/chainverify.c
+++ b/tests/chainverify.c
@@ -848,7 +848,7 @@ doit (void)
 
       if (verify_status != chains[i].expected_verify_result)
        {
-         fail ("verify_status: %d expected: %d",
+         fail ("verify_status: %d expected: %d\n",
                verify_status, chains[i].expected_verify_result);
 
          if (debug)
diff --git a/tests/crq_key_id.c b/tests/crq_key_id.c
index dc6b579..dd2be8a 100644
--- a/tests/crq_key_id.c
+++ b/tests/crq_key_id.c
@@ -59,8 +59,6 @@ doit (void)
   if (ret < 0)
     fail ("gnutls_global_init: %d\n", ret);
 
-  gcry_control (GCRYCTL_ENABLE_QUICK_RANDOM, 0);
-
   gnutls_global_set_log_function (tls_log_func);
   if (debug)
     gnutls_global_set_log_level (4711);
diff --git a/tests/cve-2009-1416.c b/tests/cve-2009-1416.c
index a89db59..1e91116 100644
--- a/tests/cve-2009-1416.c
+++ b/tests/cve-2009-1416.c
@@ -53,7 +53,6 @@ main (void)
   int ret;
 
   gnutls_global_init ();
-  gcry_control (GCRYCTL_ENABLE_QUICK_RANDOM, 0);
 
   ret = gnutls_x509_privkey_init (&key);
   if (ret < 0)
diff --git a/tests/dn2.c b/tests/dn2.c
index 1872794..42627d3 100644
--- a/tests/dn2.c
+++ b/tests/dn2.c
@@ -64,7 +64,7 @@ static char pem[] =
   "/do1TDFI0vSl5+M=\n" "-----END CERTIFICATE-----\n";
 
 static const char *info =
-  "subject 
`1.3.6.1.4.1.311.60.2.1.3=#13024445,1.3.6.1.4.1.311.60.2.1.1=#14084d75656e6368656e,2.5.4.15=#131256312e302c20436c6175736520352e286229,serialNumber=HRB
 144261,C=DE,postalCode=80807,ST=Bavaria,L=Muenchen,STREET=Frankfurter Ring 
129,O=GMX GmbH,CN=www.gmx.de', issuer `C=US,O=VeriSign\\, Inc.,OU=VeriSign 
Trust Network,OU=Terms of use at https://www.verisign.com/rpa (c)06,CN=VeriSign 
Class 3 Extended Validation SSL SGC CA', RSA key 1024 bits, signed using 
RSA-SHA1, activated `2008-11-13 00:00:00 UTC', expires `2009-11-13 23:59:59 
UTC', SHA-1 fingerprint `7ece297c45d5b17685224b4e929a30e91a9553cb'";
+  "subject 
`jurisdictionOfIncorporationCountryName=DE,jurisdictionOfIncorporationLocalityName=Muenchen,businessCategory=V1.0\\,
 Clause 5.(b),serialNumber=HRB 
144261,C=DE,postalCode=80807,ST=Bavaria,L=Muenchen,STREET=Frankfurter Ring 
129,O=GMX GmbH,CN=www.gmx.de', issuer `C=US,O=VeriSign\\, Inc.,OU=VeriSign 
Trust Network,OU=Terms of use at https://www.verisign.com/rpa (c)06,CN=VeriSign 
Class 3 Extended Validation SSL SGC CA', RSA key 1024 bits, signed using 
RSA-SHA1, activated `2008-11-13 00:00:00 UTC', expires `2009-11-13 23:59:59 
UTC', SHA-1 fingerprint `7ece297c45d5b17685224b4e929a30e91a9553cb'";
 
 void
 doit (void)
diff --git a/tests/mini-eagain.c b/tests/mini-eagain.c
index d957574..0b2cdf6 100644
--- a/tests/mini-eagain.c
+++ b/tests/mini-eagain.c
@@ -29,8 +29,7 @@
 #include <string.h>
 #include <errno.h>
 #include <gnutls/gnutls.h>
-
-#include <gcrypt.h>
+#include <gnutls/crypto.h>
 
 #include "utils.h"
 
@@ -54,7 +53,7 @@ client_pull (gnutls_transport_ptr_t tr, void *data, size_t 
len)
 {
 //  success ("client_pull len %d has %d\n", len, to_client_len);
   unsigned char rnd;
-  gcry_create_nonce (&rnd, 1);
+  gnutls_rnd(GNUTLS_RND_NONCE, &rnd, 1);
 
   if (handshake == 0 && rnd % 2 == 0)
     {
@@ -104,7 +103,7 @@ server_pull (gnutls_transport_ptr_t tr, void *data, size_t 
len)
   //success ("server_pull len %d has %d\n", len, to_server_len);
   unsigned char rnd;
 
-  gcry_create_nonce (&rnd, 1);
+  gnutls_rnd (GNUTLS_RND_NONCE, &rnd, 1);
   if (handshake == 0 && rnd % 2 == 0)
     {
       gnutls_transport_set_global_errno (EAGAIN);
@@ -133,7 +132,7 @@ server_push (gnutls_transport_ptr_t tr, const void *data, 
size_t len)
   size_t newlen = to_client_len + len;
 
   //success ("server_push len %d has %d\n", len, to_client_len);
-  gcry_create_nonce (&rnd, 1);
+  gnutls_rnd (GNUTLS_RND_NONCE, &rnd, 1);
   if (handshake == 0 && rnd % 2 == 0)
     {
       gnutls_transport_set_global_errno (EAGAIN);
diff --git a/tests/openpgpself.c b/tests/openpgpself.c
index 1b39366..2e9e543 100644
--- a/tests/openpgpself.c
+++ b/tests/openpgpself.c
@@ -395,7 +395,7 @@ server (void)
 
   gnutls_global_set_log_function (tls_log_func);
   if (debug)
-    gnutls_global_set_log_level (4711);
+    gnutls_global_set_log_level (2);
 
   gnutls_certificate_allocate_credentials (&pgp_cred);
 
diff --git a/tests/pathlen/ca-no-pathlen.pem b/tests/pathlen/ca-no-pathlen.pem
index 2243f2f..848f5e9 100644
--- a/tests/pathlen/ca-no-pathlen.pem
+++ b/tests/pathlen/ca-no-pathlen.pem
@@ -7,6 +7,7 @@ X.509 Certificate Information:
                Not After: Sat Jan 27 10:00:06 UTC 2007
        Subject: O=GnuTLS test certificate
        Subject Public Key Algorithm: RSA
+       Certificate Security Level: Weak
                Modulus (bits 512):
                        a1:63:53:6b:54:95:ac:3c:a4:4b:4b:6a:ba:c0:9c:11
                        ad:28:dd:03:a8:c0:f4:17:bf:18:cd:9f:b3:5a:d1:de
diff --git a/tests/pathlen/no-ca-or-pathlen.pem 
b/tests/pathlen/no-ca-or-pathlen.pem
index 4db9694..08c9306 100644
--- a/tests/pathlen/no-ca-or-pathlen.pem
+++ b/tests/pathlen/no-ca-or-pathlen.pem
@@ -7,6 +7,7 @@ X.509 Certificate Information:
                Not After: Fri Aug 25 23:59:59 UTC 2000
        Subject: O=VeriSign\, Inc.,OU=VeriSign Trust 
Network,OU=www.verisign.com/repository/RPA Incorp. by 
Ref.\,LIAB.LTD(c)98,OU=Persona Not Validated,OU=Digital ID Class 1 - 
Netscape,CN=Simon Josefsson,address@hidden
        Subject Public Key Algorithm: RSA
+       Certificate Security Level: Low
                Modulus (bits 1024):
                        c9:0c:ce:8a:fe:71:46:9b:ca:1d:e5:90:12:a5:11:0b
                        c6:2d:c4:33:c6:19:e8:60:59:4e:3f:64:3d:e4:f7:7b
diff --git a/tests/pkcs1-padding/pkcs1-pad b/tests/pkcs1-padding/pkcs1-pad
index 63b7e68..d9bff4e 100755
--- a/tests/pkcs1-padding/pkcs1-pad
+++ b/tests/pkcs1-padding/pkcs1-pad
@@ -35,48 +35,46 @@ fi
 
 EXPECT1=3102
 
-datefudge "2006-09-23" $CERTTOOL --verify-chain --infile 
$srcdir/pkcs1-pad-ok.pem | tee out1
-datefudge "2006-09-23" $CERTTOOL --verify-chain --infile 
$srcdir/pkcs1-pad-broken.pem | tee out2
+datefudge "2006-09-23" $CERTTOOL --verify-chain --infile 
$srcdir/pkcs1-pad-ok.pem | tee out1 >/dev/null 2>&1
+datefudge "2006-09-23" $CERTTOOL --verify-chain --infile 
$srcdir/pkcs1-pad-broken.pem | tee out2 >/dev/null 2>&1
 
 out1oks=`grep 'Verified.' out1 | wc -l | tr -d " "`
 out2oks=`grep 'Verified.' out2 | wc -l | tr -d " "`
 out1fails=`grep 'Not verified.' out1 | wc -l | tr -d " "`
 out2fails=`grep 'Not verified.' out2 | wc -l | tr -d " "`
 
-rm -f out1 out2
-
-echo out1 oks $out1oks fails $out1fails out2 oks $out2oks fails $out2fails
-
 if test "$out1oks$out2oks$out1fails$out2fails" != "$EXPECT1"; then
+    echo out1 oks $out1oks fails $out1fails out2 oks $out2oks fails $out2fails
     echo expected $EXPECT1
     echo "PKCS1-PAD1 FAIL"
     exit 1
 fi
 
+rm -f out1 out2
+
 echo "PKCS1-PAD1 OK"
 
 # Test 2, Bleichenbacher's Crypto 06 rump session
 
 EXPECT2=2002
 
-datefudge "2006-09-23" $CERTTOOL --verify-chain --infile 
$srcdir/pkcs1-pad-ok2.pem | tee out1
-datefudge "2006-09-23" $CERTTOOL --verify-chain --infile 
$srcdir/pkcs1-pad-broken2.pem | tee out2
+datefudge "2006-09-23" $CERTTOOL --verify-chain --infile 
$srcdir/pkcs1-pad-ok2.pem | tee out1 >/dev/null 2>&1
+datefudge "2006-09-23" $CERTTOOL --verify-chain --infile 
$srcdir/pkcs1-pad-broken2.pem | tee out2 >/dev/null 2>&1
 
 out1oks=`grep 'Verified.' out1 | wc -l | tr -d " "`
 out2oks=`grep 'Verified.' out2 | wc -l | tr -d " "`
 out1fails=`grep 'Not verified.' out1 | wc -l | tr -d " "`
 out2fails=`grep 'Not verified.' out2 | wc -l | tr -d " "`
 
-rm -f out1 out2
-
-echo out1 oks $out1oks fails $out1fails out2 oks $out2oks fails $out2fails
-
 if test "$out1oks$out2oks$out1fails$out2fails" != "$EXPECT2"; then
+    echo out1 oks $out1oks fails $out1fails out2 oks $out2oks fails $out2fails
     echo expected $EXPECT2
     echo "PKCS1-PAD2 FAIL"
     exit 1
 fi
 
+rm -f out1 out2
+
 echo "PKCS1-PAD2 OK"
 
 # Test 3, forged Starfield certificate,
@@ -85,21 +83,20 @@ echo "PKCS1-PAD2 OK"
 
 EXPECT3=12
 
-datefudge "2006-09-23" $CERTTOOL --verify-chain --infile 
$srcdir/pkcs1-pad-broken3.pem | tee out1
+datefudge "2006-09-23" $CERTTOOL --verify-chain --infile 
$srcdir/pkcs1-pad-broken3.pem | tee out1 >/dev/null 2>&1
 
 out1oks=`grep 'Verified.' out1 | wc -l | tr -d " "`
 out1fails=`grep 'Not verified.' out1 | wc -l | tr -d " "`
 
-rm -f out1
-
-echo out1 oks $out1oks fails $out1fails
-
 if test "$out1oks$out1fails" != "$EXPECT3"; then
+    echo out1 oks $out1oks fails $out1fails
     echo expected $EXPECT3
     echo "PKCS1-PAD3 FAIL"
     exit 1
 fi
 
+rm -f out1
+
 echo "PKCS1-PAD3 OK"
 
 # We're done.
diff --git a/tests/pkcs12-decode/pkcs12 b/tests/pkcs12-decode/pkcs12
index 8f5ab60..4eff8b3 100755
--- a/tests/pkcs12-decode/pkcs12
+++ b/tests/pkcs12-decode/pkcs12
@@ -30,9 +30,10 @@ for p12 in 'client.p12 foobar' noclient.p12 unclient.p12 
pkcs12_2certs.p12; do
     file=$1
     passwd=$2
     $CERTTOOL --p12-info --inder --password "$passwd" \
-               --infile $srcdir/$file | tee out
+               --infile $srcdir/$file > out 2>&1
     rc=$?
     if test $rc != 0; then
+       cat out
        echo "NEON PKCS12 FATAL $p12"
        ret=1
     else
diff --git a/tests/pkcs12_encode.c b/tests/pkcs12_encode.c
index 38db70d..42ff96d 100644
--- a/tests/pkcs12_encode.c
+++ b/tests/pkcs12_encode.c
@@ -65,6 +65,12 @@ static char ca_pem[] =
   "PfqUpIhz5Bbm7J4=\n" "-----END CERTIFICATE-----\n";
 const gnutls_datum_t ca_dat = { ca_pem, sizeof (ca_pem) };
 
+static void
+tls_log_func (int level, const char *str)
+{
+  fprintf (stderr, "|<%d>| %s", level, str);
+}
+
 void
 doit (void)
 {
@@ -83,6 +89,11 @@ doit (void)
   if (ret < 0)
     error (EXIT_FAILURE, 0, "gnutls_global_init %d", ret);
 
+  gnutls_global_init ();
+  gnutls_global_set_log_function (tls_log_func);
+  if (debug)
+    gnutls_global_set_log_level (4711);
+
   /* Read certs. */
   ret = gnutls_x509_crt_init (&client);
   if (ret < 0)
@@ -140,7 +151,7 @@ doit (void)
                                       i == 0 ? GNUTLS_PKCS8_USE_PKCS12_3DES
                                       : GNUTLS_PKCS_USE_PKCS12_RC2_40);
       if (ret < 0)
-       error (EXIT_FAILURE, 0, "bag_encrypt: %d", ret);
+       error (EXIT_FAILURE, 0, "bag_encrypt: %d: %s", ret, 
i==0?"3DES":"RC2-40");
 
       ret = gnutls_pkcs12_set_bag (pkcs12, bag);
       if (ret < 0)
diff --git a/tests/pkcs12_s2k.c b/tests/pkcs12_s2k.c
index 81ce328..671a44b 100644
--- a/tests/pkcs12_s2k.c
+++ b/tests/pkcs12_s2k.c
@@ -133,12 +133,12 @@ doit (void)
            fail ("_gnutls_pkcs12_string_to_key failed[0]: %d\n", rc);
 
          if (strcmp (_gnutls_bin2hex (key, sizeof (key),
-                                      tmp, sizeof (tmp)), values[x]) != 0)
+                                      tmp, sizeof (tmp), NULL), values[x]) != 
0)
            fail ("_gnutls_pkcs12_string_to_key failed[1]\n");
 
          if (debug)
            printf ("ij: %d.%d: %s\n", i, j,
-                   _gnutls_bin2hex (key, sizeof (key), tmp, sizeof (tmp)));
+                   _gnutls_bin2hex (key, sizeof (key), tmp, sizeof (tmp), 
NULL));
          x++;
        }
     }
@@ -154,13 +154,13 @@ doit (void)
        fail ("_gnutls_pkcs12_string_to_key failed[2]: %d\n", rc);
 
       if (memcmp (_gnutls_bin2hex (key, tv[i].keylen,
-                                  tmp, sizeof (tmp)),
+                                  tmp, sizeof (tmp), NULL),
                  tv[i].key, tv[i].keylen) != 0)
        fail ("_gnutls_pkcs12_string_to_key failed[3]\n");
 
       if (debug)
        printf ("tv[%d]: %s\n", i,
-               _gnutls_bin2hex (key, tv[i].keylen, tmp, sizeof (tmp)));
+               _gnutls_bin2hex (key, tv[i].keylen, tmp, sizeof (tmp), NULL));
     }
   if (debug)
     printf ("\n");
diff --git a/tests/pkcs12_s2k_pem.c b/tests/pkcs12_s2k_pem.c
index 07abe6c..165dbbd 100644
--- a/tests/pkcs12_s2k_pem.c
+++ b/tests/pkcs12_s2k_pem.c
@@ -266,7 +266,6 @@ main (void)
   int ret;
 
   gnutls_global_init ();
-  gcry_control (GCRYCTL_ENABLE_QUICK_RANDOM, 0);
 
   for (i = 0; i < sizeof (keys) / sizeof (keys[0]); i++)
     {
diff --git a/tests/pkcs8-decode/pkcs8 b/tests/pkcs8-decode/pkcs8
index 442de2f..3c630a0 100755
--- a/tests/pkcs8-decode/pkcs8
+++ b/tests/pkcs8-decode/pkcs8
@@ -29,9 +29,10 @@ for p8 in 'encpkcs8.pem foobar' unencpkcs8.pem 
'enc2pkcs8.pem baz'; do
     file=$1
     passwd=$2
     $CERTTOOL --key-info --pkcs8 --password "$passwd" \
-               --infile $srcdir/$file | tee out
+               --infile $srcdir/$file | tee out >/dev/null 2>&1
     rc=$?
     if test $rc != 0; then
+       cat out
        echo "PKCS8 FATAL $p8"
        ret=1
     else
diff --git a/tests/sha2/Makefile.am b/tests/sha2/Makefile.am
index 983f554..7cf9bde 100644
--- a/tests/sha2/Makefile.am
+++ b/tests/sha2/Makefile.am
@@ -19,10 +19,11 @@
 # along with this file; if not, write to the Free Software Foundation,
 # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 
-EXTRA_DIST = key-ca.pem key-subca.pem key-subsubca.pem key-user.pem
+EXTRA_DIST = key-ca.pem key-subca.pem key-subsubca.pem key-user.pem 
key-dsa.pem \
+       key-ca-dsa.pem
 
-dist_check_SCRIPTS = sha2
+dist_check_SCRIPTS = sha2 sha2-dsa
 
-TESTS = sha2
+TESTS = sha2 sha2-dsa
 
 TESTS_ENVIRONMENT = EXEEXT=$(EXEEXT)
diff --git a/tests/sha2/key-ca-dsa.pem b/tests/sha2/key-ca-dsa.pem
new file mode 100644
index 0000000..991f6ad
--- /dev/null
+++ b/tests/sha2/key-ca-dsa.pem
@@ -0,0 +1,28 @@
+-----BEGIN DSA PRIVATE KEY-----
+MIIEvgIBAAKCAYEAx25OA2wqGmV3ygRR94me1sFVCiYVyADh9PHdcBO4vE1htok3
+SShUlv8y8BR9qaY531tneBhsRwTbl1QTvCi/UiFasB8RnfJH36DNA6+cAU2tiy6W
+lPTeIFcYAR79Ss7fqEGlgrEv8U1nGI5DJrWe15t0Bh4y9EQXPvddWvKf1K/6tzgC
+SR3dFg3/c8dIzN/QFIR92CE+QW2ScNvzZ1hFqPFHV0521dpGJhNAFg2QOdDqchNN
+pVkV1z7oYix67zu9MSZ23/P0eooa8lCQH9NBGnw7eR79SoFuOIQAhv0I0aDHafs/
+MjNdGRfIyWeoK7wcAL5NwAWcPZRMY8m20gbIyxio+x5tr8MbLGcPHbdfB4kWBxSx
+zTY728MiuryT/Jg3pnzzzkLZ1dZIDNn5LEDfjSBFjNTWo5tTzQ0gtdb9Q6idPWZC
+SVvu9DMtbGr8GkpQq2kbOK2F757jZ1jbIPHj5sYIAsVledmDogUzfq7i95HTsTDn
+6uUsV2zw2TdCCHfZAhUA26q615JtGdKJYOcjOZjJqF7VMo8CggGAGCgoo2zrWhCt
+vXhexkMjr70u6oontJph0c6moEgq7KE/aa9HldcUlvKRRhzq+ggtkKEp16R2UbBa
+nvRLAfCW8wvZQSqc984riGX5JhKeOyjLNEYQtcNtY26Y1Ext9UKJxZNZXFc2Noff
+WfL15F9wd1VY/3mG8FcoironPfUw9AueYZn9sJSXHpeaP1kUsqBu7dhVEV+RwWkf
+Bb05oMTqA0ePWKXVdztdM0WnyXCsVs/bWGjiWlhMlqardudmi8/oxLfcJfbC6lJr
+E6XZpjTV5557zcyheXVNXB+RvQNak1/P0LZwFuis3Yqpie96iJrmfDsELZhnjRWe
+GJTSCzOy8g9guU2ELba3zcxNN7Yqevxguaa9IFYvWpqKKPTRSvOgHeYO65QXg7ou
+YKAbj+RwKkLjw2HWZlnuU/Fs2OFk4cAPsgJB2IaGjmmFfLnMI9xwIoX9FcJQl5Ur
+aNd4nDJpsFR6MTmbk/QHmtwniFcjGTHvbDT7jf6070wj1mzPHkyMAoIBgQC6nPN5
+N/sl+1JxFbKS92bPLwXW0YVIKcxqFAGhtA7cS9CksfWrZDO+Cjt/10yLL3ybR5RQ
+ZYD8exgHijCq9jEQQ2TkJl7mGZpD1sHNfrU0y4teOuXvvrtAnkLZLhPhV0nEskyc
+b6huAqJ0SpwzipdjQ0Xmh9roTSbwZ67e0RmrM6IBvd4ffOnunu2w3vaj7Ey7RV1k
+G3q5kQ1Fe6/ORXOxI3NKaeN/f+wdwzvXpQfsATdUvPnll1VP+UGvUIFmS5fvz7V/
+n4JLUTSp8NAJWyxSlvgNiQAfyC5VxzGi6nLg4zmR7/b1TlpQzm/L8T0OWz0Z8Sn6
+kRb/GHi/MvlrgjdArvMQz/i3Tt9H+gn7tGmQA/2cHujKtucMUDESv1XifyM5+AXP
+efQUKCzwci/Q/Yas5qTBtmdjvs1RSP/mj3fU3GKSJYtPM3B2QxFVutpOGSTxGpan
+yqnPPpiGngJ4w9oFU7R3PKgcCep+++vkDJIDi3SjumXd8zPYdvjDWYDYYhoCFDXP
+tGP+raIwP/zw2l2fhcvRjVHi
+-----END DSA PRIVATE KEY-----
diff --git a/tests/sha2/key-dsa.pem b/tests/sha2/key-dsa.pem
new file mode 100644
index 0000000..dcb30ea
--- /dev/null
+++ b/tests/sha2/key-dsa.pem
@@ -0,0 +1,20 @@
+-----BEGIN DSA PRIVATE KEY-----
+MIIDPQIBAAKCAQEAid7TwoSUalI4pnqpO0zaVF+xZY0jigJeR5ZkaytzNNzhHQVz
+ssSvu9cYt59IY5n1KJ0u6EqGpxNjis9O5/EOFn+obhgbeUQlQ8KLLCTMEEy9FWIb
+Ww7NuGvjt3SbpotqbLX5e2Qd3ygISP8AIdTeR0+D8XjuxJyeRRemo1g7hOVVoyOk
+EA6t7xypsYosBj18iq4ZETTHZc14NIJpLLasINgzdhoHIfWcXj0aUu5cd/Hube2d
+z+6EdIL3SayEhsYiUaRN7i/DNQmDrNYiWXrCYjP+YWVxZ1RAOK/35hD/b2B15/uR
+naDljvdOScUB5k7ebfUpGtRBbysh9BSudPh55QIVAOSh70VzAvVEPY/Mc+gShMy1
+PiNBAoIBABI72+KLTlLnmKJJmr6aMKqC6bmjF0Tetm2vqgsQXchuqZrIsqY0b41m
+l16DuoT22BhmmW1sK5oB44049iiVVoDrB6eU0aSMuuXb5Fj6f3suDAuLEqch+F75
+7IvH5AnzLFQpSo7/hWzeB8Y6tjqMp8JtWLmgfBg0ZG9WXfmTCLFYcYO2jEBdeuVC
+ANCer22nvWV50fRtMppZ/JVDtkewxqwTpY5QZ/s20z4vJ++fkUUxJLLvfvzpWV1+
+W/sDpEJU24DRPgFF2cOCFOLcjysJeH5dkflapM1MDdVCrrwN/SEI7IInjA0tmWBq
+CcUTxAi26ik7udH/EunQHIgTwB5uEvYCggEAeB9voN2lfVTNvGLxNeX9pOOXTPW6
+kJX62TAL1v0LlfoM3GCRjBNfm1i+iTTMzfqUZMRcL+xtxudoOJZxTgpx2ckwIoOE
+pCzY2C6wW24hMNnoHADGFu+ufby+2ufcILLuoeSBb0shkThl1u/CQKGpG5ds4aIH
++8p8qM5jpIZM2mQEa6rYRLnjJJspAFHg3ERDoOeJIGU9GRskoauMyacXGHv4rvGt
+yYXYuBpKKy69WWD17F8Y/mjDX0qxSj4rNnneBxvwCQ3Bz8lsDIA5Q6NyphhcT70A
+lOhAf/n9Mm2xAmuFSY4W9HI23YB/n4zTBqhXfRhmNMP4q3l0ZoWm4OsLOgIUZQeD
+EyFUllnkdimZ5ulEfOvi5/I=
+-----END DSA PRIVATE KEY-----
diff --git a/tests/sha2/sha2 b/tests/sha2/sha2
index 8c4b96d..80b4bc1 100755
--- a/tests/sha2/sha2
+++ b/tests/sha2/sha2
@@ -20,7 +20,7 @@
 # along with GnuTLS; if not, write to the Free Software Foundation,
 # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 
-set -e
+#set -e
 
 srcdir=${srcdir:-.}
 CERTTOOL=${CERTTOOL:-../../src/certtool$EXEEXT}
@@ -28,40 +28,59 @@ CERTTOOL=${CERTTOOL:-../../src/certtool$EXEEXT}
 echo ca > template
 echo cn = "SHA 512 CA" >> template
 
-$CERTTOOL --generate-self-signed --template template \
+$CERTTOOL -d 2 --generate-self-signed --template template \
     --load-privkey $srcdir/key-ca.pem \
     --outfile new-ca.pem \
-    --hash sha512 >/dev/null 2>&1
+    --hash sha512 >out 2>&1
+
+if [ $? != 0 ];then
+       cat out
+       exit 1
+fi
 
 echo ca > template
 echo cn = "SHA 384 sub-CA" >> template
 
-$CERTTOOL --generate-certificate --template template \
+$CERTTOOL -d 2 --generate-certificate --template template \
     --load-ca-privkey $srcdir/key-ca.pem \
     --load-ca-certificate new-ca.pem \
     --load-privkey $srcdir/key-subca.pem \
     --outfile new-subca.pem \
-    --hash sha384 >/dev/null 2>&1
+    --hash sha384 >out 2>&1
+
+if [ $? != 0 ];then
+       cat out
+       exit 1
+fi
 
 echo ca > template
 echo cn = "SHA 256 sub-sub-CA" >> template
 
-$CERTTOOL --generate-certificate --template template \
+$CERTTOOL -d 2 --generate-certificate --template template \
     --load-ca-privkey $srcdir/key-subca.pem \
     --load-ca-certificate new-subca.pem \
     --load-privkey $srcdir/key-subsubca.pem \
     --outfile new-subsubca.pem \
-    --hash sha256 >/dev/null 2>&1
+    --hash sha256 >out 2>&1
+
+if [ $? != 0 ];then
+       cat out
+       exit 1
+fi
 
 echo ca > template
 echo cn = "End-user" >> template
 
-$CERTTOOL --generate-certificate --template template \
+$CERTTOOL -d 2 --generate-certificate --template template \
     --load-ca-privkey $srcdir/key-subsubca.pem \
     --load-ca-certificate new-subsubca.pem \
     --load-privkey $srcdir/key-user.pem \
-    --outfile new-user.pem >/dev/null 2>&1
+    --outfile new-user.pem >out 2>&1
 
+if [ $? != 0 ];then
+       cat out
+       exit 1
+fi
 
 num=`cat new-user.pem new-subsubca.pem new-subca.pem new-ca.pem | $CERTTOOL 
--verify-chain | tee verify | grep -c Verified`
 #cat verify
diff --git a/tests/sha2/sha2-dsa b/tests/sha2/sha2-dsa
new file mode 100755
index 0000000..c778ff3
--- /dev/null
+++ b/tests/sha2/sha2-dsa
@@ -0,0 +1,65 @@
+#!/bin/sh
+
+# Copyright (C) 2006, 2007, 2008, 2010 Free Software Foundation, Inc.
+#
+# Author: Simon Josefsson
+#
+# This file is part of GnuTLS.
+#
+# GnuTLS is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; either version 3 of the License, or (at
+# your option) any later version.
+#
+# GnuTLS is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GnuTLS; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+#set -e
+
+srcdir=${srcdir:-.}
+CERTTOOL=${CERTTOOL:-../../src/certtool$EXEEXT}
+
+echo ca > template
+echo cn = "SHA 256 CA" >> template
+
+$CERTTOOL -d 2 --generate-self-signed --template template \
+    --load-privkey $srcdir/key-ca-dsa.pem \
+    --outfile new-ca-dsa.pem \
+    --hash sha256 >out 2>&1
+
+if [ $? != 0 ];then
+       cat out
+       exit 1
+fi
+
+echo ca > template
+echo cn = "End-user" >> template
+
+$CERTTOOL -d 2 --generate-certificate --template template \
+    --load-ca-privkey $srcdir/key-ca-dsa.pem \
+    --load-ca-certificate new-ca-dsa.pem \
+    --load-privkey $srcdir/key-dsa.pem \
+    --outfile new-user.pem >out 2>&1
+
+if [ $? != 0 ];then
+       cat out
+       exit 1
+fi
+
+cat new-user.pem new-ca-dsa.pem > out
+$CERTTOOL --verify-chain <out > verify
+
+if [ $? != 0 ];then
+       cat verify
+       exit 1
+fi
+
+rm -f verify new-user.pem new-dsa-ca.pem template
+
+exit 0
diff --git a/tests/userid/userid b/tests/userid/userid
index ca41267..52c906f 100755
--- a/tests/userid/userid
+++ b/tests/userid/userid
@@ -20,9 +20,15 @@
 # along with GnuTLS; if not, write to the Free Software Foundation,
 # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 
-set -e
-
 srcdir=${srcdir:-.}
 CERTTOOL=${CERTTOOL:-../../src/certtool$EXEEXT}
 
-exec $CERTTOOL --certificate-info --infile $srcdir/userid.pem
+$CERTTOOL --certificate-info --infile $srcdir/userid.pem >out 2>&1
+RET=$?
+if [ $RET !=  0 ];then
+       echo "Error in userid:"
+       cat out
+       exit 1
+fi
+
+exit 0
diff --git a/tests/x509dn.c b/tests/x509dn.c
index 1c9e715..a68af09 100644
--- a/tests/x509dn.c
+++ b/tests/x509dn.c
@@ -113,7 +113,7 @@ static int
 cert_callback (gnutls_session_t session,
               const gnutls_datum_t * req_ca_rdn, int nreqs,
               const gnutls_pk_algorithm_t * sign_algos,
-              int sign_algos_length, gnutls_retr_st * st)
+              int sign_algos_length, gnutls_retr2_st * st)
 {
   int result;
   gnutls_x509_dn_t dn;
@@ -197,7 +197,7 @@ client (void)
    */
   gnutls_certificate_set_x509_trust_mem (xcred, &ca, GNUTLS_X509_FMT_PEM);
 
-  gnutls_certificate_client_set_retrieve_function (xcred, cert_callback);
+  gnutls_certificate_set_retrieve_function (xcred, cert_callback);
 
   /* Initialize TLS session
    */
diff --git a/tests/x509self.c b/tests/x509self.c
index 33d7148..f10a51f 100644
--- a/tests/x509self.c
+++ b/tests/x509self.c
@@ -55,6 +55,7 @@ tls_log_func (int level, const char *str)
 /* A very basic TLS client, with anonymous authentication.
  */
 
+
 #define MAX_BUF 1024
 #define MSG "Hello TLS"
 
diff --git a/tests/x509signself.c b/tests/x509signself.c
deleted file mode 100644
index b5455c2..0000000
--- a/tests/x509signself.c
+++ /dev/null
@@ -1,509 +0,0 @@
-/*
- * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010 Free Software
- * Foundation, Inc.
- *
- * Author: Simon Josefsson
- *
- * This file is part of GnuTLS.
- *
- * GnuTLS is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 3 of the License, or
- * (at your option) any later version.
- *
- * GnuTLS is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with GnuTLS; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
- */
-
-/* Parts copied from GnuTLS example programs. */
-
-#ifdef HAVE_CONFIG_H
-# include <config.h>
-#endif
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/types.h>
-#include <netinet/in.h>
-#include <sys/socket.h>
-#include <sys/wait.h>
-#include <arpa/inet.h>
-#include <unistd.h>
-#include <gnutls/gnutls.h>
-#include <gnutls/x509.h>
-
-#include "ex-session-info.c"
-#include "ex-x509-info.c"
-#include "tcp.c"
-
-#include "utils.h"
-
-pid_t child;
-
-static void
-tls_log_func (int level, const char *str)
-{
-  fprintf (stderr, "%s |<%d>| %s", child ? "server" : "client", level, str);
-}
-
-/* A very basic TLS client, with anonymous authentication.
- */
-
-#define MAX_BUF 1024
-#define MSG "Hello TLS"
-
-static char ca_pem[] =
-  "-----BEGIN CERTIFICATE-----\n"
-  "MIIB5zCCAVKgAwIBAgIERiYdJzALBgkqhkiG9w0BAQUwGTEXMBUGA1UEAxMOR251\n"
-  "VExTIHRlc3QgQ0EwHhcNMDcwNDE4MTMyOTExWhcNMDgwNDE3MTMyOTExWjAZMRcw\n"
-  "FQYDVQQDEw5HbnVUTFMgdGVzdCBDQTCBnDALBgkqhkiG9w0BAQEDgYwAMIGIAoGA\n"
-  "vuyYeh1vfmslnuggeEKgZAVmQ5ltSdUY7H25WGSygKMUYZ0KT74v8C780qtcNt9T\n"
-  "7EPH/N6RvB4BprdssgcQLsthR3XKA84jbjjxNCcaGs33lvOz8A1nf8p3hD+cKfRi\n"
-  "kfYSW2JazLrtCC4yRCas/SPOUxu78of+3HiTfFm/oXUCAwEAAaNDMEEwDwYDVR0T\n"
-  "AQH/BAUwAwEB/zAPBgNVHQ8BAf8EBQMDBwQAMB0GA1UdDgQWBBTpPBz7rZJu5gak\n"
-  "Viyi4cBTJ8jylTALBgkqhkiG9w0BAQUDgYEAiaIRqGfp1jPpNeVhABK60SU0KIAy\n"
-  "njuu7kHq5peUgYn8Jd9zNzExBOEp1VOipGsf6G66oQAhDFp2o8zkz7ZH71zR4HEW\n"
-  "KoX6n5Emn6DvcEH/9pAhnGxNHJAoS7czTKv/JDZJhkqHxyrE1fuLsg5Qv25DTw7+\n"
-  "PfqUpIhz5Bbm7J4=\n" "-----END CERTIFICATE-----\n";
-const gnutls_datum_t ca = { ca_pem, sizeof (ca_pem) };
-
-static char cert_pem[] =
-  "-----BEGIN CERTIFICATE-----\n"
-  "MIICHjCCAYmgAwIBAgIERiYdNzALBgkqhkiG9w0BAQUwGTEXMBUGA1UEAxMOR251\n"
-  "VExTIHRlc3QgQ0EwHhcNMDcwNDE4MTMyOTI3WhcNMDgwNDE3MTMyOTI3WjAdMRsw\n"
-  "GQYDVQQDExJHbnVUTFMgdGVzdCBjbGllbnQwgZwwCwYJKoZIhvcNAQEBA4GMADCB\n"
-  "iAKBgLtmQ/Xyxde2jMzF3/WIO7HJS2oOoa0gUEAIgKFPXKPQ+GzP5jz37AR2ExeL\n"
-  "ZIkiW8DdU3w77XwEu4C5KL6Om8aOoKUSy/VXHqLnu7czSZ/ju0quak1o/8kR4jKN\n"
-  "zj2AC41179gAgY8oBAOgIo1hBAf6tjd9IQdJ0glhaZiQo1ipAgMBAAGjdjB0MAwG\n"
-  "A1UdEwEB/wQCMAAwEwYDVR0lBAwwCgYIKwYBBQUHAwIwDwYDVR0PAQH/BAUDAweg\n"
-  "ADAdBgNVHQ4EFgQUTLkKm/odNON+3svSBxX+odrLaJEwHwYDVR0jBBgwFoAU6Twc\n"
-  "+62SbuYGpFYsouHAUyfI8pUwCwYJKoZIhvcNAQEFA4GBALujmBJVZnvaTXr9cFRJ\n"
-  "jpfc/3X7sLUsMvumcDE01ls/cG5mIatmiyEU9qI3jbgUf82z23ON/acwJf875D3/\n"
-  "U7jyOsBJ44SEQITbin2yUeJMIm1tievvdNXBDfW95AM507ShzP12sfiJkJfjjdhy\n"
-  "dc8Siq5JojruiMizAf0pA7in\n" "-----END CERTIFICATE-----\n";
-const gnutls_datum_t cert = { cert_pem, sizeof (cert_pem) };
-
-static int
-sign_func (gnutls_session_t session,
-          void *userdata,
-          gnutls_certificate_type_t cert_type,
-          const gnutls_datum_t * cert,
-          const gnutls_datum_t * hash, gnutls_datum_t * signature)
-{
-  gnutls_x509_privkey_t key;
-  char key_pem[] =
-    "-----BEGIN RSA PRIVATE KEY-----\n"
-    "MIICXAIBAAKBgQC7ZkP18sXXtozMxd/1iDuxyUtqDqGtIFBACIChT1yj0Phsz+Y8\n"
-    "9+wEdhMXi2SJIlvA3VN8O+18BLuAuSi+jpvGjqClEsv1Vx6i57u3M0mf47tKrmpN\n"
-    "aP/JEeIyjc49gAuNde/YAIGPKAQDoCKNYQQH+rY3fSEHSdIJYWmYkKNYqQIDAQAB\n"
-    "AoGADpmARG5CQxS+AesNkGmpauepiCz1JBF/JwnyiX6vEzUh0Ypd39SZztwrDxvF\n"
-    "PJjQaKVljml1zkJpIDVsqvHdyVdse8M+Qn6hw4x2p5rogdvhhIL1mdWo7jWeVJTF\n"
-    "RKB7zLdMPs3ySdtcIQaF9nUAQ2KJEvldkO3m/bRJFEp54k0CQQDYy+RlTmwRD6hy\n"
-    "7UtMjR0H3CSZJeQ8svMCxHLmOluG9H1UKk55ZBYfRTsXniqUkJBZ5wuV1L+pR9EK\n"
-    "ca89a+1VAkEA3UmBelwEv2u9cAU1QjKjmwju1JgXbrjEohK+3B5y0ESEXPAwNQT9\n"
-    "TrDM1m9AyxYTWLxX93dI5QwNFJtmbtjeBQJARSCWXhsoaDRG8QZrCSjBxfzTCqZD\n"
-    "ZXtl807ymCipgJm60LiAt0JLr4LiucAsMZz6+j+quQbSakbFCACB8SLV1QJBAKZQ\n"
-    "YKf+EPNtnmta/rRKKvySsi3GQZZN+Dt3q0r094XgeTsAqrqujVNfPhTMeP4qEVBX\n"
-    "/iVX2cmMTSh3w3z8MaECQEp0XJWDVKOwcTW6Ajp9SowtmiZ3YDYo1LF9igb4iaLv\n"
-    "sWZGfbnU3ryjvkb6YuFjgtzbZDZHWQCo8/cOtOBmPdk=\n"
-    "-----END RSA PRIVATE KEY-----\n";
-  const gnutls_datum_t key_dat = { key_pem, sizeof (key_pem) };
-  int ret;
-
-  ret = gnutls_x509_privkey_init (&key);
-  if (ret < 0)
-    return ret;
-
-  ret = gnutls_x509_privkey_import (key, &key_dat, GNUTLS_X509_FMT_PEM);
-  if (ret < 0)
-    goto done;
-
-  ret = gnutls_x509_privkey_sign_hash (key, hash, signature);
-  if (ret < 0)
-    goto done;
-
-  ret = 0;
-
-done:
-  gnutls_x509_privkey_deinit (key);
-  return ret;
-}
-
-static void
-client (void)
-{
-  int ret, sd, ii;
-  gnutls_session_t session;
-  char buffer[MAX_BUF + 1];
-  gnutls_certificate_credentials_t xcred;
-
-  gnutls_global_init ();
-
-  gnutls_global_set_log_function (tls_log_func);
-  if (debug)
-    gnutls_global_set_log_level (4711);
-
-  gnutls_certificate_allocate_credentials (&xcred);
-
-  /* sets the trusted cas file
-   */
-  gnutls_certificate_set_x509_trust_mem (xcred, &ca, GNUTLS_X509_FMT_PEM);
-  gnutls_certificate_set_x509_key_mem (xcred, &cert, NULL,
-                                      GNUTLS_X509_FMT_PEM);
-
-  /* Initialize TLS session
-   */
-  gnutls_init (&session, GNUTLS_CLIENT);
-
-  /* Set sign callback. */
-  gnutls_sign_callback_set (session, sign_func, NULL);
-
-  /* Use default priorities */
-  gnutls_set_default_priority (session);
-
-  /* put the x509 credentials to the current session
-   */
-  gnutls_credentials_set (session, GNUTLS_CRD_CERTIFICATE, xcred);
-
-  /* connect to the peer
-   */
-  sd = tcp_connect ();
-
-  gnutls_transport_set_ptr (session, (gnutls_transport_ptr_t) sd);
-
-  /* Perform the TLS handshake
-   */
-  ret = gnutls_handshake (session);
-
-  if (ret < 0)
-    {
-      fail ("client: Handshake failed\n");
-      gnutls_perror (ret);
-      goto end;
-    }
-  else
-    {
-      if (debug)
-       success ("client: Handshake was completed\n");
-    }
-
-  if (debug)
-    success ("client: TLS version is: %s\n",
-            gnutls_protocol_get_name (gnutls_protocol_get_version
-                                      (session)));
-
-  /* see the Getting peer's information example */
-  if (debug)
-    print_info (session);
-
-  gnutls_record_send (session, MSG, strlen (MSG));
-
-  ret = gnutls_record_recv (session, buffer, MAX_BUF);
-  if (ret == 0)
-    {
-      if (debug)
-       success ("client: Peer has closed the TLS connection\n");
-      goto end;
-    }
-  else if (ret < 0)
-    {
-      fail ("client: Error: %s\n", gnutls_strerror (ret));
-      goto end;
-    }
-
-  if (debug)
-    {
-      printf ("- Received %d bytes: ", ret);
-      for (ii = 0; ii < ret; ii++)
-       {
-         fputc (buffer[ii], stdout);
-       }
-      fputs ("\n", stdout);
-    }
-
-  gnutls_bye (session, GNUTLS_SHUT_RDWR);
-
-end:
-
-  tcp_close (sd);
-
-  gnutls_deinit (session);
-
-  gnutls_certificate_free_credentials (xcred);
-
-  gnutls_global_deinit ();
-}
-
-/* This is a sample TLS 1.0 echo server, using X.509 authentication.
- */
-
-#define SA struct sockaddr
-#define MAX_BUF 1024
-#define PORT 5556              /* listen to 5556 port */
-#define DH_BITS 1024
-
-/* These are global */
-gnutls_certificate_credentials_t x509_cred;
-
-static gnutls_session_t
-initialize_tls_session (void)
-{
-  gnutls_session_t session;
-
-  gnutls_init (&session, GNUTLS_SERVER);
-
-  /* avoid calling all the priority functions, since the defaults
-   * are adequate.
-   */
-  gnutls_set_default_priority (session);
-
-  gnutls_credentials_set (session, GNUTLS_CRD_CERTIFICATE, x509_cred);
-
-  /* request client certificate if any.
-   */
-  gnutls_certificate_server_set_request (session, GNUTLS_CERT_REQUEST);
-
-  gnutls_dh_set_prime_bits (session, DH_BITS);
-
-  return session;
-}
-
-static gnutls_dh_params_t dh_params;
-
-static int
-generate_dh_params (void)
-{
-  const gnutls_datum_t p3 = { (char *) pkcs3, strlen (pkcs3) };
-  /* Generate Diffie-Hellman parameters - for use with DHE
-   * kx algorithms. These should be discarded and regenerated
-   * once a day, once a week or once a month. Depending on the
-   * security requirements.
-   */
-  gnutls_dh_params_init (&dh_params);
-  return gnutls_dh_params_import_pkcs3 (dh_params, &p3, GNUTLS_X509_FMT_PEM);
-}
-
-int err, listen_sd, i;
-int sd, ret;
-struct sockaddr_in sa_serv;
-struct sockaddr_in sa_cli;
-int client_len;
-char topbuf[512];
-gnutls_session_t session;
-char buffer[MAX_BUF + 1];
-int optval = 1;
-
-static char server_cert_pem[] =
-  "-----BEGIN CERTIFICATE-----\n"
-  "MIICVjCCAcGgAwIBAgIERiYdMTALBgkqhkiG9w0BAQUwGTEXMBUGA1UEAxMOR251\n"
-  "VExTIHRlc3QgQ0EwHhcNMDcwNDE4MTMyOTIxWhcNMDgwNDE3MTMyOTIxWjA3MRsw\n"
-  "GQYDVQQKExJHbnVUTFMgdGVzdCBzZXJ2ZXIxGDAWBgNVBAMTD3Rlc3QuZ251dGxz\n"
-  "Lm9yZzCBnDALBgkqhkiG9w0BAQEDgYwAMIGIAoGA17pcr6MM8C6pJ1aqU46o63+B\n"
-  "dUxrmL5K6rce+EvDasTaDQC46kwTHzYWk95y78akXrJutsoKiFV1kJbtple8DDt2\n"
-  "DZcevensf9Op7PuFZKBroEjOd35znDET/z3IrqVgbtm2jFqab7a+n2q9p/CgMyf1\n"
-  "tx2S5Zacc1LWn9bIjrECAwEAAaOBkzCBkDAMBgNVHRMBAf8EAjAAMBoGA1UdEQQT\n"
-  "MBGCD3Rlc3QuZ251dGxzLm9yZzATBgNVHSUEDDAKBggrBgEFBQcDATAPBgNVHQ8B\n"
-  "Af8EBQMDB6AAMB0GA1UdDgQWBBTrx0Vu5fglyoyNgw106YbU3VW0dTAfBgNVHSME\n"
-  "GDAWgBTpPBz7rZJu5gakViyi4cBTJ8jylTALBgkqhkiG9w0BAQUDgYEAaFEPTt+7\n"
-  "bzvBuOf7+QmeQcn29kT6Bsyh1RHJXf8KTk5QRfwp6ogbp94JQWcNQ/S7YDFHglD1\n"
-  "AwUNBRXwd3riUsMnsxgeSDxYBfJYbDLeohNBsqaPDJb7XailWbMQKfAbFQ8cnOxg\n"
-  "rOKLUQRWJ0K3HyXRMhbqjdLIaQiCvQLuizo=\n" "-----END CERTIFICATE-----\n";
-
-const gnutls_datum_t server_cert = { server_cert_pem,
-  sizeof (server_cert_pem)
-};
-
-static char server_key_pem[] =
-  "-----BEGIN RSA PRIVATE KEY-----\n"
-  "MIICXAIBAAKBgQDXulyvowzwLqknVqpTjqjrf4F1TGuYvkrqtx74S8NqxNoNALjq\n"
-  "TBMfNhaT3nLvxqResm62ygqIVXWQlu2mV7wMO3YNlx696ex/06ns+4VkoGugSM53\n"
-  "fnOcMRP/PciupWBu2baMWppvtr6far2n8KAzJ/W3HZLllpxzUtaf1siOsQIDAQAB\n"
-  "AoGAYAFyKkAYC/PYF8e7+X+tsVCHXppp8AoP8TEZuUqOZz/AArVlle/ROrypg5kl\n"
-  "8YunrvUdzH9R/KZ7saNZlAPLjZyFG9beL/am6Ai7q7Ma5HMqjGU8kTEGwD7K+lbG\n"
-  "iomokKMOl+kkbY/2sI5Czmbm+/PqLXOjtVc5RAsdbgvtmvkCQQDdV5QuU8jap8Hs\n"
-  "Eodv/tLJ2z4+SKCV2k/7FXSKWe0vlrq0cl2qZfoTUYRnKRBcWxc9o92DxK44wgPi\n"
-  "oMQS+O7fAkEA+YG+K9e60sj1K4NYbMPAbYILbZxORDecvP8lcphvwkOVUqbmxOGh\n"
-  "XRmTZUuhBrJhJKKf6u7gf3KWlPl6ShKEbwJASC118cF6nurTjuLf7YKARDjNTEws\n"
-  "qZEeQbdWYINAmCMj0RH2P0mvybrsXSOD5UoDAyO7aWuqkHGcCLv6FGG+qwJAOVqq\n"
-  "tXdUucl6GjOKKw5geIvRRrQMhb/m5scb+5iw8A4LEEHPgGiBaF5NtJZLALgWfo5n\n"
-  "hmC8+G8F0F78znQtPwJBANexu+Tg5KfOnzSILJMo3oXiXhf5PqXIDmbN0BKyCKAQ\n"
-  "LfkcEcUbVfmDaHpvzwY9VEaoMOKVLitETXdNSxVpvWM=\n"
-  "-----END RSA PRIVATE KEY-----\n";
-
-const gnutls_datum_t server_key = { server_key_pem,
-  sizeof (server_key_pem)
-};
-
-static void
-server_start (void)
-{
-  /* Socket operations
-   */
-  listen_sd = socket (AF_INET, SOCK_STREAM, 0);
-  if (err == -1)
-    {
-      perror ("socket");
-      fail ("server: socket failed\n");
-      return;
-    }
-
-  memset (&sa_serv, '\0', sizeof (sa_serv));
-  sa_serv.sin_family = AF_INET;
-  sa_serv.sin_addr.s_addr = INADDR_ANY;
-  sa_serv.sin_port = htons (PORT);     /* Server Port number */
-
-  setsockopt (listen_sd, SOL_SOCKET, SO_REUSEADDR, (void *) &optval,
-             sizeof (int));
-
-  err = bind (listen_sd, (SA *) & sa_serv, sizeof (sa_serv));
-  if (err == -1)
-    {
-      perror ("bind");
-      fail ("server: bind failed\n");
-      return;
-    }
-
-  err = listen (listen_sd, 1024);
-  if (err == -1)
-    {
-      perror ("listen");
-      fail ("server: listen failed\n");
-      return;
-    }
-
-  if (debug)
-    success ("server: ready. Listening to port '%d'.\n", PORT);
-}
-
-static void
-server (void)
-{
-  /* this must be called once in the program
-   */
-  gnutls_global_init ();
-
-  gnutls_global_set_log_function (tls_log_func);
-  if (debug)
-    gnutls_global_set_log_level (4711);
-
-  gnutls_certificate_allocate_credentials (&x509_cred);
-  gnutls_certificate_set_x509_trust_mem (x509_cred, &ca, GNUTLS_X509_FMT_PEM);
-
-  gnutls_certificate_set_x509_key_mem (x509_cred, &server_cert, &server_key,
-                                      GNUTLS_X509_FMT_PEM);
-
-  if (debug)
-    success ("Launched, generating DH parameters...\n");
-
-  generate_dh_params ();
-
-  gnutls_certificate_set_dh_params (x509_cred, dh_params);
-
-  client_len = sizeof (sa_cli);
-
-  session = initialize_tls_session ();
-
-  sd = accept (listen_sd, (SA *) & sa_cli, &client_len);
-
-  if (debug)
-    success ("server: connection from %s, port %d\n",
-            inet_ntop (AF_INET, &sa_cli.sin_addr, topbuf,
-                       sizeof (topbuf)), ntohs (sa_cli.sin_port));
-
-  gnutls_transport_set_ptr (session, (gnutls_transport_ptr_t) sd);
-  ret = gnutls_handshake (session);
-  if (ret < 0)
-    {
-      close (sd);
-      gnutls_deinit (session);
-      fail ("server: Handshake has failed (%s)\n\n", gnutls_strerror (ret));
-      return;
-    }
-  if (debug)
-    success ("server: Handshake was completed\n");
-
-  if (debug)
-    success ("server: TLS version is: %s\n",
-            gnutls_protocol_get_name (gnutls_protocol_get_version
-                                      (session)));
-
-  /* see the Getting peer's information example */
-  if (debug)
-    print_info (session);
-
-  i = 0;
-  for (;;)
-    {
-      memset (buffer, 0, MAX_BUF + 1);
-      ret = gnutls_record_recv (session, buffer, MAX_BUF);
-
-      if (ret == 0)
-       {
-         if (debug)
-           success ("server: Peer has closed the GnuTLS connection\n");
-         break;
-       }
-      else if (ret < 0)
-       {
-         fail ("server: Received corrupted data(%d). Closing...\n", ret);
-         break;
-       }
-      else if (ret > 0)
-       {
-         /* echo data back to the client
-          */
-         gnutls_record_send (session, buffer, strlen (buffer));
-       }
-    }
-  /* do not wait for the peer to close the connection.
-   */
-  gnutls_bye (session, GNUTLS_SHUT_WR);
-
-  close (sd);
-  gnutls_deinit (session);
-
-  close (listen_sd);
-
-  gnutls_certificate_free_credentials (x509_cred);
-
-  gnutls_dh_params_deinit (dh_params);
-
-  gnutls_global_deinit ();
-
-  if (debug)
-    success ("server: finished\n");
-}
-
-
-void
-doit (void)
-{
-  server_start ();
-  if (error_count)
-    return;
-
-  child = fork ();
-  if (child < 0)
-    {
-      perror ("fork");
-      fail ("fork");
-      return;
-    }
-
-  if (child)
-    {
-      int status;
-      /* parent */
-      server ();
-      wait (&status);
-    }
-  else
-    client ();
-}


hooks/post-receive
-- 
GNU gnutls



reply via email to

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