Skip Menu |
 

Download (untitled) / with headers
text/plain 14.1KiB
From fcusack@ratbert.iconnet.net Wed Dec 2 18:26:10 1998
Received: from MIT.EDU (SOUTH-STATION-ANNEX.MIT.EDU [18.72.1.2]) by rt-11.MIT.EDU (8.7.5/8.7.3) with SMTP id SAA14791 for <bugs@RT-11.MIT.EDU>; Wed, 2 Dec 1998 18:26:09 -0500
Received: from ratbert.iconnet.net by MIT.EDU with SMTP
id AA01025; Wed, 2 Dec 98 18:25:44 EST
Received: (from fcusack@localhost)
by ratbert.iconnet.net (8.9.1/8.9.1) id SAA12735;
Wed, 2 Dec 1998 18:26:54 -0500 (EST)
Message-Id: <199812022326.SAA12735@ratbert.iconnet.net>
Date: Wed, 2 Dec 1998 18:26:54 -0500 (EST)
From: fcusack@iconnet.net
Reply-To: fcusack@iconnet.net
To: krb5-bugs@MIT.EDU
Cc: fcusack@iconnet.net
Subject: SAM Replay detection + K/M integrity
X-Send-Pr-Version: 3.99

Show quoted text
>Number: 672
>Category: krb5-kdc
>Synopsis: gethostid() not portable; shouldn't encrypt sam-track-id w/ K/M
>Confidential: no
>Severity: serious
>Priority: medium
>Responsible: krb5-unassigned
>State: open
>Class: sw-bug
>Submitter-Id: unknown
>Arrival-Date: Wed Dec 02 18:27:00 EST 1998
>Last-Modified:
>Originator: Frank Cusack
>Organization:
Icon CMT Corp.
Show quoted text
>Release: krb5-current-19981119
>Environment:
N/A
System: SunOS ratbert 5.6 Generic_105181-09 sun4u sparc SUNW,Ultra-5_10
Architecture: sun4

Show quoted text
>Description:
A previous patch submitted by me adds a var kdc_id which is
the return value from gethostid(). This is used to prevent
replay of a sam-response to a KDC different than the one
that issued the sam-challenge.

But gethostid() isn't portable (unix only? and maybe not
all unices), and anyway, the sam-track-id had been
encrypted with the master database key. Probably not
too much of a risk doing this but it can provide a lot
of ciphertext for analysis. I don't believe any other code
uses K/M to encrypt anything that travels over the network.

This patch removes the kdc_id patch; and adds a var psr_key,
which is a random key generated at KDC startup. The psr_key
is used to encrypt the track-id instead of K/M. Since
each KDC will get a different key to encrypt the track-id with,
the "different KDC replay" is protected as a bonus.
The chance of key collision is extremely small, assuming
good randomness from krb5_c_make_random_key().

Show quoted text
>How-To-Repeat:
>Fix:
Index: include/k5-int.h
===================================================================
RCS file: /icon/d04/cvsroot/3rd-party/krb5-19981119/include/k5-int.h,v
retrieving revision 1.7
diff -u -r1.7 k5-int.h
--- k5-int.h 1998/12/02 03:10:56 1.7
+++ k5-int.h 1998/12/02 23:13:24
@@ -347,9 +347,8 @@
typedef struct _krb5_predicted_sam_response {
krb5_magic magic;
krb5_keyblock sam_key;
- krb5_int32 kdc_id; /* some magic to avoid esre replays */
- krb5_timestamp stime;
- krb5_int32 susec; /* more replay detection */
+ krb5_timestamp stime; /* for replay detection */
+ krb5_int32 susec;
krb5_data msd; /* mechanism specific data */
} krb5_predicted_sam_response;

Index: kdc/main.c
===================================================================
RCS file: /icon/d04/cvsroot/3rd-party/krb5-19981119/kdc/main.c,v
retrieving revision 1.3
diff -u -r1.3 main.c
--- main.c 1998/12/02 03:10:56 1.3
+++ main.c 1998/12/02 23:13:26
@@ -51,6 +51,9 @@

void setup_signal_handlers PROTOTYPE((void));

+krb5_keyblock psr_key;
+krb5_error_code setup_sam PROTOTYPE((void));
+
void initialize_realms PROTOTYPE((krb5_context, int, char **));

void finish_realms PROTOTYPE((char *));
@@ -59,7 +62,6 @@
static char *kdc_current_rcname = (char *) NULL;
static int rkey_init_done = 0;

-krb5_int32 kdc_id; /* hostid for SAM replay detection */
#ifdef USE_RCACHE
krb5_deltat rc_lifetime;
#endif /* USE_RCACHE */
@@ -586,6 +588,12 @@
return;
}

+krb5_error_code
+setup_sam()
+{
+ return krb5_c_make_random_key(kdc_context, ENCTYPE_DES_CBC_MD5, &psr_key);
+}
+
void
usage(name)
char *name;
@@ -821,7 +829,11 @@

setup_signal_handlers();

- kdc_id = gethostid();
+ if (retval = setup_sam()) {
+ com_err(argv[0], retval, "while initializing SAM");
+ finish_realms(argv[0]);
+ return 1;
+ }

if ((retval = setup_network(argv[0]))) {
com_err(argv[0], retval, "while initializing network");
Index: kdc/preauth/pa_sam.h
===================================================================
RCS file: /icon/d04/cvsroot/3rd-party/krb5-19981119/kdc/preauth/pa_sam.h,v
retrieving revision 1.4
diff -u -r1.4 pa_sam.h
--- pa_sam.h 1998/12/02 03:10:56 1.4
+++ pa_sam.h 1998/12/02 23:13:26
@@ -25,7 +25,8 @@

#include "k5-int.h"

-extern krb5_int32 kdc_id;
+extern krb5_keyblock psr_key;
+
#ifdef USE_RCACHE
extern krb5_deltat rc_lifetime;
#endif /* USE_RCACHE */
Index: kdc/preauth/pa_sam_cryptocard.c
===================================================================
RCS file: /icon/d04/cvsroot/3rd-party/krb5-19981119/kdc/preauth/pa_sam_cryptocard.c,v
retrieving revision 1.7
diff -u -r1.7 pa_sam_cryptocard.c
--- pa_sam_cryptocard.c 1998/12/02 03:10:56 1.7
+++ pa_sam_cryptocard.c 1998/12/02 23:13:26
@@ -244,7 +244,6 @@

/* Convert the SAD into a key. */
psr.magic = KV5M_PREDICTED_SAM_RESPONSE;
- psr.kdc_id = kdc_id;
#ifdef USE_RCACHE
/* XXX Watch these types when time_t or krb5_timestamp changes. */
if (retval = krb5_us_timeofday(context, &psr.stime, &psr.susec))
@@ -287,7 +286,7 @@
psr.msd.data = NULL;
psr.msd.length = 0;

- if (retval = krb5_c_encrypt_length(context, master_keyblock.enctype,
+ if (retval = krb5_c_encrypt_length(context, psr_key.enctype,
scratch->length, &enclen)) {
krb5_free_data(context, scratch);
goto cleanup;
@@ -301,7 +300,7 @@
tmpdata.ciphertext.length = enclen;
sc.sam_track_id = tmpdata.ciphertext; /* So we know to free it. */

- retval = krb5_c_encrypt(context, &master_keyblock,
+ retval = krb5_c_encrypt(context, &psr_key,
/* XXX */ 0, 0, scratch, &tmpdata);
krb5_free_data(context, scratch);
if (retval)
@@ -404,7 +403,7 @@

tmpdata.enctype = ENCTYPE_UNKNOWN;
tmpdata.ciphertext = sr->sam_track_id;
- if (retval = krb5_c_decrypt(context, &master_keyblock, /* XXX */ 0, 0,
+ if (retval = krb5_c_decrypt(context, &psr_key, /* XXX */ 0, 0,
&tmpdata, &scratch)) {
/* Record our retval, but let the client see a generic error. */
com_err("krb5kdc", retval, "decrypt track_id failed");
@@ -417,12 +416,6 @@
krb5_xfree(scratch.data);
if (retval) {
com_err("krb5kdc", retval, "decode_krb5_predicted_sam_response failed");
- goto cleanup;
- }
-
- if (psr->kdc_id != kdc_id) {
- com_err("krb5kdc", retval = KRB5KDC_ERR_PREAUTH_FAILED,
- "Warning - possible SAM replay attack!");
goto cleanup;
}

Index: kdc/preauth/pa_sam_digi_path.c
===================================================================
RCS file: /icon/d04/cvsroot/3rd-party/krb5-19981119/kdc/preauth/pa_sam_digi_path.c,v
retrieving revision 1.8
diff -u -r1.8 pa_sam_digi_path.c
--- pa_sam_digi_path.c 1998/12/02 22:05:29 1.8
+++ pa_sam_digi_path.c 1998/12/02 23:13:26
@@ -152,7 +152,6 @@

/* Convert the SAD into a key. */
psr.magic = KV5M_PREDICTED_SAM_RESPONSE;
- psr.kdc_id = kdc_id;
#ifdef USE_RCACHE
/* XXX Watch these types when time_t or krb5_timestamp changes. */
if (retval = krb5_us_timeofday(context, &psr.stime, &psr.susec))
@@ -187,7 +186,7 @@
if (retval = encode_krb5_predicted_sam_response(&psr, &scratch))
goto cleanup;

- if (retval = krb5_c_encrypt_length(context, master_keyblock.enctype,
+ if (retval = krb5_c_encrypt_length(context, psr_key.enctype,
scratch->length, &enclen)) {
krb5_free_data(context, scratch);
goto cleanup;
@@ -201,7 +200,7 @@
tmpdata.ciphertext.length = enclen;
sc.sam_track_id = tmpdata.ciphertext; /* So we know to free it. */

- retval = krb5_c_encrypt(context, &master_keyblock,
+ retval = krb5_c_encrypt(context, &psr_key,
/* XXX */ 0, 0, scratch, &tmpdata);
krb5_free_data(context, scratch);
if (retval)
@@ -303,7 +302,7 @@

tmpdata.enctype = ENCTYPE_UNKNOWN;
tmpdata.ciphertext = sr->sam_track_id;
- if (retval = krb5_c_decrypt(context, &master_keyblock, /* XXX */ 0, 0,
+ if (retval = krb5_c_decrypt(context, &psr_key, /* XXX */ 0, 0,
&tmpdata, &scratch)) {
/* Record our retval, but let the client see a generic error. */
com_err("krb5kdc", retval, "decrypt track_id failed");
@@ -316,12 +315,6 @@
krb5_xfree(scratch.data);
if (retval) {
com_err("krb5kdc", retval, "decode_krb5_predicted_sam_response failed");
- goto cleanup;
- }
-
- if (psr->kdc_id != kdc_id) {
- com_err("krb5kdc", retval = KRB5KDC_ERR_PREAUTH_FAILED,
- "Warning - possible SAM replay attack!");
goto cleanup;
}

Index: kdc/preauth/pa_sam_grail.c
===================================================================
RCS file: /icon/d04/cvsroot/3rd-party/krb5-19981119/kdc/preauth/pa_sam_grail.c,v
retrieving revision 1.5
diff -u -r1.5 pa_sam_grail.c
--- pa_sam_grail.c 1998/12/02 03:10:57 1.5
+++ pa_sam_grail.c 1998/12/02 23:13:26
@@ -69,7 +69,6 @@
sc.sam_challenge.length = strlen(sc.sam_challenge.data);

psr.magic = KV5M_PREDICTED_SAM_RESPONSE;
- psr.kdc_id = kdc_id;
#ifdef USE_RCACHE
/* XXX Watch these types when time_t or krb5_timestamp changes. */
if (retval = krb5_us_timeofday(context, &psr.stime, &psr.susec))
@@ -86,7 +85,7 @@
if (retval = encode_krb5_predicted_sam_response(&psr, &scratch))
goto cleanup;

- if (retval = krb5_c_encrypt_length(context, master_keyblock.enctype,
+ if (retval = krb5_c_encrypt_length(context, psr_key.enctype,
scratch->length, &enclen)) {
krb5_free_data(context, scratch);
goto cleanup;
@@ -100,7 +99,7 @@
tmpdata.ciphertext.length = enclen;
sc.sam_track_id = tmpdata.ciphertext; /* So we know to free it. */

- retval = krb5_c_encrypt(context, &master_keyblock,
+ retval = krb5_c_encrypt(context, &psr_key,
/* XXX */ 0, 0, scratch, &tmpdata);
krb5_free_data(context, scratch);
if (retval)
@@ -205,7 +204,7 @@

tmpdata.enctype = ENCTYPE_UNKNOWN;
tmpdata.ciphertext = sr->sam_track_id;
- if (retval = krb5_c_decrypt(context, &master_keyblock, /* XXX */ 0, 0,
+ if (retval = krb5_c_decrypt(context, &psr_key, /* XXX */ 0, 0,
&tmpdata, &scratch)) {
/* Record our retval, but let the client see a generic error. */
com_err("krb5kdc", retval, "decrypt track_id failed");
@@ -218,12 +217,6 @@
krb5_xfree(scratch.data);
if (retval) {
com_err("krb5kdc", retval, "decode_krb5_predicted_sam_response failed");
- goto cleanup;
- }
-
- if (psr->kdc_id != kdc_id) {
- com_err("krb5kdc", retval = KRB5KDC_ERR_PREAUTH_FAILED,
- "Warning - possible SAM replay attack!");
goto cleanup;
}

Index: kdc/preauth/pa_sam_securid.c
===================================================================
RCS file: /icon/d04/cvsroot/3rd-party/krb5-19981119/kdc/preauth/pa_sam_securid.c,v
retrieving revision 1.6
diff -u -r1.6 pa_sam_securid.c
--- pa_sam_securid.c 1998/12/02 03:10:57 1.6
+++ pa_sam_securid.c 1998/12/02 23:13:27
@@ -142,7 +142,6 @@
g_sc.sam_response_prompt.length = strlen(g_sc.sam_response_prompt.data);

psr.magic = KV5M_PREDICTED_SAM_RESPONSE;
- psr.kdc_id = kdc_id;
psr.msd.data = &g_sid_track_data;
psr.msd.length = sizeof(g_sid_track_data);
#ifdef USE_RCACHE
@@ -165,7 +164,7 @@
psr.msd.data = NULL;
psr.msd.length = 0;

- if (retval = krb5_c_encrypt_length(context, master_keyblock.enctype,
+ if (retval = krb5_c_encrypt_length(context, psr_key.enctype,
scratch->length, &enclen)) {
krb5_free_data(context, scratch);
goto cleanup;
@@ -179,7 +178,7 @@
tmpdata.ciphertext.length = enclen;
g_sc.sam_track_id = tmpdata.ciphertext; /* So we know to free it. */

- retval = krb5_c_encrypt(context, &master_keyblock,
+ retval = krb5_c_encrypt(context, &psr_key,
/* XXX */ 0, 0, scratch, &tmpdata);
krb5_free_data(context, scratch);
if (retval)
@@ -362,7 +361,7 @@

tmpdata.enctype = ENCTYPE_UNKNOWN;
tmpdata.ciphertext = sr->sam_track_id;
- if (retval = krb5_c_decrypt(context, &master_keyblock, /* XXX */ 0, 0,
+ if (retval = krb5_c_decrypt(context, &psr_key, /* XXX */ 0, 0,
&tmpdata, &scratch)) {
/* Record our retval, but let the client see a generic error. */
com_err("krb5kdc", retval, "decrypt track_id failed");
@@ -376,12 +375,6 @@
if (retval) {
com_err("krb5kdc", retval,
"decode_krb5_predicted_sam_response failed");
- goto cleanup;
- }
-
- if (psr->kdc_id != kdc_id) {
- com_err("krb5kdc", retval = KRB5KDC_ERR_PREAUTH_FAILED,
- "Warning - possible SAM replay attack!");
goto cleanup;
}

Index: lib/krb5/asn.1/asn1_k_decode.c
===================================================================
RCS file: /icon/d04/cvsroot/3rd-party/krb5-19981119/lib/krb5/asn.1/asn1_k_decode.c,v
retrieving revision 1.7
diff -u -r1.7 asn1_k_decode.c
--- asn1_k_decode.c 1998/12/02 03:10:57 1.7
+++ asn1_k_decode.c 1998/12/02 23:13:29
@@ -813,10 +813,9 @@
setup();
{ begin_structure();
get_field(val->sam_key,0,asn1_decode_encryption_key);
- get_field(val->kdc_id,1,asn1_decode_int32);
- opt_string(val->msd,2,asn1_decode_generalstring);
- get_field(val->stime,3,asn1_decode_kerberos_time);
- get_field(val->susec,4,asn1_decode_int32);
+ get_field(val->stime,1,asn1_decode_kerberos_time);
+ get_field(val->susec,2,asn1_decode_int32);
+ opt_string(val->msd,3,asn1_decode_octetstring);
end_structure();
val->magic = KV5M_PREDICTED_SAM_RESPONSE;
}
Index: lib/krb5/asn.1/asn1_k_encode.c
===================================================================
RCS file: /icon/d04/cvsroot/3rd-party/krb5-19981119/lib/krb5/asn.1/asn1_k_encode.c,v
retrieving revision 1.7
diff -u -r1.7 asn1_k_encode.c
--- asn1_k_encode.c 1998/12/02 03:10:57 1.7
+++ asn1_k_encode.c 1998/12/02 23:13:30
@@ -949,10 +949,9 @@
{
asn1_setup();

- asn1_addfield(val->susec,4,asn1_encode_integer);
- asn1_addfield(val->stime,3,asn1_encode_kerberos_time);
- add_optstring(val->msd,2,asn1_encode_generalstring);
- asn1_addfield(val->kdc_id,1,asn1_encode_integer);
+ add_optstring(val->msd,3,asn1_encode_octetstring);
+ asn1_addfield(val->susec,2,asn1_encode_integer);
+ asn1_addfield(val->stime,1,asn1_encode_kerberos_time);
asn1_addfield(&(val->sam_key),0,asn1_encode_encryption_key);

asn1_makeseq();
Show quoted text
>Audit-Trail:
>Unformatted: