Add PKINIT KDC support for freshness token
Also, fix securid_sam2 preauth for non-default salt
This commit is contained in:
parent
ed142b51b1
commit
a387becbf5
631
Add-PKINIT-KDC-support-for-freshness-token.patch
Normal file
631
Add-PKINIT-KDC-support-for-freshness-token.patch
Normal file
@ -0,0 +1,631 @@
|
|||||||
|
From 4ddfba7c9c12056f9f5819648f20f68e5625dced Mon Sep 17 00:00:00 2001
|
||||||
|
From: Greg Hudson <ghudson@mit.edu>
|
||||||
|
Date: Mon, 12 Mar 2018 11:31:46 -0400
|
||||||
|
Subject: [PATCH] Add PKINIT KDC support for freshness token
|
||||||
|
|
||||||
|
Send a freshness token in the preauth hint list if PKINIT is
|
||||||
|
configured and the request padata indicates support. Verify the
|
||||||
|
freshness token if the client includes one in a PKINIT request, and
|
||||||
|
log whether one was received. If pkinit_require_freshness is set to
|
||||||
|
true in the realm config, reject non-anonymous requests which don't
|
||||||
|
contain a freshness token.
|
||||||
|
|
||||||
|
Add freshness token tests to t_pkinit.py with some related changes.
|
||||||
|
Remove client long-term keys after testing password preauth so we get
|
||||||
|
better error reporting when pkinit_require_freshness is set and a
|
||||||
|
token is not sent. Remove ./responder invocations for test cases
|
||||||
|
which don't ask PKINIT responder questions, or else the responder
|
||||||
|
would fail now that it isn't being asked for the password. Leave
|
||||||
|
anonymous PKINIT enabled after the anonymous tests so that we can use
|
||||||
|
it again when testing enforcement of pkinit_require_freshness. Add
|
||||||
|
expected trace messages for the basic test, including one for
|
||||||
|
receiving a freshness token. Add minimal expected trace messages for
|
||||||
|
the RSA test.
|
||||||
|
|
||||||
|
ticket: 8648
|
||||||
|
(cherry picked from commit 4a9050df0bc34bfb08ba24462d6e2514640f4b8e)
|
||||||
|
---
|
||||||
|
doc/admin/conf_files/kdc_conf.rst | 4 +
|
||||||
|
doc/admin/pkinit.rst | 25 ++++++
|
||||||
|
doc/appdev/refs/macros/index.rst | 2 +
|
||||||
|
doc/formats/freshness_token.rst | 19 +++++
|
||||||
|
doc/formats/index.rst | 1 +
|
||||||
|
src/include/krb5/kdcpreauth_plugin.h | 17 +++++
|
||||||
|
src/include/krb5/krb5.hin | 3 +
|
||||||
|
src/kdc/do_as_req.c | 2 +
|
||||||
|
src/kdc/kdc_preauth.c | 130 +++++++++++++++++++++++++++++++-
|
||||||
|
src/kdc/kdc_util.h | 2 +
|
||||||
|
src/plugins/preauth/pkinit/pkinit.h | 2 +
|
||||||
|
src/plugins/preauth/pkinit/pkinit_srv.c | 51 ++++++++++++-
|
||||||
|
src/tests/t_pkinit.py | 50 ++++++++----
|
||||||
|
13 files changed, 292 insertions(+), 16 deletions(-)
|
||||||
|
create mode 100644 doc/formats/freshness_token.rst
|
||||||
|
|
||||||
|
diff --git a/doc/admin/conf_files/kdc_conf.rst b/doc/admin/conf_files/kdc_conf.rst
|
||||||
|
index 3af1c3796..1ac1a37c2 100644
|
||||||
|
--- a/doc/admin/conf_files/kdc_conf.rst
|
||||||
|
+++ b/doc/admin/conf_files/kdc_conf.rst
|
||||||
|
@@ -798,6 +798,10 @@ For information about the syntax of some of these options, see
|
||||||
|
**pkinit_require_crl_checking** should be set to true if the
|
||||||
|
policy is such that up-to-date CRLs must be present for every CA.
|
||||||
|
|
||||||
|
+**pkinit_require_freshness**
|
||||||
|
+ Specifies whether to require clients to include a freshness token
|
||||||
|
+ in PKINIT requests. The default value is false. (New in release
|
||||||
|
+ 1.17.)
|
||||||
|
|
||||||
|
.. _Encryption_types:
|
||||||
|
|
||||||
|
diff --git a/doc/admin/pkinit.rst b/doc/admin/pkinit.rst
|
||||||
|
index c601c5c9e..bec4fc800 100644
|
||||||
|
--- a/doc/admin/pkinit.rst
|
||||||
|
+++ b/doc/admin/pkinit.rst
|
||||||
|
@@ -327,3 +327,28 @@ appropriate :ref:`kdc_realms` subsection of the KDC's
|
||||||
|
To obtain anonymous credentials on a client, run ``kinit -n``, or
|
||||||
|
``kinit -n @REALMNAME`` to specify a realm. The resulting tickets
|
||||||
|
will have the client name ``WELLKNOWN/ANONYMOUS@WELLKNOWN:ANONYMOUS``.
|
||||||
|
+
|
||||||
|
+
|
||||||
|
+Freshness tokens
|
||||||
|
+----------------
|
||||||
|
+
|
||||||
|
+Freshness tokens can ensure that the client has recently had access to
|
||||||
|
+its certificate private key. If freshness tokens are not required by
|
||||||
|
+the KDC, a client program with temporary possession of the private key
|
||||||
|
+can compose requests for future timestamps and use them later.
|
||||||
|
+
|
||||||
|
+In release 1.17 and later, freshness tokens are supported by the
|
||||||
|
+client and are sent by the KDC when the client indicates support for
|
||||||
|
+them. Because not all clients support freshness tokens yet, they are
|
||||||
|
+not required by default. To check if freshness tokens are supported
|
||||||
|
+by a realm's clients, look in the KDC logs for the lines::
|
||||||
|
+
|
||||||
|
+ PKINIT: freshness token received from <client principal>
|
||||||
|
+ PKINIT: no freshness token received from <client principal>
|
||||||
|
+
|
||||||
|
+To require freshness tokens for all clients in a realm (except for
|
||||||
|
+clients authenticating anonymously), set the
|
||||||
|
+**pkinit_require_freshness** variable to ``true`` in the appropriate
|
||||||
|
+:ref:`kdc_realms` subsection of the KDC's :ref:`kdc.conf(5)` file. To
|
||||||
|
+test that this option is in effect, run ``kinit -X disable_freshness``
|
||||||
|
+and verify that authentication is unsuccessful.
|
||||||
|
diff --git a/doc/appdev/refs/macros/index.rst b/doc/appdev/refs/macros/index.rst
|
||||||
|
index e76747102..dba818b26 100644
|
||||||
|
--- a/doc/appdev/refs/macros/index.rst
|
||||||
|
+++ b/doc/appdev/refs/macros/index.rst
|
||||||
|
@@ -181,6 +181,7 @@ Public
|
||||||
|
KRB5_KEYUSAGE_KRB_ERROR_CKSUM.rst
|
||||||
|
KRB5_KEYUSAGE_KRB_PRIV_ENCPART.rst
|
||||||
|
KRB5_KEYUSAGE_KRB_SAFE_CKSUM.rst
|
||||||
|
+ KRB5_KEYUSAGE_PA_AS_FRESHNESS.rst
|
||||||
|
KRB5_KEYUSAGE_PA_FX_COOKIE.rst
|
||||||
|
KRB5_KEYUSAGE_PA_OTP_REQUEST.rst
|
||||||
|
KRB5_KEYUSAGE_PA_PKINIT_KX.rst
|
||||||
|
@@ -241,6 +242,7 @@ Public
|
||||||
|
KRB5_PADATA_AFS3_SALT.rst
|
||||||
|
KRB5_PADATA_AP_REQ.rst
|
||||||
|
KRB5_PADATA_AS_CHECKSUM.rst
|
||||||
|
+ KRB5_PADATA_AS_FRESHNESS.rst
|
||||||
|
KRB5_PADATA_ENCRYPTED_CHALLENGE.rst
|
||||||
|
KRB5_PADATA_ENC_SANDIA_SECURID.rst
|
||||||
|
KRB5_PADATA_ENC_TIMESTAMP.rst
|
||||||
|
diff --git a/doc/formats/freshness_token.rst b/doc/formats/freshness_token.rst
|
||||||
|
new file mode 100644
|
||||||
|
index 000000000..3127621a9
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/doc/formats/freshness_token.rst
|
||||||
|
@@ -0,0 +1,19 @@
|
||||||
|
+PKINIT freshness tokens
|
||||||
|
+=======================
|
||||||
|
+
|
||||||
|
+:rfc:`8070` specifies a pa-data type PA_AS_FRESHNESS, which clients
|
||||||
|
+should reflect within signed PKINIT data to prove recent access to the
|
||||||
|
+client certificate private key. The contents of a freshness token are
|
||||||
|
+left to the KDC implementation. The MIT krb5 KDC uses the following
|
||||||
|
+format for freshness tokens (starting in release 1.17):
|
||||||
|
+
|
||||||
|
+* a four-byte big-endian POSIX timestamp
|
||||||
|
+* a four-byte big-endian key version number
|
||||||
|
+* an :rfc:`3961` checksum, with no ASN.1 wrapper
|
||||||
|
+
|
||||||
|
+The checksum is computed using the first key in the local krbtgt
|
||||||
|
+principal entry for the realm (e.g. ``krbtgt/KRBTEST.COM@KRBTEST.COM``
|
||||||
|
+if the request is to the ``KRBTEST.COM`` realm) of the indicated key
|
||||||
|
+version. The checksum type must be the mandatory checksum type for
|
||||||
|
+the encryption type of the krbtgt key. The key usage value for the
|
||||||
|
+checksum is 514.
|
||||||
|
diff --git a/doc/formats/index.rst b/doc/formats/index.rst
|
||||||
|
index 8b30626d4..4ad534424 100644
|
||||||
|
--- a/doc/formats/index.rst
|
||||||
|
+++ b/doc/formats/index.rst
|
||||||
|
@@ -7,3 +7,4 @@ Protocols and file formats
|
||||||
|
ccache_file_format
|
||||||
|
keytab_file_format
|
||||||
|
cookie
|
||||||
|
+ freshness_token
|
||||||
|
diff --git a/src/include/krb5/kdcpreauth_plugin.h b/src/include/krb5/kdcpreauth_plugin.h
|
||||||
|
index f38820099..3a4754234 100644
|
||||||
|
--- a/src/include/krb5/kdcpreauth_plugin.h
|
||||||
|
+++ b/src/include/krb5/kdcpreauth_plugin.h
|
||||||
|
@@ -240,6 +240,23 @@ typedef struct krb5_kdcpreauth_callbacks_st {
|
||||||
|
|
||||||
|
/* End of version 4 kdcpreauth callbacks. */
|
||||||
|
|
||||||
|
+ /*
|
||||||
|
+ * Instruct the KDC to send a freshness token in the method data
|
||||||
|
+ * accompanying a PREAUTH_REQUIRED or PREAUTH_FAILED error, if the client
|
||||||
|
+ * indicated support for freshness tokens. This callback should only be
|
||||||
|
+ * invoked from the edata method.
|
||||||
|
+ */
|
||||||
|
+ void (*send_freshness_token)(krb5_context context,
|
||||||
|
+ krb5_kdcpreauth_rock rock);
|
||||||
|
+
|
||||||
|
+ /* Validate a freshness token sent by the client. Return 0 on success,
|
||||||
|
+ * KRB5KDC_ERR_PREAUTH_EXPIRED on error. */
|
||||||
|
+ krb5_error_code (*check_freshness_token)(krb5_context context,
|
||||||
|
+ krb5_kdcpreauth_rock rock,
|
||||||
|
+ const krb5_data *token);
|
||||||
|
+
|
||||||
|
+ /* End of version 5 kdcpreauth callbacks. */
|
||||||
|
+
|
||||||
|
} *krb5_kdcpreauth_callbacks;
|
||||||
|
|
||||||
|
/* Optional: preauth plugin initialization function. */
|
||||||
|
diff --git a/src/include/krb5/krb5.hin b/src/include/krb5/krb5.hin
|
||||||
|
index 833e72335..a650ecece 100644
|
||||||
|
--- a/src/include/krb5/krb5.hin
|
||||||
|
+++ b/src/include/krb5/krb5.hin
|
||||||
|
@@ -1035,7 +1035,10 @@ krb5_c_keyed_checksum_types(krb5_context context, krb5_enctype enctype,
|
||||||
|
#define KRB5_KEYUSAGE_AS_REQ 56
|
||||||
|
#define KRB5_KEYUSAGE_CAMMAC 64
|
||||||
|
|
||||||
|
+/* Key usage values 512-1023 are reserved for uses internal to a Kerberos
|
||||||
|
+ * implementation. */
|
||||||
|
#define KRB5_KEYUSAGE_PA_FX_COOKIE 513 /**< Used for encrypted FAST cookies */
|
||||||
|
+#define KRB5_KEYUSAGE_PA_AS_FRESHNESS 514 /**< Used for freshness tokens */
|
||||||
|
/** @} */ /* end of KRB5_KEYUSAGE group */
|
||||||
|
|
||||||
|
/**
|
||||||
|
diff --git a/src/kdc/do_as_req.c b/src/kdc/do_as_req.c
|
||||||
|
index 7c8da63e1..588c1375a 100644
|
||||||
|
--- a/src/kdc/do_as_req.c
|
||||||
|
+++ b/src/kdc/do_as_req.c
|
||||||
|
@@ -563,6 +563,7 @@ process_as_req(krb5_kdc_req *request, krb5_data *req_pkt,
|
||||||
|
state->rock.rstate = state->rstate;
|
||||||
|
state->rock.vctx = vctx;
|
||||||
|
state->rock.auth_indicators = &state->auth_indicators;
|
||||||
|
+ state->rock.send_freshness_token = FALSE;
|
||||||
|
if (!state->request->client) {
|
||||||
|
state->status = "NULL_CLIENT";
|
||||||
|
errcode = KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN;
|
||||||
|
@@ -659,6 +660,7 @@ process_as_req(krb5_kdc_req *request, krb5_data *req_pkt,
|
||||||
|
state->status = "GET_LOCAL_TGT";
|
||||||
|
goto errout;
|
||||||
|
}
|
||||||
|
+ state->rock.local_tgt = state->local_tgt;
|
||||||
|
|
||||||
|
au_state->stage = VALIDATE_POL;
|
||||||
|
|
||||||
|
diff --git a/src/kdc/kdc_preauth.c b/src/kdc/kdc_preauth.c
|
||||||
|
index 6f34dc289..80b130222 100644
|
||||||
|
--- a/src/kdc/kdc_preauth.c
|
||||||
|
+++ b/src/kdc/kdc_preauth.c
|
||||||
|
@@ -87,6 +87,9 @@
|
||||||
|
#include <assert.h>
|
||||||
|
#include <krb5/kdcpreauth_plugin.h>
|
||||||
|
|
||||||
|
+/* Let freshness tokens be valid for ten minutes. */
|
||||||
|
+#define FRESHNESS_LIFETIME 600
|
||||||
|
+
|
||||||
|
typedef struct preauth_system_st {
|
||||||
|
const char *name;
|
||||||
|
int type;
|
||||||
|
@@ -497,8 +500,68 @@ client_name(krb5_context context, krb5_kdcpreauth_rock rock)
|
||||||
|
return rock->client->princ;
|
||||||
|
}
|
||||||
|
|
||||||
|
+static void
|
||||||
|
+send_freshness_token(krb5_context context, krb5_kdcpreauth_rock rock)
|
||||||
|
+{
|
||||||
|
+ rock->send_freshness_token = TRUE;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static krb5_error_code
|
||||||
|
+check_freshness_token(krb5_context context, krb5_kdcpreauth_rock rock,
|
||||||
|
+ const krb5_data *token)
|
||||||
|
+{
|
||||||
|
+ krb5_timestamp token_ts, now;
|
||||||
|
+ krb5_key_data *kd;
|
||||||
|
+ krb5_keyblock kb;
|
||||||
|
+ krb5_kvno token_kvno;
|
||||||
|
+ krb5_checksum cksum;
|
||||||
|
+ krb5_data d;
|
||||||
|
+ uint8_t *token_cksum;
|
||||||
|
+ size_t token_cksum_len;
|
||||||
|
+ krb5_boolean valid = FALSE;
|
||||||
|
+ char ckbuf[4];
|
||||||
|
+
|
||||||
|
+ memset(&kb, 0, sizeof(kb));
|
||||||
|
+
|
||||||
|
+ if (krb5_timeofday(context, &now) != 0)
|
||||||
|
+ goto cleanup;
|
||||||
|
+
|
||||||
|
+ if (token->length <= 8)
|
||||||
|
+ goto cleanup;
|
||||||
|
+ token_ts = load_32_be(token->data);
|
||||||
|
+ token_kvno = load_32_be(token->data + 4);
|
||||||
|
+ token_cksum = (uint8_t *)token->data + 8;
|
||||||
|
+ token_cksum_len = token->length - 8;
|
||||||
|
+
|
||||||
|
+ /* Check if the token timestamp is too old. */
|
||||||
|
+ if (ts_after(now, ts_incr(token_ts, FRESHNESS_LIFETIME)))
|
||||||
|
+ goto cleanup;
|
||||||
|
+
|
||||||
|
+ /* Fetch and decrypt the local krbtgt key of the token's kvno. */
|
||||||
|
+ if (krb5_dbe_find_enctype(context, rock->local_tgt, -1, -1, token_kvno,
|
||||||
|
+ &kd) != 0)
|
||||||
|
+ goto cleanup;
|
||||||
|
+ if (krb5_dbe_decrypt_key_data(context, NULL, kd, &kb, NULL) != 0)
|
||||||
|
+ goto cleanup;
|
||||||
|
+
|
||||||
|
+ /* Verify the token checksum against the current KDC time. The checksum
|
||||||
|
+ * must use the mandatory checksum type of the krbtgt key's enctype. */
|
||||||
|
+ store_32_be(token_ts, ckbuf);
|
||||||
|
+ d = make_data(ckbuf, sizeof(ckbuf));
|
||||||
|
+ cksum.magic = KV5M_CHECKSUM;
|
||||||
|
+ cksum.checksum_type = 0;
|
||||||
|
+ cksum.length = token_cksum_len;
|
||||||
|
+ cksum.contents = token_cksum;
|
||||||
|
+ (void)krb5_c_verify_checksum(context, &kb, KRB5_KEYUSAGE_PA_AS_FRESHNESS,
|
||||||
|
+ &d, &cksum, &valid);
|
||||||
|
+
|
||||||
|
+cleanup:
|
||||||
|
+ krb5_free_keyblock_contents(context, &kb);
|
||||||
|
+ return valid ? 0 : KRB5KDC_ERR_PREAUTH_EXPIRED;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
static struct krb5_kdcpreauth_callbacks_st callbacks = {
|
||||||
|
- 4,
|
||||||
|
+ 5,
|
||||||
|
max_time_skew,
|
||||||
|
client_keys,
|
||||||
|
free_keys,
|
||||||
|
@@ -514,7 +577,9 @@ static struct krb5_kdcpreauth_callbacks_st callbacks = {
|
||||||
|
get_cookie,
|
||||||
|
set_cookie,
|
||||||
|
match_client,
|
||||||
|
- client_name
|
||||||
|
+ client_name,
|
||||||
|
+ send_freshness_token,
|
||||||
|
+ check_freshness_token
|
||||||
|
};
|
||||||
|
|
||||||
|
static krb5_error_code
|
||||||
|
@@ -770,6 +835,62 @@ cleanup:
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
+static krb5_error_code
|
||||||
|
+add_freshness_token(krb5_context context, krb5_kdcpreauth_rock rock,
|
||||||
|
+ krb5_pa_data ***pa_list)
|
||||||
|
+{
|
||||||
|
+ krb5_error_code ret;
|
||||||
|
+ krb5_timestamp now;
|
||||||
|
+ krb5_key_data *kd;
|
||||||
|
+ krb5_keyblock kb;
|
||||||
|
+ krb5_checksum cksum;
|
||||||
|
+ krb5_data d;
|
||||||
|
+ krb5_pa_data *pa;
|
||||||
|
+ char ckbuf[4];
|
||||||
|
+
|
||||||
|
+ memset(&cksum, 0, sizeof(cksum));
|
||||||
|
+ memset(&kb, 0, sizeof(kb));
|
||||||
|
+
|
||||||
|
+ if (!rock->send_freshness_token)
|
||||||
|
+ return 0;
|
||||||
|
+ if (krb5int_find_pa_data(context, rock->request->padata,
|
||||||
|
+ KRB5_PADATA_AS_FRESHNESS) == NULL)
|
||||||
|
+ return 0;
|
||||||
|
+
|
||||||
|
+ /* Fetch and decrypt the current local krbtgt key. */
|
||||||
|
+ ret = krb5_dbe_find_enctype(context, rock->local_tgt, -1, -1, 0, &kd);
|
||||||
|
+ if (ret)
|
||||||
|
+ goto cleanup;
|
||||||
|
+ ret = krb5_dbe_decrypt_key_data(context, NULL, kd, &kb, NULL);
|
||||||
|
+ if (ret)
|
||||||
|
+ goto cleanup;
|
||||||
|
+
|
||||||
|
+ /* Compute a checksum over the current KDC time. */
|
||||||
|
+ ret = krb5_timeofday(context, &now);
|
||||||
|
+ if (ret)
|
||||||
|
+ goto cleanup;
|
||||||
|
+ store_32_be(now, ckbuf);
|
||||||
|
+ d = make_data(ckbuf, sizeof(ckbuf));
|
||||||
|
+ ret = krb5_c_make_checksum(context, 0, &kb, KRB5_KEYUSAGE_PA_AS_FRESHNESS,
|
||||||
|
+ &d, &cksum);
|
||||||
|
+
|
||||||
|
+ /* Compose a freshness token from the time, krbtgt kvno, and checksum. */
|
||||||
|
+ ret = alloc_pa_data(KRB5_PADATA_AS_FRESHNESS, 8 + cksum.length, &pa);
|
||||||
|
+ if (ret)
|
||||||
|
+ goto cleanup;
|
||||||
|
+ store_32_be(now, pa->contents);
|
||||||
|
+ store_32_be(kd->key_data_kvno, pa->contents + 4);
|
||||||
|
+ memcpy(pa->contents + 8, cksum.contents, cksum.length);
|
||||||
|
+
|
||||||
|
+ /* add_pa_data_element() claims pa on success or failure. */
|
||||||
|
+ ret = add_pa_data_element(pa_list, pa);
|
||||||
|
+
|
||||||
|
+cleanup:
|
||||||
|
+ krb5_free_keyblock_contents(context, &kb);
|
||||||
|
+ krb5_free_checksum_contents(context, &cksum);
|
||||||
|
+ return ret;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
struct hint_state {
|
||||||
|
kdc_hint_respond_fn respond;
|
||||||
|
void *arg;
|
||||||
|
@@ -792,6 +913,11 @@ hint_list_finish(struct hint_state *state, krb5_error_code code)
|
||||||
|
void *oldarg = state->arg;
|
||||||
|
kdc_realm_t *kdc_active_realm = state->realm;
|
||||||
|
|
||||||
|
+ /* Add a freshness token if a preauth module requested it and the client
|
||||||
|
+ * request indicates support for it. */
|
||||||
|
+ if (!code)
|
||||||
|
+ code = add_freshness_token(kdc_context, state->rock, &state->pa_data);
|
||||||
|
+
|
||||||
|
if (!code) {
|
||||||
|
if (state->pa_data == NULL) {
|
||||||
|
krb5_klog_syslog(LOG_INFO,
|
||||||
|
diff --git a/src/kdc/kdc_util.h b/src/kdc/kdc_util.h
|
||||||
|
index 18649b8ad..a63af2503 100644
|
||||||
|
--- a/src/kdc/kdc_util.h
|
||||||
|
+++ b/src/kdc/kdc_util.h
|
||||||
|
@@ -427,11 +427,13 @@ struct krb5_kdcpreauth_rock_st {
|
||||||
|
krb5_kdc_req *request;
|
||||||
|
krb5_data *inner_body;
|
||||||
|
krb5_db_entry *client;
|
||||||
|
+ krb5_db_entry *local_tgt;
|
||||||
|
krb5_key_data *client_key;
|
||||||
|
krb5_keyblock *client_keyblock;
|
||||||
|
struct kdc_request_state *rstate;
|
||||||
|
verto_ctx *vctx;
|
||||||
|
krb5_data ***auth_indicators;
|
||||||
|
+ krb5_boolean send_freshness_token;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define isflagset(flagfield, flag) (flagfield & (flag))
|
||||||
|
diff --git a/src/plugins/preauth/pkinit/pkinit.h b/src/plugins/preauth/pkinit/pkinit.h
|
||||||
|
index 8489a3e23..fe2ec0d31 100644
|
||||||
|
--- a/src/plugins/preauth/pkinit/pkinit.h
|
||||||
|
+++ b/src/plugins/preauth/pkinit/pkinit.h
|
||||||
|
@@ -77,6 +77,7 @@
|
||||||
|
#define KRB5_CONF_PKINIT_KDC_OCSP "pkinit_kdc_ocsp"
|
||||||
|
#define KRB5_CONF_PKINIT_POOL "pkinit_pool"
|
||||||
|
#define KRB5_CONF_PKINIT_REQUIRE_CRL_CHECKING "pkinit_require_crl_checking"
|
||||||
|
+#define KRB5_CONF_PKINIT_REQUIRE_FRESHNESS "pkinit_require_freshness"
|
||||||
|
#define KRB5_CONF_PKINIT_REVOKE "pkinit_revoke"
|
||||||
|
|
||||||
|
/* Make pkiDebug(fmt,...) print, or not. */
|
||||||
|
@@ -148,6 +149,7 @@ typedef struct _pkinit_plg_opts {
|
||||||
|
int allow_upn; /* allow UPN-SAN instead of pkinit-SAN */
|
||||||
|
int dh_or_rsa; /* selects DH or RSA based pkinit */
|
||||||
|
int require_crl_checking; /* require CRL for a CA (default is false) */
|
||||||
|
+ int require_freshness; /* require freshness token (default is false) */
|
||||||
|
int disable_freshness; /* disable freshness token on client for testing */
|
||||||
|
int dh_min_bits; /* minimum DH modulus size allowed */
|
||||||
|
} pkinit_plg_opts;
|
||||||
|
diff --git a/src/plugins/preauth/pkinit/pkinit_srv.c b/src/plugins/preauth/pkinit/pkinit_srv.c
|
||||||
|
index 4e9685885..bbfde34b2 100644
|
||||||
|
--- a/src/plugins/preauth/pkinit/pkinit_srv.c
|
||||||
|
+++ b/src/plugins/preauth/pkinit/pkinit_srv.c
|
||||||
|
@@ -161,6 +161,10 @@ pkinit_server_get_edata(krb5_context context,
|
||||||
|
if (plgctx == NULL)
|
||||||
|
retval = EINVAL;
|
||||||
|
|
||||||
|
+ /* Send a freshness token if the client requested one. */
|
||||||
|
+ if (!retval)
|
||||||
|
+ cb->send_freshness_token(context, rock);
|
||||||
|
+
|
||||||
|
(*respond)(arg, retval, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -396,6 +400,31 @@ cleanup:
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
+/* Return an error if freshness tokens are required and one was not received.
|
||||||
|
+ * Log an appropriate message indicating whether a valid token was received. */
|
||||||
|
+static krb5_error_code
|
||||||
|
+check_log_freshness(krb5_context context, pkinit_kdc_context plgctx,
|
||||||
|
+ krb5_kdc_req *request, krb5_boolean valid_freshness_token)
|
||||||
|
+{
|
||||||
|
+ krb5_error_code ret;
|
||||||
|
+ char *name = NULL;
|
||||||
|
+
|
||||||
|
+ ret = krb5_unparse_name(context, request->client, &name);
|
||||||
|
+ if (ret)
|
||||||
|
+ return ret;
|
||||||
|
+ if (plgctx->opts->require_freshness && !valid_freshness_token) {
|
||||||
|
+ com_err("", 0, _("PKINIT: no freshness token, rejecting auth from %s"),
|
||||||
|
+ name);
|
||||||
|
+ ret = KRB5KDC_ERR_PREAUTH_FAILED;
|
||||||
|
+ } else if (valid_freshness_token) {
|
||||||
|
+ com_err("", 0, _("PKINIT: freshness token received from %s"), name);
|
||||||
|
+ } else {
|
||||||
|
+ com_err("", 0, _("PKINIT: no freshness token received from %s"), name);
|
||||||
|
+ }
|
||||||
|
+ krb5_free_unparsed_name(context, name);
|
||||||
|
+ return ret;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
static void
|
||||||
|
pkinit_server_verify_padata(krb5_context context,
|
||||||
|
krb5_data *req_pkt,
|
||||||
|
@@ -418,10 +447,11 @@ pkinit_server_verify_padata(krb5_context context,
|
||||||
|
pkinit_kdc_req_context reqctx = NULL;
|
||||||
|
krb5_checksum cksum = {0, 0, 0, NULL};
|
||||||
|
krb5_data *der_req = NULL;
|
||||||
|
- krb5_data k5data;
|
||||||
|
+ krb5_data k5data, *ftoken;
|
||||||
|
int is_signed = 1;
|
||||||
|
krb5_pa_data **e_data = NULL;
|
||||||
|
krb5_kdcpreauth_modreq modreq = NULL;
|
||||||
|
+ krb5_boolean valid_freshness_token = FALSE;
|
||||||
|
char **sp;
|
||||||
|
|
||||||
|
pkiDebug("pkinit_verify_padata: entered!\n");
|
||||||
|
@@ -592,6 +622,14 @@ pkinit_server_verify_padata(krb5_context context,
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
+ ftoken = auth_pack->pkAuthenticator.freshnessToken;
|
||||||
|
+ if (ftoken != NULL) {
|
||||||
|
+ retval = cb->check_freshness_token(context, rock, ftoken);
|
||||||
|
+ if (retval)
|
||||||
|
+ goto cleanup;
|
||||||
|
+ valid_freshness_token = TRUE;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
/* check if kdcPkId present and match KDC's subjectIdentifier */
|
||||||
|
if (reqp->kdcPkId.data != NULL) {
|
||||||
|
int valid_kdcPkId = 0;
|
||||||
|
@@ -634,6 +672,13 @@ pkinit_server_verify_padata(krb5_context context,
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
+ if (is_signed) {
|
||||||
|
+ retval = check_log_freshness(context, plgctx, request,
|
||||||
|
+ valid_freshness_token);
|
||||||
|
+ if (retval)
|
||||||
|
+ goto cleanup;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
if (is_signed && plgctx->auth_indicators != NULL) {
|
||||||
|
/* Assert configured authentication indicators. */
|
||||||
|
for (sp = plgctx->auth_indicators; *sp != NULL; sp++) {
|
||||||
|
@@ -1323,6 +1368,10 @@ pkinit_init_kdc_profile(krb5_context context, pkinit_kdc_context plgctx)
|
||||||
|
KRB5_CONF_PKINIT_REQUIRE_CRL_CHECKING,
|
||||||
|
0, &plgctx->opts->require_crl_checking);
|
||||||
|
|
||||||
|
+ pkinit_kdcdefault_boolean(context, plgctx->realmname,
|
||||||
|
+ KRB5_CONF_PKINIT_REQUIRE_FRESHNESS,
|
||||||
|
+ 0, &plgctx->opts->require_freshness);
|
||||||
|
+
|
||||||
|
pkinit_kdcdefault_string(context, plgctx->realmname,
|
||||||
|
KRB5_CONF_PKINIT_EKU_CHECKING,
|
||||||
|
&eku_string);
|
||||||
|
diff --git a/src/tests/t_pkinit.py b/src/tests/t_pkinit.py
|
||||||
|
index b790a7cda..3030322e1 100755
|
||||||
|
--- a/src/tests/t_pkinit.py
|
||||||
|
+++ b/src/tests/t_pkinit.py
|
||||||
|
@@ -39,6 +39,8 @@ pkinit_kdc_conf = {'realms': {'$realm': {
|
||||||
|
'pkinit_indicator': ['indpkinit1', 'indpkinit2']}}}
|
||||||
|
restrictive_kdc_conf = {'realms': {'$realm': {
|
||||||
|
'restrict_anonymous_to_tgt': 'true' }}}
|
||||||
|
+freshness_kdc_conf = {'realms': {'$realm': {
|
||||||
|
+ 'pkinit_require_freshness': 'true'}}}
|
||||||
|
|
||||||
|
testprincs = {'krbtgt/KRBTEST.COM': {'keys': 'aes128-cts'},
|
||||||
|
'user': {'keys': 'aes128-cts', 'flags': '+preauth'},
|
||||||
|
@@ -118,6 +120,10 @@ realm.kinit(realm.user_princ, password=password('user'))
|
||||||
|
realm.klist(realm.user_princ)
|
||||||
|
realm.run([kvno, realm.host_princ])
|
||||||
|
|
||||||
|
+# Having tested password preauth, remove the keys for better error
|
||||||
|
+# reporting.
|
||||||
|
+realm.run([kadminl, 'purgekeys', '-all', realm.user_princ])
|
||||||
|
+
|
||||||
|
# Test anonymous PKINIT.
|
||||||
|
realm.kinit('@%s' % realm.realm, flags=['-n'], expected_code=1,
|
||||||
|
expected_msg='not found in Kerberos database')
|
||||||
|
@@ -153,23 +159,32 @@ realm.run([kvno, realm.host_princ], expected_code=1,
|
||||||
|
realm.kinit(realm.host_princ, flags=['-k'])
|
||||||
|
realm.run([kvno, '-U', 'user', realm.host_princ])
|
||||||
|
|
||||||
|
-# Go back to a normal KDC and disable anonymous PKINIT.
|
||||||
|
+# Go back to the normal KDC environment.
|
||||||
|
realm.stop_kdc()
|
||||||
|
realm.start_kdc()
|
||||||
|
-realm.run([kadminl, 'delprinc', 'WELLKNOWN/ANONYMOUS'])
|
||||||
|
|
||||||
|
# Run the basic test - PKINIT with FILE: identity, with no password on the key.
|
||||||
|
-realm.run(['./responder', '-x', 'pkinit=',
|
||||||
|
- '-X', 'X509_user_identity=%s' % file_identity, realm.user_princ])
|
||||||
|
realm.kinit(realm.user_princ,
|
||||||
|
- flags=['-X', 'X509_user_identity=%s' % file_identity])
|
||||||
|
+ flags=['-X', 'X509_user_identity=%s' % file_identity],
|
||||||
|
+ expected_trace=('Sending unauthenticated request',
|
||||||
|
+ '/Additional pre-authentication required',
|
||||||
|
+ 'Preauthenticating using KDC method data',
|
||||||
|
+ 'PKINIT client received freshness token from KDC',
|
||||||
|
+ 'PKINIT loading CA certs and CRLs from FILE',
|
||||||
|
+ 'PKINIT client making DH request',
|
||||||
|
+ 'Produced preauth for next request: 133, 16',
|
||||||
|
+ 'PKINIT client verified DH reply',
|
||||||
|
+ 'PKINIT client found id-pkinit-san in KDC cert',
|
||||||
|
+ 'PKINIT client matched KDC principal krbtgt/'))
|
||||||
|
realm.klist(realm.user_princ)
|
||||||
|
realm.run([kvno, realm.host_princ])
|
||||||
|
|
||||||
|
# Try again using RSA instead of DH.
|
||||||
|
realm.kinit(realm.user_princ,
|
||||||
|
flags=['-X', 'X509_user_identity=%s' % file_identity,
|
||||||
|
- '-X', 'flag_RSA_PROTOCOL=yes'])
|
||||||
|
+ '-X', 'flag_RSA_PROTOCOL=yes'],
|
||||||
|
+ expected_trace=('PKINIT client making RSA request',
|
||||||
|
+ 'PKINIT client verified RSA reply'))
|
||||||
|
realm.klist(realm.user_princ)
|
||||||
|
|
||||||
|
# Test a DH parameter renegotiation by temporarily setting a 4096-bit
|
||||||
|
@@ -192,8 +207,23 @@ expected_trace = ('Sending unauthenticated request',
|
||||||
|
realm.kinit(realm.user_princ,
|
||||||
|
flags=['-X', 'X509_user_identity=%s' % file_identity],
|
||||||
|
expected_trace=expected_trace)
|
||||||
|
+
|
||||||
|
+# Test enforcement of required freshness tokens. (We can leave
|
||||||
|
+# freshness tokens required after this test.)
|
||||||
|
+realm.kinit(realm.user_princ,
|
||||||
|
+ flags=['-X', 'X509_user_identity=%s' % file_identity,
|
||||||
|
+ '-X', 'disable_freshness=yes'])
|
||||||
|
+f_env = realm.special_env('freshness', True, kdc_conf=freshness_kdc_conf)
|
||||||
|
realm.stop_kdc()
|
||||||
|
-realm.start_kdc()
|
||||||
|
+realm.start_kdc(env=f_env)
|
||||||
|
+realm.kinit(realm.user_princ,
|
||||||
|
+ flags=['-X', 'X509_user_identity=%s' % file_identity])
|
||||||
|
+realm.kinit(realm.user_princ,
|
||||||
|
+ flags=['-X', 'X509_user_identity=%s' % file_identity,
|
||||||
|
+ '-X', 'disable_freshness=yes'],
|
||||||
|
+ expected_code=1, expected_msg='Preauthentication failed')
|
||||||
|
+# Anonymous should never require a freshness token.
|
||||||
|
+realm.kinit('@%s' % realm.realm, flags=['-n', '-X', 'disable_freshness=yes'])
|
||||||
|
|
||||||
|
# Run the basic test - PKINIT with FILE: identity, with a password on the key,
|
||||||
|
# supplied by the prompter.
|
||||||
|
@@ -229,8 +259,6 @@ shutil.copy(privkey_pem, os.path.join(path, 'user.key'))
|
||||||
|
shutil.copy(privkey_enc_pem, os.path.join(path_enc, 'user.key'))
|
||||||
|
shutil.copy(user_pem, os.path.join(path, 'user.crt'))
|
||||||
|
shutil.copy(user_pem, os.path.join(path_enc, 'user.crt'))
|
||||||
|
-realm.run(['./responder', '-x', 'pkinit=', '-X',
|
||||||
|
- 'X509_user_identity=%s' % dir_identity, realm.user_princ])
|
||||||
|
realm.kinit(realm.user_princ,
|
||||||
|
flags=['-X', 'X509_user_identity=%s' % dir_identity])
|
||||||
|
realm.klist(realm.user_princ)
|
||||||
|
@@ -262,8 +290,6 @@ realm.klist(realm.user_princ)
|
||||||
|
realm.run([kvno, realm.host_princ])
|
||||||
|
|
||||||
|
# PKINIT with PKCS12: identity, with no password on the bundle.
|
||||||
|
-realm.run(['./responder', '-x', 'pkinit=',
|
||||||
|
- '-X', 'X509_user_identity=%s' % p12_identity, realm.user_princ])
|
||||||
|
realm.kinit(realm.user_princ,
|
||||||
|
flags=['-X', 'X509_user_identity=%s' % p12_identity])
|
||||||
|
realm.klist(realm.user_princ)
|
||||||
|
@@ -350,8 +376,6 @@ conf = open(softpkcs11rc, 'w')
|
||||||
|
conf.write("%s\t%s\t%s\t%s\n" % ('user', 'user token', user_pem, privkey_pem))
|
||||||
|
conf.close()
|
||||||
|
# Expect to succeed without having to supply any more information.
|
||||||
|
-realm.run(['./responder', '-x', 'pkinit=',
|
||||||
|
- '-X', 'X509_user_identity=%s' % p11_identity, realm.user_princ])
|
||||||
|
realm.kinit(realm.user_princ,
|
||||||
|
flags=['-X', 'X509_user_identity=%s' % p11_identity])
|
||||||
|
realm.klist(realm.user_princ)
|
336
Add-PKINIT-client-support-for-freshness-token.patch
Normal file
336
Add-PKINIT-client-support-for-freshness-token.patch
Normal file
@ -0,0 +1,336 @@
|
|||||||
|
From 7eb2df66aef8e2b58ec7dfa13e9ee19f5e3b5b34 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Greg Hudson <ghudson@mit.edu>
|
||||||
|
Date: Tue, 31 Jan 2017 17:02:34 -0500
|
||||||
|
Subject: [PATCH] Add PKINIT client support for freshness token
|
||||||
|
|
||||||
|
Send an empty PA_AS_FRESHNESS padata item in unauthenticated AS
|
||||||
|
requests to indicate support for RFC 8070. If the KDC includes a
|
||||||
|
PA_AS_FRESHNESS value in its method data, echo it back in the new
|
||||||
|
freshnessToken field of pkAuthenticator
|
||||||
|
|
||||||
|
ticket: 8648
|
||||||
|
(cherry picked from commit 085785362e01467cb25c79a90dcebfba9ea019d8)
|
||||||
|
---
|
||||||
|
doc/user/user_commands/kinit.rst | 3 +++
|
||||||
|
src/include/k5-int-pkinit.h | 1 +
|
||||||
|
src/include/krb5/krb5.hin | 1 +
|
||||||
|
src/lib/krb5/asn.1/asn1_k_encode.c | 5 ++++-
|
||||||
|
src/lib/krb5/krb/get_in_tkt.c | 12 ++++++++----
|
||||||
|
src/lib/krb5/krb/init_creds_ctx.h | 2 +-
|
||||||
|
src/plugins/preauth/pkinit/pkinit.h | 3 +++
|
||||||
|
src/plugins/preauth/pkinit/pkinit_clnt.c | 19 ++++++++++++++++++-
|
||||||
|
src/plugins/preauth/pkinit/pkinit_lib.c | 3 +++
|
||||||
|
src/plugins/preauth/pkinit/pkinit_trace.h | 2 ++
|
||||||
|
src/tests/asn.1/ktest.c | 4 ++++
|
||||||
|
src/tests/asn.1/pkinit_encode.out | 2 +-
|
||||||
|
src/tests/asn.1/pkinit_trval.out | 1 +
|
||||||
|
13 files changed, 50 insertions(+), 8 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/doc/user/user_commands/kinit.rst b/doc/user/user_commands/kinit.rst
|
||||||
|
index 3f9d5340f..1f696920f 100644
|
||||||
|
--- a/doc/user/user_commands/kinit.rst
|
||||||
|
+++ b/doc/user/user_commands/kinit.rst
|
||||||
|
@@ -197,6 +197,9 @@ OPTIONS
|
||||||
|
specify use of RSA, rather than the default Diffie-Hellman
|
||||||
|
protocol
|
||||||
|
|
||||||
|
+ **disable_freshness**\ [**=yes**]
|
||||||
|
+ disable sending freshness tokens (for testing purposes only)
|
||||||
|
+
|
||||||
|
|
||||||
|
ENVIRONMENT
|
||||||
|
-----------
|
||||||
|
diff --git a/src/include/k5-int-pkinit.h b/src/include/k5-int-pkinit.h
|
||||||
|
index 7b2f595cb..4622a629e 100644
|
||||||
|
--- a/src/include/k5-int-pkinit.h
|
||||||
|
+++ b/src/include/k5-int-pkinit.h
|
||||||
|
@@ -42,6 +42,7 @@ typedef struct _krb5_pk_authenticator {
|
||||||
|
krb5_timestamp ctime;
|
||||||
|
krb5_int32 nonce; /* (0..4294967295) */
|
||||||
|
krb5_checksum paChecksum;
|
||||||
|
+ krb5_data *freshnessToken;
|
||||||
|
} krb5_pk_authenticator;
|
||||||
|
|
||||||
|
/* PKAuthenticator draft9 */
|
||||||
|
diff --git a/src/include/krb5/krb5.hin b/src/include/krb5/krb5.hin
|
||||||
|
index e81bb0a6d..833e72335 100644
|
||||||
|
--- a/src/include/krb5/krb5.hin
|
||||||
|
+++ b/src/include/krb5/krb5.hin
|
||||||
|
@@ -1879,6 +1879,7 @@ krb5_verify_checksum(krb5_context context, krb5_cksumtype ctype,
|
||||||
|
#define KRB5_PADATA_OTP_PIN_CHANGE 144 /**< RFC 6560 section 4.3 */
|
||||||
|
#define KRB5_PADATA_PKINIT_KX 147 /**< RFC 6112 */
|
||||||
|
#define KRB5_ENCPADATA_REQ_ENC_PA_REP 149 /**< RFC 6806 */
|
||||||
|
+#define KRB5_PADATA_AS_FRESHNESS 150 /**< RFC 8070 */
|
||||||
|
|
||||||
|
#define KRB5_SAM_USE_SAD_AS_KEY 0x80000000
|
||||||
|
#define KRB5_SAM_SEND_ENCRYPTED_SAD 0x40000000
|
||||||
|
diff --git a/src/lib/krb5/asn.1/asn1_k_encode.c b/src/lib/krb5/asn.1/asn1_k_encode.c
|
||||||
|
index 889460989..3b23fe34a 100644
|
||||||
|
--- a/src/lib/krb5/asn.1/asn1_k_encode.c
|
||||||
|
+++ b/src/lib/krb5/asn.1/asn1_k_encode.c
|
||||||
|
@@ -1442,9 +1442,12 @@ DEFFIELD(pk_authenticator_1, krb5_pk_authenticator, ctime, 1, kerberos_time);
|
||||||
|
DEFFIELD(pk_authenticator_2, krb5_pk_authenticator, nonce, 2, int32);
|
||||||
|
DEFFIELD(pk_authenticator_3, krb5_pk_authenticator, paChecksum, 3,
|
||||||
|
ostring_checksum);
|
||||||
|
+DEFFIELD(pk_authenticator_4, krb5_pk_authenticator, freshnessToken, 4,
|
||||||
|
+ opt_ostring_data_ptr);
|
||||||
|
static const struct atype_info *pk_authenticator_fields[] = {
|
||||||
|
&k5_atype_pk_authenticator_0, &k5_atype_pk_authenticator_1,
|
||||||
|
- &k5_atype_pk_authenticator_2, &k5_atype_pk_authenticator_3
|
||||||
|
+ &k5_atype_pk_authenticator_2, &k5_atype_pk_authenticator_3,
|
||||||
|
+ &k5_atype_pk_authenticator_4
|
||||||
|
};
|
||||||
|
DEFSEQTYPE(pk_authenticator, krb5_pk_authenticator, pk_authenticator_fields);
|
||||||
|
|
||||||
|
diff --git a/src/lib/krb5/krb/get_in_tkt.c b/src/lib/krb5/krb/get_in_tkt.c
|
||||||
|
index 47a00bf2c..1d96ff163 100644
|
||||||
|
--- a/src/lib/krb5/krb/get_in_tkt.c
|
||||||
|
+++ b/src/lib/krb5/krb/get_in_tkt.c
|
||||||
|
@@ -895,7 +895,7 @@ krb5_init_creds_init(krb5_context context,
|
||||||
|
ctx->request = k5alloc(sizeof(krb5_kdc_req), &code);
|
||||||
|
if (code != 0)
|
||||||
|
goto cleanup;
|
||||||
|
- ctx->enc_pa_rep_permitted = TRUE;
|
||||||
|
+ ctx->info_pa_permitted = TRUE;
|
||||||
|
code = krb5_copy_principal(context, client, &ctx->request->client);
|
||||||
|
if (code != 0)
|
||||||
|
goto cleanup;
|
||||||
|
@@ -1389,7 +1389,11 @@ init_creds_step_request(krb5_context context,
|
||||||
|
krb5_free_data(context, ctx->encoded_previous_request);
|
||||||
|
ctx->encoded_previous_request = NULL;
|
||||||
|
}
|
||||||
|
- if (ctx->enc_pa_rep_permitted) {
|
||||||
|
+ if (ctx->info_pa_permitted) {
|
||||||
|
+ code = add_padata(&ctx->request->padata, KRB5_PADATA_AS_FRESHNESS,
|
||||||
|
+ NULL, 0);
|
||||||
|
+ if (code)
|
||||||
|
+ goto cleanup;
|
||||||
|
code = add_padata(&ctx->request->padata, KRB5_ENCPADATA_REQ_ENC_PA_REP,
|
||||||
|
NULL, 0);
|
||||||
|
}
|
||||||
|
@@ -1530,7 +1534,7 @@ init_creds_step_reply(krb5_context context,
|
||||||
|
ctx->selected_preauth_type == KRB5_PADATA_NONE) {
|
||||||
|
/* The KDC didn't like our informational padata (probably a pre-1.7
|
||||||
|
* MIT krb5 KDC). Retry without it. */
|
||||||
|
- ctx->enc_pa_rep_permitted = FALSE;
|
||||||
|
+ ctx->info_pa_permitted = FALSE;
|
||||||
|
ctx->restarted = TRUE;
|
||||||
|
code = restart_init_creds_loop(context, ctx, FALSE);
|
||||||
|
} else if (reply_code == KDC_ERR_PREAUTH_EXPIRED) {
|
||||||
|
@@ -1574,7 +1578,7 @@ init_creds_step_reply(krb5_context context,
|
||||||
|
goto cleanup;
|
||||||
|
/* Reset per-realm negotiation state. */
|
||||||
|
ctx->restarted = FALSE;
|
||||||
|
- ctx->enc_pa_rep_permitted = TRUE;
|
||||||
|
+ ctx->info_pa_permitted = TRUE;
|
||||||
|
code = restart_init_creds_loop(context, ctx, FALSE);
|
||||||
|
} else {
|
||||||
|
if (retry && ctx->selected_preauth_type != KRB5_PADATA_NONE) {
|
||||||
|
diff --git a/src/lib/krb5/krb/init_creds_ctx.h b/src/lib/krb5/krb/init_creds_ctx.h
|
||||||
|
index fe769685b..b19410a13 100644
|
||||||
|
--- a/src/lib/krb5/krb/init_creds_ctx.h
|
||||||
|
+++ b/src/lib/krb5/krb/init_creds_ctx.h
|
||||||
|
@@ -58,7 +58,7 @@ struct _krb5_init_creds_context {
|
||||||
|
krb5_data s2kparams;
|
||||||
|
krb5_keyblock as_key;
|
||||||
|
krb5_enctype etype;
|
||||||
|
- krb5_boolean enc_pa_rep_permitted;
|
||||||
|
+ krb5_boolean info_pa_permitted;
|
||||||
|
krb5_boolean restarted;
|
||||||
|
struct krb5_responder_context_st rctx;
|
||||||
|
krb5_preauthtype selected_preauth_type;
|
||||||
|
diff --git a/src/plugins/preauth/pkinit/pkinit.h b/src/plugins/preauth/pkinit/pkinit.h
|
||||||
|
index f3de9ad7a..8489a3e23 100644
|
||||||
|
--- a/src/plugins/preauth/pkinit/pkinit.h
|
||||||
|
+++ b/src/plugins/preauth/pkinit/pkinit.h
|
||||||
|
@@ -148,6 +148,7 @@ typedef struct _pkinit_plg_opts {
|
||||||
|
int allow_upn; /* allow UPN-SAN instead of pkinit-SAN */
|
||||||
|
int dh_or_rsa; /* selects DH or RSA based pkinit */
|
||||||
|
int require_crl_checking; /* require CRL for a CA (default is false) */
|
||||||
|
+ int disable_freshness; /* disable freshness token on client for testing */
|
||||||
|
int dh_min_bits; /* minimum DH modulus size allowed */
|
||||||
|
} pkinit_plg_opts;
|
||||||
|
|
||||||
|
@@ -162,6 +163,7 @@ typedef struct _pkinit_req_opts {
|
||||||
|
int require_crl_checking;
|
||||||
|
int dh_size; /* initial request DH modulus size (default=1024) */
|
||||||
|
int require_hostname_match;
|
||||||
|
+ int disable_freshness;
|
||||||
|
} pkinit_req_opts;
|
||||||
|
|
||||||
|
/*
|
||||||
|
@@ -214,6 +216,7 @@ struct _pkinit_req_context {
|
||||||
|
int identity_initialized;
|
||||||
|
int identity_prompted;
|
||||||
|
krb5_error_code identity_prompt_retval;
|
||||||
|
+ krb5_data *freshness_token;
|
||||||
|
};
|
||||||
|
typedef struct _pkinit_req_context *pkinit_req_context;
|
||||||
|
|
||||||
|
diff --git a/src/plugins/preauth/pkinit/pkinit_clnt.c b/src/plugins/preauth/pkinit/pkinit_clnt.c
|
||||||
|
index f1bc6b21d..9483d69e5 100644
|
||||||
|
--- a/src/plugins/preauth/pkinit/pkinit_clnt.c
|
||||||
|
+++ b/src/plugins/preauth/pkinit/pkinit_clnt.c
|
||||||
|
@@ -231,6 +231,8 @@ pkinit_as_req_create(krb5_context context,
|
||||||
|
auth_pack.pkAuthenticator.cusec = cusec;
|
||||||
|
auth_pack.pkAuthenticator.nonce = nonce;
|
||||||
|
auth_pack.pkAuthenticator.paChecksum = *cksum;
|
||||||
|
+ if (!reqctx->opts->disable_freshness)
|
||||||
|
+ auth_pack.pkAuthenticator.freshnessToken = reqctx->freshness_token;
|
||||||
|
auth_pack.clientDHNonce.length = 0;
|
||||||
|
auth_pack.clientPublicValue = &info;
|
||||||
|
auth_pack.supportedKDFs = (krb5_data **)supported_kdf_alg_ids;
|
||||||
|
@@ -1162,6 +1164,7 @@ pkinit_client_process(krb5_context context, krb5_clpreauth_moddata moddata,
|
||||||
|
pkinit_context plgctx = (pkinit_context)moddata;
|
||||||
|
pkinit_req_context reqctx = (pkinit_req_context)modreq;
|
||||||
|
krb5_keyblock as_key;
|
||||||
|
+ krb5_data d;
|
||||||
|
|
||||||
|
pkiDebug("pkinit_client_process %p %p %p %p\n",
|
||||||
|
context, plgctx, reqctx, request);
|
||||||
|
@@ -1174,6 +1177,12 @@ pkinit_client_process(krb5_context context, krb5_clpreauth_moddata moddata,
|
||||||
|
case KRB5_PADATA_PKINIT_KX:
|
||||||
|
reqctx->rfc6112_kdc = 1;
|
||||||
|
return 0;
|
||||||
|
+ case KRB5_PADATA_AS_FRESHNESS:
|
||||||
|
+ TRACE_PKINIT_CLIENT_FRESHNESS_TOKEN(context);
|
||||||
|
+ krb5_free_data(context, reqctx->freshness_token);
|
||||||
|
+ reqctx->freshness_token = NULL;
|
||||||
|
+ d = make_data(in_padata->contents, in_padata->length);
|
||||||
|
+ return krb5_copy_data(context, &d, &reqctx->freshness_token);
|
||||||
|
case KRB5_PADATA_PK_AS_REQ:
|
||||||
|
reqctx->rfc4556_kdc = 1;
|
||||||
|
pkiDebug("processing KRB5_PADATA_PK_AS_REQ\n");
|
||||||
|
@@ -1359,7 +1368,7 @@ cleanup:
|
||||||
|
static int
|
||||||
|
pkinit_client_get_flags(krb5_context kcontext, krb5_preauthtype patype)
|
||||||
|
{
|
||||||
|
- if (patype == KRB5_PADATA_PKINIT_KX)
|
||||||
|
+ if (patype == KRB5_PADATA_PKINIT_KX || patype == KRB5_PADATA_AS_FRESHNESS)
|
||||||
|
return PA_INFO;
|
||||||
|
return PA_REAL;
|
||||||
|
}
|
||||||
|
@@ -1376,6 +1385,7 @@ static krb5_preauthtype supported_client_pa_types[] = {
|
||||||
|
KRB5_PADATA_PK_AS_REP_OLD,
|
||||||
|
KRB5_PADATA_PK_AS_REQ_OLD,
|
||||||
|
KRB5_PADATA_PKINIT_KX,
|
||||||
|
+ KRB5_PADATA_AS_FRESHNESS,
|
||||||
|
0
|
||||||
|
};
|
||||||
|
|
||||||
|
@@ -1400,6 +1410,7 @@ pkinit_client_req_init(krb5_context context,
|
||||||
|
reqctx->opts = NULL;
|
||||||
|
reqctx->idctx = NULL;
|
||||||
|
reqctx->idopts = NULL;
|
||||||
|
+ reqctx->freshness_token = NULL;
|
||||||
|
|
||||||
|
retval = pkinit_init_req_opts(&reqctx->opts);
|
||||||
|
if (retval)
|
||||||
|
@@ -1410,6 +1421,7 @@ pkinit_client_req_init(krb5_context context,
|
||||||
|
reqctx->opts->dh_or_rsa = plgctx->opts->dh_or_rsa;
|
||||||
|
reqctx->opts->allow_upn = plgctx->opts->allow_upn;
|
||||||
|
reqctx->opts->require_crl_checking = plgctx->opts->require_crl_checking;
|
||||||
|
+ reqctx->opts->disable_freshness = plgctx->opts->disable_freshness;
|
||||||
|
|
||||||
|
retval = pkinit_init_req_crypto(&reqctx->cryptoctx);
|
||||||
|
if (retval)
|
||||||
|
@@ -1468,6 +1480,8 @@ pkinit_client_req_fini(krb5_context context, krb5_clpreauth_moddata moddata,
|
||||||
|
if (reqctx->idopts != NULL)
|
||||||
|
pkinit_fini_identity_opts(reqctx->idopts);
|
||||||
|
|
||||||
|
+ krb5_free_data(context, reqctx->freshness_token);
|
||||||
|
+
|
||||||
|
free(reqctx);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
@@ -1580,6 +1594,9 @@ handle_gic_opt(krb5_context context,
|
||||||
|
pkiDebug("Setting flag to use RSA_PROTOCOL\n");
|
||||||
|
plgctx->opts->dh_or_rsa = RSA_PROTOCOL;
|
||||||
|
}
|
||||||
|
+ } else if (strcmp(attr, "disable_freshness") == 0) {
|
||||||
|
+ if (strcmp(value, "yes") == 0)
|
||||||
|
+ plgctx->opts->disable_freshness = 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
diff --git a/src/plugins/preauth/pkinit/pkinit_lib.c b/src/plugins/preauth/pkinit/pkinit_lib.c
|
||||||
|
index 2f88545da..d5858c424 100644
|
||||||
|
--- a/src/plugins/preauth/pkinit/pkinit_lib.c
|
||||||
|
+++ b/src/plugins/preauth/pkinit/pkinit_lib.c
|
||||||
|
@@ -82,6 +82,8 @@ pkinit_init_plg_opts(pkinit_plg_opts **plgopts)
|
||||||
|
opts->dh_or_rsa = DH_PROTOCOL;
|
||||||
|
opts->allow_upn = 0;
|
||||||
|
opts->require_crl_checking = 0;
|
||||||
|
+ opts->require_freshness = 0;
|
||||||
|
+ opts->disable_freshness = 0;
|
||||||
|
|
||||||
|
opts->dh_min_bits = PKINIT_DEFAULT_DH_MIN_BITS;
|
||||||
|
|
||||||
|
@@ -145,6 +147,7 @@ free_krb5_auth_pack(krb5_auth_pack **in)
|
||||||
|
free((*in)->clientPublicValue);
|
||||||
|
}
|
||||||
|
free((*in)->pkAuthenticator.paChecksum.contents);
|
||||||
|
+ krb5_free_data(NULL, (*in)->pkAuthenticator.freshnessToken);
|
||||||
|
if ((*in)->supportedCMSTypes != NULL)
|
||||||
|
free_krb5_algorithm_identifiers(&((*in)->supportedCMSTypes));
|
||||||
|
if ((*in)->supportedKDFs) {
|
||||||
|
diff --git a/src/plugins/preauth/pkinit/pkinit_trace.h b/src/plugins/preauth/pkinit/pkinit_trace.h
|
||||||
|
index d4eb39d88..67e0caeb4 100644
|
||||||
|
--- a/src/plugins/preauth/pkinit/pkinit_trace.h
|
||||||
|
+++ b/src/plugins/preauth/pkinit/pkinit_trace.h
|
||||||
|
@@ -41,6 +41,8 @@
|
||||||
|
TRACE(c, "PKINIT client found no acceptable EKU in KDC cert")
|
||||||
|
#define TRACE_PKINIT_CLIENT_EKU_SKIP(c) \
|
||||||
|
TRACE(c, "PKINIT client skipping EKU check due to configuration")
|
||||||
|
+#define TRACE_PKINIT_CLIENT_FRESHNESS_TOKEN(c) \
|
||||||
|
+ TRACE(c, "PKINIT client received freshness token from KDC")
|
||||||
|
#define TRACE_PKINIT_CLIENT_KDF_ALG(c, kdf, keyblock) \
|
||||||
|
TRACE(c, "PKINIT client used KDF {hexdata} to compute reply key " \
|
||||||
|
"{keyblock}", kdf, keyblock)
|
||||||
|
diff --git a/src/tests/asn.1/ktest.c b/src/tests/asn.1/ktest.c
|
||||||
|
index 43084cbbd..cf63f3f66 100644
|
||||||
|
--- a/src/tests/asn.1/ktest.c
|
||||||
|
+++ b/src/tests/asn.1/ktest.c
|
||||||
|
@@ -725,6 +725,8 @@ ktest_make_sample_pk_authenticator(krb5_pk_authenticator *p)
|
||||||
|
ktest_make_sample_checksum(&p->paChecksum);
|
||||||
|
/* We don't encode the checksum type, only the contents. */
|
||||||
|
p->paChecksum.checksum_type = 0;
|
||||||
|
+ p->freshnessToken = ealloc(sizeof(krb5_data));
|
||||||
|
+ ktest_make_sample_data(p->freshnessToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
@@ -1651,6 +1653,8 @@ ktest_empty_pk_authenticator(krb5_pk_authenticator *p)
|
||||||
|
{
|
||||||
|
ktest_empty_checksum(&p->paChecksum);
|
||||||
|
p->paChecksum.contents = NULL;
|
||||||
|
+ krb5_free_data(NULL, p->freshnessToken);
|
||||||
|
+ p->freshnessToken = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
diff --git a/src/tests/asn.1/pkinit_encode.out b/src/tests/asn.1/pkinit_encode.out
|
||||||
|
index 463128de0..3b0f7190a 100644
|
||||||
|
--- a/src/tests/asn.1/pkinit_encode.out
|
||||||
|
+++ b/src/tests/asn.1/pkinit_encode.out
|
||||||
|
@@ -4,7 +4,7 @@ encode_krb5_pa_pk_as_rep(dhInfo): A0 28 30 26 80 08 6B 72 62 35 64 61 74 61 A1 0
|
||||||
|
encode_krb5_pa_pk_as_rep(encKeyPack): 81 08 6B 72 62 35 64 61 74 61
|
||||||
|
encode_krb5_pa_pk_as_rep_draft9(dhSignedData): 80 08 6B 72 62 35 64 61 74 61
|
||||||
|
encode_krb5_pa_pk_as_rep_draft9(encKeyPack): 81 08 6B 72 62 35 64 61 74 61
|
||||||
|
-encode_krb5_auth_pack: 30 81 93 A0 29 30 27 A0 05 02 03 01 E2 40 A1 11 18 0F 31 39 39 34 30 36 31 30 30 36 30 33 31 37 5A A2 03 02 01 2A A3 06 04 04 31 32 33 34 A1 22 30 20 30 13 06 09 2A 86 48 86 F7 12 01 02 02 04 06 70 61 72 61 6D 73 03 09 00 6B 72 62 35 64 61 74 61 A2 24 30 22 30 13 06 09 2A 86 48 86 F7 12 01 02 02 04 06 70 61 72 61 6D 73 30 0B 06 09 2A 86 48 86 F7 12 01 02 02 A3 0A 04 08 6B 72 62 35 64 61 74 61 A4 10 30 0E 30 0C A0 0A 06 08 6B 72 62 35 64 61 74 61
|
||||||
|
+encode_krb5_auth_pack: 30 81 9F A0 35 30 33 A0 05 02 03 01 E2 40 A1 11 18 0F 31 39 39 34 30 36 31 30 30 36 30 33 31 37 5A A2 03 02 01 2A A3 06 04 04 31 32 33 34 A4 0A 04 08 6B 72 62 35 64 61 74 61 A1 22 30 20 30 13 06 09 2A 86 48 86 F7 12 01 02 02 04 06 70 61 72 61 6D 73 03 09 00 6B 72 62 35 64 61 74 61 A2 24 30 22 30 13 06 09 2A 86 48 86 F7 12 01 02 02 04 06 70 61 72 61 6D 73 30 0B 06 09 2A 86 48 86 F7 12 01 02 02 A3 0A 04 08 6B 72 62 35 64 61 74 61 A4 10 30 0E 30 0C A0 0A 06 08 6B 72 62 35 64 61 74 61
|
||||||
|
encode_krb5_auth_pack_draft9: 30 75 A0 4F 30 4D A0 1A 30 18 A0 03 02 01 01 A1 11 30 0F 1B 06 68 66 74 73 61 69 1B 05 65 78 74 72 61 A1 10 1B 0E 41 54 48 45 4E 41 2E 4D 49 54 2E 45 44 55 A2 05 02 03 01 E2 40 A3 11 18 0F 31 39 39 34 30 36 31 30 30 36 30 33 31 37 5A A4 03 02 01 2A A1 22 30 20 30 13 06 09 2A 86 48 86 F7 12 01 02 02 04 06 70 61 72 61 6D 73 03 09 00 6B 72 62 35 64 61 74 61
|
||||||
|
encode_krb5_kdc_dh_key_info: 30 25 A0 0B 03 09 00 6B 72 62 35 64 61 74 61 A1 03 02 01 2A A2 11 18 0F 31 39 39 34 30 36 31 30 30 36 30 33 31 37 5A
|
||||||
|
encode_krb5_reply_key_pack: 30 26 A0 13 30 11 A0 03 02 01 01 A1 0A 04 08 31 32 33 34 35 36 37 38 A1 0F 30 0D A0 03 02 01 01 A1 06 04 04 31 32 33 34
|
||||||
|
diff --git a/src/tests/asn.1/pkinit_trval.out b/src/tests/asn.1/pkinit_trval.out
|
||||||
|
index 58d870631..f9edbe154 100644
|
||||||
|
--- a/src/tests/asn.1/pkinit_trval.out
|
||||||
|
+++ b/src/tests/asn.1/pkinit_trval.out
|
||||||
|
@@ -57,6 +57,7 @@ encode_krb5_auth_pack:
|
||||||
|
. . [1] [Generalized Time] "19940610060317Z"
|
||||||
|
. . [2] [Integer] 42
|
||||||
|
. . [3] [Octet String] "1234"
|
||||||
|
+. . [4] [Octet String] "krb5data"
|
||||||
|
. [1] [Sequence/Sequence Of]
|
||||||
|
. . [Sequence/Sequence Of]
|
||||||
|
. . . [Object Identifier] <9>
|
43
Fix-securid_sam2-preauth-for-non-default-salt.patch
Normal file
43
Fix-securid_sam2-preauth-for-non-default-salt.patch
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
From afe1c26d08f0aead0d4ac49ad06715b1e8be7b6d Mon Sep 17 00:00:00 2001
|
||||||
|
From: Greg Hudson <ghudson@mit.edu>
|
||||||
|
Date: Wed, 3 Jan 2018 12:06:08 -0500
|
||||||
|
Subject: [PATCH] Fix securid_sam2 preauth for non-default salt
|
||||||
|
|
||||||
|
When looking up the client long-term key, look for any salt type, not
|
||||||
|
just the default salt type.
|
||||||
|
|
||||||
|
ticket: 8629
|
||||||
|
(cherry picked from commit a2339099ad13c84de0843fd04d0ba612fc194a1e)
|
||||||
|
---
|
||||||
|
src/plugins/preauth/securid_sam2/grail.c | 3 +--
|
||||||
|
src/plugins/preauth/securid_sam2/securid2.c | 3 +--
|
||||||
|
2 files changed, 2 insertions(+), 4 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/src/plugins/preauth/securid_sam2/grail.c b/src/plugins/preauth/securid_sam2/grail.c
|
||||||
|
index 18d48f924..48b61b0d1 100644
|
||||||
|
--- a/src/plugins/preauth/securid_sam2/grail.c
|
||||||
|
+++ b/src/plugins/preauth/securid_sam2/grail.c
|
||||||
|
@@ -213,8 +213,7 @@ verify_grail_data(krb5_context context, krb5_db_entry *client,
|
||||||
|
return KRB5KDC_ERR_PREAUTH_FAILED;
|
||||||
|
|
||||||
|
ret = krb5_dbe_find_enctype(context, client,
|
||||||
|
- sr2->sam_enc_nonce_or_sad.enctype,
|
||||||
|
- KRB5_KDB_SALTTYPE_NORMAL,
|
||||||
|
+ sr2->sam_enc_nonce_or_sad.enctype, -1,
|
||||||
|
sr2->sam_enc_nonce_or_sad.kvno,
|
||||||
|
&client_key_data);
|
||||||
|
if (ret)
|
||||||
|
diff --git a/src/plugins/preauth/securid_sam2/securid2.c b/src/plugins/preauth/securid_sam2/securid2.c
|
||||||
|
index ca99ce3ef..363e17a10 100644
|
||||||
|
--- a/src/plugins/preauth/securid_sam2/securid2.c
|
||||||
|
+++ b/src/plugins/preauth/securid_sam2/securid2.c
|
||||||
|
@@ -313,8 +313,7 @@ verify_securid_data_2(krb5_context context, krb5_db_entry *client,
|
||||||
|
}
|
||||||
|
|
||||||
|
retval = krb5_dbe_find_enctype(context, client,
|
||||||
|
- sr2->sam_enc_nonce_or_sad.enctype,
|
||||||
|
- KRB5_KDB_SALTTYPE_NORMAL,
|
||||||
|
+ sr2->sam_enc_nonce_or_sad.enctype, -1,
|
||||||
|
sr2->sam_enc_nonce_or_sad.kvno,
|
||||||
|
&client_key_data);
|
||||||
|
if (retval) {
|
38
Include-etype-info-in-for-hardware-preauth-hints.patch
Normal file
38
Include-etype-info-in-for-hardware-preauth-hints.patch
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
From be4a469216fb87408484b90be9a1da772ba923df Mon Sep 17 00:00:00 2001
|
||||||
|
From: Greg Hudson <ghudson@mit.edu>
|
||||||
|
Date: Wed, 3 Jan 2018 11:59:14 -0500
|
||||||
|
Subject: [PATCH] Include etype-info in for hardware preauth hints
|
||||||
|
|
||||||
|
If a principal has the requires_hwauth bit set, include PA-ETYPE-INFO
|
||||||
|
or PA-ETYPE-INFO2 padata in the PREAUTH_REQUIRED error, as preauth
|
||||||
|
mechs involving hardware tokens may also use the principal's Kerberos
|
||||||
|
password.
|
||||||
|
|
||||||
|
ticket: 8629
|
||||||
|
(cherry picked from commit ba92da05accc524b8037453b63ced1a6c65fd2a1)
|
||||||
|
---
|
||||||
|
src/kdc/kdc_preauth.c | 4 ++--
|
||||||
|
1 file changed, 2 insertions(+), 2 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/src/kdc/kdc_preauth.c b/src/kdc/kdc_preauth.c
|
||||||
|
index 81d0b8cff..739c5e776 100644
|
||||||
|
--- a/src/kdc/kdc_preauth.c
|
||||||
|
+++ b/src/kdc/kdc_preauth.c
|
||||||
|
@@ -144,7 +144,7 @@ static preauth_system static_preauth_systems[] = {
|
||||||
|
{
|
||||||
|
"etype-info",
|
||||||
|
KRB5_PADATA_ETYPE_INFO,
|
||||||
|
- 0,
|
||||||
|
+ PA_HARDWARE,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
@@ -155,7 +155,7 @@ static preauth_system static_preauth_systems[] = {
|
||||||
|
{
|
||||||
|
"etype-info2",
|
||||||
|
KRB5_PADATA_ETYPE_INFO2,
|
||||||
|
- 0,
|
||||||
|
+ PA_HARDWARE,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
393
Refactor-KDC-krb5_pa_data-utility-functions.patch
Normal file
393
Refactor-KDC-krb5_pa_data-utility-functions.patch
Normal file
@ -0,0 +1,393 @@
|
|||||||
|
From 61e3f0142b09cb230be3a2a110f5224e773f1281 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Greg Hudson <ghudson@mit.edu>
|
||||||
|
Date: Thu, 21 Dec 2017 11:28:52 -0500
|
||||||
|
Subject: [PATCH] Refactor KDC krb5_pa_data utility functions
|
||||||
|
|
||||||
|
Move alloc_padata from fast_util.c to kdc_util.c and make it
|
||||||
|
non-static so it can be used by other files. Rename it to
|
||||||
|
alloc_pa_data for consistency with add_pa_data_element. Make it
|
||||||
|
correctly handle zero length using a null contents pointer.
|
||||||
|
|
||||||
|
Make add_pa_data_element claim both the container and contents memory
|
||||||
|
from the caller, now that callers can use alloc_pa_data to simplify
|
||||||
|
allocation and copying. Remove the copy parameter and the unused
|
||||||
|
context parameter, and put the list parameter first. Adjust all
|
||||||
|
callers accordingly, making small simplifications to memory handling
|
||||||
|
where applicable.
|
||||||
|
|
||||||
|
(cherry picked from commit 4af478c18b02e1d2444a328bb79e6976ef3d312b)
|
||||||
|
---
|
||||||
|
src/kdc/fast_util.c | 28 +-------
|
||||||
|
src/kdc/kdc_preauth.c | 14 ++--
|
||||||
|
src/kdc/kdc_util.c | 187 +++++++++++++++++++++++++-------------------------
|
||||||
|
src/kdc/kdc_util.h | 8 +--
|
||||||
|
4 files changed, 109 insertions(+), 128 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/src/kdc/fast_util.c b/src/kdc/fast_util.c
|
||||||
|
index e05107ef3..6a3fc11b9 100644
|
||||||
|
--- a/src/kdc/fast_util.c
|
||||||
|
+++ b/src/kdc/fast_util.c
|
||||||
|
@@ -451,36 +451,12 @@ kdc_fast_hide_client(struct kdc_request_state *state)
|
||||||
|
return (state->fast_options & KRB5_FAST_OPTION_HIDE_CLIENT_NAMES) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
-/* Allocate a pa-data entry with an uninitialized buffer of size len. */
|
||||||
|
-static krb5_error_code
|
||||||
|
-alloc_padata(krb5_preauthtype pa_type, size_t len, krb5_pa_data **out)
|
||||||
|
-{
|
||||||
|
- krb5_pa_data *pa;
|
||||||
|
- uint8_t *buf;
|
||||||
|
-
|
||||||
|
- *out = NULL;
|
||||||
|
- buf = malloc(len);
|
||||||
|
- if (buf == NULL)
|
||||||
|
- return ENOMEM;
|
||||||
|
- pa = malloc(sizeof(*pa));
|
||||||
|
- if (pa == NULL) {
|
||||||
|
- free(buf);
|
||||||
|
- return ENOMEM;
|
||||||
|
- }
|
||||||
|
- pa->magic = KV5M_PA_DATA;
|
||||||
|
- pa->pa_type = pa_type;
|
||||||
|
- pa->length = len;
|
||||||
|
- pa->contents = buf;
|
||||||
|
- *out = pa;
|
||||||
|
- return 0;
|
||||||
|
-}
|
||||||
|
-
|
||||||
|
/* Create a pa-data entry with the specified type and contents. */
|
||||||
|
static krb5_error_code
|
||||||
|
make_padata(krb5_preauthtype pa_type, const void *contents, size_t len,
|
||||||
|
krb5_pa_data **out)
|
||||||
|
{
|
||||||
|
- if (alloc_padata(pa_type, len, out) != 0)
|
||||||
|
+ if (alloc_pa_data(pa_type, len, out) != 0)
|
||||||
|
return ENOMEM;
|
||||||
|
memcpy((*out)->contents, contents, len);
|
||||||
|
return 0;
|
||||||
|
@@ -720,7 +696,7 @@ kdc_fast_make_cookie(krb5_context context, struct kdc_request_state *state,
|
||||||
|
goto cleanup;
|
||||||
|
|
||||||
|
/* Construct the cookie pa-data entry. */
|
||||||
|
- ret = alloc_padata(KRB5_PADATA_FX_COOKIE, 8 + enc.ciphertext.length, &pa);
|
||||||
|
+ ret = alloc_pa_data(KRB5_PADATA_FX_COOKIE, 8 + enc.ciphertext.length, &pa);
|
||||||
|
memcpy(pa->contents, "MIT1", 4);
|
||||||
|
store_32_be(kvno, pa->contents + 4);
|
||||||
|
memcpy(pa->contents + 8, enc.ciphertext.data, enc.ciphertext.length);
|
||||||
|
diff --git a/src/kdc/kdc_preauth.c b/src/kdc/kdc_preauth.c
|
||||||
|
index 739c5e776..edc30bd83 100644
|
||||||
|
--- a/src/kdc/kdc_preauth.c
|
||||||
|
+++ b/src/kdc/kdc_preauth.c
|
||||||
|
@@ -1617,18 +1617,20 @@ return_referral_enc_padata( krb5_context context,
|
||||||
|
{
|
||||||
|
krb5_error_code code;
|
||||||
|
krb5_tl_data tl_data;
|
||||||
|
- krb5_pa_data pa_data;
|
||||||
|
+ krb5_pa_data *pa;
|
||||||
|
|
||||||
|
tl_data.tl_data_type = KRB5_TL_SVR_REFERRAL_DATA;
|
||||||
|
code = krb5_dbe_lookup_tl_data(context, server, &tl_data);
|
||||||
|
if (code || tl_data.tl_data_length == 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
- pa_data.magic = KV5M_PA_DATA;
|
||||||
|
- pa_data.pa_type = KRB5_PADATA_SVR_REFERRAL_INFO;
|
||||||
|
- pa_data.length = tl_data.tl_data_length;
|
||||||
|
- pa_data.contents = tl_data.tl_data_contents;
|
||||||
|
- return add_pa_data_element(context, &pa_data, &reply->enc_padata, TRUE);
|
||||||
|
+ code = alloc_pa_data(KRB5_PADATA_SVR_REFERRAL_INFO, tl_data.tl_data_length,
|
||||||
|
+ &pa);
|
||||||
|
+ if (code)
|
||||||
|
+ return code;
|
||||||
|
+ memcpy(pa->contents, tl_data.tl_data_contents, tl_data.tl_data_length);
|
||||||
|
+ /* add_pa_data_element() claims pa on success or failure. */
|
||||||
|
+ return add_pa_data_element(&reply->enc_padata, pa);
|
||||||
|
}
|
||||||
|
|
||||||
|
krb5_error_code
|
||||||
|
diff --git a/src/kdc/kdc_util.c b/src/kdc/kdc_util.c
|
||||||
|
index 754570c01..13111215d 100644
|
||||||
|
--- a/src/kdc/kdc_util.c
|
||||||
|
+++ b/src/kdc/kdc_util.c
|
||||||
|
@@ -1353,9 +1353,9 @@ kdc_make_s4u2self_rep(krb5_context context,
|
||||||
|
krb5_enc_kdc_rep_part *reply_encpart)
|
||||||
|
{
|
||||||
|
krb5_error_code code;
|
||||||
|
- krb5_data *data = NULL;
|
||||||
|
+ krb5_data *der_user_id = NULL, *der_s4u_x509_user = NULL;
|
||||||
|
krb5_pa_s4u_x509_user rep_s4u_user;
|
||||||
|
- krb5_pa_data padata;
|
||||||
|
+ krb5_pa_data *pa;
|
||||||
|
krb5_enctype enctype;
|
||||||
|
krb5_keyusage usage;
|
||||||
|
|
||||||
|
@@ -1366,7 +1366,7 @@ kdc_make_s4u2self_rep(krb5_context context,
|
||||||
|
rep_s4u_user.user_id.options =
|
||||||
|
req_s4u_user->user_id.options & KRB5_S4U_OPTS_USE_REPLY_KEY_USAGE;
|
||||||
|
|
||||||
|
- code = encode_krb5_s4u_userid(&rep_s4u_user.user_id, &data);
|
||||||
|
+ code = encode_krb5_s4u_userid(&rep_s4u_user.user_id, &der_user_id);
|
||||||
|
if (code != 0)
|
||||||
|
goto cleanup;
|
||||||
|
|
||||||
|
@@ -1377,29 +1377,25 @@ kdc_make_s4u2self_rep(krb5_context context,
|
||||||
|
|
||||||
|
code = krb5_c_make_checksum(context, req_s4u_user->cksum.checksum_type,
|
||||||
|
tgs_subkey != NULL ? tgs_subkey : tgs_session,
|
||||||
|
- usage, data,
|
||||||
|
- &rep_s4u_user.cksum);
|
||||||
|
+ usage, der_user_id, &rep_s4u_user.cksum);
|
||||||
|
if (code != 0)
|
||||||
|
goto cleanup;
|
||||||
|
|
||||||
|
- krb5_free_data(context, data);
|
||||||
|
- data = NULL;
|
||||||
|
-
|
||||||
|
- code = encode_krb5_pa_s4u_x509_user(&rep_s4u_user, &data);
|
||||||
|
+ code = encode_krb5_pa_s4u_x509_user(&rep_s4u_user, &der_s4u_x509_user);
|
||||||
|
if (code != 0)
|
||||||
|
goto cleanup;
|
||||||
|
|
||||||
|
- padata.magic = KV5M_PA_DATA;
|
||||||
|
- padata.pa_type = KRB5_PADATA_S4U_X509_USER;
|
||||||
|
- padata.length = data->length;
|
||||||
|
- padata.contents = (krb5_octet *)data->data;
|
||||||
|
-
|
||||||
|
- code = add_pa_data_element(context, &padata, &reply->padata, FALSE);
|
||||||
|
+ /* Add a padata element, stealing memory from der_s4u_x509_user. */
|
||||||
|
+ code = alloc_pa_data(KRB5_PADATA_S4U_X509_USER, 0, &pa);
|
||||||
|
+ if (code != 0)
|
||||||
|
+ goto cleanup;
|
||||||
|
+ pa->length = der_s4u_x509_user->length;
|
||||||
|
+ pa->contents = (uint8_t *)der_s4u_x509_user->data;
|
||||||
|
+ der_s4u_x509_user->data = NULL;
|
||||||
|
+ /* add_pa_data_element() claims pa on success or failure. */
|
||||||
|
+ code = add_pa_data_element(&reply->padata, pa);
|
||||||
|
if (code != 0)
|
||||||
|
goto cleanup;
|
||||||
|
-
|
||||||
|
- free(data);
|
||||||
|
- data = NULL;
|
||||||
|
|
||||||
|
if (tgs_subkey != NULL)
|
||||||
|
enctype = tgs_subkey->enctype;
|
||||||
|
@@ -1413,33 +1409,27 @@ kdc_make_s4u2self_rep(krb5_context context,
|
||||||
|
*/
|
||||||
|
if ((req_s4u_user->user_id.options & KRB5_S4U_OPTS_USE_REPLY_KEY_USAGE) &&
|
||||||
|
enctype_requires_etype_info_2(enctype) == FALSE) {
|
||||||
|
- padata.length = req_s4u_user->cksum.length +
|
||||||
|
- rep_s4u_user.cksum.length;
|
||||||
|
- padata.contents = malloc(padata.length);
|
||||||
|
- if (padata.contents == NULL) {
|
||||||
|
- code = ENOMEM;
|
||||||
|
+ code = alloc_pa_data(KRB5_PADATA_S4U_X509_USER,
|
||||||
|
+ req_s4u_user->cksum.length +
|
||||||
|
+ rep_s4u_user.cksum.length, &pa);
|
||||||
|
+ if (code != 0)
|
||||||
|
goto cleanup;
|
||||||
|
- }
|
||||||
|
+ memcpy(pa->contents,
|
||||||
|
+ req_s4u_user->cksum.contents, req_s4u_user->cksum.length);
|
||||||
|
+ memcpy(&pa->contents[req_s4u_user->cksum.length],
|
||||||
|
+ rep_s4u_user.cksum.contents, rep_s4u_user.cksum.length);
|
||||||
|
|
||||||
|
- memcpy(padata.contents,
|
||||||
|
- req_s4u_user->cksum.contents,
|
||||||
|
- req_s4u_user->cksum.length);
|
||||||
|
- memcpy(&padata.contents[req_s4u_user->cksum.length],
|
||||||
|
- rep_s4u_user.cksum.contents,
|
||||||
|
- rep_s4u_user.cksum.length);
|
||||||
|
-
|
||||||
|
- code = add_pa_data_element(context,&padata,
|
||||||
|
- &reply_encpart->enc_padata, FALSE);
|
||||||
|
- if (code != 0) {
|
||||||
|
- free(padata.contents);
|
||||||
|
+ /* add_pa_data_element() claims pa on success or failure. */
|
||||||
|
+ code = add_pa_data_element(&reply_encpart->enc_padata, pa);
|
||||||
|
+ if (code != 0)
|
||||||
|
goto cleanup;
|
||||||
|
- }
|
||||||
|
}
|
||||||
|
|
||||||
|
cleanup:
|
||||||
|
if (rep_s4u_user.cksum.contents != NULL)
|
||||||
|
krb5_free_checksum_contents(context, &rep_s4u_user.cksum);
|
||||||
|
- krb5_free_data(context, data);
|
||||||
|
+ krb5_free_data(context, der_user_id);
|
||||||
|
+ krb5_free_data(context, der_s4u_x509_user);
|
||||||
|
|
||||||
|
return code;
|
||||||
|
}
|
||||||
|
@@ -1707,46 +1697,50 @@ enctype_requires_etype_info_2(krb5_enctype enctype)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
-/* XXX where are the generic helper routines for this? */
|
||||||
|
+/* Allocate a pa-data entry with an uninitialized buffer of size len. */
|
||||||
|
krb5_error_code
|
||||||
|
-add_pa_data_element(krb5_context context,
|
||||||
|
- krb5_pa_data *padata,
|
||||||
|
- krb5_pa_data ***inout_padata,
|
||||||
|
- krb5_boolean copy)
|
||||||
|
+alloc_pa_data(krb5_preauthtype pa_type, size_t len, krb5_pa_data **out)
|
||||||
|
{
|
||||||
|
- int i;
|
||||||
|
- krb5_pa_data **p;
|
||||||
|
+ krb5_pa_data *pa;
|
||||||
|
+ uint8_t *buf = NULL;
|
||||||
|
|
||||||
|
- if (*inout_padata != NULL) {
|
||||||
|
- for (i = 0; (*inout_padata)[i] != NULL; i++)
|
||||||
|
- ;
|
||||||
|
- } else
|
||||||
|
- i = 0;
|
||||||
|
-
|
||||||
|
- p = realloc(*inout_padata, (i + 2) * sizeof(krb5_pa_data *));
|
||||||
|
- if (p == NULL)
|
||||||
|
- return ENOMEM;
|
||||||
|
-
|
||||||
|
- *inout_padata = p;
|
||||||
|
-
|
||||||
|
- p[i] = (krb5_pa_data *)malloc(sizeof(krb5_pa_data));
|
||||||
|
- if (p[i] == NULL)
|
||||||
|
- return ENOMEM;
|
||||||
|
- *(p[i]) = *padata;
|
||||||
|
-
|
||||||
|
- p[i + 1] = NULL;
|
||||||
|
-
|
||||||
|
- if (copy) {
|
||||||
|
- p[i]->contents = (krb5_octet *)malloc(padata->length);
|
||||||
|
- if (p[i]->contents == NULL) {
|
||||||
|
- free(p[i]);
|
||||||
|
- p[i] = NULL;
|
||||||
|
+ *out = NULL;
|
||||||
|
+ if (len > 0) {
|
||||||
|
+ buf = malloc(len);
|
||||||
|
+ if (buf == NULL)
|
||||||
|
return ENOMEM;
|
||||||
|
- }
|
||||||
|
-
|
||||||
|
- memcpy(p[i]->contents, padata->contents, padata->length);
|
||||||
|
}
|
||||||
|
+ pa = malloc(sizeof(*pa));
|
||||||
|
+ if (pa == NULL) {
|
||||||
|
+ free(buf);
|
||||||
|
+ return ENOMEM;
|
||||||
|
+ }
|
||||||
|
+ pa->magic = KV5M_PA_DATA;
|
||||||
|
+ pa->pa_type = pa_type;
|
||||||
|
+ pa->length = len;
|
||||||
|
+ pa->contents = buf;
|
||||||
|
+ *out = pa;
|
||||||
|
+ return 0;
|
||||||
|
+}
|
||||||
|
|
||||||
|
+/* Add pa to list, claiming its memory. Free pa on failure. */
|
||||||
|
+krb5_error_code
|
||||||
|
+add_pa_data_element(krb5_pa_data ***list, krb5_pa_data *pa)
|
||||||
|
+{
|
||||||
|
+ size_t count;
|
||||||
|
+ krb5_pa_data **newlist;
|
||||||
|
+
|
||||||
|
+ for (count = 0; *list != NULL && (*list)[count] != NULL; count++);
|
||||||
|
+
|
||||||
|
+ newlist = realloc(*list, (count + 2) * sizeof(*newlist));
|
||||||
|
+ if (newlist == NULL) {
|
||||||
|
+ free(pa->contents);
|
||||||
|
+ free(pa);
|
||||||
|
+ return ENOMEM;
|
||||||
|
+ }
|
||||||
|
+ newlist[count] = pa;
|
||||||
|
+ newlist[count + 1] = NULL;
|
||||||
|
+ *list = newlist;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -1850,38 +1844,47 @@ kdc_handle_protected_negotiation(krb5_context context,
|
||||||
|
{
|
||||||
|
krb5_error_code retval = 0;
|
||||||
|
krb5_checksum checksum;
|
||||||
|
- krb5_data *out = NULL;
|
||||||
|
- krb5_pa_data pa, *pa_in;
|
||||||
|
+ krb5_data *der_cksum = NULL;
|
||||||
|
+ krb5_pa_data *pa, *pa_in;
|
||||||
|
+
|
||||||
|
+ memset(&checksum, 0, sizeof(checksum));
|
||||||
|
+
|
||||||
|
pa_in = krb5int_find_pa_data(context, request->padata,
|
||||||
|
KRB5_ENCPADATA_REQ_ENC_PA_REP);
|
||||||
|
if (pa_in == NULL)
|
||||||
|
return 0;
|
||||||
|
- pa.magic = KV5M_PA_DATA;
|
||||||
|
- pa.pa_type = KRB5_ENCPADATA_REQ_ENC_PA_REP;
|
||||||
|
- memset(&checksum, 0, sizeof(checksum));
|
||||||
|
- retval = krb5_c_make_checksum(context,0, reply_key,
|
||||||
|
- KRB5_KEYUSAGE_AS_REQ, req_pkt, &checksum);
|
||||||
|
+
|
||||||
|
+ /* Compute and encode a checksum over the AS-REQ. */
|
||||||
|
+ retval = krb5_c_make_checksum(context, 0, reply_key, KRB5_KEYUSAGE_AS_REQ,
|
||||||
|
+ req_pkt, &checksum);
|
||||||
|
if (retval != 0)
|
||||||
|
goto cleanup;
|
||||||
|
- retval = encode_krb5_checksum(&checksum, &out);
|
||||||
|
+ retval = encode_krb5_checksum(&checksum, &der_cksum);
|
||||||
|
if (retval != 0)
|
||||||
|
goto cleanup;
|
||||||
|
- pa.contents = (krb5_octet *) out->data;
|
||||||
|
- pa.length = out->length;
|
||||||
|
- retval = add_pa_data_element(context, &pa, out_enc_padata, FALSE);
|
||||||
|
+
|
||||||
|
+ /* Add a pa-data element to the list, stealing memory from der_cksum. */
|
||||||
|
+ retval = alloc_pa_data(KRB5_ENCPADATA_REQ_ENC_PA_REP, 0, &pa);
|
||||||
|
if (retval)
|
||||||
|
goto cleanup;
|
||||||
|
- out->data = NULL;
|
||||||
|
- pa.magic = KV5M_PA_DATA;
|
||||||
|
- pa.pa_type = KRB5_PADATA_FX_FAST;
|
||||||
|
- pa.length = 0;
|
||||||
|
- pa.contents = NULL;
|
||||||
|
- retval = add_pa_data_element(context, &pa, out_enc_padata, FALSE);
|
||||||
|
+ pa->length = der_cksum->length;
|
||||||
|
+ pa->contents = (uint8_t *)der_cksum->data;
|
||||||
|
+ der_cksum->data = NULL;
|
||||||
|
+ /* add_pa_data_element() claims pa on success or failure. */
|
||||||
|
+ retval = add_pa_data_element(out_enc_padata, pa);
|
||||||
|
+ if (retval)
|
||||||
|
+ goto cleanup;
|
||||||
|
+
|
||||||
|
+ /* Add a zero-length PA-FX-FAST element to the list. */
|
||||||
|
+ retval = alloc_pa_data(KRB5_PADATA_FX_FAST, 0, &pa);
|
||||||
|
+ if (retval)
|
||||||
|
+ goto cleanup;
|
||||||
|
+ /* add_pa_data_element() claims pa on success or failure. */
|
||||||
|
+ retval = add_pa_data_element(out_enc_padata, pa);
|
||||||
|
+
|
||||||
|
cleanup:
|
||||||
|
- if (checksum.contents)
|
||||||
|
- krb5_free_checksum_contents(context, &checksum);
|
||||||
|
- if (out != NULL)
|
||||||
|
- krb5_free_data(context, out);
|
||||||
|
+ krb5_free_checksum_contents(context, &checksum);
|
||||||
|
+ krb5_free_data(context, der_cksum);
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
diff --git a/src/kdc/kdc_util.h b/src/kdc/kdc_util.h
|
||||||
|
index f99efcf50..18649b8ad 100644
|
||||||
|
--- a/src/kdc/kdc_util.h
|
||||||
|
+++ b/src/kdc/kdc_util.h
|
||||||
|
@@ -203,10 +203,10 @@ void
|
||||||
|
free_padata_context(krb5_context context, void *padata_context);
|
||||||
|
|
||||||
|
krb5_error_code
|
||||||
|
-add_pa_data_element (krb5_context context,
|
||||||
|
- krb5_pa_data *padata,
|
||||||
|
- krb5_pa_data ***out_padata,
|
||||||
|
- krb5_boolean copy);
|
||||||
|
+alloc_pa_data(krb5_preauthtype pa_type, size_t len, krb5_pa_data **out);
|
||||||
|
+
|
||||||
|
+krb5_error_code
|
||||||
|
+add_pa_data_element(krb5_pa_data ***list, krb5_pa_data *pa);
|
||||||
|
|
||||||
|
/* kdc_preauth_ec.c */
|
||||||
|
krb5_error_code
|
738
Simplify-kdc_preauth.c-systems-table.patch
Normal file
738
Simplify-kdc_preauth.c-systems-table.patch
Normal file
@ -0,0 +1,738 @@
|
|||||||
|
From 0afb9c336dd8573faa025915fcb97e643cc3e748 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Greg Hudson <ghudson@mit.edu>
|
||||||
|
Date: Sun, 11 Feb 2018 15:23:35 -0500
|
||||||
|
Subject: [PATCH] Simplify kdc_preauth.c systems table
|
||||||
|
|
||||||
|
Get rid of static_preauth_systems, and replace it with explicit calls
|
||||||
|
to helper functions in get_preauth_hint_list() and return_padata().
|
||||||
|
Stop preallocating pa-data lists, instead reallocating on each
|
||||||
|
addition using add_pa_data_element(). Also simplify
|
||||||
|
maybe_add_etype_info2() using add_pa_data_element().
|
||||||
|
|
||||||
|
The KRB5_PADATA_PAC_REQUEST table entry did nothing, and was probably
|
||||||
|
originally added back when the KDC would error out on unrecognized
|
||||||
|
padata types. The KRB5_PADATA_SERVER_REFERRAL entry has been disabled
|
||||||
|
since it was first added.
|
||||||
|
|
||||||
|
(cherry picked from commit fea1a488924faa3938ef723feaa1ff12d22a91ff)
|
||||||
|
---
|
||||||
|
src/kdc/kdc_preauth.c | 526 ++++++++++++++++++--------------------------------
|
||||||
|
1 file changed, 184 insertions(+), 342 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/src/kdc/kdc_preauth.c b/src/kdc/kdc_preauth.c
|
||||||
|
index edc30bd83..6f34dc289 100644
|
||||||
|
--- a/src/kdc/kdc_preauth.c
|
||||||
|
+++ b/src/kdc/kdc_preauth.c
|
||||||
|
@@ -101,108 +101,14 @@ typedef struct preauth_system_st {
|
||||||
|
krb5_kdcpreauth_loop_fn loop;
|
||||||
|
} preauth_system;
|
||||||
|
|
||||||
|
+static preauth_system *preauth_systems;
|
||||||
|
+static size_t n_preauth_systems;
|
||||||
|
+
|
||||||
|
static krb5_error_code
|
||||||
|
make_etype_info(krb5_context context, krb5_preauthtype pa_type,
|
||||||
|
krb5_principal client, krb5_key_data *client_key,
|
||||||
|
krb5_enctype enctype, krb5_pa_data **pa_out);
|
||||||
|
|
||||||
|
-static void
|
||||||
|
-get_etype_info(krb5_context context, krb5_kdc_req *request,
|
||||||
|
- krb5_kdcpreauth_callbacks cb, krb5_kdcpreauth_rock rock,
|
||||||
|
- krb5_kdcpreauth_moddata moddata, krb5_preauthtype pa_type,
|
||||||
|
- krb5_kdcpreauth_edata_respond_fn respond, void *arg);
|
||||||
|
-
|
||||||
|
-static krb5_error_code
|
||||||
|
-return_etype_info(krb5_context, krb5_pa_data *padata,
|
||||||
|
- krb5_data *req_pkt, krb5_kdc_req *request,
|
||||||
|
- krb5_kdc_rep *reply, krb5_keyblock *encrypting_key,
|
||||||
|
- krb5_pa_data **send_pa, krb5_kdcpreauth_callbacks cb,
|
||||||
|
- krb5_kdcpreauth_rock rock, krb5_kdcpreauth_moddata moddata,
|
||||||
|
- krb5_kdcpreauth_modreq modreq);
|
||||||
|
-
|
||||||
|
-static krb5_error_code
|
||||||
|
-return_pw_salt(krb5_context, krb5_pa_data *padata,
|
||||||
|
- krb5_data *req_pkt, krb5_kdc_req *request, krb5_kdc_rep *reply,
|
||||||
|
- krb5_keyblock *encrypting_key, krb5_pa_data **send_pa,
|
||||||
|
- krb5_kdcpreauth_callbacks cb, krb5_kdcpreauth_rock rock,
|
||||||
|
- krb5_kdcpreauth_moddata moddata, krb5_kdcpreauth_modreq modreq);
|
||||||
|
-
|
||||||
|
-
|
||||||
|
-
|
||||||
|
-static preauth_system static_preauth_systems[] = {
|
||||||
|
- {
|
||||||
|
- "FAST",
|
||||||
|
- KRB5_PADATA_FX_FAST,
|
||||||
|
- PA_HARDWARE,
|
||||||
|
- NULL,
|
||||||
|
- NULL,
|
||||||
|
- NULL,
|
||||||
|
- NULL,
|
||||||
|
- NULL,
|
||||||
|
- 0
|
||||||
|
- },
|
||||||
|
- {
|
||||||
|
- "etype-info",
|
||||||
|
- KRB5_PADATA_ETYPE_INFO,
|
||||||
|
- PA_HARDWARE,
|
||||||
|
- NULL,
|
||||||
|
- NULL,
|
||||||
|
- NULL,
|
||||||
|
- get_etype_info,
|
||||||
|
- 0,
|
||||||
|
- return_etype_info
|
||||||
|
- },
|
||||||
|
- {
|
||||||
|
- "etype-info2",
|
||||||
|
- KRB5_PADATA_ETYPE_INFO2,
|
||||||
|
- PA_HARDWARE,
|
||||||
|
- NULL,
|
||||||
|
- NULL,
|
||||||
|
- NULL,
|
||||||
|
- get_etype_info,
|
||||||
|
- 0,
|
||||||
|
- return_etype_info
|
||||||
|
- },
|
||||||
|
- {
|
||||||
|
- "pw-salt",
|
||||||
|
- KRB5_PADATA_PW_SALT,
|
||||||
|
- PA_PSEUDO, /* Don't include this in the error list */
|
||||||
|
- NULL,
|
||||||
|
- NULL,
|
||||||
|
- NULL,
|
||||||
|
- 0,
|
||||||
|
- 0,
|
||||||
|
- return_pw_salt
|
||||||
|
- },
|
||||||
|
- {
|
||||||
|
- "pac-request",
|
||||||
|
- KRB5_PADATA_PAC_REQUEST,
|
||||||
|
- PA_PSEUDO,
|
||||||
|
- NULL,
|
||||||
|
- NULL,
|
||||||
|
- NULL,
|
||||||
|
- NULL,
|
||||||
|
- NULL,
|
||||||
|
- NULL
|
||||||
|
- },
|
||||||
|
-#if 0
|
||||||
|
- {
|
||||||
|
- "server-referral",
|
||||||
|
- KRB5_PADATA_SERVER_REFERRAL,
|
||||||
|
- PA_PSEUDO,
|
||||||
|
- 0,
|
||||||
|
- 0,
|
||||||
|
- return_server_referral
|
||||||
|
- },
|
||||||
|
-#endif
|
||||||
|
-};
|
||||||
|
-
|
||||||
|
-#define NUM_STATIC_PREAUTH_SYSTEMS (sizeof(static_preauth_systems) / \
|
||||||
|
- sizeof(*static_preauth_systems))
|
||||||
|
-
|
||||||
|
-static preauth_system *preauth_systems;
|
||||||
|
-static size_t n_preauth_systems;
|
||||||
|
-
|
||||||
|
/* Get all available kdcpreauth vtables and a count of preauth types they
|
||||||
|
* support. Return an empty list on failure. */
|
||||||
|
static void
|
||||||
|
@@ -284,7 +190,6 @@ load_preauth_plugins(struct server_handle *handle, krb5_context context,
|
||||||
|
get_plugin_vtables(context, &vtables, &n_tables, &n_systems);
|
||||||
|
|
||||||
|
/* Allocate the list of static and plugin preauth systems. */
|
||||||
|
- n_systems += NUM_STATIC_PREAUTH_SYSTEMS;
|
||||||
|
preauth_systems = calloc(n_systems + 1, sizeof(preauth_system));
|
||||||
|
if (preauth_systems == NULL)
|
||||||
|
goto cleanup;
|
||||||
|
@@ -292,13 +197,8 @@ load_preauth_plugins(struct server_handle *handle, krb5_context context,
|
||||||
|
if (get_realm_names(handle, &realm_names))
|
||||||
|
goto cleanup;
|
||||||
|
|
||||||
|
- /* Add the static system to the list first. No static systems require
|
||||||
|
- * initialization, so just make a direct copy. */
|
||||||
|
- memcpy(preauth_systems, static_preauth_systems,
|
||||||
|
- sizeof(static_preauth_systems));
|
||||||
|
-
|
||||||
|
/* Add the dynamically-loaded mechanisms to the list. */
|
||||||
|
- n_systems = NUM_STATIC_PREAUTH_SYSTEMS;
|
||||||
|
+ n_systems = 0;
|
||||||
|
for (i = 0; i < n_tables; i++) {
|
||||||
|
/* Try to initialize this module. */
|
||||||
|
vt = &vtables[i];
|
||||||
|
@@ -622,7 +522,9 @@ find_pa_system(int type, preauth_system **preauth)
|
||||||
|
{
|
||||||
|
preauth_system *ap;
|
||||||
|
|
||||||
|
- ap = preauth_systems ? preauth_systems : static_preauth_systems;
|
||||||
|
+ if (preauth_systems == NULL)
|
||||||
|
+ return KRB5_PREAUTH_BAD_TYPE;
|
||||||
|
+ ap = preauth_systems;
|
||||||
|
while ((ap->type != -1) && (ap->type != type))
|
||||||
|
ap++;
|
||||||
|
if (ap->type == -1)
|
||||||
|
@@ -776,6 +678,98 @@ const char *missing_required_preauth(krb5_db_entry *client,
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
+/* Return true if request's enctypes indicate support for etype-info2. */
|
||||||
|
+static krb5_boolean
|
||||||
|
+requires_info2(const krb5_kdc_req *request)
|
||||||
|
+{
|
||||||
|
+ int i;
|
||||||
|
+
|
||||||
|
+ for (i = 0; i < request->nktypes; i++) {
|
||||||
|
+ if (enctype_requires_etype_info_2(request->ktype[i]))
|
||||||
|
+ return TRUE;
|
||||||
|
+ }
|
||||||
|
+ return FALSE;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+/* Add PA-ETYPE-INFO2 and possibly PA-ETYPE-INFO entries to pa_list as
|
||||||
|
+ * appropriate for the request and client principal. */
|
||||||
|
+static krb5_error_code
|
||||||
|
+add_etype_info(krb5_context context, krb5_kdcpreauth_rock rock,
|
||||||
|
+ krb5_pa_data ***pa_list)
|
||||||
|
+{
|
||||||
|
+ krb5_error_code ret;
|
||||||
|
+ krb5_pa_data *pa;
|
||||||
|
+
|
||||||
|
+ if (rock->client_key == NULL)
|
||||||
|
+ return 0;
|
||||||
|
+
|
||||||
|
+ if (!requires_info2(rock->request)) {
|
||||||
|
+ /* Include PA-ETYPE-INFO only for old clients. */
|
||||||
|
+ ret = make_etype_info(context, KRB5_PADATA_ETYPE_INFO,
|
||||||
|
+ rock->client->princ, rock->client_key,
|
||||||
|
+ rock->client_keyblock->enctype, &pa);
|
||||||
|
+ if (ret)
|
||||||
|
+ return ret;
|
||||||
|
+ /* add_pa_data_element() claims pa on success or failure. */
|
||||||
|
+ ret = add_pa_data_element(pa_list, pa);
|
||||||
|
+ if (ret)
|
||||||
|
+ return ret;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ /* Always include PA-ETYPE-INFO2. */
|
||||||
|
+ ret = make_etype_info(context, KRB5_PADATA_ETYPE_INFO2,
|
||||||
|
+ rock->client->princ, rock->client_key,
|
||||||
|
+ rock->client_keyblock->enctype, &pa);
|
||||||
|
+ if (ret)
|
||||||
|
+ return ret;
|
||||||
|
+ /* add_pa_data_element() claims pa on success or failure. */
|
||||||
|
+ return add_pa_data_element(pa_list, pa);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+/* Add PW-SALT or AFS3-SALT entries to pa_list as appropriate for the request
|
||||||
|
+ * and client principal. */
|
||||||
|
+static krb5_error_code
|
||||||
|
+add_pw_salt(krb5_context context, krb5_kdcpreauth_rock rock,
|
||||||
|
+ krb5_pa_data ***pa_list)
|
||||||
|
+{
|
||||||
|
+ krb5_error_code ret;
|
||||||
|
+ krb5_pa_data *pa;
|
||||||
|
+ krb5_data *salt = NULL;
|
||||||
|
+ krb5_int16 salttype;
|
||||||
|
+
|
||||||
|
+ /* Only include this pa-data for old clients. */
|
||||||
|
+ if (rock->client_key == NULL || requires_info2(rock->request))
|
||||||
|
+ return 0;
|
||||||
|
+
|
||||||
|
+ ret = krb5_dbe_compute_salt(context, rock->client_key,
|
||||||
|
+ rock->request->client, &salttype, &salt);
|
||||||
|
+ if (ret)
|
||||||
|
+ return 0;
|
||||||
|
+
|
||||||
|
+ if (salttype == KRB5_KDB_SALTTYPE_AFS3) {
|
||||||
|
+ ret = alloc_pa_data(KRB5_PADATA_AFS3_SALT, salt->length + 1, &pa);
|
||||||
|
+ if (ret)
|
||||||
|
+ goto cleanup;
|
||||||
|
+ memcpy(pa->contents, salt->data, salt->length);
|
||||||
|
+ pa->contents[salt->length] = '\0';
|
||||||
|
+ } else {
|
||||||
|
+ /* Steal memory from salt to make the pa-data entry. */
|
||||||
|
+ ret = alloc_pa_data(KRB5_PADATA_PW_SALT, 0, &pa);
|
||||||
|
+ if (ret)
|
||||||
|
+ goto cleanup;
|
||||||
|
+ pa->length = salt->length;
|
||||||
|
+ pa->contents = (uint8_t *)salt->data;
|
||||||
|
+ salt->data = NULL;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ /* add_pa_data_element() claims pa on success or failure. */
|
||||||
|
+ ret = add_pa_data_element(pa_list, pa);
|
||||||
|
+
|
||||||
|
+cleanup:
|
||||||
|
+ krb5_free_data(context, salt);
|
||||||
|
+ return ret;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
struct hint_state {
|
||||||
|
kdc_hint_respond_fn respond;
|
||||||
|
void *arg;
|
||||||
|
@@ -787,7 +781,7 @@ struct hint_state {
|
||||||
|
|
||||||
|
int hw_only;
|
||||||
|
preauth_system *ap;
|
||||||
|
- krb5_pa_data **pa_data, **pa_cur;
|
||||||
|
+ krb5_pa_data **pa_data;
|
||||||
|
krb5_preauthtype pa_type;
|
||||||
|
};
|
||||||
|
|
||||||
|
@@ -799,7 +793,7 @@ hint_list_finish(struct hint_state *state, krb5_error_code code)
|
||||||
|
kdc_realm_t *kdc_active_realm = state->realm;
|
||||||
|
|
||||||
|
if (!code) {
|
||||||
|
- if (state->pa_data[0] == 0) {
|
||||||
|
+ if (state->pa_data == NULL) {
|
||||||
|
krb5_klog_syslog(LOG_INFO,
|
||||||
|
_("%spreauth required but hint list is empty"),
|
||||||
|
state->hw_only ? "hw" : "");
|
||||||
|
@@ -820,20 +814,27 @@ hint_list_next(struct hint_state *arg);
|
||||||
|
static void
|
||||||
|
finish_get_edata(void *arg, krb5_error_code code, krb5_pa_data *pa)
|
||||||
|
{
|
||||||
|
+ krb5_error_code ret;
|
||||||
|
struct hint_state *state = arg;
|
||||||
|
|
||||||
|
if (code == 0) {
|
||||||
|
if (pa == NULL) {
|
||||||
|
- /* Include an empty value of the current type. */
|
||||||
|
- pa = calloc(1, sizeof(*pa));
|
||||||
|
- pa->magic = KV5M_PA_DATA;
|
||||||
|
- pa->pa_type = state->pa_type;
|
||||||
|
+ ret = alloc_pa_data(state->pa_type, 0, &pa);
|
||||||
|
+ if (ret)
|
||||||
|
+ goto error;
|
||||||
|
}
|
||||||
|
- *state->pa_cur++ = pa;
|
||||||
|
+ /* add_pa_data_element() claims pa on success or failure. */
|
||||||
|
+ ret = add_pa_data_element(&state->pa_data, pa);
|
||||||
|
+ if (ret)
|
||||||
|
+ goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
state->ap++;
|
||||||
|
hint_list_next(state);
|
||||||
|
+ return;
|
||||||
|
+
|
||||||
|
+error:
|
||||||
|
+ hint_list_finish(state, ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
@@ -870,16 +871,16 @@ get_preauth_hint_list(krb5_kdc_req *request, krb5_kdcpreauth_rock rock,
|
||||||
|
krb5_pa_data ***e_data_out, kdc_hint_respond_fn respond,
|
||||||
|
void *arg)
|
||||||
|
{
|
||||||
|
+ kdc_realm_t *kdc_active_realm = rock->rstate->realm_data;
|
||||||
|
struct hint_state *state;
|
||||||
|
+ krb5_pa_data *pa;
|
||||||
|
|
||||||
|
*e_data_out = NULL;
|
||||||
|
|
||||||
|
/* Allocate our state. */
|
||||||
|
state = calloc(1, sizeof(*state));
|
||||||
|
- if (state == NULL) {
|
||||||
|
- (*respond)(arg);
|
||||||
|
- return;
|
||||||
|
- }
|
||||||
|
+ if (state == NULL)
|
||||||
|
+ goto error;
|
||||||
|
state->hw_only = isflagset(rock->client->attributes,
|
||||||
|
KRB5_KDB_REQUIRES_HW_AUTH);
|
||||||
|
state->respond = respond;
|
||||||
|
@@ -888,17 +889,27 @@ get_preauth_hint_list(krb5_kdc_req *request, krb5_kdcpreauth_rock rock,
|
||||||
|
state->rock = rock;
|
||||||
|
state->realm = rock->rstate->realm_data;
|
||||||
|
state->e_data_out = e_data_out;
|
||||||
|
-
|
||||||
|
- state->pa_data = calloc(n_preauth_systems + 1, sizeof(krb5_pa_data *));
|
||||||
|
- if (!state->pa_data) {
|
||||||
|
- free(state);
|
||||||
|
- (*respond)(arg);
|
||||||
|
- return;
|
||||||
|
- }
|
||||||
|
-
|
||||||
|
- state->pa_cur = state->pa_data;
|
||||||
|
+ state->pa_data = NULL;
|
||||||
|
state->ap = preauth_systems;
|
||||||
|
+
|
||||||
|
+ /* Add an empty PA-FX-FAST element to advertise FAST support. */
|
||||||
|
+ if (alloc_pa_data(KRB5_PADATA_FX_FAST, 0, &pa) != 0)
|
||||||
|
+ goto error;
|
||||||
|
+ /* add_pa_data_element() claims pa on success or failure. */
|
||||||
|
+ if (add_pa_data_element(&state->pa_data, pa) != 0)
|
||||||
|
+ goto error;
|
||||||
|
+
|
||||||
|
+ if (add_etype_info(kdc_context, rock, &state->pa_data) != 0)
|
||||||
|
+ goto error;
|
||||||
|
+
|
||||||
|
hint_list_next(state);
|
||||||
|
+ return;
|
||||||
|
+
|
||||||
|
+error:
|
||||||
|
+ if (state != NULL)
|
||||||
|
+ krb5_free_pa_data(kdc_context, state->pa_data);
|
||||||
|
+ free(state);
|
||||||
|
+ (*respond)(arg);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
@@ -1029,10 +1040,10 @@ filter_preauth_error(krb5_error_code code)
|
||||||
|
static krb5_error_code
|
||||||
|
maybe_add_etype_info2(struct padata_state *state, krb5_error_code code)
|
||||||
|
{
|
||||||
|
+ krb5_error_code ret;
|
||||||
|
krb5_context context = state->context;
|
||||||
|
krb5_kdcpreauth_rock rock = state->rock;
|
||||||
|
- krb5_pa_data **list = state->pa_e_data;
|
||||||
|
- size_t count;
|
||||||
|
+ krb5_pa_data *pa;
|
||||||
|
|
||||||
|
/* Only add key information when requesting another preauth round trip. */
|
||||||
|
if (code != KRB5KDC_ERR_MORE_PREAUTH_DATA_REQUIRED)
|
||||||
|
@@ -1048,18 +1059,14 @@ maybe_add_etype_info2(struct padata_state *state, krb5_error_code code)
|
||||||
|
KRB5_PADATA_FX_COOKIE) != NULL)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
- /* Reallocate state->pa_e_data to make room for the etype-info2 element. */
|
||||||
|
- for (count = 0; list != NULL && list[count] != NULL; count++);
|
||||||
|
- list = realloc(list, (count + 2) * sizeof(*list));
|
||||||
|
- if (list == NULL)
|
||||||
|
- return ENOMEM;
|
||||||
|
- list[count] = list[count + 1] = NULL;
|
||||||
|
- state->pa_e_data = list;
|
||||||
|
+ ret = make_etype_info(context, KRB5_PADATA_ETYPE_INFO2,
|
||||||
|
+ rock->client->princ, rock->client_key,
|
||||||
|
+ rock->client_keyblock->enctype, &pa);
|
||||||
|
+ if (ret)
|
||||||
|
+ return ret;
|
||||||
|
|
||||||
|
- /* Generate an etype-info2 element in the new slot. */
|
||||||
|
- return make_etype_info(context, KRB5_PADATA_ETYPE_INFO2,
|
||||||
|
- rock->client->princ, rock->client_key,
|
||||||
|
- rock->client_keyblock->enctype, &list[count]);
|
||||||
|
+ /* add_pa_data_element() claims pa on success or failure. */
|
||||||
|
+ return add_pa_data_element(&state->pa_e_data, pa);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Release state and respond to the AS-REQ processing code with the result of
|
||||||
|
@@ -1279,17 +1286,20 @@ return_padata(krb5_context context, krb5_kdcpreauth_rock rock,
|
||||||
|
{
|
||||||
|
krb5_error_code retval;
|
||||||
|
krb5_pa_data ** padata;
|
||||||
|
- krb5_pa_data ** send_pa_list;
|
||||||
|
- krb5_pa_data ** send_pa;
|
||||||
|
+ krb5_pa_data ** send_pa_list = NULL;
|
||||||
|
+ krb5_pa_data * send_pa;
|
||||||
|
krb5_pa_data * pa = 0;
|
||||||
|
krb5_pa_data null_item;
|
||||||
|
preauth_system * ap;
|
||||||
|
- int * pa_order;
|
||||||
|
+ int * pa_order = NULL;
|
||||||
|
int * pa_type;
|
||||||
|
int size = 0;
|
||||||
|
krb5_kdcpreauth_modreq *modreq_ptr;
|
||||||
|
krb5_boolean key_modified;
|
||||||
|
krb5_keyblock original_key;
|
||||||
|
+
|
||||||
|
+ memset(&original_key, 0, sizeof(original_key));
|
||||||
|
+
|
||||||
|
if ((!*padata_context) &&
|
||||||
|
(make_padata_context(context, padata_context) != 0)) {
|
||||||
|
return KRB5KRB_ERR_GENERIC;
|
||||||
|
@@ -1300,26 +1310,18 @@ return_padata(krb5_context context, krb5_kdcpreauth_rock rock,
|
||||||
|
size++;
|
||||||
|
}
|
||||||
|
|
||||||
|
- if ((send_pa_list = malloc((size+1) * sizeof(krb5_pa_data *))) == NULL)
|
||||||
|
- return ENOMEM;
|
||||||
|
- if ((pa_order = malloc((size+1) * sizeof(int))) == NULL) {
|
||||||
|
- free(send_pa_list);
|
||||||
|
- return ENOMEM;
|
||||||
|
- }
|
||||||
|
+ pa_order = k5calloc(size + 1, sizeof(int), &retval);
|
||||||
|
+ if (pa_order == NULL)
|
||||||
|
+ goto cleanup;
|
||||||
|
sort_pa_order(context, request, pa_order);
|
||||||
|
|
||||||
|
retval = krb5_copy_keyblock_contents(context, encrypting_key,
|
||||||
|
&original_key);
|
||||||
|
- if (retval) {
|
||||||
|
- free(send_pa_list);
|
||||||
|
- free(pa_order);
|
||||||
|
- return retval;
|
||||||
|
- }
|
||||||
|
+ if (retval)
|
||||||
|
+ goto cleanup;
|
||||||
|
key_modified = FALSE;
|
||||||
|
null_item.contents = NULL;
|
||||||
|
null_item.length = 0;
|
||||||
|
- send_pa = send_pa_list;
|
||||||
|
- *send_pa = 0;
|
||||||
|
|
||||||
|
for (pa_type = pa_order; *pa_type != -1; pa_type++) {
|
||||||
|
ap = &preauth_systems[*pa_type];
|
||||||
|
@@ -1349,20 +1351,30 @@ return_padata(krb5_context context, krb5_kdcpreauth_rock rock,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
+ send_pa = NULL;
|
||||||
|
retval = ap->return_padata(context, pa, req_pkt, request, reply,
|
||||||
|
- encrypting_key, send_pa, &callbacks, rock,
|
||||||
|
+ encrypting_key, &send_pa, &callbacks, rock,
|
||||||
|
ap->moddata, *modreq_ptr);
|
||||||
|
if (retval)
|
||||||
|
goto cleanup;
|
||||||
|
|
||||||
|
- if (*send_pa)
|
||||||
|
- send_pa++;
|
||||||
|
- *send_pa = 0;
|
||||||
|
+ if (send_pa != NULL) {
|
||||||
|
+ /* add_pa_data_element() claims send_pa on success or failure. */
|
||||||
|
+ retval = add_pa_data_element(&send_pa_list, send_pa);
|
||||||
|
+ if (retval)
|
||||||
|
+ goto cleanup;
|
||||||
|
+ }
|
||||||
|
}
|
||||||
|
|
||||||
|
- retval = 0;
|
||||||
|
+ /* Add etype-info and pw-salt pa-data as needed. */
|
||||||
|
+ retval = add_etype_info(context, rock, &send_pa_list);
|
||||||
|
+ if (retval)
|
||||||
|
+ goto cleanup;
|
||||||
|
+ retval = add_pw_salt(context, rock, &send_pa_list);
|
||||||
|
+ if (retval)
|
||||||
|
+ goto cleanup;
|
||||||
|
|
||||||
|
- if (send_pa_list[0]) {
|
||||||
|
+ if (send_pa_list != NULL) {
|
||||||
|
reply->padata = send_pa_list;
|
||||||
|
send_pa_list = 0;
|
||||||
|
}
|
||||||
|
@@ -1370,8 +1382,7 @@ return_padata(krb5_context context, krb5_kdcpreauth_rock rock,
|
||||||
|
cleanup:
|
||||||
|
krb5_free_keyblock_contents(context, &original_key);
|
||||||
|
free(pa_order);
|
||||||
|
- if (send_pa_list)
|
||||||
|
- krb5_free_pa_data(context, send_pa_list);
|
||||||
|
+ krb5_free_pa_data(context, send_pa_list);
|
||||||
|
|
||||||
|
return (retval);
|
||||||
|
}
|
||||||
|
@@ -1438,9 +1449,8 @@ make_etype_info(krb5_context context, krb5_preauthtype pa_type,
|
||||||
|
krb5_enctype enctype, krb5_pa_data **pa_out)
|
||||||
|
{
|
||||||
|
krb5_error_code retval;
|
||||||
|
- krb5_pa_data *pa = NULL;
|
||||||
|
krb5_etype_info_entry **entry = NULL;
|
||||||
|
- krb5_data *scratch = NULL;
|
||||||
|
+ krb5_data *der_etype_info = NULL;
|
||||||
|
int etype_info2 = (pa_type == KRB5_PADATA_ETYPE_INFO2);
|
||||||
|
|
||||||
|
*pa_out = NULL;
|
||||||
|
@@ -1454,125 +1464,23 @@ make_etype_info(krb5_context context, krb5_preauthtype pa_type,
|
||||||
|
goto cleanup;
|
||||||
|
|
||||||
|
if (etype_info2)
|
||||||
|
- retval = encode_krb5_etype_info2(entry, &scratch);
|
||||||
|
+ retval = encode_krb5_etype_info2(entry, &der_etype_info);
|
||||||
|
else
|
||||||
|
- retval = encode_krb5_etype_info(entry, &scratch);
|
||||||
|
+ retval = encode_krb5_etype_info(entry, &der_etype_info);
|
||||||
|
if (retval)
|
||||||
|
goto cleanup;
|
||||||
|
- pa = k5alloc(sizeof(*pa), &retval);
|
||||||
|
- if (pa == NULL)
|
||||||
|
+
|
||||||
|
+ /* Steal the data from der_etype_info to create a pa-data element. */
|
||||||
|
+ retval = alloc_pa_data(pa_type, 0, pa_out);
|
||||||
|
+ if (retval)
|
||||||
|
goto cleanup;
|
||||||
|
- pa->magic = KV5M_PA_DATA;
|
||||||
|
- pa->pa_type = pa_type;
|
||||||
|
- pa->contents = (unsigned char *)scratch->data;
|
||||||
|
- pa->length = scratch->length;
|
||||||
|
- scratch->data = NULL;
|
||||||
|
- *pa_out = pa;
|
||||||
|
+ (*pa_out)->contents = (uint8_t *)der_etype_info->data;
|
||||||
|
+ (*pa_out)->length = der_etype_info->length;
|
||||||
|
+ der_etype_info->data = NULL;
|
||||||
|
|
||||||
|
cleanup:
|
||||||
|
krb5_free_etype_info(context, entry);
|
||||||
|
- krb5_free_data(context, scratch);
|
||||||
|
- return retval;
|
||||||
|
-}
|
||||||
|
-
|
||||||
|
-/* Return true if request's enctypes indicate support for etype-info2. */
|
||||||
|
-static krb5_boolean
|
||||||
|
-requires_info2(const krb5_kdc_req *request)
|
||||||
|
-{
|
||||||
|
- int i;
|
||||||
|
-
|
||||||
|
- for (i = 0; i < request->nktypes; i++) {
|
||||||
|
- if (enctype_requires_etype_info_2(request->ktype[i]))
|
||||||
|
- return TRUE;
|
||||||
|
- }
|
||||||
|
- return FALSE;
|
||||||
|
-}
|
||||||
|
-
|
||||||
|
-/* Generate hint list padata for PA-ETYPE-INFO or PA-ETYPE-INFO2. */
|
||||||
|
-static void
|
||||||
|
-get_etype_info(krb5_context context, krb5_kdc_req *request,
|
||||||
|
- krb5_kdcpreauth_callbacks cb, krb5_kdcpreauth_rock rock,
|
||||||
|
- krb5_kdcpreauth_moddata moddata, krb5_preauthtype pa_type,
|
||||||
|
- krb5_kdcpreauth_edata_respond_fn respond, void *arg)
|
||||||
|
-{
|
||||||
|
- krb5_error_code ret;
|
||||||
|
- krb5_pa_data *pa = NULL;
|
||||||
|
-
|
||||||
|
- if (rock->client_key == NULL) {
|
||||||
|
- ret = KRB5KDC_ERR_PADATA_TYPE_NOSUPP;
|
||||||
|
- } else if (pa_type == KRB5_PADATA_ETYPE_INFO && requires_info2(request)) {
|
||||||
|
- ret = KRB5KDC_ERR_PADATA_TYPE_NOSUPP;
|
||||||
|
- } else {
|
||||||
|
- ret = make_etype_info(context, pa_type, rock->client->princ,
|
||||||
|
- rock->client_key, rock->client_keyblock->enctype,
|
||||||
|
- &pa);
|
||||||
|
- }
|
||||||
|
- (*respond)(arg, ret, pa);
|
||||||
|
-}
|
||||||
|
-
|
||||||
|
-/* Generate AS-REP padata for PA-ETYPE-INFO or PA-ETYPE-INFO2. */
|
||||||
|
-static krb5_error_code
|
||||||
|
-return_etype_info(krb5_context context, krb5_pa_data *padata,
|
||||||
|
- krb5_data *req_pkt, krb5_kdc_req *request,
|
||||||
|
- krb5_kdc_rep *reply, krb5_keyblock *encrypting_key,
|
||||||
|
- krb5_pa_data **send_pa, krb5_kdcpreauth_callbacks cb,
|
||||||
|
- krb5_kdcpreauth_rock rock, krb5_kdcpreauth_moddata moddata,
|
||||||
|
- krb5_kdcpreauth_modreq modreq)
|
||||||
|
-{
|
||||||
|
- *send_pa = NULL;
|
||||||
|
- if (rock->client_key == NULL)
|
||||||
|
- return 0;
|
||||||
|
- if (padata->pa_type == KRB5_PADATA_ETYPE_INFO && requires_info2(request))
|
||||||
|
- return 0;
|
||||||
|
- return make_etype_info(context, padata->pa_type, rock->client->princ,
|
||||||
|
- rock->client_key, encrypting_key->enctype, send_pa);
|
||||||
|
-}
|
||||||
|
-
|
||||||
|
-static krb5_error_code
|
||||||
|
-return_pw_salt(krb5_context context, krb5_pa_data *in_padata,
|
||||||
|
- krb5_data *req_pkt, krb5_kdc_req *request, krb5_kdc_rep *reply,
|
||||||
|
- krb5_keyblock *encrypting_key, krb5_pa_data **send_pa,
|
||||||
|
- krb5_kdcpreauth_callbacks cb, krb5_kdcpreauth_rock rock,
|
||||||
|
- krb5_kdcpreauth_moddata moddata, krb5_kdcpreauth_modreq modreq)
|
||||||
|
-{
|
||||||
|
- krb5_error_code retval;
|
||||||
|
- krb5_pa_data * padata;
|
||||||
|
- krb5_data * salt = NULL;
|
||||||
|
- krb5_int16 salttype;
|
||||||
|
- krb5_key_data * client_key = rock->client_key;
|
||||||
|
-
|
||||||
|
- if (client_key == NULL || requires_info2(request))
|
||||||
|
- return 0;
|
||||||
|
-
|
||||||
|
- retval = krb5_dbe_compute_salt(context, client_key, request->client,
|
||||||
|
- &salttype, &salt);
|
||||||
|
- if (retval)
|
||||||
|
- return 0;
|
||||||
|
-
|
||||||
|
- padata = k5alloc(sizeof(*padata), &retval);
|
||||||
|
- if (padata == NULL)
|
||||||
|
- goto cleanup;
|
||||||
|
- padata->magic = KV5M_PA_DATA;
|
||||||
|
-
|
||||||
|
- if (salttype == KRB5_KDB_SALTTYPE_AFS3) {
|
||||||
|
- padata->contents = k5memdup0(salt->data, salt->length, &retval);
|
||||||
|
- if (padata->contents == NULL)
|
||||||
|
- goto cleanup;
|
||||||
|
- padata->pa_type = KRB5_PADATA_AFS3_SALT;
|
||||||
|
- padata->length = salt->length + 1;
|
||||||
|
- } else {
|
||||||
|
- padata->pa_type = KRB5_PADATA_PW_SALT;
|
||||||
|
- padata->length = salt->length;
|
||||||
|
- padata->contents = (krb5_octet *)salt->data;
|
||||||
|
- salt->data = NULL;
|
||||||
|
- }
|
||||||
|
-
|
||||||
|
- *send_pa = padata;
|
||||||
|
- padata = NULL;
|
||||||
|
-
|
||||||
|
-cleanup:
|
||||||
|
- free(padata);
|
||||||
|
- krb5_free_data(context, salt);
|
||||||
|
+ krb5_free_data(context, der_etype_info);
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -1656,69 +1564,3 @@ return_enc_padata(krb5_context context, krb5_data *req_pkt,
|
||||||
|
cleanup:
|
||||||
|
return code;
|
||||||
|
}
|
||||||
|
-
|
||||||
|
-
|
||||||
|
-#if 0
|
||||||
|
-static krb5_error_code return_server_referral(krb5_context context,
|
||||||
|
- krb5_pa_data * padata,
|
||||||
|
- krb5_db_entry *client,
|
||||||
|
- krb5_db_entry *server,
|
||||||
|
- krb5_kdc_req *request,
|
||||||
|
- krb5_kdc_rep *reply,
|
||||||
|
- krb5_key_data *client_key,
|
||||||
|
- krb5_keyblock *encrypting_key,
|
||||||
|
- krb5_pa_data **send_pa)
|
||||||
|
-{
|
||||||
|
- krb5_error_code code;
|
||||||
|
- krb5_tl_data tl_data;
|
||||||
|
- krb5_pa_data *pa_data;
|
||||||
|
- krb5_enc_data enc_data;
|
||||||
|
- krb5_data plain;
|
||||||
|
- krb5_data *enc_pa_data;
|
||||||
|
-
|
||||||
|
- *send_pa = NULL;
|
||||||
|
-
|
||||||
|
- tl_data.tl_data_type = KRB5_TL_SERVER_REFERRAL;
|
||||||
|
-
|
||||||
|
- code = krb5_dbe_lookup_tl_data(context, server, &tl_data);
|
||||||
|
- if (code || tl_data.tl_data_length == 0)
|
||||||
|
- return 0; /* no server referrals to return */
|
||||||
|
-
|
||||||
|
- plain.length = tl_data.tl_data_length;
|
||||||
|
- plain.data = tl_data.tl_data_contents;
|
||||||
|
-
|
||||||
|
- /* Encrypt ServerReferralData */
|
||||||
|
- code = krb5_encrypt_helper(context, encrypting_key,
|
||||||
|
- KRB5_KEYUSAGE_PA_SERVER_REFERRAL_DATA,
|
||||||
|
- &plain, &enc_data);
|
||||||
|
- if (code)
|
||||||
|
- return code;
|
||||||
|
-
|
||||||
|
- /* Encode ServerReferralData into PA-SERVER-REFERRAL-DATA */
|
||||||
|
- code = encode_krb5_enc_data(&enc_data, &enc_pa_data);
|
||||||
|
- if (code) {
|
||||||
|
- krb5_free_data_contents(context, &enc_data.ciphertext);
|
||||||
|
- return code;
|
||||||
|
- }
|
||||||
|
-
|
||||||
|
- krb5_free_data_contents(context, &enc_data.ciphertext);
|
||||||
|
-
|
||||||
|
- /* Return PA-SERVER-REFERRAL-DATA */
|
||||||
|
- pa_data = (krb5_pa_data *)malloc(sizeof(*pa_data));
|
||||||
|
- if (pa_data == NULL) {
|
||||||
|
- krb5_free_data(context, enc_pa_data);
|
||||||
|
- return ENOMEM;
|
||||||
|
- }
|
||||||
|
-
|
||||||
|
- pa_data->magic = KV5M_PA_DATA;
|
||||||
|
- pa_data->pa_type = KRB5_PADATA_SVR_REFERRAL_INFO;
|
||||||
|
- pa_data->length = enc_pa_data->length;
|
||||||
|
- pa_data->contents = enc_pa_data->data;
|
||||||
|
-
|
||||||
|
- free(enc_pa_data); /* don't free contents */
|
||||||
|
-
|
||||||
|
- *send_pa = pa_data;
|
||||||
|
-
|
||||||
|
- return 0;
|
||||||
|
-}
|
||||||
|
-#endif
|
11
krb5.spec
11
krb5.spec
@ -18,7 +18,7 @@ Summary: The Kerberos network authentication system
|
|||||||
Name: krb5
|
Name: krb5
|
||||||
Version: 1.16
|
Version: 1.16
|
||||||
# for prerelease, should be e.g., 0.% {prerelease}.1% { ?dist } (without spaces)
|
# for prerelease, should be e.g., 0.% {prerelease}.1% { ?dist } (without spaces)
|
||||||
Release: 10%{?dist}
|
Release: 11%{?dist}
|
||||||
|
|
||||||
# lookaside-cached sources; two downloads and a build artifact
|
# lookaside-cached sources; two downloads and a build artifact
|
||||||
Source0: https://web.mit.edu/kerberos/dist/krb5/1.16/krb5-%{version}%{prerelease}.tar.gz
|
Source0: https://web.mit.edu/kerberos/dist/krb5/1.16/krb5-%{version}%{prerelease}.tar.gz
|
||||||
@ -65,6 +65,12 @@ Patch38: Fix-flaws-in-LDAP-DN-checking.patch
|
|||||||
Patch39: Fix-capaths-.-values-on-client.patch
|
Patch39: Fix-capaths-.-values-on-client.patch
|
||||||
Patch40: Fix-hex-conversion-of-PKINIT-certid-strings.patch
|
Patch40: Fix-hex-conversion-of-PKINIT-certid-strings.patch
|
||||||
Patch41: Exit-with-status-0-from-kadmind.patch
|
Patch41: Exit-with-status-0-from-kadmind.patch
|
||||||
|
Patch42: Include-etype-info-in-for-hardware-preauth-hints.patch
|
||||||
|
Patch43: Fix-securid_sam2-preauth-for-non-default-salt.patch
|
||||||
|
Patch44: Refactor-KDC-krb5_pa_data-utility-functions.patch
|
||||||
|
Patch45: Simplify-kdc_preauth.c-systems-table.patch
|
||||||
|
Patch46: Add-PKINIT-client-support-for-freshness-token.patch
|
||||||
|
Patch47: Add-PKINIT-KDC-support-for-freshness-token.patch
|
||||||
|
|
||||||
License: MIT
|
License: MIT
|
||||||
URL: http://web.mit.edu/kerberos/www/
|
URL: http://web.mit.edu/kerberos/www/
|
||||||
@ -714,6 +720,9 @@ exit 0
|
|||||||
%{_libdir}/libkadm5srv_mit.so.*
|
%{_libdir}/libkadm5srv_mit.so.*
|
||||||
|
|
||||||
%changelog
|
%changelog
|
||||||
|
* Mon Mar 19 2018 Robbie Harwood <rharwood@redhat.com> - 1.16-11
|
||||||
|
- Add PKINIT KDC support for freshness token
|
||||||
|
|
||||||
* Wed Mar 14 2018 Robbie Harwood <rharwood@redhat.com> - 1.16-10
|
* Wed Mar 14 2018 Robbie Harwood <rharwood@redhat.com> - 1.16-10
|
||||||
- Exit with status 0 from kadmind
|
- Exit with status 0 from kadmind
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user