Hi Sim,

[EMAIL PROTECTED] wrote:


Hi all,
I'm trying to get the MusclePAM module to work, but it seems that there are some irregularities in the program, i can't find the testpam.c file specified by the Makefile, moreover when it builds the pam_musclecard.so i don't think it builds it correctly 'cause in the Makefile the library directories are not pointing correctly, so has anyone got it working?are there missing files?or is it just mine? what's a better PAM alternative?, Thanks in advance.

Yes, the linker options point to default paths, as configured in /etc/ld.so.conf. If you installed MUSCLE's pcsc elsewhere, then use your editor. Muscle is always in a state of flow ;) Be part of it, Configure scripts are always welcome. Actually I do not know where testpam.c is left, but you may test it right away, when logged in(!) by placing the shared object in /lib/security and changing your /etc/pam.d/login to

#auth requisite /lib/security/pam_unix.so nullok
auth requisite /lib/security/pam_musclecard.so

Attached you find my current version of MusclePAM, as patch against the one shipped with muscleframework 1.1.3; the patch provides additional support for PEM certs, Root CA chains/directories. Uses OpenSSL 0.9.7-beta3.
Works great for me.

HTH
--
Martin Buechler
diff -Nauwr MusclePAM.orig/Makefile MusclePAM/Makefile
--- MusclePAM.orig/Makefile     Thu Sep 26 20:48:56 2002
+++ MusclePAM/Makefile  Tue Dec 10 10:30:53 2002
@@ -1,9 +1,13 @@
-CC = gcc -fPIC
+CC = gcc -fPIC -Wall -O2
 DEFS= -D_REENTRANT
 INC = -I/usr/local/include -I.
-LIBS = -lpcsclite -lpthread -lpam -lcrypto
+LIBS = -L/usr/local/lib -lpcsclite -lpthread -lpam -lcrypto
 OBJ  = preferences.o certutils.o pam_smartcard.o cardtools.o
 
+SSL_PROGRAM=openssl
+CERT_SUFFIX=cert
+
+
 all: pam_musclecard.so
 clean:
        rm *.o pam_musclecard.so
@@ -18,3 +22,54 @@
 
 %.o: %.c
        $(CC) -c $< $(INC) $(DEFS)
+
+
+##
+##  Makefile to keep the hash symlinks in SSLCACertificatePath up to date
+##  Copyright (c) 1998-2000 Ralf S. Engelschall, All Rights Reserved. 
+##
+
+hashdir: 
+       -@ssl_program="$(SSL_PROGRAM)"; \
+       if [ ".$$ssl_program" = . ]; then \
+           for dir in . `echo $$PATH | sed -e 's/:/ /g'`; do \
+               for program in openssl ssleay; do \
+                   if [ -f "$$dir/$$program" ]; then \
+                       if [ -x "$$dir/$$program" ]; then \
+                           ssl_program="$$dir/$$program"; \
+                                               break; \
+                       fi; \
+                   fi; \
+               done; \
+               if [ ".$$ssl_program" != . ]; then \
+                               break; \
+               fi; \
+           done; \
+       fi; \
+       if [ ".$$ssl_program" = . ]; then \
+           echo "Error: neither 'openssl' nor 'ssleay' program found" 1>&2; \
+           exit 1; \
+       fi; \
+       for file in *.$(CERT_SUFFIX); do \
+           if [ ".`grep SKIPME $$file`" != . ]; then \
+               echo dummy |\
+               awk '{ printf("%-15s ... Skipped\n", file); }' \
+               "file=$$file"; \
+           else \
+               n=0; \
+               while [ 1 ]; do \
+                   hash="`$$ssl_program x509 -noout -hash <$$file`"; \
+                   if [ -r "$$hash.$$n" ]; then \
+                       n=`expr $$n + 1`; \
+                   else \
+                       echo dummy |\
+                       awk '{ printf("%-15s ... %s\n", file, hash); }' \
+                       "file=$$file" "hash=$$hash.$$n"; \
+                       ln -s $$file $$hash.$$n; \
+                       break; \
+                   fi; \
+               done; \
+           fi; \
+       done
+
+
diff -Nauwr MusclePAM.orig/README MusclePAM/README
--- MusclePAM.orig/README       Thu Sep 26 20:48:56 2002
+++ MusclePAM/README    Mon Dec  9 14:43:59 2002
@@ -20,7 +20,7 @@
 - Request and Verify PIN #1
 - Compute Crypt of the nonce with RSA 1024 bit key #3
 - Get the user's certificate from the smartcard
-- Verify the users certificate using the root CA certificate in /etc/root.cert
+- Verify the users certificate using the root CA certificate and/or CA chain
 - Extract the users public key from the certificate
 - Decrypt the nonce using the user's public key
 - Compare the original nonce with the last
diff -Nauwr MusclePAM.orig/cardtools.c MusclePAM/cardtools.c
--- MusclePAM.orig/cardtools.c  Thu Sep 26 20:48:56 2002
+++ MusclePAM/cardtools.c       Mon Dec  9 12:00:37 2002
@@ -31,7 +31,6 @@
 int pcsc_init(MSCLPTokenConnection pConnection, int num)
 {
   MSCLong32 rv;
-  int i;
   MSCTokenInfo tokenList[20];
   MSCULong32 arrayLength;
 
diff -Nauwr MusclePAM.orig/certutils.c MusclePAM/certutils.c
--- MusclePAM.orig/certutils.c  Thu Sep 26 20:48:56 2002
+++ MusclePAM/certutils.c       Mon Dec  9 12:10:02 2002
@@ -20,6 +20,7 @@
 #include <syslog.h>
 #include "certutils.h"
 #include "preferences.h"
+#include <openssl/pem.h>
 
 int getRandom(char *buf, int len)
 {
@@ -77,7 +78,7 @@
     return -1;
  
   // Get the cert
-  PEM_read_X509(fp,&mycert,NULL);
+  PEM_read_X509(fp,&mycert,NULL,NULL);
   if (mycert == NULL)
     return -1;
  
@@ -133,6 +134,93 @@
 
   return 0;
 }
+
+int checkCertStore(X509_STORE *ctx, 
+                   X509* cert, 
+                   STACK_OF(X509) *uchain, 
+                   STACK_OF(X509) *tchain) {
+
+  int i=0,ret=0;
+  X509_STORE_CTX *csc;
+
+  csc = X509_STORE_CTX_new();
+  if (csc == NULL)
+    {
+      goto end;
+    }
+  X509_STORE_set_flags(ctx, 0
+                       /*
+                       X509_V_FLAG_IGNORE_CRITICAL | 
+                       X509_V_FLAG_CB_ISSUER_CHECK |
+                       X509_V_FLAG_CRL_CHECK       | 
+                       X509_V_FLAG_CRL_CHECK_ALL*/);
+  if(!X509_STORE_CTX_init(csc,ctx,cert,uchain))
+    {    
+      goto end;
+    }
+  if(tchain) X509_STORE_CTX_trusted_stack(csc, tchain);
+
+  i=X509_verify_cert(csc);
+  X509_STORE_CTX_free(csc);
+
+  ret=0;
+ end:
+  if (i)
+    {
+      ret=1;
+      syslog(LOG_ERR, "OK, verify result code: %d\n", ret);
+    }
+  else
+    syslog(LOG_ERR,"Verification failed, %s\n", ret);
+
+  return(ret);
+}
+
+STACK_OF(X509) *load_chain(char *certfile) {
+  STACK_OF(X509_INFO) *sk=NULL;
+  STACK_OF(X509) *stack=NULL, *ret=NULL;
+  BIO *in=NULL;
+  X509_INFO *xi;
+  
+  if(!(stack = sk_X509_new_null())) {
+    syslog(LOG_ERR,"memory allocation failure\n");
+    goto end;
+  }
+  
+  if(!(in=BIO_new_file(certfile, "r"))) {
+    syslog(LOG_ERR,"error opening the file, %s\n",certfile);
+    goto end;
+  }
+  
+  /* This loads from a file, a stack of x509/crl/pkey sets */
+  if(!(sk=PEM_X509_INFO_read_bio(in,NULL,NULL,NULL))) {
+    syslog(LOG_ERR,"error reading the file, %s\n",certfile);
+    goto end;
+  }
+  
+  /* scan over it and pull out the certs */
+  while (sk_X509_INFO_num(sk))
+    {
+      xi=sk_X509_INFO_shift(sk);
+      if (xi->x509 != NULL)
+        {
+          sk_X509_push(stack,xi->x509);
+          xi->x509=NULL;
+        }
+      X509_INFO_free(xi);
+    }
+  if(!sk_X509_num(stack)) {
+    syslog(LOG_ERR,"no certificates in file, %s\n",certfile);
+    sk_X509_free(stack);
+    goto end;
+  }
+  ret=stack;
+ end:
+  BIO_free(in);
+  sk_X509_INFO_free(sk);
+  return(ret);
+}
+
 
 /* Extract certificate from smartcard */
 int getPublicKey(X509 *cert, EVP_PKEY **pub_key) {
diff -Nauwr MusclePAM.orig/certutils.h MusclePAM/certutils.h
--- MusclePAM.orig/certutils.h  Thu Sep 26 20:48:56 2002
+++ MusclePAM/certutils.h       Mon Dec  9 12:01:24 2002
@@ -1,5 +1,5 @@
-#ifndef RSA_H
-#define RSA_H
+#ifndef CERTUTILS_H
+#define CERTUTILS_H
 
 #include <sys/types.h>
 #include <sys/stat.h>
@@ -37,6 +37,7 @@
  * @returns 0 on success, -1 otherwise
  */
 int getFileCert(const char *file, X509 **cert);
+int getFileCertPEM(const char *file, X509 **cert);
 
 /**
  * Reads a certificate stored in DER-format from a smartcard.
@@ -55,6 +56,13 @@
  * @returns 0 on success, -1 otherwise
  */
 int checkCert(X509 *cert);
+
+int checkCertStore(X509_STORE *ctx, 
+                   X509* cert, 
+                   STACK_OF(X509) *uchain, 
+                   STACK_OF(X509) *tchain);
+
+STACK_OF(X509) *load_chain(char *certfile);
 
 /**
  * Extract the public key of a given certificate.
diff -Nauwr MusclePAM.orig/pam-muscle.conf MusclePAM/pam-muscle.conf
--- MusclePAM.orig/pam-muscle.conf      Thu Sep 26 20:48:56 2002
+++ MusclePAM/pam-muscle.conf   Tue Dec 10 10:35:26 2002
@@ -8,11 +8,11 @@
 CertNumber             = 0                # Certificate number to use
 PinNumber              = 1                # Pin number to verify
 UserPath               = /home/           # Path to user home directory
-CertName               = user.cert        # User Certificate in DER format
-RootCACert             = /etc/root.cert   # Root CA certificate
+RootCACert             = /etc/pam.d/root.cert # Root CA certificate
+RootCADir              = /etc/pam.d       # Root CA hash dir
 LDAPHost               = unsupported      # Web-server with LDAP
 LDAPPath               = unsupported      # Search path in LDAP
-AuthMode               = UserCert         # RootCert or UserCert - se README
+AuthMode               = RootCert         # RootCert or UserCert - se README
 
 
 # End
diff -Nauwr MusclePAM.orig/pam_smartcard.c MusclePAM/pam_smartcard.c
--- MusclePAM.orig/pam_smartcard.c      Thu Sep 26 20:48:56 2002
+++ MusclePAM/pam_smartcard.c   Mon Dec  9 12:20:48 2002
@@ -29,12 +29,15 @@
 #include "cardtools.h"
 #include "certutils.h"
 #include <openssl/evp.h>
+#include <openssl/x509v3.h>
+#include <openssl/err.h>
 #include <string.h>
 #include <preferences.h>
 
 #define PRV_KEY_NUMBER               3
 #define LOGNAME "PAM-SmartCard"     /* Name for logfile entries */
 #define RAND_SIZE 128               /* Size of the random value */
+#define MAX_USERNAME_LEN 128
 #define DEBUG 1
 
 /**
@@ -132,13 +135,23 @@
   return PAM_SUCCESS;
 }
 
-int readRootCert(X509 **userCert, MSCTokenConnection pConnection, 
+int verifyRootCert(X509 **userCert, MSCTokenConnection pConnection, 
                 struct secure_data *sd) {
-  EVP_PKEY *pubkey;
-  int index, rv;
-  X509 *tmpCert, *rootCert;
+
+  int index, rv = 0;
+  X509 *tmpCert;
   STACK *emlst;
-  unsigned char userid[16];
+  unsigned char *userid;  
+  char *p;
+
+  X509_STORE *cert_ctx=NULL;
+  X509_LOOKUP *lookup=NULL;
+  STACK_OF(X509) *untrusted = NULL, *trusted = NULL;
+
+  cert_ctx=X509_STORE_new();
+  if (cert_ctx == NULL) goto cleanup;
+  //X509_STORE_set_verify_cb_func(cert_ctx,NULL);
+
 
   rv = getCardCert(pConnection, &tmpCert);
 
@@ -150,14 +163,18 @@
   }
 
   emlst = (STACK *) X509_get1_email(tmpCert);
-  strncpy(userid, sk_value(emlst, 0), 16);
-  X509_email_free(emlst);
 
-  for (index = 0; index < 15; index++)
-    if (userid[index] == '@')
+  for (index = 0, p = sk_value(emlst,0); 
+       *p && index < MAX_USERNAME_LEN;
+       p++,index++)
+    if (*p == '@')
       break;
 
-  if (index >= 15 || index < 1) {
+  userid = (unsigned char *) malloc(sizeof(unsigned char) * index + 1 );
+  strncpy(userid, sk_value(emlst, 0), index);
+  X509_email_free(emlst);
+
+  if (index >= MAX_USERNAME_LEN || index < 1) {
     syslog(LOG_ERR, "error getting email address from certificate");
     pcsc_release(&pConnection);
     pam_release_data(sd);
@@ -177,59 +194,84 @@
     return PAM_AUTHINFO_UNAVAIL;
   }
 
+  free(userid);
+
   rv = checkCert(tmpCert);
 
   if (rv == -1) {
-    syslog(LOG_ERR, "user certificate expired or revoked");
+    syslog(LOG_ERR, "user certificate expired");
     pcsc_release(&pConnection);
     pam_release_data(sd);
-    return PAM_AUTHINFO_UNAVAIL;
+    return PAM_AUTHTOK_EXPIRED;
   }
 
-  rv = getFileCert(pr.rootcacert, &rootCert);
+  lookup=X509_STORE_add_lookup(cert_ctx,X509_LOOKUP_file());
 
-  if (rv == -1) {
-    /* Try to read a PEM cert */
-    rv = getFileCertPEM(pr.rootcacert, &rootCert);
+  if (pr.rootcacert && strlen(pr.rootcacert) > 0) {
+    if (!X509_LOOKUP_load_file(lookup,pr.rootcacert,X509_FILETYPE_PEM)) {
+      syslog(LOG_ERR, "Error loading CA file %s\n", pr.rootcacert);
+      rv = PAM_AUTHINFO_UNAVAIL;
+      goto cleanup;
   }
+  } else X509_LOOKUP_load_file(lookup,NULL,X509_FILETYPE_DEFAULT);
 
-  if (rv == -1) {
-    syslog(LOG_ERR, "cannot find root certificate in /etc/root.cert");
-    pcsc_release(&pConnection);
-    pam_release_data(sd);
-    return PAM_AUTHINFO_UNAVAIL;
+  lookup=X509_STORE_add_lookup(cert_ctx,X509_LOOKUP_hash_dir());
+  
+  if (pr.rootcadir && strlen(pr.rootcadir) > 0) {
+    if(!X509_LOOKUP_add_dir(lookup,pr.rootcadir,X509_FILETYPE_PEM)) {
+      syslog(LOG_ERR, "Error loading directory %s\n", pr.rootcadir);
+      rv =  PAM_AUTHINFO_UNAVAIL;
+      goto cleanup;
   }
+  } else X509_LOOKUP_add_dir(lookup,NULL,X509_FILETYPE_DEFAULT);
 
-  rv = checkCert(rootCert);
+#if 0  /* still untested */
+  if(pr.untrusted != NULL && strlen(pr.untrusted) > 0) {
+    if(!(untrusted = load_chain(pr.untrusted))) {
+      syslog(LOG_ERR, "Error loading untrusted chain file %s\n", pr.untrusted);
+      rv = PAM_AUTHINFO_UNAVAIL;
+      goto cleanup;
+    }
+  }
 
-  if (rv == -1) {
-    syslog(LOG_ERR, "root certificate expiret or recoked");
-    pcsc_release(&pConnection);
-    pam_release_data(sd);
-    return PAM_AUTHINFO_UNAVAIL;
+  if(pr.trusted != NULL  && strlen(pr.trusted) > 0) {
+    if(!(trusted = load_chain(pr.trusted))) {
+      syslog(LOG_ERR, "Error loading trusted chain file %s\n", pr.trusted);
+      rv = PAM_AUTHINFO_UNAVAIL;
+      goto cleanup;
   }
+  }
+#endif
 
-  rv = getPublicKey(rootCert, &pubkey);
+  rv = checkCertStore(cert_ctx,tmpCert, untrusted, trusted);
 
-  if (rv == -1) {
-    syslog(LOG_ERR, "cannot read public key file from root certificate");
-    pcsc_release(&pConnection);
-    pam_release_data(sd);
-    return PAM_AUTHINFO_UNAVAIL;
+  if (rv <= 0) {
+    syslog(LOG_ERR, "user certificate does not have a valid signature");
+    rv =  PAM_PERM_DENIED;
+    goto cleanup;
   }
 
-  if (!X509_verify(tmpCert, pubkey)) {
-    syslog(LOG_ERR, "user certificate does not have a valid signature");
+  *userCert = tmpCert;
+  
+  rv = 0;
+  
+  if (0) {
+    
+  cleanup:
     pcsc_release(&pConnection);
     pam_release_data(sd);
-    return PAM_AUTHINFO_UNAVAIL;
+    X509_free(tmpCert);
   }
+  if (cert_ctx != NULL) X509_STORE_free(cert_ctx);
+  sk_X509_pop_free(untrusted, X509_free);
+  sk_X509_pop_free(trusted, X509_free);
+  EVP_cleanup();
+  CRYPTO_cleanup_all_ex_data(); 
+  ERR_remove_state(0);
+  ERR_free_strings(); 
 
-  *userCert = tmpCert;
-
-  X509_free(rootCert);
+  return rv;
 
-  return 0;
 }
 
 int readUserCert(X509 **userCert, MSCTokenConnection pConnection, 
@@ -274,14 +316,12 @@
   MSCTokenConnection pConnection;
   MSCCryptInit cryptInit;
   MSCULong32 cryptSize;
-  MSCUChar8 pinNumber;
-  MSCKeyInfo keyInfo;
 
   struct secure_data *sd;
   int i, rv, reader, result;
   int try_first_pass, use_first_pass;
   unsigned char error[150];
-  unsigned char nameBuf[100];
+  
   X509 *userCert;
   EVP_PKEY *pubkey;
 
@@ -289,7 +329,14 @@
   try_first_pass = 0;
   use_first_pass = 0;
 
+  // init OpenSSL
   ERR_load_crypto_strings();
+  OpenSSL_add_all_digests(); OpenSSL_add_all_ciphers();
+  /*
+  EVP_add_digest(EVP_md5());
+  EVP_add_digest(EVP_sha1()); 
+  EVP_add_digest_alias(SN_sha1WithRSAEncryption,SN_sha1WithRSA);
+  */
   util_ReadPreferences();
 
   /* open log */
@@ -404,7 +451,7 @@
   /* get the certs for the user and root CA */
 
   if (pr.authmode == ROOTCERT)
-    rv = readRootCert(&userCert, pConnection, sd);
+    rv = verifyRootCert(&userCert, pConnection, sd);
   else
     rv = readUserCert(&userCert, pConnection, sd);
 
diff -Nauwr MusclePAM.orig/preferences.c MusclePAM/preferences.c
--- MusclePAM.orig/preferences.c        Thu Sep 26 20:48:56 2002
+++ MusclePAM/preferences.c     Tue Dec 10 10:35:02 2002
@@ -16,6 +16,7 @@
  *                                                                  *
  ********************************************************************/
 
+#include <string.h>
 #include <stdio.h>
 #include <syslog.h>
 #include "preferences.h"
@@ -26,7 +27,10 @@
   1,
   "/home/",
   "user.cert",
-  "/etc/root.cert",
+  "/etc/pam.d/root.cert",
+  "/etc/pam.d",
+  "",
+  "",
   "",
   "",
   ROOTCERT
@@ -133,6 +137,38 @@
              strncpy(pr.rootcacert, token, 200);
             }
         }
+      else if (!strcasecmp("RootCADir", token))
+        {
+         token = (char *) strtok(0, sep);
+         if (!token)
+           syslog(LOG_ERR, "Config option \"RootCADir\" failed");
+         else
+            {
+             strncpy(pr.rootcadir, token, 200);
+            }
+        }
+#if 0
+      else if (!strcasecmp("UntrustedCAChain", token))
+        {
+         token = (char *) strtok(0, sep);
+         if (!token)
+           syslog(LOG_ERR, "Config option \"UntrustedCAChain\" failed");
+         else
+            {
+             strncpy(pr.untrusted, token, 200);
+            }
+        }
+      else if (!strcasecmp("TrustedCAChain", token))
+        {
+         token = (char *) strtok(0, sep);
+         if (!token)
+           syslog(LOG_ERR, "Config option \"TrustedCAChain\" failed");
+         else
+            {
+             strncpy(pr.trusted, token, 200);
+            }
+        }
+#endif
       else if (!strcasecmp("LDAPHost", token))
         {
          token = (char *) strtok(0, sep);
diff -Nauwr MusclePAM.orig/preferences.h MusclePAM/preferences.h
--- MusclePAM.orig/preferences.h        Thu Sep 26 20:48:56 2002
+++ MusclePAM/preferences.h     Sun Dec  8 15:40:46 2002
@@ -21,6 +21,9 @@
   char userpath[200];
   char certname[64];
   char rootcacert[200];
+  char rootcadir[200];
+  char untrusted[200];
+  char trusted[200];
   char ldaphost[200];
   char ldappath[200];
   int authmode;

Reply via email to