Fix weak random number hole

Obtained from: CERT
This commit is contained in:
ache 1996-02-21 21:40:14 +00:00
parent 95238e0742
commit 08caf16158
8 changed files with 284 additions and 15 deletions

60
eBones/README.PATCH Normal file
View File

@ -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 <patch_krb
This will install changes to various kerberos modules to upgrade them
to use des_new_random_key(). It also will install a new program,
"fix_kdb_keys.c." After the patch is complete type "make world" at the
toplevel of your Kerberos source tree. This will, among other things,
build the fix_kdb_keys program.

View File

@ -1,7 +1,7 @@
# From: @(#)Makefile 5.1 (Berkeley) 6/25/90
# $Id$
# $Id: Makefile,v 1.1 1995/09/13 17:24:15 markm Exp $
SUBDIR= ext_srvtab kadmind kdb_destroy kdb_edit kdb_init kdb_util \
kerberos kprop ksrvutil kstash make_keypair
SUBDIR= ext_srvtab fix_kdb_keys kadmind kdb_destroy kdb_edit kdb_init \
kdb_util kerberos kprop ksrvutil kstash make_keypair
.include <bsd.subdir.mk>

View File

@ -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 <bsd.prog.mk>

View File

@ -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
* <mit-copyright.h>.
*
* This routine changes the Kerberos encryption keys for principals,
* i.e., users or services.
*/
/*
* exit returns 0 ==> success -1 ==> error
*/
#include <stdio.h>
#include <signal.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/file.h>
#ifdef NEED_TIME_H
#include <time.h>
#endif
#include <sys/time.h>
#include <des.h>
#include <krb.h>
#include <krb_db.h>
/* MKEYFILE is now defined in kdc.h */
#include <kdc.h>
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);
}

View File

@ -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);
}

View File

@ -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);

View File

@ -5,13 +5,13 @@
* <Copyright.MIT>.
*
* 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,

View File

@ -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);
}