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

multiple krb5 salted des keys



For "ease" of migration to Kerberos v5, which we're hurrying along due to
the needs of our upcoming win2k infrastructure, we determined we needed
the ability to have multiple KRB5_PW_SALT DES keys for a principal, and to
use the correct one at the correct time. Several years ago we switched our
AFS cell to default to v4-salted keys, as opposed to AFS salted keys, so
users typically have a v4 slated key now. Upon conversion we also wish
them to have a real, standard v5 salted key, as the Kerberos stuff in
Win2000 doesn't appear to like v4-salted keys at all, ever. Nor, however,
does AFS like v5-salted keys, and the kaserver compatibility in the
Heimdal KDC isn't really useful if it tries to return keys to clients that
they can't use.

Attached is a patch which does what's needed to make this work: namely,
the KDC will serve a v4 salted key in the kerberos4 and kaserver
interfaces in preference to a v5 salted key, and the mods to make all the
necessary keys be created in set_keys is also included. Which keys get
used for what is configurable in the kdc configuration file, though I
somewhat dislike the option names I came up with.

Also in this patch:
kdc/connect.c: wrap port 750 binding in enable_v4
kdc/hprop.c: dump v4 salted keys rather than afs keys, if 0'd out for now. 
		should arguably be an option.
	     also, a pw_expire time of 0 is also used as a never time
		rather than a now time
lib/hdb/hdb_local.h: prefer db.h to db_185.h. this has to do with the db3
		bindings, and finding we have those and then not being
		able to use them.

-D


Index: kdc/524.c
===================================================================
RCS file: /usr/tmp/heimdal/cvs/heimdal/kdc/524.c,v
retrieving revision 1.12
diff -u -r1.12 524.c
--- 524.c	2000/06/07 09:54:21	1.12
+++ 524.c	2000/06/08 18:56:08
@@ -68,7 +68,7 @@
 		from, spn);
 	goto out;
     }
-    ret = hdb_enctype2key(context, server, t->enc_part.etype, &skey);
+    ret = hdb_encsalt2key(context, server, t->enc_part.etype, 0, 0, &skey);
     if(ret){
 	kdc_log(0, "No suitable key found for server (%s) "
 		"when converting ticket from ", spn, from);
Index: kdc/connect.c
===================================================================
RCS file: /usr/tmp/heimdal/cvs/heimdal/kdc/connect.c,v
retrieving revision 1.75
diff -u -r1.75 connect.c
--- connect.c	2000/06/07 09:52:28	1.75
+++ connect.c	2000/06/10 03:45:40
@@ -125,12 +125,14 @@
 static void
 add_standard_ports (int family)
 {
     add_port_service(family, "kerberos", 88, "udp");
     add_port_service(family, "kerberos", 88, "tcp");
     add_port_service(family, "kerberos-sec", 88, "udp");
     add_port_service(family, "kerberos-sec", 88, "tcp");
-    add_port_service(family, "kerberos-iv", 750, "udp");
-    add_port_service(family, "kerberos-iv", 750, "tcp");
+    if (enable_v4) {
+	add_port_service(family, "kerberos-iv", 750, "udp");
+	add_port_service(family, "kerberos-iv", 750, "tcp");
+    }
     if(enable_http)
 	add_port_service(family, "http", 80, "tcp");
 #ifdef KRB4
Index: kdc/hprop.c
===================================================================
RCS file: /usr/tmp/heimdal/cvs/heimdal/kdc/hprop.c,v
retrieving revision 1.41
diff -u -r1.41 hprop.c
--- hprop.c	2000/03/03 12:35:48	1.41
+++ hprop.c	2000/06/09 23:36:31
@@ -302,9 +302,15 @@
     hdb.keys.val = malloc(hdb.keys.len * sizeof(*hdb.keys.val));
     hdb.keys.val[0].mkvno = NULL;
     hdb.keys.val[0].salt = calloc(1, sizeof(*hdb.keys.val[0].salt));
+#if 0
+    hdb.keys.val[0].salt->type = pa_pw_salt;
+    hdb.keys.val[0].salt->salt.data = strdup("");
+    hdb.keys.val[0].salt->salt.length = 0;
+#else
     hdb.keys.val[0].salt->type = hdb_afs3_salt;
     hdb.keys.val[0].salt->salt.data = strdup(cell);
     hdb.keys.val[0].salt->salt.length = strlen(cell);
+#endif
     
     hdb.keys.val[0].key.keytype = ETYPE_DES_CBC_MD5;
     krb5_data_copy(&hdb.keys.val[0].key.keyvalue, ent->key, sizeof(ent->key));
@@ -321,7 +327,8 @@
 	*hdb.valid_end = ntohl(ent->valid_end);
     }
     
-    if (ntohl(ent->pw_change) != NEVERDATE && ent->pw_expire != 255) {
+    if (ntohl(ent->pw_change) != NEVERDATE && 
+	(ent->pw_expire != 255) && (ent->pw_expire != 0)) {
 	ALLOC(hdb.pw_end);
 	*hdb.pw_end = ntohl(ent->pw_change)
 	    + 24 * 60 * 60 * ent->pw_expire;
Index: kdc/kerberos4.c
===================================================================
RCS file: /usr/tmp/heimdal/cvs/heimdal/kdc/kerberos4.c,v
retrieving revision 1.29
diff -u -r1.29 kerberos4.c
--- kerberos4.c	2000/06/07 09:53:39	1.29
+++ kerberos4.c	2000/06/08 21:23:52
@@ -109,13 +109,43 @@
 krb5_error_code
 get_des_key(hdb_entry *principal, Key **key)
 {
-    krb5_error_code ret;
+    krb5_error_code ret = 0;
 
-    ret = hdb_enctype2key(context, principal, ETYPE_DES_CBC_MD5, key);
-    if(ret)
-	ret = hdb_enctype2key(context, principal, ETYPE_DES_CBC_MD4, key);
-    if(ret)
-	ret = hdb_enctype2key(context, principal, ETYPE_DES_CBC_CRC, key);
+    if (krb5_config_get_bool (context,
+                              NULL, "kdc", "use_v4_salt", NULL)) {
+	ret = hdb_encsalt2key(context, principal, ETYPE_DES_CBC_MD5, 
+			      KRB5_PW_SALT, 0, key);
+	if(ret)
+	    ret = hdb_encsalt2key(context, principal, ETYPE_DES_CBC_MD4, 
+				  KRB5_PW_SALT, 0, key);
+	if(ret)
+	    ret = hdb_encsalt2key(context, principal, ETYPE_DES_CBC_CRC, 
+				  KRB5_PW_SALT, 0, key);
+    }
+    if (krb5_config_get_bool (context,
+                              NULL, "kdc", "use_afs3_salt", NULL)) {
+	if(ret)
+	    ret = hdb_encsalt2key(context, principal, ETYPE_DES_CBC_MD5, 
+				  KRB5_AFS3_SALT, 1, key);
+	if(ret)
+	    ret = hdb_encsalt2key(context, principal, ETYPE_DES_CBC_MD4, 
+				  KRB5_AFS3_SALT, 1, key);
+	if(ret)
+	    ret = hdb_encsalt2key(context, principal, ETYPE_DES_CBC_CRC, 
+				  KRB5_AFS3_SALT, 1, key);
+    }
+    if (!krb5_config_get_bool (context,
+                              NULL, "kdc", "no_v4_k5_salt", NULL)) {
+	if(ret)
+	    ret = hdb_encsalt2key(context, principal, ETYPE_DES_CBC_MD5, 
+				  0, 0, key);
+	if(ret)
+	    ret = hdb_encsalt2key(context, principal, ETYPE_DES_CBC_MD4, 
+				  0, 0, key);
+	if(ret)
+	    ret = hdb_encsalt2key(context, principal, ETYPE_DES_CBC_CRC, 
+				  0, 0, key);
+    }
     if(ret)
 	return ret;
     if ((*key)->key.keyvalue.length == 0)
Index: kdc/kerberos5.c
===================================================================
RCS file: /usr/tmp/heimdal/cvs/heimdal/kdc/kerberos5.c,v
retrieving revision 1.111
diff -u -r1.111 kerberos5.c
--- kerberos5.c	2000/03/11 03:27:36	1.111
+++ kerberos5.c	2000/06/08 18:57:09
@@ -87,12 +87,12 @@
     krb5_error_code ret;
     for(i = 0; i < num_etypes; i++) {
 	if(client){
-	    ret = hdb_enctype2key(context, client, etypes[i], ckey);
+	    ret = hdb_encsalt2key(context, client, etypes[i], 0, 0, ckey);
 	    if(ret)
 		continue;
 	}
 	if(server){
-	    ret = hdb_enctype2key(context, server, etypes[i], skey);
+	    ret = hdb_encsalt2key(context, server, etypes[i], 0, 0, skey);
 	    if(ret)
 		continue;
 	}
@@ -115,7 +115,7 @@
     for(i = 0; i < len ; i++) {
 	krb5_error_code tmp;
 
-	tmp = hdb_enctype2key(context, princ, etypes[i], key);
+	tmp = hdb_encsalt2key(context, princ, etypes[i], 0, 0, key);
 	if (tmp == 0) {
 	    if ((*key)->key.keyvalue.length != 0) {
 		ret = 0;
@@ -537,7 +537,8 @@
 		goto out;
 	    }
 	    
-	    ret = hdb_enctype2key(context, client, enc_data.etype, &pa_key);
+	    ret = hdb_encsalt2key(context, client, enc_data.etype, 0, 0, 
+				  &pa_key);
 	    if(ret){
 		char *estr;
 		e_text = "No key matches pa-data";
@@ -1379,7 +1380,8 @@
 	goto out2;
     }
 
-    ret = hdb_enctype2key(context, krbtgt, ap_req.ticket.enc_part.etype, &tkey);
+    ret = hdb_encsalt2key(context, krbtgt, ap_req.ticket.enc_part.etype, 
+			  0, 0, &tkey);
     if(ret){
 	char *str;
 	krb5_enctype_to_string(context, ap_req.ticket.enc_part.etype, &str);
@@ -1508,7 +1510,8 @@
 		ret = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN;
 		goto out;
 	    }
-	    ret = hdb_enctype2key(context, uu, t->enc_part.etype, &tkey);
+	    ret = hdb_encsalt2key(context, uu, t->enc_part.etype, 0, 0, 
+				  &tkey);
 	    if(ret){
 		ret = KRB5KDC_ERR_ETYPE_NOSUPP; /* XXX */
 		goto out;
Index: lib/hdb/hdb.c
===================================================================
RCS file: /usr/tmp/heimdal/cvs/heimdal/lib/hdb/hdb.c,v
retrieving revision 1.36
diff -u -r1.36 hdb.c
--- hdb.c	2000/04/05 03:35:10	1.36
+++ hdb.c	2000/06/08 21:21:36
@@ -61,9 +61,11 @@
 };
 
 krb5_error_code
-hdb_next_enctype2key(krb5_context context,
+hdb_next_encsalt2key(krb5_context context,
 		     hdb_entry *e,
 		     krb5_enctype enctype,
+		     krb5_salttype salttype,
+		     unsigned int saltlen,
 		     Key **key)
 {
     Key *k;
@@ -72,20 +74,29 @@
 	 k < e->keys.val + e->keys.len; 
 	 k++)
 	if(k->key.keytype == enctype){
-	    *key = k;
-	    return 0;
+	    if ((salttype == 0) ||
+		(!k->salt && ((salttype == KRB5_PW_SALT) && (saltlen == 0))) ||
+		((salttype == k->salt->type) && 
+		 ((salttype != KRB5_PW_SALT) ||
+		  (((saltlen == 0) && (k->salt->salt.length == 0)) ||
+		   ((saltlen > 0) && (k->salt->salt.length > 0)))))) {
+		*key = k;
+		return 0;
+	    }
 	}
     return KRB5_PROG_ETYPE_NOSUPP; /* XXX */
 }
 
 krb5_error_code
-hdb_enctype2key(krb5_context context, 
+hdb_encsalt2key(krb5_context context, 
 		hdb_entry *e, 
 		krb5_enctype enctype, 
+		krb5_salttype salttype,
+		unsigned int saltlen,
 		Key **key)
 {
     *key = NULL;
-    return hdb_next_enctype2key(context, e, enctype, key);
+    return hdb_next_encsalt2key(context, e, enctype, salttype, saltlen, key);
 }
 
 /* this is a bit ugly, but will get better when the crypto framework
Index: lib/hdb/hdb_locl.h
===================================================================
RCS file: /usr/tmp/heimdal/cvs/heimdal/lib/hdb/hdb_locl.h,v
retrieving revision 1.13
diff -u -r1.13 hdb_locl.h
--- hdb_locl.h	2000/02/06 05:17:05	1.13
+++ hdb_locl.h	2000/06/08 19:19:52
@@ -61,10 +61,10 @@
 #include <hdb.h>
 #include <hdb-private.h>
 
-#if defined(HAVE_DB_185_H)
-#include <db_185.h>
-#elif defined(HAVE_DB_H)
+#if defined(HAVE_DB_H)
 #include <db.h>
+#elif defined(HAVE_DB_185_H)
+#include <db_185.h>
 #endif
 
 #ifdef HAVE_NDBM_H
Index: lib/kadm5/set_keys.c
===================================================================
RCS file: /usr/tmp/heimdal/cvs/heimdal/lib/kadm5/set_keys.c,v
retrieving revision 1.19
diff -u -r1.19 set_keys.c
--- set_keys.c	2000/03/23 23:06:31	1.19
+++ set_keys.c	2000/06/08 22:13:47
@@ -95,58 +95,101 @@
 		const char *password)
 {
     kadm5_ret_t ret = 0;
-    int i;
-    unsigned len;
+    int i, j, numsalts;
+    unsigned len = 0;
     Key *keys;
-    krb5_salt salt;
+    krb5_salt v5salt, v4salt, afssalt, **salts, *salt;
     krb5_boolean v4_salt = FALSE;
+    krb5_boolean afs_salt = FALSE;
+    char *afscell = NULL;
 
-    len  = n_des_types + 1;
-    keys = malloc (len * sizeof(*keys));
-    if (keys == NULL)
-	return ENOMEM;
+    v5salt.salttype         = KRB5_PW_SALT;
+    v5salt.saltvalue.length = 0;
+    v5salt.saltvalue.data   = NULL;
+    numsalts = 1;
 
-    init_keys (keys, len);
-
-    salt.salttype         = KRB5_PW_SALT;
-    salt.saltvalue.length = 0;
-    salt.saltvalue.data   = NULL;
+    ret = krb5_get_pw_salt (context->context, ent->principal, &v5salt);
+    if (ret)
+	goto out;
 
     if (krb5_config_get_bool (context->context,
+			      NULL, "kadmin", "use_afs3_salt", NULL)) {
+	const char *cell = krb5_config_get_string (context->context, 
+						   NULL, "kadmin",
+						   "afs-cell", NULL);
+	if (cell) {
+	    afs_salt = TRUE;
+	    numsalts++;
+	    afscell = strdup(cell);
+	}
+    }
+    if (krb5_config_get_bool (context->context,
 			      NULL, "kadmin", "use_v4_salt", NULL)) {
 	v4_salt = TRUE;
-    } else {
-	ret = krb5_get_pw_salt (context->context, ent->principal, &salt);
-	if (ret)
-	    goto out;
+	numsalts++;
+    } 
+
+    salts = malloc (numsalts * sizeof(*salts));
+    if (salts == NULL)
+	return ENOMEM;
+
+    salts[0] = &v5salt;
+    i = 1;
+
+    if (afs_salt) {
+	    afssalt.saltvalue.data   = afscell;
+	    afssalt.salttype         = KRB5_AFS3_SALT;
+	    afssalt.saltvalue.length = strlen(afscell);
+	    salts[i++] = &afssalt;
     }
 
-    for (i = 0; i < n_des_types; ++i) {
-	ret = krb5_string_to_key_salt (context->context,
-				       des_types[i],
-				       password,
-				       salt,
-				       &keys[i].key);
-	if (ret)
-	    goto out;
-	if (v4_salt) {
-	    keys[i].salt = malloc (sizeof(*keys[i].salt));
-	    if (keys[i].salt == NULL) {
-		ret = ENOMEM;
-		goto out;
-	    }
-	    keys[i].salt->type = salt.salttype;
-	    ret = copy_octet_string (&salt.saltvalue, &keys[i].salt->salt);
+    if (v4_salt) {
+	v4salt.salttype         = KRB5_PW_SALT;
+	v4salt.saltvalue.length = 0;
+	v4salt.saltvalue.data   = NULL;
+	salts[i++] = &v4salt;
+    }
+
+    len  = (numsalts * n_des_types) + 1;
+    keys = malloc (len * sizeof(*keys));
+    if (keys == NULL)
+	return ENOMEM;
+
+    init_keys (keys, len);
+
+    for (j = 0; j < numsalts; ++j) {
+	salt = salts[j];
+	for (i = 0; i < n_des_types; ++i) {
+	    ret = krb5_string_to_key_salt (context->context,
+					   des_types[i],
+					   password,
+					   *salt,
+					   &keys[i+(j*n_des_types)].key);
 	    if (ret)
 		goto out;
-	}
+	    if ((salt->salttype == KRB5_AFS3_SALT) || 
+		((salt->salttype == KRB5_PW_SALT) && 
+		 (salt->saltvalue.length != 0))) {
+		keys[i+(j*n_des_types)].salt = 
+		    malloc (sizeof(*keys[i+(j*n_des_types)].salt));
+		if (keys[i+(j*n_des_types)].salt == NULL) {
+		    ret = ENOMEM;
+		    goto out;
+		}
+		keys[i+(j*n_des_types)].salt->type = salt->salttype;
+		ret = copy_octet_string (&salt->saltvalue, 
+					 &keys[i+(j*n_des_types)].salt->salt);
+		if (ret)
+		    goto out;
+	    }
+    }
     }
 
     ret = krb5_string_to_key (context->context,
 			      ETYPE_DES3_CBC_SHA1,
 			      password,
 			      ent->principal,
-			      &keys[n_des_types].key);
+			      &keys[n_des_types*numsalts].key);
     if (ret)
 	goto out;
 
@@ -156,7 +199,9 @@
     ent->kvno++;
     return ret;
 out:
-    krb5_data_free (&salt.saltvalue);
+    krb5_data_free (&v5salt.saltvalue);
+    if (afs_salt)
+	krb5_data_free (&afssalt.saltvalue);
     free_keys (context, len, keys);
     return ret;
 }