From 3c15e9724dae95a4bf0899a8b8efc3e9e3f486ab Mon Sep 17 00:00:00 2001
From: Alexander Scheel <ascheel@redhat.com>
Date: Wed, 5 Jul 2017 11:38:30 -0400
Subject: [PATCH] Implement GSS_C_CHANNEL_BOUND_FLAG
Define a new channel-bound GSS return flag, and set it in the krb5
mech if the initiator sent channel bindings matching the acceptor's.
Do not error out if the acceptor specifies channel bindings and the
initiator does not send them.
[ghudson@mit.edu: simplified code changes; fleshed out commit message]
[iboukris: cherry-picked from another PR and reduced in scope]
ticket: 8899 (new)
(cherry picked from commit 429a31146083fac21958631c2af572b08ec91022)
(cherry picked from commit 3ea1d6296ced3a998e79356f9be212e4c5e6a5d5)
---
src/lib/gssapi/generic/gssapi_ext.h | 2 ++
src/lib/gssapi/krb5/accept_sec_context.c | 18 +++++++++++++-----
2 files changed, 15 insertions(+), 5 deletions(-)
diff --git a/src/lib/gssapi/generic/gssapi_ext.h b/src/lib/gssapi/generic/gssapi_ext.h
index 218456e44..c675e8ebb 100644
--- a/src/lib/gssapi/generic/gssapi_ext.h
+++ b/src/lib/gssapi/generic/gssapi_ext.h
@@ -595,6 +595,8 @@ gss_store_cred_into(
* attribute (along with any applicable RFC 5587 attributes).
*/
+#define GSS_C_CHANNEL_BOUND_FLAG 2048 /* 0x00000800 */
+
OM_uint32 KRB5_CALLCONV
gssspi_query_meta_data(
OM_uint32 *minor_status,
diff --git a/src/lib/gssapi/krb5/accept_sec_context.c b/src/lib/gssapi/krb5/accept_sec_context.c
index 70dd7fc0c..9d3e2f4fe 100644
--- a/src/lib/gssapi/krb5/accept_sec_context.c
+++ b/src/lib/gssapi/krb5/accept_sec_context.c
@@ -427,6 +427,9 @@ kg_process_extension(krb5_context context,
GSS_C_SEQUENCE_FLAG | GSS_C_DCE_STYLE | \
GSS_C_IDENTIFY_FLAG | GSS_C_EXTENDED_ERROR_FLAG)
+/* A zero-value channel binding, for comparison */
+static const uint8_t null_cb[CB_MD5_LEN];
+
/*
* The krb5 GSS mech appropriates the authenticator checksum field from RFC
* 4120 to store structured data instead of a checksum, indicated with checksum
@@ -435,9 +438,10 @@ kg_process_extension(krb5_context context,
*
* Interpret the checksum. Read delegated creds into *deleg_out if it is not
* NULL. Set *flags_out to the allowed subset of token flags, plus
- * GSS_C_DELEG_FLAG if a delegated credential was present. Process any
- * extensions found using exts. On error, set *code_out to a krb5_error code
- * for use as a minor status value.
+ * GSS_C_DELEG_FLAG if a delegated credential was present and
+ * GSS_C_CHANNEL_BOUND_FLAG if matching channel bindings are present. Process
+ * any extensions found using exts. On error, set *code_out to a krb5_error
+ * code for use as a minor status value.
*/
static OM_uint32
process_checksum(OM_uint32 *minor_status, krb5_context context,
@@ -450,7 +454,7 @@ process_checksum(OM_uint32 *minor_status, krb5_context context,
krb5_error_code code = 0;
OM_uint32 status, option_id, token_flags;
size_t cb_len, option_len;
- krb5_boolean valid;
+ krb5_boolean valid, token_cb_present = FALSE, cb_match = FALSE;
krb5_key subkey;
krb5_data option, empty = empty_data();
krb5_checksum cb_cksum;
@@ -516,7 +520,9 @@ process_checksum(OM_uint32 *minor_status, krb5_context context,
goto fail;
}
assert(cb_cksum.length == cb_len);
- if (k5_bcmp(token_cb, cb_cksum.contents, cb_len) != 0) {
+ token_cb_present = (k5_bcmp(token_cb, null_cb, cb_len) != 0);
+ cb_match = (k5_bcmp(token_cb, cb_cksum.contents, cb_len) == 0);
+ if (token_cb_present && !cb_match) {
status = GSS_S_BAD_BINDINGS;
goto fail;
}
@@ -525,6 +531,8 @@ process_checksum(OM_uint32 *minor_status, krb5_context context,
/* Read the token flags and accept some of them as context flags. */
token_flags = k5_input_get_uint32_le(&in);
*flags_out = token_flags & INITIATOR_FLAGS;
+ if (cb_match)
+ *flags_out |= GSS_C_CHANNEL_BOUND_FLAG;
/* Read the delegated credential if present. */
if (in.len >= 4 && (token_flags & GSS_C_DELEG_FLAG)) {