287c72
From e2cc7a04f0dbfbf1a8bc6cd70f639c56a203af28 Mon Sep 17 00:00:00 2001
31ace6
From: Greg Hudson <ghudson@mit.edu>
31ace6
Date: Mon, 23 Mar 2020 19:10:03 -0400
31ace6
Subject: [PATCH] Eliminate redundant PKINIT responder invocation
31ace6
31ace6
In pkinit_client_prep_questions(), only act if the input padata type
31ace6
is KRB5_PADATA_PK_AS_REQ.  Otherwise we will ask questions again when
31ace6
the KDC issues a ticket.
31ace6
31ace6
Commit 7621d2f9a87214327ca3b2594e34dc7cea84596b (ticket 8242)
31ace6
unintentionally changed the behavior of pkinit_load_fs_cert_and_key(),
31ace6
causing pkinit_client_prep_questions() to do nothing on its first
31ace6
call.  Restore the original behavior of returning 0 when prompting is
31ace6
deferred.
31ace6
31ace6
Modify the existing "FILE identity, password on key (responder)"
31ace6
PKINIT test to check that the responder is only invoked once.
31ace6
31ace6
ticket: 8885
31ace6
(cherry picked from commit f1286842ce7b9e507a4ce0a47f44ab361a98be63)
31ace6
(cherry picked from commit 4a05805eb39ba088c07f782fb52a6538ec3f2db6)
31ace6
---
31ace6
 src/plugins/preauth/pkinit/pkinit_clnt.c           |  5 +++++
31ace6
 src/plugins/preauth/pkinit/pkinit_crypto_openssl.c | 13 +++++++------
31ace6
 src/tests/t_pkinit.py                              | 11 +++++++----
31ace6
 3 files changed, 19 insertions(+), 10 deletions(-)
31ace6
31ace6
diff --git a/src/plugins/preauth/pkinit/pkinit_clnt.c b/src/plugins/preauth/pkinit/pkinit_clnt.c
31ace6
index 2f0431991..9b991ffe0 100644
31ace6
--- a/src/plugins/preauth/pkinit/pkinit_clnt.c
31ace6
+++ b/src/plugins/preauth/pkinit/pkinit_clnt.c
31ace6
@@ -897,6 +897,11 @@ pkinit_client_prep_questions(krb5_context context,
31ace6
     k5_json_object jval = NULL;
31ace6
     k5_json_number jflag = NULL;
31ace6
 
31ace6
+    /* Don't ask questions for the informational padata items or when the
31ace6
+     * ticket is issued. */
31ace6
+    if (pa_data->pa_type != KRB5_PADATA_PK_AS_REQ)
31ace6
+        return 0;
31ace6
+
31ace6
     if (!reqctx->identity_initialized) {
31ace6
         pkinit_client_profile(context, plgctx, reqctx, cb, rock,
31ace6
                               &request->server->realm);
31ace6
diff --git a/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c b/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c
31ace6
index dd718c2be..dbb054378 100644
31ace6
--- a/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c
31ace6
+++ b/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c
31ace6
@@ -4362,17 +4362,18 @@ pkinit_load_fs_cert_and_key(krb5_context context,
31ace6
 
31ace6
     /* Load the certificate. */
31ace6
     retval = get_cert(certname, &x);
31ace6
-    if (retval != 0 || x == NULL) {
31ace6
-        retval = oerr(context, 0, _("Cannot read certificate file '%s'"),
31ace6
+    if (retval) {
31ace6
+        retval = oerr(context, retval, _("Cannot read certificate file '%s'"),
31ace6
                       certname);
31ace6
-        goto cleanup;
31ace6
     }
31ace6
+    if (retval || x == NULL)
31ace6
+        goto cleanup;
31ace6
     /* Load the key. */
31ace6
     retval = get_key(context, id_cryptoctx, keyname, fsname, &y, password);
31ace6
-    if (retval != 0 || y == NULL) {
31ace6
-        retval = oerr(context, 0, _("Cannot read key file '%s'"), fsname);
31ace6
+    if (retval)
31ace6
+        retval = oerr(context, retval, _("Cannot read key file '%s'"), fsname);
31ace6
+    if (retval || y == NULL)
31ace6
         goto cleanup;
31ace6
-    }
31ace6
 
31ace6
     id_cryptoctx->creds[cindex] = malloc(sizeof(struct _pkinit_cred_info));
31ace6
     if (id_cryptoctx->creds[cindex] == NULL) {
31ace6
diff --git a/src/tests/t_pkinit.py b/src/tests/t_pkinit.py
31ace6
index 69daf4987..ecd450e8a 100755
31ace6
--- a/src/tests/t_pkinit.py
31ace6
+++ b/src/tests/t_pkinit.py
31ace6
@@ -248,10 +248,13 @@ realm.run(['./adata', realm.host_princ],
31ace6
 # supplied by the responder.
31ace6
 # Supply the response in raw form.
31ace6
 mark('FILE identity, password on key (responder)')
31ace6
-realm.run(['./responder', '-x', 'pkinit={"%s": 0}' % file_enc_identity,
31ace6
-           '-r', 'pkinit={"%s": "encrypted"}' % file_enc_identity,
31ace6
-           '-X', 'X509_user_identity=%s' % file_enc_identity,
31ace6
-           realm.user_princ])
31ace6
+out = realm.run(['./responder', '-x', 'pkinit={"%s": 0}' % file_enc_identity,
31ace6
+                 '-r', 'pkinit={"%s": "encrypted"}' % file_enc_identity,
31ace6
+                 '-X', 'X509_user_identity=%s' % file_enc_identity,
31ace6
+                 realm.user_princ])
31ace6
+# Regression test for #8885 (password question asked twice).
31ace6
+if out.count('OK: ') != 1:
31ace6
+    fail('Wrong number of responder calls')
31ace6
 # Supply the response through the convenience API.
31ace6
 realm.run(['./responder', '-X', 'X509_user_identity=%s' % file_enc_identity,
31ace6
            '-p', '%s=%s' % (file_enc_identity, 'encrypted'), realm.user_princ])