CK_OBJECT_HANDLE *objp);
static krb5_error_code pkinit_login
(krb5_context context, pkinit_identity_crypto_context id_cryptoctx,
- CK_TOKEN_INFO *tip);
+ CK_TOKEN_INFO *tip, const char *password);
static krb5_error_code pkinit_open_session
(krb5_context context, pkinit_identity_crypto_context id_cryptoctx);
static void * pkinit_C_LoadModule(const char *modname, CK_FUNCTION_LIST_PTR_PTR p11p);
struct get_key_cb_data {
krb5_context context;
pkinit_identity_crypto_context id_cryptoctx;
+ const char *fsname;
char *filename;
+ const char *password;
};
static int
krb5_error_code retval;
char *prompt;
- if (asprintf(&prompt, "%s %s", _("Pass phrase for"), data->filename) < 0)
+ if (data->id_cryptoctx->defer_id_prompt) {
+ /* Supply the identity name to be passed to a responder callback. */
+ pkinit_set_deferred_id(&data->id_cryptoctx->deferred_ids,
+ data->fsname, 0, NULL);
return -1;
- rdat.data = buf;
- rdat.length = size;
- kprompt.prompt = prompt;
- kprompt.hidden = 1;
- kprompt.reply = &rdat;
- prompt_type = KRB5_PROMPT_TYPE_PREAUTH;
-
- /* PROMPTER_INVOCATION */
- k5int_set_prompt_types(data->context, &prompt_type);
- id_cryptoctx = data->id_cryptoctx;
- retval = data->id_cryptoctx->prompter(data->context,
- id_cryptoctx->prompter_data, NULL,
- NULL, 1, &kprompt);
- k5int_set_prompt_types(data->context, 0);
- free(prompt);
- return retval ? -1 : (int)rdat.length;
+ }
+ if (data->password == NULL) {
+ /* We don't already have a password to use, so prompt for one. */
+ if (data->id_cryptoctx->prompter == NULL)
+ return -1;
+ if (asprintf(&prompt, "%s %s", _("Pass phrase for"),
+ data->filename) < 0)
+ return -1;
+ rdat.data = buf;
+ rdat.length = size;
+ kprompt.prompt = prompt;
+ kprompt.hidden = 1;
+ kprompt.reply = &rdat;
+ prompt_type = KRB5_PROMPT_TYPE_PREAUTH;
+
+ /* PROMPTER_INVOCATION */
+ k5int_set_prompt_types(data->context, &prompt_type);
+ id_cryptoctx = data->id_cryptoctx;
+ retval = (data->id_cryptoctx->prompter)(data->context,
+ id_cryptoctx->prompter_data,
+ NULL, NULL, 1, &kprompt);
+ k5int_set_prompt_types(data->context, 0);
+ free(prompt);
+ if (retval != 0)
+ return -1;
+ } else {
+ /* Just use the already-supplied password. */
+ rdat.length = strlen(data->password);
+ if ((int)rdat.length >= size)
+ return -1;
+ snprintf(buf, size, "%s", data->password);
+ }
+ return (int)rdat.length;
}
static krb5_error_code
get_key(krb5_context context, pkinit_identity_crypto_context id_cryptoctx,
- char *filename, EVP_PKEY **retkey)
+ char *filename, const char *fsname, EVP_PKEY **retkey,
+ const char *password)
{
EVP_PKEY *pkey = NULL;
BIO *tmp = NULL;
cb_data.context = context;
cb_data.id_cryptoctx = id_cryptoctx;
cb_data.filename = filename;
+ cb_data.fsname = fsname;
+ cb_data.password = password;
pkey = PEM_read_bio_PrivateKey(tmp, NULL, get_key_cb, &cb_data);
- if (pkey == NULL) {
+ if (pkey == NULL && !id_cryptoctx->defer_id_prompt) {
retval = EIO;
pkiDebug("failed to read private key from %s\n", filename);
goto cleanup;
return;
if (ctx->p11 != NULL) {
- if (ctx->session) {
+ if (ctx->session != CK_INVALID_HANDLE) {
ctx->p11->C_CloseSession(ctx->session);
ctx->session = CK_INVALID_HANDLE;
}
etype = CMS_get0_eContentType(cms);
/*
- * Prior to 1.10 the MIT client incorrectly omitted the pkinit structure
+ * Prior to 1.10 the MIT client incorrectly emitted the pkinit structure
* directly in a CMS ContentInfo rather than using SignedData with no
* signers. Handle that case.
*/
static krb5_error_code
pkinit_login(krb5_context context,
pkinit_identity_crypto_context id_cryptoctx,
- CK_TOKEN_INFO *tip)
+ CK_TOKEN_INFO *tip, const char *password)
{
krb5_data rdat;
char *prompt;
if (tip->flags & CKF_PROTECTED_AUTHENTICATION_PATH) {
rdat.data = NULL;
rdat.length = 0;
+ } else if (password != NULL) {
+ rdat.data = strdup(password);
+ rdat.length = strlen(password);
+ } else if (id_cryptoctx->prompter == NULL) {
+ r = KRB5_LIBOS_CANTREADPWD;
+ rdat.data = NULL;
} else {
if (tip->flags & CKF_USER_PIN_LOCKED)
warning = " (Warning: PIN locked)";
CK_ULONG count = 0;
CK_SLOT_ID_PTR slotlist;
CK_TOKEN_INFO tinfo;
+ char *p11name;
+ const char *password;
if (cctx->p11_module != NULL)
return 0; /* session already open */
}
cctx->slotid = slotlist[i];
free(slotlist);
- pkiDebug("open_session: slotid %d (%lu of %d)\n", (int) cctx->slotid,
+ pkiDebug("open_session: slotid %d (%lu of %d)\n", (int)cctx->slotid,
i + 1, (int) count);
/* Login if needed */
- if (tinfo.flags & CKF_LOGIN_REQUIRED)
- r = pkinit_login(context, cctx, &tinfo);
+ if (tinfo.flags & CKF_LOGIN_REQUIRED) {
+ if (cctx->p11_module_name != NULL) {
+ if (cctx->slotid != PK_NOSLOT) {
+ if (asprintf(&p11name,
+ "PKCS11:module_name=%s:slotid=%ld:token=%s",
+ cctx->p11_module_name, (long)cctx->slotid,
+ tinfo.label) < 0)
+ p11name = NULL;
+ } else {
+ if (asprintf(&p11name,
+ "PKCS11:module_name=%s,token=%s",
+ cctx->p11_module_name,
+ tinfo.label) < 0)
+ p11name = NULL;
+ }
+ } else {
+ p11name = NULL;
+ }
+ if (cctx->defer_id_prompt) {
+ /* Supply the identity name to be passed to the responder. */
+ pkinit_set_deferred_id(&cctx->deferred_ids,
+ p11name, tinfo.flags, NULL);
+ free(p11name);
+ return KRB5KRB_ERR_GENERIC;
+ }
+ /* Look up a responder-supplied password for the token. */
+ password = pkinit_find_deferred_id(cctx->deferred_ids, p11name);
+ free(p11name);
+ r = pkinit_login(context, cctx, &tinfo, password);
+ }
return r;
}
char prompt_string[128];
char prompt_reply[128];
char *prompt_prefix = _("Pass phrase for");
+ char *p12name = reassemble_pkcs12_name(idopts->cert_filename);
+ const char *tmp;
pkiDebug("Initial PKCS12_parse with no password failed\n");
- 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 >= (int) sizeof(prompt_string)) {
- pkiDebug("Prompt string, '%s %s', is too long!\n",
- prompt_prefix, idopts->cert_filename);
+ if (id_cryptoctx->defer_id_prompt) {
+ /* Supply the identity name to be passed to the responder. */
+ pkinit_set_deferred_id(&id_cryptoctx->deferred_ids, p12name, 0,
+ NULL);
+ free(p12name);
+ retval = 0;
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, 0);
+ /* Try to read a responder-supplied password. */
+ tmp = pkinit_find_deferred_id(id_cryptoctx->deferred_ids, p12name);
+ free(p12name);
+ if (tmp != NULL) {
+ /* Try using the responder-supplied password. */
+ rdat.data = (char *)tmp;
+ rdat.length = strlen(tmp);
+ } else if (id_cryptoctx->prompter == NULL) {
+ /* We can't use a prompter. */
+ goto cleanup;
+ } else {
+ /* Ask using a prompter. */
+ 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 >= (int)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, 0);
+ }
ret = PKCS12_parse(p12, rdat.data, &y, &x, NULL);
if (ret == 0) {
- pkiDebug("Seconde PKCS12_parse with password failed\n");
+ pkiDebug("Second PKCS12_parse with password failed\n");
goto cleanup;
}
}
krb5_error_code retval;
X509 *x = NULL;
EVP_PKEY *y = NULL;
+ char *fsname = NULL;
+ const char *password;
- /* load the certificate */
+ fsname = reassemble_files_name(certname, keyname);
+
+ /* Try to read a responder-supplied password. */
+ password = pkinit_find_deferred_id(id_cryptoctx->deferred_ids, fsname);
+
+ /* Load the certificate. */
retval = get_cert(certname, &x);
if (retval != 0 || x == NULL) {
pkiDebug("failed to load user's certificate from '%s'\n", certname);
goto cleanup;
}
- retval = get_key(context, id_cryptoctx, keyname, &y);
+ /* Load the key. */
+ retval = get_key(context, id_cryptoctx, keyname, fsname, &y, password);
if (retval != 0 || y == NULL) {
pkiDebug("failed to load user's private key from '%s'\n", keyname);
goto cleanup;
retval = 0;
cleanup:
- if (retval) {
+ free(fsname);
+ if (retval != 0 || y == NULL) {
if (x != NULL)
X509_free(x);
if (y != NULL)
continue;
}
- if (i == 0) {
+ if (!id_cryptoctx->defer_id_prompt && i == 0) {
pkiDebug("%s: No cert/key pairs found in directory '%s'\n",
__FUNCTION__, idopts->cert_filename);
retval = ENOENT;
/* Copy stuff from idopts -> id_cryptoctx */
if (idopts->p11_module_name != NULL) {
+ free(id_cryptoctx->p11_module_name);
id_cryptoctx->p11_module_name = strdup(idopts->p11_module_name);
if (id_cryptoctx->p11_module_name == NULL)
return ENOMEM;
if (pkinit_open_session(context, id_cryptoctx)) {
pkiDebug("can't open pkcs11 session\n");
- return KRB5KDC_ERR_PREAUTH_FAILED;
+ if (!id_cryptoctx->defer_id_prompt)
+ return KRB5KDC_ERR_PREAUTH_FAILED;
+ }
+ if (id_cryptoctx->defer_id_prompt) {
+ /*
+ * We need to reset all of the PKCS#11 state, so that the next time we
+ * poke at it, it'll be in as close to the state it was in after we
+ * loaded it the first time as we can make it.
+ */
+ pkinit_fini_pkcs11(id_cryptoctx);
+ pkinit_init_pkcs11(id_cryptoctx);
+ return 0;
}
#ifndef PKINIT_USE_MECH_LIST
pkinit_identity_crypto_context id_cryptoctx,
const char *identity, const char *password)
{
- unsigned long flags;
+ unsigned long ck_flags;
- flags = pkinit_get_deferred_id_flags(id_cryptoctx->deferred_ids,
- identity);
+ ck_flags = pkinit_get_deferred_id_flags(id_cryptoctx->deferred_ids,
+ identity);
return pkinit_set_deferred_id(&id_cryptoctx->deferred_ids,
- identity, flags, password);
+ identity, ck_flags, password);
}
/*