summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSam Hartman <hartmans@mit.edu>2003-03-17 01:03:11 +0000
committerSam Hartman <hartmans@mit.edu>2003-03-17 01:03:11 +0000
commiteeefea9966e50bf16af6e2df9e8b74d892598bef (patch)
treea90a9b3603e6fec48c0b7febcb26e0c83e01752f
parent1b190c9ac0a47f4dbd8db4a2e191758fc8d030f7 (diff)
downloadkrb5-eeefea9966e50bf16af6e2df9e8b74d892598bef.tar.gz
krb5-eeefea9966e50bf16af6e2df9e8b74d892598bef.tar.xz
krb5-eeefea9966e50bf16af6e2df9e8b74d892598bef.zip
Disable krb4 cross-realm in krb524d and krb5kdc. Provide an option to
reenable (-X) which prints a warning that you are creating a security hole. Remove support for generating krb4 tickets encrypted using 3DES service keys as it is insecure. They are still accepted however. The KDc is much more strict about accepting only tickets that it would have issued in the current configuration. In particular if the KDC would choose some enctype for writing a TGT, other enctypes will not be accepted when using a TGT. Ticket: 1385 Target_Version: 1.3 Tags: pullup git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@15286 dc483132-0cff-0310-8789-dd5450dbe970
-rw-r--r--src/kdc/ChangeLog13
-rw-r--r--src/kdc/kdc_util.h1
-rw-r--r--src/kdc/kerberos_v4.c129
-rw-r--r--src/kdc/main.c9
-rw-r--r--src/krb524/ChangeLog8
-rw-r--r--src/krb524/cnv_tkt_skey.c20
-rw-r--r--src/krb524/krb524d.c36
-rw-r--r--src/lib/kdb/ChangeLog8
-rw-r--r--src/lib/kdb/keytab.c47
9 files changed, 190 insertions, 81 deletions
diff --git a/src/kdc/ChangeLog b/src/kdc/ChangeLog
index eb4273615..040281988 100644
--- a/src/kdc/ChangeLog
+++ b/src/kdc/ChangeLog
@@ -1,3 +1,16 @@
+2003-03-16 Sam Hartman <hartmans@mit.edu>
+
+ * main.c (initialize_realms): Add support to call
+ enable_v4_crossrealm if the user wants insecure operation
+
+ * kerberos_v4.c: Add enable_v4_crossrealm. By default krb4
+ cross-realm is not allowed as it is insecure. Also, remove
+ support for generating krb4 tickets encrypted in 3DES as they are
+ insecure.
+
+ * kdc_util.h: Define enable_v4_crossrealm, new function to enable
+ secure krb4 cross-realm authentication
+
2003-03-05 Tom Yu <tlyu@mit.edu>
* main.c (init_realm): Update call to krb5_ktdb_resolve().
diff --git a/src/kdc/kdc_util.h b/src/kdc/kdc_util.h
index 9abe3b860..05ba07f4f 100644
--- a/src/kdc/kdc_util.h
+++ b/src/kdc/kdc_util.h
@@ -176,6 +176,7 @@ krb5_error_code process_v4 (const krb5_data *,
const krb5_fulladdr *,
krb5_data **);
void process_v4_mode (const char *, const char *);
+void enable_v4_crossrealm(char *);
#else
#define process_v4(foo,bar,quux,foobar) KRB5KRB_AP_ERR_BADVERSION
#endif
diff --git a/src/kdc/kerberos_v4.c b/src/kdc/kerberos_v4.c
index a87a1d5e5..01359792f 100644
--- a/src/kdc/kerberos_v4.c
+++ b/src/kdc/kerberos_v4.c
@@ -146,7 +146,7 @@ static krb5_data *response;
void kerberos_v4 (struct sockaddr_in *, KTEXT);
void kerb_err_reply (struct sockaddr_in *, KTEXT, long, char *);
-static int set_tgtkey (char *, krb5_kvno);
+static int set_tgtkey (char *, krb5_kvno, krb5_boolean);
/* Attributes converted from V5 to V4 - internal representation */
#define V4_KDB_REQUIRES_PREAUTH 0x1
@@ -180,6 +180,8 @@ static const struct v4mode_lookup_entry v4mode_table[] = {
static const int v4mode_table_nents = sizeof(v4mode_table)/
sizeof(v4mode_table[0]);
+static int allow_v4_crossrealm = 0;
+
void process_v4_mode(const char *program_name, const char *string)
{
int i, found;
@@ -205,6 +207,11 @@ void process_v4_mode(const char *program_name, const char *string)
return;
}
+void enable_v4_crossrealm ( char *programname) {
+ allow_v4_crossrealm = 1;
+ krb5_klog_syslog(LOG_ERR, "Enabling v4 cross-realm compatibility; this is a known security hole");
+}
+
krb5_error_code
process_v4(const krb5_data *pkt, const krb5_fulladdr *client_fulladdr,
krb5_data **resp)
@@ -382,6 +389,14 @@ compat_decrypt_key (krb5_key_data *in5, unsigned char *out4,
/* array of name-components + NULL ptr
*/
+/*
+ * Previously this code returned either a v4 key or a v5 key and you
+ * could tell from the enctype of the v5 key whether the v4 key was
+ * useful. Now we return both keys so the code can try both des3 and
+ * des decryption. We fail if the ticket doesn't have a v4 key.
+ * Also, note as a side effect, the v5 key is basically useless in
+ * the client case. It is still returned so the caller can free it.
+ */
static int
kerb_get_principal(char *name, char *inst, /* could have wild cards */
Principal *principal,
@@ -461,8 +476,28 @@ kerb_get_principal(char *name, char *inst, /* could have wild cards */
return(0);
}
} else {
- /* XXX yes I know this is a hardcoded search order */
- if (krb5_dbe_find_enctype(kdc_context, &entries,
+ if ( krb5_dbe_find_enctype(kdc_context, &entries,
+ ENCTYPE_DES_CBC_CRC,
+ KRB5_KDB_SALTTYPE_V4, kvno, &pkey) &&
+ krb5_dbe_find_enctype(kdc_context, &entries,
+ ENCTYPE_DES_CBC_CRC,
+ -1, kvno, &pkey)) {
+ lt = klog(L_KRB_PERR,
+ "KDC V4: failed to find key for %s.%s #%d",
+ name, inst, kvno);
+ krb5_db_free_principal(kdc_context, &entries, nprinc);
+ return(0);
+ }
+ }
+
+ if (!compat_decrypt_key(pkey, k, k5key, issrv)) {
+ memcpy( &principal->key_low, k, LONGLEN);
+ memcpy( &principal->key_high, (krb5_ui_4 *) k + 1, LONGLEN);
+ }
+ memset(k, 0, sizeof k);
+ if (issrv) {
+ krb5_free_keyblock_contents (kdc_context, k5key);
+ if (krb5_dbe_find_enctype(kdc_context, &entries,
ENCTYPE_DES3_CBC_RAW,
-1, kvno, &pkey) &&
krb5_dbe_find_enctype(kdc_context, &entries,
@@ -478,17 +513,16 @@ kerb_get_principal(char *name, char *inst, /* could have wild cards */
ENCTYPE_DES_CBC_CRC,
-1, kvno, &pkey)) {
lt = klog(L_KRB_PERR,
- "KDC V4: failed to find key for %s.%s #%d",
+ "KDC V4: failed to find key for %s.%s #%d (after having found it once)",
name, inst, kvno);
krb5_db_free_principal(kdc_context, &entries, nprinc);
return(0);
}
- }
+ compat_decrypt_key(pkey, k, k5key, issrv);
+ memset (k, 0, sizeof k);
+ }
+
- if (!compat_decrypt_key(pkey, k, k5key, issrv)) {
- memcpy( &principal->key_low, k, LONGLEN);
- memcpy( &principal->key_high, (krb5_ui_4 *) k + 1, LONGLEN);
- }
/*
* Convert v5's entries struct to v4's Principal struct:
* v5's time-unit for lifetimes is 1 sec, while v4 uses 5 minutes,
@@ -732,21 +766,14 @@ kerberos_v4(struct sockaddr_in *client, KTEXT pkt)
kdb_encrypt_key(key, key, master_key,
master_key_schedule, DECRYPT);
/* construct and seal the ticket */
- if (K4KDC_ENCTYPE_OK(k5key.enctype)) {
- krb_create_ticket(tk, k_flags, a_name_data.name,
- a_name_data.instance, local_realm,
- client_host.s_addr, (char *) session_key,
- lifetime, kerb_time.tv_sec,
- s_name_data.name, s_name_data.instance,
- key);
- } else {
- krb_cr_tkt_krb5(tk, k_flags, a_name_data.name,
- a_name_data.instance, local_realm,
- client_host.s_addr, (char *) session_key,
- lifetime, kerb_time.tv_sec,
- s_name_data.name, s_name_data.instance,
- &k5key);
- }
+ /* We always issue des tickets; the 3des tickets are a broken hack*/
+ krb_create_ticket(tk, k_flags, a_name_data.name,
+ a_name_data.instance, local_realm,
+ client_host.s_addr, (char *) session_key,
+ lifetime, kerb_time.tv_sec,
+ s_name_data.name, s_name_data.instance,
+ key);
+
krb5_free_keyblock_contents(kdc_context, &k5key);
memset(key, 0, sizeof(key));
memset(key_s, 0, sizeof(key_s));
@@ -826,8 +853,15 @@ kerberos_v4(struct sockaddr_in *client, KTEXT pkt)
strncpy(tktrlm, (char *)auth->dat + 3, REALM_SZ);
tktrlm[REALM_SZ-1] = '\0';
kvno = (krb5_kvno)auth->dat[2];
- if (set_tgtkey(tktrlm, kvno)) {
- lt = klog(L_ERR_UNK,
+ if ((!allow_v4_crossrealm)&&strcmp(tktrlm, local_realm) != 0) {
+ lt = klog(L_ERR_UNK,
+ "Cross realm ticket from %s denied by policy,", tktrlm);
+ kerb_err_reply(client, pkt,
+ KERB_ERR_PRINCIPAL_UNKNOWN, lt);
+ return;
+ }
+ if (set_tgtkey(tktrlm, kvno, 0)) {
+ lt = klog(L_ERR_UNK,
"FAILED set_tgtkey realm %s, kvno %d. Host: %s ",
tktrlm, kvno, inet_ntoa(client_host));
/* no better error code */
@@ -837,6 +871,19 @@ kerberos_v4(struct sockaddr_in *client, KTEXT pkt)
}
kerno = krb_rd_req(auth, "krbtgt", tktrlm, client_host.s_addr,
ad, 0);
+ if (kerno) {
+ if (set_tgtkey(tktrlm, kvno, 1)) {
+ lt = klog(L_ERR_UNK,
+ "FAILED 3des set_tgtkey realm %s, kvno %d. Host: %s ",
+ tktrlm, kvno, inet_ntoa(client_host));
+ /* no better error code */
+ kerb_err_reply(client, pkt,
+ KERB_ERR_PRINCIPAL_UNKNOWN, lt);
+ return;
+ }
+ kerno = krb_rd_req(auth, "krbtgt", tktrlm, client_host.s_addr,
+ ad, 0);
+ }
if (kerno) {
klog(L_ERR_UNK, "FAILED krb_rd_req from %s: %s",
@@ -913,21 +960,13 @@ kerberos_v4(struct sockaddr_in *client, KTEXT pkt)
des_new_random_key(session_key);
#endif
- if (K4KDC_ENCTYPE_OK(k5key.enctype)) {
- krb_create_ticket(tk, k_flags, ad->pname, ad->pinst,
- ad->prealm, client_host.s_addr,
- (char *) session_key, lifetime,
- kerb_time.tv_sec,
- s_name_data.name, s_name_data.instance,
- key);
- } else {
- krb_cr_tkt_krb5(tk, k_flags, ad->pname, ad->pinst,
- ad->prealm, client_host.s_addr,
- (char *) session_key, lifetime,
- kerb_time.tv_sec,
- s_name_data.name, s_name_data.instance,
- &k5key);
- }
+ /* ALways issue des tickets*/
+ krb_create_ticket(tk, k_flags, ad->pname, ad->pinst,
+ ad->prealm, client_host.s_addr,
+ (char *) session_key, lifetime,
+ kerb_time.tv_sec,
+ s_name_data.name, s_name_data.instance,
+ key);
krb5_free_keyblock_contents(kdc_context, &k5key);
memset(key, 0, sizeof(key));
memset(key_s, 0, sizeof(key_s));
@@ -1107,11 +1146,12 @@ check_princ(char *p_name, char *instance, int lifetime, Principal *p,
/* Set the key for krb_rd_req so we can check tgt */
static int
-set_tgtkey(char *r, krb5_kvno kvno)
+set_tgtkey(char *r, krb5_kvno kvno, krb5_boolean use_3des)
{
int n;
static char lastrealm[REALM_SZ] = "";
static int last_kvno = 0;
+ static krb5_boolean last_use_3des = 0;
static int more;
Principal p_st;
Principal *p = &p_st;
@@ -1119,7 +1159,7 @@ set_tgtkey(char *r, krb5_kvno kvno)
krb5_keyblock k5key;
k5key.contents = NULL;
- if (!strcmp(lastrealm, r) && last_kvno == kvno)
+ if (!strcmp(lastrealm, r) && last_kvno == kvno && last_use_3des == use_3des)
return (KSUCCESS);
/* log("Getting key for %s", r); */
@@ -1141,11 +1181,12 @@ set_tgtkey(char *r, krb5_kvno kvno)
return KFAILURE;
}
- if (!K4KDC_ENCTYPE_OK(k5key.enctype)) {
+ if (use_3des&&!K4KDC_ENCTYPE_OK(k5key.enctype)) {
krb_set_key_krb5(kdc_context, &k5key);
strncpy(lastrealm, r, sizeof(lastrealm) - 1);
lastrealm[sizeof(lastrealm) - 1] = '\0';
last_kvno = kvno;
+ last_use_3des = use_3des;
} else {
/* unseal tgt key from master key */
memcpy(key, &p->key_low, 4);
diff --git a/src/kdc/main.c b/src/kdc/main.c
index 3e5091cbf..5fb460b0a 100644
--- a/src/kdc/main.c
+++ b/src/kdc/main.c
@@ -551,7 +551,7 @@ setup_sam(void)
void
usage(char *name)
{
- fprintf(stderr, "usage: %s [-d dbpathname] [-r dbrealmname] [-R replaycachename ]\n\t[-m] [-k masterenctype] [-M masterkeyname] [-p port] [-4 v4mode] [-n]\n", name);
+ fprintf(stderr, "usage: %s [-d dbpathname] [-r dbrealmname] [-R replaycachename ]\n\t[-m] [-k masterenctype] [-M masterkeyname] [-p port] [-4 v4mode] [-X] [-n]\n", name);
return;
}
@@ -606,7 +606,7 @@ initialize_realms(krb5_context kcontext, int argc, char **argv)
* Loop through the option list. Each time we encounter a realm name,
* use the previously scanned options to fill in for defaults.
*/
- while ((c = getopt(argc, argv, "r:d:mM:k:R:e:p:s:n4:3")) != -1) {
+ while ((c = getopt(argc, argv, "r:d:mM:k:R:e:p:s:n4:X3")) != -1) {
switch(c) {
case 'r': /* realm name for db */
if (!find_realm_data(optarg, (krb5_ui_4) strlen(optarg))) {
@@ -662,6 +662,11 @@ initialize_realms(krb5_context kcontext, int argc, char **argv)
v4mode = strdup(optarg);
#endif
break;
+ case 'X':
+#ifdef KRB5_KRB4_COMPAT
+ enable_v4_crossrealm(argv[0]);
+#endif
+ break;
case '3':
#ifdef ATHENA_DES3_KLUDGE
if (krb5_enctypes_list[krb5_enctypes_length-1].etype
diff --git a/src/krb524/ChangeLog b/src/krb524/ChangeLog
index 2a7b6cc54..ba03cc0da 100644
--- a/src/krb524/ChangeLog
+++ b/src/krb524/ChangeLog
@@ -1,3 +1,11 @@
+2003-03-16 Sam Hartman <hartmans@mit.edu>
+
+ * krb524d.c (handle_classic_v4): Do not support 3des enctypes as
+ they are insecure. Also, by default do not allow krb4
+ cross-realm.
+
+ * cnv_tkt_skey.c (krb524_convert_tkt_skey): Don't support 3des tickets
+
2003-03-12 Ken Raeburn <raeburn@mit.edu>
* cnv_tkt_skey.c (krb524_convert_tkt_skey): Extract source IP
diff --git a/src/krb524/cnv_tkt_skey.c b/src/krb524/cnv_tkt_skey.c
index 595a1d392..3730ce43c 100644
--- a/src/krb524/cnv_tkt_skey.c
+++ b/src/krb524/cnv_tkt_skey.c
@@ -184,26 +184,8 @@ int krb524_convert_tkt_skey(context, v5tkt, v4tkt, v5_skey, v4_skey,
sname,
sinst,
v4_skey->contents);
- } else {
- /* Force enctype to be raw if using DES3. */
- if (v4_skey->enctype == ENCTYPE_DES3_CBC_SHA1 ||
- v4_skey->enctype == ENCTYPE_LOCAL_DES3_HMAC_SHA1)
- v4_skey->enctype = ENCTYPE_DES3_CBC_RAW;
- ret = krb524int_krb_cr_tkt_krb5(v4tkt,
- 0, /* flags */
- pname,
- pinst,
- prealm,
- sinp->sin_addr.s_addr,
- (char *) v5etkt->session->contents,
- lifetime,
- /* issue_data */
- server_time,
- sname,
- sinst,
- v4_skey);
}
-
+ else abort();
krb5_free_enc_tkt_part(context, v5etkt);
v5tkt->enc_part2 = NULL;
if (ret == KSUCCESS)
diff --git a/src/krb524/krb524d.c b/src/krb524/krb524d.c
index 4995b515f..0dce9cbc9 100644
--- a/src/krb524/krb524d.c
+++ b/src/krb524/krb524d.c
@@ -76,6 +76,7 @@ static int debug = 0;
void *handle = NULL;
int use_keytab, use_master;
+int allow_v4_crossrealm = 0;
char *keytab = NULL;
krb5_keytab kt;
@@ -137,7 +138,10 @@ int main(argc, argv)
config_params.mask = 0;
while (argc) {
- if (strncmp(*argv, "-k", 2) == 0)
+ if (strncmp(*argv, "-X", 2) == 0) {
+ allow_v4_crossrealm = 1;
+ }
+ else if (strncmp(*argv, "-k", 2) == 0)
use_keytab = 1;
else if (strncmp(*argv, "-m", 2) == 0)
use_master = 1;
@@ -524,19 +528,7 @@ handle_classic_v4 (krb5_context context, krb5_ticket *v5tkt,
&v5_service_key, NULL)))
goto error;
- if ((ret = lookup_service_key(context, v5tkt->server,
- ENCTYPE_DES3_CBC_RAW,
- 0, /* highest kvno */
- &v4_service_key, v4kvno)) &&
- (ret = lookup_service_key(context, v5tkt->server,
- ENCTYPE_LOCAL_DES3_HMAC_SHA1,
- 0,
- &v4_service_key, v4kvno)) &&
- (ret = lookup_service_key(context, v5tkt->server,
- ENCTYPE_DES3_CBC_SHA1,
- 0,
- &v4_service_key, v4kvno)) &&
- (ret = lookup_service_key(context, v5tkt->server,
+ if ( (ret = lookup_service_key(context, v5tkt->server,
ENCTYPE_DES_CBC_CRC,
0,
&v4_service_key, v4kvno)))
@@ -544,8 +536,19 @@ handle_classic_v4 (krb5_context context, krb5_ticket *v5tkt,
if (debug)
printf("service key retrieved\n");
+ if ((ret = krb5_decrypt_tkt_part(context, &v5_service_key, v5tkt))) {
+ goto error;
+ }
- ret = krb524_convert_tkt_skey(context, v5tkt, &v4tkt, &v5_service_key,
+ if (!(allow_v4_crossrealm || krb5_realm_compare(context, v5tkt->server,
+ v5tkt->enc_part2->client))) {
+ret = KRB5KDC_ERR_POLICY ;
+ goto error;
+ }
+ krb5_free_enc_tkt_part(context, v5tkt->enc_part2);
+ v5tkt->enc_part2= NULL;
+
+ ret = krb524_convert_tkt_skey(context, v5tkt, &v4tkt, &v5_service_key,
&v4_service_key,
(struct sockaddr_in *)saddr);
if (ret)
@@ -561,6 +564,9 @@ handle_classic_v4 (krb5_context context, krb5_ticket *v5tkt,
printf("v4 credentials encoded\n");
error:
+ if (v5tkt->enc_part2)
+ krb5_free_enc_tkt_part(context, v5tkt->enc_part2);
+
if(v5_service_key.contents)
krb5_free_keyblock_contents(context, &v5_service_key);
if (v4_service_key.contents)
diff --git a/src/lib/kdb/ChangeLog b/src/lib/kdb/ChangeLog
index d685be6d9..4592b4c19 100644
--- a/src/lib/kdb/ChangeLog
+++ b/src/lib/kdb/ChangeLog
@@ -1,3 +1,11 @@
+2003-03-16 Sam Hartman <hartmans@mit.edu>
+
+ * keytab.c (krb5_ktkdb_get_entry): Match only against the first
+ enctype for non-cross-realm tickets so we will only accept
+ tickets that the current configuration would have issued. For
+ cross-realm tickets be liberal and match against the specified
+ enctype.
+
2003-03-05 Tom Yu <tlyu@mit.edu>
* kdb_xdr.c (krb5_dbe_search_enctype): Check for ktype > 0 rather
diff --git a/src/lib/kdb/keytab.c b/src/lib/kdb/keytab.c
index 6ec375ac2..6a1dea152 100644
--- a/src/lib/kdb/keytab.c
+++ b/src/lib/kdb/keytab.c
@@ -24,10 +24,14 @@
* or implied warranty.
*
*/
+#include <string.h>
#include "k5-int.h"
#include "kdb_kt.h"
+static int
+is_xrealm_tgt(krb5_context, krb5_const_principal);
+
krb5_error_code krb5_ktkdb_close (krb5_context, krb5_keytab);
krb5_error_code krb5_ktkdb_get_entry (krb5_context, krb5_keytab, krb5_const_principal,
@@ -116,6 +120,8 @@ krb5_ktkdb_get_entry(in_context, id, principal, kvno, enctype, entry)
krb5_db_entry db_entry;
krb5_boolean more = 0;
int n = 0;
+ int xrealm_tgt = is_xrealm_tgt(context, principal);
+ int similar;
if (ktkdb_ctx)
context = ktkdb_ctx;
@@ -150,16 +156,31 @@ krb5_ktkdb_get_entry(in_context, id, principal, kvno, enctype, entry)
if (kerror)
goto error;
+ /* For cross realm tgts, we match whatever enctype is provided;
+ * for other principals, we only match the first enctype that is
+ * found. Since the TGS and AS code do the same thing, then we
+ * will only successfully decrypt tickets we have issued.*/
kerror = krb5_dbe_find_enctype(context, &db_entry,
- enctype, -1, kvno, &key_data);
+ xrealm_tgt?enctype:-1,
+ -1, kvno, &key_data);
if (kerror)
goto error;
+
kerror = krb5_dbekd_decrypt_key_data(context, master_key,
key_data, &entry->key, NULL);
if (kerror)
goto error;
+ kerror = krb5_c_enctype_compare(context, enctype, entry->key.enctype, &similar);
+ if (kerror)
+ goto error;
+
+ if (!similar) {
+ kerror = KRB5_KDB_NO_PERMITTED_KEY;
+ goto error;
+ }
+
/*
* Coerce the enctype of the output keyblock in case we got an
* inexact match on the enctype.
@@ -176,3 +197,27 @@ krb5_ktkdb_get_entry(in_context, id, principal, kvno, enctype, entry)
krb5_db_close_database(context);
return(kerror);
}
+
+/*
+ * is_xrealm_tgt: Returns true if the principal is a cross-realm TGT
+ * principal-- a principal with first component krbtgt and second
+ * component not equal to realm.
+ */
+static int
+is_xrealm_tgt(krb5_context context, krb5_const_principal princ)
+{
+ krb5_data *dat;
+ if (krb5_princ_size(context, princ) != 2)
+ return 0;
+ dat = krb5_princ_component(context, princ, 0);
+ if (strncmp("krbtgt", dat->data, dat->length) != 0)
+ return 0;
+ dat = krb5_princ_component(context, princ, 1);
+ if (dat->length != princ->realm.length)
+ return 1;
+ if (strcmp(dat->data, princ->realm.data) == 0)
+ return 0;
+ return 1;
+
+}
+