Re: pam_pkcs11 NSS patch.

classic Classic list List threaded Threaded
17 messages Options
Reply | Threaded
Open this post in threaded view
|

Re: pam_pkcs11 NSS patch.

Jonsy (teleline)
El mar, 03-04-2007 a las 14:43 -0700, Robert Relyea escribió:
> Hi Juan,
> Just another ping.

Ping ack.

Sorry. At this moment, I have no time nor interest in continuing
development of pam-pkcs11

Fell free to contact opensc team and look for people to restart
project.

Regards.
Juan Antonio

_______________________________________________
opensc-devel mailing list
[hidden email]
http://www.opensc-project.org/mailman/listinfo/opensc-devel

smime.p7s (4K) Download Attachment
Reply | Threaded
Open this post in threaded view
|

Re: Re: pam_pkcs11 NSS patch.

Ludovic Rousseau
Hello Robert,

On 04/04/07, Jonsito <[hidden email]> wrote:

> El mar, 03-04-2007 a las 14:43 -0700, Robert Relyea escribió:
> > Hi Juan,
> > Just another ping.
>
> Ping ack.
>
> Sorry. At this moment, I have no time nor interest in continuing
> development of pam-pkcs11
>
> Fell free to contact opensc team and look for people to restart
> project.

I, more or less, use pam-pkcs11. I would really be interested in
integrating your RedHat patches.

I propose to discuss pam-pkcs11 patches and evolution on this list
(opensc-devel). Unless you have something secret to say and you can
mail me privately.

Regards,

--
 Dr. Ludovic Rousseau
_______________________________________________
opensc-devel mailing list
[hidden email]
http://www.opensc-project.org/mailman/listinfo/opensc-devel
Reply | Threaded
Open this post in threaded view
|

Re: Re: pam_pkcs11 NSS patch.

Ludovic Rousseau
On 04/04/07, Ludovic Rousseau <[hidden email]> wrote:
> I, more or less, use pam-pkcs11. I would really be interested in
> integrating your RedHat patches.

And I work on the pam_pkcs11 source code right now. So it is the very
good time to submit your patches :-)

Be sure to use a subversion version before generating your diffs.

Bye

--
  Dr. Ludovic Rousseau
_______________________________________________
opensc-devel mailing list
[hidden email]
http://www.opensc-project.org/mailman/listinfo/opensc-devel
Reply | Threaded
Open this post in threaded view
|

Re: Re: pam_pkcs11 NSS patch.

relyea
Ludovic Rousseau wrote:

> On 04/04/07, Ludovic Rousseau <[hidden email]> wrote:
>> I, more or less, use pam-pkcs11. I would really be interested in
>> integrating your RedHat patches.
>
> And I work on the pam_pkcs11 source code right now. So it is the very
> good time to submit your patches :-)
>
> Be sure to use a subversion version before generating your diffs.
>
> Bye
>
Thanks Ludovic,

I had already updated to pam_pkcs11-0.5.3-svn-r230, so I took that patch
and applied it to the latest svn and corrected any problems. We have 3
broad sets of patches:

 1. allow pam_pkcs11 to be built with nss rather than direct to pkcs 11
and openSSL (this allows us to use things like NSS's OCSP, and work with
multiple simultaneous tokens for login).
 2. work well with gdm and gnome-screensaver (which can now restart the
pam stack on smart card insertion and removal).
 3. internationalize the strings passed to the user from pam_pkcs11
(using  GetText).

Since those are separate ideas I'll give them in separate paches. The
NSS patch is included here.

This patch is the largest of the three, so it makes sense to get it
through first. I've attached the patch and a (fairly long) description
of the changes that were made. Hopefully the latter will help you
identify potential issues without getting bogged down in the details.
The patch applies is made from the current svn trunk build pulled this
morning (PDT).

I've kept both svn tree around so we can turn around any changes to the
patch quickly

Thanks,

bob

------------------------------------------------------------------------
    Introduction to the pam_pkcs11-nss.patch

This patch adds compile time support for the NSS crypto libraries. It optionally
replaces the raw PKCS #11 operations and open SSL certificate processing with
functionsprovided by the NSS crypto libraries. This change is controlled by a
configure option, '--with-nss' or '--without-nss'. --without-nss is the default.
This package requires nss 3.10 as a minimum.

When --with-nss is selected, pam_pkcs11 can support the following:

1) multiple simultaeous pkcs #11 modules used for authentication. NSS already
handles multiple smart card handlers running at the same time. This means you
can configure your box to log in with both CAC and pkcs #12 tokens by loading
both sets of modules. This support must be configured in pam_pkcs11, otherwise
NSS will only use the user selected pkcs11 module, same as the current direct
to pkcs #11 support.

2) Optional OCSP support. This support is built into NSS already. If you
compile --with-nss, you can simply turn it on.

3) with --with-nss, pkcs11_eventmgr automatically uses C_WaitForSlotEvent for
those tokens that support it, and pull for those that don't. (NSS has this support
built in).

4) with --with-nss, any cert key type NSS supports will work correctly (RSA,
DSA, ECDSA, etc).

5) nss automatically supports part of the certificate chain stored on the
smart card. This allows you to store a single root certificate in the database
and keep the intermediates on the token itself.

6) src/common/rsaref is not need to build any of pam_pkcs11 (if --with-nss is used).

Other differences when --with-nss and --without-nss:

1) The crl policy is ignored. NSS handles crls automatically already. It
uses standard external tools to keep crls up-to-date.

2) The tools will only display user certs, that is certificates for which the
token claims to hold the private key for.

                        The patch itself

The changes in this patch can be categorized in the following broad categories:

1) build changes.
2) interface changes to make the crypto operations more generic.
3) implement the NSS versions of the base crypto functions.

                         Changes by file

./configure.in:
 1. switch between the nss module and the openssl depending on the state of
--with-nss. (openssl is the default).
 2. added environment variables CRYPO_CFLAGS and CRYPTO_LIBS
 3. added the AM conditional HAVE_NSS

./src/common -- This is where most of the NSS specific code lives. Basically
the following  interface changes were made:

./src/common/pkcs11_lib.c ./src/common/pkcs11_lib.h
 cert_object_t and pkcs11_handle_t were made opaque handles. Applications no
longer have direct access to their member functions members are accessed
through accessor functions. These new accessor functions are:

  find_slot_by_number: Takes a pkcs11_handle_t, an input slot number, and
  returns a generic slot number and success for failure. The input slot number
  is the same 'ones' based index into the SlotList. The generic slot number is
  library specific (NSS now returns the slotID, the non-NSS code returns the
  'zero' based index into the SlotList). If the input slot number is zero, the
  first present smart card is returned.

  get_slot_label: takes a pkcs11_handle_t and returns the label for the
  currently opened slot.

  get_X509_certificate: takes a cert_object_t and returns the X509 Cert. NOTE:
  the X509 certificate itself has been made into a generic handle which could
  be either an openssl X509 or an NSS CERTCertificate.  see cert_st.h for more
  info.

  crypto_init: This function is called to set up the crypto system. It takes
  a pointer to the cert policy to help setup. While not exactly an accessor
  function, it is new.

  In addition to these accessors, the following existing functions have changed:

  load_pkcs11_module: now allocates a pkcs11_handle_t and returns it. Since
  pkcs11_handle_t's are opaque, applications no longer know how big they are,
  and therefore can't allocate them from the stack.

  get_certificate_list (was get_certificate): returns an array of pointers to
  cert_object_t's. unlike the short-lived get_certificate_list in the branch,
  this function actually operates as an accessor function. The returned
  certificate list is still 'owned' by the pkcs11_handle_t. Subsequent calls to
  get_certificate_list will return the same array as the previous calls. The
  array is freed automatically when the pkcs11_handle_t is closed (just as it
  is in the original base code). This change was necessary because
  pkcs11_handle_t is no longer accessible (it no longer holds the same data in
  the different implementations).

  get_private_key: takes a handle to a cert_object_t. It looks up the private
  key for that object and returns failure if it can't find it. This change is
  because the patch gets rid of the chosen cert field. Applications chose the
  cert and pass the cert directly into this and the sign function.

  sign_value: takes a cert_object_t. If the cert_object_t does not have a
  private key, then sign_value will fail. If get_private_key was not called on
  cert_object_t at some time in the past, sign_value will automatically call
  it.  This change was also motivated by the removal of the chosen_cert field.

   Another way of implementing the get_private_key/sign_value is to create an
   new chosen cert accessor function and reverting the implementation for these
   two functions. The new APIs, however, allow for multiple certs to sign in a
   single pkcs11_handle_t context.

./src/common/cert_st.h ./src/common/cert_info.h ./src/common/cert_vfy.h
 The only interface changes here are:
   1) adding nss_dir and ocsp_policy to cert_policy_st.
   2) changing the definition of X509 depending on whether which cert library
   we are using (X509 for openSSL, CERTCertificate or NSS). The use of a
   #define here limitted the extent of the patch in other modules.
   3) generic defines for algorithm types.
   4) addition of 3 new CERT_Info types. (Issuer, serial number, key algorithm).

  cert_st.h is a new function, which other files can include in place of
  <openssl/x509.h>

./src/common/cert_info.c ./src/common/cert_vfy.c
  These basically accepted the new NSS implementations for the certificate
  verify and info functions. These patches are relatively straight forward.
  The original API did not need any tweaking.

./src/common/algorithm.c ./src/common/alg_st.h
  These new files provide generic API's to do access the hash algorithm to
  pass to cert_info. If access to actual hashing or crypto were
  needed, the new functions could be added here. Like cert_st.h, alg_st.h
  replaces the use of <openssl/evp.h>

./src/common/NSPRerrs.h ./src/common/SECerrs.h ./src/common/secutil.h
./src/common/SSLerrs.h
  These new files provide the NSS error message mappings.

 Changes in ./src/common make up about 65% of the patch.


./src/mappers/*.c
  The mapper functions were changes to use the generic form of hashing defined
  in alg_st.h. (mostly replacing <openssl/x509v3.h> with cert_st.h and NULL
  in cert_info with ALGORITHM_NULL).

  exceptions: opensc_mapper.c and oopenssh_mapper.c  are not implemented for
  NSS because of the use of BIO directly.

  These changes make up less than 10 % of the patch.

./src/pam_pkcs11/pam_config.c
  Added support to fetch nss_dir and ocsp_policy.

./src/pam_pkcs11/pam_pkcs11.c
  Change to use the new API. These changes include:
  1) calling the new crypto_init function instead of the various openSSL
  init functions.
  2) pam_pkcs11 now holds a pointer to the pkcs11_handle_t rather than a static
  version. A large number of diffs are simply changing &ph to ph.
  3) Use the accessor functions to get the slotnum and the cert list.
  4) chosen_cert is now a local variable rather than a field in pkcs11_handle_t
  5) move pkcs11_login back before the get_certificate_list. Some tokens need
  be to authenticated before we can read the certificates. More importantly,
  the NSS cert code is only returning user certificates (certificates with the
  private keys). Only a small number of tokens know now to identify user
  certificates if you aren't logged in. Since this change is a reversion of
  a previous change in this version of pam_pkcs11, we may need to do more
  to reconcile it. Perhaps putting explicit #ifdef HAVE_NSS around the early
  login, adding a later login with #ifndef HAVE_NSS.
  6) the get_private_key call was moved into sign_value, so it's removed
  from pam_pkcs11 itself. It would be easy to revert this change and continue
  to call get_private_key directly.


./src/tools/pkcs11_eventmgr.c
  pkcs11_eventmgr is basically 2 implementations of the pkcs11_eventmgr
  stitched together with ifdefs. A reasonable todo would be to build the
  proper generic interfaces to have a 'clean' pkcs11_eventmgr and hide the
  details in src/common/pkcs11_lib.c like we do with all the rest. The existing
  code doesn't even use the generic init calls that already exist.

./src/tools/*.c [the rest]
  The same type of generic changes made to pam_pkcs11.c




   








Index: configure.in
===================================================================
--- configure.in (revision 237)
+++ configure.in (working copy)
@@ -100,9 +100,42 @@
 #AC_SUBST(LIBP11_LIBS)
 #AM_CONDITIONAL(HAVE_LIBP11, test x$with_libp11 = xyes)
 
-# Check and set OpenSSL paths
-PKG_CHECK_MODULES(OPENSSL, openssl, [ with_ssl=yes ], [ AC_MSG_ERROR([openssl not found]) ])
+PKG_PROG_PKG_CONFIG
 
+# Check and set crypto paths
+AC_ARG_WITH(nss,
+  [  --with-nss          use NSS instead of openSSL and raw PKCS 11 (default=no)])
+if test "$with_nss" = "yes" -o "$with_nss" = "true"
+then
+  PKG_CHECK_MODULES(NSS, nss, [with_nss=yes],
+   [ AC_MSG_ERROR(could not locate NSS crypto library) ] )
+  OPENSSL_CFLAGS=
+  OPENSSL_LIBS=
+  AC_SUBST(OPENSSL_CFLAGS)
+  AC_SUBST(OPENSSL_LIBS)
+  with_ssl=no
+else
+   PKG_CHECK_MODULES(OPENSSL, openssl, [with_ssl=yes ],
+    [ AC_MSG_ERROR(openssl not found) ])
+  NSS_CFLAGS=
+  NSS_LIBS=
+  AC_SUBST(NSS_CFLAGS)
+  AC_SUBST(NSS_LIBS)
+  with_nss=no
+fi
+AM_CONDITIONAL(HAVE_NSS, test x$with_nss = xyes)
+if test "$with_nss" = "yes"
+then
+    CRYPTO_CFLAGS="${NSS_CFLAGS}-DHAVE_NSS"
+    CRYPTO_LIBS=${NSS_LIBS}
+else
+    CRYPTO_CFLAGS=${OPENSSL_CFLAGS}
+    CRYPTO_LIBS=${OPENSSL_LIBS}
+fi
+AC_SUBST(CRYPTO_CFLAGS)
+AC_SUBST(CRYPTO_LIBS)
+
+
 # Check for PCSC-Lite
 AC_ARG_WITH(pcsclite,
   AC_HELP_STRING([--with-pcsclite], [Use pcsc-lite (default=yes)]),
@@ -235,5 +268,7 @@
 echo "PC/SC support:       ${with_pcsclite}"
 echo "CURL support:        ${with_curl}"
 echo "LDAP support:        ${with_ldap}"
+echo "NSS support:         ${with_nss}"
+echo "OPENSSL support:     ${with_ssl}"
 #echo "LIBP11 support:      ${with_libp11}"
 echo ""
Index: src/pam_pkcs11/mapper_mgr.h
===================================================================
--- src/pam_pkcs11/mapper_mgr.h (revision 237)
+++ src/pam_pkcs11/mapper_mgr.h (working copy)
@@ -28,8 +28,7 @@
 #include <config.h>
 #endif
 
-#include <openssl/x509.h>
-
+#include "../common/cert_st.h"
 #include "../scconf/scconf.h"
 #include "../mappers/mapper.h"
 
Index: src/pam_pkcs11/pam_pkcs11.c
===================================================================
--- src/pam_pkcs11/pam_pkcs11.c (revision 237)
+++ src/pam_pkcs11/pam_pkcs11.c (working copy)
@@ -26,7 +26,6 @@
 #endif
 #include <security/pam_appl.h>
 #include <security/pam_modules.h>
-#include <openssl/x509.h>
 #include <syslog.h>
 #include <ctype.h>
 #include <string.h>
@@ -34,9 +33,9 @@
 #include "../scconf/scconf.h"
 #include "../common/debug.h"
 #include "../common/error.h"
-#include "../common/rsaref/pkcs11.h"
 #include "../common/pkcs11_lib.h"
 #include "../common/cert_vfy.h"
+#include "../common/cert_st.h"
 #include "pam_config.h"
 #include "mapper_mgr.h"
 
@@ -121,7 +120,10 @@
   unsigned int slot_num = 0;
   struct configuration_st *configuration;
 
-  pkcs11_handle_t ph;
+  pkcs11_handle_t *ph;
+  cert_object_t *chosen_cert = NULL;
+  cert_object_t **cert_list;
+  int ncert;
   unsigned char random_value[128];
   unsigned char *signature;
   unsigned long signature_length;
@@ -156,8 +158,12 @@
   }
   
   /* init openssl */
-  OpenSSL_add_all_algorithms();
-  ERR_load_crypto_strings();
+  rv = crypto_init(&configuration->policy);
+  if (rv != 0) {
+    DBG("Failed to initialize crypto");
+    syslog(LOG_ERR, "Failed to initialize crypto");
+    return PAM_AUTHINFO_UNAVAIL;
+  }
 
   /* get user name */
   rv = pam_get_user(pamh, &user, NULL);
@@ -178,38 +184,32 @@
 
   /* initialise pkcs #11 module */
   DBG("initialising pkcs #11 module...");
-  rv = init_pkcs11_module(&ph,configuration->support_threads);
+  rv = init_pkcs11_module(ph,configuration->support_threads);
   if (rv != 0) {
-    release_pkcs11_module(&ph);
+    release_pkcs11_module(ph);
     DBG1("init_pkcs11_module() failed: %s", get_error());
     syslog(LOG_ERR, "init_pkcs11_module() failed: %s", get_error());
     return PAM_AUTHINFO_UNAVAIL;
   }
 
   /* open pkcs #11 session */
-  slot_num= configuration->slot_num;
-  if (slot_num == 0) {
-    DBG("using the first slot with an available token");
-    for (slot_num = 0; slot_num < ph.slot_count && !ph.slots[slot_num].token_present; slot_num++);
-    if (slot_num >= ph.slot_count) {
-      release_pkcs11_module(&ph);
-      DBG("no token available");
-      syslog(LOG_ERR, "no token available");
-      return PAM_AUTHINFO_UNAVAIL;
-    }
-  } else {
-    slot_num--;
+  rv = find_slot_by_number(ph, configuration->slot_num, &slot_num);
+  if (rv != 0) {
+    release_pkcs11_module(ph);
+    DBG("no token available");
+    syslog(LOG_ERR, "no token available");
+    return PAM_AUTHINFO_UNAVAIL;
   }
-  rv = open_pkcs11_session(&ph, slot_num);
+  rv = open_pkcs11_session(ph, slot_num);
   if (rv != 0) {
-    release_pkcs11_module(&ph);
+    release_pkcs11_module(ph);
     DBG1("open_pkcs11_session() failed: %s", get_error());
     syslog(LOG_ERR, "open_pkcs11_session() failed: %s", get_error());
     return PAM_AUTHINFO_UNAVAIL;
   }
 
   /* get password */
-  sprintf(password_prompt, "PIN for token %.32s: ", ph.slots[slot_num].label);
+  sprintf(password_prompt, "PIN for token %.32s: ", get_slot_label(ph));
   if (configuration->use_first_pass) {
     rv = pam_get_pwd(pamh, &password, NULL, PAM_AUTHTOK, 0);
   } else if (configuration->try_first_pass) {
@@ -218,6 +218,7 @@
     rv = pam_get_pwd(pamh, &password, password_prompt, 0, PAM_AUTHTOK);
   }
   if (rv != PAM_SUCCESS) {
+    release_pkcs11_module(ph);
     syslog(LOG_ERR, "pam_get_pwd() failed: %s", pam_strerror(pamh, rv));
     return PAM_AUTHINFO_UNAVAIL;
   }
@@ -227,25 +228,39 @@
 
   /* check password length */
   if (!configuration->nullok && strlen(password) == 0) {
+    release_pkcs11_module(ph);
     memset(password, 0, strlen(password));
     free(password);
     syslog(LOG_ERR, "password length is zero but the 'nullok' argument was not defined.");
     return PAM_AUTH_ERR;
   }
 
-  rv= get_certificates(&ph);
+  /* call pkcs#11 login to ensure that the user is the real owner of the card
+   * we need to do thise before get_certificate_list because some tokens
+   * can not read their certificates until the token is authenticated */
+  rv = pkcs11_login(ph, password);
+  /* erase and free in-memory password data asap */
+  memset(password, 0, strlen(password));
+  free(password);
+  if (rv != 0) {
+    DBG1("open_pkcs11_login() failed: %s", get_error());
+    syslog(LOG_ERR, "open_pkcs11_login() failed: %s", get_error());
+    goto auth_failed_nopw;
+  }
+
+  cert_list = get_certificate_list(ph, &ncert);
   if (rv<0) {
     DBG1("get_certificate_list() failed: %s", get_error());
     syslog(LOG_ERR, "get_certificate_list() failed: %s", get_error());
-    goto auth_failed;
+    goto auth_failed_nopw;
   }
 
   /* load mapper modules */
   load_mappers(configuration->ctx);
 
   /* find a valid and matching certificates */
-  for (i = 0; i < ph.cert_count; i++) {
-    X509 *x509 = ph.certs[i].x509;
+  for (i = 0; i < ncert; i++) {
+    X509 *x509 = get_X509_certificate(cert_list[i]);
     if (!x509 ) continue; /* sanity check */
     DBG1("verifing the certificate #%d", i + 1);
 
@@ -254,7 +269,7 @@
       if (rv < 0) {
         DBG1("verify_certificate() failed: %s", get_error());
         syslog(LOG_ERR, "verify_certificate() failed: %s", get_error());
- goto auth_failed;
+ goto auth_failed_nopw;
       } else if (rv != 1) {
         DBG1("verify_certificate() failed: %s", get_error());
         continue; /* try next certificate */
@@ -280,58 +295,49 @@
   if (rv != PAM_SUCCESS) {
     DBG1("pam_set_item() failed %s", pam_strerror(pamh, rv));
     syslog(LOG_ERR, "pam_set_item() failed %s", pam_strerror(pamh, rv));
-    goto auth_failed;
+    goto auth_failed_nopw;
  }
-          ph.choosen_cert = &ph.certs[i];
+          chosen_cert = cert_list[i];
           break; /* end loop, as find user success */
       }
     } else {
       /* User provided:
          check whether the certificate matches the user */
-      rv = match_user(x509, user);
+        rv = match_user(x509, user);
         if (rv < 0) { /* match error; abort and return */
-        DBG1("match_user() failed: %s", get_error());
-        syslog(LOG_ERR, "match_user() failed: %s", get_error());
-  goto auth_failed;
+          DBG1("match_user() failed: %s", get_error());
+          syslog(LOG_ERR, "match_user() failed: %s", get_error());
+  goto auth_failed_nopw;
         } else if (rv == 0) { /* match didn't success */
-        DBG("certificate is valid bus does not match the user");
+          DBG("certificate is valid bus does not match the user");
   continue; /* try next certificate */
         } else { /* match success */
-        DBG("certificate is valid and matches the user");
-        ph.choosen_cert = &ph.certs[i];
-        break;
+          DBG("certificate is valid and matches the user");
+          chosen_cert = cert_list[i];
+          break;
       }
     } /* if is_spaced string */
   } /* for (i=0; i<ncerts; i++) */
 
   /* now myCert points to our found certificate or null if no user found */
-  if (!ph.choosen_cert) {
+  if (!chosen_cert) {
     DBG("no valid certificate which meets all requirements found");
     syslog(LOG_ERR, "no valid certificate which meets all requirements found");
-    goto auth_failed;
+    goto auth_failed_nopw;
   }
 
-  /* call pkcs#11 login to ensure that the user is the real owner of the card */
-  rv = pkcs11_login(&ph, password);
 
-  /* erase and free in-memory password data asap */
-  memset(password, 0, strlen(password));
-  free(password);
-  if (rv != 0) {
-    DBG1("open_pkcs11_login() failed: %s", get_error());
-    syslog(LOG_ERR, "open_pkcs11_login() failed: %s", get_error());
-    goto auth_failed_nopw;
-  }
-
   /* if signature check is enforced, generate random data, sign and verify */
   if (configuration->policy.signature_policy) {
 
-    rv = get_private_key(&ph);
+#ifdef notdef
+    rv = get_private_key(ph);
     if (rv != 0) {
       DBG1("get_private_key() failed: %s", get_error());
       syslog(LOG_ERR, "get_private_key() failed: %s", get_error());
       goto auth_failed_nopw;
     }
+#endif
 
     /* read random value */
     rv = get_random_value(random_value, sizeof(random_value));
@@ -343,7 +349,8 @@
 
     /* sign random value */
     signature = NULL;
-    rv = sign_value(&ph, random_value, sizeof(random_value), &signature, &signature_length);
+    rv = sign_value(ph, chosen_cert, random_value, sizeof(random_value),
+    &signature, &signature_length);
     if (rv != 0) {
       DBG1("sign_value() failed: %s", get_error());
       syslog(LOG_ERR, "sign_value() failed: %s", get_error());
@@ -352,12 +359,12 @@
 
     /* verify the signature */
     DBG("verifying signature...");
-    rv = verify_signature(ph.choosen_key->x509,
+    rv = verify_signature(get_X509_certificate(chosen_cert),
              random_value, sizeof(random_value), signature, signature_length);
     if (signature != NULL) free(signature);
     if (rv != 0) {
-      close_pkcs11_session(&ph);
-      release_pkcs11_module(&ph);
+      close_pkcs11_session(ph);
+      release_pkcs11_module(ph);
       DBG1("verify_signature() failed: %s", get_error());
       syslog(LOG_ERR, "verify_signature() failed: %s", get_error());
       return PAM_AUTH_ERR;
@@ -368,9 +375,9 @@
   }
 
   /* close pkcs #11 session */
-  rv = close_pkcs11_session(&ph);
+  rv = close_pkcs11_session(ph);
   if (rv != 0) {
-    release_pkcs11_module(&ph);
+    release_pkcs11_module(ph);
     DBG1("close_pkcs11_session() failed: %s", get_error());
     syslog(LOG_ERR, "close_pkcs11_module() failed: %s", get_error());
     return PAM_AUTHINFO_UNAVAIL;
@@ -378,7 +385,7 @@
 
   /* release pkcs #11 module */
   DBG("releasing pkcs #11 module...");
-  release_pkcs11_module(&ph);
+  release_pkcs11_module(ph);
 
   DBG("authentication succeeded");
   return PAM_SUCCESS;
@@ -390,8 +397,8 @@
 
 auth_failed_nopw:
     unload_mappers();
-    close_pkcs11_session(&ph);
-    release_pkcs11_module(&ph);
+    close_pkcs11_session(ph);
+    release_pkcs11_module(ph);
     return PAM_AUTHINFO_UNAVAIL;
 }
 
Index: src/pam_pkcs11/pam_config.c
===================================================================
--- src/pam_pkcs11/pam_config.c (revision 237)
+++ src/pam_pkcs11/pam_config.c (working copy)
@@ -44,7 +44,7 @@
         0, /* int slot_num; */
  0, /* support threads */
  /* cert policy; */
-        { 0,CRLP_NONE,0,"/etc/pam_pkcs11/cacerts","/etc/pam_pkcs11/crls" },
+        { 0,CRLP_NONE,0,"/etc/pam_pkcs11/cacerts","/etc/pam_pkcs11/crls","/etc/pam_pkcs11/nssdb",OCSP_NONE },
  NULL /* char *username */
 };
 
@@ -58,10 +58,12 @@
         DBG1("slot_num %d",configuration.slot_num);
         DBG1("ca_dir %s",configuration.policy.ca_dir);
         DBG1("crl_dir %s",configuration.policy.crl_dir);
+        DBG1("nss_dir %s",configuration.policy.nss_dir);
         DBG1("support_threads %d",configuration.support_threads);
         DBG1("ca_policy %d",configuration.policy.ca_policy);
         DBG1("crl_policy %d",configuration.policy.crl_policy);
         DBG1("signature_policy %d",configuration.policy.signature_policy);
+        DBG1("ocsp_policy %d",configuration.policy.ocsp_policy);
 }
 
 /*
@@ -93,8 +95,8 @@
     scconf_get_bool(root,"nullok",configuration.nullok);
  configuration.debug =
     scconf_get_bool(root,"debug",configuration.debug);
- if (configuration.debug) set_debug_level(1);
- else set_debug_level(0);
+ /*if (configuration.debug) set_debug_level(1);
+ else set_debug_level(0); */
  configuration.use_first_pass =
     scconf_get_bool(root,"use_first_pass",configuration.use_first_pass);
  configuration.try_first_pass =
@@ -119,6 +121,8 @@
         scconf_get_str(pkcs11_mblk,"ca_dir",configuration.policy.ca_dir);
     configuration.policy.crl_dir = (char *)
         scconf_get_str(pkcs11_mblk,"crl_dir",configuration.policy.crl_dir);
+    configuration.policy.nss_dir = (char *)
+        scconf_get_str(pkcs11_mblk,"nss_dir",configuration.policy.nss_dir);
     configuration.slot_num =
         scconf_get_int(pkcs11_mblk,"slot_num",configuration.slot_num);
     configuration.support_threads =
@@ -127,6 +131,7 @@
     while(policy_list) {
         if ( !strcmp(policy_list->data,"none") ) {
  configuration.policy.crl_policy=CRLP_NONE;
+ configuration.policy.ocsp_policy=OCSP_NONE;
  configuration.policy.ca_policy=0;
  configuration.policy.signature_policy=0;
  break;
@@ -136,6 +141,8 @@
  configuration.policy.crl_policy=CRLP_ONLINE;
  } else if ( !strcmp(policy_list->data,"crl_offline") ) {
  configuration.policy.crl_policy=CRLP_OFFLINE;
+ } else if ( !strcmp(policy_list->data,"ocsp_on") ) {
+ configuration.policy.ocsp_policy=OCSP_ON;
  } else if ( !strcmp(policy_list->data,"ca") ) {
  configuration.policy.ca_policy=1;
  } else if ( !strcmp(policy_list->data,"signature") ) {
@@ -218,11 +225,16 @@
  res=sscanf(argv[i],"crl_dir=%255s",configuration.policy.crl_dir);
  continue;
    }
+   if (strstr(argv[i],"nss_dir=") ) {
+ res=sscanf(argv[i],"nss_dir=%255s",configuration.policy.nss_dir);
+ continue;
+   }
    if (strstr(argv[i],"cert_policy=") ) {
  if (strstr(argv[i],"none")) {
  configuration.policy.crl_policy=CRLP_NONE;
  configuration.policy.ca_policy=0;
  configuration.policy.signature_policy=0;
+ configuration.policy.ocsp_policy=OCSP_NONE;
  }
  if (strstr(argv[i],"crl_online")) {
  configuration.policy.crl_policy=CRLP_ONLINE;
@@ -233,6 +245,9 @@
  if (strstr(argv[i],"crl_auto")) {
  configuration.policy.crl_policy=CRLP_AUTO;
  }
+ if ( strstr(argv[i],"ocsp_on") ) {
+ configuration.policy.ocsp_policy=OCSP_ON;
+ }
  if (strstr(argv[i],"ca")) {
  configuration.policy.ca_policy=1;
  }
Index: src/pam_pkcs11/Makefile.am
===================================================================
--- src/pam_pkcs11/Makefile.am (revision 237)
+++ src/pam_pkcs11/Makefile.am (working copy)
@@ -2,7 +2,8 @@
 
 MAINTAINERCLEANFILES = Makefile.in
 
-AM_CFLAGS = -Wall -fno-strict-aliasing $(OPENSSL_CFLAGS)
+AM_CFLAGS = -Wall -fno-strict-aliasing $(CRYPTO_CFLAGS)
+AM_CPPFLAGS = -Wall -fno-strict-aliasing $(CRYPTO_CFLAGS)
 
 lib_LTLIBRARIES = pam_pkcs11.la
 
@@ -10,7 +11,7 @@
  mapper_mgr.c mapper_mgr.h \
  pam_config.c pam_config.h
 pam_pkcs11_la_LDFLAGS = -module -avoid-version
-pam_pkcs11_la_LIBADD = $(LIBMAPPERS) $(OPENSSL_LIBS)
+pam_pkcs11_la_LIBADD = $(LIBMAPPERS) $(CRYPTO_LIBS)
 
 install:      
  $(mkinstalldirs) $(DESTDIR)/$(libdir)/security
Index: src/pam_pkcs11/mapper_mgr.c
===================================================================
--- src/pam_pkcs11/mapper_mgr.c (revision 237)
+++ src/pam_pkcs11/mapper_mgr.c (working copy)
@@ -29,7 +29,7 @@
 
 #include <stdlib.h>
 #include <dlfcn.h>
-#include <openssl/x509.h>
+#include "../common/cert_st.h"
 
 #include "../scconf/scconf.h"
 #include "../common/debug.h"
Index: src/tools/pkcs11_listcerts.c
===================================================================
--- src/tools/pkcs11_listcerts.c (revision 237)
+++ src/tools/pkcs11_listcerts.c (working copy)
@@ -24,11 +24,9 @@
 #include <string.h>
 #include <errno.h>
 #include <unistd.h>
-#include <openssl/x509.h>
 #include "../scconf/scconf.h"
 #include "../common/debug.h"
 #include "../common/error.h"
-#include "../common/rsaref/pkcs11.h"
 #include "../common/pkcs11_lib.h"
 #include "../common/cert_info.h"
 #include "../pam_pkcs11/pam_config.h"
@@ -39,7 +37,8 @@
   int ncerts;
   unsigned int slot_num = 0;
   struct configuration_st *configuration;
-  pkcs11_handle_t ph;
+  pkcs11_handle_t *ph;
+  cert_object_t **certs;
 
   /* first of all check whether debugging should be enabled */
   for (i = 0; i < argc; i++)
@@ -55,8 +54,11 @@
   }
 
   /* init openssl */
-  OpenSSL_add_all_algorithms();
-  ERR_load_crypto_strings();
+  rv = crypto_init(&configuration->policy);
+  if (rv != 0) {
+    DBG("Couldn't initialize crypto module ");
+    return 1;
+  }
 
   /* load pkcs #11 module */
   DBG("loading pkcs #11 module...");
@@ -68,57 +70,57 @@
 
   /* initialise pkcs #11 module */
   DBG("initialising pkcs #11 module...");
-  rv = init_pkcs11_module(&ph,configuration->support_threads);
+  rv = init_pkcs11_module(ph,configuration->support_threads);
   if (rv != 0) {
-    release_pkcs11_module(&ph);
+    release_pkcs11_module(ph);
     DBG1("init_pkcs11_module() failed: %s", get_error());
     return 1;
   }
 
   /* open pkcs #11 session */
-  slot_num= configuration->slot_num;
-  if (slot_num == 0) {
-    DBG("using the first slot with an available token");
-    for (slot_num = 0; slot_num < ph.slot_count && !ph.slots[slot_num].token_present; slot_num++);
-    if (slot_num >= ph.slot_count) {
-      release_pkcs11_module(&ph);
-      DBG("no token available");
-      return 1;
-    }
-  } else {
-    slot_num--;
+  rv = find_slot_by_number(ph, configuration->slot_num, &slot_num);
+  if (rv != 0) {
+    release_pkcs11_module(ph);
+    DBG("no token available");
+    return 1;
   }
-  rv = open_pkcs11_session(&ph, slot_num);
+
+  rv = open_pkcs11_session(ph, slot_num);
   if (rv != 0) {
-    release_pkcs11_module(&ph);
+    release_pkcs11_module(ph);
     DBG1("open_pkcs11_session() failed: %s", get_error());
     return 1;
   }
 
-  /* get certificate list */
-  rv = get_certificates(&ph);
-  if (rv<0) {
-    close_pkcs11_session(&ph);
-    release_pkcs11_module(&ph);
-    DBG1("get_certificates() failed: %s", get_error());
-    return 3;
-  }
-
   /* do login */
-  rv= pkcs11_pass_login(&ph,configuration->nullok);
+  rv = pkcs11_pass_login(ph,configuration->nullok);
   if (rv<0){
     DBG1("Login failed: %s",get_error());
     return 4;
   }
 
+  /* get certificate list */
+  certs = get_certificate_list(ph, &ncerts);
+  if (certs == NULL) {
+    close_pkcs11_session(ph);
+    release_pkcs11_module(ph);
+    DBG1("get_certificates() failed: %s", get_error());
+    return 3;
+  }
+
   /* print some info on found certificates */
-  DBG1("Found '%d' certificate(s)",ph.cert_count);
-  for(i =0; i<ph.cert_count;i++) {
-    X509 *cert=ph.certs[i].x509;
+  DBG1("Found '%d' certificate(s)", ncerts);
+  for(i =0; i< ncerts;i++) {
+    char **name;
+    X509 *cert=get_X509_certificate(certs[i]);
+    
     DBG1("Certificate #%d:", i+1);
-    DBG1("- Subject:   %s", X509_NAME_oneline(X509_get_subject_name(cert), NULL, 0));
-    DBG1("- Issuer:    %s", X509_NAME_oneline(X509_get_issuer_name(cert), NULL, 0));
-    DBG1("- Algorithm: %s", OBJ_nid2ln(OBJ_obj2nid(cert->cert_info->key->algor->algorithm)));
+    name = cert_info(cert, CERT_SUBJECT, ALGORITHM_NULL);
+    DBG1("- Subject:   %s", name[0]); free(name[0]);
+    name = cert_info(cert, CERT_ISSUER, ALGORITHM_NULL);
+    DBG1("- Issuer:    %s", name[0]); free(name[0]);
+    name = cert_info(cert, CERT_KEY_ALG, ALGORITHM_NULL);
+    DBG1("- Algorithm: %s", name[0]); free(name[0]);
     rv = verify_certificate(cert,&configuration->policy);
     if (rv < 0) {
         DBG1("verify_certificate() process error: %s", get_error());
@@ -127,31 +129,30 @@
         DBG1("verify_certificate() failed: %s", get_error());
         continue; /* try next certificate */
     }
-    ph.choosen_cert=&ph.certs[i];
-    rv = get_private_key(&ph);
+    rv = get_private_key(ph, certs[i]);
     if (rv<0) {
  DBG1("Certificate '%d'does not have associated private key",i+1);
     }
   } /* for */
 
   /* close pkcs #11 session */
-  rv = close_pkcs11_session(&ph);
+  rv = close_pkcs11_session(ph);
   if (rv != 0) {
-    release_pkcs11_module(&ph);
+    release_pkcs11_module(ph);
     DBG1("close_pkcs11_session() failed: %s", get_error());
     return 4;
   }
 
   /* release pkcs #11 module */
   DBG("releasing pkcs #11 module...");
-  release_pkcs11_module(&ph);
+  release_pkcs11_module(ph);
 
   DBG("Process completed");
   return 0;
 
 auth_failed:
-  close_pkcs11_session(&ph);
-  release_pkcs11_module(&ph);
+  close_pkcs11_session(ph);
+  release_pkcs11_module(ph);
   return 5;
 
 }
Index: src/tools/pkcs11_inspect.c
===================================================================
--- src/tools/pkcs11_inspect.c (revision 237)
+++ src/tools/pkcs11_inspect.c (working copy)
@@ -27,7 +27,6 @@
 #include "../scconf/scconf.h"
 #include "../common/debug.h"
 #include "../common/error.h"
-#include "../common/rsaref/pkcs11.h"
 #include "../common/pkcs11_lib.h"
 #include "../common/cert_vfy.h"
 #include "../pam_pkcs11/pam_config.h"
@@ -35,9 +34,11 @@
 
 int main(int argc, const char **argv) {
   int i, rv;
-  pkcs11_handle_t ph;
+  pkcs11_handle_t *ph;
   struct configuration_st *configuration;
   unsigned int slot_num = 0;
+  cert_object_t **certs;
+  int cert_count;
 
   /* first of all check whether debugging should be enabled */
   for (i = 0; i < argc; i++)
@@ -53,8 +54,11 @@
   }
 
   /* init openssl */
-  OpenSSL_add_all_algorithms();
-  ERR_load_crypto_strings();
+  rv = crypto_init(&configuration->policy);
+  if (rv != 0) {
+    DBG1("crypto_init() failed: %s", get_error());
+    return 1;
+  }
 
   /* load pkcs #11 module */
   DBG("loading pkcs #11 module...");
@@ -67,47 +71,42 @@
 
   /* initialise pkcs #11 module */
   DBG("initialising pkcs #11 module...");
-  rv = init_pkcs11_module(&ph,configuration->support_threads);
+  rv = init_pkcs11_module(ph,configuration->support_threads);
   if (rv != 0) {
-    release_pkcs11_module(&ph);
+    release_pkcs11_module(ph);
     DBG1("init_pkcs11_module() failed: %s", get_error());
     return 1;
   }
 
   /* open pkcs #11 session */
-  slot_num= configuration->slot_num;
-  if (slot_num == 0) {
-    DBG("using the first slot with an available token");
-    for (slot_num = 0; slot_num < ph.slot_count && !ph.slots[slot_num].token_present; slot_num++);
-    if (slot_num >= ph.slot_count) {
-      release_pkcs11_module(&ph);
-      ERR("no token available");
-      return 1;
-    }
-  } else {
-    slot_num--;
+  rv = find_slot_by_number(ph, configuration->slot_num, &slot_num);
+  if (rv != 0) {
+    release_pkcs11_module(ph);
+    DBG("no token available");
+    return 1;
   }
-  rv = open_pkcs11_session(&ph, slot_num);
+
+  rv = open_pkcs11_session(ph, slot_num);
   if (rv != 0) {
-    release_pkcs11_module(&ph);
+    release_pkcs11_module(ph);
     ERR1("open_pkcs11_session() failed: %s", get_error());
     return 1;
   }
 
-#if 0
+#if HAVE_NSS
   /* not really needed, but.... */
-  rv = pkcs11_pass_login(&ph,configuration->nullok);
+  rv = pkcs11_pass_login(ph,configuration->nullok);
   if (rv != 0) {
     ERR1("pkcs11_pass_login() failed: %s", get_error());
     return 2;
   }
 #endif
 
-  /* get certificate list */
-  rv = get_certificates(&ph);
-  if (rv<0) {
-    close_pkcs11_session(&ph);
-    release_pkcs11_module(&ph);
+  /* get certificate list (cert space is owned by ph) */
+  certs = get_certificate_list(ph, &cert_count);
+  if (certs == NULL) {
+    close_pkcs11_session(ph);
+    release_pkcs11_module(ph);
     ERR1("get_certificates() failed: %s", get_error());
     return 3;
   }
@@ -116,16 +115,16 @@
   load_mappers(configuration->ctx);
 
   /* find valid certificates and look for contents */
-  DBG1("Found '%d' certificate(s)",ph.cert_count);
-  for (i = 0; i < ph.cert_count; i++) {
-    X509 *x509 = ph.certs[i].x509;
+  DBG1("Found '%d' certificate(s)", cert_count);
+  for (i = 0; i < cert_count; i++) {
+    X509 *x509 = get_X509_certificate(certs[i]);
     if (x509 != NULL) {
       DBG1("verifing the certificate #%d", i + 1);
       /* verify certificate (date, signature, CRL, ...) */
       rv = verify_certificate(x509, &configuration->policy);
       if (rv < 0) {
-        close_pkcs11_session(&ph);
-        release_pkcs11_module(&ph);
+        close_pkcs11_session(ph);
+        release_pkcs11_module(ph);
  unload_mappers();
         ERR1("verify_certificate() failed: %s", get_error());
         return 1;
@@ -143,16 +142,16 @@
   unload_mappers();
 
   /* close pkcs #11 session */
-  rv = close_pkcs11_session(&ph);
+  rv = close_pkcs11_session(ph);
   if (rv != 0) {
-    release_pkcs11_module(&ph);
+    release_pkcs11_module(ph);
     ERR1("close_pkcs11_session() failed: %s", get_error());
     return 1;
   }
 
   /* release pkcs #11 module */
   DBG("releasing pkcs #11 module...");
-  release_pkcs11_module(&ph);
+  release_pkcs11_module(ph);
 
   DBG("Process completed");
   return 0;
Index: src/tools/Makefile.am
===================================================================
--- src/tools/Makefile.am (revision 237)
+++ src/tools/Makefile.am (working copy)
@@ -4,7 +4,7 @@
 
 FINDER_OBJS =  ../pam_pkcs11/mapper_mgr.o ../pam_pkcs11/pam_config.o
 
-INCLUDES = $(PCSC_CFLAGS) $(OPENSSL_CFLAGS)
+INCLUDES = $(PCSC_CFLAGS) $(CRYPTO_CFLAGS)
 AM_LDFLAGS = $(PCSC_LIBS)
 
 if HAVE_PCSC
@@ -16,13 +16,13 @@
 endif
 
 pklogin_finder_SOURCES = pklogin_finder.c
-pklogin_finder_LDADD = $(FINDER_OBJS) $(LIBMAPPERS)
+pklogin_finder_LDADD = $(FINDER_OBJS) $(LIBMAPPERS)
 
 pkcs11_listcerts_SOURCES = pkcs11_listcerts.c
 pkcs11_listcerts_LDADD = ../pam_pkcs11/pam_config.o $(LIBSCCONF) $(LIBCOMMON) $(OPENSSL_LIBS)
 
 pkcs11_eventmgr_SOURCES = pkcs11_eventmgr.c
-pkcs11_eventmgr_LDADD = $(LIBSCCONF) $(LIBCOMMON) $(OPENSSL_LIBS)
+pkcs11_eventmgr_LDADD = $(LIBSCCONF) $(LIBCOMMON) $(CRYPTO_LIBS)
 
 pkcs11_inspect_SOURCES = pkcs11_inspect.c
 pkcs11_inspect_LDADD = $(FINDER_OBJS) $(LIBMAPPERS)
Index: src/tools/pkcs11_eventmgr.c
===================================================================
--- src/tools/pkcs11_eventmgr.c (revision 237)
+++ src/tools/pkcs11_eventmgr.c (working copy)
@@ -26,7 +26,6 @@
 #include <sys/wait.h>
 
 #include "../scconf/scconf.h"
-#include "../common/rsaref/pkcs11.h"
 #include "../common/pkcs11_lib.h"
 #include "../common/debug.h"
 #include "../common/error.h"
@@ -50,27 +49,61 @@
 int daemonize;
 int debug;
 char *cfgfile;
-char *pkcs11_module;
+char *pkcs11_module = NULL;
+#ifdef HAVE_NSS
+char *nss_dir = NULL;
+#endif
 
 scconf_context *ctx;
 const scconf_block *root;
 
-pkcs11_handle_t ph;
+#ifdef HAVE_NSS
+SECMODModule *module;
+#else
+#include "../common/rsaref/pkcs11.h"
+pkcs11_handle_t *ph;
 
+typedef struct slot_st slot_t;
+
+/* The direct calls should be abstracted, for now "expose" the pkcs11_handle_t */
+struct pkcs11_handle_str {
+  void *module_handle;
+  CK_FUNCTION_LIST_PTR fl;
+  slot_t *slots;
+  CK_ULONG slot_count;
+  CK_SESSION_HANDLE session;
+  cert_object_t *keys;
+  int key_count;
+  int current_slot;
+};
+
+#endif
+
 void thats_all_folks() {
     int rv;
     DBG("Exitting");
+#ifdef HAVE_NSS
+    if (module) {
+ SECMOD_DestroyModule(module);
+    }
+    rv = NSS_Shutdown();
+    if (rv != SECSuccess) {
+      DBG("NSS Shutdown failed");
+      return;
+    }
+#else
     /* close pkcs #11 session */
-    rv = close_pkcs11_session(&ph);
+    rv = close_pkcs11_session(ph);
     if (rv != 0) {
-      release_pkcs11_module(&ph);
+      release_pkcs11_module(ph);
       DBG1("close_pkcs11_session() failed: %s", get_error());
       return;
     }
 
     /* release pkcs #11 module */
     DBG("releasing pkcs #11 module...");
-    release_pkcs11_module(&ph);
+    release_pkcs11_module(ph);
+#endif
     return;
 }
 
@@ -174,6 +207,9 @@
  polling_time = scconf_get_int(root,"polling_time",polling_time);
  expire_time = scconf_get_int(root,"expire_time",expire_time);
  pkcs11_module = (char *) scconf_get_str(root,"pkcs11_module",pkcs11_module);
+#ifdef HAVE_NSS
+ nss_dir = (char *) scconf_get_str(root,"nss_dir",nss_dir);
+#endif
  if (debug) set_debug_level(1);
  return 0;
 }
@@ -226,6 +262,12 @@
                 pkcs11_module=1+strchr(argv[i],'=');
                 continue;
             }
+#ifdef HAVE_NSS
+            if (strstr(argv[i],"nss_dir=") ) {
+                nss_dir=1+strchr(argv[i],'=');
+                continue;
+            }
+#endif
             if (strstr(argv[i],"debug") ) {
  continue;  /* already parsed: skip */
     }
@@ -247,6 +289,61 @@
  return 0;
 }
 
+#ifdef HAVE_NSS
+struct SlotStatusStr {
+    CK_SLOT_ID slotID;
+    PRUint32 series;
+    int present;
+};
+
+struct SlotStatusStr *slotStatus = NULL;
+int slotCount = 0;
+int maxEntries = 0;
+
+int
+do_expand_slot_status(void)
+{
+#define ENTRY_STEP 10
+    struct SlotStatusStr *tmp;
+    tmp = (struct SlotStatusStr *)
+    realloc(slotStatus,
+ (maxEntries+ENTRY_STEP)*sizeof(struct SlotStatusStr));
+    if (!tmp) {
+ return 0;
+    }
+    slotStatus = tmp;
+    maxEntries += ENTRY_STEP;
+    return 1;
+}
+
+struct SlotStatusStr *
+get_token_status(CK_SLOT_ID slotID)
+{
+    /* linear search is ok for modules with few slots, if we have modules with
+     * thousands of slots or more, we would need to revisit this */
+    int i;
+
+    for (i=0; i < slotCount; i++) {
+ if (slotStatus[i].slotID == slotID) {
+ return &slotStatus[i];
+ }
+    }
+    if (slotCount >=  maxEntries) {
+ if (!do_expand_slot_status()) {
+    return NULL;
+ }
+    }
+
+
+    i = slotCount++;
+    slotStatus[i].slotID = slotID;
+    slotStatus[i].present = 0;
+    slotStatus[i].series = 0;
+    return &slotStatus[i];
+}
+
+
+#else
 /*
 * try to find a valid token from slot list
 * returns CARD_PRESENT, CARD_NOT_PRESENT or CARD_ERROR
@@ -255,7 +352,7 @@
     int rv;
     unsigned long num_tokens=0;
     /* get Number of of slots with valid tokens */
-    rv = ph.fl->C_GetSlotList(TRUE, NULL, &num_tokens);
+    rv = ph->fl->C_GetSlotList(TRUE, NULL, &num_tokens);
     if (rv != CKR_OK) {
         DBG1("C_GetSlotList() failed: %x", rv);
         return CARD_ERROR;
@@ -264,8 +361,133 @@
     if (num_tokens>0) return CARD_PRESENT;
     return CARD_NOT_PRESENT;
 }
+#endif
 
 int main(int argc, char *argv[]) {
+#ifdef HAVE_NSS
+    SECStatus rv;
+
+    /* parse args and configuration file */
+    parse_args(argc,argv);
+
+    DBG("Initializing NSS ...");
+    if (nss_dir) {
+ /* initialize with read only databases */
+ rv = NSS_Init(nss_dir);
+    } else {
+ /* not database secified */
+ rv = NSS_NoDB_Init(NULL);
+    }
+
+    if (rv != SECSuccess) {
+        DBG("NSS_Initialize failed.");
+ return 1;
+    }
+
+    /* acquire the module before we daemonize so we can return an error
+     * to the user if it fails */
+    DBG("loading the module ...");
+    if (pkcs11_module) {
+#define SPEC_TEMPLATE "library=\"%s\" name=\"SmartCard\""
+ char *moduleSpec =
+ (char *)malloc(sizeof(SPEC_TEMPLATE) + strlen(pkcs11_module));
+ if (!moduleSpec) {
+    DBG1("Malloc failed when allocating module spec", strerror(errno));
+    return 1;
+ }
+ sprintf(moduleSpec,SPEC_TEMPLATE, pkcs11_module);
+ DBG2("loading Module explictly, moduleSpec=<%s> module=%s\n",
+ moduleSpec, pkcs11_module);
+ module = SECMOD_LoadUserModule(moduleSpec, NULL, 0);
+ free(moduleSpec);
+ if (!module) {
+    DBG("Failed to load SmartCard software");
+    return 1;
+ }
+    } else {
+     /* no module specified? look for one in the our of NSS's
+         * secmod.db */
+ SECMODModuleList *modList = SECMOD_GetDefaultModuleList();
+
+ /* threaded applications should also acquire the
+ * DefaultModuleListLock */
+ DBG("Looking up new module\n");
+ for ( ; modList; modList->next) {
+    if (SECMOD_HasRemovableSlots(modList->module)) {
+ module = SECMOD_ReferenceModule(modList->module);
+ break;
+    }
+ }
+ if (!module) {
+    DBG("Failed to find any SmartCard software");
+    return 1;
+ }
+    }
+
+    if (daemonize) {
+ DBG("Going to be daemon...");
+ if ( daemon(0,debug)<0 ) {
+ DBG1("Error in daemon() call", strerror(errno));
+ SECMOD_DestroyModule(module);
+         rv = NSS_Shutdown();
+ if (ctx) scconf_free(ctx);
+ return 1;
+ }
+    }
+
+    /*
+     * Wait endlessly for all events in the list of readers
+     * We only stop in case of an error
+     *
+     */
+    DBG("Waiting for Events");
+    do {
+ /* wait for any token uses C_WaitForSlotEvent if the token supports it.
+ * otherwise it polls by hand*/
+ struct SlotStatusStr *slotStatus;
+ PK11SlotInfo *slot = SECMOD_WaitForAnyTokenEvent(module, 0,
+ PR_SecondsToInterval(polling_time));
+
+ /* exit on an error */
+ if (slot == NULL) {
+    break;
+ }
+
+ /* examine why we got the event */
+ slotStatus = get_token_status(PK11_GetSlotID(slot));
+
+ /* if the slot is present, see if it was just removed */
+ if (PK11_IsPresent(slot)) {
+   PRUint32 series = PK11_GetSlotSeries(slot);
+
+   /* skip spurious insert events */
+   if (series != slotStatus->series) {
+#ifdef notdef
+ /* if one was already present, remove it
+ * This can happen if you pull the token and insert it
+ * before the PK11_IsPresent call above */
+ if (slotStatus->present) {
+                    DBG("Card removed, ");
+    execute_event("card_remove");
+ }
+#endif
+ DBG("Card inserted, ");
+ execute_event("card_insert");
+   }
+   slotStatus->series = series;
+   slotStatus->present = 1;
+ } else {
+   if (slotStatus->present) {
+ DBG("Card removed, ");
+ execute_event("card_remove");
+   }
+   slotStatus->series = 0;
+   slotStatus->present = 0;
+ }
+ PK11_FreeSlot(slot);
+    } while(1);
+
+#else
     int rv;
 
     int first_loop   = 0;
@@ -275,10 +497,9 @@
 
     /* parse args and configuration file */
     parse_args(argc,argv);
-
     /* load pkcs11 module */
     DBG("loading pkcs #11 module...");
-    rv = load_pkcs11_module(pkcs11_module, &ph);
+    rv = load_pkcs11_module(pkcs11_module, ph);
     if (rv != 0) {
         DBG1("load_pkcs11_module() failed: %s", get_error());
         return 1;
@@ -286,9 +507,9 @@
 
     /* open pkcs11 sesion */
     DBG("initialising pkcs #11 module...");
-    rv = ph.fl->C_Initialize(NULL);
+    rv = ph->fl->C_Initialize(NULL);
     if (rv != 0) {
-        release_pkcs11_module(&ph);
+        release_pkcs11_module(ph);
         DBG1("C_Initialize() failed: %d", rv);
         return 1;
     }
@@ -298,7 +519,7 @@
  DBG("Going to be daemon...");
  if ( daemon(0,debug)<0 ) {
  DBG1("Error in daemon() call: %s", strerror(errno));
-         release_pkcs11_module(&ph);
+         release_pkcs11_module(ph);
  if (ctx) scconf_free(ctx);
  return 1;
  }
@@ -349,8 +570,8 @@
  re-initialize library on card removal
  */    
      DBG("Re-initialising pkcs #11 module...");
-     rv = ph.fl->C_Finalize(NULL);
-     rv = ph.fl->C_Initialize(NULL);
+     rv = ph->fl->C_Finalize(NULL);
+     rv = ph->fl->C_Initialize(NULL);
                }
                if (new_state == CARD_PRESENT) {
                     DBG("Card inserted, ");
@@ -358,6 +579,7 @@
                }
            }
     } while (1);
+#endif
     /* If we get here means that an error or exit status occurred */
     DBG("Exited from main loop");
     thats_all_folks();
Index: src/tools/pklogin_finder.c
===================================================================
--- src/tools/pklogin_finder.c (revision 237)
+++ src/tools/pklogin_finder.c (working copy)
@@ -27,7 +27,6 @@
 #include "../scconf/scconf.h"
 #include "../common/debug.h"
 #include "../common/error.h"
-#include "../common/rsaref/pkcs11.h"
 #include "../common/pkcs11_lib.h"
 #include "../common/cert_vfy.h"
 #include "../pam_pkcs11/pam_config.h"
@@ -36,8 +35,10 @@
 int main(int argc, const char **argv) {
   int i, rv;
   char *user;
-  pkcs11_handle_t ph;
+  pkcs11_handle_t *ph;
   struct configuration_st *configuration;
+  cert_object_t **certs;
+  int cert_count;
   unsigned int slot_num = 0;
 
 
@@ -55,8 +56,11 @@
   }
 
   /* init openssl */
-  OpenSSL_add_all_algorithms();
-  ERR_load_crypto_strings();
+  rv = crypto_init(&configuration->policy);
+  if (rv != 0) {
+    DBG("Couldn't initialize crypto module ");
+    return 1;
+  }
 
   /* load pkcs #11 module */
   DBG("loading pkcs #11 module...");
@@ -68,36 +72,30 @@
 
   /* initialise pkcs #11 module */
   DBG("initialising pkcs #11 module...");
-  rv = init_pkcs11_module(&ph,configuration->support_threads);
+  rv = init_pkcs11_module(ph,configuration->support_threads);
   if (rv != 0) {
-    release_pkcs11_module(&ph);
+    release_pkcs11_module(ph);
     DBG1("init_pkcs11_module() failed: %s", get_error());
     return 1;
   }
 
   /* open pkcs #11 session */
-  slot_num= configuration->slot_num;
-  if (slot_num == 0) {
-    DBG("using the first slot with an available token");
-    for (slot_num = 0; slot_num < ph.slot_count && !ph.slots[slot_num].token_present; slot_num++);
-    if (slot_num >= ph.slot_count) {
-      release_pkcs11_module(&ph);
-      DBG("no token available");
-      return 1;
-    }
-  } else {
-    slot_num--;
+  rv = find_slot_by_number(ph,configuration->slot_num, &slot_num);
+  if (rv != 0) {
+    release_pkcs11_module(ph);
+    DBG("no token available");
+    return 1;
   }
-  rv = open_pkcs11_session(&ph, slot_num);
+  rv = open_pkcs11_session(ph, slot_num);
   if (rv != 0) {
-    release_pkcs11_module(&ph);
+    release_pkcs11_module(ph);
     DBG1("open_pkcs11_session() failed: %s", get_error());
     return 1;
   }
 
-#if 0
+#ifdef HAVE_NSS
   /* not really needed, but... */
-  rv = pkcs11_pass_login(&ph,configuration->nullok);
+  rv = pkcs11_pass_login(ph,configuration->nullok);
   if (rv != 0) {
     DBG1("pkcs11_pass_login() failed: %s", get_error());
     return 2;
@@ -105,11 +103,11 @@
 #endif
 
   /* get certificate list */
-  rv = get_certificates(&ph);
-  if (rv<0) {
-    close_pkcs11_session(&ph);
-    release_pkcs11_module(&ph);
-    DBG1("get_certificates() failed: %s", get_error());
+  certs = get_certificate_list(ph, &cert_count);
+  if (certs == NULL) {
+    close_pkcs11_session(ph);
+    release_pkcs11_module(ph);
+    DBG1("get_certificate_list() failed: %s", get_error());
     return 3;
   }
 
@@ -117,16 +115,16 @@
   load_mappers(configuration->ctx);
 
   /* find a valid and matching certificates */
-  DBG1("Found '%d' certificate(s)",ph.cert_count);
-  for (i = 0; i < ph.cert_count; i++) {
-    X509 *x509 = ph.certs[i].x509;
+  DBG1("Found '%d' certificate(s)", cert_count);
+  for (i = 0; i < cert_count; i++) {
+    X509 *x509 = get_X509_certificate(certs[i]);
     if (x509 != NULL) {
       DBG1("verifing the certificate #%d", i + 1);
       /* verify certificate (date, signature, CRL, ...) */
       rv = verify_certificate(x509,&configuration->policy);
       if (rv < 0) {
-        close_pkcs11_session(&ph);
-        release_pkcs11_module(&ph);
+        close_pkcs11_session(ph);
+        release_pkcs11_module(ph);
         unload_mappers();
         DBG1("verify_certificate() failed: %s", get_error());
         return 1;
@@ -151,16 +149,16 @@
   unload_mappers(); /* no longer needed */
 
   /* close pkcs #11 session */
-  rv = close_pkcs11_session(&ph);
+  rv = close_pkcs11_session(ph);
   if (rv != 0) {
-    release_pkcs11_module(&ph);
+    release_pkcs11_module(ph);
     DBG1("close_pkcs11_session() failed: %s", get_error());
     return 1;
   }
 
   /* release pkcs #11 module */
   DBG("releasing pkcs #11 module...");
-  release_pkcs11_module(&ph);
+  release_pkcs11_module(ph);
 
   DBG("Process completed");
   return (!user)? 1:0;
Index: src/mappers/pwent_mapper.c
===================================================================
--- src/mappers/pwent_mapper.c (revision 237)
+++ src/mappers/pwent_mapper.c (working copy)
@@ -28,9 +28,7 @@
 
 #include <pwd.h>
 #include <sys/types.h>
-#include <openssl/objects.h>
-#include <openssl/err.h>
-#include <openssl/x509v3.h>
+#include "../common/cert_st.h"
 #include "../scconf/scconf.h"
 #include "../common/debug.h"
 #include "../common/error.h"
@@ -54,7 +52,7 @@
 * Returns the common name of certificate as an array list
 */
 static char ** pwent_mapper_find_entries(X509 *x509, void *context) {
-        char **entries= cert_info(x509,CERT_CN,NULL);
+        char **entries= cert_info(x509,CERT_CN,ALGORITHM_NULL);
         if (!entries) {
                 DBG("get_common_name() failed");
                 return NULL;
@@ -68,7 +66,7 @@
 static char * pwent_mapper_find_user(X509 *x509,void *context) {
         char *str;
  char *found_user = NULL;
-        char **entries  = cert_info(x509,CERT_CN,NULL);
+        char **entries  = cert_info(x509,CERT_CN,ALGORITHM_NULL);
         if (!entries) {
             DBG("get_common_name() failed");
             return NULL;
@@ -100,7 +98,7 @@
 static int pwent_mapper_match_user(X509 *x509, const char *login, void *context) {
         char *str;
  struct passwd *pw = getpwnam(login);
-        char **entries  = cert_info(x509,CERT_CN,NULL);
+        char **entries  = cert_info(x509,CERT_CN,ALGORITHM_NULL);
         if (!entries) {
             DBG("get_common_name() failed");
             return -1;
Index: src/mappers/cn_mapper.c
===================================================================
--- src/mappers/cn_mapper.c (revision 237)
+++ src/mappers/cn_mapper.c (working copy)
@@ -26,7 +26,7 @@
 #include <config.h>
 #endif
 
-#include <openssl/x509.h>
+#include "../common/cert_st.h"
 #include "../scconf/scconf.h"
 #include "../common/debug.h"
 #include "../common/error.h"
@@ -49,7 +49,7 @@
 * Return array of found CN's
 */
 static char ** cn_mapper_find_entries(X509 *x509, void *context) {
-        char **entries= cert_info(x509,CERT_CN,NULL);
+        char **entries= cert_info(x509,CERT_CN,ALGORITHM_NULL);
         if (!entries) {
                 DBG("get_common_name() failed");
                 return NULL;
@@ -62,7 +62,7 @@
 */
 static char * cn_mapper_find_user(X509 *x509, void *context) {
         char *res;
-        char **entries= cert_info(x509,CERT_CN,NULL);
+        char **entries= cert_info(x509,CERT_CN,ALGORITHM_NULL);
         if (!entries) {
             DBG("get_common_name() failed");
             return NULL;
@@ -83,7 +83,7 @@
 static int cn_mapper_match_user(X509 *x509,const char *login, void *context) {
         char *str;
         int match_found = 0;
-        char **entries  = cert_info(x509,CERT_CN,NULL);
+        char **entries  = cert_info(x509,CERT_CN,ALGORITHM_NULL);
         if (!entries) {
             DBG("get_common_name() failed");
             return -1;
Index: src/mappers/null_mapper.c
===================================================================
--- src/mappers/null_mapper.c (revision 237)
+++ src/mappers/null_mapper.c (working copy)
@@ -26,7 +26,7 @@
 #include <config.h>
 #endif
 
-#include <openssl/x509.h>
+#include "../common/cert_st.h"
 #include "../scconf/scconf.h"
 #include "../common/debug.h"
 #include "../common/error.h"
Index: src/mappers/generic_mapper.c
===================================================================
--- src/mappers/generic_mapper.c (revision 237)
+++ src/mappers/generic_mapper.c (working copy)
@@ -26,8 +26,8 @@
 #include <config.h>
 #endif
 
-#include <openssl/evp.h>
-#include <openssl/x509.h>
+/*#include <openssl/evp.h> */
+#include "../common/cert_st.h"
 #include "../scconf/scconf.h"
 #include "../common/debug.h"
 #include "../common/error.h"
@@ -51,7 +51,7 @@
                 DBG("NULL certificate provided");
                 return NULL;
         }
- return cert_info(x509, id_type, NULL);
+ return cert_info(x509, id_type, ALGORITHM_NULL);
 }
 
 static char **get_mapped_entries(char **entries) {
Index: src/mappers/krb_mapper.c
===================================================================
--- src/mappers/krb_mapper.c (revision 237)
+++ src/mappers/krb_mapper.c (working copy)
@@ -26,7 +26,7 @@
 #include <config.h>
 #endif
 
-#include <openssl/x509v3.h>
+#include "../common/cert_st.h"
 #include "../scconf/scconf.h"
 #include "../common/debug.h"
 #include "../common/error.h"
@@ -53,7 +53,7 @@
 * Return array of found CN's
 */
 static char ** krb_mapper_find_entries(X509 *x509, void *context) {
-        char **entries= cert_info(x509,CERT_KPN,NULL);
+        char **entries= cert_info(x509,CERT_KPN,ALGORITHM_NULL);
         if (!entries) {
                 DBG("get_krb_principalname() failed");
                 return NULL;
@@ -65,7 +65,7 @@
 */
 static char * krb_mapper_find_user(X509 *x509, void *context) {
         char *res;
-        char **entries= cert_info(x509,CERT_KPN,NULL);
+        char **entries= cert_info(x509,CERT_KPN,ALGORITHM_NULL);
         if (!entries) {
             DBG("get_krb_principalname() failed");
             return NULL;
@@ -86,7 +86,7 @@
 static int krb_mapper_match_user(X509 *x509, const char *login, void *context) {
  char *str;
         int match_found = 0;
-        char **entries  = cert_info(x509,CERT_KPN,NULL);
+        char **entries  = cert_info(x509,CERT_KPN,ALGORITHM_NULL);
         if (!entries) {
             DBG("get_krb_principalname() failed");
             return -1;
Index: src/mappers/openssh_mapper.c
===================================================================
--- src/mappers/openssh_mapper.c (revision 237)
+++ src/mappers/openssh_mapper.c (working copy)
@@ -37,9 +37,11 @@
 #include <string.h>
 #include <errno.h>
 
-#include <openssl/x509.h>
+#include "../common/cert_st.h"
+#ifndef HAVE_NSS
 #include <openssl/evp.h>
 #include <openssl/bn.h>
+#endif
 
 #include "../scconf/scconf.h"
 #include "../common/debug.h"
@@ -65,6 +67,7 @@
 
 #define OPENSSH_LINE_MAX 8192 /* from openssh SSH_MAX_PUBKEY_BYTES */
 
+#ifndef HAVE_NSS
 static EVP_PKEY *ssh1_line_to_key(char *line) {
  EVP_PKEY *key;
  RSA *rsa;
@@ -221,12 +224,13 @@
  *keys = keys2;
  (*nkeys)++;
 }
+#endif
 
 /*
 * Returns the public key of certificate as an array list
 */
 static char ** openssh_mapper_find_entries(X509 *x509, void *context) {
-        char **entries= cert_info(x509,CERT_SSHPUK,NULL);
+        char **entries= cert_info(x509,CERT_SSHPUK,ALGORITHM_NULL);
         if (!entries) {
                 DBG("get_public_key() failed");
                 return NULL;
@@ -235,6 +239,9 @@
 }
 
 static int openssh_mapper_match_keys(X509 *x509, const char *filename) {
+#ifdef HAVE_NSS
+ return -1;
+#else
  FILE *fd;
  char line[OPENSSH_LINE_MAX];
  int i;
@@ -284,6 +291,7 @@
         }
         DBG("User authorized_keys file doesn't match cert public key(s)");
         return 0;
+#endif
 }
 
 _DEFAULT_MAPPER_END
Index: src/mappers/ldap_mapper.c
===================================================================
--- src/mappers/ldap_mapper.c (revision 237)
+++ src/mappers/ldap_mapper.c (working copy)
@@ -28,9 +28,9 @@
 #endif
 
 #include <ldap.h>
-#include <openssl/x509.h>
 #include <pwd.h>
 
+#include "../common/cert_st.h"
 #include "../common/debug.h"
 #include "../common/error.h"
 #include "../scconf/scconf.h"
@@ -184,7 +184,7 @@
 _DEFAULT_MAPPER_END
 
 static char ** ldap_mapper_find_entries(X509 *x509, void *context) {
-        char **entries= cert_info(x509,CERT_PEM,NULL);
+        char **entries= cert_info(x509,CERT_PEM,ALGORITHM_NULL);
         if (!entries) {
                 DBG("get_certificate() failed");
                 return NULL;
Index: src/mappers/uid_mapper.c
===================================================================
--- src/mappers/uid_mapper.c (revision 237)
+++ src/mappers/uid_mapper.c (working copy)
@@ -26,7 +26,7 @@
 #include <config.h>
 #endif
 
-#include <openssl/x509.h>
+#include "../common/cert_st.h"
 #include "../scconf/scconf.h"
 #include "../common/debug.h"
 #include "../common/error.h"
@@ -48,7 +48,7 @@
 * Return the list of UID's on this certificate
 */
 static char ** uid_mapper_find_entries(X509 *x509, void *context) {
- char **entries= cert_info(x509,CERT_UID,NULL);
+ char **entries= cert_info(x509,CERT_UID,ALGORITHM_NULL);
         if (!entries) {
                 DBG("get_unique_id() failed");
                 return NULL;
@@ -63,7 +63,7 @@
 */
 static char * uid_mapper_find_user(X509 *x509, void *context) {
  char *res;
- char **entries= cert_info(x509,CERT_UID,NULL);
+ char **entries= cert_info(x509,CERT_UID,ALGORITHM_NULL);
         if (!entries) {
             DBG("get_unique_id() failed");
             return NULL;
@@ -84,7 +84,7 @@
 static int uid_mapper_match_user(X509 *x509, const char *login, void *context) {
  char *str;
  int match_found = 0;
- char **entries  = cert_info(x509,CERT_UID,NULL);
+ char **entries  = cert_info(x509,CERT_UID,ALGORITHM_NULL);
         if (!entries) {
             DBG("get_unique_id() failed");
             return -1;
Index: src/mappers/mapper.h
===================================================================
--- src/mappers/mapper.h (revision 237)
+++ src/mappers/mapper.h (working copy)
@@ -31,7 +31,7 @@
 #include <stdlib.h>
 #include <string.h>
 #include <pwd.h>
-#include <openssl/x509.h>
+#include <../common/cert_st.h>
 #include "../scconf/scconf.h"
 
 /**
Index: src/mappers/opensc_mapper.c
===================================================================
--- src/mappers/opensc_mapper.c (revision 237)
+++ src/mappers/opensc_mapper.c (working copy)
@@ -39,10 +39,7 @@
 #include <string.h>
 #include <errno.h>
 
-#include <openssl/bn.h>
-#include <openssl/pem.h>
-#include <openssl/x509.h>
-
+#include "../common/cert_st.h"
 #include "../scconf/scconf.h"
 #include "../common/debug.h"
 #include "../common/error.h"
@@ -61,7 +58,7 @@
 * Return the list of certificates as an array list
 */
 static char ** opensc_mapper_find_entries(X509 *x509, void *context) {
-        char **entries= cert_info(x509,CERT_PEM,NULL);
+        char **entries= cert_info(x509,CERT_PEM,ALGORITHM_NULL);
         if (!entries) {
                 DBG("get_certificate() failed");
                 return NULL;
@@ -78,6 +75,10 @@
         char filename[PATH_MAX];
         X509 **certs;
         int ncerts, i, rc;
+#ifdef HAVE_NSS
+ /* still need to genericize the BIO functions here */
+ return -1;
+#else
         BIO *in;
 
         if (!x509) return -1;
@@ -109,6 +110,7 @@
             if (X509_cmp(certs[i],x509) == 0) return 1; /* Match found */
         }
         return 0; /* Don't match */
+#endif
 }
 
 static int opensc_mapper_match_user(X509 *x509, const char *user, void *context) {
Index: src/mappers/subject_mapper.c
===================================================================
--- src/mappers/subject_mapper.c (revision 237)
+++ src/mappers/subject_mapper.c (working copy)
@@ -26,9 +26,9 @@
 #include <config.h>
 #endif
 
-#include <openssl/objects.h>
-#include <openssl/err.h>
-#include <openssl/x509v3.h>
+/*#include <openssl/objects.h> */
+/*#include <openssl/err.h> */
+#include "../common/cert_st.h"
 #include "../scconf/scconf.h"
 #include "../common/debug.h"
 #include "../common/error.h"
@@ -45,7 +45,7 @@
 * returns the Certificate subject
 */
 static char ** subject_mapper_find_entries(X509 *x509, void *context) {
- char **entries= cert_info(x509,CERT_SUBJECT,NULL);
+ char **entries= cert_info(x509,CERT_SUBJECT,ALGORITHM_NULL);
  if (!entries) {
  DBG("X509_get_subject_name failed");
  return NULL;
@@ -57,7 +57,7 @@
 parses the certificate and return the first Subject entry found, or NULL
 */
 static char * subject_mapper_find_user(X509 *x509, void *context) {
- char **entries = cert_info(x509,CERT_SUBJECT,NULL);
+ char **entries = cert_info(x509,CERT_SUBJECT,ALGORITHM_NULL);
  if (!entries) {
  DBG("X509_get_subject_name failed");
  return NULL;
@@ -70,7 +70,7 @@
 * with provided user
 */
 static int subject_mapper_match_user(X509 *x509, const char *login, void *context) {
- char **entries = cert_info(x509,CERT_SUBJECT,NULL);
+ char **entries = cert_info(x509,CERT_SUBJECT,ALGORITHM_NULL);
  if (!entries) {
  DBG("X509_get_subject_name failed");
  return -1;
Index: src/mappers/ms_mapper.c
===================================================================
--- src/mappers/ms_mapper.c (revision 237)
+++ src/mappers/ms_mapper.c (working copy)
@@ -26,7 +26,7 @@
 #include <config.h>
 #endif
 
-#include <openssl/x509v3.h>
+#include "../common/cert_st.h"
 #include "../scconf/scconf.h"
 #include "../common/debug.h"
 #include "../common/error.h"
@@ -86,7 +86,7 @@
 * Extract the MS Universal Principal Name array list
 */
 static char ** ms_mapper_find_entries(X509 *x509, void *context) {
-        char **entries= cert_info(x509,CERT_UPN,NULL);
+        char **entries= cert_info(x509,CERT_UPN,ALGORITHM_NULL);
         if (!entries) {
                 DBG("get_ms_upn() failed");
                 return NULL;
@@ -99,7 +99,7 @@
 */
 static char * ms_mapper_find_user(X509 *x509, void *context) {
  char *str;
-        char **entries  = cert_info(x509,CERT_UPN,NULL);
+        char **entries  = cert_info(x509,CERT_UPN,ALGORITHM_NULL);
         if (!entries) {
             DBG("get_ms_upn() failed");
             return NULL;
@@ -127,7 +127,7 @@
 static int ms_mapper_match_user(X509 *x509, const char *user, void *context) {
         char *str;
         int match_found = 0;
-        char **entries  = cert_info(x509,CERT_UPN,NULL);
+        char **entries  = cert_info(x509,CERT_UPN,ALGORITHM_NULL);
         if (!entries) {
             DBG("get_ms_upn() failed");
             return -1;
Index: src/mappers/digest_mapper.c
===================================================================
--- src/mappers/digest_mapper.c (revision 237)
+++ src/mappers/digest_mapper.c (working copy)
@@ -26,8 +26,8 @@
 #include <config.h>
 #endif
 
-#include <openssl/evp.h>
-#include <openssl/x509.h>
+#include "../common/cert_st.h"
+#include "../common/alg_st.h"
 #include "../scconf/scconf.h"
 #include "../common/debug.h"
 #include "../common/error.h"
@@ -40,7 +40,7 @@
 */
 
 static const char *mapfile = "none";
-static const char *algorithm= "sha1";
+static ALGORITHM_TYPE algorithm= ALGORITHM_SHA1;
 static int debug= 0;
 
 /*
@@ -108,23 +108,23 @@
 mapper_module * digest_mapper_module_init(scconf_block *blk,const char *mapper_name) {
 #endif
  mapper_module *pt;
- const EVP_MD *digest;
+ char *hash_alg_string;
  if (blk) {
  debug = scconf_get_bool( blk,"debug",0);
- algorithm = scconf_get_str( blk,"algorithm","sha1");
+ hash_alg_string = scconf_get_str( blk,"algorithm","sha1");
  mapfile= scconf_get_str(blk,"mapfile",mapfile);
  } else {
  /* should not occurs, but... */
  DBG1("No block declaration for mapper '%s'",mapper_name);
  }
  set_debug_level(debug);
- digest = EVP_get_digestbyname(algorithm);
- if(!digest) {
- DBG1("Invalid digest algorithm %s, using 'sha1'",algorithm);
- algorithm="sha1";
+ algorithm = Alg_get_alg_from_string(hash_alg_string);
+ if(algorithm == ALGORITHM_NULL) {
+ DBG1("Invalid digest algorithm %s, using 'sha1'", hash_alg_string);
+ algorithm = ALGORITHM_SHA1;
  }
  pt = init_mapper_st(blk,mapper_name);
- if (pt) DBG3("Digest mapper started. debug: %d, mapfile: %s, algorithm: %s",debug,mapfile,algorithm);
+ if (pt) DBG3("Digest mapper started. debug: %d, mapfile: %s, algorithm: %s",debug,mapfile,hash_alg_string);
  else DBG("Digest mapper initialization failed");
  return pt;
 }
Index: src/mappers/mail_mapper.c
===================================================================
--- src/mappers/mail_mapper.c (revision 237)
+++ src/mappers/mail_mapper.c (working copy)
@@ -57,7 +57,7 @@
 * Extract list of email entries on certificate
 */
 static char ** mail_mapper_find_entries(X509 *x509, void *context) {
-        char **entries= cert_info(x509,CERT_EMAIL,NULL);
+        char **entries= cert_info(x509,CERT_EMAIL,ALGORITHM_NULL);
         if (!entries) {
                 DBG("get_email() failed");
                 return NULL;
@@ -107,7 +107,7 @@
 parses the certificate and return the email entry found, or NULL
 */
 static char * mail_mapper_find_user(X509 *x509, void *context) {
-        char **entries= cert_info(x509,CERT_EMAIL,NULL);
+        char **entries= cert_info(x509,CERT_EMAIL,ALGORITHM_NULL);
         if (!entries) {
                 DBG("get_email() failed");
                 return NULL;
@@ -123,7 +123,7 @@
 static int mail_mapper_match_user(X509 *x509, const char *login, void *context) {
  char *item;
  char *str;
-        char **entries= cert_info(x509,CERT_EMAIL,NULL);
+        char **entries= cert_info(x509,CERT_EMAIL,ALGORITHM_NULL);
         if (!entries) {
                 DBG("get_email() failed");
                 return 0;
Index: src/mappers/Makefile.am
===================================================================
--- src/mappers/Makefile.am (revision 237)
+++ src/mappers/Makefile.am (working copy)
@@ -5,7 +5,8 @@
 libdir = @libdir@/pam_pkcs11
 
 # Add openssl specific flags
-AM_CFLAGS = $(OPENSSL_CFLAGS)
+AM_CFLAGS = $(CRYPTO_CFLAGS)
+AM_CPPFLAGS = $(CRYPTO_CFLAGS)
 
 # Statically linked mapperis list
 # Uncomment to get refered mapper statically linked
Index: src/common/error.h
===================================================================
--- src/common/error.h (revision 237)
+++ src/common/error.h (working copy)
@@ -18,8 +18,15 @@
 #ifndef __ERROR_H_
 #define __ERROR_H_
 
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <config.h>
 #include <stdarg.h>
+#ifndef HAVE_NSS
 #include <openssl/err.h>
+#endif
 #include <errno.h>
 
 /** Default error message buffer size */
Index: src/common/SSLerrs.h
===================================================================
--- src/common/SSLerrs.h (revision 0)
+++ src/common/SSLerrs.h (revision 0)
@@ -0,0 +1,371 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is the Netscape security libraries.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1994-2000
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/* SSL-specific security error codes  */
+/* caller must include "sslerr.h" */
+
+ER3(SSL_ERROR_EXPORT_ONLY_SERVER, SSL_ERROR_BASE + 0,
+"Unable to communicate securely.  Peer does not support high-grade encryption.")
+
+ER3(SSL_ERROR_US_ONLY_SERVER, SSL_ERROR_BASE + 1,
+"Unable to communicate securely.  Peer requires high-grade encryption which is not supported.")
+
+ER3(SSL_ERROR_NO_CYPHER_OVERLAP, SSL_ERROR_BASE + 2,
+"Cannot communicate securely with peer: no common encryption algorithm(s).")
+
+ER3(SSL_ERROR_NO_CERTIFICATE, SSL_ERROR_BASE + 3,
+"Unable to find the certificate or key necessary for authentication.")
+
+ER3(SSL_ERROR_BAD_CERTIFICATE, SSL_ERROR_BASE + 4,
+"Unable to communicate securely with peer: peers's certificate was rejected.")
+
+/* unused (SSL_ERROR_BASE + 5),*/
+
+ER3(SSL_ERROR_BAD_CLIENT, SSL_ERROR_BASE + 6,
+"The server has encountered bad data from the client.")
+
+ER3(SSL_ERROR_BAD_SERVER, SSL_ERROR_BASE + 7,
+"The client has encountered bad data from the server.")
+
+ER3(SSL_ERROR_UNSUPPORTED_CERTIFICATE_TYPE, SSL_ERROR_BASE + 8,
+"Unsupported certificate type.")
+
+ER3(SSL_ERROR_UNSUPPORTED_VERSION, SSL_ERROR_BASE + 9,
+"Peer using unsupported version of security protocol.")
+
+/* unused (SSL_ERROR_BASE + 10),*/
+
+ER3(SSL_ERROR_WRONG_CERTIFICATE, SSL_ERROR_BASE + 11,
+"Client authentication failed: private key in key database does not match public key in certificate database.")
+
+ER3(SSL_ERROR_BAD_CERT_DOMAIN, SSL_ERROR_BASE + 12,
+"Unable to communicate securely with peer: requested domain name does not match the server's certificate.")
+
+/* SSL_ERROR_POST_WARNING (SSL_ERROR_BASE + 13),
+   defined in sslerr.h
+*/
+
+ER3(SSL_ERROR_SSL2_DISABLED, (SSL_ERROR_BASE + 14),
+"Peer only supports SSL version 2, which is locally disabled.")
+
+
+ER3(SSL_ERROR_BAD_MAC_READ, (SSL_ERROR_BASE + 15),
+"SSL received a record with an incorrect Message Authentication Code.")
+
+ER3(SSL_ERROR_BAD_MAC_ALERT, (SSL_ERROR_BASE + 16),
+"SSL peer reports incorrect Message Authentication Code.")
+
+ER3(SSL_ERROR_BAD_CERT_ALERT, (SSL_ERROR_BASE + 17),
+"SSL peer cannot verify your certificate.")
+
+ER3(SSL_ERROR_REVOKED_CERT_ALERT, (SSL_ERROR_BASE + 18),
+"SSL peer rejected your certificate as revoked.")
+
+ER3(SSL_ERROR_EXPIRED_CERT_ALERT, (SSL_ERROR_BASE + 19),
+"SSL peer rejected your certificate as expired.")
+
+ER3(SSL_ERROR_SSL_DISABLED, (SSL_ERROR_BASE + 20),
+"Cannot connect: SSL is disabled.")
+
+ER3(SSL_ERROR_FORTEZZA_PQG, (SSL_ERROR_BASE + 21),
+"Cannot connect: SSL peer is in another FORTEZZA domain.")
+
+
+ER3(SSL_ERROR_UNKNOWN_CIPHER_SUITE          , (SSL_ERROR_BASE + 22),
+"An unknown SSL cipher suite has been requested.")
+
+ER3(SSL_ERROR_NO_CIPHERS_SUPPORTED          , (SSL_ERROR_BASE + 23),
+"No cipher suites are present and enabled in this program.")
+
+ER3(SSL_ERROR_BAD_BLOCK_PADDING             , (SSL_ERROR_BASE + 24),
+"SSL received a record with bad block padding.")
+
+ER3(SSL_ERROR_RX_RECORD_TOO_LONG            , (SSL_ERROR_BASE + 25),
+"SSL received a record that exceeded the maximum permissible length.")
+
+ER3(SSL_ERROR_TX_RECORD_TOO_LONG            , (SSL_ERROR_BASE + 26),
+"SSL attempted to send a record that exceeded the maximum permissible length.")
+
+/*
+ * Received a malformed (too long or short or invalid content) SSL handshake.
+ */
+ER3(SSL_ERROR_RX_MALFORMED_HELLO_REQUEST    , (SSL_ERROR_BASE + 27),
+"SSL received a malformed Hello Request handshake message.")
+
+ER3(SSL_ERROR_RX_MALFORMED_CLIENT_HELLO     , (SSL_ERROR_BASE + 28),
+"SSL received a malformed Client Hello handshake message.")
+
+ER3(SSL_ERROR_RX_MALFORMED_SERVER_HELLO     , (SSL_ERROR_BASE + 29),
+"SSL received a malformed Server Hello handshake message.")
+
+ER3(SSL_ERROR_RX_MALFORMED_CERTIFICATE      , (SSL_ERROR_BASE + 30),
+"SSL received a malformed Certificate handshake message.")
+
+ER3(SSL_ERROR_RX_MALFORMED_SERVER_KEY_EXCH  , (SSL_ERROR_BASE + 31),
+"SSL received a malformed Server Key Exchange handshake message.")
+
+ER3(SSL_ERROR_RX_MALFORMED_CERT_REQUEST     , (SSL_ERROR_BASE + 32),
+"SSL received a malformed Certificate Request handshake message.")
+
+ER3(SSL_ERROR_RX_MALFORMED_HELLO_DONE       , (SSL_ERROR_BASE + 33),
+"SSL received a malformed Server Hello Done handshake message.")
+
+ER3(SSL_ERROR_RX_MALFORMED_CERT_VERIFY      , (SSL_ERROR_BASE + 34),
+"SSL received a malformed Certificate Verify handshake message.")
+
+ER3(SSL_ERROR_RX_MALFORMED_CLIENT_KEY_EXCH  , (SSL_ERROR_BASE + 35),
+"SSL received a malformed Client Key Exchange handshake message.")
+
+ER3(SSL_ERROR_RX_MALFORMED_FINISHED         , (SSL_ERROR_BASE + 36),
+"SSL received a malformed Finished handshake message.")
+
+/*
+ * Received a malformed (too long or short) SSL record.
+ */
+ER3(SSL_ERROR_RX_MALFORMED_CHANGE_CIPHER    , (SSL_ERROR_BASE + 37),
+"SSL received a malformed Change Cipher Spec record.")
+
+ER3(SSL_ERROR_RX_MALFORMED_ALERT            , (SSL_ERROR_BASE + 38),
+"SSL received a malformed Alert record.")
+
+ER3(SSL_ERROR_RX_MALFORMED_HANDSHAKE        , (SSL_ERROR_BASE + 39),
+"SSL received a malformed Handshake record.")
+
+ER3(SSL_ERROR_RX_MALFORMED_APPLICATION_DATA , (SSL_ERROR_BASE + 40),
+"SSL received a malformed Application Data record.")
+
+/*
+ * Received an SSL handshake that was inappropriate for the state we're in.
+ * E.g. Server received message from server, or wrong state in state machine.
+ */
+ER3(SSL_ERROR_RX_UNEXPECTED_HELLO_REQUEST   , (SSL_ERROR_BASE + 41),
+"SSL received an unexpected Hello Request handshake message.")
+
+ER3(SSL_ERROR_RX_UNEXPECTED_CLIENT_HELLO    , (SSL_ERROR_BASE + 42),
+"SSL received an unexpected Client Hello handshake message.")
+
+ER3(SSL_ERROR_RX_UNEXPECTED_SERVER_HELLO    , (SSL_ERROR_BASE + 43),
+"SSL received an unexpected Server Hello handshake message.")
+
+ER3(SSL_ERROR_RX_UNEXPECTED_CERTIFICATE     , (SSL_ERROR_BASE + 44),
+"SSL received an unexpected Certificate handshake message.")
+
+ER3(SSL_ERROR_RX_UNEXPECTED_SERVER_KEY_EXCH , (SSL_ERROR_BASE + 45),
+"SSL received an unexpected Server Key Exchange handshake message.")
+
+ER3(SSL_ERROR_RX_UNEXPECTED_CERT_REQUEST    , (SSL_ERROR_BASE + 46),
+"SSL received an unexpected Certificate Request handshake message.")
+
+ER3(SSL_ERROR_RX_UNEXPECTED_HELLO_DONE      , (SSL_ERROR_BASE + 47),
+"SSL received an unexpected Server Hello Done handshake message.")
+
+ER3(SSL_ERROR_RX_UNEXPECTED_CERT_VERIFY     , (SSL_ERROR_BASE + 48),
+"SSL received an unexpected Certificate Verify handshake message.")
+
+ER3(SSL_ERROR_RX_UNEXPECTED_CLIENT_KEY_EXCH , (SSL_ERROR_BASE + 49),
+"SSL received an unexpected Cllient Key Exchange handshake message.")
+
+ER3(SSL_ERROR_RX_UNEXPECTED_FINISHED        , (SSL_ERROR_BASE + 50),
+"SSL received an unexpected Finished handshake message.")
+
+/*
+ * Received an SSL record that was inappropriate for the state we're in.
+ */
+ER3(SSL_ERROR_RX_UNEXPECTED_CHANGE_CIPHER   , (SSL_ERROR_BASE + 51),
+"SSL received an unexpected Change Cipher Spec record.")
+
+ER3(SSL_ERROR_RX_UNEXPECTED_ALERT           , (SSL_ERROR_BASE + 52),
+"SSL received an unexpected Alert record.")
+
+ER3(SSL_ERROR_RX_UNEXPECTED_HANDSHAKE       , (SSL_ERROR_BASE + 53),
+"SSL received an unexpected Handshake record.")
+
+ER3(SSL_ERROR_RX_UNEXPECTED_APPLICATION_DATA, (SSL_ERROR_BASE + 54),
+"SSL received an unexpected Application Data record.")
+
+/*
+ * Received record/message with unknown discriminant.
+ */
+ER3(SSL_ERROR_RX_UNKNOWN_RECORD_TYPE        , (SSL_ERROR_BASE + 55),
+"SSL received a record with an unknown content type.")
+
+ER3(SSL_ERROR_RX_UNKNOWN_HANDSHAKE          , (SSL_ERROR_BASE + 56),
+"SSL received a handshake message with an unknown message type.")
+
+ER3(SSL_ERROR_RX_UNKNOWN_ALERT              , (SSL_ERROR_BASE + 57),
+"SSL received an alert record with an unknown alert description.")
+
+/*
+ * Received an alert reporting what we did wrong.  (more alerts above)
+ */
+ER3(SSL_ERROR_CLOSE_NOTIFY_ALERT            , (SSL_ERROR_BASE + 58),
+"SSL peer has closed this connection.")
+
+ER3(SSL_ERROR_HANDSHAKE_UNEXPECTED_ALERT    , (SSL_ERROR_BASE + 59),
+"SSL peer was not expecting a handshake message it received.")
+
+ER3(SSL_ERROR_DECOMPRESSION_FAILURE_ALERT   , (SSL_ERROR_BASE + 60),
+"SSL peer was unable to succesfully decompress an SSL record it received.")
+
+ER3(SSL_ERROR_HANDSHAKE_FAILURE_ALERT       , (SSL_ERROR_BASE + 61),
+"SSL peer was unable to negotiate an acceptable set of security parameters.")
+
+ER3(SSL_ERROR_ILLEGAL_PARAMETER_ALERT       , (SSL_ERROR_BASE + 62),
+"SSL peer rejected a handshake message for unacceptable content.")
+
+ER3(SSL_ERROR_UNSUPPORTED_CERT_ALERT        , (SSL_ERROR_BASE + 63),
+"SSL peer does not support certificates of the type it received.")
+
+ER3(SSL_ERROR_CERTIFICATE_UNKNOWN_ALERT     , (SSL_ERROR_BASE + 64),
+"SSL peer had some unspecified issue with the certificate it received.")
+
+
+ER3(SSL_ERROR_GENERATE_RANDOM_FAILURE       , (SSL_ERROR_BASE + 65),
+"SSL experienced a failure of its random number generator.")
+
+ER3(SSL_ERROR_SIGN_HASHES_FAILURE           , (SSL_ERROR_BASE + 66),
+"Unable to digitally sign data required to verify your certificate.")
+
+ER3(SSL_ERROR_EXTRACT_PUBLIC_KEY_FAILURE    , (SSL_ERROR_BASE + 67),
+"SSL was unable to extract the public key from the peer's certificate.")
+
+ER3(SSL_ERROR_SERVER_KEY_EXCHANGE_FAILURE   , (SSL_ERROR_BASE + 68),
+"Unspecified failure while processing SSL Server Key Exchange handshake.")
+
+ER3(SSL_ERROR_CLIENT_KEY_EXCHANGE_FAILURE   , (SSL_ERROR_BASE + 69),
+"Unspecified failure while processing SSL Client Key Exchange handshake.")
+
+ER3(SSL_ERROR_ENCRYPTION_FAILURE            , (SSL_ERROR_BASE + 70),
+"Bulk data encryption algorithm failed in selected cipher suite.")
+
+ER3(SSL_ERROR_DECRYPTION_FAILURE            , (SSL_ERROR_BASE + 71),
+"Bulk data decryption algorithm failed in selected cipher suite.")
+
+ER3(SSL_ERROR_SOCKET_WRITE_FAILURE          , (SSL_ERROR_BASE + 72),
+"Attempt to write encrypted data to underlying socket failed.")
+
+ER3(SSL_ERROR_MD5_DIGEST_FAILURE            , (SSL_ERROR_BASE + 73),
+"MD5 digest function failed.")
+
+ER3(SSL_ERROR_SHA_DIGEST_FAILURE            , (SSL_ERROR_BASE + 74),
+"SHA-1 digest function failed.")
+
+ER3(SSL_ERROR_MAC_COMPUTATION_FAILURE       , (SSL_ERROR_BASE + 75),
+"MAC computation failed.")
+
+ER3(SSL_ERROR_SYM_KEY_CONTEXT_FAILURE       , (SSL_ERROR_BASE + 76),
+"Failure to create Symmetric Key context.")
+
+ER3(SSL_ERROR_SYM_KEY_UNWRAP_FAILURE        , (SSL_ERROR_BASE + 77),
+"Failure to unwrap the Symmetric key in Client Key Exchange message.")
+
+ER3(SSL_ERROR_PUB_KEY_SIZE_LIMIT_EXCEEDED   , (SSL_ERROR_BASE + 78),
+"SSL Server attempted to use domestic-grade public key with export cipher suite.")
+
+ER3(SSL_ERROR_IV_PARAM_FAILURE              , (SSL_ERROR_BASE + 79),
+"PKCS11 code failed to translate an IV into a param.")
+
+ER3(SSL_ERROR_INIT_CIPHER_SUITE_FAILURE     , (SSL_ERROR_BASE + 80),
+"Failed to initialize the selected cipher suite.")
+
+ER3(SSL_ERROR_SESSION_KEY_GEN_FAILURE       , (SSL_ERROR_BASE + 81),
+"Client failed to generate session keys for SSL session.")
+
+ER3(SSL_ERROR_NO_SERVER_KEY_FOR_ALG         , (SSL_ERROR_BASE + 82),
+"Server has no key for the attempted key exchange algorithm.")
+
+ER3(SSL_ERROR_TOKEN_INSERTION_REMOVAL       , (SSL_ERROR_BASE + 83),
+"PKCS#11 token was inserted or removed while operation was in progress.")
+
+ER3(SSL_ERROR_TOKEN_SLOT_NOT_FOUND          , (SSL_ERROR_BASE + 84),
+"No PKCS#11 token could be found to do a required operation.")
+
+ER3(SSL_ERROR_NO_COMPRESSION_OVERLAP        , (SSL_ERROR_BASE + 85),
+"Cannot communicate securely with peer: no common compression algorithm(s).")
+
+ER3(SSL_ERROR_HANDSHAKE_NOT_COMPLETED       , (SSL_ERROR_BASE + 86),
+"Cannot initiate another SSL handshake until current handshake is complete.")
+
+ER3(SSL_ERROR_BAD_HANDSHAKE_HASH_VALUE      , (SSL_ERROR_BASE + 87),
+"Received incorrect handshakes hash values from peer.")
+
+ER3(SSL_ERROR_CERT_KEA_MISMATCH             , (SSL_ERROR_BASE + 88),
+"The certificate provided cannot be used with the selected key exchange algorithm.")
+
+ER3(SSL_ERROR_NO_TRUSTED_SSL_CLIENT_CA , (SSL_ERROR_BASE + 89),
+"No certificate authority is trusted for SSL client authentication.")
+
+ER3(SSL_ERROR_SESSION_NOT_FOUND , (SSL_ERROR_BASE + 90),
+"Client's SSL session ID not found in server's session cache.")
+
+ER3(SSL_ERROR_DECRYPTION_FAILED_ALERT     , (SSL_ERROR_BASE + 91),
+"Peer was unable to decrypt an SSL record it received.")
+
+ER3(SSL_ERROR_RECORD_OVERFLOW_ALERT       , (SSL_ERROR_BASE + 92),
+"Peer received an SSL record that was longer than is permitted.")
+
+ER3(SSL_ERROR_UNKNOWN_CA_ALERT            , (SSL_ERROR_BASE + 93),
+"Peer does not recognize and trust the CA that issued your certificate.")
+
+ER3(SSL_ERROR_ACCESS_DENIED_ALERT         , (SSL_ERROR_BASE + 94),
+"Peer received a valid certificate, but access was denied.")
+
+ER3(SSL_ERROR_DECODE_ERROR_ALERT          , (SSL_ERROR_BASE + 95),
+"Peer could not decode an SSL handshake message.")
+
+ER3(SSL_ERROR_DECRYPT_ERROR_ALERT         , (SSL_ERROR_BASE + 96),
+"Peer reports failure of signature verification or key exchange.")
+
+ER3(SSL_ERROR_EXPORT_RESTRICTION_ALERT    , (SSL_ERROR_BASE + 97),
+"Peer reports negotiation not in compliance with export regulations.")
+
+ER3(SSL_ERROR_PROTOCOL_VERSION_ALERT      , (SSL_ERROR_BASE + 98),
+"Peer reports incompatible or unsupported protocol version.")
+
+ER3(SSL_ERROR_INSUFFICIENT_SECURITY_ALERT , (SSL_ERROR_BASE + 99),
+"Server requires ciphers more secure than those supported by client.")
+
+ER3(SSL_ERROR_INTERNAL_ERROR_ALERT        , (SSL_ERROR_BASE + 100),
+"Peer reports it experienced an internal error.")
+
+ER3(SSL_ERROR_USER_CANCELED_ALERT         , (SSL_ERROR_BASE + 101),
+"Peer user canceled handshake.")
+
+ER3(SSL_ERROR_NO_RENEGOTIATION_ALERT      , (SSL_ERROR_BASE + 102),
+"Peer does not permit renegotiation of SSL security parameters.")
+
+ER3(SSL_ERROR_SERVER_CACHE_NOT_CONFIGURED , (SSL_ERROR_BASE + 103),
+"SSL server cache not configured and not disabled for this socket.")
Index: src/common/cert_info.c
===================================================================
--- src/common/cert_info.c (revision 237)
+++ src/common/cert_info.c (working copy)
@@ -23,6 +23,189 @@
 #include <config.h>
 #endif
 
+#include "debug.h"
+#include "error.h"
+#include "strings.h"
+#include "cert_info.h"
+#include "alg_st.h"
+
+#ifdef HAVE_NSS
+
+#include "secoid.h"
+
+/*
+ * NSS dynamic oid support.
+ *  NSS is able to understand new oid tags provided by the application,
+ *  including
+ *  understanding new cert extensions that NSS previously did not understand.
+ *  This code adds the oids for the Kerberos Principle and the Microsoft UPN
+ */
+#define TO_ITEM(x) {siDEROID, (unsigned char *)(x), sizeof(x) }
+
+/* kerberois oid: 1.3.6.1.5.2.2 */
+SECOidTag CERT_KerberosPN_OID = SEC_OID_UNKNOWN;
+static const unsigned char kerberosOID[] =  { 0x2b, 0x6, 0x1, 0x5, 0x2, 0x2 };
+static const SECOidData kerberosPN_Entry =
+       { TO_ITEM(kerberosOID), SEC_OID_UNKNOWN,
+       "Kerberos Priniciple", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION };
+
+SECOidTag CERT_MicrosoftUPN_OID = SEC_OID_UNKNOWN;
+/* { 1.3.6.1.4.1.311 } */
+static const unsigned char microsoftUPNOID[] =  
+        { 0x2b, 0x6, 0x1, 0x4, 0x1, 0x82, 0x37 }; /*, xxxx  */
+static const SECOidData microsoftUPN_Entry =
+        { TO_ITEM(microsoftUPNOID), SEC_OID_UNKNOWN,
+        "Microsoft Universal Priniciple", CKM_INVALID_MECHANISM,
+        INVALID_CERT_EXTENSION };
+
+/* register the oid if we haven't already */
+static void
+cert_fetchOID(SECOidTag *data, const SECOidData *src)
+{
+  if (*data == SEC_OID_UNKNOWN) {
+    /* AddEntry does the right thing if someone else has already
+     * added the oid. (that is return that oid tag) */
+    *data = SECOID_AddEntry(src);
+  }
+  return;
+}
+
+static char **
+cert_GetNameElements(CERTName *name, int wantedTag)
+{
+  static char *results[CERT_INFO_SIZE];
+  CERTRDN** rdns;
+  CERTRDN *rdn;
+  char *buf = 0;
+  int i=0;
+
+  rdns = name->rdns;
+  while (rdns && (rdn = *rdns++) != 0) {
+    CERTAVA** avas = rdn->avas;
+    CERTAVA*  ava;
+    while (avas && (ava = *avas++) != 0) {
+      int tag = CERT_GetAVATag(ava);
+      if ( tag == wantedTag ) {
+        SECItem *decodeItem = CERT_DecodeAVAValue(&ava->value);
+        if(!decodeItem) {
+          results[i] = NULL;
+          return results[0] ? results : NULL;
+        }
+        buf = (char *)malloc(decodeItem->len + 1);
+        if ( buf ) {
+          memcpy(buf, decodeItem->data, decodeItem->len);
+          buf[decodeItem->len] = 0;
+        }
+        SECITEM_FreeItem(decodeItem, PR_TRUE);
+        results[i] = buf;
+        i++;
+        if (i == CERT_INFO_SIZE-1) {
+          goto done;
+        }
+      }
+    }
+  }
+done:
+  results[i] = NULL;
+  return results[0] ? results : NULL;
+}
+
+/*
+* Evaluate Certificate Signature Digest
+*/
+static char **cert_info_digest(X509 *x509, ALGORITHM_TYPE algorithm) {
+  static char *entries[2] = { NULL,NULL };
+  HASH_HashType  type = HASH_GetHashTypeByOidTag(algorithm);
+  unsigned char data[HASH_LENGTH_MAX];
+
+  if (type == HASH_AlgNULL) {
+    type = HASH_AlgSHA1;
+    DBG1("Invalid digest algorithm, using 'sha1'",algorithm);
+  }
+  HASH_HashBuf(type, data, x509->derCert.data, x509->derCert.len);
+  entries[0] = bin2hex(data,HASH_ResultLen(type));
+  return entries;
+}
+
+
+/**
+* request info on certificate
+* @param x509 Certificate to parse
+* @param type Information to retrieve
+* @param algorithm Digest algoritm to use
+* @return utf-8 string array with provided information
+*/
+char **cert_info(X509 *x509, int type, ALGORITHM_TYPE algorithm ) {
+  static char *results[CERT_INFO_SIZE];
+  SECOidData *oid;
+  int i;
+
+  if (!x509) {
+    DBG("Null certificate provided");
+    return NULL;
+  }
+  switch (type) {
+    case CERT_CN      : /* Certificate Common Name */
+      return cert_GetNameElements(&x509->subject, SEC_OID_AVA_COMMON_NAME);
+    case CERT_SUBJECT : /* Certificate subject */
+      results[0] = CERT_NameToAscii(&x509->subject);
+      results[1] = 0;
+      break;
+    case CERT_ISSUER : /* Certificate issuer */
+      results[0] = CERT_NameToAscii(&x509->issuer);
+      results[1] = 0;
+      break;
+    case CERT_SERIAL : /* Certificate serial number */
+      results[0] = bin2hex(x509->serialNumber.data, x509->serialNumber.len);
+      results[1] = 0;
+      break;
+    case CERT_KPN     : /* Kerberos principal name */
+      cert_fetchOID(&CERT_KerberosPN_OID, &kerberosPN_Entry);
+      return cert_GetNameElements(&x509->subject, CERT_KerberosPN_OID);
+    case CERT_EMAIL   : /* Certificate e-mail */
+      for (i=1, results[0] = CERT_GetFirstEmailAddress(x509);
+        results[i-1] && i < CERT_INFO_SIZE; i++) {
+        results[i] = CERT_GetNextEmailAddress(x509, results[i-1]);
+      }
+      results[i] = NULL;
+      for (i=0; results[i]; i++) {
+        results[i] = strdup(results[i]);
+      }
+      break;
+    /* need oid tag. */
+    case CERT_UPN     : /* Microsoft's Universal Principal Name */
+      cert_fetchOID(&CERT_MicrosoftUPN_OID ,& microsoftUPN_Entry);
+      return cert_GetNameElements(&x509->subject, CERT_MicrosoftUPN_OID);
+    case CERT_UID     : /* Certificate Unique Identifier */
+      return cert_GetNameElements(&x509->subject, SEC_OID_RFC1274_UID);
+      break;
+    case CERT_PUK     : /* Certificate Public Key */
+      return NULL;
+    case CERT_DIGEST  : /* Certificate Signature Digest */
+      if ( !algorithm ) {
+        DBG("Must specify digest algorithm");
+        return NULL;
+      }
+      return cert_info_digest(x509,algorithm);
+    case CERT_KEY_ALG     :
+      oid = SECOID_FindOID(&x509->subjectPublicKeyInfo.algorithm.algorithm);
+      if (oid == NULL) {
+        results[0] = strdup("Unknown");
+      } else {
+        results[0] = strdup(oid->desc);
+      }
+      results[1] = 0;
+      break;
+    default           :
+      DBG1("Invalid info type requested: %d",type);
+      return NULL;
+    }
+  if (results[0] == NULL) {
+    return NULL;
+  }
+  return results;
+}
+#else
 #include <openssl/evp.h>
 #include <openssl/objects.h>
 #include <openssl/err.h>
@@ -138,6 +321,23 @@
 }
 
 /*
+* Extract Certificate's Issuer
+*/
+static char **cert_info_issuer(X509 *x509) {
+ X509_NAME *issuer;
+ static char *entries[2] = { NULL, NULL };
+ entries[0] = malloc(256);
+ if (!entries[0]) return NULL;
+        issuer = X509_get_issuer_name(x509);
+        if (!issuer) {
+                DBG("X509_get_issuer_name failed");
+                return NULL;
+        }
+        X509_NAME_oneline(issuer, entries[0], 256 );
+ return entries;
+}
+
+/*
 * Extract Certificate's Kerberos Principal Name
 */
 static char **cert_info_kpn(X509 *x509) {
@@ -265,6 +465,9 @@
 static char **cert_info_uid(X509 *x509) {
  static char *results[CERT_INFO_SIZE];
  int lastpos,position;
+        ASN1_STRING *str;
+        unsigned char *txt;
+ int uid_type = UID_TYPE;
         X509_NAME *name = X509_get_subject_name(x509);
         if (!name) {
  DBG("Certificate has no subject");
@@ -272,10 +475,14 @@
  }
  for (position=0;position<CERT_INFO_SIZE;position++) results[position]= NULL;
  position=0;
- lastpos = X509_NAME_get_index_by_NID(name,UID_TYPE,-1);
+ lastpos = X509_NAME_get_index_by_NID(name,uid_type,-1);
  if (lastpos == -1) {
- DBG("Certificate has no UniqueID");
- return NULL;
+ uid_type = NID_userId;
+ lastpos = X509_NAME_get_index_by_NID(name,uid_type,-1);
+ if (lastpos == -1) {
+ DBG("Certificate has no UniqueID");
+ return NULL;
+ }
  }
  while( ( lastpos != -1 ) && (position<CERT_INFO_MAX_ENTRIES) ) {
     X509_NAME_ENTRY *entry;
@@ -531,6 +738,17 @@
  return entries;
 }
 
+/*
+* Return certificate in PEM format
+*/
+static char **cert_key_alg(X509 *x509) {
+ static char *entries[2] = { NULL,NULL };
+ char *alg = OBJ_nid2ln(
+                    OBJ_obj2nid(x509->cert_info->key->algor->algorithm));
+ entries[0]=strdup(alg);
+ return entries;
+}
+
 /**
 * request info on certificate
 * @param x509 Certificate to parse
@@ -548,6 +766,11 @@
  return cert_info_cn(x509);
     case CERT_SUBJECT : /* Certificate subject */
  return cert_info_subject(x509);
+    case CERT_ISSUER : /* Certificate issuer */
+ return cert_info_issuer(x509);
+    case CERT_SERIAL : /* Certificate serial number */
+ /* fix me */
+ return NULL;
     case CERT_KPN     : /* Kerberos principal name */
  return cert_info_kpn(x509);
     case CERT_EMAIL   : /* Certificate e-mail */
@@ -568,6 +791,8 @@
     return NULL;
  }
  return cert_info_digest(x509,algorithm);
+    case CERT_KEY_ALG     : /* certificate signature algorithm */
+ return cert_key_alg(x509);
     default           :
  DBG1("Invalid info type requested: %d",type);
  return NULL;
@@ -575,5 +800,5 @@
  /* should not get here */
  return NULL;
 }
-
-#endif /* __CERT_INFO_C_ */
+#endif /* HAVE_NSS */
+#endif /* _CERT_INFO_C */
Index: src/common/cert_st.h
===================================================================
--- src/common/cert_st.h (revision 0)
+++ src/common/cert_st.h (revision 0)
@@ -0,0 +1,42 @@
+/*
+ * PKCS #11 PAM Login Module
+ * Copyright (C) 2003-2004 Mario Strasser <[hidden email]>
+ * Copyright (C) 2005 Juan Antonio Martinez <[hidden email]>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * $Id$
+ */
+
+#ifndef _CERT_ST_H
+#define _CERT_ST_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+typedef struct cert_policy_st cert_policy;
+
+#ifdef HAVE_NSS
+#include <cert.h>
+#include <secoidt.h>
+typedef SECOidTag ALGORITHM_TYPE;
+#define ALGORITHM_NULL  SEC_OID_UNKNOWN
+/* we really should make a neutral define for this */
+#define X509 CERTCertificate
+#else
+#include <openssl/x509.h>
+typedef const char *ALGORITHM_TYPE;
+#define ALGORITHM_NULL  NULL
+#endif
+
+
+#endif /* _CERT_ST_H */
Index: src/common/SECerrs.h
===================================================================
--- src/common/SECerrs.h (revision 0)
+++ src/common/SECerrs.h (revision 0)
@@ -0,0 +1,506 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is the Netscape security libraries.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1994-2000
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/* General security error codes  */
+/* Caller must #include "secerr.h" */
+
+ER3(SEC_ERROR_IO, SEC_ERROR_BASE + 0,
+"An I/O error occurred during security authorization.")
+
+ER3(SEC_ERROR_LIBRARY_FAILURE, SEC_ERROR_BASE + 1,
+"security library failure.")
+
+ER3(SEC_ERROR_BAD_DATA, SEC_ERROR_BASE + 2,
+"security library: received bad data.")
+
+ER3(SEC_ERROR_OUTPUT_LEN, SEC_ERROR_BASE + 3,
+"security library: output length error.")
+
+ER3(SEC_ERROR_INPUT_LEN, SEC_ERROR_BASE + 4,
+"security library has experienced an input length error.")
+
+ER3(SEC_ERROR_INVALID_ARGS, SEC_ERROR_BASE + 5,
+"security library: invalid arguments.")
+
+ER3(SEC_ERROR_INVALID_ALGORITHM, SEC_ERROR_BASE + 6,
+"security library: invalid algorithm.")
+
+ER3(SEC_ERROR_INVALID_AVA, SEC_ERROR_BASE + 7,
+"security library: invalid AVA.")
+
+ER3(SEC_ERROR_INVALID_TIME, SEC_ERROR_BASE + 8,
+"Improperly formatted time string.")
+
+ER3(SEC_ERROR_BAD_DER, SEC_ERROR_BASE + 9,
+"security library: improperly formatted DER-encoded message.")
+
+ER3(SEC_ERROR_BAD_SIGNATURE, SEC_ERROR_BASE + 10,
+"Peer's certificate has an invalid signature.")
+
+ER3(SEC_ERROR_EXPIRED_CERTIFICATE, SEC_ERROR_BASE + 11,
+"Peer's Certificate has expired.")
+
+ER3(SEC_ERROR_REVOKED_CERTIFICATE, SEC_ERROR_BASE + 12,
+"Peer's Certificate has been revoked.")
+
+ER3(SEC_ERROR_UNKNOWN_ISSUER, SEC_ERROR_BASE + 13,
+"Peer's Certificate issuer is not recognized.")
+
+ER3(SEC_ERROR_BAD_KEY, SEC_ERROR_BASE + 14,
+"Peer's public key is invalid.")
+
+ER3(SEC_ERROR_BAD_PASSWORD, SEC_ERROR_BASE + 15,
+"The security password entered is incorrect.")
+
+ER3(SEC_ERROR_RETRY_PASSWORD, SEC_ERROR_BASE + 16,
+"New password entered incorrectly.  Please try again.")
+
+ER3(SEC_ERROR_NO_NODELOCK, SEC_ERROR_BASE + 17,
+"security library: no nodelock.")
+
+ER3(SEC_ERROR_BAD_DATABASE, SEC_ERROR_BASE + 18,
+"security library: bad database.")
+
+ER3(SEC_ERROR_NO_MEMORY, SEC_ERROR_BASE + 19,
+"security library: memory allocation failure.")
+
+ER3(SEC_ERROR_UNTRUSTED_ISSUER, SEC_ERROR_BASE + 20,
+"Peer's certificate issuer has been marked as not trusted by the user.")
+
+ER3(SEC_ERROR_UNTRUSTED_CERT, SEC_ERROR_BASE + 21,
+"Peer's certificate has been marked as not trusted by the user.")
+
+ER3(SEC_ERROR_DUPLICATE_CERT, (SEC_ERROR_BASE + 22),
+"Certificate already exists in your database.")
+
+ER3(SEC_ERROR_DUPLICATE_CERT_NAME, (SEC_ERROR_BASE + 23),
+"Downloaded certificate's name duplicates one already in your database.")
+
+ER3(SEC_ERROR_ADDING_CERT, (SEC_ERROR_BASE + 24),
+"Error adding certificate to database.")
+
+ER3(SEC_ERROR_FILING_KEY, (SEC_ERROR_BASE + 25),
+"Error refiling the key for this certificate.")
+
+ER3(SEC_ERROR_NO_KEY, (SEC_ERROR_BASE + 26),
+"The private key for this certificate cannot be found in key database")
+
+ER3(SEC_ERROR_CERT_VALID, (SEC_ERROR_BASE + 27),
+"This certificate is valid.")
+
+ER3(SEC_ERROR_CERT_NOT_VALID, (SEC_ERROR_BASE + 28),
+"This certificate is not valid.")
+
+ER3(SEC_ERROR_CERT_NO_RESPONSE, (SEC_ERROR_BASE + 29),
+"Cert Library: No Response")
+
+ER3(SEC_ERROR_EXPIRED_ISSUER_CERTIFICATE, (SEC_ERROR_BASE + 30),
+"The certificate issuer's certificate has expired.  Check your system date and time.")
+
+ER3(SEC_ERROR_CRL_EXPIRED, (SEC_ERROR_BASE + 31),
+"The CRL for the certificate's issuer has expired.  Update it or check your system data and time.")
+
+ER3(SEC_ERROR_CRL_BAD_SIGNATURE, (SEC_ERROR_BASE + 32),
+"The CRL for the certificate's issuer has an invalid signature.")
+
+ER3(SEC_ERROR_CRL_INVALID, (SEC_ERROR_BASE + 33),
+"New CRL has an invalid format.")
+
+ER3(SEC_ERROR_EXTENSION_VALUE_INVALID, (SEC_ERROR_BASE + 34),
+"Certificate extension value is invalid.")
+
+ER3(SEC_ERROR_EXTENSION_NOT_FOUND, (SEC_ERROR_BASE + 35),
+"Certificate extension not found.")
+
+ER3(SEC_ERROR_CA_CERT_INVALID, (SEC_ERROR_BASE + 36),
+"Issuer certificate is invalid.")
+  
+ER3(SEC_ERROR_PATH_LEN_CONSTRAINT_INVALID, (SEC_ERROR_BASE + 37),
+"Certificate path length constraint is invalid.")
+
+ER3(SEC_ERROR_CERT_USAGES_INVALID, (SEC_ERROR_BASE + 38),
+"Certificate usages field is invalid.")
+
+ER3(SEC_INTERNAL_ONLY, (SEC_ERROR_BASE + 39),
+"**Internal ONLY module**")
+
+ER3(SEC_ERROR_INVALID_KEY, (SEC_ERROR_BASE + 40),
+"The key does not support the requested operation.")
+
+ER3(SEC_ERROR_UNKNOWN_CRITICAL_EXTENSION, (SEC_ERROR_BASE + 41),
+"Certificate contains unknown critical extension.")
+
+ER3(SEC_ERROR_OLD_CRL, (SEC_ERROR_BASE + 42),
+"New CRL is not later than the current one.")
+
+ER3(SEC_ERROR_NO_EMAIL_CERT, (SEC_ERROR_BASE + 43),
+"Not encrypted or signed: you do not yet have an email certificate.")
+
+ER3(SEC_ERROR_NO_RECIPIENT_CERTS_QUERY, (SEC_ERROR_BASE + 44),
+"Not encrypted: you do not have certificates for each of the recipients.")
+
+ER3(SEC_ERROR_NOT_A_RECIPIENT, (SEC_ERROR_BASE + 45),
+"Cannot decrypt: you are not a recipient, or matching certificate and \
+private key not found.")
+
+ER3(SEC_ERROR_PKCS7_KEYALG_MISMATCH, (SEC_ERROR_BASE + 46),
+"Cannot decrypt: key encryption algorithm does not match your certificate.")
+
+ER3(SEC_ERROR_PKCS7_BAD_SIGNATURE, (SEC_ERROR_BASE + 47),
+"Signature verification failed: no signer found, too many signers found, \
+or improper or corrupted data.")
+
+ER3(SEC_ERROR_UNSUPPORTED_KEYALG, (SEC_ERROR_BASE + 48),
+"Unsupported or unknown key algorithm.")
+
+ER3(SEC_ERROR_DECRYPTION_DISALLOWED, (SEC_ERROR_BASE + 49),
+"Cannot decrypt: encrypted using a disallowed algorithm or key size.")
+
+
+/* Fortezza Alerts */
+ER3(XP_SEC_FORTEZZA_BAD_CARD, (SEC_ERROR_BASE + 50),
+"Fortezza card has not been properly initialized.  \
+Please remove it and return it to your issuer.")
+
+ER3(XP_SEC_FORTEZZA_NO_CARD, (SEC_ERROR_BASE + 51),
+"No Fortezza cards Found")
+
+ER3(XP_SEC_FORTEZZA_NONE_SELECTED, (SEC_ERROR_BASE + 52),
+"No Fortezza card selected")
+
+ER3(XP_SEC_FORTEZZA_MORE_INFO, (SEC_ERROR_BASE + 53),
+"Please select a personality to get more info on")
+
+ER3(XP_SEC_FORTEZZA_PERSON_NOT_FOUND, (SEC_ERROR_BASE + 54),
+"Personality not found")
+
+ER3(XP_SEC_FORTEZZA_NO_MORE_INFO, (SEC_ERROR_BASE + 55),
+"No more information on that Personality")
+
+ER3(XP_SEC_FORTEZZA_BAD_PIN, (SEC_ERROR_BASE + 56),
+"Invalid Pin")
+
+ER3(XP_SEC_FORTEZZA_PERSON_ERROR, (SEC_ERROR_BASE + 57),
+"Couldn't initialize Fortezza personalities.")
+/* end fortezza alerts. */
+
+ER3(SEC_ERROR_NO_KRL, (SEC_ERROR_BASE + 58),
+"No KRL for this site's certificate has been found.")
+
+ER3(SEC_ERROR_KRL_EXPIRED, (SEC_ERROR_BASE + 59),
+"The KRL for this site's certificate has expired.")
+
+ER3(SEC_ERROR_KRL_BAD_SIGNATURE, (SEC_ERROR_BASE + 60),
+"The KRL for this site's certificate has an invalid signature.")
+
+ER3(SEC_ERROR_REVOKED_KEY, (SEC_ERROR_BASE + 61),
+"The key for this site's certificate has been revoked.")
+
+ER3(SEC_ERROR_KRL_INVALID, (SEC_ERROR_BASE + 62),
+"New KRL has an invalid format.")
+
+ER3(SEC_ERROR_NEED_RANDOM, (SEC_ERROR_BASE + 63),
+"security library: need random data.")
+
+ER3(SEC_ERROR_NO_MODULE, (SEC_ERROR_BASE + 64),
+"security library: no security module can perform the requested operation.")
+
+ER3(SEC_ERROR_NO_TOKEN, (SEC_ERROR_BASE + 65),
+"The security card or token does not exist, needs to be initialized, or has been removed.")
+
+ER3(SEC_ERROR_READ_ONLY, (SEC_ERROR_BASE + 66),
+"security library: read-only database.")
+
+ER3(SEC_ERROR_NO_SLOT_SELECTED, (SEC_ERROR_BASE + 67),
+"No slot or token was selected.")
+
+ER3(SEC_ERROR_CERT_NICKNAME_COLLISION, (SEC_ERROR_BASE + 68),
+"A certificate with the same nickname already exists.")
+
+ER3(SEC_ERROR_KEY_NICKNAME_COLLISION, (SEC_ERROR_BASE + 69),
+"A key with the same nickname already exists.")
+
+ER3(SEC_ERROR_SAFE_NOT_CREATED, (SEC_ERROR_BASE + 70),
+"error while creating safe object")
+
+ER3(SEC_ERROR_BAGGAGE_NOT_CREATED, (SEC_ERROR_BASE + 71),
+"error while creating baggage object")
+
+ER3(XP_JAVA_REMOVE_PRINCIPAL_ERROR, (SEC_ERROR_BASE + 72),
+"Couldn't remove the principal")
+
+ER3(XP_JAVA_DELETE_PRIVILEGE_ERROR, (SEC_ERROR_BASE + 73),
+"Couldn't delete the privilege")
+
+ER3(XP_JAVA_CERT_NOT_EXISTS_ERROR, (SEC_ERROR_BASE + 74),
+"This principal doesn't have a certificate")
+
+ER3(SEC_ERROR_BAD_EXPORT_ALGORITHM, (SEC_ERROR_BASE + 75),
+"Required algorithm is not allowed.")
+
+ER3(SEC_ERROR_EXPORTING_CERTIFICATES, (SEC_ERROR_BASE + 76),
+"Error attempting to export certificates.")
+
+ER3(SEC_ERROR_IMPORTING_CERTIFICATES, (SEC_ERROR_BASE + 77),
+"Error attempting to import certificates.")
+
+ER3(SEC_ERROR_PKCS12_DECODING_PFX, (SEC_ERROR_BASE + 78),
+"Unable to import.  Decoding error.  File not valid.")
+
+ER3(SEC_ERROR_PKCS12_INVALID_MAC, (SEC_ERROR_BASE + 79),
+"Unable to import.  Invalid MAC.  Incorrect password or corrupt file.")
+
+ER3(SEC_ERROR_PKCS12_UNSUPPORTED_MAC_ALGORITHM, (SEC_ERROR_BASE + 80),
+"Unable to import.  MAC algorithm not supported.")
+
+ER3(SEC_ERROR_PKCS12_UNSUPPORTED_TRANSPORT_MODE,(SEC_ERROR_BASE + 81),
+"Unable to import.  Only password integrity and privacy modes supported.")
+
+ER3(SEC_ERROR_PKCS12_CORRUPT_PFX_STRUCTURE, (SEC_ERROR_BASE + 82),
+"Unable to import.  File structure is corrupt.")
+
+ER3(SEC_ERROR_PKCS12_UNSUPPORTED_PBE_ALGORITHM, (SEC_ERROR_BASE + 83),
+"Unable to import.  Encryption algorithm not supported.")
+
+ER3(SEC_ERROR_PKCS12_UNSUPPORTED_VERSION, (SEC_ERROR_BASE + 84),
+"Unable to import.  File version not supported.")
+
+ER3(SEC_ERROR_PKCS12_PRIVACY_PASSWORD_INCORRECT,(SEC_ERROR_BASE + 85),
+"Unable to import.  Incorrect privacy password.")
+
+ER3(SEC_ERROR_PKCS12_CERT_COLLISION, (SEC_ERROR_BASE + 86),
+"Unable to import.  Same nickname already exists in database.")
+
+ER3(SEC_ERROR_USER_CANCELLED, (SEC_ERROR_BASE + 87),
+"The user pressed cancel.")
+
+ER3(SEC_ERROR_PKCS12_DUPLICATE_DATA, (SEC_ERROR_BASE + 88),
+"Not imported, already in database.")
+
+ER3(SEC_ERROR_MESSAGE_SEND_ABORTED, (SEC_ERROR_BASE + 89),
+"Message not sent.")
+
+ER3(SEC_ERROR_INADEQUATE_KEY_USAGE, (SEC_ERROR_BASE + 90),
+"Certificate key usage inadequate for attempted operation.")
+
+ER3(SEC_ERROR_INADEQUATE_CERT_TYPE, (SEC_ERROR_BASE + 91),
+"Certificate type not approved for application.")
+
+ER3(SEC_ERROR_CERT_ADDR_MISMATCH, (SEC_ERROR_BASE + 92),
+"Address in signing certificate does not match address in message headers.")
+
+ER3(SEC_ERROR_PKCS12_UNABLE_TO_IMPORT_KEY, (SEC_ERROR_BASE + 93),
+"Unable to import.  Error attempting to import private key.")
+
+ER3(SEC_ERROR_PKCS12_IMPORTING_CERT_CHAIN, (SEC_ERROR_BASE + 94),
+"Unable to import.  Error attempting to import certificate chain.")
+
+ER3(SEC_ERROR_PKCS12_UNABLE_TO_LOCATE_OBJECT_BY_NAME, (SEC_ERROR_BASE + 95),
+"Unable to export.  Unable to locate certificate or key by nickname.")
+
+ER3(SEC_ERROR_PKCS12_UNABLE_TO_EXPORT_KEY, (SEC_ERROR_BASE + 96),
+"Unable to export.  Private Key could not be located and exported.")
+
+ER3(SEC_ERROR_PKCS12_UNABLE_TO_WRITE, (SEC_ERROR_BASE + 97),
+"Unable to export.  Unable to write the export file.")
+
+ER3(SEC_ERROR_PKCS12_UNABLE_TO_READ, (SEC_ERROR_BASE + 98),
+"Unable to import.  Unable to read the import file.")
+
+ER3(SEC_ERROR_PKCS12_KEY_DATABASE_NOT_INITIALIZED, (SEC_ERROR_BASE + 99),
+"Unable to export.  Key database corrupt or deleted.")
+
+ER3(SEC_ERROR_KEYGEN_FAIL, (SEC_ERROR_BASE + 100),
+"Unable to generate public/private key pair.")
+
+ER3(SEC_ERROR_INVALID_PASSWORD, (SEC_ERROR_BASE + 101),
+"Password entered is invalid.  Please pick a different one.")
+
+ER3(SEC_ERROR_RETRY_OLD_PASSWORD, (SEC_ERROR_BASE + 102),
+"Old password entered incorrectly.  Please try again.")
+
+ER3(SEC_ERROR_BAD_NICKNAME, (SEC_ERROR_BASE + 103),
+"Certificate nickname already in use.")
+
+ER3(SEC_ERROR_NOT_FORTEZZA_ISSUER,       (SEC_ERROR_BASE + 104),
+"Peer FORTEZZA chain has a non-FORTEZZA Certificate.")
+
+ER3(SEC_ERROR_CANNOT_MOVE_SENSITIVE_KEY, (SEC_ERROR_BASE + 105),
+"A sensitive key cannot be moved to the slot where it is needed.")
+
+ER3(SEC_ERROR_JS_INVALID_MODULE_NAME, (SEC_ERROR_BASE + 106),
+"Invalid module name.")
+
+ER3(SEC_ERROR_JS_INVALID_DLL, (SEC_ERROR_BASE + 107),
+"Invalid module path/filename")
+
+ER3(SEC_ERROR_JS_ADD_MOD_FAILURE, (SEC_ERROR_BASE + 108),
+"Unable to add module")
+
+ER3(SEC_ERROR_JS_DEL_MOD_FAILURE, (SEC_ERROR_BASE + 109),
+"Unable to delete module")
+
+ER3(SEC_ERROR_OLD_KRL,     (SEC_ERROR_BASE + 110),
+"New KRL is not later than the current one.")
+
+ER3(SEC_ERROR_CKL_CONFLICT,     (SEC_ERROR_BASE + 111),
+"New CKL has different issuer than current CKL.  Delete current CKL.")
+
+ER3(SEC_ERROR_CERT_NOT_IN_NAME_SPACE, (SEC_ERROR_BASE + 112),
+"The Certifying Authority for this certificate is not permitted to issue a \
+certificate with this name.")
+
+ER3(SEC_ERROR_KRL_NOT_YET_VALID, (SEC_ERROR_BASE + 113),
+"The key revocation list for this certificate is not yet valid.")
+
+ER3(SEC_ERROR_CRL_NOT_YET_VALID, (SEC_ERROR_BASE + 114),
+"The certificate revocation list for this certificate is not yet valid.")
+
+ER3(SEC_ERROR_UNKNOWN_CERT, (SEC_ERROR_BASE + 115),
+"The requested certificate could not be found.")
+
+ER3(SEC_ERROR_UNKNOWN_SIGNER, (SEC_ERROR_BASE + 116),
+"The signer's certificate could not be found.")
+
+ER3(SEC_ERROR_CERT_BAD_ACCESS_LOCATION, (SEC_ERROR_BASE + 117),
+"The location for the certificate status server has invalid format.")
+
+ER3(SEC_ERROR_OCSP_UNKNOWN_RESPONSE_TYPE, (SEC_ERROR_BASE + 118),
+"The OCSP response cannot be fully decoded; it is of an unknown type.")
+
+ER3(SEC_ERROR_OCSP_BAD_HTTP_RESPONSE, (SEC_ERROR_BASE + 119),
+"The OCSP server returned unexpected/invalid HTTP data.")
+
+ER3(SEC_ERROR_OCSP_MALFORMED_REQUEST, (SEC_ERROR_BASE + 120),
+"The OCSP server found the request to be corrupted or improperly formed.")
+
+ER3(SEC_ERROR_OCSP_SERVER_ERROR, (SEC_ERROR_BASE + 121),
+"The OCSP server experienced an internal error.")
+
+ER3(SEC_ERROR_OCSP_TRY_SERVER_LATER, (SEC_ERROR_BASE + 122),
+"The OCSP server suggests trying again later.")
+
+ER3(SEC_ERROR_OCSP_REQUEST_NEEDS_SIG, (SEC_ERROR_BASE + 123),
+"The OCSP server requires a signature on this request.")
+
+ER3(SEC_ERROR_OCSP_UNAUTHORIZED_REQUEST, (SEC_ERROR_BASE + 124),
+"The OCSP server has refused this request as unauthorized.")
+
+ER3(SEC_ERROR_OCSP_UNKNOWN_RESPONSE_STATUS, (SEC_ERROR_BASE + 125),
+"The OCSP server returned an unrecognizable status.")
+
+ER3(SEC_ERROR_OCSP_UNKNOWN_CERT, (SEC_ERROR_BASE + 126),
+"The OCSP server has no status for the certificate.")
+
+ER3(SEC_ERROR_OCSP_NOT_ENABLED, (SEC_ERROR_BASE + 127),
+"You must enable OCSP before performing this operation.")
+
+ER3(SEC_ERROR_OCSP_NO_DEFAULT_RESPONDER, (SEC_ERROR_BASE + 128),
+"You must set the OCSP default responder before performing this operation.")
+
+ER3(SEC_ERROR_OCSP_MALFORMED_RESPONSE, (SEC_ERROR_BASE + 129),
+"The response from the OCSP server was corrupted or improperly formed.")
+
+ER3(SEC_ERROR_OCSP_UNAUTHORIZED_RESPONSE, (SEC_ERROR_BASE + 130),
+"The signer of the OCSP response is not authorized to give status for \
+this certificate.")
+
+ER3(SEC_ERROR_OCSP_FUTURE_RESPONSE, (SEC_ERROR_BASE + 131),
+"The OCSP response is not yet valid (contains a date in the future).")
+
+ER3(SEC_ERROR_OCSP_OLD_RESPONSE, (SEC_ERROR_BASE + 132),
+"The OCSP response contains out-of-date information.")
+
+ER3(SEC_ERROR_DIGEST_NOT_FOUND, (SEC_ERROR_BASE + 133),
+"The CMS or PKCS #7 Digest was not found in signed message.")
+
+ER3(SEC_ERROR_UNSUPPORTED_MESSAGE_TYPE, (SEC_ERROR_BASE + 134),
+"The CMS or PKCS #7 Message type is unsupported.")
+
+ER3(SEC_ERROR_MODULE_STUCK, (SEC_ERROR_BASE + 135),
+"PKCS #11 module could not be removed because it is still in use.")
+
+ER3(SEC_ERROR_BAD_TEMPLATE, (SEC_ERROR_BASE + 136),
+"Could not decode ASN.1 data. Specified template was invalid.")
+
+ER3(SEC_ERROR_CRL_NOT_FOUND, (SEC_ERROR_BASE + 137),
+"No matching CRL was found.")
+
+ER3(SEC_ERROR_REUSED_ISSUER_AND_SERIAL,        (SEC_ERROR_BASE + 138),
+"You are attempting to import a cert with the same issuer/serial as \
+an existing cert, but that is not the same cert.")
+
+ER3(SEC_ERROR_BUSY, (SEC_ERROR_BASE + 139),
+"NSS could not shutdown. Objects are still in use.")
+
+ER3(SEC_ERROR_EXTRA_INPUT, (SEC_ERROR_BASE + 140),
+"DER-encoded message contained extra unused data.")
+
+ER3(SEC_ERROR_UNSUPPORTED_ELLIPTIC_CURVE, (SEC_ERROR_BASE + 141),
+"Unsupported elliptic curve.")
+
+ER3(SEC_ERROR_UNSUPPORTED_EC_POINT_FORM, (SEC_ERROR_BASE + 142),
+"Unsupported elliptic curve point form.")
+
+ER3(SEC_ERROR_UNRECOGNIZED_OID, (SEC_ERROR_BASE + 143),
+"Unrecognized Object IDentifier.")
+
+ER3(SEC_ERROR_OCSP_INVALID_SIGNING_CERT, (SEC_ERROR_BASE + 144),
+"Invalid OCSP signing certificate in OCSP response.")
+
+ER3(SEC_ERROR_REVOKED_CERTIFICATE_CRL,          (SEC_ERROR_BASE + 145),
+"Certificate is revoked in issuer's certificate revocation list.")
+
+ER3(SEC_ERROR_REVOKED_CERTIFICATE_OCSP,         (SEC_ERROR_BASE + 146),
+"Issuer's OCSP responder reports certificate is revoked.")
+
+ER3(SEC_ERROR_CRL_INVALID_VERSION,              (SEC_ERROR_BASE + 147),
+"Issuer's Certificate Revocation List has an unknown version number.")
+
+ER3(SEC_ERROR_CRL_V1_CRITICAL_EXTENSION,        (SEC_ERROR_BASE + 148),
+"Issuer's V1 Certificate Revocation List has a critical extension.")
+
+ER3(SEC_ERROR_CRL_UNKNOWN_CRITICAL_EXTENSION,   (SEC_ERROR_BASE + 149),
+"Issuer's V2 Certificate Revocation List has an unknown critical extension.")
+
+ER3(SEC_ERROR_UNKNOWN_OBJECT_TYPE,        (SEC_ERROR_BASE + 150),
+"Unknown object type specified.")
+
+ER3(SEC_ERROR_INCOMPATIBLE_PKCS11,        (SEC_ERROR_BASE + 151),
+"PKCS #11 driver violates the spec in an incompatible way.")
+
+ER3(SEC_ERROR_NO_EVENT,         (SEC_ERROR_BASE + 152),
+"No new slot event is available at this time.")
Index: src/common/secutil.h
===================================================================
--- src/common/secutil.h (revision 0)
+++ src/common/secutil.h (revision 0)
@@ -0,0 +1,424 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is the Netscape security libraries.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1994-2000
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+#ifndef _SEC_UTIL_H_
+#define _SEC_UTIL_H_
+
+#include "seccomon.h"
+#include "secitem.h"
+#include "prerror.h"
+#include "base64.h"
+#include "key.h"
+#include "secpkcs7.h"
+#include "secasn1.h"
+#include "secder.h"
+#include <stdio.h>
+
+#define SEC_CT_PRIVATE_KEY "private-key"
+#define SEC_CT_PUBLIC_KEY "public-key"
+#define SEC_CT_CERTIFICATE "certificate"
+#define SEC_CT_CERTIFICATE_REQUEST "certificate-request"
+#define SEC_CT_PKCS7 "pkcs7"
+#define SEC_CT_CRL "crl"
+
+#define NS_CERTREQ_HEADER "-----BEGIN NEW CERTIFICATE REQUEST-----"
+#define NS_CERTREQ_TRAILER "-----END NEW CERTIFICATE REQUEST-----"
+
+#define NS_CERT_HEADER "-----BEGIN CERTIFICATE-----"
+#define NS_CERT_TRAILER "-----END CERTIFICATE-----"
+
+#define NS_CRL_HEADER  "-----BEGIN CRL-----"
+#define NS_CRL_TRAILER "-----END CRL-----"
+
+/* From libsec/pcertdb.c --- it's not declared in sec.h */
+extern SECStatus SEC_AddPermCertificate(CERTCertDBHandle *handle,
+ SECItem *derCert, char *nickname, CERTCertTrust *trust);
+
+
+#ifdef SECUTIL_NEW
+typedef int (*SECU_PPFunc)(PRFileDesc *out, SECItem *item,
+                           char *msg, int level);
+#else
+typedef int (*SECU_PPFunc)(FILE *out, SECItem *item, char *msg, int level);
+#endif
+
+typedef struct {
+    enum {
+ PW_NONE = 0,
+ PW_FROMFILE = 1,
+ PW_PLAINTEXT = 2,
+ PW_EXTERNAL = 3
+    } source;
+    char *data;
+} secuPWData;
+
+/*
+** Change a password on a token, or initialize a token with a password
+** if it does not already have one.
+** Use passwd to send the password in plaintext, pwFile to specify a
+** file containing the password, or NULL for both to prompt the user.
+*/
+SECStatus SECU_ChangePW(PK11SlotInfo *slot, char *passwd, char *pwFile);
+
+/*  These were stolen from the old sec.h... */
+/*
+** Check a password for legitimacy. Passwords must be at least 8
+** characters long and contain one non-alphabetic. Return DSTrue if the
+** password is ok, DSFalse otherwise.
+*/
+extern PRBool SEC_CheckPassword(char *password);
+
+/*
+** Blind check of a password. Complement to SEC_CheckPassword which
+** ignores length and content type, just retuning DSTrue is the password
+** exists, DSFalse if NULL
+*/
+extern PRBool SEC_BlindCheckPassword(char *password);
+
+/*
+** Get a password.
+** First prompt with "msg" on "out", then read the password from "in".
+** The password is then checked using "chkpw".
+*/
+extern char *SEC_GetPassword(FILE *in, FILE *out, char *msg,
+      PRBool (*chkpw)(char *));
+
+char *SECU_FilePasswd(PK11SlotInfo *slot, PRBool retry, void *arg);
+
+char *SECU_GetPasswordString(void *arg, char *prompt);
+
+/*
+** Write a dongle password.
+** Uses MD5 to hash constant system data (hostname, etc.), and then
+** creates RC4 key to encrypt a password "pw" into a file "fd".
+*/
+extern SECStatus SEC_WriteDongleFile(int fd, char *pw);
+
+/*
+** Get a dongle password.
+** Uses MD5 to hash constant system data (hostname, etc.), and then
+** creates RC4 key to decrypt and return a password from file "fd".
+*/
+extern char *SEC_ReadDongleFile(int fd);
+
+
+/* End stolen headers */
+
+/* Just sticks the two strings together with a / if needed */
+char *SECU_AppendFilenameToDir(char *dir, char *filename);
+
+/* Returns result of getenv("SSL_DIR") or NULL */
+extern char *SECU_DefaultSSLDir(void);
+
+/*
+** Should be called once during initialization to set the default
+**    directory for looking for cert.db, key.db, and cert-nameidx.db files
+** Removes trailing '/' in 'base'
+** If 'base' is NULL, defaults to set to .netscape in home directory.
+*/
+extern char *SECU_ConfigDirectory(const char* base);
+
+/*
+** Basic callback function for SSL_GetClientAuthDataHook
+*/
+extern int
+SECU_GetClientAuthData(void *arg, PRFileDesc *fd,
+       struct CERTDistNamesStr *caNames,
+       struct CERTCertificateStr **pRetCert,
+       struct SECKEYPrivateKeyStr **pRetKey);
+
+/* print out an error message */
+extern void SECU_PrintError(char *progName, char *msg, ...);
+
+/* print out a system error message */
+extern void SECU_PrintSystemError(char *progName, char *msg, ...);
+
+/* Return informative error string */
+extern const char * SECU_Strerror(PRErrorCode errNum);
+
+/* print information about cert verification failure */
+extern void
+SECU_printCertProblems(FILE *outfile, CERTCertDBHandle *handle,
+ CERTCertificate *cert, PRBool checksig,
+ SECCertificateUsage certUsage, void *pinArg, PRBool verbose);
+
+/* Read the contents of a file into a SECItem */
+extern SECStatus SECU_FileToItem(SECItem *dst, PRFileDesc *src);
+extern SECStatus SECU_TextFileToItem(SECItem *dst, PRFileDesc *src);
+
+/* Read in a DER from a file, may be ascii  */
+extern SECStatus
+SECU_ReadDERFromFile(SECItem *der, PRFileDesc *inFile, PRBool ascii);
+
+/* Indent based on "level" */
+extern void SECU_Indent(FILE *out, int level);
+
+/* Print integer value and hex */
+extern void SECU_PrintInteger(FILE *out, SECItem *i, char *m, int level);
+
+/* Print ObjectIdentifier symbolically */
+extern SECOidTag SECU_PrintObjectID(FILE *out, SECItem *oid, char *m, int level);
+
+/* Print AlgorithmIdentifier symbolically */
+extern void SECU_PrintAlgorithmID(FILE *out, SECAlgorithmID *a, char *m,
+  int level);
+
+/* Print SECItem as hex */
+extern void SECU_PrintAsHex(FILE *out, SECItem *i, const char *m, int level);
+
+/* dump a buffer in hex and ASCII */
+extern void SECU_PrintBuf(FILE *out, const char *msg, const void *vp, int len);
+
+/*
+ * Format and print the UTC Time "t".  If the tag message "m" is not NULL,
+ * do indent formatting based on "level" and add a newline afterward;
+ * otherwise just print the formatted time string only.
+ */
+extern void SECU_PrintUTCTime(FILE *out, SECItem *t, char *m, int level);
+
+/*
+ * Format and print the Generalized Time "t".  If the tag message "m"
+ * is not NULL, * do indent formatting based on "level" and add a newline
+ * afterward; otherwise just print the formatted time string only.
+ */
+extern void SECU_PrintGeneralizedTime(FILE *out, SECItem *t, char *m,
+      int level);
+
+/*
+ * Format and print the UTC or Generalized Time "t".  If the tag message
+ * "m" is not NULL, do indent formatting based on "level" and add a newline
+ * afterward; otherwise just print the formatted time string only.
+ */
+extern void SECU_PrintTimeChoice(FILE *out, SECItem *t, char *m, int level);
+
+/* callback for listing certs through pkcs11 */
+extern SECStatus SECU_PrintCertNickname(CERTCertListNode* cert, void *data);
+
+/* Dump all certificate nicknames in a database */
+extern SECStatus
+SECU_PrintCertificateNames(CERTCertDBHandle *handle, PRFileDesc* out,
+                           PRBool sortByName, PRBool sortByTrust);
+
+/* See if nickname already in database. Return 1 true, 0 false, -1 error */
+int SECU_CheckCertNameExists(CERTCertDBHandle *handle, char *nickname);
+
+/* Dump contents of cert req */
+extern int SECU_PrintCertificateRequest(FILE *out, SECItem *der, char *m,
+ int level);
+
+/* Dump contents of certificate */
+extern int SECU_PrintCertificate(FILE *out, SECItem *der, char *m, int level);
+
+/* print trust flags on a cert */
+extern void SECU_PrintTrustFlags(FILE *out, CERTCertTrust *trust, char *m, int level);
+
+/* Dump contents of public key */
+extern int SECU_PrintPublicKey(FILE *out, SECItem *der, char *m, int level);
+
+#ifdef HAVE_EPV_TEMPLATE
+/* Dump contents of private key */
+extern int SECU_PrintPrivateKey(FILE *out, SECItem *der, char *m, int level);
+#endif
+
+/* Print the MD5 and SHA1 fingerprints of a cert */
+extern int SECU_PrintFingerprints(FILE *out, SECItem *derCert, char *m,
+                                  int level);
+
+/* Pretty-print any PKCS7 thing */
+extern int SECU_PrintPKCS7ContentInfo(FILE *out, SECItem *der, char *m,
+      int level);
+
+/* Init PKCS11 stuff */
+extern SECStatus SECU_PKCS11Init(PRBool readOnly);
+
+/* Dump contents of signed data */
+extern int SECU_PrintSignedData(FILE *out, SECItem *der, char *m, int level,
+ SECU_PPFunc inner);
+
+extern int SECU_PrintCrl(FILE *out, SECItem *der, char *m, int level);
+
+extern void
+SECU_PrintCRLInfo(FILE *out, CERTCrl *crl, char *m, int level);
+
+extern void SECU_PrintString(FILE *out, SECItem *si, char *m, int level);
+extern void SECU_PrintAny(FILE *out, SECItem *i, char *m, int level);
+
+extern void SECU_PrintPolicy(FILE *out, SECItem *value, char *msg, int level);
+extern void SECU_PrintPrivKeyUsagePeriodExtension(FILE *out, SECItem *value,
+                                 char *msg, int level);
+
+extern void SECU_PrintExtensions(FILE *out, CERTCertExtension **extensions,
+ char *msg, int level);
+
+extern void SECU_PrintName(FILE *out, CERTName *name, char *msg, int level);
+
+#ifdef SECU_GetPassword
+/* Convert a High public Key to a Low public Key */
+extern SECKEYLowPublicKey *SECU_ConvHighToLow(SECKEYPublicKey *pubHighKey);
+#endif
+
+extern SECItem *SECU_GetPBEPassword(void *arg);
+
+extern char *SECU_GetModulePassword(PK11SlotInfo *slot, PRBool retry, void *arg);
+
+extern SECStatus DER_PrettyPrint(FILE *out, SECItem *it, PRBool raw);
+extern void SEC_Init(void);
+
+extern char *SECU_SECModDBName(void);
+
+extern void SECU_PrintPRandOSError(char *progName);
+
+extern SECStatus SECU_RegisterDynamicOids(void);
+
+/* Identifies hash algorithm tag by its string representation. */
+extern SECOidTag SECU_StringToSignatureAlgTag(const char *alg);
+
+/* Store CRL in output file or pk11 db. Also
+ * encodes with base64 and exports to file if ascii flag is set
+ * and file is not NULL. */
+extern SECStatus SECU_StoreCRL(PK11SlotInfo *slot, SECItem *derCrl,
+                               PRFileDesc *outFile, int ascii, char *url);
+
+
+/*
+** DER sign a single block of data using private key encryption and the
+** MD5 hashing algorithm. This routine first computes a digital signature
+** using SEC_SignData, then wraps it with an CERTSignedData and then der
+** encodes the result.
+** "arena" is the memory arena to use to allocate data from
+**      "sd" returned CERTSignedData
+** "result" the final der encoded data (memory is allocated)
+** "buf" the input data to sign
+** "len" the amount of data to sign
+** "pk" the private key to encrypt with
+*/
+extern SECStatus SECU_DerSignDataCRL(PRArenaPool *arena, CERTSignedData *sd,
+                                     unsigned char *buf, int len,
+                                     SECKEYPrivateKey *pk, SECOidTag algID);
+
+typedef enum  {
+    noKeyFound = 1,
+    noSignatureMatch = 2,
+    failToEncode = 3,
+    failToSign = 4,
+    noMem = 5
+} SignAndEncodeFuncExitStat;
+
+extern SECStatus
+SECU_SignAndEncodeCRL(CERTCertificate *issuer, CERTSignedCrl *signCrl,
+                      SECOidTag hashAlgTag, SignAndEncodeFuncExitStat *resCode);
+
+extern SECStatus
+SECU_CopyCRL(PRArenaPool *destArena, CERTCrl *destCrl, CERTCrl *srcCrl);
+
+/*
+** Finds the crl Authority Key Id extension. Returns NULL if no such extension
+** was found.
+*/
+CERTAuthKeyID *
+SECU_FindCRLAuthKeyIDExten (PRArenaPool *arena, CERTSignedCrl *crl);
+
+/*
+ * Find the issuer of a crl. Cert usage should be checked before signing a crl.
+ */
+CERTCertificate *
+SECU_FindCrlIssuer(CERTCertDBHandle *dbHandle, SECItem* subject,
+                   CERTAuthKeyID* id, PRTime validTime);
+
+
+/* call back function used in encoding of an extension. Called from
+ * SECU_EncodeAndAddExtensionValue */
+typedef SECStatus (* EXTEN_EXT_VALUE_ENCODER) (PRArenaPool *extHandleArena,
+                                               void *value, SECItem *encodedValue);
+
+/* Encodes and adds extensions to the CRL or CRL entries. */
+SECStatus
+SECU_EncodeAndAddExtensionValue(PRArenaPool *arena, void *extHandle,
+                                void *value, PRBool criticality, int extenType,
+                                EXTEN_EXT_VALUE_ENCODER EncodeValueFn);
+
+
+/*
+ *
+ *  Utilities for parsing security tools command lines
+ *
+ */
+
+/*  A single command flag  */
+typedef struct {
+    char flag;
+    PRBool needsArg;
+    char *arg;
+    PRBool activated;
+} secuCommandFlag;
+
+/*  A full array of command/option flags  */
+typedef struct
+{
+    int numCommands;
+    int numOptions;
+
+    secuCommandFlag *commands;
+    secuCommandFlag *options;
+} secuCommand;
+
+/*  fill the "arg" and "activated" fields for each flag  */
+SECStatus
+SECU_ParseCommandLine(int argc, char **argv, char *progName, secuCommand *cmd);
+char *
+SECU_GetOptionArg(secuCommand *cmd, int optionNum);
+
+/*
+ *
+ *  Error messaging
+ *
+ */
+
+/* Return informative error string */
+char *SECU_ErrorString(int16 err);
+
+/* Return informative error string. Does not call XP_GetString */
+char *SECU_ErrorStringRaw(int16 err);
+
+void printflags(char *trusts, unsigned int flags);
+
+#ifndef XP_UNIX
+extern int ffs(unsigned int i);
+#endif
+
+#include "secerr.h"
+#include "sslerr.h"
+
+#endif /* _SEC_UTIL_H_ */
Index: src/common/cert_info.h
===================================================================
--- src/common/cert_info.h (revision 237)
+++ src/common/cert_info.h (working copy)
@@ -19,7 +19,7 @@
 #ifndef __CERT_INFO_H_
 #define __CERT_INFO_H_
 
-#include <openssl/x509.h>
+#include "cert_st.h"
 
 /** Certificate Common Name */
 #define CERT_CN 1
@@ -41,6 +41,12 @@
 #define CERT_SSHPUK 9
 /** Certificate in PEM format */
 #define CERT_PEM 10
+/** Certificate issuer */
+#define CERT_ISSUER 11
+/** Certificate serial number */
+#define CERT_SERIAL 12
+/** Certificate key algorithm */
+#define CERT_KEY_ALG 13
 
 /** Max size of returned certificate content array */
 #define CERT_INFO_SIZE 16
@@ -68,7 +74,7 @@
 * @param algorithm to use in evaluate certificate digest; else null
 * @return utf-8 string array with provided information
 */
-CERTINFO_EXTERN char **cert_info(X509 *x509, int type, const char *algorithm);
+CERTINFO_EXTERN char **cert_info(X509 *x509, int type, ALGORITHM_TYPE algorithm);
 
 #undef CERTINFO_EXTERN
 
Index: src/common/alg_st.h
===================================================================
--- src/common/alg_st.h (revision 0)
+++ src/common/alg_st.h (revision 0)
@@ -0,0 +1,52 @@
+/*
+ * PKCS #11 PAM Login Module
+ * Copyright (C) 2003-2004 Mario Strasser <[hidden email]>
+ * Copyright (C) 2005 Juan Antonio Martinez <[hidden email]>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * $Id$
+ */
+
+#ifndef _ALG_ST_H
+#define _ALG_ST_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+
+#ifdef HAVE_NSS
+#include <secoid.h>
+#include <sechash.h>
+typedef SECHashObject ALGDIGEST;
+#define ALGORITHM_SHA512 SEC_OID_SHA512
+#define ALGORITHM_SHA384 SEC_OID_SHA385
+#define ALGORITHM_SHA256 SEC_OID_SHA256
+#define ALGORITHM_SHA1  SEC_OID_SHA1
+#define ALGORITHM_MD5  SEC_OID_MD5
+#define ALGORITHM_MD2  SEC_OID_MD2
+#else
+#include <openssl/evp.h>
+typedef EVP_MD ALGDIGEST;
+#define ALGORITHM_SHA512 "sha512"
+#define ALGORITHM_SHA384 "sha384"
+#define ALGORITHM_SHA256 "sha256"
+#define ALGORITHM_SHA1  "sha1"
+#define ALGORITHM_MD5  "md5"
+#define ALGORITHM_MD2  "md2"
+#endif
+
+ALGORITHM_TYPE Alg_get_alg_from_string(const char *);
+/* EVP_get_digestbyname */
+ALGDIGEST *Alg_get_digest_by_name(ALGORITHM_TYPE hash);
+
+#endif /* _ALG_ST_H */
Index: src/common/cert_vfy.c
===================================================================
--- src/common/cert_vfy.c (revision 237)
+++ src/common/cert_vfy.c (working copy)
@@ -14,18 +14,71 @@
  *
  * $Id$
  */
+#include "debug.h"
+#include "cert_vfy.h"
 
+#ifdef HAVE_NSS
+
+#include "cert.h"
+
+int verify_certificate(X509 * x509, cert_policy *policy)
+{
+    SECStatus rv;
+    CERTCertDBHandle *handle;
+
+    handle = CERT_GetDefaultCertDB();
+
+    /* NSS already check all the revocation info with OCSP and crls */
+    DBG2("Verifying Cert: %s (%s)", x509->nickname, x509->subjectName);
+    rv = CERT_VerifyCertNow(handle, x509, PR_TRUE, certUsageSSLClient,
+ NULL);
+    if (rv != SECSuccess) {
+ DBG1("Couldn't verify Cert: %s", SECU_Strerror(PR_GetError()));
+    }
+
+    return rv == SECSuccess ? 1 : 0;
+}
+
+int verify_signature(X509 * x509, unsigned char *data, int data_length,
+                     unsigned char *signature, int signature_length)
+{
+
+  SECKEYPublicKey *key;
+  SECOidTag algid;
+  SECStatus rv;
+  SECItem sig;
+
+  /* grab the key */
+  key = CERT_ExtractPublicKey(x509);
+  if (key == NULL) {
+ DBG1("Couldn't extract key from certificate: %s",
+ SECU_Strerror(PR_GetError()));
+ return -1;
+  }
+  /* shouldn't the algorithm be passed in? */
+  algid = SEC_GetSignatureAlgorithmOidTag(key->keyType, SEC_OID_SHA1);
+
+  sig.data = signature;
+  sig.len = signature_length;
+  rv = VFY_VerifyData(data, data_length, key, &sig, algid, NULL);
+  if (rv != SECSuccess) {
+ DBG1("Couldn't verify Signature: %s", SECU_Strerror(PR_GetError()));
+  }
+  SECKEY_DestroyPublicKey(key);
+  return (rv == SECSuccess)? 0 : 1;
+}
+
+#else
+
 #define __CERT_VFY_C_
 
 #include <string.h>
 #include <openssl/objects.h>
 #include <openssl/err.h>
 #include <openssl/x509v3.h>
-#include "debug.h"
 #include "error.h"
 #include "base64.h"
 #include "uri.h"
-#include "cert_vfy.h"
 
 static X509_CRL *download_crl(const char *uri)
 {
@@ -421,3 +474,4 @@
   DBG("signature is valid");
   return 0;
 }
+#endif
Index: src/common/NSPRerrs.h
===================================================================
--- src/common/NSPRerrs.h (revision 0)
+++ src/common/NSPRerrs.h (revision 0)
@@ -0,0 +1,153 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is the Netscape security libraries.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1994-2000
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+/* General NSPR 2.0 errors */
+/* Caller must #include "prerror.h" */
+
+ER2( PR_OUT_OF_MEMORY_ERROR, "Memory allocation attempt failed." )
+ER2( PR_BAD_DESCRIPTOR_ERROR, "Invalid file descriptor." )
+ER2( PR_WOULD_BLOCK_ERROR, "The operation would have blocked." )
+ER2( PR_ACCESS_FAULT_ERROR, "Invalid memory address argument." )
+ER2( PR_INVALID_METHOD_ERROR, "Invalid function for file type." )
+ER2( PR_ILLEGAL_ACCESS_ERROR, "Invalid memory address argument." )
+ER2( PR_UNKNOWN_ERROR, "Some unknown error has occurred." )
+ER2( PR_PENDING_INTERRUPT_ERROR,"Operation interrupted by another thread." )
+ER2( PR_NOT_IMPLEMENTED_ERROR, "function not implemented." )
+ER2( PR_IO_ERROR, "I/O function error." )
+ER2( PR_IO_TIMEOUT_ERROR, "I/O operation timed out." )
+ER2( PR_IO_PENDING_ERROR, "I/O operation on busy file descriptor." )
+ER2( PR_DIRECTORY_OPEN_ERROR, "The directory could not be opened." )
+ER2( PR_INVALID_ARGUMENT_ERROR, "Invalid function argument." )
+ER2( PR_ADDRESS_NOT_AVAILABLE_ERROR, "Network address not available (in use?)." )
+ER2( PR_ADDRESS_NOT_SUPPORTED_ERROR, "Network address type not supported." )
+ER2( PR_IS_CONNECTED_ERROR, "Already connected." )
+ER2( PR_BAD_ADDRESS_ERROR, "Network address is invalid." )
+ER2( PR_ADDRESS_IN_USE_ERROR, "Local Network address is in use." )
+ER2( PR_CONNECT_REFUSED_ERROR, "Connection refused by peer." )
+ER2( PR_NETWORK_UNREACHABLE_ERROR, "Network address is presently unreachable." )
+ER2( PR_CONNECT_TIMEOUT_ERROR, "Connection attempt timed out." )
+ER2( PR_NOT_CONNECTED_ERROR, "Network file descriptor is not connected." )
+ER2( PR_LOAD_LIBRARY_ERROR, "Failure to load dynamic library." )
+ER2( PR_UNLOAD_LIBRARY_ERROR, "Failure to unload dynamic library." )
+ER2( PR_FIND_SYMBOL_ERROR,
+"Symbol not found in any of the loaded dynamic libraries." )
+ER2( PR_INSUFFICIENT_RESOURCES_ERROR, "Insufficient system resources." )
+ER2( PR_DIRECTORY_LOOKUP_ERROR,
+"A directory lookup on a network address has failed." )
+ER2( PR_TPD_RANGE_ERROR,
+"Attempt to access a TPD key that is out of range." )
+ER2( PR_PROC_DESC_TABLE_FULL_ERROR, "Process open FD table is full." )
+ER2( PR_SYS_DESC_TABLE_FULL_ERROR, "System open FD table is full." )
+ER2( PR_NOT_SOCKET_ERROR,
+"Network operation attempted on non-network file descriptor." )
+ER2( PR_NOT_TCP_SOCKET_ERROR,
+"TCP-specific function attempted on a non-TCP file descriptor." )
+ER2( PR_SOCKET_ADDRESS_IS_BOUND_ERROR, "TCP file descriptor is already bound." )
+ER2( PR_NO_ACCESS_RIGHTS_ERROR, "Access Denied." )
+ER2( PR_OPERATION_NOT_SUPPORTED_ERROR,
+"The requested operation is not supported by the platform." )
+ER2( PR_PROTOCOL_NOT_SUPPORTED_ERROR,
+"The host operating system does not support the protocol requested." )
+ER2( PR_REMOTE_FILE_ERROR, "Access to the remote file has been severed." )
+ER2( PR_BUFFER_OVERFLOW_ERROR,
+"The value requested is too large to be stored in the data buffer provided." )
+ER2( PR_CONNECT_RESET_ERROR, "TCP connection reset by peer." )
+ER2( PR_RANGE_ERROR, "Unused." )
+ER2( PR_DEADLOCK_ERROR, "The operation would have deadlocked." )
+ER2( PR_FILE_IS_LOCKED_ERROR, "The file is already locked." )
+ER2( PR_FILE_TOO_BIG_ERROR,
+"Write would result in file larger than the system allows." )
+ER2( PR_NO_DEVICE_SPACE_ERROR, "The device for storing the file is full." )
+ER2( PR_PIPE_ERROR, "Unused." )
+ER2( PR_NO_SEEK_DEVICE_ERROR, "Unused." )
+ER2( PR_IS_DIRECTORY_ERROR,
+"Cannot perform a normal file operation on a directory." )
+ER2( PR_LOOP_ERROR, "Symbolic link loop." )
+ER2( PR_NAME_TOO_LONG_ERROR, "File name is too long." )
+ER2( PR_FILE_NOT_FOUND_ERROR, "File not found." )
+ER2( PR_NOT_DIRECTORY_ERROR,
+"Cannot perform directory operation on a normal file." )
+ER2( PR_READ_ONLY_FILESYSTEM_ERROR,
+"Cannot write to a read-only file system." )
+ER2( PR_DIRECTORY_NOT_EMPTY_ERROR,
+"Cannot delete a directory that is not empty." )
+ER2( PR_FILESYSTEM_MOUNTED_ERROR,
+"Cannot delete or rename a file object while the file system is busy." )
+ER2( PR_NOT_SAME_DEVICE_ERROR,
+"Cannot rename a file to a file system on another device." )
+ER2( PR_DIRECTORY_CORRUPTED_ERROR,
+"The directory object in the file system is corrupted." )
+ER2( PR_FILE_EXISTS_ERROR,
+"Cannot create or rename a filename that already exists." )
+ER2( PR_MAX_DIRECTORY_ENTRIES_ERROR,
+"Directory is full.  No additional filenames may be added." )
+ER2( PR_INVALID_DEVICE_STATE_ERROR,
+"The required device was in an invalid state." )
+ER2( PR_DEVICE_IS_LOCKED_ERROR, "The device is locked." )
+ER2( PR_NO_MORE_FILES_ERROR, "No more entries in the directory." )
+ER2( PR_END_OF_FILE_ERROR, "Encountered end of file." )
+ER2( PR_FILE_SEEK_ERROR, "Seek error." )
+ER2( PR_FILE_IS_BUSY_ERROR, "The file is busy." )
+ER2( PR_IN_PROGRESS_ERROR,
+"Operation is still in progress (probably a non-blocking connect)." )
+ER2( PR_ALREADY_INITIATED_ERROR,
+"Operation has already been initiated (probably a non-blocking connect)." )
+
+#ifdef PR_GROUP_EMPTY_ERROR
+ER2( PR_GROUP_EMPTY_ERROR, "The wait group is empty." )
+#endif
+
+#ifdef PR_INVALID_STATE_ERROR
+ER2( PR_INVALID_STATE_ERROR, "Object state improper for request." )
+#endif
+
+#ifdef PR_NETWORK_DOWN_ERROR
+ER2( PR_NETWORK_DOWN_ERROR, "Network is down." )
+#endif
+
+#ifdef PR_SOCKET_SHUTDOWN_ERROR
+ER2( PR_SOCKET_SHUTDOWN_ERROR, "The socket was previously shut down." )
+#endif
+
+#ifdef PR_CONNECT_ABORTED_ERROR
+ER2( PR_CONNECT_ABORTED_ERROR, "TCP Connection aborted." )
+#endif
+
+#ifdef PR_HOST_UNREACHABLE_ERROR
+ER2( PR_HOST_UNREACHABLE_ERROR, "Host is unreachable." )
+#endif
+
+/* always last */
+ER2( PR_MAX_ERROR, "Placeholder for the end of the list" )
Index: src/common/cert_vfy.h
===================================================================
--- src/common/cert_vfy.h (revision 237)
+++ src/common/cert_vfy.h (working copy)
@@ -27,7 +27,7 @@
 #ifndef __CERT_VFY_H_
 #define __CERT_VFY_H_
 
-#include <openssl/x509.h>
+#include "cert_st.h"
 
 typedef enum {
  /** Do not perform any CRL verification */
@@ -40,13 +40,20 @@
  CRLP_AUTO
  } crl_policy_t;
 
-typedef struct cert_policy_st {
+typedef enum {
+ OCSP_NONE,
+ OCSP_ON
+ } ocsp_policy_t;
+
+struct cert_policy_st {
  int ca_policy;
  int crl_policy;
  int signature_policy;
  char *ca_dir;
  char *crl_dir;
-} cert_policy;
+ char *nss_dir;
+ int ocsp_policy;
+};
 
 #ifndef __CERT_VFY_C
 #define CERTVFY_EXTERN extern
Index: src/common/algorithm.c
===================================================================
--- src/common/algorithm.c (revision 0)
+++ src/common/algorithm.c (revision 0)
@@ -0,0 +1,77 @@
+/*
+ * PKCS #11 PAM Login Module
+ * Copyright (C) 2003-2004 Mario Strasser <[hidden email]>
+ * Copyright (C) 2005 Juan Antonio Martinez <[hidden email]>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * $Id$
+ */
+
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <cert_st.h>
+#include <alg_st.h>
+
+#ifdef HAVE_NSS
+ALGORITHM_TYPE Alg_get_alg_from_string(const char *hashString)
+{
+    /* sigh, we don't have any string to out conversion
+     * it would be nice to at least search the oid table by
+     * description */
+    SECOidTag hashOIDTag;
+
+    if (strcasecmp(hashString, "sha1") == 0) {
+ hashOIDTag = SEC_OID_SHA1;
+    } else if (strcasecmp(hashString, "md5") == 0) {
+ hashOIDTag = SEC_OID_MD5;
+    } else if (strcasecmp(hashString, "md2") == 0) {
+ hashOIDTag = SEC_OID_MD2;
+    } else if (strcasecmp(hashString, "sha512") == 0) {
+ hashOIDTag = SEC_OID_SHA512;
+    } else if (strcasecmp(hashString, "sha384") == 0) {
+ hashOIDTag = SEC_OID_SHA384;
+    } else if (strcasecmp(hashString, "sha256") == 0) {
+ hashOIDTag = SEC_OID_SHA256;
+    } else {
+ hashOIDTag = ALGORITHM_NULL;
+    }
+
+    return hashOIDTag;
+}
+
+ALGDIGEST *Alg_get_digest_by_name(ALGORITHM_TYPE hash)
+{
+    return HASH_GetHashObjectByOidTag(hash);
+}
+
+#else
+
+ALGORITHM_TYPE Alg_get_alg_from_string(const char *hashString)
+{
+    const EVP_MD *digest;
+
+    digest = EVP_get_digestbyname(hashString);
+    if (!digest) {
+ return ALGORITHM_NULL;
+    }
+    return hashString;
+}
+
+ALGDIGEST *Alg_get_digest_by_name(ALGORITHM_TYPE hash)
+{
+    return EVP_get_digestbyname((char *)hash);
+}
+#endif
+
Index: src/common/pkcs11_lib.c
===================================================================
--- src/common/pkcs11_lib.c (revision 237)
+++ src/common/pkcs11_lib.c (working copy)
@@ -17,6 +17,9 @@
 
 #define __PKCS11_LIB_C__
 
+/*
+ * common includes
+ */
 #include <dlfcn.h>
 #include <sys/types.h>
 #include <sys/stat.h>
@@ -24,28 +27,633 @@
 #include <unistd.h>
 #include <errno.h>
 #include <string.h>
+#include "debug.h"
+#include "error.h"
+#include "cert_info.h"
+#include "pkcs11_lib.h"
+
+
+/*
+ * this functions is completely common between both implementation.
+ */
+int pkcs11_pass_login(pkcs11_handle_t *h, int nullok)
+{
+  int rv;
+  char *pin;
+
+  /* get password */
+  pin =getpass("PIN for token: ");
+#ifndef DEBUG_HIDE_PASSWORD
+  DBG1("PIN = [%s]", pin);
+#endif
+  /* for safety reasons, clean PIN string from memory asap */
+
+  /* check password length */
+  if (!nullok && strlen(pin) == 0) {
+    memset(pin, 0, strlen(pin));
+    free(pin);
+    set_error("Empty passwords not allowed");
+    return -1;
+  }
+
+  /* perform pkcs #11 login */
+  rv = pkcs11_login(h, pin);
+  memset(pin, 0, strlen(pin));
+  free(pin);
+  if (rv != 0) {
+    /* DBG1("pkcs11_login() failed: %s", get_error()); */
+    return -1;
+  }
+  return 0;
+}
+
+#ifdef HAVE_NSS
+/*
+ * Using NSS to find the manage the PKCS #11 modules
+ */
+#include "nss.h"
+#include "cert.h"
+#include "secmod.h"
+#include "pk11pub.h"
+#include "cert_st.h"
+#include "secutil.h"
+#include "cryptohi.h"
+#include "ocsp.h"
+#include <unistd.h>
+#include <errno.h>
+
+#include "cert_vfy.h"
+
+struct pkcs11_handle_str {
+  SECMODModule *module;
+  PRBool is_user_module;
+  PK11SlotInfo *slot;
+  cert_object_t **certs;
+  int cert_count;
+};
+
+static int app_has_NSS = 0;
+
+
+char *
+password_passthrough(PK11SlotInfo *slot, PRBool retry, void *arg)
+{
+  /* give up if 1) no password was supplied, or 2) the password has already
+   * been rejected once by this token. */
+  if (retry || (arg == NULL)) {
+    return NULL;
+  }
+  return PL_strdup((char *)arg);
+}
+
+
+int crypto_init(cert_policy *policy) {
+  SECStatus rv;
+
+  DBG("Initializing NSS ...");
+  if (NSS_IsInitialized()) {
+    app_has_NSS = 1;
+    /* we should save the app's password function */
+    PK11_SetPasswordFunc(password_passthrough);
+    DBG("...  NSS is initialized");
+    return 0;
+  }
+  if (policy->nss_dir) {
+    /* initialize with read only databases */
+    DBG1("Initializing NSS ... database=%s", policy->nss_dir);
+    rv = NSS_Init(policy->nss_dir);
+  } else {
+    /* not database secified */
+    DBG("Initializing NSS ... with no db");
+    rv = NSS_NoDB_Init(NULL);
+  }
+
+  if (rv != SECSuccess) {
+    DBG1("NSS_Initialize faile: %s", SECU_Strerror(PR_GetError()));
+    return -1;
+  }
+  /* register a callback */
+  PK11_SetPasswordFunc(password_passthrough);
+
+  if (policy->ocsp_policy == OCSP_ON) {
+    CERT_EnableOCSPChecking(CERT_GetDefaultCertDB());
+  }
+  DBG("...  NSS Complete");
+  return 0;
+}
+
+
+static SECMODModule *find_module_by_library(char *pkcs11_module)
+{
+  SECMODModule *module = NULL;
+  SECMODModuleList *modList = SECMOD_GetDefaultModuleList();
+
+  /* threaded applications should also acquire the
+   * DefaultModuleListLock */
+  DBG("Looking up module in list");
+  for ( ; modList; modList = modList->next) {
+    char *dllName = modList->module->dllName;
+    DBG2("modList = 0x%x next = 0x%x\n", modList, modList->next);
+    DBG1("dllName= %s \n", dllName ? dllName : "<null>");
+    if (dllName && strcmp(dllName,pkcs11_module) == 0) {
+        module = SECMOD_ReferenceModule(modList->module);
+        break;
+    }
+  }
+  return module;
+}
+
+/*
+ * NSS allows you to load a specific module. If the user specified a module
+ * to load, load it, otherwize select on of the standard modules from the
+ * secmod.db list.
+ */
+int load_pkcs11_module(char *pkcs11_module, pkcs11_handle_t **hp)
+{
+  pkcs11_handle_t *h = (pkcs11_handle_t *)calloc(sizeof(pkcs11_handle_t),1);
+  SECMODModule *module = NULL;
+#define SPEC_TEMPLATE "library=\"%s\" name=\"SmartCard\""
+  char *moduleSpec = NULL;
+
+  if (!pkcs11_module || (strcasecmp(pkcs11_module,"any module") == 0)) {
+    h->is_user_module = PR_FALSE;
+    h->module = NULL;
+    *hp = h;
+    return 0;
+  }
+
+  /* found it, use the existing module */
+  module = find_module_by_library(pkcs11_module);
+  if (module) {
+    h->is_user_module = PR_FALSE;
+    h->module = module;
+    *hp = h;
+    return 0;
+  }
+
+  /* specified module is not already loaded, load it now */
+  moduleSpec = (char *)malloc(sizeof(SPEC_TEMPLATE) + strlen(pkcs11_module));
+  if (!moduleSpec) {
+    DBG1("Malloc failed when allocating module spec", strerror(errno));
+    free (h);
+    return -1;
+  }
+  sprintf(moduleSpec,SPEC_TEMPLATE, pkcs11_module);
+  DBG2("loading Module explictly, moduleSpec=<%s> module=%s",
+                                                moduleSpec, pkcs11_module);
+  module = SECMOD_LoadUserModule(moduleSpec, NULL, 0);
+  free(moduleSpec);
+  if ((!module) || !module->loaded) {
+    DBG1("Failed to load SmartCard software %s", SECU_Strerror(PR_GetError()));
+    free (h);
+    if (module) {
+      SECMOD_DestroyModule(module);
+    }
+    return -1;
+  }
+  h->is_user_module = PR_TRUE;
+  h->module = module;
+  *hp = h;
+  DBG("load module complete");
+  return 0;
+}
+
+int init_pkcs11_module(pkcs11_handle_t *h, int flag)
+{
+  return 0; /* NSS initialized the module on load */
+}
+
+int find_slot_by_number(pkcs11_handle_t *h, int slot_num, unsigned int *slotID)
+{
+  SECMODModule *module = h->module;
+  int i;
+
+  /* if module is null,
+   * any of the PKCS #11 modules specified in the system config
+   * is available, find one */
+  if (module == NULL) {
+    PK11SlotList *list;
+    PK11SlotListElement *le;
+    PK11SlotInfo *slot = NULL;
+
+    /* find a slot, we haven't specifically selected a module,
+     * so find an appropriate one. */
+    /* get them all */
+    list = PK11_GetAllTokens(CKM_INVALID_MECHANISM, PR_FALSE, PR_TRUE, NULL);
+    if (list == NULL) {
+ return -1;
+    }
+    for (le = list->head; le; le = le->next) {
+      CK_SLOT_INFO slInfo;
+      SECStatus rv;
+
+      slInfo.flags = 0;
+      rv = PK11_GetSlotInfo(le->slot, &slInfo);
+      if (rv == SECSuccess && (slInfo.flags & CKF_REMOVABLE_DEVICE)) {
+ slot = PK11_ReferenceSlot(le->slot);
+ module = SECMOD_ReferenceModule(PK11_GetModule(le->slot));
+ break;
+      }
+    }
+    PK11_FreeSlotList(list);
+    if (slot == NULL) {
+ return -1;
+    }
+    h->slot = slot;
+    h->module = module;
+    *slotID = PK11_GetSlotID(slot);
+    return 0;
+  }
+
+  /*
+   * we're configured with a specific module, look for a present slot
+   * on that module. */
+  if (slot_num == 0) {
+    /* threaded applications should also acquire the
+     * DefaultModuleListLock */
+    for (i=0; i < module->slotCount; i++) {
+      if (module->slots[i] && PK11_IsPresent(module->slots[i])) {
+        h->slot = PK11_ReferenceSlot(module->slots[i]);
+        *slotID = PK11_GetSlotID(h->slot);
+        return 0;
+      }
+    }
+  }
+  /* we're configured for a specific module and token, see if it's present */
+  slot_num--;
+  if (slot_num >= 0 && slot_num < module->slotCount && module->slots &&
+      module->slots[i] && PK11_IsPresent(module->slots[i])) {
+    h->slot = PK11_ReferenceSlot(module->slots[i]);
+    *slotID = PK11_GetSlotID(h->slot);
+    return 0;
+  }
+  return -1;
+}
+
+void release_pkcs11_module(pkcs11_handle_t *h)
+{
+  SECStatus rv;
+  close_pkcs11_session(h);
+  if (h->is_user_module) {
+    rv = SECMOD_UnloadUserModule(h->module);
+    if (rv != SECSuccess) {
+      DBG1("Unloading UserModule failed: %s", SECU_Strerror(PR_GetError()));
+    }
+  }
+
+  if (h->module) {
+    SECMOD_DestroyModule(h->module);
+  }
+  memset(h, 0, sizeof(pkcs11_handle_t));
+  free(h);
+
+  /* if we initialized NSS, then we need to shut it down */
+  if (!app_has_NSS) {
+    rv = NSS_Shutdown();
+    if (rv != SECSuccess) {
+      DBG1("NSS Shutdown Failed: %s", SECU_Strerror(PR_GetError()));
+    }
+  }
+}
+
+int open_pkcs11_session(pkcs11_handle_t *h, unsigned int slot_num)
+{
+  /* NSS manages the sessions under the covers, use this function to
+   * select a slot */
+  if (h->slot != NULL) {
+    /* we've already selected the slot */
+    if (PK11_GetSlotID(h->slot) == slot_num) {
+ return 0;
+    }
+    /* the slot we've selected isn't the one we want to open */
+    PK11_FreeSlot(h->slot);
+    h->slot = NULL;
+  }
+
+  /* look the slot up */
+  h->slot = SECMOD_LookupSlot(h->module->moduleID, slot_num);
+  if (h->slot == NULL) {
+    return -1;
+  }
+
+  /* make sure it is present */
+  if (!PK11_IsPresent(h->slot)) {
+    PK11_FreeSlot(h->slot);
+    h->slot = NULL;
+    return -1;
+  }
+  return 0;
+}
+
+int pkcs11_login(pkcs11_handle_t *h, char *password)
+{
+  SECStatus rv;
+
+  if (h->slot == NULL) {
+    DBG("Login failed: No Slot selected");
+    return -1;
+  }
+  rv = PK11_Authenticate(h->slot, PR_FALSE, password);
+  if (rv != SECSuccess) {
+    DBG1("Login failed: %s", SECU_Strerror(PR_GetError()));
+  }
+  return (rv == SECSuccess) ? 0 : -1;
+}
+
+int close_pkcs11_session(pkcs11_handle_t *h)
+{
+  if (h->slot) {
+    PK11_Logout(h->slot);
+    PK11_FreeSlot(h->slot);
+    h->slot = NULL;
+  }
+  if (h->certs) {
+    CERT_DestroyCertArray((CERTCertificate **)h->certs, h->cert_count);
+    h->certs = NULL;
+    h->cert_count = 0;
+  }
+  return 0;
+}
+
+const char *get_slot_label(pkcs11_handle_t *h)
+{
+  if (!h->slot) {
+    return NULL;
+  }
+  return PK11_GetTokenName(h->slot);
+}
+
+cert_object_t **get_certificate_list(pkcs11_handle_t *h, int *count)
+{
+  CERTCertList * certList;
+  CERTCertListNode *node;
+  cert_object_t **certs;
+  int certCount = 0;
+  int certIndex = 0;
+  SECStatus rv;
+
+  if (!h->slot) {
+    return NULL;
+  }
+  if (h->certs) {
+    *count = h->cert_count;
+    return h->certs;
+  }
+
+  certList = PK11_ListCertsInSlot(h->slot);
+  if (!certList) {
+    DBG1("Couldn't get Certs from token: %s", SECU_Strerror(PR_GetError()));
+    return NULL;
+  }
+
+  /* only want signing certs */
+  rv = CERT_FilterCertListByUsage(certList,  certUsageSSLClient, PR_FALSE);
+  if (rv != SECSuccess) {
+      CERT_DestroyCertList(certList);
+      DBG1("Couldn't filter out email certs: %s",
+ SECU_Strerror(PR_GetError()));
+      return NULL;
+  }
+
+  /* only user certs have keys */
+  rv = CERT_FilterCertListForUserCerts(certList);
+  if (rv != SECSuccess) {
+    CERT_DestroyCertList(certList);
+    DBG1("Couldn't filter out user certs: %s", SECU_Strerror(PR_GetError()));
+    return NULL;
+  }
+
+  /* convert the link list from NSS to the array used by pam_pkcs11 */
+  for (node = CERT_LIST_HEAD(certList); !CERT_LIST_END(node,certList);
+ node = CERT_LIST_NEXT(node)) {
+ if (node->cert) {
+    DBG3("cert %d: found (%s), \"%s\"", certCount,
+ node->cert->nickname, node->cert->subjectName);
+    certCount++;
+    }
+  }
+
+  if (certCount == 0) {
+    CERT_DestroyCertList(certList);
+    DBG("no certs found found");
+    return NULL;
+  }
+
+  certs = (cert_object_t **)malloc(sizeof(cert_object_t *)*certCount);
+  if (certs == NULL) {
+    return NULL;
+  }
+
+  for (node = CERT_LIST_HEAD(certList); !CERT_LIST_END(node,certList);
+                                         node = CERT_LIST_NEXT(node)) {
+    if (node->cert) {
+      certs[certIndex++] = (cert_object_t *)CERT_DupCertificate(node->cert);
+      if (certIndex == certCount) {
+        break;
+      }
+    }
+  }
+  CERT_DestroyCertList(certList);
+  h->certs = certs;
+  h->cert_count = certIndex;
+
+  *count = certIndex;
+  return certs;
+}
+
+int get_private_key(pkcs11_handle_t *h, cert_object_t *cert) {
+  /* all certs returned from NSS are user certs, and the private key
+   * has already been identified */
+  return 0;
+}
+
+const X509 *get_X509_certificate(cert_object_t *cert)
+{
+  return (CERTCertificate *)cert;
+}
+
+int sign_value(pkcs11_handle_t *h, cert_object_t *cert, CK_BYTE *data,
+      CK_ULONG length, CK_BYTE **signature, CK_ULONG *signature_length)
+{
+  SECOidTag algtag;
+  SECKEYPrivateKey *key;
+  SECItem result;
+  SECStatus rv;
+
+  if (h->slot == NULL) {
+    return -1;
+  }
+
+  /* get the key */
+  key = PK11_FindPrivateKeyFromCert(h->slot, (CERTCertificate *)cert, NULL);
+  if (key == NULL) {
+    DBG1("Couldn't Find key for Cert: %s", SECU_Strerror(PR_GetError()));
+    return -1;
+  }
+
+  /* get the oid */
+  algtag = SEC_GetSignatureAlgorithmOidTag(key->keyType, SEC_OID_SHA1);
+
+  /* sign the data */
+  rv = SEC_SignData(&result, data, length, key, algtag);
+  SECKEY_DestroyPrivateKey(key);
+  if (rv != SECSuccess) {
+    DBG1("Signature failed: %s", SECU_Strerror(PR_GetError()));
+    return -1;
+  }
+
+  *signature = (CK_BYTE *)result.data;
+  *signature_length = result.len;
+  return 0;
+}
+
+int get_random_value(unsigned char *data, int length)
+{
+  SECStatus rv = PK11_GenerateRandom(data,length);
+  if (rv != SECSuccess) {
+    DBG1("couldn't generate random number: %s", SECU_Strerror(PR_GetError()));
+  }
+  return (rv == SECSuccess) ? 0 : -1;
+}
+
+#include "nspr.h"
+
+struct tuple_str {
+    PRErrorCode errNum;
+    const char * errString;
+};
+
+typedef struct tuple_str tuple_str;
+
+#define ER2(a,b)   {a, b},
+#define ER3(a,b,c) {a, c},
+
+#include "secerr.h"
+#include "sslerr.h"
+
+const tuple_str errStrings[] = {
+/* keep this list in asceding order of error numbers */
+#include "SSLerrs.h"
+#include "SECerrs.h"
+#include "NSPRerrs.h"
+};
+
+const PRInt32 numStrings = sizeof(errStrings) / sizeof(tuple_str);
+
+/* Returns a UTF-8 encoded constant error string for "errNum".
+ * Returns NULL of errNum is unknown.
+ */
+const char *
+SECU_Strerror(PRErrorCode errNum)
+{
+  PRInt32 low  = 0;
+  PRInt32 high = numStrings - 1;
+  PRInt32 i;
+  PRErrorCode num;
+  static int initDone;
+
+  /* make sure table is in ascending order.
+   * binary search depends on it.
+   */
+  if (!initDone) {
+    PRErrorCode lastNum = ((PRInt32)0x80000000);
+    for (i = low; i <= high; ++i) {
+      num = errStrings[i].errNum;
+      if (num <= lastNum) {
+        fprintf(stderr,
+                "sequence error in error strings at item %d\n"
+                "error %d (%s)\n"
+                "should come after \n"
+                "error %d (%s)\n",
+                i, lastNum, errStrings[i-1].errString,
+                num, errStrings[i].errString);
+      }
+      lastNum = num;
+    }
+    initDone = 1;
+  }
+
+  /* Do binary search of table. */
+  while (low + 1 < high) {
+    i = (low + high) / 2;
+    num = errStrings[i].errNum;
+    if (errNum == num)
+      return errStrings[i].errString;
+    if (errNum < num)
+      high = i;
+    else
+      low = i;
+  }
+  if (errNum == errStrings[low].errNum)
+    return errStrings[low].errString;
+  if (errNum == errStrings[high].errNum)
+    return errStrings[high].errString;
+  return NULL;
+}
+
+#else
+#include "cert_st.h"
 #include <openssl/x509.h>
 #include <openssl/err.h>
 
 #include "rsaref/pkcs11.h"
-#include "pkcs11_lib.h"
-#include "debug.h"
-#include "error.h"
-#include "cert_info.h"
 
-int load_pkcs11_module(char *module, pkcs11_handle_t *h)
+
+struct cert_object_str {
+  CK_KEY_TYPE key_type;
+  CK_CERTIFICATE_TYPE type;
+  CK_BYTE *id;
+  CK_ULONG id_length;
+  CK_OBJECT_HANDLE private_key;
+  X509 *x509;
+};
+
+typedef struct {
+  CK_SLOT_ID id;
+  CK_BBOOL token_present;
+  CK_UTF8CHAR label[33];
+} slot_t;
+
+struct pkcs11_handle_str {
+  void *module_handle;
+  CK_FUNCTION_LIST_PTR fl;
+  slot_t *slots;
+  CK_ULONG slot_count;
+  CK_SESSION_HANDLE session;
+  cert_object_t **certs;
+  int cert_count;
+  int current_slot;
+};
+
+
+int crypto_init(cert_policy *policy)
 {
+  /* arg is ignored for OPENSSL */
+  OpenSSL_add_all_algorithms();
+  ERR_load_crypto_strings();
+}
+
+int load_pkcs11_module(char *module, pkcs11_handle_t **hp)
+{
   int rv;
   struct stat module_stat;
   CK_C_GetFunctionList C_GetFunctionList;
+  pkcs11_handle_t *h;
 
   DBG1("PKCS #11 module = [%s]", module);
   /* reset pkcs #11 handle */
-  memset(h, 0, sizeof(pkcs11_handle_t));
+  
+  h = (pkcs11_handle_t *)calloc(sizeof(pkcs11_handle_t), 1);
+  if (h == NULL) {
+    set_error("pkcs11_handle_t malloc failed: %s", strerror(errno));
+    return -1;
+  }
+
   /* check module permissions */
   rv = stat(module, &module_stat);
   if (rv < 0) {
     set_error("stat() failed: %s", strerror(errno));
+    free(h);
     return -1;
   }
   DBG3("module permissions: uid = %d, gid = %d, mode = %o",
@@ -54,6 +662,7 @@
       || module_stat.st_uid != 0 || module_stat.st_gid != 0) {
     set_error("the pkcs #11 module MUST be owned by root and MUST NOT "
               "be writeable by the group or others");
+    free(h);
     return -1;
   }
   /* load module */
@@ -61,6 +670,7 @@
   h->module_handle = dlopen(module, RTLD_NOW);
   if (h->module_handle == NULL) {
     set_error("dlopen() failed: %s", dlerror());
+    free(h);
     return -1;
   }
   /* try to get the function list */
@@ -68,13 +678,16 @@
   C_GetFunctionList = (CK_C_GetFunctionList)dlsym(h->module_handle, "C_GetFunctionList");
   if (C_GetFunctionList == NULL) {
     set_error("dlsym() failed: %s", dlerror());
+    free(h);
     return -1;
   }
   rv = C_GetFunctionList(&h->fl);
   if (rv != CKR_OK) {
     set_error("C_GetFunctionList() failed: %x", rv);
+    free(h);
     return -1;
   }
+  *hp = h;
   return 0;
 }
 
@@ -197,8 +810,28 @@
   if (h->slots != NULL)
     free(h->slots);
   memset(h, 0, sizeof(pkcs11_handle_t));
+  free(h);
 }
 
+int find_slot_by_number(pkcs11_handle_t *h, int slot_num, unsigned int *slot)
+{
+   /* zero means find the best slot */
+   if (slot_num == 0) {
+ for (slot_num = 0; slot_num < h->slot_count &&
+ !h->slots[slot_num].token_present; slot_num++);
+   } else {
+ /* otherwize it's an index into the slot table  (it is *NOT* the slot
+ * id!).... */
+ slot_num--;
+   }
+   if ((slot_num >= h->slot_count) || (!h->slots[slot_num].token_present)) {
+ return -1;
+   }
+   *slot = slot_num;
+   return 0;
+}
+
+
 int open_pkcs11_session(pkcs11_handle_t *h, unsigned int slot)
 {
   int rv;
@@ -214,6 +847,7 @@
     set_error("C_OpenSession() failed: %x", rv);
     return -1;
   }
+  h->current_slot = slot;
   return 0;
 }
 
@@ -230,35 +864,21 @@
   return 0;
 }
 
-int pkcs11_pass_login(pkcs11_handle_t *h, int nullok)
+static void free_certs(cert_object_t **certs, int cert_count)
 {
-  int rv;
-  char *pin;
+  int i;
 
-  /* get password */
-  pin =getpass("PIN for token: ");
-#ifndef DEBUG_HIDE_PASSWORD
-  DBG1("PIN = [%s]", pin);
-#endif
-  /* for safety reasons, clean PIN string from memory asap */
-
-  /* check password length */
-  if (!nullok && strlen(pin) == 0) {
-    memset(pin, 0, strlen(pin));
-    free(pin);
-    set_error("Empty passwords not allowed");
-    return -1;
+  for (i = 0; i < cert_count; i++) {
+    if (!certs[i]) {
+ continue;
+    }
+    if (certs[i]->x509 != NULL)
+      X509_free(certs[i]->x509);
+    if (certs[i]->id != NULL)
+      free(certs[i]->id);
+    free(certs[i]);
   }
-
-  /* perform pkcs #11 login */
-  rv = pkcs11_login(h, pin);
-  memset(pin, 0, strlen(pin));
-  free(pin);
-  if (rv != 0) {
-    /* DBG1("pkcs11_login() failed: %s", get_error()); */
-    return -1;
-  }
-  return 0;
+  free(certs);
 }
 
 int close_pkcs11_session(pkcs11_handle_t *h)
@@ -280,29 +900,22 @@
   }
   DBG("releasing keys and certificates");
   if (h->certs != NULL) {
-    for (i = 0; i < h->cert_count; i++) {
-      if (h->certs[i].x509 != NULL)
-        X509_free(h->certs[i].x509);
-      if (h->certs[i].id != NULL)
-        free(h->certs[i].id);
-    }
-    free(h->certs);
+    free_certs(h->certs, h->cert_count);
     h->certs = NULL;
     h->cert_count = 0;
   }
-  free(h->choosen_key);
   return 0;
 }
 
 /* get a list of certificates */
-int get_certificates(pkcs11_handle_t *h)
+cert_object_t **get_certificate_list(pkcs11_handle_t *h, int *ncerts)
 {
   CK_BYTE *id_value;
   CK_BYTE *cert_value;
   CK_OBJECT_HANDLE object;
   CK_ULONG object_count;
   X509 *x509;
-  cert_object_t *certs;
+  cert_object_t **certs = NULL;
   int rv;
   
   CK_OBJECT_CLASS cert_class = CKO_CERTIFICATE;
@@ -317,10 +930,15 @@
     {CKA_VALUE, NULL, 0}
   };
 
+  if (h->certs) {
+    *ncerts = h->cert_count;
+    return h->certs;
+  }
+
   rv = h->fl->C_FindObjectsInit(h->session, cert_template, 2);
   if (rv != CKR_OK) {
     set_error("C_FindObjectsInit() failed: %x", rv);
-    return -1;
+    return NULL;
   }
   while(1) {
     /* look for certificates */
@@ -393,36 +1011,51 @@
         goto getlist_error;
       }
     /* finally add certificate to chain */
-    certs= realloc(h->certs,(h->cert_count+1) * sizeof(cert_object_t));
+    certs= realloc(h->certs,(h->cert_count+1) * sizeof(cert_object_t *));
     if (!certs) {
         free(id_value);
-        free(cert_value);
+        X509_free(x509);
  set_error("realloc() not space to re-size cert table");
         goto getlist_error;
     }
     h->certs=certs;
     DBG1("Saving Certificate #%d:", h->cert_count + 1);
-    memset(&h->certs[h->cert_count], 0, sizeof(cert_object_t));
+    certs[h->cert_count] = NULL;
     DBG1("- type: %02x", cert_type);
     DBG1("- id:   %02x", id_value[0]);
-    h->certs[h->cert_count].type = cert_type;
-    h->certs[h->cert_count].id   = id_value;
-    h->certs[h->cert_count].id_length = cert_template[2].ulValueLen;
-    h->certs[h->cert_count].x509 = x509;
+    h->certs[h->cert_count] = (cert_object_t *)calloc(sizeof(cert_object_t),1);
+    if (h->certs[h->cert_count] == NULL) {
+ free(id_value);
+        X509_free(x509);
+ set_error("malloc() not space to allocate cert object");
+        goto getlist_error;
+    }
+    h->certs[h->cert_count]->type = cert_type;
+    h->certs[h->cert_count]->id   = id_value;
+    h->certs[h->cert_count]->id_length = cert_template[2].ulValueLen;
+    h->certs[h->cert_count]->x509 = x509;
+    h->certs[h->cert_count]->private_key = CK_INVALID_HANDLE;
+    h->certs[h->cert_count]->key_type = 0;
     ++h->cert_count;
 
   } /* end of while(1) */
 
   /* release FindObject Sesion */
-    rv = h->fl->C_FindObjectsFinal(h->session);
-    if (rv != CKR_OK) {
-      set_error("C_FindObjectsFinal() failed: %x", rv);
-      return -1;
-    }
+  rv = h->fl->C_FindObjectsFinal(h->session);
+  if (rv != CKR_OK) {
+    set_error("C_FindObjectsFinal() failed: %x", rv);
+    free_certs(certs, h->cert_count);
+    certs = NULL;
+    h->certs = NULL;
+    h->cert_count = 0;
+    return NULL;
+  }
 
+  *ncerts = h->cert_count;
+
   /* arriving here means that's all right */
   DBG1("Found %d certificates in token",h->cert_count);
-  return 0;
+  return h->certs;
 
   /* some error arrived: clean as possible, and return fail */
 getlist_error:
@@ -430,11 +1063,14 @@
   if (rv != CKR_OK) {
     set_error("C_FindObjectsFinal() failed: %x", rv);
   }
-  return -1;
+  free_certs(h->certs, h->cert_count);
+  h->certs = NULL;
+  h->cert_count = 0;
+  return NULL;
 }
 
 /* retrieve the private key associated with a given certificate */
-int get_private_key(pkcs11_handle_t *h) {
+int get_private_key(pkcs11_handle_t *h, cert_object_t *cert) {
   CK_OBJECT_CLASS key_class = CKO_PRIVATE_KEY;
   CK_BBOOL key_sign = CK_TRUE;
   CK_KEY_TYPE key_type = CKK_RSA; /* default, should be properly set */
@@ -450,78 +1086,83 @@
   CK_OBJECT_HANDLE object;
   CK_ULONG object_count;
   CK_BYTE *key_id;
-  key_object_t *keys;
+  cert_object_t *keys;
   int rv;
-  if (!h->choosen_cert) {
-    set_error("No certificate selected", rv);
-    return -1;
+
+  if (cert->private_key != CK_INVALID_HANDLE) {
+     /* we've alrady found the private key for this certificate */
+     return 0;
   }
 
-  key_template[3].pValue= h->choosen_cert->id;
-  key_template[3].ulValueLen= h->choosen_cert->id_length;
-  rv = h->fl->C_FindObjectsInit(h->session, key_template, 4);
+  key_template[3].pValue = cert->id;
+  key_template[3].ulValueLen = cert->id_length;
+  rv = h->fl->C_FindObjectsInit(h->session, key_template, 2);
   if (rv != CKR_OK) {
     set_error("C_FindObjectsInit() failed: %x", rv);
     return -1;
   }
-
-    rv = h->fl->C_FindObjects(h->session, &object, 1, &object_count);
-    if (rv != CKR_OK) {
-      set_error("C_FindObjects() failed: %x", rv);
-      goto get_privkey_failed;
-    }
+  rv = h->fl->C_FindObjects(h->session, &object, 1, &object_count);
+  if (rv != CKR_OK) {
+    set_error("C_FindObjects() failed: %x", rv);
+    goto get_privkey_failed;
+  }
   if (object_count <= 0) {
       /* cert without prk: perhaps CA or CA-chain cert */
       set_error("No private key found for cert: %x", rv);
       goto get_privkey_failed;
   }
-  /* create space for priv key data */
-  h->choosen_key=malloc(sizeof(key_object_t));
-  if (!h->choosen_key) {
-      set_error("No space for private data");
-      goto get_privkey_failed;
-  }
-  /* and store priv key related data */
-  h->choosen_key->type = key_type;
-  h->choosen_key->id = h->choosen_cert->id;
-  h->choosen_key->id_length = h->choosen_cert->id_length;
-  h->choosen_key->x509 = h->choosen_cert->x509;
-  h->choosen_key->private_key = object;
 
   /* and finally release Find session */
   rv = h->fl->C_FindObjectsFinal(h->session);
-    if (rv != CKR_OK) {
-      set_error("C_FindObjectsFinal() failed: %x", rv);
-      return -1;
-    }
+  if (rv != CKR_OK) {
+    set_error("C_FindObjectsFinal() failed: %x", rv);
+    return -1;
+  }
 
+  cert->private_key = object;
+  cert->key_type = CKK_RSA;
+
   return 0;
 
 get_privkey_failed:
   rv = h->fl->C_FindObjectsFinal(h->session);
   if (rv != CKR_OK) {
     set_error("C_FindObjectsFinal() failed: %x", rv);
-    return -1;
   }
-  h->choosen_key=NULL;
-    return -1;
+  return -1;
 }
 
-int sign_value(pkcs11_handle_t *h, CK_BYTE *data, CK_ULONG length,
-               CK_BYTE **signature, CK_ULONG *signature_length)
+const char *get_slot_label(pkcs11_handle_t *h)
 {
+  return h->slots[h->current_slot].label;
+}
+
+const X509 *get_X509_certificate(cert_object_t *cert)
+{
+  return cert->x509;
+}
+
+int sign_value(pkcs11_handle_t *h, cert_object_t *cert, CK_BYTE *data,
+ CK_ULONG length, CK_BYTE **signature, CK_ULONG *signature_length)
+{
   int rv;
   CK_BYTE hash[15 + SHA_DIGEST_LENGTH] =
       "\x30\x21\x30\x09\x06\x05\x2b\x0e\x03\x02\x1a\x05\x00\x04\x14";
   CK_MECHANISM mechanism = { 0, NULL, 0 };
 
+
+  if (get_private_key(h, cert) == -1) {
+    set_error("Couldn't find private key for certificate");
+    return -1;
+  }
+
   /* set mechanism */
-  switch (h->choosen_key->type) {
+  switch (cert->key_type) {
     case CKK_RSA:
       mechanism.mechanism = CKM_RSA_PKCS;
       break;
     default:
-      set_error("unsupported key type %d", h->choosen_key->type);
+      set_error("unsupported key type %d", cert->type);
       return -1;
   }
   /* compute hash-value */
@@ -529,7 +1170,7 @@
   DBG5("hash[%d] = [...:%02x:%02x:%02x:...:%02x]", sizeof(hash),
       hash[15], hash[16], hash[17], hash[sizeof(hash) - 1]);
   /* sign the token */
-  rv = h->fl->C_SignInit(h->session, &mechanism, h->choosen_key->private_key);
+  rv = h->fl->C_SignInit(h->session, &mechanism, cert->private_key);
   if (rv != CKR_OK) {
     set_error("C_SignInit() failed: %x", rv);
     return -1;
@@ -588,3 +1229,4 @@
       data[1], data[2], data[length - 1]);
   return 0;
 }
+#endif /* HAVE_NSS */
Index: src/common/Makefile.am
===================================================================
--- src/common/Makefile.am (revision 237)
+++ src/common/Makefile.am (working copy)
@@ -2,6 +2,9 @@
 
 MAINTAINERCLEANFILES = Makefile.in
 
+AM_CFLAGS = $(CRYPTO_CFLAGS)
+AM_CPPFLAGS = $(CRYPTO_CFLAGS)
+
 SUBDIRS = . rsaref
 
 noinst_HEADERS = debug.h error.h uri.h strings.h \
@@ -10,12 +13,12 @@
 noinst_PROGRAMS =
 noinst_LTLIBRARIES = libcommon.la
 
-libcommon_la_SOURCES = cert_vfy.c cert_vfy.h \
+libcommon_la_SOURCES = algorithm.c cert_vfy.c cert_vfy.h \
  cert_info.c cert_info.h \
  debug.c debug.h error.c error.h \
  uri.c uri.h strings.c strings.h \
  pkcs11_lib.c \
  base64.c base64.h
 
-libcommon_la_LIBADD = $(OPENSSL_LIBS) $(PTHREAD_LIBS)
+libcommon_la_LIBADD = $(CRYPTO_LIBS) $(PTHREAD_LIBS)
 libcommon_la_CFLAGS = $(PTHREAD_CFLAGS)
Index: src/common/pkcs11_lib.h
===================================================================
--- src/common/pkcs11_lib.h (revision 237)
+++ src/common/pkcs11_lib.h (working copy)
@@ -17,59 +17,35 @@
 #ifndef __PKCS11_LIB_H__
 #define __PKCS11_LIB_H__
 
-#include <openssl/x509.h>
-#include "rsaref/pkcs11.h"
+#include "cert_st.h"
 
-typedef struct {
-  CK_KEY_TYPE type;
-  CK_BYTE *id;
-  CK_ULONG id_length;
-  CK_OBJECT_HANDLE private_key;
-  X509 *x509;
-} key_object_t;
+typedef struct cert_object_str cert_object_t;
+typedef struct pkcs11_handle_str pkcs11_handle_t;
 
-typedef struct {
-  CK_KEY_TYPE type;
-  CK_BYTE *id;
-  CK_ULONG id_length;
-  X509 *x509;
-} cert_object_t;
-
-typedef struct {
-  CK_SLOT_ID id;
-  CK_BBOOL token_present;
-  CK_UTF8CHAR label[33];
-} slot_t;
-
-typedef struct {
-  void *module_handle;
-  CK_FUNCTION_LIST_PTR fl;
-  slot_t *slots;
-  CK_ULONG slot_count;
-  CK_SESSION_HANDLE session;
-  cert_object_t *certs;
-  int cert_count;
-  cert_object_t *choosen_cert;
-  key_object_t *choosen_key;
-} pkcs11_handle_t;
-
 #ifndef __PKCS11_LIB_C__
 #define PKCS11_EXTERN extern
 #else
 #define PKCS11_EXTERN
 #endif
 
-PKCS11_EXTERN int load_pkcs11_module(char *module, pkcs11_handle_t *h);
+PKCS11_EXTERN int crypto_init(cert_policy *policy);
+PKCS11_EXTERN int load_pkcs11_module(char *module, pkcs11_handle_t **h);
 PKCS11_EXTERN int init_pkcs11_module(pkcs11_handle_t *h,int flag);
+PKCS11_EXTERN int find_slot_by_number(pkcs11_handle_t *h,int slot_num,
+                                      unsigned int *slot);
+PKCS11_EXTERN const char *get_slot_label(pkcs11_handle_t *h);
+PKCS11_EXTERN const X509 *get_X509_certificate(cert_object_t *cert);
 PKCS11_EXTERN void release_pkcs11_module(pkcs11_handle_t *h);
 PKCS11_EXTERN int open_pkcs11_session(pkcs11_handle_t *h, unsigned int slot);
 PKCS11_EXTERN int close_pkcs11_session(pkcs11_handle_t *h);
 PKCS11_EXTERN int pkcs11_login(pkcs11_handle_t *h, char *password);
 PKCS11_EXTERN int pkcs11_pass_login(pkcs11_handle_t *h, int nullok);
-PKCS11_EXTERN int get_certificates(pkcs11_handle_t *h);
-PKCS11_EXTERN int get_private_key(pkcs11_handle_t *h);
-PKCS11_EXTERN int sign_value(pkcs11_handle_t *h, CK_BYTE *data, CK_ULONG length,
-               CK_BYTE **signature, CK_ULONG *signature_length);
+PKCS11_EXTERN cert_object_t **get_certificate_list(pkcs11_handle_t *h,
+                                                  int *ncert);
+PKCS11_EXTERN int get_private_key(pkcs11_handle_t *h, cert_object_t *);
+PKCS11_EXTERN int sign_value(pkcs11_handle_t *h, cert_object_t *,
+               unsigned char *data, unsigned long length,
+               unsigned char **signature, unsigned long *signature_length);
 PKCS11_EXTERN int get_random_value(unsigned char *data, int length);
 
 #undef PKCS11_EXTERN

_______________________________________________
opensc-devel mailing list
[hidden email]
http://www.opensc-project.org/mailman/listinfo/opensc-devel

smime.p7s (4K) Download Attachment
Reply | Threaded
Open this post in threaded view
|

Re: Re: pam_pkcs11 NSS patch.

Ludovic Rousseau
On 05/04/07, Robert Relyea <[hidden email]> wrote:
> Since those are separate ideas I'll give them in separate paches. The
> NSS patch is included here.
>
> This patch is the largest of the three, so it makes sense to get it
> through first. I've attached the patch and a (fairly long) description
> of the changes that were made. Hopefully the latter will help you
> identify potential issues without getting bogged down in the details.
> The patch applies is made from the current svn trunk build pulled this
> morning (PDT).

Applied in revision 238.

Go on with the other patches.

Regards,

--
 Dr. Ludovic Rousseau
_______________________________________________
opensc-devel mailing list
[hidden email]
http://www.opensc-project.org/mailman/listinfo/opensc-devel
Reply | Threaded
Open this post in threaded view
|

Re: Re: pam_pkcs11 NSS patch.

Ludovic Rousseau
In reply to this post by relyea
On 05/04/07, Robert Relyea <[hidden email]> wrote:
>     Introduction to the pam_pkcs11-nss.patch

I have a compiler warning:
pkcs11_eventmgr.c: In function 'main':
pkcs11_eventmgr.c:502: attention : passing argument 2 of
'load_pkcs11_module' from incompatible pointer type

I think a correct patch is:
Index: src/tools/pkcs11_eventmgr.c
===================================================================
--- src/tools/pkcs11_eventmgr.c (révision 238)
+++ src/tools/pkcs11_eventmgr.c (copie de travail)
@@ -499,7 +499,7 @@ int main(int argc, char *argv[]) {
     parse_args(argc,argv);
     /* load pkcs11 module */
     DBG("loading pkcs #11 module...");
-    rv = load_pkcs11_module(pkcs11_module, ph);
+    rv = load_pkcs11_module(pkcs11_module, &ph);
     if (rv != 0) {
         DBG1("load_pkcs11_module() failed: %s", get_error());
         return 1;


I applied the proposed patch in revision 241. If you think it is wrong
please tell me.

bye

--
 Dr. Ludovic Rousseau
_______________________________________________
opensc-devel mailing list
[hidden email]
http://www.opensc-project.org/mailman/listinfo/opensc-devel
Reply | Threaded
Open this post in threaded view
|

Re: Re: pam_pkcs11 NSS patch.

relyea
Ludovic Rousseau wrote:

> On 05/04/07, Robert Relyea <[hidden email]> wrote:
>>     Introduction to the pam_pkcs11-nss.patch
>
> I have a compiler warning:
> pkcs11_eventmgr.c: In function 'main':
> pkcs11_eventmgr.c:502: attention : passing argument 2 of
> 'load_pkcs11_module' from incompatible pointer type
>
> I think a correct patch is:
> Index: src/tools/pkcs11_eventmgr.c
> ===================================================================
> --- src/tools/pkcs11_eventmgr.c (révision 238)
> +++ src/tools/pkcs11_eventmgr.c (copie de travail)
> @@ -499,7 +499,7 @@ int main(int argc, char *argv[]) {
>     parse_args(argc,argv);
>     /* load pkcs11 module */
>     DBG("loading pkcs #11 module...");
> -    rv = load_pkcs11_module(pkcs11_module, ph);
> +    rv = load_pkcs11_module(pkcs11_module, &ph);
>     if (rv != 0) {
>         DBG1("load_pkcs11_module() failed: %s", get_error());
>         return 1;
>
>
> I applied the proposed patch in revision 241. If you think it is wrong
> please tell me.
Yikes, This is the correct patch!

I just did an update, and a clean checkout, and it looks like the new
files didn't get added to the repository.

A      src/common/SSLerrs.h
A      src/common/cert_st.h
A      src/common/SECerrs.h
A      src/common/secutil.h
A      src/common/alg_st.h
A      src/common/NSPRerrs.h
A      src/common/algorithm.c

They must be in or tree, or you wouldn't have been able to compile.

I'll get the next patch ready just now!

Thanks!

bob
>
> bye
>


_______________________________________________
opensc-devel mailing list
[hidden email]
http://www.opensc-project.org/mailman/listinfo/opensc-devel

smime.p7s (4K) Download Attachment
Reply | Threaded
Open this post in threaded view
|

Re: Re: pam_pkcs11 NSS patch.

Ludovic Rousseau
On 12/04/07, Robert Relyea <[hidden email]> wrote:

> I just did an update, and a clean checkout, and it looks like the new
> files didn't get added to the repository.
>
> A      src/common/SSLerrs.h
> A      src/common/cert_st.h
> A      src/common/SECerrs.h
> A      src/common/secutil.h
> A      src/common/alg_st.h
> A      src/common/NSPRerrs.h
> A      src/common/algorithm.c
>
> They must be in or tree, or you wouldn't have been able to compile.

Exact. "svn diff" did not show them.
I also modified src/common/Makefile.am to include them in the .tar.gz
generated by "make dist".

Now corrected with revision 244

Thanks

--
  Dr. Ludovic Rousseau
_______________________________________________
opensc-devel mailing list
[hidden email]
http://www.opensc-project.org/mailman/listinfo/opensc-devel
Reply | Threaded
Open this post in threaded view
|

Re: Re: pam_pkcs11 NSS patch.

relyea
Ludovic Rousseau wrote:
> On 12/04/07, Robert Relyea <[hidden email]> wrote:
>> I just did an update, and a clean checkout, and it looks like the new
>> files didn't get added to the repository.
>
> Exact. "svn diff" did not show them.
> I also modified src/common/Makefile.am to include them in the .tar.gz
> generated by "make dist".
>
> Now corrected with revision 244
Thanks!

Here's patch installment 2 of 3.

This patch adds some new semantics to allow pam_pkcs11 to play nice in
both command line and gui applications. The heart of this change adds
three new configuration options.

card_only:
  1. If card only is set, pam_pkcs11 does not prompt for the user name
if  the token is inserted, but gets the user name from the token.
  2. If a token is inserted, it must be used to log in with, failure to
unlock the token, or validate the certs will cause login to fail.
  3. If we logged in using a smart card, we must now authenticate using
that same smart card.
  4. card_only is required to activate the remaining 2 options. If
card_only is not set, the current pam_pkcs11 semantics apply (with the
exception of some prompt name changes and the environment variables
described below).

wait_for_token:
  wait_for_token is only meaningful if card_only is set.
  if wait_for_token is set, then pam_pkcs11 will block waiting for an
  appropriate token to be inserted. An appropriate token is:
    1) a token that is inserted in the slot specified for login in the
config
    file (if no slot is specified a token inserted in any slot).
    2) a token which matches the token used to log in initially. (only
applies
    if you are logged in and you used a token to do so).

screen_savers:
   is a list of screen saver services. This list is only parsed if
card_only is
   set. Basically the screen saver will bypass pam_pkcs11 if a token was not
   used to login (The basic idea is you always unlock the screen saver with
   the same mechanism you used to login).

The other major change is the addition of new environment variables:
PKCS11_LOGIN_TOKEN_NAME - the name of the token used to log into the system.
PKCS11_LOGIN_CERT_ISSUER - the issuer of the cert used to log in
(rendered as
a human readable string).
PKCS11_LOGIN_CERT_SERIAL - the serial number of the cert used to log in
(rendered as colon separated hex value).

These environment variables are set at initial login.

pam_pkcs11 uses PKCS_LOGIN_TOKEN_NAME to determine whether or not it
needs to
use a specific token to log into.

screen savers use this environment variable to determine
if it needs to kick in on token removal (this allows screen savers to be
picky about when to kick in -- they don't have to kick in if you insert or
remove a token that wasn't used to log into).

pam_krb uses the PKCS11_LOGIN_CERT_ISSUER and PKCS11_LOGIN_CERT_SERIAL to
determine which specific certificate was used to login in (issuer/serial
number
uniquely identifies a certificate).

Typical usage for the patch:

For a normal (card_only) case, your pam line would look like:

auth        [success=ok authinfo_unavail=2 ignore=2 default=die]
pam_pkcs11.so

For the case where you want to require the smart card as part of the
authentication, your pam config line would look like:

auth        [success=ok ignore=2 default=die] pam_pkcs11.so wait_for_card

If you share your pam_config file with all our services, you can restrict
which services require smart card login with a pam_succeed_if before your
pam_pkcs11 line:

auth        [success=3 default=ignore] pam_succeed_if.so service notin
login:gdm:xdm:kdm:xscreensaver:gnome-screensaver:kscreensaver quiet use_uid

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

The patch itself, file by file:

src/pam_pkcs11/pam_pkcs11.c -

Most of the patch is in here. The implementation of the environment
variables
and new options are in this patch. In addition to the these, the patch has
the following change:

1) a bug fix for passing the password on in the pam_stack (required to
pam_krb
to successfully implement pkinit).
2) use the pam_syslog() function instead of syslog().
3) use of pam_prompt to allow gui apps to display important information.

src/pam_pkcs11/pam_config.[ch] -

parse the new options in pam_pkcs11.conf.

src/tools/pkcs11_setup.c -
src/tools/Makefile.am

This is a new tool to allow command line editting of pam_pkcs11.conf and
pkcs11_eventmgr.conf. It only supports adding insertion/removal actions and
changing the default token. We don't actually use it any more, but it
may have
utility to others. I think the command may need some work to be more
general.
It's purpose is to allow perl/python/your favorite scripting language access
to display and modify portions of the pam_pkcs11.conf file. (Feel free
to drop
it if you like, I've included it for completeness).

src/tools/pkcs11_eventmgr.c -

bug fix for a crash if module loading fails.

src/common/cert_info.c

Add the ability to fetch the certificate serial number when using the
open ssl
library.

src/common/pkcs11_lib.[ch]

Add find_slot_by_number_and_label() which optionally adds the token name as
part of the slot selection criteria. Used by pam_pkcs11 in the case we are
authenticating after we have already logged in.

Add wait_for_token() which waits until an approriate token is inserted. Used
to implement the wait_for_token option.

src/common/strings.c

Fix bug in bin2hex where it would trash the heap if asked to output a string
for a zero length buffer.



Index: src/pam_pkcs11/pam_pkcs11.c
===================================================================
--- src/pam_pkcs11/pam_pkcs11.c (revision 264)
+++ src/pam_pkcs11/pam_pkcs11.c (working copy)
@@ -26,6 +26,7 @@
 #endif
 #include <security/pam_appl.h>
 #include <security/pam_modules.h>
+#include <security/pam_ext.h>
 #include <syslog.h>
 #include <ctype.h>
 #include <string.h>
@@ -35,6 +36,7 @@
 #include "../common/error.h"
 #include "../common/pkcs11_lib.h"
 #include "../common/cert_vfy.h"
+#include "../common/cert_info.h"
 #include "../common/cert_st.h"
 #include "pam_config.h"
 #include "mapper_mgr.h"
@@ -102,7 +104,7 @@
     free(&resp[0]);
     /* save password if variable nitem is set */
     if ((nitem == PAM_AUTHTOK) || (nitem == PAM_OLDAUTHTOK)) {
-      rv = pam_set_item(pamh, nitem, pwd);
+      rv = pam_set_item(pamh, nitem, *pwd);
       if (rv != PAM_SUCCESS)
         return rv;
     }
@@ -114,11 +116,13 @@
 PAM_EXTERN int pam_sm_authenticate(pam_handle_t *pamh, int flags, int argc, const char **argv)
 {
   int i, rv;
-  const char *user;
+  const char *user = NULL;
   char *password;
-  char password_prompt[64];
+  char password_prompt[70];
   unsigned int slot_num = 0;
+  int is_a_screen_saver = 0;
   struct configuration_st *configuration;
+  int pkcs11_pam_fail = PAM_AUTHINFO_UNAVAIL;
 
   pkcs11_handle_t *ph;
   cert_object_t *chosen_cert = NULL;
@@ -127,6 +131,10 @@
   unsigned char random_value[128];
   unsigned char *signature;
   unsigned long signature_length;
+  /* enough space to hold an issuer DN */
+  char env_temp[256] = "";
+  char **issuer, **serial;
+  const char *login_token_name = NULL;
 
   /* first of all check whether debugging should be enabled */
   for (i = 0; i < argc; i++)
@@ -140,8 +148,6 @@
  ERR("Error setting configuration parameters");
  return PAM_AUTHINFO_UNAVAIL;
   }
-  /* open log */
-  openlog(LOGNAME, LOG_CONS | LOG_PID, LOG_AUTHPRIV);
 
   /* fail if we are using a remote server
    * local login: DISPLAY=:0
@@ -152,7 +158,8 @@
   if (display && (display[0] != ':') && (display[0] != '\0'))
   {
  ERR1("Remote login (from %s) is not (yet) supported", display);
- syslog(LOG_ERR, "Remote login (from %s) is not (yet) supported",
+ pam_syslog(pamh, LOG_ERR,
+                        "Remote login (from %s) is not (yet) supported",
  display);
  return PAM_AUTHINFO_UNAVAIL;
   }
@@ -162,24 +169,74 @@
   rv = crypto_init(&configuration->policy);
   if (rv != 0) {
     ERR("Failed to initialize crypto");
-    syslog(LOG_ERR, "Failed to initialize crypto");
+    pam_syslog(pamh,LOG_ERR, "Failed to initialize crypto");
     return PAM_AUTHINFO_UNAVAIL;
   }
 
-  /* get user name */
-  rv = pam_get_user(pamh, &user, NULL);
-  if (rv != PAM_SUCCESS) {
-    syslog(LOG_ERR, "pam_get_user() failed %s", pam_strerror(pamh, rv));
-    return PAM_USER_UNKNOWN;
+
+  /*
+   * card_only means:
+   *  1) always get the userid from the certificate.
+   *  2) don't prompt for the user name if the card is present.
+   *  3) if the token is present, then we must use the cardAuth mechanism.
+   *
+   * wait_for_card means:
+   *  1) nothing if card_only isn't set
+   *  2) if logged in, block in pam conversation until the token used for login
+   *     is inserted
+   *  3) if not logged in, block until a token that could be used for logging in
+   *     is inserted
+   * right now, logged in means PKC11_LOGIN_TOKEN_NAME is set,
+   * but we could something else later (like set some per-user state in
+   * a pam session module keyed off uid)
+   */
+  if (configuration->card_only) {
+ char *service;
+ if (configuration->screen_savers) {
+    DBG("Is it a screen saver?");
+        rv = pam_get_item(pamh, PAM_SERVICE, (const void **) &service);
+    for (i=0; configuration->screen_savers[i]; i++) {
+ if (strcmp(configuration->screen_savers[i], service) == 0) {
+    is_a_screen_saver = 1;
+    break;
+ }
+    }
+ }
+
+ pkcs11_pam_fail = PAM_CRED_INSUFFICIENT;
+        
+ /* look to see if username is already set */
+     rv = pam_get_item(pamh, PAM_USER, (const void **) &user);
+ if (user) {
+    DBG1("explicit username = [%s]", user);
+ }
+  } else {
+        pam_prompt(pamh, PAM_TEXT_INFO, NULL,
+                   "Please insert your smart card or enter your username.");
+ /* get user name */
+ rv = pam_get_user(pamh, &user, NULL);
+
+ if (rv != PAM_SUCCESS) {
+  pam_syslog(pamh, LOG_ERR,
+                     "pam_get_user() failed %s", pam_strerror(pamh, rv));
+  return PAM_USER_UNKNOWN;
+ }
+ DBG1("username = [%s]", user);
   }
-  DBG1("username = [%s]", user);
+  login_token_name = getenv("PKCS11_LOGIN_TOKEN_NAME");
 
+  /* if we are using a screen saver, and we didn't log in using the smart card
+   * drop to the next pam module.  */
+  if (is_a_screen_saver && !login_token_name) {
+    return PAM_IGNORE;
+  }
+
   /* load pkcs #11 module */
   DBG("loading pkcs #11 module...");
   rv = load_pkcs11_module(configuration->pkcs11_modulepath, &ph);
   if (rv != 0) {
     ERR1("load_pkcs11_module() failed: %s", get_error());
-    syslog(LOG_ERR, "load_pkcs11_module() failed: %s", get_error());
+    pam_syslog(pamh, LOG_ERR, "load_pkcs11_module() failed: %s", get_error());
     return PAM_AUTHINFO_UNAVAIL;
   }
 
@@ -189,39 +246,86 @@
   if (rv != 0) {
     release_pkcs11_module(ph);
     ERR1("init_pkcs11_module() failed: %s", get_error());
-    syslog(LOG_ERR, "init_pkcs11_module() failed: %s", get_error());
+    pam_syslog(pamh, LOG_ERR, "init_pkcs11_module() failed: %s", get_error());
     return PAM_AUTHINFO_UNAVAIL;
   }
 
   /* open pkcs #11 session */
-  rv = find_slot_by_number(ph, configuration->slot_num, &slot_num);
+  rv = find_slot_by_number_and_label(ph, configuration->slot_num,
+                                     login_token_name, &slot_num);
   if (rv != 0) {
-    release_pkcs11_module(ph);
-    ERR("no token available");
-    syslog(LOG_ERR, "no token available");
-    return PAM_AUTHINFO_UNAVAIL;
+    ERR("no suitable token available");
+    pam_syslog(pamh, LOG_ERR, "no suitable token available");
+
+    if (!configuration->card_only) {
+      release_pkcs11_module(ph);
+      return PAM_AUTHINFO_UNAVAIL;
+    }
+
+    /* we must have a smart card, either because we've configured it as such,
+     * or because we used one to log in */
+    if (login_token_name || configuration->wait_for_card) {
+      if (login_token_name) {
+        sprintf(password_prompt,
+                "Please insert your smart card called \"%.32s\".",
+                login_token_name);
+        pam_prompt(pamh, PAM_TEXT_INFO, NULL, password_prompt);
+      } else {
+        pam_prompt(pamh, PAM_TEXT_INFO, NULL,
+                 "Please insert your smart card.");
+      }
+      rv = wait_for_token(ph, configuration->slot_num,
+                          login_token_name, &slot_num);
+      if (rv != 0) {
+        release_pkcs11_module(ph);
+        return pkcs11_pam_fail;
+      }
+    } else if (user) {
+      /* we have a user and no smart card, go to the next pam module */
+      release_pkcs11_module(ph);
+      return PAM_AUTHINFO_UNAVAIL;
+    } else {
+      /* we haven't prompted for the user yet, get the user and see if
+       * the smart card has been inserted in the mean time */
+      pam_prompt(pamh, PAM_TEXT_INFO, NULL,
+                 "Please insert your smart card or enter username.");
+      rv = pam_get_user(pamh, &user, NULL);
+
+      /* check one last time for the smart card before bouncing to the next
+       * module */
+      rv = find_slot_by_number(ph, configuration->slot_num, &slot_num);
+      if (rv != 0) {
+        /* user gave us a user id and no smart card go to next module */
+        release_pkcs11_module(ph);
+        return PAM_AUTHINFO_UNAVAIL;
+      }
+    }
+  } else {
+      pam_prompt(pamh, PAM_TEXT_INFO, NULL, "Smart card inserted. ");
   }
   rv = open_pkcs11_session(ph, slot_num);
   if (rv != 0) {
     release_pkcs11_module(ph);
     ERR1("open_pkcs11_session() failed: %s", get_error());
-    syslog(LOG_ERR, "open_pkcs11_session() failed: %s", get_error());
-    return PAM_AUTHINFO_UNAVAIL;
+    pam_syslog(pamh, LOG_ERR, "open_pkcs11_session() failed: %s", get_error());
+    return pkcs11_pam_fail;
   }
 
   /* get password */
-  sprintf(password_prompt, "PIN for token %.32s: ", get_slot_label(ph));
+  sprintf(password_prompt, "Welcome %.32s!", get_slot_label(ph));
+  pam_prompt(pamh, PAM_TEXT_INFO, NULL, password_prompt);
   if (configuration->use_first_pass) {
     rv = pam_get_pwd(pamh, &password, NULL, PAM_AUTHTOK, 0);
   } else if (configuration->try_first_pass) {
-    rv = pam_get_pwd(pamh, &password, password_prompt, PAM_AUTHTOK, PAM_AUTHTOK);
+    rv = pam_get_pwd(pamh, &password, "Smart card password:", PAM_AUTHTOK, PAM_AUTHTOK);
   } else {
-    rv = pam_get_pwd(pamh, &password, password_prompt, 0, PAM_AUTHTOK);
+    rv = pam_get_pwd(pamh, &password, "Smart card password:", 0, PAM_AUTHTOK);
   }
   if (rv != PAM_SUCCESS) {
     release_pkcs11_module(ph);
-    syslog(LOG_ERR, "pam_get_pwd() failed: %s", pam_strerror(pamh, rv));
-    return PAM_AUTHINFO_UNAVAIL;
+    pam_syslog(pamh, LOG_ERR,
+               "pam_get_pwd() failed: %s", pam_strerror(pamh, rv));
+    return pkcs11_pam_fail;
   }
 #ifndef DEBUG_HIDE_PASSWORD
   DBG1("password = [%s]", password);
@@ -232,7 +336,8 @@
     release_pkcs11_module(ph);
     memset(password, 0, strlen(password));
     free(password);
-    syslog(LOG_ERR, "password length is zero but the 'nullok' argument was not defined.");
+    pam_syslog(pamh, LOG_ERR,
+         "password length is zero but the 'nullok' argument was not defined.");
     return PAM_AUTH_ERR;
   }
 
@@ -245,14 +350,14 @@
   free(password);
   if (rv != 0) {
     ERR1("open_pkcs11_login() failed: %s", get_error());
-    syslog(LOG_ERR, "open_pkcs11_login() failed: %s", get_error());
+    pam_syslog(pamh, LOG_ERR, "open_pkcs11_login() failed: %s", get_error());
     goto auth_failed_nopw;
   }
 
   cert_list = get_certificate_list(ph, &ncert);
   if (rv<0) {
     ERR1("get_certificate_list() failed: %s", get_error());
-    syslog(LOG_ERR, "get_certificate_list() failed: %s", get_error());
+    pam_syslog(pamh, LOG_ERR, "get_certificate_list() failed: %s", get_error());
     goto auth_failed_nopw;
   }
 
@@ -261,7 +366,7 @@
 
   /* find a valid and matching certificates */
   for (i = 0; i < ncert; i++) {
-    X509 *x509 = get_X509_certificate(cert_list[i]);
+    X509 *x509 = (X509 *)get_X509_certificate(cert_list[i]);
     if (!x509 ) continue; /* sanity check */
     DBG1("verifing the certificate #%d", i + 1);
 
@@ -269,7 +374,8 @@
       rv = verify_certificate(x509,&configuration->policy);
       if (rv < 0) {
         ERR1("verify_certificate() failed: %s", get_error());
-        syslog(LOG_ERR, "verify_certificate() failed: %s", get_error());
+        pam_syslog(pamh, LOG_ERR,
+                   "verify_certificate() failed: %s", get_error());
  goto auth_failed_nopw;
       } else if (rv != 1) {
         ERR1("verify_certificate() failed: %s", get_error());
@@ -287,7 +393,8 @@
  user=find_user(x509);
  if (!user) {
           ERR2("find_user() failed: %s on cert #%d", get_error(),i+1);
-          syslog(LOG_ERR,"find_user() failed: %s on cert #%d",get_error(),i+1);
+          pam_syslog(pamh, LOG_ERR,
+                     "find_user() failed: %s on cert #%d",get_error(),i+1);
   continue; /* try on next certificate */
  } else {
           DBG1("certificate is valid and matches user %s",user);
@@ -295,7 +402,8 @@
     rv = pam_set_item(pamh, PAM_USER,(const void *)user);
   if (rv != PAM_SUCCESS) {
     ERR1("pam_set_item() failed %s", pam_strerror(pamh, rv));
-    syslog(LOG_ERR, "pam_set_item() failed %s", pam_strerror(pamh, rv));
+    pam_syslog(pamh, LOG_ERR,
+                       "pam_set_item() failed %s", pam_strerror(pamh, rv));
     goto auth_failed_nopw;
  }
           chosen_cert = cert_list[i];
@@ -307,7 +415,7 @@
         rv = match_user(x509, user);
         if (rv < 0) { /* match error; abort and return */
           ERR1("match_user() failed: %s", get_error());
-          syslog(LOG_ERR, "match_user() failed: %s", get_error());
+          pam_syslog(pamh, LOG_ERR, "match_user() failed: %s", get_error());
   goto auth_failed_nopw;
         } else if (rv == 0) { /* match didn't success */
           DBG("certificate is valid bus does not match the user");
@@ -323,7 +431,8 @@
   /* now myCert points to our found certificate or null if no user found */
   if (!chosen_cert) {
     ERR("no valid certificate which meets all requirements found");
-    syslog(LOG_ERR, "no valid certificate which meets all requirements found");
+    pam_syslog(pamh, LOG_ERR,
+               "no valid certificate which meets all requirements found");
     goto auth_failed_nopw;
   }
 
@@ -335,7 +444,8 @@
     rv = get_private_key(ph);
     if (rv != 0) {
       ERR1("get_private_key() failed: %s", get_error());
-      syslog(LOG_ERR, "get_private_key() failed: %s", get_error());
+      pam_syslog(pamh, LOG_ERR,
+                 "get_private_key() failed: %s", get_error());
       goto auth_failed_nopw;
     }
 #endif
@@ -344,7 +454,7 @@
     rv = get_random_value(random_value, sizeof(random_value));
     if (rv != 0) {
       ERR1("get_random_value() failed: %s", get_error());
-      syslog(LOG_ERR, "get_random_value() failed: %s", get_error());
+      pam_syslog(pamh, LOG_ERR, "get_random_value() failed: %s", get_error());
       goto auth_failed_nopw;
     }
 
@@ -354,20 +464,22 @@
     &signature, &signature_length);
     if (rv != 0) {
       ERR1("sign_value() failed: %s", get_error());
-      syslog(LOG_ERR, "sign_value() failed: %s", get_error());
+      pam_syslog(pamh, LOG_ERR, "sign_value() failed: %s", get_error());
       goto auth_failed_nopw;
     }
 
     /* verify the signature */
     DBG("verifying signature...");
-    rv = verify_signature(get_X509_certificate(chosen_cert),
+    rv = verify_signature((X509 *)get_X509_certificate(chosen_cert),
              random_value, sizeof(random_value), signature, signature_length);
-    if (signature != NULL) free(signature);
+    if (signature != NULL) {
+      free(signature);
+    }
     if (rv != 0) {
       close_pkcs11_session(ph);
       release_pkcs11_module(ph);
       ERR1("verify_signature() failed: %s", get_error());
-      syslog(LOG_ERR, "verify_signature() failed: %s", get_error());
+      pam_syslog(pamh, LOG_ERR, "verify_signature() failed: %s", get_error());
       return PAM_AUTH_ERR;
     }
 
@@ -375,13 +487,69 @@
       DBG("Skipping signature check");
   }
 
+  /*
+   * fill in the environment variables.
+   */
+  snprintf(env_temp, sizeof(env_temp) - 1,
+   "PKCS11_LOGIN_TOKEN_NAME=%.*s",
+   (sizeof(env_temp) - 1) - strlen("PKCS11_LOGIN_TOKEN_NAME="),
+   get_slot_label(ph));
+  rv = pam_putenv(pamh, env_temp);
+
+  if (rv != PAM_SUCCESS) {
+    ERR1("could not put token name in environment: %s",
+         pam_strerror(pamh, rv));
+    pam_syslog(pamh, LOG_ERR, "could not put token name in environment: %s",
+           pam_strerror(pamh, rv));
+  }
+
+  issuer = cert_info((X509 *)get_X509_certificate(chosen_cert), CERT_ISSUER,
+                     ALGORITHM_NULL);
+  if (issuer) {
+    snprintf(env_temp, sizeof(env_temp) - 1,
+   "PKCS11_LOGIN_CERT_ISSUER=%.*s",
+   (sizeof(env_temp) - 1) - strlen("PKCS11_LOGIN_CERT_ISSUER="),
+   issuer[0]);
+    rv = pam_putenv(pamh, env_temp);
+  } else {
+    ERR("couldn't get certificate issuer.");
+    pam_syslog(pamh, LOG_ERR, "couldn't get certificate issuer.");
+  }
+
+  if (rv != PAM_SUCCESS) {
+    ERR1("could not put cert issuer in environment: %s",
+         pam_strerror(pamh, rv));
+    pam_syslog(pamh, LOG_ERR, "could not put cert issuer in environment: %s",
+           pam_strerror(pamh, rv));
+  }
+
+  serial = cert_info((X509 *)get_X509_certificate(chosen_cert), CERT_SERIAL,
+                     ALGORITHM_NULL);
+  if (serial) {
+    snprintf(env_temp, sizeof(env_temp) - 1,
+   "PKCS11_LOGIN_CERT_SERIAL=%.*s",
+   (sizeof(env_temp) - 1) - strlen("PKCS11_LOGIN_CERT_SERIAL="),
+   serial[0]);
+    rv = pam_putenv(pamh, env_temp);
+  } else {
+    ERR("couldn't get certificate serial number.");
+    pam_syslog(pamh, LOG_ERR, "couldn't get certificate serial number.");
+  }
+
+  if (rv != PAM_SUCCESS) {
+    ERR1("could not put cert serial in environment: %s",
+         pam_strerror(pamh, rv));
+    pam_syslog(pamh, LOG_ERR, "could not put cert serial in environment: %s",
+           pam_strerror(pamh, rv));
+  }
+
   /* close pkcs #11 session */
   rv = close_pkcs11_session(ph);
   if (rv != 0) {
     release_pkcs11_module(ph);
     ERR1("close_pkcs11_session() failed: %s", get_error());
-    syslog(LOG_ERR, "close_pkcs11_module() failed: %s", get_error());
-    return PAM_AUTHINFO_UNAVAIL;
+    pam_syslog(pamh, LOG_ERR, "close_pkcs11_module() failed: %s", get_error());
+    return pkcs11_pam_fail;
   }
 
   /* release pkcs #11 module */
@@ -399,7 +567,7 @@
     unload_mappers();
     close_pkcs11_session(ph);
     release_pkcs11_module(ph);
-    return PAM_AUTHINFO_UNAVAIL;
+    return pkcs11_pam_fail;
 }
 
 PAM_EXTERN int pam_sm_setcred(pam_handle_t *pamh, int flags, int argc, const char **argv)
@@ -412,36 +580,40 @@
 PAM_EXTERN int pam_sm_acct_mgmt(pam_handle_t *pamh, int flags, int argc, const char **argv)
 {
   ERR("Warning: Function pm_sm_acct_mgmt() is not implemented in this module");
-  openlog(LOGNAME, LOG_CONS | LOG_PID, LOG_AUTHPRIV);
-  syslog(LOG_WARNING, "Function pm_sm_acct_mgmt() is not implemented in this module");
-  closelog();
+  pam_syslog(pamh, LOG_WARNING,
+             "Function pm_sm_acct_mgmt() is not implemented in this module");
   return PAM_SERVICE_ERR;
 }
 
 PAM_EXTERN int pam_sm_open_session(pam_handle_t *pamh, int flags, int argc, const char **argv)
 {
   ERR("Warning: Function pam_sm_open_session() is not implemented in this module");
-  openlog(LOGNAME, LOG_CONS | LOG_PID, LOG_AUTHPRIV);
-  syslog(LOG_WARNING, "Function pm_sm_open_session() is not implemented in this module");
-  closelog();
+  pam_syslog(pamh, LOG_WARNING,
+             "Function pm_sm_open_session() is not implemented in this module");
   return PAM_SERVICE_ERR;
 }
 
 PAM_EXTERN int pam_sm_close_session(pam_handle_t *pamh, int flags, int argc, const char **argv)
 {
   ERR("Warning: Function pam_sm_close_session() is not implemented in this module");
-  openlog(LOGNAME, LOG_CONS | LOG_PID, LOG_AUTHPRIV);
-  syslog(LOG_WARNING, "Function pm_sm_close_session() is not implemented in this module");
-  closelog();
+  pam_syslog(pamh, LOG_WARNING,
+           "Function pm_sm_close_session() is not implemented in this module");
   return PAM_SERVICE_ERR;
 }
 
 PAM_EXTERN int pam_sm_chauthtok(pam_handle_t *pamh, int flags, int argc, const char **argv)
 {
+  char *login_token_name;
+
   ERR("Warning: Function pam_sm_chauthtok() is not implemented in this module");
-  openlog(LOGNAME, LOG_CONS | LOG_PID, LOG_AUTHPRIV);
-  syslog(LOG_WARNING, "Function pam_sm_chauthtok() is not implemented in this module");
-  closelog();
+  pam_syslog(pamh, LOG_WARNING,
+             "Function pam_sm_chauthtok() is not implemented in this module");
+
+  login_token_name = getenv("PKCS11_LOGIN_TOKEN_NAME");
+  if (login_token_name && (flags & PAM_PRELIM_CHECK)) {
+    pam_prompt(pamh, PAM_TEXT_INFO, NULL,
+               "Cannot change the password on your smart card.");
+  }
   return PAM_SERVICE_ERR;
 }
 
Index: src/pam_pkcs11/pam_config.c
===================================================================
--- src/pam_pkcs11/pam_config.c (revision 264)
+++ src/pam_pkcs11/pam_config.c (working copy)
@@ -39,8 +39,11 @@
         0, /* int try_first_pass; */
         0, /* int use_first_pass; */
         0, /* int use_authok; */
+        0, /* int card_only; */
+        0, /* int wait_for_card; */
         "default", /* const char *pkcs11_module; */
         "/etc/pam_pkcs11/pkcs11_module.so",/* const char *pkcs11_module_path; */
+        NULL,                           /* screen savers */
         0, /* int slot_num; */
  0, /* support threads */
  /* cert policy; */
@@ -55,6 +58,8 @@
         DBG1("try_first_pass %d",configuration.try_first_pass);
         DBG1("use_first_pass %d", configuration.use_first_pass);
         DBG1("use_authok %d", configuration.use_authok);
+        DBG1("card_only %d", configuration.card_only);
+        DBG1("wait_for_card %d", configuration.wait_for_card);
         DBG1("pkcs11_module %s",configuration.pkcs11_module);
         DBG1("slot_num %d",configuration.slot_num);
         DBG1("ca_dir %s",configuration.policy.ca_dir);
@@ -75,6 +80,8 @@
  scconf_block **pkcs11_mblocks,*pkcs11_mblk;
  const scconf_list *mapper_list;
  const scconf_list *policy_list;
+ const scconf_list *screen_saver_list;
+ const scconf_list *tmp;
  scconf_context *ctx;
  const scconf_block *root;
  configuration.ctx = scconf_new(configuration.config_file);
@@ -105,6 +112,10 @@
     scconf_get_bool(root,"try_first_pass",configuration.try_first_pass);
  configuration.use_authok =
     scconf_get_bool(root,"use_authok",configuration.use_authok);
+ configuration.card_only =
+    scconf_get_bool(root,"card_only",configuration.card_only);
+ configuration.wait_for_card =
+    scconf_get_bool(root,"wait_for_card",configuration.wait_for_card);
  configuration.pkcs11_module = ( char * )
     scconf_get_str(root,"use_pkcs11_module",configuration.pkcs11_module);
  /* search pkcs11 module options */
@@ -155,6 +166,18 @@
  policy_list= policy_list->next;
     }
  }
+ screen_saver_list = scconf_find_list(root,"screen_savers");
+ if (screen_saver_list) {
+   int count,i;
+   for (count=0, tmp=screen_saver_list; tmp ; tmp=tmp->next, count++);
+
+   configuration.screen_savers =
+ (char **) malloc((count+1)*sizeof(char *));
+   for (i=0, tmp=screen_saver_list; tmp; tmp=tmp->next, i++) {
+ configuration.screen_savers[i] = (char *)tmp->data;
+   }
+   configuration.screen_savers[count] = 0;
+        }
  /* now obtain and initialize mapper list */
  mapper_list = scconf_find_list(root,"use_mappers");
  if (!mapper_list) {
@@ -187,8 +210,8 @@
  parse_config_file();
  /* display_config(); */
  /* finally parse provided arguments */
- /* skip argv[0] :-) */
- for (i = 1; i < argc; i++) {
+ /* dont skip argv[0] */
+ for (i = 0; i < argc; i++) {
    if (strcmp("nullok", argv[i]) == 0) {
  configuration.nullok = 1;
  continue;
@@ -201,6 +224,14 @@
        configuration.use_first_pass = 1;
  continue;
    }
+       if (strcmp("wait_for_card", argv[i]) == 0) {
+       configuration.wait_for_card = 1;
+ continue;
+   }
+       if (strcmp("dont_wait_for_card", argv[i]) == 0) {
+       configuration.wait_for_card = 0;
+ continue;
+   }
        if (strcmp("debug", argv[i]) == 0) {
        configuration.debug = 1;
  set_debug_level(1);
Index: src/pam_pkcs11/pam_config.h
===================================================================
--- src/pam_pkcs11/pam_config.h (revision 264)
+++ src/pam_pkcs11/pam_config.h (working copy)
@@ -33,8 +33,11 @@
  int try_first_pass;
  int use_first_pass;
  int use_authok;
+ int card_only;
+ int wait_for_card;
  char *pkcs11_module;
  char *pkcs11_modulepath;
+ char **screen_savers;
  int slot_num;
  int support_threads;
  cert_policy policy;
Index: src/tools/pkcs11_setup.c
===================================================================
--- src/tools/pkcs11_setup.c (revision 0)
+++ src/tools/pkcs11_setup.c (revision 0)
@@ -0,0 +1,519 @@
+/*
+ * PKCS#11 Card viewer tool
+ * Copyright (C) 2006 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ */
+
+#define _GNU_SOURCE
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <ctype.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <dlfcn.h>
+#include "../scconf/scconf.h"
+#include "../common/debug.h"
+#include "../common/error.h"
+
+#define PAM_PKCS11_CONF "/etc/pam_pkcs11/pam_pkcs11.conf"
+#define EVENTMGR_CONF "/etc/pam_pkcs11/pkcs11_eventmgr.conf"
+
+static const char Ins_action[] = "ins_action=";
+static const char Rm_action[] = "rm_action=";
+static const char Use_module[] = "use_module=";
+static const char List_modules[] = "list_modules";
+
+enum params { INS_ACTION, RM_ACTION, USE_MODULE, LIST_MODULES };
+
+static const char const *param_names[] = { Ins_action, Rm_action, Use_module, List_modules };
+static int pn_sizes[] = { sizeof(Ins_action), sizeof(Rm_action), sizeof(Use_module), sizeof(List_modules) };
+
+#define NUM_PARAMS (sizeof(param_names)/sizeof(param_names[0]))
+
+const char *scconf_replace_str(scconf_block * block, const char *option, const char *value)
+{
+    scconf_list *list = NULL;
+    scconf_item *item;
+
+    scconf_list_add(&list, value);
+    item = scconf_item_add(NULL, block, NULL, SCCONF_ITEM_TYPE_VALUE, option, list);
+
+    /* now clear out the item list */
+    scconf_list_destroy(item->value.list);
+    item->value.list = list;  /* adopt */
+    return value;
+}
+
+int scconf_replace_str_list(scconf_block * block, const char *option, const char *value)
+{
+    scconf_list *list = NULL;
+    scconf_item *item;
+    char *lstitem = NULL;
+    char *next;
+    
+    while (value != NULL) {
+        if ((next=strchr(value, ',')) != NULL) {
+            lstitem = strndup(value, next-value);
+            next++;
+        }
+        else {
+            lstitem = strdup(value);
+        }
+        if (lstitem == NULL)
+            return 1;
+        scconf_list_add(&list, lstitem);
+        value = next;
+        free(lstitem);
+    }
+        
+    item = scconf_item_add(NULL, block, NULL, SCCONF_ITEM_TYPE_VALUE, option, list);
+
+    /* now clear out the item list */
+    scconf_list_destroy(item->value.list);
+    item->value.list = list;  /* adopt */
+    return 0;
+}
+
+int list_modules(void)
+{
+    const scconf_block *pam_pkcs11;
+    scconf_block **pkcs11_blocks;
+    scconf_context *ctx = NULL;
+    int i;
+    int result = 1;
+
+    /*
+     * loop through looking for smart card entries
+     */
+    ctx = scconf_new(PAM_PKCS11_CONF);
+    if (ctx == NULL) {
+     goto bail;
+    }
+    if (scconf_parse(ctx) <= 0 ) {
+     goto bail;
+    }
+    pam_pkcs11 = scconf_find_block(ctx, NULL, "pam_pkcs11");
+    if (!pam_pkcs11) {
+     goto bail;
+    }
+    pkcs11_blocks = scconf_find_blocks(ctx, pam_pkcs11, "pkcs11_module", NULL);
+    if (!pkcs11_blocks) {
+     goto bail;
+    }
+
+    /* list only those smart cards which are actually installed */
+    for (i=0; pkcs11_blocks[i]; i++) {
+     void *libhandle;
+     const char *path =
+     scconf_get_str(pkcs11_blocks[i], "module", NULL);
+     /* check to see if the module exists on the system */
+     if (!path || *path == 0) {
+     continue;
+     }
+     /* verify the module exists */
+        if ((libhandle=dlopen(path, RTLD_LAZY)) != NULL) {
+        dlclose(libhandle);
+        if (pkcs11_blocks[i] && pkcs11_blocks[i]->name
+            && pkcs11_blocks[i]->name->data) {
+        printf("%s\n", pkcs11_blocks[i]->name->data);
+        }
+     }
+    }
+    
+    result = 0;
+
+bail:
+    if (ctx) {
+     scconf_free(ctx);
+    }
+    return result;
+}
+
+int print_default_module(void)
+{
+    const scconf_block *pam_pkcs11;
+    scconf_context *ctx = NULL;
+    int result = 1;
+
+    /*
+    * read the base pam_pkcs11.conf
+    */
+    ctx = scconf_new(PAM_PKCS11_CONF);
+    if (ctx == NULL) {
+        goto bail;
+    }
+    if (scconf_parse(ctx) <= 0) {
+        goto bail;
+    }
+    pam_pkcs11 = scconf_find_block(ctx, NULL, "pam_pkcs11");
+    if (!pam_pkcs11) {
+        goto bail;
+    }
+    printf("%s\n", scconf_get_str(pam_pkcs11, "use_pkcs11_module", ""));
+    result = 0;
+
+    bail:
+    if (ctx) {
+        scconf_free(ctx);
+    }
+    ctx = NULL;
+
+    return result;
+}
+
+int set_default_module(const char *mod)
+{
+ scconf_block *pam_pkcs11, *pkcs11_eventmgr;
+ scconf_block **modules = NULL;
+ scconf_context *ctx = NULL;
+ scconf_context *ectx = NULL;
+ const char *lib = NULL;
+ int result = 1;
+
+ /*
+ * write out pam_pkcs11.conf
+ */
+ ctx = scconf_new(PAM_PKCS11_CONF);
+ if (ctx == NULL) {
+ goto bail;
+ }
+ if (scconf_parse(ctx) <= 0) {
+ goto bail;
+ }
+ pam_pkcs11 = (scconf_block *)scconf_find_block(ctx, NULL, "pam_pkcs11");
+ if (!pam_pkcs11) {
+ goto bail;
+ }
+ scconf_replace_str(pam_pkcs11, "use_pkcs11_module", mod);
+
+ modules = scconf_find_blocks(ctx, pam_pkcs11, "pkcs11_module", mod);
+ if (!modules || !modules[0]) {
+ goto bail;
+ }
+ lib = scconf_get_str(modules[0], "module", NULL);
+ if (!lib) {
+ goto bail;
+ }
+ result = scconf_write(ctx, NULL);
+ if (result != 0) {
+    goto bail;
+ }
+
+ ectx = scconf_new(EVENTMGR_CONF);
+ if (ectx == NULL) {
+ goto bail;
+ }
+ if (scconf_parse(ectx) <= 0) {
+ goto bail;
+ }
+ pkcs11_eventmgr = (scconf_block *)
+ scconf_find_block(ectx, NULL, "pkcs11_eventmgr");
+ if (!pkcs11_eventmgr) {
+ goto bail;
+ }
+ scconf_replace_str(pkcs11_eventmgr, "pkcs11_module", lib);
+ result = scconf_write(ectx, NULL);
+
+bail:
+ if (modules) {
+ free(modules);
+ }
+ if (ctx) {
+ scconf_free(ctx);
+ }
+ if (ectx) {
+ scconf_free(ectx);
+ }
+
+ return result;
+}
+
+int print_card_insert_action(void)
+{
+ const scconf_block *pkcs11_eventmgr;
+ scconf_block **event_blocks = NULL;
+ scconf_context *ctx = NULL;
+ const scconf_list *actionList = NULL;
+    int result = 1;
+
+ /*
+ * read the pkcs11_eventmgr.conf to get our action
+ */
+ ctx = scconf_new(EVENTMGR_CONF);
+ if (ctx == NULL) {
+ goto bail;
+ }
+ if (scconf_parse(ctx) <= 0) {
+ goto bail;
+ }
+ pkcs11_eventmgr = scconf_find_block(ctx, NULL, "pkcs11_eventmgr");
+ if (!pkcs11_eventmgr) {
+ goto bail;
+ }
+ event_blocks = scconf_find_blocks(ctx, pkcs11_eventmgr, "event",
+ "card_insert");
+ if (!event_blocks || !event_blocks[0]) {
+ goto bail;
+ }
+ actionList = scconf_find_list(event_blocks[0],"action");
+ if (actionList) {
+   char *lst = scconf_list_strdup(actionList, "\n");
+   if (lst != NULL) {
+       printf("%s\n", lst);
+       free(lst);
+   }
+ }
+ result = 0;
+
+bail:
+ if (event_blocks) {
+ free(event_blocks);
+ }
+ if (ctx) {
+ scconf_free(ctx);
+ }
+
+ return result;
+}
+
+int set_card_insert_action(const char *act)
+{
+ scconf_block *pkcs11_eventmgr;
+ scconf_block **insert_blocks = NULL;
+ scconf_context *ctx = NULL;
+    int result = 1;
+
+ /*
+ * write out pkcs11_eventmgr.conf
+ */
+ ctx = scconf_new(EVENTMGR_CONF);
+ if (ctx == NULL) {
+ goto bail;
+ }
+ if (scconf_parse(ctx) <= 0) {
+ goto bail;
+ }
+ pkcs11_eventmgr = (scconf_block *)
+ scconf_find_block(ctx, NULL, "pkcs11_eventmgr");
+ if (!pkcs11_eventmgr) {
+ goto bail;
+ }
+ insert_blocks = scconf_find_blocks(ctx, pkcs11_eventmgr,
+ "event", "card_insert");
+ if (!insert_blocks || !insert_blocks[0]) {
+ goto bail;
+ }
+
+ scconf_replace_str_list(insert_blocks[0], "action", act);
+
+ result = scconf_write(ctx, NULL);
+
+bail:
+ if (insert_blocks) {
+ free(insert_blocks);
+ }
+ if (ctx) {
+ scconf_free(ctx);
+ }
+ return result;
+}
+
+int print_card_remove_action(void)
+{
+ const scconf_block *pkcs11_eventmgr;
+ scconf_block **event_blocks = NULL;
+ scconf_context *ctx = NULL;
+ const scconf_list *actionList = NULL;
+    int result = 1;
+
+ /*
+ * read the pkcs11_eventmgr.conf to get our action
+ */
+ ctx = scconf_new(EVENTMGR_CONF);
+ if (ctx == NULL) {
+ goto bail;
+ }
+ if (scconf_parse(ctx) <= 0) {
+ goto bail;
+ }
+ pkcs11_eventmgr = scconf_find_block(ctx, NULL, "pkcs11_eventmgr");
+ if (!pkcs11_eventmgr) {
+ goto bail;
+ }
+ event_blocks = scconf_find_blocks(ctx, pkcs11_eventmgr, "event",
+ "card_remove");
+ if (!event_blocks || !event_blocks[0]) {
+ goto bail;
+ }
+ actionList = scconf_find_list(event_blocks[0],"action");
+ if (actionList) {
+   char *lst = scconf_list_strdup(actionList, "\n");
+   if (lst != NULL) {
+       printf("%s\n", lst);
+       free(lst);
+   }
+ }
+ result = 0;
+
+bail:
+ if (event_blocks) {
+ free(event_blocks);
+ }
+ if (ctx) {
+ scconf_free(ctx);
+ }
+
+ return result;
+}
+
+int set_card_remove_action(const char *act)
+{
+ scconf_block *pkcs11_eventmgr;
+ scconf_block **insert_blocks = NULL;
+ scconf_context *ctx = NULL;
+    int result = 1;
+
+ /*
+ * write out pkcs11_eventmgr.conf
+ */
+ ctx = scconf_new(EVENTMGR_CONF);
+ if (ctx == NULL) {
+ goto bail;
+ }
+ if (scconf_parse(ctx) <= 0) {
+ goto bail;
+ }
+ pkcs11_eventmgr = (scconf_block *)
+ scconf_find_block(ctx, NULL, "pkcs11_eventmgr");
+ if (!pkcs11_eventmgr) {
+ goto bail;
+ }
+ insert_blocks = scconf_find_blocks(ctx, pkcs11_eventmgr,
+ "event", "card_remove");
+ if (!insert_blocks || !insert_blocks[0]) {
+ goto bail;
+ }
+
+ scconf_replace_str_list(insert_blocks[0], "action", act);
+
+ result = scconf_write(ctx, NULL);
+
+bail:
+ if (insert_blocks) {
+ free(insert_blocks);
+ }
+ if (ctx) {
+ scconf_free(ctx);
+ }
+ return result;
+}
+
+int main(int argc, const char **argv)
+{
+    int i;
+    int pname;
+    const char *params[NUM_PARAMS];
+    
+    memset(params, '\0', sizeof(params));
+    
+    for (i = 1; i < argc; i++) {
+     for (pname = 0; pname < NUM_PARAMS; pname++) {
+        if (param_names[pname][pn_sizes[pname]-2] == '=') {
+            if (strncmp(argv[i], param_names[pname], pn_sizes[pname]-1) == 0) {
+                params[pname] = argv[i] + pn_sizes[pname] - 1;
+            }
+            else if (strncmp(argv[i], param_names[pname], pn_sizes[pname]-2) == 0
+                && argv[i][pn_sizes[pname]-2] == '\0') {
+                params[pname] = (void *)1;
+            }
+        }
+        else {
+            if (strcmp(argv[i], param_names[pname]) == 0) {
+                params[pname] = (void *)1;
+            }
+         }
+        }
+    }
+    
+    for (pname = 0; pname < NUM_PARAMS; pname++) {
+    if (params[pname] != NULL)
+        break;
+    }
+    
+    if (pname == NUM_PARAMS) {
+ DBG("No correct parameter specified");
+ printf("usage: pkcs11_setup [list_modules] [use_module[=<module_name>]]\n"
+       "                    [ins_action[=<executable,executable,...>]]\n"
+       "                    [rm_action[=<executable,executable,...>]]\n");
+    }
+    
+    if (params[LIST_MODULES] != NULL) {
+        DBG("List modules:");
+        return list_modules();
+    }
+    else {
+        if (params[USE_MODULE] == (void *)1) {
+            DBG("Print default module:");
+            if ((i=print_default_module()) != 0) {
+                DBG1("Print default module failed with: %d", i);
+                return i;
+            }
+            return 0;
+        }
+        else if (params[USE_MODULE] != NULL) {
+            DBG1("Set default module: %s", params[USE_MODULE]);
+            if ((i=set_default_module(params[USE_MODULE])) != 0) {
+                DBG1("Set default module failed with: %d", i);
+                return i;
+            }
+        }
+        if (params[INS_ACTION] == (void *)1) {
+            DBG("Print card insert action:");
+            if ((i=print_card_insert_action()) != 0) {
+                DBG1("Print card insert action failed with: %d", i);
+                return i;
+            }
+            return 0;
+        }      
+        else if (params[INS_ACTION] != NULL) {
+            DBG1("Set card insert action: %s", params[INS_ACTION]);
+            if ((i=set_card_insert_action(params[INS_ACTION])) != 0) {
+                DBG1("Set card insert action failed with: %d", i);
+                return i;
+            }
+        }
+        if (params[RM_ACTION] == (void *)1) {
+            DBG("Print card remove action:");
+            if ((i=print_card_remove_action()) != 0) {
+                DBG1("Set card remove action failed with: %d", i);
+                return i;
+            }
+            return 0;
+        }        
+        else if (params[RM_ACTION] != NULL) {
+            DBG1("Set card remove action: %s", params[RM_ACTION]);
+            if ((i=set_card_remove_action(params[RM_ACTION])) != 0) {
+                DBG1("Set card remove action failed with: %d", i);
+                return i;
+            }
+        }        
+    }
+    DBG("Process completed");
+    return 0;
+}
Index: src/tools/Makefile.am
===================================================================
--- src/tools/Makefile.am (revision 264)
+++ src/tools/Makefile.am (working copy)
@@ -8,11 +8,11 @@
 AM_LDFLAGS = $(PCSC_LIBS)
 
 if HAVE_PCSC
-bin_PROGRAMS = card_eventmgr pkcs11_eventmgr pklogin_finder pkcs11_inspect pkcs11_listcerts
+bin_PROGRAMS = card_eventmgr pkcs11_eventmgr pklogin_finder pkcs11_inspect pkcs11_listcerts pkcs11_setup
 card_eventmgr_SOURCES = card_eventmgr.c
 card_eventmgr_LDADD = $(LIBSCCONF) $(LIBCOMMON)
 else
-bin_PROGRAMS = pkcs11_eventmgr pklogin_finder pkcs11_inspect pkcs11_listcerts
+bin_PROGRAMS = pkcs11_eventmgr pklogin_finder pkcs11_inspect pkcs11_listcerts pkcs11_setup
 endif
 
 pklogin_finder_SOURCES = pklogin_finder.c
@@ -26,3 +26,6 @@
 
 pkcs11_inspect_SOURCES = pkcs11_inspect.c
 pkcs11_inspect_LDADD = $(FINDER_OBJS) $(LIBMAPPERS)
+
+pkcs11_setup_SOURCES = pkcs11_setup.c
+pkcs11_setup_LDADD = $(LIBSCCONF) $(LIBCOMMON)
Index: src/tools/pkcs11_eventmgr.c
===================================================================
--- src/tools/pkcs11_eventmgr.c (revision 264)
+++ src/tools/pkcs11_eventmgr.c (working copy)
@@ -31,7 +31,7 @@
 #include "../common/error.h"
 
 #ifdef HAVE_NSS
-#include <nss/secmod.h>
+#include <secmod.h>
 #endif
 
 #define DEF_POLLING 1    /* 1 second timeout */
@@ -404,7 +404,10 @@
  moduleSpec, pkcs11_module);
  module = SECMOD_LoadUserModule(moduleSpec, NULL, 0);
  free(moduleSpec);
- if (!module) {
+ if (!module || module->loaded == 0) {
+            if (module) {
+               SECMOD_DestroyModule(module);
+            }
     DBG("Failed to load SmartCard software");
     return 1;
  }
Index: src/common/cert_info.c
===================================================================
--- src/common/cert_info.c (revision 264)
+++ src/common/cert_info.c (working copy)
@@ -747,6 +747,34 @@
  return entries;
 }
 
+/*
+* Return certificate in PEM format
+*/
+static char **cert_info_serial_number(X509 *x509) {
+ static char *entries[2] = { NULL,NULL };
+ ASN1_INTEGER *serial = X509_get_serialNumber(x509);
+ int len;
+ char *buffer = NULL, *tmp_ptr;
+
+ len = i2c_ASN1_INTEGER(serial, NULL);
+
+ if (len < 0) {
+ return NULL;
+ }
+ buffer = malloc(len);
+ if (buffer == NULL) {
+ return NULL;
+ }
+
+ /* i2c_ASN1_INTEGER "kindly" increments our pointer by len,
+ * give it a temp ptr it can tweak to it's hearts content */
+ tmp_ptr = buffer;
+ len = i2c_ASN1_INTEGER(serial, &tmp_ptr);
+ entries[0] = bin2hex(buffer,len);
+ free(buffer);
+ return entries;
+}
+
 /**
 * request info on certificate
 * @param x509 Certificate to parse
@@ -768,7 +796,7 @@
  return cert_info_issuer(x509);
     case CERT_SERIAL : /* Certificate serial number */
  /* fix me */
- return NULL;
+ return cert_info_serial_number(x509);
     case CERT_KPN     : /* Kerberos principal name */
  return cert_info_kpn(x509);
     case CERT_EMAIL   : /* Certificate e-mail */
Index: src/common/pkcs11_lib.c
===================================================================
--- src/common/pkcs11_lib.c (revision 264)
+++ src/common/pkcs11_lib.c (working copy)
@@ -81,9 +81,14 @@
 #include "ocsp.h"
 #include <unistd.h>
 #include <errno.h>
+#include "syslog.h"
 
 #include "cert_vfy.h"
 
+#ifndef PAM_PKCS11_POLL_TIME
+#define PAM_PKCS11_POLL_TIME 500 /* ms */
+#endif
+
 struct pkcs11_handle_str {
   SECMODModule *module;
   PRBool is_user_module;
@@ -290,6 +295,96 @@
   return -1;
 }
 
+/*
+ * find a slot by it's slot number or label. If slot number is '0' any
+ * slot is ok.
+ */
+int find_slot_by_number_and_label(pkcs11_handle_t *h,
+  int wanted_slot_id,
+  const char *wanted_slot_label,
+                                  unsigned int *slot_num)
+{
+  int rv;
+  const char *slot_label = NULL;
+  PK11SlotInfo *slot = NULL;
+
+  /* we want a specific slot id, or we don't kare about the label */
+  if ((wanted_slot_label == NULL) || (wanted_slot_id != 0)) {
+    rv = find_slot_by_number(h, wanted_slot_id, slot_num);
+
+    /* if we don't care about the label, or we failed, we're done */
+    if ((wanted_slot_label == NULL) || (rv != 0)) {
+      return rv;
+    }
+
+    /* verify it's the label we want */
+    slot_label = PK11_GetTokenName(h->slot);
+
+    if ((slot_label != NULL) &&
+        (strcmp (wanted_slot_label, slot_label) == 0)) {
+      return 0;
+    }
+    return -1;
+  }
+
+  /* we want a specific slot by label only */
+  slot = PK11_FindSlotByName(wanted_slot_label);
+  if (!slot) {
+    return -1;
+  }
+
+  /* make sure it's in the right module */
+  if (h->module) {
+    if (h->module != PK11_GetModule(slot)) {
+ PK11_FreeSlot(slot);
+ return -1;
+    }
+  } else {
+    /* no module was specified, use the one slot came in */
+    h->module = SECMOD_ReferenceModule(PK11_GetModule(slot));
+  }
+  h->slot = slot; /* Adopt the reference */
+  *slot_num = PK11_GetSlotID(h->slot);
+  return 0;
+}
+
+int wait_for_token(pkcs11_handle_t *h,
+                   int wanted_slot_id,
+                   const char *wanted_slot_label,
+                   unsigned int *slot_num)
+{
+  int rv;
+
+  rv = -1;
+  do {
+    /* see if the card we're looking for is inserted */
+    rv = find_slot_by_number_and_label (h, wanted_slot_id,  wanted_slot_label,
+                                        slot_num);
+    if (rv !=  0) {
+      PK11SlotInfo *slot;
+      PRIntervalTime slot_poll_interval; /* only for legacy hardware */
+
+      /* if the card is not inserted, then block until something happens */
+      slot_poll_interval = PR_MillisecondsToInterval(PAM_PKCS11_POLL_TIME);
+      slot = SECMOD_WaitForAnyTokenEvent(h->module, 0 /* flags */,
+                                         slot_poll_interval);
+
+      /* unexpected error */
+      if (slot == NULL) {
+        break;
+      }
+
+      /* something happened, continue loop and check if the card
+       * we're looking for is inserted
+       */
+      PK11_FreeSlot(slot);
+      continue;
+    }
+  } while (rv != 0);
+
+  return rv;
+}
+
 void release_pkcs11_module(pkcs11_handle_t *h)
 {
   SECStatus rv;
@@ -383,6 +478,8 @@
   return PK11_GetTokenName(h->slot);
 }
 
+
+
 cert_object_t **get_certificate_list(pkcs11_handle_t *h, int *count)
 {
   CERTCertList * certList;
@@ -692,10 +789,50 @@
   return 0;
 }
 
+static int
+refresh_slots(pkcs11_handle_t *h)
+{
+  CK_ULONG i;
+  int j;
+
+  for (i = 0; i < h->slot_count; i++) {
+    CK_SLOT_INFO sinfo;
+    CK_TOKEN_INFO tinfo;
+    CK_RV rv;
+
+    DBG1("slot %d:", i + 1);
+    rv = h->fl->C_GetSlotInfo(h->slots[i].id, &sinfo);
+    if (rv != CKR_OK) {
+      set_error("C_GetSlotInfo() failed: %x", rv);
+      return -1;
+    }
+    DBG1("- description: %.64s", sinfo.slotDescription);
+    DBG1("- manufacturer: %.32s", sinfo.manufacturerID);
+    DBG1("- flags: %04lx", sinfo.flags);
+    if (sinfo.flags & CKF_TOKEN_PRESENT) {
+      DBG("- token:");
+      rv = h->fl->C_GetTokenInfo(h->slots[i].id, &tinfo);
+      if (rv != CKR_OK) {
+        set_error("C_GetTokenInfo() failed: %x", rv);
+        return -1;
+      }
+      DBG1("  - label: %.32s", tinfo.label);
+      DBG1("  - manufacturer: %.32s", tinfo.manufacturerID);
+      DBG1("  - model: %.16s", tinfo.model);
+      DBG1("  - serial: %.16s", tinfo.serialNumber);
+      DBG1("  - flags: %04lx", tinfo.flags);
+      h->slots[i].token_present = TRUE;
+      memcpy(h->slots[i].label, tinfo.label, 32);
+      for (j = 31; h->slots[i].label[j] == ' '; j--) h->slots[i].label[j] = 0;
+    }
+  }
+  return 0;
+}
+
 int init_pkcs11_module(pkcs11_handle_t *h,int flag)
 {
   int rv;
-  CK_ULONG i, j;
+  CK_ULONG i;
   CK_SLOT_ID_PTR slots;
   CK_INFO info;
   CK_C_INITIALIZE_ARGS initArgs;
@@ -763,40 +900,10 @@
   DBG1("number of slots (b): %d", h->slot_count);
   /* show some information about the slots/tokens and setup slot info */
   for (i = 0; i < h->slot_count; i++) {
-    CK_SLOT_INFO sinfo;
-    CK_TOKEN_INFO tinfo;
-
-    DBG1("slot %d:", i + 1);
-    rv = h->fl->C_GetSlotInfo(slots[i], &sinfo);
-    if (rv != CKR_OK) {
-      free(slots);
-      set_error("C_GetSlotInfo() failed: %x", rv);
-      return -1;
-    }
     h->slots[i].id = slots[i];
-    DBG1("- description: %.64s", sinfo.slotDescription);
-    DBG1("- manufacturer: %.32s", sinfo.manufacturerID);
-    DBG1("- flags: %04lx", sinfo.flags);
-    if (sinfo.flags & CKF_TOKEN_PRESENT) {
-      DBG("- token:");
-      rv = h->fl->C_GetTokenInfo(slots[i], &tinfo);
-      if (rv != CKR_OK) {
-        free(slots);
-        set_error("C_GetTokenInfo() failed: %x", rv);
-        return -1;
-      }
-      DBG1("  - label: %.32s", tinfo.label);
-      DBG1("  - manufacturer: %.32s", tinfo.manufacturerID);
-      DBG1("  - model: %.16s", tinfo.model);
-      DBG1("  - serial: %.16s", tinfo.serialNumber);
-      DBG1("  - flags: %04lx", tinfo.flags);
-      h->slots[i].token_present = TRUE;
-      memcpy(h->slots[i].label, tinfo.label, 32);
-      for (j = 31; h->slots[i].label[j] == ' '; j--) h->slots[i].label[j] = 0;
-    }
   }
   free(slots);
-  return 0;
+  return refresh_slots(h);
 }
 
 void release_pkcs11_module(pkcs11_handle_t *h)
@@ -832,7 +939,71 @@
    return 0;
 }
 
+int find_slot_by_number_and_label(pkcs11_handle_t *h,
+  int wanted_slot_id,
+  const char *wanted_slot_label,
+                                  unsigned int *slot_num)
+{
+  unsigned int slot_index;
+  int rv;
+  const char *slot_label = NULL;
 
+  /* we want a specific slot id, or we don't kare about the label */
+  if ((wanted_slot_label == NULL) || (wanted_slot_id != 0)) {
+    rv = find_slot_by_number(h, wanted_slot_id, slot_num);
+
+    /* if we don't care about the label, or we failed, we're done */
+    if ((wanted_slot_label == NULL) || (rv != 0)) {
+      return rv;
+    }
+
+    /* verify it's the label we want */
+    slot_label = h->slots[*slot_num].label;
+
+    if ((slot_label != NULL) &&
+        (strcmp (wanted_slot_label, slot_label) == 0)) {
+      return 0;
+    }
+    return -1;
+  }
+
+  /* look up the slot by it's label from the list */
+  for (slot_index = 0; slot_index < h->slot_count; slot_index++) {
+    if (h->slots[slot_index].token_present) {
+      slot_label = h->slots[slot_index].label;
+      if ((slot_label != NULL) &&
+          (strcmp (wanted_slot_label, slot_label) == 0)) {
+        *slot_num = slot_index;
+        return 0;
+      }
+    }
+  }
+  return -1;
+}
+
+int wait_for_token(pkcs11_handle_t *h,
+                   int wanted_slot_id,
+                   const char *wanted_slot_label,
+                   unsigned int *slot_num)
+{
+  int rv;
+
+  rv = -1;
+  do {
+    /* see if the card we're looking for is inserted */
+    rv = find_slot_by_number_and_label (h, wanted_slot_id,  wanted_slot_label,
+                                        slot_num);
+    if (rv !=  0) {
+      /* could call C_WaitForSlotEvent, for now just poll */
+      sleep(10);
+      refresh_slots(h);
+      continue;
+    }
+  } while (rv != 0);
+
+  return rv;
+}
+
 int open_pkcs11_session(pkcs11_handle_t *h, unsigned int slot)
 {
   int rv;
@@ -852,6 +1023,7 @@
   return 0;
 }
 
+
 int pkcs11_login(pkcs11_handle_t *h, char *password)
 {
   int rv;
Index: src/common/strings.c
===================================================================
--- src/common/strings.c (revision 264)
+++ src/common/strings.c (working copy)
@@ -83,6 +83,10 @@
  char *pt;
  char *res= (char *) malloc(1+3*len);
  if (!res) return NULL;
+ if (len == 0) {
+    *res = 0;
+    return res;
+ }
  for(i=0,pt=res;i<len;i++,pt+=3){
     sprintf(pt,"%02X:",binstr[i]);
  }
Index: src/common/pkcs11_lib.h
===================================================================
--- src/common/pkcs11_lib.h (revision 264)
+++ src/common/pkcs11_lib.h (working copy)
@@ -33,7 +33,14 @@
 PKCS11_EXTERN int init_pkcs11_module(pkcs11_handle_t *h,int flag);
 PKCS11_EXTERN int find_slot_by_number(pkcs11_handle_t *h,int slot_num,
                                       unsigned int *slot);
+PKCS11_EXTERN int find_slot_by_number_and_label(pkcs11_handle_t *h,
+                                      int slot_num, const char *slot_label,
+                                      unsigned int *slot);
 PKCS11_EXTERN const char *get_slot_label(pkcs11_handle_t *h);
+PKCS11_EXTERN int wait_for_token(pkcs11_handle_t *h,
+                                 int wanted_slot_num,
+                                 const char *wanted_slot_label,
+                                 unsigned int *slot);
 PKCS11_EXTERN const X509 *get_X509_certificate(cert_object_t *cert);
 PKCS11_EXTERN void release_pkcs11_module(pkcs11_handle_t *h);
 PKCS11_EXTERN int open_pkcs11_session(pkcs11_handle_t *h, unsigned int slot);

_______________________________________________
opensc-devel mailing list
[hidden email]
http://www.opensc-project.org/mailman/listinfo/opensc-devel
Reply | Threaded
Open this post in threaded view
|

pam_pkcs11 LDAP patch Was: Re: pam_pkcs11 NSS patch.

S. Wefel
In reply to this post by Ludovic Rousseau
Ludovic Rousseau schrieb:

> On 04/04/07, Ludovic Rousseau <[hidden email]> wrote:
>> I, more or less, use pam-pkcs11. I would really be interested in
>> integrating your RedHat patches.
>
> And I work on the pam_pkcs11 source code right now. So it is the very
> good time to submit your patches :-)
>
> Be sure to use a subversion version before generating your diffs.
>
> Bye

Hello,

would you please so kind to include the ldap-patches for
pam-pkcs11 at location
http://nirvana.informatik.uni-halle.de/~wefel/smartcard/libpam-pkcs11/

which offers:
- support for more than one LDAP server as fallback system
- support of secure connection (SSL+TLS) because someone
may use simple authentication with username and password
- multiple certificates per attribute
- LDAP-URI support
- selection of base, one-level or subtree search
- timeout support
and a somewhat enhanced documentation.

thanks,
S. Wefel
_______________________________________________
opensc-devel mailing list
[hidden email]
http://www.opensc-project.org/mailman/listinfo/opensc-devel
Reply | Threaded
Open this post in threaded view
|

Re: pam_pkcs11 NSS patch.

Ludovic Rousseau
In reply to this post by relyea
On 13/04/07, Robert Relyea <[hidden email]> wrote:
> Here's patch installment 2 of 3.

I can't find the needed file security/pam_ext.h in your patch. I guess
you forgot to add --new-file when you used diff :-)

Can you send the missing file?

Bye

--
  Dr. Ludovic Rousseau
_______________________________________________
opensc-devel mailing list
[hidden email]
http://www.opensc-project.org/mailman/listinfo/opensc-devel
Reply | Threaded
Open this post in threaded view
|

Re: pam_pkcs11 LDAP patch Was: Re: pam_pkcs11 NSS patch.

Ludovic Rousseau
In reply to this post by S. Wefel
On 20/04/07, S. Wefel <[hidden email]> wrote:

> Ludovic Rousseau schrieb:
> > On 04/04/07, Ludovic Rousseau <[hidden email]> wrote:
> >> I, more or less, use pam-pkcs11. I would really be interested in
> >> integrating your RedHat patches.
> >
> > And I work on the pam_pkcs11 source code right now. So it is the very
> > good time to submit your patches :-)
> >
> > Be sure to use a subversion version before generating your diffs.
> >
> > Bye
>
> Hello,
>
> would you please so kind to include the ldap-patches for
> pam-pkcs11 at location
> http://nirvana.informatik.uni-halle.de/~wefel/smartcard/libpam-pkcs11/
>
> which offers:
> - support for more than one LDAP server as fallback system
> - support of secure connection (SSL+TLS) because someone
> may use simple authentication with username and password
> - multiple certificates per attribute
> - LDAP-URI support
> - selection of base, one-level or subtree search
> - timeout support
> and a somewhat enhanced documentation.

Applied in revision 268.

Thanks

--
 Dr. Ludovic Rousseau
_______________________________________________
opensc-devel mailing list
[hidden email]
http://www.opensc-project.org/mailman/listinfo/opensc-devel
Reply | Threaded
Open this post in threaded view
|

Re: pam_pkcs11 NSS patch.

relyea
In reply to this post by Ludovic Rousseau
Ludovic Rousseau wrote:
> On 13/04/07, Robert Relyea <[hidden email]> wrote:
>> Here's patch installment 2 of 3.
>
> I can't find the needed file security/pam_ext.h in your patch. I guess
> you forgot to add --new-file when you used diff :-)
>
> Can you send the missing file?
It's part of pam 0.99.6.2 (supplies pam_prompt). If you don't have that
version of pam, you won't have the pam_prompt function either. I can
supply a patch that will also work with older versions of pam, and use
configure to determine which you have.

bob
>
> Bye
>


_______________________________________________
opensc-devel mailing list
[hidden email]
http://www.opensc-project.org/mailman/listinfo/opensc-devel

smime.p7s (4K) Download Attachment
Reply | Threaded
Open this post in threaded view
|

Re: pam_pkcs11 NSS patch.

Ludovic Rousseau
On 09/05/07, Robert Relyea <[hidden email]> wrote:
> Ludovic Rousseau wrote:
> > On 13/04/07, Robert Relyea <[hidden email]> wrote:
> > I can't find the needed file security/pam_ext.h in your patch. I guess
> > you forgot to add --new-file when you used diff :-)
> >
> > Can you send the missing file?
> It's part of pam 0.99.6.2 (supplies pam_prompt). If you don't have that
> version of pam, you won't have the pam_prompt function either.

I see. Debian only has version 0.79. A bug #360460 has been opened to
have a new version in Debian.

> I can
> supply a patch that will also work with older versions of pam, and use
> configure to determine which you have.

That would be great. Otherwise pam_pkcs11 could not be complied on
Debian (and derivatives) without hacking.

Thanks,

--
  Dr. Ludovic Rousseau
_______________________________________________
opensc-devel mailing list
[hidden email]
http://www.opensc-project.org/mailman/listinfo/opensc-devel
Reply | Threaded
Open this post in threaded view
|

Re: pam_pkcs11 NSS patch.

Ludovic Rousseau
On 16/05/07, Robert Relyea <[hidden email]> wrote:

> Ludovic Rousseau wrote:
> > On 09/05/07, Ludovic Rousseau <[hidden email]> wrote:
> >> On 09/05/07, Robert Relyea <[hidden email]> wrote:
> >> > Ludovic Rousseau wrote:
> >> > > On 13/04/07, Robert Relyea <[hidden email]> wrote:
> >> > > I can't find the needed file security/pam_ext.h in your patch. I
> >> guess
> >> > > you forgot to add --new-file when you used diff :-)
> >> > >
> >> > > Can you send the missing file?
> >> > It's part of pam 0.99.6.2 (supplies pam_prompt). If you don't have
> >> that
> >> > version of pam, you won't have the pam_prompt function either.
> >>
> >> I see. Debian only has version 0.79. A bug #360460 has been opened to
> >> have a new version in Debian.
> >>
> >> > I can
> >> > supply a patch that will also work with older versions of pam, and use
> >> > configure to determine which you have.
> >>
> >> That would be great. Otherwise pam_pkcs11 could not be complied on
> >> Debian (and derivatives) without hacking.
> >
> > Any progress on this patch?
> Sorry for the delay. Thanks for your patience. I haven't tested this on
> a older pam implementation, but I did verify that the config stuff works
> correctly by renaming pam_ext.h on my system.

Patch applied.

Please, go one with the third and last patch.

Regards,

--
 Dr. Ludovic Rousseau
_______________________________________________
opensc-devel mailing list
[hidden email]
http://www.opensc-project.org/mailman/listinfo/opensc-devel
Reply | Threaded
Open this post in threaded view
|

Re: pam_pkcs11 NSS patch.

relyea
Ludovic Rousseau wrote:

>>
>> >> > I can
>> >> > supply a patch that will also work with older versions of pam,
>> and use
>> >> > configure to determine which you have.
>> >>
>> >> That would be great. Otherwise pam_pkcs11 could not be complied on
>> >> Debian (and derivatives) without hacking.
>> >
>> > Any progress on this patch?
>> Sorry for the delay. Thanks for your patience. I haven't tested this on
>> a older pam implementation, but I did verify that the config stuff works
>> correctly by renaming pam_ext.h on my system.
>
> Patch applied.
>
> Please, go one with the third and last patch.
>
> Regards,
Hi Ludovic,

It looks like an added file didn't get put in the repository:
src/tools/pkcs11_setup.c

I'll get the 3 patch ready shortly.

bob


_______________________________________________
opensc-devel mailing list
[hidden email]
http://www.opensc-project.org/mailman/listinfo/opensc-devel

smime.p7s (4K) Download Attachment
Reply | Threaded
Open this post in threaded view
|

Re: pam_pkcs11 NSS patch.

Ludovic Rousseau
On 21/05/07, Robert Relyea <[hidden email]> wrote:
> It looks like an added file didn't get put in the repository:
> src/tools/pkcs11_setup.c

Argh. Exact. Commited in revision 273.

> I'll get the 3 patch ready shortly.

OK. Thanks

--
 Dr. Ludovic Rousseau
_______________________________________________
opensc-devel mailing list
[hidden email]
http://www.opensc-project.org/mailman/listinfo/opensc-devel