Hi Sim, [EMAIL PROTECTED] wrote:
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
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.
#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;
