[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: kdc upgrade gives key length error



On Mon, Oct 14, 2002 at 01:50:19AM -0400, Aidan Cully wrote:
> Hi, tonight I upgraded my KDC to NetBSD-current, which appears to be
> Heimdal 0.5, and now I can't kinit due to the KDC getting a
> KRB5_BAD_KEYSIZE error in krb5_crypto_init...  This appears to be when
> trying the kdc tries to load the krbtgt/REALM@REALM principal from the
> database.  I dug a bit, and the key in the database has a length 4
> bytes longer than the enctype would expect.  The extra four (invalid)
> bytes of the key are all 0s...  I'm not sure, but this also looks like
> it's the case with my user principal, as it also has the last four
> bytes of the key being 0.  Is this a known problem, or should I try
> and dig further?

Operating under the assumption that this wasn't a known problem, I dug
further...  I've just discovered that the problem stems from using a
master key with a type of DES_CBC_CRC (yeah, it's old), though it may
be more generic than that...

I traced through the code path for the 'cpw' command in kadmin -l, and
finally noticed it generating a correct looking key, then sealing it
with krb5_encrypt (via hdb_seal_keys_mkey) before storing the key to
the database.  Inside encrypt_internal, there's the following block of
code:
    block_sz = (sz + et->blocksize - 1) &~ (et->blocksize - 1); /* pad */
The length of the encrypted block is set to block_sz:
    result->data = p;
    result->length = block_sz;
checksm_sz == 4, so block_sz == len + 8, with 4 extra bytes for
encryption padding.  The unseal_keys_mkey does not remove this padding,
and returns a length that's 4 bytes too long, which is why my KDC has
been sucking.  The length of a key on input to hdb_seal_keys is 24, and
when I call hdb_unseal_keys, I get one of length 28, hence the
KRB5_BAD_KEYSIZE error.

I don't know a good solution to this problem...  In the meantime, I'm
doing this:
--- lib/hdb/mkey.c.orig	Sun Oct 20 23:38:03 2002
+++ lib/hdb/mkey.c	Sun Oct 20 23:48:07 2002
@@ -376,6 +376,7 @@
 hdb_unseal_keys_mkey(krb5_context context, hdb_entry *ent, hdb_master_key mkey)
 {
     int i;
+    int keysize;
     krb5_error_code ret;
     krb5_data res;
     Key *k;
@@ -402,6 +403,25 @@
 	memset(k->key.keyvalue.data, 0, k->key.keyvalue.length);
 	free(k->key.keyvalue.data);
 	k->key.keyvalue = res;
+
+	/*
+	 * XXX: krb5_encrypt puts on an unknown amount of encryption padding
+	 * when encrypting a block, which krb5_decrypt can't figure out, so
+	 * it assumes no padding.  When this happens with a key being sealed,
+	 * a future call to attempt to use this key will generate a
+	 * KRB5_BAD_KEYSIZE error, so force the size to match the key when
+	 * unsealing an entry.
+	 *
+	 * A better way to do this would be to store the key size in the
+	 * database, but that breaks binary compatibility.
+	 */
+	ret = XXX_krb5_keysize(k->key.keytype, &keysize);
+	if (ret)
+	    return ret;
+	if (keysize > k->key.keyvalue.length)
+	    return HDB_ERR_KEYSIZE_MISMATCH;
+	k->key.keyvalue.length = keysize;
+
 	free(k->mkvno);
 	k->mkvno = NULL;
     }
--- lib/hdb/hdb_err.et.orig	Sun Oct 20 23:42:57 2002
+++ lib/hdb/hdb_err.et	Sun Oct 20 23:43:47 2002
@@ -23,5 +23,6 @@
 error_code EXISTS,		"Entry already exists in database"
 error_code BADVERSION,		"Wrong database version"
 error_code NO_MKEY,		"No correct master key"
+error_code KEYSIZE_MISMATCH,	"Key size mismatch"
 
 end
--- lib/krb5/crypto.c.orig	Sun Oct 20 23:35:14 2002
+++ lib/krb5/crypto.c	Sun Oct 20 23:37:32 2002
@@ -2967,6 +2967,19 @@
 
 
 krb5_error_code
+XXX_krb5_keysize(krb5_enctype etype, int *size)
+{
+    struct encryption_type *et;
+
+    et = _find_enctype(etype);
+    if (et == NULL)
+	return KRB5_PROG_ETYPE_NOSUPP;
+    *size = et->keytype->size;
+    return 0;
+}
+
+
+krb5_error_code
 krb5_crypto_init(krb5_context context,
 		 const krb5_keyblock *key,
 		 krb5_enctype etype,
---end here.

which seems to have solved things...
--aidan