[OpenAFS] Re: Heimdal KDC bug mentioned in rekeying document

Russ Allbery rra@stanford.edu
Tue, 06 Aug 2013 16:23:08 -0700


--=-=-=

Ken Dreyer <ktdreyer@ktdreyer.com> writes:

> I have a question about the exact patches that are necessary. There were
> several patches that went into heimdal-1-5-branch after 1.5.3 that
> appear to relate to enctypes. I'm working on packaging Heimdal 1.5.3 for
> Fedora and EPEL, so will I need all of these?

Here's the patch that we're running in production on top of 1.5.2 (plus
some unrelated local patches and pullups, so there may be a small bit of
fuzz).  This is a fold of all the related patches that went into
heimdal-1-5-branch and possibly some stuff that isn't on there yet.

None of this is my work; it's from KTH and from Jeffrey and Nico.

You need basically all of this, I think.  I tried to leave off some stuff
that didn't seem relevant to a site with allow-weak-crypto = true, and it
still didn't work.

-- 
Russ Allbery (rra@stanford.edu)             <http://www.eyrie.org/~eagle/>


--=-=-=
Content-Type: text/x-diff
Content-Disposition: attachment; filename=des-key-selection

Author: Russ Allbery <rra@stanford.edu>
Author: Nicolas Williams <nico@cryptonector.com>
Author: Love Hornquist Astrand <lha@h5l.org>
Author: Jeffrey Altman <jaltman@secure-endpoints.com>
Subject: Patch rollup for AFS DES session key support

Rollup of patches required to allow old AFS aklog to get a DES
session key when talking to an afs/* principal that has no DES
enctypes.  This requires allowing Heimdal to negotiate a DES
session key for known-weak service principals and to be willing
to use two separate enctypes for the session key and the server
key.

The components of this change are:

12cd2c9cbd1ca027a3ef9ac7ab3e79526b1348ae
4c6976a6bdf8a76c6f3c650ae970d46c931e5c71
c757eb7fb04a9b0ca883ddb72c1bc75bf5d814f3 (small portion only)
afa9db62ba8250d24e7e5beb0a1d91d6b2d0a85a
f4f89ac8e0f8583b7a2a3413fee5526a5b137d5b
1f147f0fa66427c1976d5f88eb8bcdfe5f213287
1826106ff4befe3e7dffc18692e40bd244c0d8d8
71fb56309c63f51ce9a4e0b6d454b60ff3ea786b
dfc7ed639f8ba7eced10f2d7efd08aa038ac2ecd

all from Heimdal master, plus subsequent patches from Jeffrey Altman
and Ragnar Sundblad.

--- heimdal.orig/kdc/krb5tgs.c
+++ heimdal/kdc/krb5tgs.c
@@ -969,10 +969,10 @@
 	    goto out;
     }
 
-    if (krb5_enctype_valid(context, et.key.keytype) != 0
-	&& _kdc_is_weak_exception(server->entry.principal, et.key.keytype))
+    if (krb5_enctype_valid(context, serverkey->keytype) != 0
+	&& _kdc_is_weak_exception(server->entry.principal, serverkey->keytype))
     {
-	krb5_enctype_enable(context, et.key.keytype);
+	krb5_enctype_enable(context, serverkey->keytype);
 	is_weak = 1;
     }
 
@@ -988,12 +988,12 @@
        etype list, even if we don't want a session key with
        DES3? */
     ret = _kdc_encode_reply(context, config,
-			    &rep, &et, &ek, et.key.keytype,
+			    &rep, &et, &ek, serverkey->keytype,
 			    kvno,
 			    serverkey, 0, replykey, rk_is_subkey,
 			    e_text, reply);
     if (is_weak)
-	krb5_enctype_disable(context, et.key.keytype);
+	krb5_enctype_disable(context, serverkey->keytype);
 
 out:
     free_TGS_REP(&rep);
@@ -1703,15 +1703,21 @@
 				  krb5_principal_is_krbtgt(context, sp) ?
 				  config->tgt_use_strongest_session_key :
 				  config->svc_use_strongest_session_key, FALSE,
-				  server, b->etype.val, b->etype.len, NULL,
-				  &skey);
+				  server, b->etype.val, b->etype.len, &etype,
+				  NULL);
 	    if(ret) {
 		kdc_log(context, config, 0,
 			"Server (%s) has no support for etypes", spn);
 		goto out;
 	    }
+	    ret = _kdc_get_preferred_key(context, config, server, spn,
+					 NULL, &skey);
+	    if(ret) {
+		kdc_log(context, config, 0,
+			"Server (%s) has no supported etypes", spn);
+		goto out;
+	    }
 	    ekey = &skey->key;
-	    etype = skey->key.keytype;
 	    kvno = server->entry.kvno;
 	}
 
--- heimdal.orig/kdc/kerberos5.c
+++ heimdal/kdc/kerberos5.c
@@ -120,7 +120,7 @@
 /*
  * return the first appropriate key of `princ' in `ret_key'.  Look for
  * all the etypes in (`etypes', `len'), stopping as soon as we find
- * one, but preferring one that has default salt
+ * one, but preferring one that has default salt. 
  */
 
 krb5_error_code
@@ -131,9 +131,10 @@
 {
     krb5_error_code ret;
     krb5_salt def_salt;
-    krb5_enctype enctype = ETYPE_NULL;
-    Key *key;
-    int i;
+    krb5_enctype enctype = (krb5_enctype)ETYPE_NULL;
+    const krb5_enctype *p;
+    Key *key = NULL;
+    int i, k;
 
     /* We'll want to avoid keys with v4 salted keys in the pre-auth case... */
     ret = krb5_get_pw_salt(context, princ->entry.principal, &def_salt);
@@ -143,10 +144,6 @@
     ret = KRB5KDC_ERR_ETYPE_NOSUPP;
 
     if (use_strongest_session_key) {
-	const krb5_enctype *p;
-	krb5_enctype clientbest = ETYPE_NULL;
-	int j;
-
 	/*
 	 * Pick the strongest key that the KDC, target service, and
 	 * client all support, using the local cryptosystem enctype
@@ -160,34 +157,35 @@
 
 	/* drive the search with local supported enctypes list */
 	p = krb5_kerberos_enctypes(context);
-	for (i = 0; p[i] != ETYPE_NULL && enctype == ETYPE_NULL; i++) {
-	    if (krb5_enctype_valid(context, p[i]) != 0)
+	for (i = 0;
+	    p[i] != (krb5_enctype)ETYPE_NULL && enctype == (krb5_enctype)ETYPE_NULL;
+	    i++) {
+	    if (krb5_enctype_valid(context, p[i]) != 0 &&
+                !_kdc_is_weak_exception(princ->entry.principal, p[i]))
 		continue;
 
 	    /* check that the client supports it too */
-	    for (j = 0; j < len && enctype == ETYPE_NULL; j++) {
-		if (p[i] != etypes[j])
+	    for (k = 0; k < len && enctype == (krb5_enctype)ETYPE_NULL; k++) {
+	    
+                if (p[i] != etypes[k])
 		    continue;
-		/* save best of union of { client, crypto system } */
-		if (clientbest == ETYPE_NULL)
-		    clientbest = p[i];
+
 		/* check target princ support */
-		ret = hdb_enctype2key(context, &princ->entry, p[i], &key);
-		if (ret)
-		    continue;
-		if (is_preauth && !is_default_salt_p(&def_salt, key))
-		    continue;
-		enctype = p[i];
-	    }
+		key = NULL;
+		while (hdb_next_enctype2key(context, &princ->entry,
+					     p[i], &key) == 0) {
+		    if (key->key.keyvalue.length == 0) {
+			ret = KRB5KDC_ERR_NULL_KEY;
+			continue;
+		    }
+		    enctype = p[i];
+		    ret = 0;
+		    if (is_preauth && ret_key != NULL &&
+                        !is_default_salt_p(&def_salt, key))
+			continue;
+		}
+            }
 	}
-	if (clientbest != ETYPE_NULL && enctype == ETYPE_NULL)
-	    enctype = clientbest;
-	else if (enctype == ETYPE_NULL)
-	    ret = KRB5KDC_ERR_ETYPE_NOSUPP;
-	if (ret == 0 && ret_enctype != NULL)
-	    *ret_enctype = enctype;
-	if (ret == 0 && ret_key != NULL)
-	    *ret_key = key;
     } else {
 	/*
 	 * Pick the first key from the client's enctype list that is
@@ -198,29 +196,51 @@
 	 * weak enctypes in krb5.conf and selects this key selection
 	 * algorithm, then we get exactly what RFC4120 says.
 	 */
-	for(key = NULL, i = 0; ret != 0 && i < len; i++, key = NULL) {
+	for(i = 0; ret != 0 && i < len; i++) {
 
 	    if (krb5_enctype_valid(context, etypes[i]) != 0 &&
 		!_kdc_is_weak_exception(princ->entry.principal, etypes[i]))
 		continue;
 
-	    while (hdb_next_enctype2key(context, &princ->entry, etypes[i], &key) == 0) {
+            key = NULL;
+	    while (ret != 0 &&
+		   hdb_next_enctype2key(context, &princ->entry,
+					etypes[i], &key) == 0) {
 		if (key->key.keyvalue.length == 0) {
 		    ret = KRB5KDC_ERR_NULL_KEY;
 		    continue;
 		}
-		if (ret_key != NULL)
-		    *ret_key = key;
-		if (ret_enctype != NULL)
-		    *ret_enctype = etypes[i];
+		enctype = etypes[i];
 		ret = 0;
-		if (is_preauth && is_default_salt_p(&def_salt, key))
-		    goto out;
+		if (is_preauth && ret_key != NULL &&
+                    !is_default_salt_p(&def_salt, key))
+		    continue;
 	    }
 	}
     }
 
-out:
+    if (enctype == (krb5_enctype)ETYPE_NULL) {
+        /*
+         * if the service principal is one for which there is a known 1DES
+         * exception and no other enctype matches both the client request and
+         * the service key list, provide a DES-CBC-CRC key.
+         */
+        if (ret_key == NULL &&
+            _kdc_is_weak_exception(princ->entry.principal, ETYPE_DES_CBC_CRC)) {
+            ret = 0;
+            enctype = ETYPE_DES_CBC_CRC;
+        } else {
+            ret = KRB5KDC_ERR_ETYPE_NOSUPP;
+        }
+    }
+
+    if (ret == 0) {
+        if (ret_enctype != NULL)
+            *ret_enctype = enctype;
+        if (ret_key != NULL)
+            *ret_key = key;
+    }
+
     krb5_free_salt (context, def_salt);
     return ret;
 }
--- heimdal.orig/lib/krb5/krb5.conf.5
+++ heimdal/lib/krb5/krb5.conf.5
@@ -418,21 +418,21 @@
 is supported by the KDC and the target principal when the target
 principal is a krbtgt principal.  Else it will prefer the first key from
 the client's AS-REQ enctype list that is also supported by the KDC and
-the target principal. Defaults to TRUE.
+the target principal.  Defaults to FALSE.
 .It Li svc-use-strongest-session-key = Va BOOL
 Like tgt-use-strongest-session-key, but applies to the session key
 enctype of tickets for services other than krbtgt principals. Defaults
-to TRUE.
+to FALSE.
 .It Li preauth-use-strongest-session-key = Va BOOL
 If TRUE then select the strongest possible enctype from the client's
 AS-REQ for PA-ETYPE-INFO2 (i.e., for password-based pre-authentication).
-Else pick the first supported enctype from the client's AS-REQ. Defaults
-to TRUE.
+Else pick the first supported enctype from the client's AS-REQ.  Defaults
+to FALSE.
 .It Li use-strongest-server-key = Va BOOL
 If TRUE then the KDC picks, for the ticket encrypted part's key, the
 first supported enctype from the target service principal's hdb entry's
 current keyset. Else the KDC picks the first supported enctype from the
-target service principal's hdb entry's current keyset. Defaults to TRUE.
+target service principal's hdb entry's current keyset.  Defaults to TRUE.
 .It Li check-ticket-addresses = Va BOOL
 Verify the addresses in the tickets used in tgs requests.
 .\" XXX
--- heimdal.orig/kdc/misc.c
+++ heimdal/kdc/misc.c
@@ -141,7 +141,8 @@
 	const krb5_enctype *p = krb5_kerberos_enctypes(context);
 
 	for (i = 0; p[i] != ETYPE_NULL; i++) {
-	    if (krb5_enctype_valid(context, p[i]) != 0)
+	    if (krb5_enctype_valid(context, p[i]) != 0 &&
+                !_kdc_is_weak_exception(h->entry.principal, p[i]))
 		continue;
 	    ret = hdb_enctype2key(context, &h->entry, p[i], key);
 	    if (ret != 0)
@@ -154,8 +155,8 @@
 	*key = NULL;
 
 	for (i = 0; i < h->entry.keys.len; i++) {
-	    if (krb5_enctype_valid(context, h->entry.keys.val[i].key.keytype)
-		!= 0)
+	    if (krb5_enctype_valid(context, h->entry.keys.val[i].key.keytype) != 0 &&
+                !_kdc_is_weak_exception(h->entry.principal, h->entry.keys.val[i].key.keytype))
 		continue;
 	    ret = hdb_enctype2key(context, &h->entry,
 		h->entry.keys.val[i].key.keytype, key);

--=-=-=--