[Pcsclite-cvs-commit] CVS MusclePAM
CVS User rousseau
ludovic.rousseau@free.fr
Wed, 15 Sep 2004 01:00:58 -0600
Update of /cvsroot/muscleapps/MusclePAM
In directory haydn:/tmp/cvs-serv18609
Modified Files:
README certutils.c certutils.h pam_smartcard.c
Log Message:
patch from Bruce Barnett
http://archives.neohapsis.com/archives/dev/muscle/2004-q3/0372.html
--- /cvsroot/muscleapps/MusclePAM/README 2003/05/20 21:49:50 1.4
+++ /cvsroot/muscleapps/MusclePAM/README 2004/09/15 07:00:58 1.5
@@ -36,13 +36,89 @@
Configuration
-There is a configuration file located in /etc/pamsmartcrc. This will have
-paramaters that are read by the authentication module. Most of these are
-self-explanatory, except AuthMode. This paramater can have two values:
-1. UserCert - the module will look in ~/.muscle/user.cert for the
- certificate.
-2. RootCert - the module will retreive the certificate from the smartcard
- and validate the signature by looking at the RootCA's
- certificate in /etc/root.cert. It will also check that the
- username corresponds to the username in the certificate.
-
+There is a configuration file located in /etc/musclepam/pam-muscle.conf.
+This will have parameters that are read by the authentication module.
+Most of these are self-explanatory, except AuthMode. This parameter can
+have two values:
+
+1. UserCert - the module will look in ~/.muscle/user.cert for the
+ certificate.
+2. RootCert - the module will retreive the certificate from the smartcard
+ and validate the signature by looking at the RootCA's
+ certificate in /etc/root.cert. It will also check that the
+ username corresponds to the username in the certificate.
+
+
+
+If UserCert is selected, then the certificate can be in one of three formats.
+ 1) DER/BER X509 - this is a binary format
+ 2) PEM X509 (PEM_read_X509) - in PEM format
+
+ This is in base64 format, and has the form
+ -----BEGIN CERTIFICATE-----
+ MIIEzzCCA7egAwIBAgIBADANBgkqhkiG9w0BAQQFADBvMQswCQYDVQQGEwJkZTEg
+ [snip]
+ -----END CERTIFICATE-----
+ 3) PEM - PUBKEY
+ -----BEGIN PUBLIC KEY-----
+ MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDhs17bA92YPg8XrR9s34qoK2Fc
+ [snip]
+ -----END PUBLIC KEY-----
+
+ The third form can be obtained by using musacletool to create a
+ keypair, export it, and then using b2fs to convert it into a
+ pubkey format
+
+ Example
+
+ $ muscleTool
+ muscle > tokens
+ 1. MuscleCard Applet
+ muscle > connect 1
+ muscle [MuscleCard Applet] > verify 1 <PINVALUE>
+ PIN Verify Successful
+ muscle [MuscleCard Applet] > genkeys
+ ***************** Key Generation Routine *****************
+ Note: Keys will be generated with default permissions
+ using the RSA CRT algorithm for generation.
+ **********************************************************
+ Enter the private key number: 1
+ Enter the public key number: 2
+ Are you sure ? (Y/N): y
+ Generating keys
+ *******************************] : Success
+ muscle [MuscleCard Applet] > listkeys
+ Key Type Key Num SIZE READ WRITE USE
+ ----------------- ----------- ----- ------ ------ ------
+ RSA PRIVATE CRT 1 1024 NEVER PIN #1 PIN #1
+ RSA PUBLIC 2 1024 ALWAYS PIN #1 PIN #1
+ muscle [MuscleCard Applet] > exportkey 2 cert.blob
+ Export Key Successful
+ muscle [MuscleCard Applet] > release
+ muscle > exit
+
+ # now use b2fs to convert the blob into a PEM public key certificate
+ % b2fs cert.blob >~/.muscle/user.cert
+
+
+Note that the user can do this without any outside authority. Make sure
+the home directory and certificate is not writable. (pam_musclecard.so
+should check to make sure this is not possible. However it doesn't, so
+this is a potential security problem).
+
+Once you have the certificate in place, I have been able to get the su
+and login modules to work with PAM.
+
+Modify
+ /etc/pam.d/su
+to contain
+ auth required /lib/security/pam_musclecard.so service=system-auth
+
+ and /etc/pam.d/login to contain
+ auth required /lib/security/pam_musclecard.so service=system-auth
+
+and when you try to log into the console, or to do an su, it first
+checks if a smartcard is plugged in. If so, it asks for a PIN value.
+Then it procees to verify it with the user's ~user/.muscle/user.cert
+file.
+
--- /cvsroot/muscleapps/MusclePAM/certutils.c 2003/05/20 21:46:58 1.5
+++ /cvsroot/muscleapps/MusclePAM/certutils.c 2004/09/15 07:00:58 1.6
@@ -76,22 +76,49 @@
// Open file
fp = fopen(file, "rb");
- if (fp == NULL)
+ if (fp == NULL) {
+ syslog(LOG_ERR, "cannot open certificate file %s: %s", file, strerror(errno));
return -1;
-
+ }
// Get the cert
PEM_read_X509(fp,&mycert,NULL,NULL);
fclose(fp);
- if (mycert == NULL)
+ if (mycert == NULL) {
+ syslog(LOG_ERR, "File %s does not contain X509 certificate - PEM_read_X509() fails", file);
return -1;
-
+ }
+
*cert = mycert;
return 0;
}
+/* add the code to read a public key certificate from a file */
+int getPubKeyFromFile(const char *file, EVP_PKEY **cert) {
+ FILE *fp;
+ EVP_PKEY *mycert = NULL;
+
+ // Open file
+ fp = fopen(file, "rb");
+ if (fp == NULL) {
+ syslog(LOG_ERR, "cannot open certificate file %s: %s", file, strerror(errno));
+ return -1;
+ }
+ // Get the cert
+ PEM_read_PUBKEY(fp,&mycert,NULL,NULL);
+
+ fclose(fp);
+
+ if (mycert == NULL) {
+ syslog(LOG_ERR, "File %s does not contain Public Key certificate - PEM_read_PUBKEY() fails", file);
+ return -1;
+ }
+ *cert = mycert;
+ return 0;
+}
+
/* Method to read a certificate from a a smartcard */
int getCardCert(MSCTokenConnection pConnection, X509 **cert) {
int rv;
--- /cvsroot/muscleapps/MusclePAM/certutils.h 2003/10/03 19:30:31 1.4
+++ /cvsroot/muscleapps/MusclePAM/certutils.h 2004/09/15 07:00:58 1.5
@@ -66,6 +66,14 @@
*/
int getPublicKey(X509 *cert, EVP_PKEY** pub_key);
+/**
+ * Extract the public key of a given certificate from a file
+ *
+ * @param filename - certificate that stores the public key
+ * @param pub_key - public key object to write key into
+ * @returns 0 on success, -1 otherwise
+ */
+int getPubKeyFromFile(const char *filename, EVP_PKEY** pub_key);
#endif
/*** end of file ***********************************************************/
--- /cvsroot/muscleapps/MusclePAM/pam_smartcard.c 2003/10/02 19:30:13 1.15
+++ /cvsroot/muscleapps/MusclePAM/pam_smartcard.c 2004/09/15 07:00:58 1.16
@@ -8,6 +8,7 @@
* Mario Strasser <mast@gmx.net> *
* David Corcoran <corcoran@linuxnet.com> *
* Eirik A. Herskedal <ehersked@cs.purdue.edu> *
+ * Bruce Barnett <muscle040302@grymoire.com>
* *
********************************************************************
* *
@@ -250,37 +251,47 @@
return 0;
}
-int readUserCert(X509 **userCert, MSCTokenConnection pConnection,
+int readUserPubKey(EVP_PKEY **userCert, MSCTokenConnection pConnection,
struct secure_data *sd) {
int rv;
- X509 *tmpCert;
+ EVP_PKEY *tmpCert;
+ X509 *tmpCert1;
unsigned char homeFile[200];
+ /* tries to get a public key information from the user's public key certificate */
snprintf(homeFile, 200, "%s%s/.muscle/%s", pr.userpath, sd->user, pr.certname);
- rv = getFileCert(homeFile, &tmpCert);
+ rv = getFileCert(homeFile, &tmpCert1);
if (rv == -1) {
- /* Try to read a PEM cert */
- rv = getFileCertPEM(homeFile, &tmpCert);
- }
+ /* Didn't work - now try public key cert */
+ /* for UserAuth - this could also be a public key Certificate, not an X509 (signed) */
- if (rv == -1) {
- syslog(LOG_ERR, "cannot read certificate from %s", homeFile);
- pcsc_release(&pConnection);
- pam_release_data(sd);
- return PAM_AUTHINFO_UNAVAIL;
- }
+ /* This makes the assumption the user created the certificate
+ without an outside authority to sign it. */
- rv = checkCert(tmpCert);
+ rv = getPubKeyFromFile(homeFile, &tmpCert);
+ } else {
+ syslog(LOG_ERR, "user certificate successfully read from %s", homeFile);
+ rv = checkCert(tmpCert1);
+ if (rv == -1) {
+ syslog(LOG_ERR, "user certificate expired or revoked");
+ pcsc_release(&pConnection);
+ pam_release_data(sd);
+ return PAM_AUTHINFO_UNAVAIL;
+ }
+ rv = getPublicKey(tmpCert1, &tmpCert);
+ }
+
if (rv == -1) {
- syslog(LOG_ERR, "user certificate expired or revoked");
+ syslog(LOG_ERR, "cannot read certificate from %s", homeFile);
pcsc_release(&pConnection);
pam_release_data(sd);
return PAM_AUTHINFO_UNAVAIL;
}
+
*userCert = tmpCert;
return 0;
@@ -311,7 +322,7 @@
util_ReadPreferences();
/* open log */
- //openlog(LOGNAME, LOG_CONS | LOG_PID, LOG_AUTHPRIV);
+ openlog(LOGNAME, LOG_CONS | LOG_PID, LOG_AUTHPRIV);
/* init data */
sd = (struct secure_data*)malloc(sizeof(struct secure_data));
@@ -323,12 +334,12 @@
/* init pcsc */
rv = pcsc_init(&pConnection, reader);
if (rv != MSC_SUCCESS) {
- syslog(LOG_ERR, "musclecard error: %s", msc_error(rv));
+ syslog(LOG_ERR, "musclecard error during pcsc_init: %s", msc_error(rv));
pam_release_data(sd);
return PAM_AUTHINFO_UNAVAIL;
}
- if (pr.debug) printf("Welcome\n");
+ if (pr.debug) printf("Welcome to pam_musclecard.so verification Module\n");
/* get user name */
rv = pam_get_user(pamh, &sd->user, NULL);
@@ -339,6 +350,7 @@
return PAM_USER_UNKNOWN;
}
+ if (pr.debug) printf("User = %s\n", sd->user);
/* get password */
if (use_first_pass) {
rv = pam_get_pin(pamh, sd->pin, NULL, PAM_AUTHTOK, 0);
@@ -356,8 +368,7 @@
return PAM_AUTHINFO_UNAVAIL;
}
- if (pr.debug)
- printf("pin = %s\n\n", sd->pin);
+ /* if (pr.debug) printf("pin = %s\n\n", sd->pin); */
/* get random value */
rv = getRandom(sd->rand, RAND_SIZE);
@@ -377,7 +388,7 @@
printf("\n\n");
}
- /* We must get the ACL for key #3 to determine which pin must
+ /* We must get the ACL for key #3 (or whatever) to determine which pin must
be verified */
/* verify chv1 */
@@ -385,8 +396,8 @@
rv = MSCVerifyPIN(&pConnection, pr.pinnumber, sd->pin, PIN_SIZE);
if (rv != MSC_SUCCESS) {
- printf("Invalid PIN Entered\n");
- syslog(LOG_ERR, "musclecard error: %s", msc_error(rv));
+ if (pr.debug) printf("Invalid PIN Entered\n");
+ syslog(LOG_ERR, "musclecard error during Verify PIN: %s", msc_error(rv));
pcsc_release(&pConnection);
pam_release_data(sd);
return PAM_AUTHINFO_UNAVAIL;
@@ -403,8 +414,13 @@
rv = MSCComputeCrypt(&pConnection, &cryptInit, (MSCPUChar8)sd->rand,
RAND_SIZE, (MSCPUChar8)sd->cipher, &cryptSize);
- if (rv != MSC_SUCCESS) {
- syslog(LOG_ERR, "musclecard error: %s", msc_error(rv));
+ if (rv == MSC_INCORRECT_P1) {
+ syslog(LOG_ERR, "musclecard error during Compute Crypt, incorrect P1 value, certificate #%d: %s", pr.certnumber, msc_error(rv));
+ pcsc_release(&pConnection);
+ pam_release_data(sd);
+ return PAM_AUTHINFO_UNAVAIL;
+ } else if (rv != MSC_SUCCESS) {
+ syslog(LOG_ERR, "musclecard error during Compute Crypt, certificate #%d, %s", pr.certnumber, msc_error(rv));
pcsc_release(&pConnection);
pam_release_data(sd);
return PAM_AUTHINFO_UNAVAIL;
@@ -421,15 +437,14 @@
/* get the certs for the user and root CA */
- if (pr.authmode == ROOTCERT)
+ if (pr.authmode == ROOTCERT) {
rv = readRootCert(&userCert, pConnection, sd);
- else
- rv = readUserCert(&userCert, pConnection, sd);
-
- if (rv != 0)
- return PAM_AUTHINFO_UNAVAIL;
-
- rv = getPublicKey(userCert, &pubkey);
+ if (rv != 0)
+ return PAM_AUTHINFO_UNAVAIL;
+ rv = getPublicKey(userCert, &pubkey);
+ } else {
+ rv = readUserPubKey(&pubkey, pConnection, sd);
+ }
if (rv == -1) {
syslog(LOG_ERR, "cannot read public key file from user certificate");
@@ -438,6 +453,22 @@
return PAM_AUTHINFO_UNAVAIL;
}
+
+ /* This sectionj can be used to verify the user's certificate */
+#ifdef DEBUG_SPECIAL1
+ if (pr.debug) {
+ syslog(LOG_ERR, "Public key file read from user certificate");
+ printf("public exponent : %s\n", BN_bn2hex(pubkey->pkey.rsa->e));
+ printf("public modulus : %s\n", BN_bn2hex(pubkey->pkey.rsa->n));
+ }
+
+ BIO *eout=NULL;
+ eout = BIO_new(BIO_s_file());
+ BIO_set_fp(eout,stdout,BIO_NOCLOSE);
+ RSA_print(eout, pubkey->pkey.rsa, 0);
+
+#endif
+
rv = RSA_public_decrypt(128, sd->cipher, sd->plain, pubkey->pkey.rsa,
RSA_NO_PADDING);
@@ -447,7 +478,7 @@
if (rv == -1) {
syslog(LOG_ERR, "cannot decode random number");
ERR_error_string(ERR_get_error(), error);
- printf("Error from openssl:\t %s\n", error);
+ if (pr.debug) printf("Error from openssl:\t %s\n", error);
pcsc_release(&pConnection);
pam_release_data(sd);
return PAM_AUTHINFO_UNAVAIL;
@@ -462,9 +493,80 @@
printf("\n\n");
}
+
+ /* Here is another debug section. It asks the card to decrypy what it sent out.
+ * This should be the same as the input.
+ * Normally this isn't used - Bruce */
+
+#ifdef DEBUG_SPECIAL
+ if (pr.debug) {
+ /* double check to make sure this works. We should be able to ask the card to decrypt this as well */
+
+/* assume the next certificate is the matching public key - This may be a bas assumption. -Bruce */
+ cryptInit.keyNum = pr.certnumber + 1;
+ cryptInit.cipherMode = MSC_MODE_RSA_NOPAD;
+ cryptInit.cipherDirection = MSC_DIR_DECRYPT;
+ cryptInit.optParams = NULL;
+ cryptInit.optParamsSize = 0;
+ cryptSize = RAND_SIZE;
+
+ struct secure_data *sd2;
+ sd2 = (struct secure_data*)malloc(sizeof(struct secure_data));
+ if (sd2 == NULL) {
+ syslog(LOG_CRIT, "not enough free memory to initialize sd2");
+ return PAM_AUTHINFO_UNAVAIL;
+ }
+ memcpy(sd2->rand,sd->cipher,RAND_SIZE);
+ rv = MSCComputeCrypt(&pConnection, &cryptInit, (MSCPUChar8)sd2->rand,
+ RAND_SIZE, (MSCPUChar8)sd2->cipher, &cryptSize);
+
+ if (rv != MSC_SUCCESS) {
+
+ syslog(LOG_ERR, "musclecard error during reverse Compute Crypt, certificate #%d: %s", cryptInit.keyNum, msc_error(rv));
+ }
+ printf("Undecoded value using key #%d = ", cryptInit.keyNum);
+ for (i=0; i < RAND_SIZE; i++) {
+ rv = (unsigned char)sd2->cipher[i];
+ printf("%02x", rv);
+ }
+ printf("\n\n");
+ }
+ printf("Compare two values size by side: \n");
+ for (i=0; i < 128; i+=8) {
+ printf("\t%02X%02X%02X%02X %02X%02X%02X%02X == %02X%02X%02X%02X %02X%02X%02X%02X?\n",
+ (unsigned char)sd->rand[i],
+ (unsigned char)sd->rand[i+1],
+ (unsigned char)sd->rand[i+2],
+ (unsigned char)sd->rand[i+3],
+ (unsigned char)sd->rand[i+4],
+ (unsigned char)sd->rand[i+5],
+ (unsigned char)sd->rand[i+6],
+ (unsigned char)sd->rand[i+7],
+ (unsigned char)sd->plain[i],
+ (unsigned char)sd->plain[i+1],
+ (unsigned char)sd->plain[i+2],
+ (unsigned char)sd->plain[i+3],
+ (unsigned char)sd->plain[i+4],
+ (unsigned char)sd->plain[i+5],
+ (unsigned char)sd->plain[i+6],
+ (unsigned char)sd->plain[i+7]
+ );
+ }
+
+#endif
+
/* compare original value and result from smartcard */
- if (memcmp(sd->rand, sd->plain, RAND_SIZE) == 0) result = PAM_SUCCESS;
- else result = PAM_AUTH_ERR;
+ if (memcmp(sd->rand, sd->plain, RAND_SIZE) == 0) {
+ if (pr.debug)
+ printf("Challenge was Successfully met\n");
+ result = PAM_SUCCESS;
+ } else {
+ if (pr.debug)
+ syslog(LOG_ERR, "musclecard challenge failed for user %s", sd->user);
+
+ result = PAM_AUTH_ERR;
+ }
+
/* Release certificates */
X509_free(userCert);