I tracked the problem down to this commit:

commit 6df0783c7eef0984b712792a25dd2f5a39f8f337
Author: Love Hornquist Astrand <l...@apple.com>
Date:   Wed Sep 23 00:14:57 2009 -0700

    Redo client key handling for AS
    
    Pick the replykey to be the same as the preauth key, this allows
    us to delay the picking of client key to when its needed, this
    means that we can have a reply keys for PKINIT that is independant
    of what keys the client have.

The attached dif (which is probably totally wrong and shouldn't be
applied anywhere outside of a test instance) to Heimdal 1.5 makes the
kdc work again with no error.

-- 

..ooOO ch...@chiappa.net              | My opinions are my own  OOoo..
..ooOO chris.chia...@oracle.com       | and certainly not those OOoo..
..ooOO http://www.chiappa.net/~chris/ | of my employer          OOoo..
diff -wur heimdal-1.5.orig/kdc/kerberos5.c heimdal-1.5/kdc/kerberos5.c
--- heimdal-1.5.orig/kdc/kerberos5.c    2011-07-30 16:43:29.000000000 -0400
+++ heimdal-1.5/kdc/kerberos5.c 2011-08-04 12:16:57.388529876 -0400
@@ -977,14 +977,13 @@
     const char *e_text = NULL;
     krb5_crypto crypto;
     Key *ckey, *skey;
-    EncryptionKey *reply_key = NULL, session_key;
+    EncryptionKey *reply_key = NULL;
     int flags = HDB_F_FOR_AS_REQ;
 #ifdef PKINIT
     pk_client_params *pkp = NULL;
 #endif
 
     memset(&rep, 0, sizeof(rep));
-    memset(&session_key, 0, sizeof(session_key));
     krb5_data_zero(&e_data);
 
     ALLOC(rep.padata);
@@ -1085,18 +1084,14 @@
     memset(&ek, 0, sizeof(ek));
 
     /*
-     * Select a session enctype from the list of the crypto system
-     * supported enctypes that is supported by the client and is one of
-     * the enctype of the enctype of the service (likely krbtgt).
-     *
-     * The latter is used as a hint of what enctypes all KDC support,
-     * to make sure a newer version of KDC won't generate a session
-     * enctype that an older version of a KDC in the same realm can't
-     * decrypt.
+     * Find the client key for reply encryption and pa-type salt, Pick
+     * the client key upfront before the other keys because that is
+     * going to affect what enctypes we are going to use in
+     * ETYPE-INFO{,2}.
      */
     ret = _kdc_find_etype(context, config->as_use_strongest_session_key, FALSE,
                          client, b->etype.val, b->etype.len, &sessionetype,
-                         NULL);
+                         &ckey);
     if (ret) {
        kdc_log(context, config, 0,
                "Client (%s) from %s has no common enctypes with KDC "
@@ -1320,8 +1315,6 @@
 
            set_salt_padata(rep.padata, pa_key->salt);
 
-           reply_key = &pa_key->key;
-
            ret = krb5_enctype_to_string(context, pa_key->key.keytype, &str);
            if (ret)
                str = NULL;
@@ -1466,6 +1459,63 @@
     if(ret)
        goto out;
 
+    /*
+     * Select a session enctype from the list of the crypto systems
+     * supported enctype, is supported by the client and is one of the
+     * enctype of the enctype of the krbtgt.
+     *
+     * The later is used as a hint what enctype all KDC are supporting
+     * to make sure a newer version of KDC wont generate a session
+     * enctype that and older version of a KDC in the same realm can't
+     * decrypt.
+     *
+     * But if the KDC admin is paranoid and doesn't want to have "no
+     * the best" enctypes on the krbtgt, lets save the best pick from
+     * the client list and hope that that will work for any other
+     * KDCs.
+     */
+    {
+       const krb5_enctype *p;
+       krb5_enctype clientbest = ETYPE_NULL;
+       int i, j;
+
+       p = krb5_kerberos_enctypes(context);
+
+       sessionetype = ETYPE_NULL;
+
+       for (i = 0; p[i] != ETYPE_NULL && sessionetype == ETYPE_NULL; i++) {
+           if (krb5_enctype_valid(context, p[i]) != 0)
+               continue;
+
+           for (j = 0; j < b->etype.len && sessionetype == ETYPE_NULL; j++) {
+               Key *dummy;
+               /* check with client */
+               if (p[i] != b->etype.val[j])
+                   continue;
+               /* save best of union of { client, crypto system } */
+               if (clientbest == ETYPE_NULL)
+                   clientbest = p[i];
+               /* check with krbtgt */
+               ret = hdb_enctype2key(context, &server->entry, p[i], &dummy);
+               if (ret)
+                   continue;
+               sessionetype = p[i];
+           }
+       }
+       /* if krbtgt had no shared keys with client, pick clients best */
+       if (clientbest != ETYPE_NULL && sessionetype == ETYPE_NULL) {
+           sessionetype = clientbest;
+       } else if (sessionetype == ETYPE_NULL) {
+           kdc_log(context, config, 0,
+                   "Client (%s) from %s has no common enctypes with KDC"
+                   "to use for the session key",
+                   client_name, from);
+           goto out;
+       }
+    }
+
+    log_as_req(context, config, setype, setype, b);
+
     if(f.renew || f.validate || f.proxy || f.forwarded || f.enc_tkt_in_skey
        || (f.request_anonymous && !config->allow_anonymous)) {
        ret = KRB5KDC_ERR_BADOPTION;
@@ -1682,13 +1732,12 @@
 
     } else
 #endif
-    {
+    if (ckey) {
+       reply_key = &ckey->key;
        ret = krb5_generate_random_keyblock(context, sessionetype, &et.key);
        if (ret)
            goto out;
-    }
-
-    if (reply_key == NULL) {
+    } else {
        e_text = "Client have no reply key";
        ret = KRB5KDC_ERR_CLIENT_NOTYET;
        goto out;
@@ -1698,6 +1747,9 @@
     if (ret)
        goto out;
 
+    if (ckey)
+       set_salt_padata (rep.padata, ckey->salt);
+
     /* Add signing of alias referral */
     if (f.canonicalize) {
        PA_ClientCanonicalized canon;
@@ -1803,8 +1855,6 @@
     if (ret)
        goto out;
 
-    log_as_req(context, config, reply_key->keytype, setype, b);
-
     ret = _kdc_encode_reply(context, config,
                            &rep, &et, &ek, setype, server->entry.kvno,
                            &skey->key, client->entry.kvno,
diff -wur heimdal-1.5.orig/kdc/krb5tgs.c heimdal-1.5/kdc/krb5tgs.c
--- heimdal-1.5.orig/kdc/krb5tgs.c      2011-07-30 16:43:29.000000000 -0400
+++ heimdal-1.5/kdc/krb5tgs.c   2011-08-04 12:12:53.480518123 -0400
@@ -1700,7 +1700,7 @@
 
            ret = _kdc_find_etype(context,
                                  config->tgs_use_strongest_session_key, FALSE,
-                                 server, b->etype.val, b->etype.len, NULL,
+                                 server, b->etype.val, b->etype.len, &etype,
                                  &skey);
            if(ret) {
                kdc_log(context, config, 0,
@@ -1708,7 +1708,6 @@
                goto out;
            }
            ekey = &skey->key;
-           etype = skey->key.keytype;
            kvno = server->entry.kvno;
        }
 

Reply via email to