changeset 12953:2df46ea8f1b1

6929628 pkinit preauth plugin needs interface so caller can provide PIN
author Will Fiveash <will.fiveash@oracle.com>
date Wed, 28 Jul 2010 17:47:31 -0500
parents 982975ba6eba
children e1e7ceb4453f
files exception_lists/copyright usr/src/lib/krb5/plugins/preauth/pkinit/pkinit.h usr/src/lib/krb5/plugins/preauth/pkinit/pkinit_clnt.c usr/src/lib/krb5/plugins/preauth/pkinit/pkinit_crypto_openssl.c usr/src/lib/krb5/plugins/preauth/pkinit/pkinit_crypto_openssl.h usr/src/lib/krb5/plugins/preauth/pkinit/pkinit_identity.c usr/src/lib/pam_modules/krb5/krb5_authenticate.c
diffstat 7 files changed, 129 insertions(+), 58 deletions(-) [+]
line wrap: on
line diff
--- a/exception_lists/copyright	Wed Jul 28 14:00:54 2010 -0700
+++ b/exception_lists/copyright	Wed Jul 28 17:47:31 2010 -0500
@@ -304,14 +304,11 @@
 usr/src/lib/krb5/plugins/kdb/ldap/libkdb_ldap/ldap_tkt_policy.h
 usr/src/lib/krb5/plugins/preauth/pkinit/pkinit_accessor.c
 usr/src/lib/krb5/plugins/preauth/pkinit/pkinit_accessor.h
-usr/src/lib/krb5/plugins/preauth/pkinit/pkinit_clnt.c
 usr/src/lib/krb5/plugins/preauth/pkinit/pkinit_crypto.h
-usr/src/lib/krb5/plugins/preauth/pkinit/pkinit_identity.c
 usr/src/lib/krb5/plugins/preauth/pkinit/pkinit_lib.c
 usr/src/lib/krb5/plugins/preauth/pkinit/pkinit_matching.c
 usr/src/lib/krb5/plugins/preauth/pkinit/pkinit_profile.c
 usr/src/lib/krb5/plugins/preauth/pkinit/pkinit_srv.c
-usr/src/lib/krb5/plugins/preauth/pkinit/pkinit.h
 usr/src/lib/krb5/ss/copyright.h
 usr/src/lib/krb5/ss/mit-sipb-copyright.h
 usr/src/lib/krb5/ss/options.c
--- a/usr/src/lib/krb5/plugins/preauth/pkinit/pkinit.h	Wed Jul 28 14:00:54 2010 -0700
+++ b/usr/src/lib/krb5/plugins/preauth/pkinit/pkinit.h	Wed Jul 28 17:47:31 2010 -0500
@@ -28,6 +28,10 @@
  * SUCH DAMAGES.
  */
 
+/*
+ * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
+ */
+
 #ifndef _PKINIT_H
 #define _PKINIT_H
 
@@ -196,6 +200,7 @@
     char *token_label;
     char *cert_id_string;
     char *cert_label;
+    char *PIN; /* Solaris Kerberos */
 #endif
 } pkinit_identity_opts;
 
--- a/usr/src/lib/krb5/plugins/preauth/pkinit/pkinit_clnt.c	Wed Jul 28 14:00:54 2010 -0700
+++ b/usr/src/lib/krb5/plugins/preauth/pkinit/pkinit_clnt.c	Wed Jul 28 17:47:31 2010 -0500
@@ -28,6 +28,10 @@
  * SUCH DAMAGES.
  */
 
+/*
+ * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
+ */
+
 #include <stdio.h>
 #include <stdlib.h>
 #include <errno.h>
@@ -1472,6 +1476,11 @@
 	    pkiDebug("Setting flag to use RSA_PROTOCOL\n");
 	    plgctx->opts->dh_or_rsa = RSA_PROTOCOL;
 	}
+    } else if (strcmp(attr, "PIN") == 0) {
+	/* Solaris Kerberos: handle our PIN attr */
+	plgctx->idopts->PIN = strdup(value);
+	if (plgctx->idopts->PIN == NULL)
+	    return ENOMEM;
     }
     return 0;
 }
--- a/usr/src/lib/krb5/plugins/preauth/pkinit/pkinit_crypto_openssl.c	Wed Jul 28 14:00:54 2010 -0700
+++ b/usr/src/lib/krb5/plugins/preauth/pkinit/pkinit_crypto_openssl.c	Wed Jul 28 17:47:31 2010 -0500
@@ -769,6 +769,7 @@
     ctx->slotid = PK_NOSLOT;
     ctx->token_label = NULL;
     ctx->cert_label = NULL;
+    ctx->PIN = NULL;
     ctx->session = CK_INVALID_HANDLE;
     ctx->p11 = NULL;
     ctx->p11flags = 0; /* Solaris Kerberos */
@@ -811,6 +812,10 @@
 	free(ctx->cert_id);
     if (ctx->cert_label != NULL)
 	free(ctx->cert_label);
+    if (ctx->PIN != NULL) {
+	(void) memset(ctx->PIN, 0, strlen(ctx->PIN));
+	free(ctx->PIN);
+    }
 #endif
 }
 
@@ -3363,6 +3368,10 @@
     return CKR_OK;
 }
 
+/*
+ * Solaris Kerberos: this function was changed to support a PIN being passed
+ * in.  If that is the case the user will not be prompted for their PIN.
+ */
 static krb5_error_code
 pkinit_login(krb5_context context,
 	     pkinit_identity_crypto_context id_cryptoctx,
@@ -3378,6 +3387,15 @@
     if (tip->flags & CKF_PROTECTED_AUTHENTICATION_PATH) {
 	rdat.data = NULL;
 	rdat.length = 0;
+    } else if (id_cryptoctx->PIN != NULL) {
+	if ((rdat.data = strdup(id_cryptoctx->PIN)) == NULL)
+	    return (ENOMEM);
+	/*
+	 * Don't include NULL string terminator in length calculation as this
+	 * PIN is passed to the C_Login function and only the text chars should
+	 * be considered to be the PIN.
+	 */
+	rdat.length = strlen(id_cryptoctx->PIN);
     } else {
         unsigned char *lastnonwspc, *iterp; /* Solaris Kerberos - trim token label */
         int count;
@@ -3409,8 +3427,12 @@
 	    (void) strlcat(prompt, gettext(" (Warning: PIN final try)"), prompt_len);
 	else if (tip->flags & CKF_USER_PIN_COUNT_LOW)
 	    (void) strlcat(prompt, gettext(" (Warning: PIN count low)"), prompt_len);
-	rdat.data = (char *)malloc(tip->ulMaxPinLen + 2);
+	rdat.data = malloc(tip->ulMaxPinLen + 2);
 	rdat.length = tip->ulMaxPinLen + 1;
+	/*
+	 * Note that the prompter function will set rdat.length such that the
+	 * NULL terminator is not included
+	 */
 
 	kprompt.prompt = prompt;
 	kprompt.hidden = 1;
@@ -3421,7 +3443,7 @@
 	k5int_set_prompt_types(context, &prompt_type);
 	r = (*id_cryptoctx->prompter)(context, id_cryptoctx->prompter_data,
 		NULL, NULL, 1, &kprompt);
-	k5int_set_prompt_types(context, 0);
+	k5int_set_prompt_types(context, NULL);
 	free(prompt);
     }
 
@@ -3441,8 +3463,10 @@
             id_cryptoctx->p11flags |= C_LOGIN_DONE;
         }
     }
-    if (rdat.data)
+    if (rdat.data) {
+	(void) memset(rdat.data, 0, rdat.length);
 	free(rdat.data);
+    }
 
     return r;
 }
@@ -4105,27 +4129,33 @@
 
 	pkiDebug("Initial PKCS12_parse with no password failed\n");
 
-	(void) memset(prompt_reply, '\0', sizeof(prompt_reply));
-	rdat.data = prompt_reply;
-	rdat.length = sizeof(prompt_reply);
-
-	r = snprintf(prompt_string, sizeof(prompt_string), "%s %s",
-		     prompt_prefix, idopts->cert_filename);
-	if (r >= sizeof(prompt_string)) {
-	    pkiDebug("Prompt string, '%s %s', is too long!\n",
-		     prompt_prefix, idopts->cert_filename);
-	    goto cleanup;
+	if (id_cryptoctx->PIN != NULL) {
+		/* Solaris Kerberos: use PIN if set */
+		rdat.data = id_cryptoctx->PIN;
+		/* note rdat.length isn't needed in this case */
+	} else {
+		(void) memset(prompt_reply, '\0', sizeof(prompt_reply));
+		rdat.data = prompt_reply;
+		rdat.length = sizeof(prompt_reply);
+
+		r = snprintf(prompt_string, sizeof(prompt_string), "%s %s",
+			     prompt_prefix, idopts->cert_filename);
+		if (r >= sizeof(prompt_string)) {
+		    pkiDebug("Prompt string, '%s %s', is too long!\n",
+			     prompt_prefix, idopts->cert_filename);
+		    goto cleanup;
+		}
+		kprompt.prompt = prompt_string;
+		kprompt.hidden = 1;
+		kprompt.reply = &rdat;
+		prompt_type = KRB5_PROMPT_TYPE_PREAUTH;
+
+		/* PROMPTER_INVOCATION */
+		k5int_set_prompt_types(context, &prompt_type);
+		r = (*id_cryptoctx->prompter)(context, id_cryptoctx->prompter_data,
+					      NULL, NULL, 1, &kprompt);
+		k5int_set_prompt_types(context, NULL);
 	}
-	kprompt.prompt = prompt_string;
-	kprompt.hidden = 1;
-	kprompt.reply = &rdat;
-	prompt_type = KRB5_PROMPT_TYPE_PREAUTH;
-
-	/* PROMPTER_INVOCATION */
-	k5int_set_prompt_types(context, &prompt_type);
-	r = (*id_cryptoctx->prompter)(context, id_cryptoctx->prompter_data,
-				      NULL, NULL, 1, &kprompt);
-	k5int_set_prompt_types(context, 0);
 
 	ret = PKCS12_parse(p12, rdat.data, &y, &x, NULL);
 	if (ret == 0) {
@@ -4389,6 +4419,11 @@
 	if (id_cryptoctx->cert_label == NULL)
 	    return ENOMEM;
     }
+    if (idopts->PIN != NULL) {
+	id_cryptoctx->PIN = strdup(idopts->PIN);
+	if (id_cryptoctx->PIN == NULL)
+	    return ENOMEM;
+    }
     /* Convert the ascii cert_id string into a binary blob */
     /*
      * Solaris Kerberos:
--- a/usr/src/lib/krb5/plugins/preauth/pkinit/pkinit_crypto_openssl.h	Wed Jul 28 14:00:54 2010 -0700
+++ b/usr/src/lib/krb5/plugins/preauth/pkinit/pkinit_crypto_openssl.h	Wed Jul 28 17:47:31 2010 -0500
@@ -80,6 +80,7 @@
     CK_SLOT_ID slotid;
     char *token_label;
     char *cert_label;
+    char *PIN; /* Solaris Kerberos: */
     /* These are crypto-specific */
     void *p11_module;
     CK_SESSION_HANDLE session;
--- a/usr/src/lib/krb5/plugins/preauth/pkinit/pkinit_identity.c	Wed Jul 28 14:00:54 2010 -0700
+++ b/usr/src/lib/krb5/plugins/preauth/pkinit/pkinit_identity.c	Wed Jul 28 17:47:31 2010 -0500
@@ -28,6 +28,10 @@
  * SUCH DAMAGES.
  */
 
+/*
+ * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
+ */
+
 #include <errno.h>
 #include <string.h>
 #include <stdio.h>
@@ -136,6 +140,7 @@
     opts->token_label = NULL;
     opts->cert_id_string = NULL;
     opts->cert_label = NULL;
+    opts->PIN = NULL;
 #endif
 
     *idopts = opts;
@@ -219,6 +224,11 @@
 	if (newopts->cert_label == NULL)
 	    goto cleanup;
     }
+    if (src_opts->PIN != NULL) {
+	newopts->PIN = strdup(src_opts->PIN);
+	if (newopts->PIN == NULL)
+	    goto cleanup;
+    }
 #endif
 
 
@@ -255,6 +265,10 @@
 	free(idopts->cert_id_string);
     if (idopts->cert_label != NULL)
 	free(idopts->cert_label);
+    if (idopts->PIN != NULL) {
+	(void) memset(idopts->PIN, 0, strlen(idopts->PIN));
+	free(idopts->PIN);
+    }
 #endif
     free(idopts);
 }
--- a/usr/src/lib/pam_modules/krb5/krb5_authenticate.c	Wed Jul 28 14:00:54 2010 -0700
+++ b/usr/src/lib/pam_modules/krb5/krb5_authenticate.c	Wed Jul 28 17:47:31 2010 -0500
@@ -20,8 +20,7 @@
  */
 
 /*
- * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
  */
 
 #include <security/pam_appl.h>
@@ -499,7 +498,7 @@
 		KRB5_TGS_NAME_SIZE,
 		KRB5_TGS_NAME
 	};
-	krb5_get_init_creds_opt opts;
+	krb5_get_init_creds_opt *opts = NULL;
 	krb5_kdc_rep *as_reply = NULL;
 	/*
 	 * "result" should not be assigned PAM_SUCCESS unless
@@ -515,8 +514,6 @@
 		    "PAM-KRB5 (auth): attempt_krb5_auth: start: user='%s'",
 		    user ? user : "<null>");
 
-	krb5_get_init_creds_opt_init(&opts);
-
 	/* need to free context with krb5_free_context */
 	if (code = krb5_init_secure_context(&kmd->kcontext)) {
 		__pam_log(LOG_AUTH | LOG_ERR,
@@ -632,35 +629,44 @@
 	} else
 		my_creds->times.renew_till = 0;
 
-	krb5_get_init_creds_opt_set_tkt_life(&opts, lifetime);
+	code = krb5_get_init_creds_opt_alloc(kmd->kcontext, &opts);
+	if (code != 0) {
+		__pam_log(LOG_AUTH | LOG_ERR,
+		    "Error allocating gic opts: %s",
+		    error_message(code));
+		result = PAM_SYSTEM_ERR;
+		goto out;
+	}
+
+	krb5_get_init_creds_opt_set_tkt_life(opts, lifetime);
 
 	if (proxiable_flag) { 		/* Set in config file */
 		if (kmd->debug)
 			__pam_log(LOG_AUTH | LOG_DEBUG,
 			    "PAM-KRB5 (auth): Proxiable tickets "
 			    "requested");
-		krb5_get_init_creds_opt_set_proxiable(&opts, TRUE);
+		krb5_get_init_creds_opt_set_proxiable(opts, TRUE);
 	}
 	if (forwardable_flag) {
 		if (kmd->debug)
 			__pam_log(LOG_AUTH | LOG_DEBUG,
 			    "PAM-KRB5 (auth): Forwardable tickets "
 			    "requested");
-		krb5_get_init_creds_opt_set_forwardable(&opts, TRUE);
+		krb5_get_init_creds_opt_set_forwardable(opts, TRUE);
 	}
 	if (renewable_flag) {
 		if (kmd->debug)
 			__pam_log(LOG_AUTH | LOG_DEBUG,
 			    "PAM-KRB5 (auth): Renewable tickets "
 			    "requested");
-		krb5_get_init_creds_opt_set_renew_life(&opts, rlife);
+		krb5_get_init_creds_opt_set_renew_life(opts, rlife);
 	}
 	if (no_address_flag) {
 		if (kmd->debug)
 			__pam_log(LOG_AUTH | LOG_DEBUG,
 			    "PAM-KRB5 (auth): Addressless tickets "
 			    "requested");
-		krb5_get_init_creds_opt_set_address_list(&opts, NULL);
+		krb5_get_init_creds_opt_set_address_list(opts, NULL);
 	}
 
 	/*
@@ -686,28 +692,30 @@
 			KRB5_PADATA_PK_AS_REQ,
 			KRB5_PADATA_PK_AS_REQ_OLD
 		};
-		krb5_get_init_creds_opt_set_preauth_list(&opts, pk_pa_list, 2);
+		krb5_get_init_creds_opt_set_preauth_list(opts, pk_pa_list, 2);
+
+		if (*krb5_pass == NULL || strlen(*krb5_pass) != 0) {
+			if (*krb5_pass != NULL) {
+				/* treat the krb5_pass as a PIN */
+				code = krb5_get_init_creds_opt_set_pa(
+				    kmd->kcontext, opts, "PIN", *krb5_pass);
+			}
 
-		if (*krb5_pass == NULL) {
-			/* let preauth plugin prompt for PIN */
-			code = __krb5_get_init_creds_password(kmd->kcontext,
-			    my_creds,
-			    me,
-			    NULL, /* clear text passwd */
-			    pam_krb5_prompter, /* prompter */
-			    pamh, /* prompter data */
-			    0, /* start time */
-			    NULL, /* defaults to krbtgt@REALM */
-			    &opts,
-			    &as_reply);
+			if (!code) {
+				code = __krb5_get_init_creds_password(
+				    kmd->kcontext,
+				    my_creds,
+				    me,
+				    NULL, /* clear text passwd */
+				    pam_krb5_prompter, /* prompter */
+				    pamh, /* prompter data */
+				    0, /* start time */
+				    NULL, /* defaults to krbtgt@REALM */
+				    opts,
+				    &as_reply);
+			}
 		} else {
-			/*
-			 * krb pkinit does not support setting the PIN so we
-			 * punt on trying to use krb5_pass as the PIN for now.
-			 * Note that once this is supported by pkinit the code
-			 * should make sure krb5_pass isn't empty and if it is
-			 * then that's an error.
-			 */
+			/* invalid PIN */
 			code = KRB5KRB_AP_ERR_BAD_INTEGRITY;
 		}
 	} else {
@@ -725,7 +733,7 @@
 				KRB5_PADATA_ENC_TIMESTAMP
 			};
 
-			krb5_get_init_creds_opt_set_preauth_list(&opts,
+			krb5_get_init_creds_opt_set_preauth_list(opts,
 			    pk_pa_list, 1);
 
 			/*
@@ -743,7 +751,7 @@
 			    NULL,	/* data */
 			    0,		/* start time */
 			    NULL,	/* defaults to krbtgt@REALM */
-			    &opts,
+			    opts,
 			    &as_reply);
 		}
 	}
@@ -951,6 +959,8 @@
 		krb5_free_context(kmd->kcontext);
 		kmd->kcontext = NULL;
 	}
+	if (opts)
+		krb5_get_init_creds_opt_free(kmd->kcontext, opts);
 
 	if (kmd->debug)
 		__pam_log(LOG_AUTH | LOG_DEBUG,