From cd03be26f1019467b1be10b4f2b2b75265e94aff Mon Sep 17 00:00:00 2001 From: Theodore Tso Date: Tue, 19 Mar 1996 02:33:21 +0000 Subject: [PATCH] Mon Mar 18 20:56:37 1996 Theodore Y. Ts'o * kerberos5.c (kerberos5_send): Send in as input the authentication type pair (ap->type, ap->way) to be checksumed in the authenticator. (kerberos5_is): If the checksum is present in the authenticator, then validate the authentication type pair against the checksum. (kerberos5_reply): If we didn't do mutual authentication, and we receive a KRB_ACCEPT, then stash away the session key anyway. This way we have a chance of doing encryption even if mutual authentication wasn't done. * encrypt.c (EncryptStartInput, EncryptStartOutput): Added conditional around printf so that these two functions can be called by the server. (encrypt_is_encrypting): New function which returns true only if both sides of the telnet stream is encrypted. Fri Mar 15 18:19:44 1996 Theodore Y. Ts'o * auth.c: Added new authentication scheme for Krb5 mutual authentication with mandatory encryption. (auth_send, auth_send_retry): Split auth_send() so that the functionality done by auth_send_retry() is separate. This avoids a really dodgy pointer comparison which was caused by auth_send() being used for two purposes. If the client has not requested encryption, then don't use the authentication systems which require encryption. (auth_must_encrypt): New function which returns whether or not encryption must be negotiated. * auth-proto.h: Added prototype for new option auth_must_encrypt(). * Makefile.in (ENCRYPTION, DES_ENCRYPTION): Added defines to turn on encryption and des encryption. git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@7661 dc483132-0cff-0310-8789-dd5450dbe970 --- src/appl/telnet/libtelnet/ChangeLog | 38 ++++++ src/appl/telnet/libtelnet/Makefile.in | 3 +- src/appl/telnet/libtelnet/auth-proto.h | 1 + src/appl/telnet/libtelnet/auth.c | 131 +++++++++++--------- src/appl/telnet/libtelnet/enc-proto.h | 1 + src/appl/telnet/libtelnet/encrypt.c | 23 ++-- src/appl/telnet/libtelnet/kerberos5.c | 162 ++++++++++++++++++------- 7 files changed, 246 insertions(+), 113 deletions(-) diff --git a/src/appl/telnet/libtelnet/ChangeLog b/src/appl/telnet/libtelnet/ChangeLog index eca0bd655..391cd7166 100644 --- a/src/appl/telnet/libtelnet/ChangeLog +++ b/src/appl/telnet/libtelnet/ChangeLog @@ -1,3 +1,41 @@ +Mon Mar 18 20:56:37 1996 Theodore Y. Ts'o + + * kerberos5.c (kerberos5_send): Send in as input the + authentication type pair (ap->type, ap->way) to be + checksumed in the authenticator. + (kerberos5_is): If the checksum is present in the + authenticator, then validate the authentication type pair + against the checksum. + (kerberos5_reply): If we didn't do mutual authentication, + and we receive a KRB_ACCEPT, then stash away the session + key anyway. This way we have a chance of doing encryption + even if mutual authentication wasn't done. + + * encrypt.c (EncryptStartInput, EncryptStartOutput): Added + conditional around printf so that these two functions can + be called by the server. + (encrypt_is_encrypting): New function which returns true + only if both sides of the telnet stream is encrypted. + +Fri Mar 15 18:19:44 1996 Theodore Y. Ts'o + + * auth.c: Added new authentication scheme for Krb5 mutual + authentication with mandatory encryption. + (auth_send, auth_send_retry): Split auth_send() so that + the functionality done by auth_send_retry() is separate. + This avoids a really dodgy pointer comparison which was + caused by auth_send() being used for two purposes. + If the client has not requested encryption, then don't + use the authentication systems which require encryption. + (auth_must_encrypt): New function which returns whether + or not encryption must be negotiated. + + * auth-proto.h: Added prototype for new option + auth_must_encrypt(). + + * Makefile.in (ENCRYPTION, DES_ENCRYPTION): Added defines to turn + on encryption and des encryption. + Fri Jan 26 01:05:46 1996 Sam Hartman * kerberos5.c (kerberos5_send): Get DES_CBC-CRC credentials. diff --git a/src/appl/telnet/libtelnet/Makefile.in b/src/appl/telnet/libtelnet/Makefile.in index bc9d47aba..d0af781c8 100644 --- a/src/appl/telnet/libtelnet/Makefile.in +++ b/src/appl/telnet/libtelnet/Makefile.in @@ -19,7 +19,8 @@ # # @(#)Makefile.generic 5.5 (Berkeley) 3/1/91 # -AUTH_DEF=-DAUTHENTICATION -DKRB5 -DFORWARD -UNO_LOGIN_F -DLOGIN_CAP_F -DLOGIN_PROGRAM=KRB5_PATH_LOGIN +AUTH_DEF=-DAUTHENTICATION -DENCRYPTION -DDES_ENCRYPTION -DKRB5 -DFORWARD \ + -UNO_LOGIN_F -DLOGIN_CAP_F -DLOGIN_PROGRAM=KRB5_PATH_LOGIN LOCALINCLUDES=-I.. -I$(srcdir)/.. -I$(SRCTOP)/include/kerberosIV CFLAGS = $(CCOPTS) $(AUTH_DEF) $(DEFS) $(LOCALINCLUDES) LIBOBJS=@LIBOBJS@ diff --git a/src/appl/telnet/libtelnet/auth-proto.h b/src/appl/telnet/libtelnet/auth-proto.h index b93c9c266..c14f6ed06 100644 --- a/src/appl/telnet/libtelnet/auth-proto.h +++ b/src/appl/telnet/libtelnet/auth-proto.h @@ -73,6 +73,7 @@ void auth_is P((unsigned char *, int)); void auth_reply P((unsigned char *, int)); void auth_finished P((Authenticator *, int)); int auth_wait P((char *)); +int auth_must_encrypt P((void)); void auth_disable_name P((char *)); void auth_gen_printsub P((unsigned char *, int, unsigned char *, int)); diff --git a/src/appl/telnet/libtelnet/auth.c b/src/appl/telnet/libtelnet/auth.c index dc54fb07a..50a6ae79f 100644 --- a/src/appl/telnet/libtelnet/auth.c +++ b/src/appl/telnet/libtelnet/auth.c @@ -95,6 +95,8 @@ extern rsaencpwd_printsub(); #endif int auth_debug_mode = 0; +int auth_has_failed = 0; +int auth_enable_encrypt = 0; static char *Name = "Noname"; static int Server = 0; static Authenticator *authenticated = 0; @@ -126,6 +128,16 @@ Authenticator authenticators[] = { spx_printsub }, #endif #ifdef KRB5 +#ifdef ENCRYPTION + { AUTHTYPE_KERBEROS_V5, + AUTH_WHO_CLIENT|AUTH_HOW_MUTUAL|AUTH_ENCRYPT_ON, + kerberos5_init, + kerberos5_send, + kerberos5_is, + kerberos5_reply, + kerberos5_status, + kerberos5_printsub }, +#endif { AUTHTYPE_KERBEROS_V5, AUTH_WHO_CLIENT|AUTH_HOW_MUTUAL, kerberos5_init, kerberos5_send, @@ -387,10 +399,6 @@ auth_send(data, cnt) unsigned char *data; int cnt; { - Authenticator *ap; - static unsigned char str_none[] = { IAC, SB, TELOPT_AUTHENTICATION, - TELQUAL_IS, AUTHTYPE_NULL, 0, - IAC, SE }; if (Server) { if (auth_debug_mode) { printf(">>>%s: auth_send called!\r\n", Name); @@ -404,63 +412,68 @@ auth_send(data, cnt) } /* - * Save the data, if it is new, so that we can continue looking - * at it if the authorization we try doesn't work + * Save the list of authentication mechanisms */ - /* ANSI X3.159-1989 section 3.3.6 indicates that this entire - conditional is undefined. It will probably work on flat address - space UNIX systems though. --eichin@mit.edu */ - if (data < _auth_send_data || - data > _auth_send_data + sizeof(_auth_send_data)) { - auth_send_cnt = cnt > sizeof(_auth_send_data) - ? sizeof(_auth_send_data) - : cnt; - memcpy((void *)_auth_send_data, (void *)data, auth_send_cnt); - auth_send_data = _auth_send_data; - } else { + auth_send_cnt = cnt; + if (auth_send_cnt > sizeof(_auth_send_data)) + auth_send_cnt = sizeof(_auth_send_data); + memcpy((void *)_auth_send_data, (void *)data, auth_send_cnt); + auth_send_data = _auth_send_data; + + auth_send_retry(); +} + +/* + * Try the next authentication mechanism on the list, and see if it + * works. + */ +void auth_send_retry() +{ + Authenticator *ap; + static unsigned char str_none[] = { IAC, SB, TELOPT_AUTHENTICATION, + TELQUAL_IS, AUTHTYPE_NULL, 0, + IAC, SE }; + + if (Server) { + if (auth_debug_mode) { + printf(">>>%s: auth_send_retry called!\r\n", Name); + } + return; + } + + for (;(auth_send_cnt -= 2) >= 0; auth_send_data += 2) { + if (auth_debug_mode) + printf(">>>%s: He supports %d\r\n", Name, *auth_send_data); + if (!(i_support & typemask(*auth_send_data))) + continue; + if (i_wont_support & typemask(*auth_send_data)) + continue; + ap = findauthenticator(auth_send_data[0], auth_send_data[1]); + if (!ap || !ap->send) + continue; + if ((ap->way & AUTH_ENCRYPT_MASK) && !auth_enable_encrypt) + continue; + + if (auth_debug_mode) + printf(">>>%s: Trying %d %d\r\n", Name, auth_send_data[0], + auth_send_data[1]); + if ((*ap->send)(ap)) { /* - * This is probably a no-op, but we just make sure + * Okay, we found one we like and did it. we can go + * home now. */ - auth_send_data = data; - auth_send_cnt = cnt; - } - while ((auth_send_cnt -= 2) >= 0) { if (auth_debug_mode) - printf(">>>%s: He supports %d\r\n", - Name, *auth_send_data); - if ((i_support & ~i_wont_support) & typemask(*auth_send_data)) { - ap = findauthenticator(auth_send_data[0], - auth_send_data[1]); - if (ap && ap->send) { - if (auth_debug_mode) - printf(">>>%s: Trying %d %d\r\n", - Name, auth_send_data[0], - auth_send_data[1]); - if ((*ap->send)(ap)) { - /* - * Okay, we found one we like - * and did it. - * we can go home now. - */ - if (auth_debug_mode) - printf(">>>%s: Using type %d\r\n", - Name, *auth_send_data); - auth_send_data += 2; - return; - } - } - /* else - * just continue on and look for the - * next one if we didn't do anything. - */ - } + printf(">>>%s: Using type %d\r\n", Name, *auth_send_data); auth_send_data += 2; + return; + } } net_write(str_none, sizeof(str_none)); printsub('>', &str_none[2], sizeof(str_none) - 2); if (auth_debug_mode) printf(">>>%s: Sent failure message\r\n", Name); auth_finished(0, AUTH_REJECT); + auth_has_failed = 1; #ifdef KANNAN /* * We requested strong authentication, however no mechanisms worked. @@ -471,16 +484,6 @@ auth_send(data, cnt) #endif /* KANNAN */ } - void -auth_send_retry() -{ - /* - * if auth_send_cnt <= 0 then auth_send will end up rejecting - * the authentication and informing the other side of this. - */ - auth_send(auth_send_data, auth_send_cnt); -} - void auth_is(data, cnt) unsigned char *data; @@ -621,6 +624,14 @@ auth_wait(name) return(validuser); } +int auth_must_encrypt() +{ + if (authenticated && + ((authenticated->way & AUTH_ENCRYPT_MASK) == AUTH_ENCRYPT_ON)) + return 1; + return 0; +} + void auth_debug(mode) int mode; diff --git a/src/appl/telnet/libtelnet/enc-proto.h b/src/appl/telnet/libtelnet/enc-proto.h index d5f31d607..996a4f5d0 100644 --- a/src/appl/telnet/libtelnet/enc-proto.h +++ b/src/appl/telnet/libtelnet/enc-proto.h @@ -77,6 +77,7 @@ void encrypt_send_request_start P((void)); void encrypt_send_request_end P((void)); void encrypt_send_end P((void)); void encrypt_wait P((void)); +int encrypt_is_encrypting P((void)); void encrypt_send_support P((void)); void encrypt_send_keyid P((int, unsigned char *, int, int)); int net_write P((unsigned char *, int)); diff --git a/src/appl/telnet/libtelnet/encrypt.c b/src/appl/telnet/libtelnet/encrypt.c index 4a539b92b..15f2a88b2 100644 --- a/src/appl/telnet/libtelnet/encrypt.c +++ b/src/appl/telnet/libtelnet/encrypt.c @@ -332,7 +332,8 @@ EncryptStartInput() encrypt_send_request_start(); return(1); } - printf("No previous decryption mode, decryption not enabled\r\n"); + if (!Server) + printf("No previous decryption mode, decryption not enabled\r\n"); return(0); } @@ -343,7 +344,8 @@ EncryptStartOutput() encrypt_start_output(encrypt_mode); return(1); } - printf("No previous encryption mode, encryption not enabled\r\n"); + if (!Server) + printf("No previous encryption mode, encryption not enabled\r\n"); return(0); } @@ -723,27 +725,28 @@ encrypt_request_start(data, cnt) static unsigned char str_keyid[(MAXKEYLEN*2)+5] = { IAC, SB, TELOPT_ENCRYPT }; -encrypt_enc_keyid(keyid, len) +void encrypt_keyid(); + +void encrypt_enc_keyid(keyid, len) unsigned char *keyid; int len; { encrypt_keyid(&ki[1], keyid, len); } -encrypt_dec_keyid(keyid, len) +void encrypt_dec_keyid(keyid, len) unsigned char *keyid; int len; { encrypt_keyid(&ki[0], keyid, len); } -encrypt_keyid(kp, keyid, len) +void encrypt_keyid(kp, keyid, len) struct key_info *kp; unsigned char *keyid; int len; { Encryptions *ep; - unsigned char *strp, *cp; int dir = kp->dir; register int ret = 0; @@ -939,7 +942,6 @@ encrypt_send_request_end() void encrypt_wait() { - register int encrypt, decrypt; if (encrypt_debug_mode) printf(">>>%s: in encrypt_wait\r\n", Name); if (!havesessionkey || !(I_SUPPORT_ENCRYPT & remote_supports_decrypt)) @@ -949,6 +951,13 @@ encrypt_wait() return; } +int encrypt_is_encrypting() +{ + if (encrypt_output && decrypt_input) + return 1; + return 0; +} + void encrypt_debug(mode) int mode; diff --git a/src/appl/telnet/libtelnet/kerberos5.c b/src/appl/telnet/libtelnet/kerberos5.c index 523657a22..6f947e357 100644 --- a/src/appl/telnet/libtelnet/kerberos5.c +++ b/src/appl/telnet/libtelnet/kerberos5.c @@ -188,6 +188,8 @@ kerberos5_send(ap) krb5_creds creds; /* telnet gets session key from here */ krb5_creds * new_creds = 0; int ap_opts; + char type_check[2]; + krb5_data check_data; #ifdef ENCRYPTION krb5_keyblock *newkey = 0; @@ -259,34 +261,47 @@ kerberos5_send(ap) ap_opts |= AP_OPTS_USE_SUBKEY; #endif /* ENCRYPTION */ - if ((r = krb5_auth_con_init(telnet_context, &auth_context))) { - if (auth_debug_mode) { - printf("Kerberos V5: failed to init auth_context (%s)\r\n", - error_message(r)); + if (auth_context) { + krb5_auth_con_free(telnet_context, auth_context); + auth_context = 0; } - return(0); - } - - krb5_auth_con_setflags(telnet_context, auth_context, - KRB5_AUTH_CONTEXT_RET_TIME); - - r = krb5_mk_req_extended(telnet_context, &auth_context, ap_opts, - NULL, new_creds, &auth); + if ((r = krb5_auth_con_init(telnet_context, &auth_context))) { + if (auth_debug_mode) { + printf("Kerberos V5: failed to init auth_context (%s)\r\n", + error_message(r)); + } + return(0); + } + + krb5_auth_con_setflags(telnet_context, auth_context, + KRB5_AUTH_CONTEXT_RET_TIME); + + type_check[0] = ap->type; + type_check[1] = ap->way; + check_data.magic = KV5M_DATA; + check_data.length = 2; + check_data.data = (char *) &type_check; + + r = krb5_mk_req_extended(telnet_context, &auth_context, ap_opts, + &check_data, new_creds, &auth); #ifdef ENCRYPTION krb5_auth_con_getlocalsubkey(telnet_context, auth_context, &newkey); if (session_key) { -krb5_free_keyblock(telnet_context, session_key); -session_key = 0; + krb5_free_keyblock(telnet_context, session_key); + session_key = 0; } if (newkey) { /* keep the key in our private storage, but don't use it yet---see kerberos5_reply() below */ - if ((newkey->enctype != ENCTYPE_DES_CBC_CRC) && (newkey-> enctype != ENCTYPE_DES_CBC_MD5)) { - if ((new_creds->keyblock.enctype == ENCTYPE_DES_CBC_CRC)||( new_creds->keyblock.enctype == ENCTYPE_DES_CBC_MD5)) + if ((newkey->enctype != ENCTYPE_DES_CBC_CRC) && + (newkey-> enctype != ENCTYPE_DES_CBC_MD5)) { + if ((new_creds->keyblock.enctype == ENCTYPE_DES_CBC_CRC) || + (new_creds->keyblock.enctype == ENCTYPE_DES_CBC_MD5)) /* use the session key in credentials instead */ - krb5_copy_keyblock(telnet_context,&new_creds->keyblock, &session_key); + krb5_copy_keyblock(telnet_context,&new_creds->keyblock, + &session_key); else /* XXX ? */; } else { @@ -334,9 +349,11 @@ kerberos5_is(ap, data, cnt) #ifdef ENCRYPTION Session_Key skey; #endif + char errbuf[128]; char *name; char *getenv(); krb5_data inbuf; + krb5_authenticator *authenticator; if (cnt-- < 1) return; @@ -370,21 +387,61 @@ kerberos5_is(ap, data, cnt) krb5_free_principal(telnet_context, server); } if (r) { - char errbuf[128]; - - errout: - (void) strcpy(errbuf, "Read req failed: "); + (void) strcpy(errbuf, "krb5_rd_req failed: "); (void) strcat(errbuf, error_message(r)); - Data(ap, KRB_REJECT, errbuf, -1); - if (auth_debug_mode) - printf("%s\r\n", errbuf); - return; + goto errout; + } + r = krb5_auth_con_getauthenticator(telnet_context, + auth_context, + &authenticator); + if (r) { + (void) strcpy(errbuf, + "krb5_auth_con_getauthenticator failed: "); + (void) strcat(errbuf, error_message(r)); + goto errout; + } + if ((ap->way & AUTH_ENCRYPT_MASK) == AUTH_ENCRYPT_ON && + !authenticator->checksum) { + (void) strcpy(errbuf, + "authenticator is missing required checksum"); + goto errout; + } + if (authenticator->checksum) { + char type_check[2]; + krb5_checksum *cksum = authenticator->checksum; + krb5_keyblock *key; + + type_check[0] = ap->type; + type_check[1] = ap->way; + + r = krb5_auth_con_getkey(telnet_context, auth_context, + &key); + if (r) { + (void) strcpy(errbuf, "krb5_auth_con_getkey failed: "); + (void) strcat(errbuf, error_message(r)); + goto errout; + } + r = krb5_verify_checksum(telnet_checksum, + cksum->checksum_type, cksum, + &type_check, 2, key->contents, + key->length); + if (r) { + (void) strcpy(errbuf, + "checksum verification failed: "); + (void) strcat(errbuf, error_message(r)); + goto errout; + } + krb5_free_keyblock(telnet_context, key); } + krb5_free_authenticator(telnet_context, authenticator); if ((ap->way & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) { /* do ap_rep stuff here */ if ((r = krb5_mk_rep(telnet_context, auth_context, - &outbuf))) + &outbuf))) { + (void) strcpy(errbuf, "Make reply failed: "); + (void) strcat(errbuf, error_message(r)); goto errout; + } Data(ap, KRB_RESPONSE, outbuf.data, outbuf.length); } @@ -403,23 +460,17 @@ kerberos5_is(ap, data, cnt) free(name); krb5_auth_con_getremotesubkey(telnet_context, auth_context, &newkey); + if (session_key) { + krb5_free_keyblock(telnet_context, session_key); + session_key = 0; + } if (newkey) { - if (session_key) { - krb5_free_keyblock(telnet_context, session_key); - session_key = 0; - } - - krb5_copy_keyblock(telnet_context, newkey, - &session_key); + krb5_copy_keyblock(telnet_context, newkey, &session_key); krb5_free_keyblock(telnet_context, newkey); } else { - if (session_key){ - krb5_free_keyblock(telnet_context, session_key); -session_key = 0; - } - krb5_copy_keyblock(telnet_context, - ticket->enc_part2->session, - &session_key); + krb5_copy_keyblock(telnet_context, + ticket->enc_part2->session, + &session_key); } #ifdef ENCRYPTION @@ -458,6 +509,17 @@ session_key = 0; Data(ap, KRB_REJECT, 0, 0); break; } + return; + + errout: + Data(ap, KRB_REJECT, errbuf, -1); + if (auth_debug_mode) + printf("%s\r\n", errbuf); + if (auth_context) { + krb5_auth_con_free(telnet_context, auth_context); + auth_context = 0; + } + return; } void @@ -483,11 +545,20 @@ kerberos5_reply(ap, data, cnt) auth_send_retry(); return; case KRB_ACCEPT: - if ((ap->way & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL && - !mutual_complete) { - printf("[ Kerberos V5 accepted you, but didn't provide mutual authentication! ]\r\n"); - auth_send_retry(); - return; + if (!mutual_complete) { + if ((ap->way & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) { + printf("[ Kerberos V5 accepted you, but didn't provide mutual authentication! ]\r\n"); + auth_send_retry(); + return; + } +#ifdef ENCRYPTION + if (session_key) { + skey.type = SK_DES; + skey.length = 8; + skey.data = session_key->contents; + encrypt_session_key(&skey, 0); + } +#endif /* ENCRYPTION */ } if (cnt) printf("[ Kerberos V5 accepts you as ``%.*s'' ]\r\n", cnt, data); @@ -542,6 +613,7 @@ kerberos5_reply(ap, data, cnt) printf("Unknown Kerberos option %d\r\n", data[-1]); return; } + return; } int -- 2.26.2