third_party/heimdal: import lorikeet-heimdal-202404171655 (commit 28a56d818074e049f03...
authorStefan Metzmacher <metze@samba.org>
Mon, 4 Mar 2024 09:30:55 +0000 (10:30 +0100)
committerAndrew Bartlett <abartlet@samba.org>
Tue, 23 Apr 2024 23:50:33 +0000 (23:50 +0000)
BUG: https://bugzilla.samba.org/show_bug.cgi?id=15603
BUG: https://bugzilla.samba.org/show_bug.cgi?id=15621

See also:
https://github.com/heimdal/heimdal/pull/1234
https://github.com/heimdal/heimdal/pull/1238
https://github.com/heimdal/heimdal/pull/1240

Signed-off-by: Stefan Metzmacher <metze@samba.org>
Reviewed-by: Andrew Bartlett <abartlet@samba.org>
third_party/heimdal/lib/gssapi/krb5/8003.c
third_party/heimdal/lib/gssapi/krb5/init_sec_context.c
third_party/heimdal/lib/gssapi/test_context.c
third_party/heimdal/lib/krb5/build_auth.c
third_party/heimdal/lib/krb5/mk_req_ext.c
third_party/heimdal/tests/gss/check-context.in

index 0b91cf83b82d5e99424fd4e762b588aa6769582c..74ff349ab7b3575cd61d7b11d0ae5761c33d04d0 100644 (file)
@@ -87,6 +87,11 @@ _gsskrb5_create_8003_checksum (
 {
     u_char *p;
 
+#define _GSS_C_NON_8003_WIRE_FLAGS \
+       GSS_C_CHANNEL_BOUND_FLAG
+
+    flags &= ~_GSS_C_NON_8003_WIRE_FLAGS;
+
     /*
      * see rfc1964 (section 1.1.1 (Initial Token), and the checksum value
      * field's format) */
index 7749fc6cadd871920732ef22d390e578f66e5831..fbf9e5521c2faf5906ff87713baeb5783fd2c82f 100644 (file)
@@ -498,6 +498,7 @@ init_auth_restart
     krb5_data fwd_data, timedata;
     int32_t offset = 0, oldoffset = 0;
     uint32_t flagmask;
+    krb5_boolean channel_bound = FALSE;
 
     krb5_data_zero(&outbuf);
     krb5_data_zero(&fwd_data);
@@ -587,6 +588,11 @@ init_auth_restart
     }
     flags |= GSS_C_TRANS_FLAG;
 
+    if (req_flags & GSS_C_CHANNEL_BOUND_FLAG) {
+       flags |= GSS_C_CHANNEL_BOUND_FLAG;
+       channel_bound = TRUE;
+    }
+
     if (ret_flags)
        *ret_flags = flags;
     ctx->flags = flags;
@@ -626,6 +632,7 @@ init_auth_restart
                                     enctype,
                                     ctx->kcred,
                                     &cksum,
+                                    channel_bound,
                                     &authenticator,
                                     KRB5_KU_AP_REQ_AUTH);
 
@@ -787,6 +794,9 @@ repl_mutual
                return GSS_S_FAILURE;
            }
        }
+       if (ret != GSS_S_COMPLETE) {
+               return ret;
+       }
        kret = krb5_rd_rep (context,
                            ctx->auth_context,
                            &indata,
index 907e9c4d208621cc70bbeb1d22d539b933e58df5..e6d505033c3c52c684eddf1204ac83e7814b4d42 100644 (file)
@@ -82,6 +82,7 @@ static int token_split  = 0;
 static int version_flag = 0;
 static int verbose_flag = 0;
 static int help_flag   = 0;
+static int i_channel_bound = 0;
 static char *i_channel_bindings = NULL;
 static char *a_channel_bindings = NULL;
 
@@ -287,6 +288,8 @@ loop(gss_OID mechoid,
        flags |= GSS_C_DELEG_FLAG;
     if (policy_deleg_flag)
        flags |= GSS_C_DELEG_POLICY_FLAG;
+    if (i_channel_bound)
+       flags |= GSS_C_CHANNEL_BOUND_FLAG;
 
     input_token.value = rk_UNCONST(target);
     input_token.length = strlen(target);
@@ -904,6 +907,7 @@ static struct getargs args[] = {
     {"client-name", 0,  arg_string,     &client_name, "client name", NULL },
     {"client-password", 0,  arg_string, &client_password, "client password", NULL },
     {"anonymous", 0,   arg_flag,       &anon_flag, "anonymous auth", NULL },
+    {"i-channel-bound",0, arg_flag,    &i_channel_bound, "initiator channel bound", NULL },
     {"i-channel-bindings", 0, arg_string, &i_channel_bindings, "initiator channel binding data", NULL },
     {"a-channel-bindings", 0, arg_string, &a_channel_bindings, "acceptor channel binding data", NULL },
     {"limit-enctype",0,        arg_string,     &limit_enctype_string, "enctype", NULL },
index 3e0012562a3c60fb8659dfa0695b3a53a4d2e316..ae757f7b043be5d67e9bf306c170fa44064379cf 100644 (file)
@@ -86,6 +86,7 @@ add_etypelist(krb5_context context,
 
 static krb5_error_code
 add_ap_options(krb5_context context,
+              krb5_boolean channel_bound,
               krb5_authdata *auth_data)
 {
     krb5_error_code ret;
@@ -98,6 +99,9 @@ add_ap_options(krb5_context context,
                                              "client_aware_channel_bindings",
                                              NULL);
 
+    if (channel_bound)
+       require_cb = TRUE;
+
     if (!require_cb)
        return 0;
 
@@ -115,8 +119,90 @@ add_ap_options(krb5_context context,
     return ret;
 }
 
+static krb5_error_code
+add_target_principal(krb5_context context,
+                    krb5_const_principal server,
+                    krb5_authdata *auth_data)
+{
+    krb5_error_code ret;
+    AuthorizationDataElement ade;
+    char *s, *s2 = NULL;
+    size_t s2_len;
+
+    if (server == NULL) {
+       return 0;
+    }
+
+    ret = krb5_unparse_name_flags(context, server,
+                                 KRB5_PRINCIPAL_UNPARSE_DISPLAY,
+                                 &s);
+    if (ret)
+       return ret;
+
+    {
+       size_t ucs2_len;
+       uint16_t *ucs2;
+       unsigned int flags;
+
+       ret = wind_utf8ucs2_length(s, &ucs2_len);
+       if (ret) {
+           krb5_set_error_message(context, ret, "Principal %s is not valid UTF-8", s);
+           free(s);
+           return ret;
+       }
+
+       ucs2 = malloc(sizeof(ucs2[0]) * ucs2_len);
+       if (ucs2 == NULL) {
+           free(s);
+           return krb5_enomem(context);
+       }
+
+       ret = wind_utf8ucs2(s, ucs2, &ucs2_len);
+       if (ret) {
+           free(ucs2);
+           krb5_set_error_message(context, ret, "Principal %s is not valid UTF-8", s);
+           free(s);
+           return ret;
+       } else
+           free(s);
+
+       s2_len = (ucs2_len + 1) * 2;
+       s2 = malloc(s2_len);
+       if (s2 == NULL) {
+           free(ucs2);
+           return krb5_enomem(context);
+       }
+
+       flags = WIND_RW_LE;
+       ret = wind_ucs2write(ucs2, ucs2_len,
+                            &flags, s2, &s2_len);
+       free(ucs2);
+       if (ret) {
+           free(s2);
+           krb5_set_error_message(context, ret, "Failed to write to UCS-2 buffer");
+           return ret;
+       }
+
+       /*
+        * we do not want zero termination
+        */
+       s2_len = ucs2_len * 2;
+    }
+
+    ade.ad_type = KRB5_AUTHDATA_TARGET_PRINCIPAL;
+    ade.ad_data.length = s2_len;
+    ade.ad_data.data = s2;
+
+    ret = add_AuthorizationData(auth_data, &ade);
+    free(s2);
+
+    return ret;
+}
+
 static krb5_error_code
 make_ap_authdata(krb5_context context,
+                 krb5_boolean channel_bound,
+                 krb5_const_principal server,
                  krb5_authdata **auth_data)
 {
     krb5_error_code ret;
@@ -136,7 +222,13 @@ make_ap_authdata(krb5_context context,
      * in the AP authenticator when looking for AD-AP-OPTIONS. Make sure to
      * bundle it together with etypes.
      */
-    ret = add_ap_options(context, &ad);
+    ret = add_ap_options(context, channel_bound, &ad);
+    if (ret) {
+       free_AuthorizationData(&ad);
+       return ret;
+    }
+
+    ret = add_target_principal(context, server, &ad);
     if (ret) {
        free_AuthorizationData(&ad);
        return ret;
@@ -165,6 +257,7 @@ _krb5_build_authenticator (krb5_context context,
                           krb5_enctype enctype,
                           krb5_creds *cred,
                           Checksum *cksum,
+                          krb5_boolean channel_bound,
                           krb5_data *result,
                           krb5_key_usage usage)
 {
@@ -221,7 +314,10 @@ _krb5_build_authenticator (krb5_context context,
             * This is not GSS-API specific, we only enable it for
             * GSS for now
             */
-           ret = make_ap_authdata(context, &auth.authorization_data);
+           ret = make_ap_authdata(context,
+                                  channel_bound,
+                                  cred->server,
+                                  &auth.authorization_data);
            if (ret)
                goto fail;
        }
index a8a07f1c718f7a3a36e975e0b69ea5354653e844..09c116cd97b2de0e5cda5e76c40a5062cf62e2ed 100644 (file)
@@ -117,6 +117,7 @@ _krb5_mk_req_internal(krb5_context context,
                                    ac->keyblock->keytype,
                                    in_creds,
                                    c_opt,
+                                   FALSE, /* channel_bound */
                                    &authenticator,
                                    encrypt_usage);
     if (c_opt)
index 266fc3849022affaa5b025d036f72549f57712d8..5a836b9dc77267f67d634478d988a8464202c8ca 100644 (file)
@@ -389,6 +389,41 @@ for mech in krb5 spnego; do
                --mech-type=$mech host@lucid.test.h5l.se 2>/dev/null && \
                { eval "$testfailed"; }
 
+       echo "${mech}: initiator null bindings bound (client-aware-flag)" ; > messages.log
+       ${context} -v --i-channel-bound \
+               --mech-type=$mech host@lucid.test.h5l.se > cbinding.log || \
+               { eval "$testfailed"; }
+       grep "sflags:" cbinding.log | grep "channel-bound" > /dev/null && \
+               { echo "channel-bound flag unexpected"; eval "$testfailed"; }
+
+       echo "${mech}: initiator only bindings (client-aware-flag)" ; > messages.log
+       ${context} -v --i-channel-bound \
+               --i-channel-bindings=abc \
+               --mech-type=$mech host@lucid.test.h5l.se > cbinding.log || \
+               { eval "$testfailed"; }
+       grep "sflags:" cbinding.log | grep "channel-bound" > /dev/null && \
+               { echo "channel-bound flag unexpected"; eval "$testfailed"; }
+
+       echo "${mech}: acceptor only bindings (client-aware-flag)" ; > messages.log
+       ${context} -v --i-channel-bound \
+               --a-channel-bindings=abc \
+               --mech-type=$mech host@lucid.test.h5l.se 2>/dev/null && \
+               { eval "$testfailed"; }
+
+       echo "${mech}: matching bindings (client-aware-flag)" ; > messages.log
+       ${context} -v --i-channel-bound \
+               --i-channel-bindings=abc --a-channel-bindings=abc \
+               --mech-type=$mech host@lucid.test.h5l.se > cbinding.log || \
+               { eval "$testfailed"; }
+       grep "sflags:" cbinding.log | grep "channel-bound" > /dev/null || \
+               { echo "no channel-bound flag"; eval "$testfailed"; }
+
+       echo "${mech}: non matching bindings (client-aware-flag)" ; > messages.log
+       ${context} -v --i-channel-bound \
+               --i-channel-bindings=abc --a-channel-bindings=xyz \
+               --mech-type=$mech host@lucid.test.h5l.se 2>/dev/null && \
+               { eval "$testfailed"; }
+
 done
 
 #echo "sasl-digest-md5"