From 08caf16158c1e7e8ade82d9e9e48799e902ae109 Mon Sep 17 00:00:00 2001 From: ache Date: Wed, 21 Feb 1996 21:40:14 +0000 Subject: [PATCH] Fix weak random number hole Obtained from: CERT --- eBones/README.PATCH | 60 ++++++ eBones/usr.sbin/Makefile | 6 +- eBones/usr.sbin/fix_kdb_keys/Makefile | 10 + eBones/usr.sbin/fix_kdb_keys/fix_kdb_keys.c | 191 ++++++++++++++++++++ eBones/usr.sbin/kdb_edit/kdb_edit.c | 8 +- eBones/usr.sbin/kdb_init/kdb_init.c | 7 +- eBones/usr.sbin/kerberos/kerberos.c | 9 +- eBones/usr.sbin/ksrvutil/ksrvutil.c | 8 +- 8 files changed, 284 insertions(+), 15 deletions(-) create mode 100644 eBones/README.PATCH create mode 100644 eBones/usr.sbin/fix_kdb_keys/Makefile create mode 100644 eBones/usr.sbin/fix_kdb_keys/fix_kdb_keys.c diff --git a/eBones/README.PATCH b/eBones/README.PATCH new file mode 100644 index 000000000000..33cb15f09b1b --- /dev/null +++ b/eBones/README.PATCH @@ -0,0 +1,60 @@ +READ THIS ENTIRE FILE BEFORE PROCEEDING! + +This distribution contains a "diff" file suitable for using with the +"patch" program to update your Kerberos (version 4) source tree. The +gist of the patch is to replace calls to des_random_key() with calls +to des_new_random_key(). + +The primary difference is that des_random_key() uses a seeding +technique which is predictable and therefore +vulnerable. des_new_random_key() uses a feedback mechanism based on +the Data Encryption Standard (DES) and is seeded with a secret (and +therefore unknown to an attacker) value. This value is the database +master key, which is a convenient secret value. + +This patch assumes that you have the new_rnd_key.c key module (which +contains the definition and code for des_new_random_key()). It has +been part of the standard Version 4 distribution since 1992 and is +used in the admin server (our primary error at MIT was not upgrading +all of Kerberos to use this newer generator. This patch finishes the +job). + +In addition to the patch file for the Kerberos distribution this +distribution also contains a program for changing critical system keys +(namely the "krbtgt" and "changepw.kerberos" keys). When you +originally built your Kerberos database these keys were chosen at +random, using the vulnerable version of the kerberos random number +generator. Therefore it is possible for an attacker to mount an attack +to guess these values. If an attacker can determine the key for the +"krbtgt" ticket, they can construct tickets claiming to be any +kerberos principal. Similarly if an attacker can obtain the +"changepw.kerberos" key, they can change anyone's password. + +The enclosed "fix_kdb_keys.c" (part of the patch file) program, which +you run on the KDC server, will change these critical keys to new +values using the newer random number generator. IMPORTANT: When you +run fix_kdb_keys, all outstanding ticket granting tickets will +immediately become invalid. This will be disruptive to your user +community. We recommend that you either do this late at night or early +in the morning before most users have logged in. Alternatively +pre-announce a definitive time when you will run the program and +inform your users that they will have to get new tickets at that time +(using either "kinit" or simply by logging out and then in again). + +NOTE: The only client program modified is "ksrvutil" which is used to +generate new server keys. All other client/server programs are +unaffected. End users do *not* need to obtain new versions of programs +that use Kerberos. This is because most random number generation in +the Kerberos system is done on the KDC system. By fixing kerberos.c +you have repaired most of the damage. + +To install this patch copy patch_krb to the toplevel of your Kerberos +source tree. Then type: + +patch -p0 diff --git a/eBones/usr.sbin/fix_kdb_keys/Makefile b/eBones/usr.sbin/fix_kdb_keys/Makefile new file mode 100644 index 000000000000..6cbdd167e83d --- /dev/null +++ b/eBones/usr.sbin/fix_kdb_keys/Makefile @@ -0,0 +1,10 @@ +# From: @(#)Makefile 5.2 (Berkeley) 3/5/91 +# $Id: Makefile,v 1.7 1995/09/26 06:20:18 mark Exp $ + +PROG= fix_kdb_keys +CFLAGS+=-DKERBEROS -DDEBUG +DPADD= ${LIBKDB} ${LIBKRB} ${LIBDES} +LDADD= -L${KDBOBJDIR} -lkdb -L${KRBOBJDIR} -lkrb -L${DESOBJDIR} -ldes +NOMAN= YES + +.include diff --git a/eBones/usr.sbin/fix_kdb_keys/fix_kdb_keys.c b/eBones/usr.sbin/fix_kdb_keys/fix_kdb_keys.c new file mode 100644 index 000000000000..3719e784c854 --- /dev/null +++ b/eBones/usr.sbin/fix_kdb_keys/fix_kdb_keys.c @@ -0,0 +1,191 @@ +/* + * $Source: /afs/net/project/krb4/src/admin/RCS/kdb_edit.c,v $ + * $Author: tytso $ + * + * Copyright 1985, 1986, 1987, 1988 by the Massachusetts Institute + * of Technology. + * + * For copying and distribution information, please see the file + * . + * + * This routine changes the Kerberos encryption keys for principals, + * i.e., users or services. + */ + +/* + * exit returns 0 ==> success -1 ==> error + */ + +#include +#include +#include +#include +#include +#include +#include + +#ifdef NEED_TIME_H +#include +#endif +#include + +#include +#include +#include +/* MKEYFILE is now defined in kdc.h */ +#include + +char prog[32]; +char *progname = prog; +int nflag = 0; +int debug = 0; +extern int krb_debug; + +Principal principal_data; + +static C_Block master_key; +static Key_schedule master_key_schedule; +static long master_key_version; + +static char realm[REALM_SZ]; + +void fatal_error(), cleanup(); +void Usage(); +void change_principal(); + +int main(argc, argv) + int argc; + char *argv[]; +{ + int i; + + prog[sizeof prog - 1] = '\0'; /* make sure terminated */ + strncpy(prog, argv[0], sizeof prog - 1); /* salt away invoking + * program */ + + /* Assume a long is four bytes */ + if (sizeof(long) != 4) { + fprintf(stderr, "%s: size of long is %d.\n", prog, sizeof(long)); + exit(-1); + } + while (--argc > 0 && (*++argv)[0] == '-') + for (i = 1; argv[0][i] != '\0'; i++) { + switch (argv[0][i]) { + + /* debug flag */ + case 'd': + debug = 1; + continue; + + /* debug flag */ + case 'l': + krb_debug |= 1; + continue; + + case 'n': /* read MKEYFILE for master key */ + nflag = 1; + continue; + + default: + fprintf(stderr, "%s: illegal flag \"%c\"\n", progname, argv[0][i]); + Usage(); /* Give message and die */ + } + }; + + if (krb_get_lrealm(realm, 1)) { + fprintf(stderr, "Couldn't get local realm information.\n"); + fatal_error(); + } + + kerb_init(); + if (argc > 0) { + if (kerb_db_set_name(*argv) != 0) { + fprintf(stderr, "Could not open altername database name\n"); + fatal_error(); + } + } + + if (kdb_get_master_key ((nflag == 0), + master_key, master_key_schedule) != 0) { + fprintf (stderr, "Couldn't read master key.\n"); + fatal_error(); + } + + if ((master_key_version = kdb_verify_master_key(master_key, + master_key_schedule, + stdout)) < 0) + fatal_error(); + + des_init_random_number_generator(master_key); + + change_principal("krbtgt", realm); + change_principal("changepw", KRB_MASTER); + + cleanup(); + + printf("\nKerberos database updated successfully. Note that all\n"); + printf("existing ticket-granting tickets have been invalidated.\n\n"); + + return(0); +} + +void change_principal(input_name, input_instance) + char *input_name; + char *input_instance; +{ + int n, more; + C_Block new_key; + + n = kerb_get_principal(input_name, input_instance, &principal_data, + 1, &more); + if (!n) { + fprintf(stderr, "Can't find principal database for %s.%s.\n", + input_name, input_instance); + fatal_error(); + } + if (more) { + fprintf(stderr, "More than one entry for %s.%s.\n", input_name, + input_instance); + fatal_error(); + } + + des_new_random_key(new_key); + + /* seal it under the kerberos master key */ + kdb_encrypt_key (new_key, new_key, + master_key, master_key_schedule, + ENCRYPT); + memcpy(&principal_data.key_low, new_key, 4); + memcpy(&principal_data.key_high, ((long *) new_key) + 1, 4); + memset(new_key, 0, sizeof(new_key)); + + principal_data.key_version++; + + if (kerb_put_principal(&principal_data, 1)) { + fprintf(stderr, "\nError updating Kerberos database"); + fatal_error(); + } + + memset(&principal_data.key_low, 0, 4); + memset(&principal_data.key_high, 0, 4); +} + +void fatal_error() +{ + cleanup(); + exit(1); +} + +void cleanup() +{ + + memset(master_key, 0, sizeof(master_key)); + memset(master_key_schedule, 0, sizeof(master_key_schedule)); + memset(&principal_data, 0, sizeof(principal_data)); +} + +void Usage() +{ + fprintf(stderr, "Usage: %s [-n]\n", progname); + exit(1); +} diff --git a/eBones/usr.sbin/kdb_edit/kdb_edit.c b/eBones/usr.sbin/kdb_edit/kdb_edit.c index 82bf9a4e9972..eadbcf5300a5 100644 --- a/eBones/usr.sbin/kdb_edit/kdb_edit.c +++ b/eBones/usr.sbin/kdb_edit/kdb_edit.c @@ -8,7 +8,7 @@ * i.e., users or services. * * from: kdb_edit.c,v 4.2 90/01/09 16:05:09 raeburn Exp $ - * $Id: kdb_edit.c,v 1.5 1995/08/03 17:15:54 mark Exp $ + * $Id: kdb_edit.c,v 1.5 1995/09/07 21:37:17 markm Exp $ */ /* @@ -18,7 +18,7 @@ #if 0 #ifndef lint static char rcsid[] = -"$Id: kdb_edit.c,v 1.5 1995/08/03 17:15:54 mark Exp $"; +"$Id: kdb_edit.c,v 1.5 1995/09/07 21:37:17 markm Exp $"; #endif lint #endif @@ -173,6 +173,8 @@ main(argc, argv) stdout)) < 0) exit (-1); + des_init_random_number_generator(master_key); + /* lookup the default values */ n = kerb_get_principal(KERB_DEFAULT_NAME, KERB_DEFAULT_INST, &default_princ, 1, &more); @@ -282,7 +284,7 @@ change_principal() bzero(new_key, sizeof(C_Block)); new_key[0] = 127; #else - random_key(new_key); + des_new_random_key(new_key); /* yes, random */ #endif bzero(pw_str, sizeof pw_str); } diff --git a/eBones/usr.sbin/kdb_init/kdb_init.c b/eBones/usr.sbin/kdb_init/kdb_init.c index de99181d5c3b..42d1b1882377 100644 --- a/eBones/usr.sbin/kdb_init/kdb_init.c +++ b/eBones/usr.sbin/kdb_init/kdb_init.c @@ -7,13 +7,13 @@ * already exists. * * from: kdb_init.c,v 4.0 89/01/24 21:50:45 jtkohl Exp $ - * $Id: kdb_init.c,v 1.4 1995/07/18 16:37:35 mark Exp $ + * $Id: kdb_init.c,v 1.4 1995/09/07 21:37:20 markm Exp $ */ #if 0 #ifndef lint static char rcsid[] = -"$Id: kdb_init.c,v 1.4 1995/07/18 16:37:35 mark Exp $"; +"$Id: kdb_init.c,v 1.4 1995/09/07 21:37:20 markm Exp $"; #endif lint #endif @@ -97,6 +97,7 @@ main(argc, argv) fprintf (stderr, "Couldn't read master key.\n"); exit (-1); } + des_init_random_number_generator(master_key); if ( add_principal(KERB_M_NAME, KERB_M_INST, MASTER_KEY) || @@ -140,7 +141,7 @@ add_principal(name, instance, aap_op) bzero(new_key, sizeof(C_Block)); new_key[0] = 127; #else - random_key(new_key); + des_new_random_key(new_key); #endif kdb_encrypt_key (new_key, new_key, master_key, master_key_schedule, ENCRYPT); diff --git a/eBones/usr.sbin/kerberos/kerberos.c b/eBones/usr.sbin/kerberos/kerberos.c index a15475db6138..c30f6a175f87 100644 --- a/eBones/usr.sbin/kerberos/kerberos.c +++ b/eBones/usr.sbin/kerberos/kerberos.c @@ -5,13 +5,13 @@ * . * * from: kerberos.c,v 4.19 89/11/01 17:18:07 qjb Exp $ - * $Id: kerberos.c,v 1.4 1995/09/07 21:37:27 markm Exp $ + * $Id: kerberos.c,v 1.5 1995/09/17 00:39:00 gibbs Exp $ */ #if 0 #ifndef lint static char rcsid[] = -"$Id: kerberos.c,v 1.4 1995/09/07 21:37:27 markm Exp $"; +"$Id: kerberos.c,v 1.5 1995/09/17 00:39:00 gibbs Exp $"; #endif lint #endif @@ -269,6 +269,7 @@ main(argc, argv) bzero (master_key_schedule, sizeof (master_key_schedule)); exit (-1); } + des_init_random_number_generator(master_key); master_key_version = (u_char) kerror; @@ -434,7 +435,7 @@ kerberos(client, pkt) #ifdef NOENCRYPTION bzero(session_key, sizeof(C_Block)); #else - random_key(session_key); + des_new_random_key(session_key); #endif /* unseal server's key from master key */ bcopy(&s_name_data.key_low, key, 4); @@ -565,7 +566,7 @@ kerberos(client, pkt) #ifdef NOENCRYPTION bzero(session_key, sizeof(C_Block)); #else - random_key(session_key); + des_new_random_key(session_key); #endif krb_create_ticket(tk, k_flags, ad->pname, ad->pinst, diff --git a/eBones/usr.sbin/ksrvutil/ksrvutil.c b/eBones/usr.sbin/ksrvutil/ksrvutil.c index 1062ea5cc938..08fa9f5b881f 100644 --- a/eBones/usr.sbin/ksrvutil/ksrvutil.c +++ b/eBones/usr.sbin/ksrvutil/ksrvutil.c @@ -12,7 +12,7 @@ static char rcsid_ksrvutil_c[] = "BonesHeader: /afs/athena.mit.edu/astaff/project/kerberos/src/kadmin/RCS/ksrvutil.c,v 4.1 89/09/26 09:33:49 jtkohl Exp "; static const char rcsid[] = - "$Id: ksrvutil.c,v 1.1 1995/07/18 16:40:11 mark Exp $"; + "$Id: ksrvutil.c,v 1.5 1995/09/07 21:38:40 markm Exp $"; #endif lint #endif @@ -523,16 +523,20 @@ get_svc_new_key(new_key, sname, sinst, srealm, keyfile) char *keyfile; { int status = KADM_SUCCESS; + CREDENTIALS c; if (((status = krb_get_svc_in_tkt(sname, sinst, srealm, PWSERV_NAME, KADM_SINST, 1, keyfile)) == KSUCCESS) && + ((status = krb_get_cred(PWSERV_NAME, KADM_SINST, srealm, &c)) == + KSUCCESS) && ((status = kadm_init_link("changepw", KRB_MASTER, srealm)) == KADM_SUCCESS)) { #ifdef NOENCRYPTION bzero((char *) new_key, sizeof(des_cblock)); new_key[0] = (unsigned char) 1; #else /* NOENCRYPTION */ - des_random_key(new_key); + des_init_random_number_generator(c.session); + (void) des_new_random_key(new_key); #endif /* NOENCRYPTION */ return(KADM_SUCCESS); }