diff --git a/ChangeLog b/ChangeLog index e565baa10..dca730db0 100644 --- a/ChangeLog +++ b/ChangeLog @@ -107,6 +107,10 @@ Sun Nov 29 01:56:21 1998 Assar Westerlund * configure.in: add hesiod +Wed Nov 25 11:37:48 1998 Johan Danielsson + + * lib/krb5/krb5_err.et: add some codes from kerberos-revisions-03 + Mon Nov 23 12:53:48 1998 Assar Westerlund * lib/kadm5/log.c: rename delete -> remove @@ -135,6 +139,10 @@ Sun Nov 22 06:54:48 1998 Assar Westerlund * lib/krb5/get_cred.c: re-structure code. remove limits on ASN1 generated bits. +Sun Nov 22 01:49:50 1998 Johan Danielsson + + * kdc/hprop.c (v4_prop): fix bogus indexing + Sat Nov 21 23:12:27 1998 Assar Westerlund * lib/krb5/free.c (krb5_xfree): new function @@ -155,10 +163,82 @@ Sat Nov 21 23:12:27 1998 Assar Westerlund * admin/ktutil.c (kt_remove): some more type correctness. +Sat Nov 21 16:49:20 1998 Johan Danielsson + + * kuser/klist.c: try to list enctypes as keytypes + + * kuser/kinit.c: remove extra `--cache' option, add `--enctypes' + to set list of enctypes to use + + * kadmin/load.c: load strings as hex + + * kadmin/dump.c: dump hex as string is possible + + * admin/ktutil.c: use print_version() + + * configure.in, acconfig.h: test for hesiod + +Sun Nov 15 17:28:19 1998 Johan Danielsson + + * lib/krb5/crypto.c: add some crypto debug code + + * lib/krb5/get_in_tkt.c (_krb5_extract_ticket): don't use fixed + buffer when encoding ticket + + * lib/krb5/auth_context.c (re-)implement `krb5_auth_setenctype' + + * kdc/kerberos5.c: allow mis-match of tgt session key, and service + session key + + * admin/ktutil.c: keytype -> enctype + Fri Nov 13 05:35:48 1998 Assar Westerlund * lib/krb5/krb5.h (KRB5_TGS_NAME, KRB5_TGS_NAME_SIZE): added +Mon Nov 2 01:15:06 1998 Assar Westerlund + + * lib/krb5/rd_req.c: adapt to new crypto api + + * lib/krb5/rd_rep.c: adapt to new crypto api + + * lib/krb5/rd_priv.c: adopt to new crypto api + + * lib/krb5/rd_cred.c: adopt to new crypto api + + * lib/krb5/principal.c: ENOMEM -> ERANGE + + * lib/krb5/mk_safe.c: cleanup and adopt to new crypto api + + * lib/krb5/mk_req_ext.c: adopt to new crypto api + + * lib/krb5/mk_req.c: get enctype from auth_context keyblock + + * lib/krb5/mk_rep.c: cleanup and adopt to new crypto api + + * lib/krb5/mk_priv.c: adopt to new crypto api + + * lib/krb5/keytab.c: adopt to new crypto api + + * lib/krb5/get_in_tkt_with_skey.c: adopt to new crypto api + + * lib/krb5/get_in_tkt_with_keytab.c: adopt to new crypto api + + * lib/krb5/get_in_tkt_pw.c: adopt to new crypto api + + * lib/krb5/get_in_tkt.c: adopt to new crypto api + + * lib/krb5/get_cred.c: adopt to new crypto api + + * lib/krb5/generate_subkey.c: use new crypto api + + * lib/krb5/context.c: rename etype functions to enctype ditto + + * lib/krb5/build_auth.c: use new crypto api + + * lib/krb5/auth_context.c: remove enctype and cksumtype from + auth_context + Mon Nov 2 01:15:06 1998 Assar Westerlund * kdc/connect.c (handle_udp, handle_tcp): correct type of `n' @@ -168,6 +248,10 @@ Mon Nov 2 01:15:06 1998 Assar Westerlund * appl/rsh/rshd.c (recv_krb5_auth): disable `do_encrypt' if not encrypting. +Tue Sep 15 18:41:38 1998 Johan Danielsson + + * admin/ktutil.c: fix printing of unrecognized keytypes + Tue Sep 15 17:02:33 1998 Johan Danielsson * lib/kadm5/set_keys.c: add KEYTYPE_USE_AFS3_SALT to keytype if @@ -188,6 +272,70 @@ Tue Aug 25 23:30:52 1998 Assar Westerlund * lib/krb5/context.c (krb5_get_use_admin_kdc, krb5_set_use_admin_kdc): new functions +Tue Aug 18 22:24:12 1998 Johan Danielsson + + * lib/krb5/crypto.c: remove all calls to abort(); check return + value from _key_schedule; + (RSA_MD[45]_DES_verify): zero tmp and res; + (RSA_MD5_DES3_{verify,checksum}): implement + +Mon Aug 17 20:18:46 1998 Assar Westerlund + + * kdc/kerberos4.c (swap32): conditionalize + + * lib/krb5/mk_req_ext.c (krb5_mk_req_internal): new function + + * lib/krb5/get_host_realm.c (krb5_get_host_realm): if the hostname + returned from gethostby*() isn't a FQDN, try with the original + hostname + + * lib/krb5/get_cred.c (make_pa_tgs_req): use krb5_mk_req_internal + and correct key usage + + * lib/krb5/crypto.c (verify_checksum): make static + + * admin/ktutil.c (kt_list): use krb5_enctype_to_string + +Sun Aug 16 20:57:56 1998 Assar Westerlund + + * kadmin/cpw.c (do_cpw_entry): use asprintf for the prompt + + * kadmin/ank.c (ank): print principal name in prompt + + * lib/krb5/crypto.c (hmac): always allocate space for checksum. + never trust c.checksum.length + (_get_derived_key): try to return the derived key + +Sun Aug 16 19:48:42 1998 Johan Danielsson + + * lib/krb5/crypto.c (hmac): fix some peculiarities and bugs + (get_checksum_key): assume usage is `formatted' + (create_checksum,verify_checksum): moved the guts of the krb5_* + functions here, both take `formatted' key-usages + (encrypt_internal_derived): fix various bogosities + (derive_key): drop key_type parameter (already given by the + encryption_type) + + * kdc/kerberos5.c (check_flags): handle case where client is NULL + + * kdc/connect.c (process_request): return zero after processing + kerberos 4 request + +Sun Aug 16 18:38:15 1998 Johan Danielsson + + * lib/krb5/crypto.c: merge x-*.[ch] into one file + + * lib/krb5/cache.c: remove residual from krb5_ccache_data + +Fri Aug 14 16:28:23 1998 Johan Danielsson + + * lib/krb5/x-crypto.c (derive_key): move DES3 specific code to + separate function (will eventually end up someplace else) + + * lib/krb5/x-crypto.c (krb5_string_to_key_derived): allocate key + + * configure.in, acconfig.h: test for four valued krb_put_int + Thu Aug 13 23:46:29 1998 Assar Westerlund * Release 0.0t @@ -197,6 +345,14 @@ Thu Aug 13 22:40:17 1998 Assar Westerlund * lib/krb5/config_file.c (parse_binding): remove trailing whitespace +Wed Aug 12 20:15:11 1998 Johan Danielsson + + * lib/krb5/x-checksum.c (krb5_verify_checksum): pass checksum type + to krb5_create_checksum + + * lib/krb5/x-key.c: implement DES3_string_to_key_derived; fix a + few typos + Wed Aug 5 12:39:54 1998 Assar Westerlund * Release 0.0s @@ -207,6 +363,58 @@ Thu Jul 30 23:12:17 1998 Assar Westerlund * lib/krb5/mk_error.c (krb5_mk_error): realloc until you die +Thu Jul 23 19:49:03 1998 Johan Danielsson + + * kdc/kdc_locl.h: proto for `get_des_key' + + * configure.in: test for four valued el_init + + * kuser/klist.c: keytype -> enctype + + * kpasswd/kpasswdd.c (change): use new `krb5_string_to_key*' + + * kdc/hprop.c (v4_prop, ka_convert): convert to a set of keys + + * kdc/kaserver.c: use `get_des_key' + + * kdc/524.c: use new crypto api + + * kdc/kerberos4.c: use new crypto api + + * kdc/kerberos5.c: always treat keytypes as enctypes; use new + crypto api + + * kdc/kstash.c: adapt to new crypto api + + * kdc/string2key.c: adapt to new crypto api + + * admin/srvconvert.c: add keys for all possible enctypes + + * admin/ktutil.c: keytype -> enctype + + * appl/rsh/rshd.c: use krb5_verify_authenticator_checksum + + * lib/gssapi/init_sec_context.c: get enctype from auth_context + keyblock + + * lib/hdb/hdb.c: remove hdb_*_keytype2key + + * lib/kadm5/set_keys.c: adapt to new crypto api + + * lib/kadm5/rename_s.c: adapt to new crypto api + + * lib/kadm5/get_s.c: adapt to new crypto api + + * lib/kadm5/create_s.c: add keys for des-cbc-crc, des-cbc-md4, + des-cbc-md5, and des3-cbc-sha1 + + * lib/krb5/heim_err.et: error message for unsupported salt + + * lib/krb5/codec.c: short-circuit these functions, since they are + not needed any more + + * lib/krb5/rd_safe.c: cleanup and adapt to new crypto api + Mon Jul 13 23:00:59 1998 Assar Westerlund * lib/krb5/send_to_kdc.c (krb5_sendto_kdc): don't advance diff --git a/acconfig.h b/acconfig.h index d460f3e37..89f90f07d 100644 --- a/acconfig.h +++ b/acconfig.h @@ -17,6 +17,14 @@ #undef HAVE_U_INT32_T #undef HAVE_U_INT64_T +#undef HAVE_FOUR_VALUED_KRB_PUT_INT + +#ifdef HAVE_FOUR_VALUED_KRB_PUT_INT +#define KRB_PUT_INT(F, T, L, S) krb_put_int((F), (T), (L), (S)) +#else +#define KRB_PUT_INT(F, T, L, S) krb_put_int((F), (T), (L)) +#endif + /* Define this to the type ssize_t should be */ #undef ssize_t @@ -178,6 +186,9 @@ /* Define if you have a readline compatible library */ #undef HAVE_READLINE +/* define if el_init takes four arguments */ +#undef HAVE_FOUR_VALUED_EL_INIT + /* Define if you have hesiod */ #undef HESIOD @@ -229,6 +240,12 @@ static /**/const char *const rcsid[] = { (char *)rcsid, "\100(#)" msg } #define AUTHENTICATION 1 #endif +/* Define if you have hesiod */ +#undef HESIOD + +/* define if you want key-deriving des3 code */ +#undef NEW_DES3_CODE + /* Set this if you want des encryption */ #undef DES_ENCRYPTION diff --git a/admin/ktutil.c b/admin/ktutil.c index 659d9e4c3..c2c0de92e 100644 --- a/admin/ktutil.c +++ b/admin/ktutil.c @@ -54,7 +54,7 @@ kt_list(int argc, char **argv) } printf("%s", "Version"); printf(" "); - printf("%-6s", "Type"); + printf("%-15s", "Type"); printf(" "); printf("%s", "Principal"); printf("\n"); @@ -62,8 +62,10 @@ kt_list(int argc, char **argv) char *p; printf(" %3d ", entry.vno); printf(" "); - krb5_keytype_to_string(context, entry.keyblock.keytype, &p); - printf("%-6s", p); + ret = krb5_enctype_to_string(context, entry.keyblock.keytype, &p); + if (ret != 0) + asprintf(&p, "unknown (%d)", entry.keyblock.keytype); + printf("%-15s", p); free(p); printf(" "); krb5_unparse_name(context, entry.principal, &p); @@ -85,12 +87,12 @@ kt_remove(int argc, char **argv) krb5_principal principal = NULL; int kvno = 0; char *keytype_string = NULL; - krb5_keytype keytype = KEYTYPE_NULL; + krb5_enctype enctype = 0; int help_flag = 0; struct getargs args[] = { { "principal", 'p', arg_string, NULL, "principal to remove" }, { "kvno", 'V', arg_integer, NULL, "key version to remove" }, - { "keytype", 't', arg_string, NULL, "key type to remove" }, + { "enctype", 't', arg_string, NULL, "enctype to remove" }, { "help", 'h', arg_flag, NULL } }; int num_args = sizeof(args) / sizeof(args[0]); @@ -116,11 +118,11 @@ kt_remove(int argc, char **argv) } } if(keytype_string) { - ret = krb5_string_to_keytype(context, keytype_string, &keytype); + ret = krb5_string_to_enctype(context, keytype_string, &enctype); if(ret) { int t; if(sscanf(keytype_string, "%d", &t) == 1) - keytype = (krb5_keytype)t; + enctype = t; else { krb5_warn(context, ret, "%s", keytype_string); if(principal) @@ -129,14 +131,14 @@ kt_remove(int argc, char **argv) } } } - if (!principal && !keytype && !kvno) { + if (!principal && !enctype && !kvno) { krb5_warnx(context, "You must give at least one of " - "principal, keytype or kvno."); + "principal, enctype or kvno."); return 0; } entry.principal = principal; - entry.keyblock.keytype = keytype; + entry.keyblock.keytype = enctype; entry.vno = kvno; ret = krb5_kt_remove_entry(context, keytab, &entry); if(ret) @@ -154,15 +156,15 @@ kt_add(int argc, char **argv) char buf[128]; char *principal_string = NULL; int kvno = -1; - char *keytype_string = NULL; - krb5_keytype keytype; + char *enctype_string = NULL; + krb5_enctype enctype; char *password_string = NULL; int random_flag = 0; int help_flag = 0; struct getargs args[] = { { "principal", 'p', arg_string, NULL, "principal of key", "principal"}, { "kvno", 'V', arg_integer, NULL, "key version of key" }, - { "keytype", 't', arg_string, NULL, "key type of key" }, + { "enctype", 'e', arg_string, NULL, "encryption type of key" }, { "password", 'w', arg_string, NULL, "password for key"}, { "random", 'r', arg_flag, NULL, "generate random key" }, { "help", 'h', arg_flag, NULL } @@ -172,7 +174,7 @@ kt_add(int argc, char **argv) int i = 0; args[i++].value = &principal_string; args[i++].value = &kvno; - args[i++].value = &keytype_string; + args[i++].value = &enctype_string; args[i++].value = &password_string; args[i++].value = &random_flag; args[i++].value = &help_flag; @@ -196,19 +198,19 @@ kt_add(int argc, char **argv) krb5_warn(context, ret, "%s", principal_string); return 0; } - if(keytype_string == NULL) { - printf("Keytype: "); + if(enctype_string == NULL) { + printf("Encryption type: "); fgets(buf, sizeof(buf), stdin); buf[strcspn(buf, "\r\n")] = '\0'; - keytype_string = buf; + enctype_string = buf; } - ret = krb5_string_to_keytype(context, keytype_string, &keytype); + ret = krb5_string_to_enctype(context, enctype_string, &enctype); if(ret) { int t; - if(sscanf(keytype_string, "%d", &t) == 1) - keytype = (krb5_keytype)t; + if(sscanf(enctype_string, "%d", &t) == 1) + enctype = t; else { - krb5_warn(context, ret, "%s", keytype_string); + krb5_warn(context, ret, "%s", enctype_string); if(entry.principal) krb5_free_principal(context, entry.principal); return 0; @@ -224,14 +226,11 @@ kt_add(int argc, char **argv) des_read_pw_string(buf, sizeof(buf), "Password: ", 1); password_string = buf; } - if(password_string) { - krb5_data salt; - krb5_get_salt(entry.principal, &salt); - krb5_string_to_key(password_string, &salt, keytype, &entry.keyblock); - krb5_data_free(&salt); - } else { - krb5_generate_random_keyblock(context, keytype, &entry.keyblock); - } + if(password_string) + krb5_string_to_key(context, enctype, password_string, + entry.principal, &entry.keyblock); + else + krb5_generate_random_keyblock(context, enctype, &entry.keyblock); entry.vno = kvno; ret = krb5_kt_add_entry(context, keytab, &entry); if(ret) @@ -313,8 +312,10 @@ main(int argc, char **argv) usage(1); if(help_flag) usage(0); - if(version_flag) - krb5_errx(context, 0, "%s", heimdal_version); + if(version_flag) { + print_version(NULL); + exit(0); + } argc -= optind; argv += optind; if(argc == 0) diff --git a/admin/srvconvert.c b/admin/srvconvert.c index 7ecb23b72..ac455507e 100644 --- a/admin/srvconvert.c +++ b/admin/srvconvert.c @@ -151,7 +151,6 @@ srvconv(int argc, char **argv) } entry.vno = kvno; - entry.keyblock.keytype = KEYTYPE_DES; entry.keyblock.keyvalue.data = key; entry.keyblock.keyvalue.length = 8; @@ -168,6 +167,11 @@ srvconv(int argc, char **argv) } } + entry.keyblock.keytype = ETYPE_DES_CBC_MD5; + ret = krb5_kt_add_entry(context, keytab, &entry); + entry.keyblock.keytype = ETYPE_DES_CBC_MD4; + ret = krb5_kt_add_entry(context, keytab, &entry); + entry.keyblock.keytype = ETYPE_DES_CBC_CRC; ret = krb5_kt_add_entry(context, keytab, &entry); krb5_free_principal(context, entry.principal); if(ret) { diff --git a/appl/afsutil/Makefile.am b/appl/afsutil/Makefile.am index 2bc446496..a36fade09 100644 --- a/appl/afsutil/Makefile.am +++ b/appl/afsutil/Makefile.am @@ -11,7 +11,7 @@ AFSPROGS = endif bin_PROGRAMS = $(AFSPROGS) -LDADD = $(top_builddir)/lib/kafs/libkafs.a \ +LDADD = $(top_builddir)/lib/kafs/libkafs.a $(AIX_EXTRA_KAFS) \ $(LIB_krb4) \ $(top_builddir)/lib/krb5/libkrb5.la \ $(top_builddir)/lib/asn1/libasn1.la \ diff --git a/appl/ftp/ChangeLog b/appl/ftp/ChangeLog index 3effe84bc..26df1b9da 100644 --- a/appl/ftp/ChangeLog +++ b/appl/ftp/ChangeLog @@ -1,3 +1,7 @@ +Tue Dec 1 14:44:29 1998 Johan Danielsson + + * ftpd/Makefile.am: link with extra libs for aix + Sun Nov 22 10:28:20 1998 Assar Westerlund * ftpd/ftpd.c (retrying): support on-the-fly decompression @@ -33,6 +37,10 @@ Tue Sep 1 16:56:42 1998 Johan Danielsson * ftp/cmds.c (quote1): fix % quoting bug +Fri Aug 14 17:10:06 1998 Johan Danielsson + + * ftp/krb4.c: krb_put_int -> KRB_PUT_INT + Tue Jun 30 18:07:15 1998 Assar Westerlund * ftp/security.c (auth): free `app_data' diff --git a/appl/ftp/ftp/krb4.c b/appl/ftp/ftp/krb4.c index 95f37abf0..4d83ece53 100644 --- a/appl/ftp/ftp/krb4.c +++ b/appl/ftp/ftp/krb4.c @@ -152,7 +152,7 @@ krb4_adat(void *app_data, void *buf, size_t len) cs = auth_dat.checksum + 1; { unsigned char tmp[4]; - krb_put_int(cs, tmp, 4, sizeof(tmp)); + KRB_PUT_INT(cs, tmp, 4, sizeof(tmp)); tmp_len = krb_mk_safe(tmp, msg, 4, &d->key, &LOCAL_ADDR, &REMOTE_ADDR); } if(tmp_len < 0){ diff --git a/appl/ftp/ftpd/Makefile.am b/appl/ftp/ftpd/Makefile.am index 19b3f24af..a3a255439 100644 --- a/appl/ftp/ftpd/Makefile.am +++ b/appl/ftp/ftpd/Makefile.am @@ -40,7 +40,7 @@ gssapi.c: CLEANFILES = security.c security.h krb4.c gssapi.c if KRB4 -afslib = $(top_builddir)/lib/kafs/libkafs.a +afslib = $(top_builddir)/lib/kafs/libkafs.a $(AIX_EXTRA_KAFS) else afslib = endif diff --git a/appl/rsh/common.c b/appl/rsh/common.c index a4c32ad5f..9ce02d070 100644 --- a/appl/rsh/common.c +++ b/appl/rsh/common.c @@ -68,9 +68,12 @@ do_read (int fd, ret = krb5_net_read (context, &fd, buf, outer_len); if (ret != outer_len) return ret; - status = krb5_decrypt(context, buf, outer_len, - ETYPE_DES_CBC_CRC, /* XXX */ - keyblock, &data); + + + + status = krb5_decrypt(context, crypto, KRB5_KU_OTHER_ENCRYPTED, + buf, outer_len, &data); + if (status) errx (1, "%s", krb5_get_err_text (context, status)); memcpy (buf, data.data, len); @@ -98,12 +101,9 @@ do_write (int fd, void *buf, size_t sz) u_int32_t len; int ret; - status = krb5_encrypt (context, - buf, - sz, - ETYPE_DES_CBC_CRC, /* XXX */ - keyblock, - &data); + status = krb5_encrypt(context, crypto, KRB5_KU_OTHER_ENCRYPTED, + buf, sz, &data); + if (status) errx (1, "%s", krb5_get_err_text(context, status)); len = htonl(sz); diff --git a/appl/rsh/rsh.c b/appl/rsh/rsh.c index 575531a44..4631e1e0f 100644 --- a/appl/rsh/rsh.c +++ b/appl/rsh/rsh.c @@ -44,6 +44,7 @@ int do_encrypt; int do_forward; krb5_context context; krb5_keyblock *keyblock; +krb5_crypto crypto; des_key_schedule schedule; des_cblock iv; @@ -278,6 +279,11 @@ send_krb5_auth(int s, errx (1, "krb5_auth_con_getkey: %s", krb5_get_err_text(context, status)); + krb5_crypto_init(context, keyblock, 0, &crypto); + if(status) + errx (1, "krb5_crypto_init: %s", + krb5_get_err_text(context, status)); + len = strlen(remote_user) + 1; if (net_write (s, remote_user, len) != len) err (1, "write"); diff --git a/appl/rsh/rsh_locl.h b/appl/rsh/rsh_locl.h index 196f76bd7..a8872c58b 100644 --- a/appl/rsh/rsh_locl.h +++ b/appl/rsh/rsh_locl.h @@ -122,6 +122,7 @@ extern enum auth_method auth_method; extern int do_encrypt; extern krb5_context context; extern krb5_keyblock *keyblock; +extern krb5_crypto crypto; extern des_key_schedule schedule; extern des_cblock iv; diff --git a/appl/rsh/rshd.c b/appl/rsh/rshd.c index 2ac43f90a..3123b8d63 100644 --- a/appl/rsh/rshd.c +++ b/appl/rsh/rshd.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997 Kungliga Tekniska Högskolan + * Copyright (c) 1997, 1998 Kungliga Tekniska Högskolan * (Royal Institute of Technology, Stockholm, Sweden). * All rights reserved. * @@ -43,6 +43,7 @@ enum auth_method auth_method; krb5_context context; krb5_keyblock *keyblock; +krb5_crypto crypto; des_key_schedule schedule; des_cblock iv; @@ -225,7 +226,6 @@ recv_krb5_auth (int s, u_char *buf, krb5_auth_context auth_context = NULL; krb5_ticket *ticket; krb5_error_code status; - krb5_authenticator authenticator; krb5_data cksum_data; krb5_principal server; @@ -269,33 +269,31 @@ recv_krb5_auth (int s, u_char *buf, status = krb5_auth_con_getkey (context, auth_context, &keyblock); if (status) - syslog_and_die ("krb5_auth_con_getkey: %s", - krb5_get_err_text(context, status)); + syslog_and_die ("krb5_auth_con_getkey: %s", + krb5_get_err_text(context, status)); - status = krb5_auth_getauthenticator (context, - auth_context, - &authenticator); - if (status) - syslog_and_die ("krb5_auth_getauthenticator: %s", - krb5_get_err_text(context, status)); + status = krb5_crypto_init(context, keyblock, 0, &crypto); + if(status) + syslog_and_die("krb5_crypto_init: %s", + krb5_get_err_text(context, status)); + cksum_data.length = asprintf ((char **)&cksum_data.data, "%u:%s%s", ntohs(thisaddr.sin_port), cmd, server_username); - status = krb5_verify_checksum (context, - cksum_data.data, - cksum_data.length, - keyblock, - authenticator->cksum); + status = krb5_verify_authenticator_checksum(context, + auth_context, + cksum_data.data, + cksum_data.length); + if (status) - syslog_and_die ("krb5_verify_checksum: %s", + syslog_and_die ("krb5_verify_authenticator_checksum: %s", krb5_get_err_text(context, status)); free (cksum_data.data); - krb5_free_authenticator (context, &authenticator); recv_krb5_creds (s, auth_context, server_username, ticket->client); diff --git a/appl/telnet/ChangeLog b/appl/telnet/ChangeLog index 260c896c4..4b0d2a334 100644 --- a/appl/telnet/ChangeLog +++ b/appl/telnet/ChangeLog @@ -4,6 +4,18 @@ Mon Feb 1 04:08:36 1999 Assar Westerlund if we actually have IPv6. From "Brandon S. Allbery KF8NH" +Sat Nov 21 16:51:00 1998 Johan Danielsson + + * telnetd/sys_term.c (cleanup): don't call vhangup() on sgi:s + +Fri Aug 14 16:29:18 1998 Johan Danielsson + + * libtelnet/kerberos.c: krb_put_int -> KRB_PUT_INT + +Thu Jul 23 20:29:05 1998 Johan Danielsson + + * libtelnet/kerberos5.c: use krb5_verify_authenticator_checksum + Wed May 27 04:19:17 1998 Assar Westerlund * telnet/sys_bsd.c (process_rings): correct call to `stilloob' diff --git a/appl/telnet/libtelnet/kerberos.c b/appl/telnet/libtelnet/kerberos.c index abcbc4545..a41835b9c 100644 --- a/appl/telnet/libtelnet/kerberos.c +++ b/appl/telnet/libtelnet/kerberos.c @@ -620,13 +620,13 @@ pack_cred(CREDENTIALS *cred, unsigned char *buf) p += REALM_SZ; memcpy(p, cred->session, 8); p += 8; - p += krb_put_int(cred->lifetime, p, 4, 4); - p += krb_put_int(cred->kvno, p, 4, 4); - p += krb_put_int(cred->ticket_st.length, p, 4, 4); + p += KRB_PUT_INT(cred->lifetime, p, 4, 4); + p += KRB_PUT_INT(cred->kvno, p, 4, 4); + p += KRB_PUT_INT(cred->ticket_st.length, p, 4, 4); memcpy(p, cred->ticket_st.dat, cred->ticket_st.length); p += cred->ticket_st.length; - p += krb_put_int(0, p, 4, 4); - p += krb_put_int(cred->issue_date, p, 4, 4); + p += KRB_PUT_INT(0, p, 4, 4); + p += KRB_PUT_INT(cred->issue_date, p, 4, 4); memcpy (p, cred->pname, ANAME_SZ); p += ANAME_SZ; memcpy (p, cred->pinst, INST_SZ); diff --git a/appl/telnet/libtelnet/kerberos5.c b/appl/telnet/libtelnet/kerberos5.c index 69181b550..394fbbb5f 100644 --- a/appl/telnet/libtelnet/kerberos5.c +++ b/appl/telnet/libtelnet/kerberos5.c @@ -256,7 +256,6 @@ kerberos5_is(Authenticator *ap, unsigned char *data, int cnt) krb5_keyblock *key_block; char *name; krb5_principal server; - krb5_authenticator authenticator; int zero = 0; if (cnt-- < 1) @@ -327,55 +326,29 @@ kerberos5_is(Authenticator *ap, unsigned char *data, int cnt) free (errbuf); return; } - - ret = krb5_auth_con_getkey(context, auth_context, &key_block); - if (ret) { - Data(ap, KRB_REJECT, "krb5_auth_con_getkey failed", -1); - auth_finished(ap, AUTH_REJECT); - if (auth_debug_mode) - printf("Kerberos V5: " - "krb5_auth_con_getkey failed (%s)\r\n", - krb5_get_err_text(context, ret)); - return; - } - ret = krb5_auth_getauthenticator (context, - auth_context, - &authenticator); - if (ret) { - Data(ap, KRB_REJECT, "krb5_auth_getauthenticator failed", -1); - auth_finished(ap, AUTH_REJECT); - if (auth_debug_mode) - printf("Kerberos V5: " - "krb5_auth_getauthenticator failed (%s)\r\n", - krb5_get_err_text(context, ret)); - return; - } - - if (authenticator->cksum) { + { char foo[2]; - + foo[0] = ap->type; foo[1] = ap->way; + + ret = krb5_verify_authenticator_checksum(context, + auth_context, + foo, + sizeof(foo)); - ret = krb5_verify_checksum (context, - foo, - sizeof(foo), - key_block, - authenticator->cksum); if (ret) { - Data(ap, KRB_REJECT, "No checksum", -1); + char *errbuf; + asprintf(&errbuf, "Bad checksum: %s", + krb5_get_err_text(context, ret)); + Data(ap, KRB_REJECT, errbuf, -1); if (auth_debug_mode) - printf ("No checksum\r\n"); - krb5_free_authenticator (context, - &authenticator); - + printf ("%s\r\n", errbuf); + free(errbuf); return; } } - krb5_free_authenticator (context, - &authenticator); - ret = krb5_auth_con_getremotesubkey (context, auth_context, &key_block); @@ -416,7 +389,9 @@ kerberos5_is(Authenticator *ap, unsigned char *data, int cnt) name ? name : ""); } - if(key_block->keytype == KEYTYPE_DES) { + if(key_block->keytype == ETYPE_DES_CBC_MD5 || + key_block->keytype == ETYPE_DES_CBC_MD4 || + key_block->keytype == ETYPE_DES_CBC_CRC) { Session_Key skey; skey.type = SK_DES; diff --git a/appl/telnet/telnetd/sys_term.c b/appl/telnet/telnetd/sys_term.c index 391b746f6..10fa6be9b 100644 --- a/appl/telnet/telnetd/sys_term.c +++ b/appl/telnet/telnetd/sys_term.c @@ -1602,8 +1602,10 @@ cleanup(int sig) #if defined(HAVE_UTMPX_H) || !defined(HAVE_LOGWTMP) rmut(); #ifdef HAVE_VHANGUP +#ifndef __sgi vhangup(); /* XXX */ #endif +#endif #else char *p; diff --git a/cf/test-package.m4 b/cf/test-package.m4 index 99a55400e..8fbee37d3 100644 --- a/cf/test-package.m4 +++ b/cf/test-package.m4 @@ -1,6 +1,6 @@ dnl $Id$ dnl -dnl AC_TEST_PACKAGE(package,header,lib,linkline) +dnl AC_TEST_PACKAGE(package,header,lib,linkline,default location) AC_DEFUN(AC_TEST_PACKAGE, [ AC_MSG_CHECKING(for $1) @@ -32,16 +32,20 @@ define([foo], translit($1, [a-z], [A-Z])) @@@syms="$syms foo"@@@ END -if test -n "$with_$1"; then - AC_DEFINE([foo]) - if test "$with_$1" != "yes"; then - $1_dir=$with_$1 +if test -n "$with_$1" -o -n "$5"; then +dnl AC_DEFINE([foo]) + if test -n "$with_$1" -a "$with_$1" != "yes"; then + $1_dir="$with_$1" + elif test -n "$5"; then + $1_dir="$5" fi dnl Try to find include if test -n "$with_$1_include"; then trydir=$with_$1_include - elif test "$with_$1" != "yes"; then + elif test -n "$with_$1" -a "$with_$1" != "yes"; then trydir="$with_$1 $with_$1/include" + elif test -n "$5"; then + trydir="$5/include" else trydir= fi @@ -57,14 +61,16 @@ dnl Try to find include done if test -n "$found"; then $1_include=$res - else + elif test -n "$with_$1"; then AC_MSG_ERROR(Cannot find $2) fi dnl Try to find lib if test -n "$with_$1_lib"; then trydir=$with_$1_lib - elif test "$with_$1" != "yes"; then + elif test -n "$with_$1" -a "$with_$1" != "yes"; then trydir="$with_$1 $with_$1/lib" + elif test -n "$5"; then + trydir="$5/lib" else trydir= fi @@ -83,11 +89,18 @@ dnl Try to find lib done if test -n "$found"; then $1_lib=$res - else + elif test -n "$with_$1"; then AC_MSG_ERROR(Cannot find $3) fi - AC_MSG_RESULT([headers $$1_include, libraries $$1_lib]) - AC_DEFINE_UNQUOTED(foo) + if test -n "$$1_include" -o -n "$$1_lib"; then + AC_MSG_RESULT([headers $$1_include, libraries $$1_lib]) + AC_DEFINE_UNQUOTED(foo) + if test "$with_$1" = "" -a "$5"; then + with_$1="$5" + fi + else + AC_MSG_RESULT(no) + fi if test -n "$$1_include"; then foo[INCLUDE]="-I$$1_include" fi diff --git a/configure.in b/configure.in index 9d0d78b41..cc790af16 100644 --- a/configure.in +++ b/configure.in @@ -3,6 +3,10 @@ AC_REVISION($Revision$) AC_INIT(lib/krb5/send_to_kdc.c) AM_CONFIG_HEADER(include/config.h) +AC_CONFIG_AUX_DIR_DEFAULT +if test "`uname`" = AIX; then + INSTALL="$ac_install_sh" +fi AM_INIT_AUTOMAKE(heimdal,0.0u) AC_PREFIX_DEFAULT(/usr/heimdal) @@ -20,6 +24,8 @@ case "$host" in ;; esac +test -z "$CFLAGS" && CFLAGS="-g" + dnl Checks for programs. AC_PROG_CC @@ -39,7 +45,6 @@ if test "$GCC" = "yes"; then fi AC_SUBST(WFLAGS) AC_SUBST(WFLAGS_NOUNUSED) -test -z "$CFLAGS" && CFLAGS="-g" berkeley_db=db AC_ARG_WITH(berkeley-db, @@ -49,7 +54,7 @@ if test "$withval" = no; then fi ]) -AC_TEST_PACKAGE(krb4,krb.h,libkrb.a,-lkrb) +AC_TEST_PACKAGE(krb4,krb.h,libkrb.a,-lkrb,/usr/athena) if test "$with_krb4"; then AC_DEFINE(KRB4, 1) @@ -57,11 +62,45 @@ if test "$with_krb4"; then INCLUDE_krb4="$KRB4INCLUDE" EXTRA_LIB45=lib45.a AC_SUBST(EXTRA_LIB45) + AC_CACHE_CHECK(for four valued krb_put_int, ac_cv_func_krb_put_int_four, + [save_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS $INCLUDE_krb4" + AC_TRY_COMPILE([#include ],[ + char tmp[4]; + krb_put_int(17, tmp, 4, sizeof(tmp));], + ac_cv_func_krb_put_int_four=yes, + ac_cv_func_krb_put_int_four=no) + CFLAGS="$save_CFLAGS" + ]) + if test "$ac_cv_func_krb_put_int_four" = yes; then + AC_DEFINE(HAVE_FOUR_VALUED_KRB_PUT_INT, 1) + fi fi AM_CONDITIONAL(KRB4, test "$with_krb4")dnl AC_SUBST(LIB_krb4)dnl AC_SUBST(INCLUDE_krb4)dnl -AM_CONDITIONAL(AIX, test `uname` = AIX)dnl +AM_CONDITIONAL(AIX, test "`uname`" = AIX)dnl +AM_CONDITIONAL(AIX4, test "`uname`" = AIX -a "`uname -v`" = 4) +aix_dynamic_afs=yes +AM_CONDITIONAL(AIX_DYNAMIC_AFS, test "$aix_dynamic_afs" = yes)dnl + +if test "`uname`" = AIX ;then + if test "$aix_dynamic_afs" = yes; then + AC_FIND_FUNC_NO_LIBS(dlopen, dl) + if test "$ac_cv_funclib_dlopen" = yes; then + AIX_EXTRA_KAFS= + elif test "$ac_cv_funclib_dlopen" != no; then + AIX_EXTRA_KAFS="$ac_cv_funclib_dlopen" + else + AIX_EXTRA_KAFS=-lld + fi + else + AIX_EXTRA_KAFS= + fi +fi +AM_CONDITIONAL(HAVE_DLOPEN, test "$ac_cv_funclib_dlopen" != no)dnl +AC_SUBST(AFS_EXTRA_LD)dnl +AC_SUBST(AIX_EXTRA_KAFS)dnl AC_ARG_ENABLE(kaserver, [ --enable-kaserver if you want the KDC to try to emulate a kaserver], @@ -85,7 +124,7 @@ fi otp=yes AC_ARG_ENABLE(otp, -[ --disable-otp if you don't want OTP support], +[ --disable-otp if you don't want OTP support], [ if test "$enableval" = "no"; then otp=no @@ -99,6 +138,18 @@ fi AC_SUBST(LIB_otp) AC_SUBST(OTP_dir) +new_des3_code=no +AC_ARG_ENABLE(new-des3-code, +[ --enable-new-des3-code to make new key-deriving des3 the default], +[ +if test "$enableval" = "yes"; then + new_des3_code=yes +fi +]) +if test "$new_des3_code" = "yes"; then + AC_DEFINE(NEW_DES3_CODE, 1) +fi + AC_PATH_PROG(NROFF, nroff) AC_PATH_PROG(GROFF, groff) AC_CACHE_CHECK(how to format man pages,ac_cv_sys_man_format, @@ -547,6 +598,17 @@ dnl Tests for editline dnl AC_FIND_FUNC_NO_LIBS(el_init, edit) +if test "$ac_cv_func_el_init" = yes ; then + AC_CACHE_CHECK(for four argument el_init, ac_cv_func_el_init_four,[ + AC_TRY_COMPILE([#include + #include ], + [el_init("", NULL, NULL, NULL);], + ac_cv_func_el_init_four=yes, + ac_cv_func_el_init_four=no)]) + if test "$ac_cv_func_el_init_four" = yes; then + AC_DEFINE(HAVE_FOUR_VALUED_EL_INIT, 1) + fi +fi AC_FIND_FUNC_NO_LIBS(readline, edit readline) ac_foo=no if test "$with_readline"; then diff --git a/doc/draft-horowitz-key-derivation-01.txt b/doc/draft-horowitz-key-derivation-01.txt new file mode 100644 index 000000000..4dcff486b --- /dev/null +++ b/doc/draft-horowitz-key-derivation-01.txt @@ -0,0 +1,244 @@ +Network Working Group M. Horowitz + Cygnus Solutions +Internet-Draft March, 1997 + + + Key Derivation for Authentication, Integrity, and Privacy + +Status of this Memo + + This document is an Internet-Draft. Internet-Drafts are working + documents of the Internet Engineering Task Force (IETF), its areas, + and its working groups. Note that other groups may also distribute + working documents as Internet-Drafts. + + Internet-Drafts are draft documents valid for a maximum of six months + and may be updated, replaced, or obsoleted by other documents at any + time. It is inappropriate to use Internet-Drafts as reference + material or to cite them other than as ``work in progress.'' + + To learn the current status of any Internet-Draft, please check the + ``1id-abstracts.txt'' listing contained in the Internet-Drafts Shadow + Directories on ds.internic.net (US East Coast), nic.nordu.net + (Europe), ftp.isi.edu (US West Coast), or munnari.oz.au (Pacific + Rim). + + Distribution of this memo is unlimited. Please send comments to the + author. + +Abstract + + Recent advances in cryptography have made it desirable to use longer + cryptographic keys, and to make more careful use of these keys. In + particular, it is considered unwise by some cryptographers to use the + same key for multiple purposes. Since most cryptographic-based + systems perform a range of functions, such as authentication, key + exchange, integrity, and encryption, it is desirable to use different + cryptographic keys for these purposes. + + This RFC does not define a particular protocol, but defines a set of + cryptographic transformations for use with arbitrary network + protocols and block cryptographic algorithm. + + +Deriving Keys + + In order to use multiple keys for different functions, there are two + possibilities: + + - Each protocol ``key'' contains multiple cryptographic keys. The + implementation would know how to break up the protocol ``key'' for + use by the underlying cryptographic routines. + + - The protocol ``key'' is used to derive the cryptographic keys. + The implementation would perform this derivation before calling + + + +Horowitz [Page 1] + +Internet Draft Key Derivation March, 1997 + + + the underlying cryptographic routines. + + In the first solution, the system has the opportunity to provide + separate keys for different functions. This has the advantage that + if one of these keys is broken, the others remain secret. However, + this comes at the cost of larger ``keys'' at the protocol layer. In + addition, since these ``keys'' may be encrypted, compromising the + cryptographic key which is used to encrypt them compromises all the + component keys. Also, the not all ``keys'' are used for all possible + functions. Some ``keys'', especially those derived from passwords, + are generated from limited amounts of entropy. Wasting some of this + entropy on cryptographic keys which are never used is unwise. + + The second solution uses keys derived from a base key to perform + cryptographic operations. By carefully specifying how this key is + used, all of the advantages of the first solution can be kept, while + eliminating some disadvantages. In particular, the base key must be + used only for generating the derived keys, and this derivation must + be non-invertible and entropy-preserving. Given these restrictions, + compromise of one derived keys does not compromise the other subkeys. + Attack of the base key is limited, since it is only used for + derivation, and is not exposed to any user data. + + Since the derived key has as much entropy as the base keys (if the + cryptosystem is good), password-derived keys have the full benefit of + all the entropy in the password. + + To generate a derived key from a base key: + + Derived Key = DK(Base Key, Well-Known Constant) + + where + + DK(Key, Constant) = n-truncate(E(Key, Constant)) + + In this construction, E(Key, Plaintext) is a block cipher, Constant + is a well-known constant defined by the protocol, and n-truncate + truncates its argument by taking the first n bits; here, n is the key + size of E. + + If the output of E is is shorter than n bits, then some entropy in + the key will be lost. If the Constant is smaller than the block size + of E, then it must be padded so it may be encrypted. If the Constant + is larger than the block size, then it must be folded down to the + block size to avoid chaining, which affects the distribution of + entropy. + + In any of these situations, a variation of the above construction is + used, where the folded Constant is encrypted, and the resulting + output is fed back into the encryption as necessary (the | indicates + concatentation): + + K1 = E(Key, n-fold(Constant)) + K2 = E(Key, K1) + + + +Horowitz [Page 2] + +Internet Draft Key Derivation March, 1997 + + + K3 = E(Key, K2) + K4 = ... + + DK(Key, Constant) = n-truncate(K1 | K2 | K3 | K4 ...) + + n-fold is an algorithm which takes m input bits and ``stretches'' + them to form n output bits with no loss of entropy, as described in + [Blumenthal96]. In this document, n-fold is always used to produce n + bits of output, where n is the key size of E. + + If the size of the Constant is not equal to the block size of E, then + the Constant must be n-folded to the block size of E. This number is + used as input to E. If the block size of E is less than the key + size, then the output from E is taken as input to a second invocation + of E. This process is repeated until the number of bits accumulated + is greater than or equal to the key size of E. When enough bits have + been computed, the first n are taken as the derived key. + + Since the derived key is the result of one or more encryptions in the + base key, deriving the base key from the derived key is equivalent to + determining the key from a very small number of plaintext/ciphertext + pairs. Thus, this construction is as strong as the cryptosystem + itself. + + +Deriving Keys from Passwords + + When protecting information with a password or other user data, it is + necessary to convert an arbitrary bit string into an encryption key. + In addition, it is sometimes desirable that the transformation from + password to key be difficult to reverse. A simple variation on the + construction in the prior section can be used: + + Key = DK(n-fold(Password), Well-Known Constant) + + The n-fold algorithm is reversible, so recovery of the n-fold output + is equivalent to recovery of Password. However, recovering the n- + fold output is difficult for the same reason recovering the base key + from a derived key is difficult. + + + + Traditionally, the transformation from plaintext to ciphertext, or + vice versa, is determined by the cryptographic algorithm and the key. + A simple way to think of derived keys is that the transformation is + determined by the cryptographic algorithm, the constant, and the key. + + For interoperability, the constants used to derive keys for different + purposes must be specified in the protocol specification. The + constants must not be specified on the wire, or else an attacker who + determined one derived key could provide the associated constant and + spoof data using that derived key, rather than the one the protocol + designer intended. + + + + +Horowitz [Page 3] + +Internet Draft Key Derivation March, 1997 + + + Determining which parts of a protocol require their own constants is + an issue for the designer of protocol using derived keys. + + +Security Considerations + + This entire document deals with security considerations relating to + the use of cryptography in network protocols. + + +Acknowledgements + + I would like to thank Uri Blumenthal, Hugo Krawczyk, and Bill + Sommerfeld for their contributions to this document. + + +References + + [Blumenthal96] Blumenthal, U., "A Better Key Schedule for DES-Like + Ciphers", Proceedings of PRAGOCRYPT '96, 1996. + + +Author's Address + + Marc Horowitz + Cygnus Solutions + 955 Massachusetts Avenue + Cambridge, MA 02139 + + Phone: +1 617 354 7688 + Email: marc@cygnus.com + + + + + + + + + + + + + + + + + + + + + + + + + + +Horowitz [Page 4] diff --git a/doc/standardisation/draft-horowitz-key-derivation-01.txt b/doc/standardisation/draft-horowitz-key-derivation-01.txt new file mode 100644 index 000000000..4dcff486b --- /dev/null +++ b/doc/standardisation/draft-horowitz-key-derivation-01.txt @@ -0,0 +1,244 @@ +Network Working Group M. Horowitz + Cygnus Solutions +Internet-Draft March, 1997 + + + Key Derivation for Authentication, Integrity, and Privacy + +Status of this Memo + + This document is an Internet-Draft. Internet-Drafts are working + documents of the Internet Engineering Task Force (IETF), its areas, + and its working groups. Note that other groups may also distribute + working documents as Internet-Drafts. + + Internet-Drafts are draft documents valid for a maximum of six months + and may be updated, replaced, or obsoleted by other documents at any + time. It is inappropriate to use Internet-Drafts as reference + material or to cite them other than as ``work in progress.'' + + To learn the current status of any Internet-Draft, please check the + ``1id-abstracts.txt'' listing contained in the Internet-Drafts Shadow + Directories on ds.internic.net (US East Coast), nic.nordu.net + (Europe), ftp.isi.edu (US West Coast), or munnari.oz.au (Pacific + Rim). + + Distribution of this memo is unlimited. Please send comments to the + author. + +Abstract + + Recent advances in cryptography have made it desirable to use longer + cryptographic keys, and to make more careful use of these keys. In + particular, it is considered unwise by some cryptographers to use the + same key for multiple purposes. Since most cryptographic-based + systems perform a range of functions, such as authentication, key + exchange, integrity, and encryption, it is desirable to use different + cryptographic keys for these purposes. + + This RFC does not define a particular protocol, but defines a set of + cryptographic transformations for use with arbitrary network + protocols and block cryptographic algorithm. + + +Deriving Keys + + In order to use multiple keys for different functions, there are two + possibilities: + + - Each protocol ``key'' contains multiple cryptographic keys. The + implementation would know how to break up the protocol ``key'' for + use by the underlying cryptographic routines. + + - The protocol ``key'' is used to derive the cryptographic keys. + The implementation would perform this derivation before calling + + + +Horowitz [Page 1] + +Internet Draft Key Derivation March, 1997 + + + the underlying cryptographic routines. + + In the first solution, the system has the opportunity to provide + separate keys for different functions. This has the advantage that + if one of these keys is broken, the others remain secret. However, + this comes at the cost of larger ``keys'' at the protocol layer. In + addition, since these ``keys'' may be encrypted, compromising the + cryptographic key which is used to encrypt them compromises all the + component keys. Also, the not all ``keys'' are used for all possible + functions. Some ``keys'', especially those derived from passwords, + are generated from limited amounts of entropy. Wasting some of this + entropy on cryptographic keys which are never used is unwise. + + The second solution uses keys derived from a base key to perform + cryptographic operations. By carefully specifying how this key is + used, all of the advantages of the first solution can be kept, while + eliminating some disadvantages. In particular, the base key must be + used only for generating the derived keys, and this derivation must + be non-invertible and entropy-preserving. Given these restrictions, + compromise of one derived keys does not compromise the other subkeys. + Attack of the base key is limited, since it is only used for + derivation, and is not exposed to any user data. + + Since the derived key has as much entropy as the base keys (if the + cryptosystem is good), password-derived keys have the full benefit of + all the entropy in the password. + + To generate a derived key from a base key: + + Derived Key = DK(Base Key, Well-Known Constant) + + where + + DK(Key, Constant) = n-truncate(E(Key, Constant)) + + In this construction, E(Key, Plaintext) is a block cipher, Constant + is a well-known constant defined by the protocol, and n-truncate + truncates its argument by taking the first n bits; here, n is the key + size of E. + + If the output of E is is shorter than n bits, then some entropy in + the key will be lost. If the Constant is smaller than the block size + of E, then it must be padded so it may be encrypted. If the Constant + is larger than the block size, then it must be folded down to the + block size to avoid chaining, which affects the distribution of + entropy. + + In any of these situations, a variation of the above construction is + used, where the folded Constant is encrypted, and the resulting + output is fed back into the encryption as necessary (the | indicates + concatentation): + + K1 = E(Key, n-fold(Constant)) + K2 = E(Key, K1) + + + +Horowitz [Page 2] + +Internet Draft Key Derivation March, 1997 + + + K3 = E(Key, K2) + K4 = ... + + DK(Key, Constant) = n-truncate(K1 | K2 | K3 | K4 ...) + + n-fold is an algorithm which takes m input bits and ``stretches'' + them to form n output bits with no loss of entropy, as described in + [Blumenthal96]. In this document, n-fold is always used to produce n + bits of output, where n is the key size of E. + + If the size of the Constant is not equal to the block size of E, then + the Constant must be n-folded to the block size of E. This number is + used as input to E. If the block size of E is less than the key + size, then the output from E is taken as input to a second invocation + of E. This process is repeated until the number of bits accumulated + is greater than or equal to the key size of E. When enough bits have + been computed, the first n are taken as the derived key. + + Since the derived key is the result of one or more encryptions in the + base key, deriving the base key from the derived key is equivalent to + determining the key from a very small number of plaintext/ciphertext + pairs. Thus, this construction is as strong as the cryptosystem + itself. + + +Deriving Keys from Passwords + + When protecting information with a password or other user data, it is + necessary to convert an arbitrary bit string into an encryption key. + In addition, it is sometimes desirable that the transformation from + password to key be difficult to reverse. A simple variation on the + construction in the prior section can be used: + + Key = DK(n-fold(Password), Well-Known Constant) + + The n-fold algorithm is reversible, so recovery of the n-fold output + is equivalent to recovery of Password. However, recovering the n- + fold output is difficult for the same reason recovering the base key + from a derived key is difficult. + + + + Traditionally, the transformation from plaintext to ciphertext, or + vice versa, is determined by the cryptographic algorithm and the key. + A simple way to think of derived keys is that the transformation is + determined by the cryptographic algorithm, the constant, and the key. + + For interoperability, the constants used to derive keys for different + purposes must be specified in the protocol specification. The + constants must not be specified on the wire, or else an attacker who + determined one derived key could provide the associated constant and + spoof data using that derived key, rather than the one the protocol + designer intended. + + + + +Horowitz [Page 3] + +Internet Draft Key Derivation March, 1997 + + + Determining which parts of a protocol require their own constants is + an issue for the designer of protocol using derived keys. + + +Security Considerations + + This entire document deals with security considerations relating to + the use of cryptography in network protocols. + + +Acknowledgements + + I would like to thank Uri Blumenthal, Hugo Krawczyk, and Bill + Sommerfeld for their contributions to this document. + + +References + + [Blumenthal96] Blumenthal, U., "A Better Key Schedule for DES-Like + Ciphers", Proceedings of PRAGOCRYPT '96, 1996. + + +Author's Address + + Marc Horowitz + Cygnus Solutions + 955 Massachusetts Avenue + Cambridge, MA 02139 + + Phone: +1 617 354 7688 + Email: marc@cygnus.com + + + + + + + + + + + + + + + + + + + + + + + + + + +Horowitz [Page 4] diff --git a/kadmin/ank.c b/kadmin/ank.c index ec3d66898..051e37eca 100644 --- a/kadmin/ank.c +++ b/kadmin/ank.c @@ -88,7 +88,15 @@ add_new_key(int argc, char **argv) password = "hemlig"; } if(password == NULL){ - if(des_read_pw_string(pwbuf, sizeof(pwbuf), "Password: ", 1)) + char *princ_name; + char *prompt; + + krb5_unparse_name(context, princ_ent, &princ_name); + asprintf (&prompt, "%s's Password: ", princ_name); + free (princ_name); + ret = des_read_pw_string (pwbuf, sizeof(pwbuf), prompt, 1); + free (prompt); + if (ret) goto out; password = pwbuf; } diff --git a/kadmin/cpw.c b/kadmin/cpw.c index 181428b20..d7d3ae17e 100644 --- a/kadmin/cpw.c +++ b/kadmin/cpw.c @@ -61,17 +61,21 @@ usage(void) static int do_cpw_entry(krb5_principal principal, void *data) { - char *pw, pwbuf[128], prompt[128], *pr; + char *pw, pwbuf[128]; struct cpw_entry_data *e = data; krb5_error_code ret = 0; pw = e->password; if(e->random == 0){ if(pw == NULL){ - krb5_unparse_name(context, principal, &pr); - snprintf(prompt, sizeof(prompt), "%s's Password: ", pr); - free(pr); + char *princ_name; + char *prompt; + + krb5_unparse_name(context, principal, &princ_name); + asprintf(&prompt, "%s's Password: ", princ_name); + free (princ_name); ret = des_read_pw_string(pwbuf, sizeof(pwbuf), prompt, 1); + free (prompt); if(ret){ return 0; /* XXX error code? */ } diff --git a/kadmin/dump.c b/kadmin/dump.c index 548aace1f..bbe7286a4 100644 --- a/kadmin/dump.c +++ b/kadmin/dump.c @@ -50,7 +50,7 @@ RCSID("$Id$"); kvno keys... mkvno (unused) - keytype + enctype keyvalue salt (- means use normal salt) creation date and principal @@ -67,10 +67,24 @@ RCSID("$Id$"); static void append_hex(char *str, krb5_data *data) { - int i; - char *p = calloc(1, data->length * 2 + 1); + int i, s = 1; + char *p; + p = data->data; for(i = 0; i < data->length; i++) - sprintf(p + 2 * i, "%02x", ((u_char*)data->data)[i]); + if(!isalnum(p[i]) && p[i] != '.'){ + s = 0; + break; + } + if(s){ + p = calloc(1, data->length + 2 + 1); + p[0] = '\"'; + p[data->length + 1] = '\"'; + memcpy(p + 1, data->data, data->length); + }else{ + p = calloc(1, data->length * 2 + 1); + for(i = 0; i < data->length; i++) + sprintf(p + 2 * i, "%02x", ((u_char*)data->data)[i]); + } strcat(str, p); free(p); } @@ -117,6 +131,20 @@ hdb_entry2string(hdb_entry *ent, char **str) ent->keys.val[i].key.keytype); strcat(buf, p); free(p); +#if 0 + if(ent->keys.val[i].enctypes != NULL) { + int j; + for(j = 0; j < ent->keys.val[i].enctypes->len; j++) { + char tmp[16]; + snprintf(tmp, sizeof(tmp), "%u", + ent->keys.val[i].enctypes->val[j]); + if(j > 0) + strcat(buf, ","); + strcat(buf, tmp); + } + } + strcat(buf, ":"); +#endif append_hex(buf, &ent->keys.val[i].key.keyvalue); strcat(buf, ":"); if(ent->keys.val[i].salt){ @@ -174,6 +202,7 @@ hdb_entry2string(hdb_entry *ent, char **str) asprintf(&p, "%d", HDBFlags2int(ent->flags)); strcat(buf, p); free(p); +#if 0 strcat(buf, " "); if(ent->etypes == NULL || ent->etypes->len == 0) @@ -187,6 +216,7 @@ hdb_entry2string(hdb_entry *ent, char **str) strcat(buf, ":"); } } +#endif *str = strdup(buf); diff --git a/kadmin/load.c b/kadmin/load.c index a36bc989c..66264abc1 100644 --- a/kadmin/load.c +++ b/kadmin/load.c @@ -147,10 +147,14 @@ parse_keys(hdb_entry *ent, char *str) key->salt->type = type; if (p_len) { - krb5_data_alloc(&key->salt->salt, (p_len - 1) / 2 + 1); - for(i = 0; i < p_len; i += 2){ - sscanf(p + i, "%02x", &tmp); - ((u_char*)key->salt->salt.data)[i / 2] = tmp; + if(*p == '\"'){ + krb5_data_copy(&key->salt->salt, p + 1, p_len - 2); + }else{ + krb5_data_alloc(&key->salt->salt, (p_len - 1) / 2 + 1); + for(i = 0; i < p_len; i += 2){ + sscanf(p + i, "%02x", &tmp); + ((u_char*)key->salt->salt.data)[i / 2] = tmp; + } } } else krb5_data_zero (&key->salt->salt); @@ -184,11 +188,12 @@ parse_hdbflags2int(char *str) return int2HDBFlags(i); } +#if 0 static void parse_etypes(char *str, unsigned **val, unsigned *len) { unsigned v; - + *val = NULL; *len = 0; while(sscanf(str, "%u", &v) == 1) { @@ -200,6 +205,7 @@ parse_etypes(char *str, unsigned **val, unsigned *len) str++; } } +#endif static void doit(char *filename, int merge) @@ -292,12 +298,14 @@ doit(char *filename, int merge) ent.max_life = parse_integer(NULL, e.max_life); ent.max_renew = parse_integer(NULL, e.max_renew); ent.flags = parse_hdbflags2int(e.flags); +#if 0 ALLOC(ent.etypes); parse_etypes(e.etypes, &ent.etypes->val, &ent.etypes->len); if(ent.etypes->len == 0) { free(ent.etypes); ent.etypes = NULL; } +#endif db->store(context, db, 1, &ent); hdb_free_entry (context, &ent); diff --git a/kdc/524.c b/kdc/524.c index 928b117cf..8cd8680cf 100644 --- a/kdc/524.c +++ b/kdc/524.c @@ -47,6 +47,7 @@ do_524(Ticket *t, krb5_data *reply, const char *from) { krb5_error_code ret = 0; krb5_principal sprinc = NULL; + krb5_crypto crypto; hdb_entry *server; Key *skey; krb5_data et_data; @@ -65,18 +66,19 @@ do_524(Ticket *t, krb5_data *reply, const char *from) from, spn); goto out; } - ret = hdb_etype2key(context, server, t->enc_part.etype, &skey); + ret = hdb_enctype2key(context, server, t->enc_part.etype, &skey); if(ret){ kdc_log(0, "No suitable key found for server (%s) " "when converting ticket from ", spn, from); goto out; } - ret = krb5_decrypt (context, - t->enc_part.cipher.data, - t->enc_part.cipher.length, - t->enc_part.etype, - &skey->key, - &et_data); + krb5_crypto_init(context, &skey->key, 0, &crypto); + ret = krb5_decrypt_EncryptedData (context, + crypto, + KRB5_KU_TICKET, + &t->enc_part, + &et_data); + krb5_crypto_destroy(context, crypto); if(ret){ kdc_log(0, "Failed to decrypt ticket from %s for %s", from, spn); goto out; @@ -118,7 +120,7 @@ do_524(Ticket *t, krb5_data *reply, const char *from) kdc_log(0, "Failed to encode v4 ticket (%s)", spn); goto out; } - ret = hdb_etype2key(context, server, KEYTYPE_DES, &skey); + ret = get_des_key(server, &skey); if(ret){ kdc_log(0, "No DES key for server (%s)", spn); goto out; diff --git a/kdc/connect.c b/kdc/connect.c index 2a8a38dd3..f3fc8e311 100644 --- a/kdc/connect.c +++ b/kdc/connect.c @@ -289,6 +289,7 @@ process_request(unsigned char *buf, else if(maybe_version4(buf, len)){ *sendlength = 0; /* elbitapmoc sdrawkcab XXX */ do_version4(buf, len, reply, from, (struct sockaddr_in*)addr); + return 0; }else if(decode_Ticket(buf, len, &ticket, &i) == 0){ ret = do_524(&ticket, reply, from); free_Ticket(&ticket); diff --git a/kdc/hprop.c b/kdc/hprop.c index 97c0e9bc9..5c666c1fb 100644 --- a/kdc/hprop.c +++ b/kdc/hprop.c @@ -149,13 +149,13 @@ v4_prop(void *arg, Principal *p) free(s); } - ent.keys.len = 1; - ALLOC(ent.keys.val); + ent.kvno = p->key_version; + ent.keys.len = 3; + ent.keys.val = malloc(ent.keys.len * sizeof(*ent.keys.val)); ent.keys.val[0].mkvno = p->kdc_key_ver; ent.keys.val[0].salt = calloc(1, sizeof(*ent.keys.val[0].salt)); ent.keys.val[0].salt->type = pa_pw_salt; - ent.kvno = p->key_version; - ent.keys.val[0].key.keytype = KEYTYPE_DES; + ent.keys.val[0].key.keytype = ETYPE_DES_CBC_MD5; krb5_data_alloc(&ent.keys.val[0].key.keyvalue, sizeof(des_cblock)); { @@ -170,6 +170,10 @@ v4_prop(void *arg, Principal *p) ent.flags.invalid = 1; } } + copy_Key(&ent.keys.val[0], &ent.keys.val[1]); + ent.keys.val[1].key.keytype = ETYPE_DES_CBC_MD4; + copy_Key(&ent.keys.val[0], &ent.keys.val[2]); + ent.keys.val[2].key.keytype = ETYPE_DES_CBC_CRC; ALLOC(ent.max_life); *ent.max_life = krb_life_to_time(0, p->max_life); @@ -270,17 +274,21 @@ ka_convert(struct prop_data *pd, int fd, struct ka_entry *ent, const char *cell) krb5_warn(pd->context, ret, "krb5_425_conv_principal"); return 0; } - hdb.keys.len = 1; - ALLOC(hdb.keys.val); + hdb.kvno = ntohl(ent->kvno); + hdb.keys.len = 3; + hdb.keys.val = malloc(hdb.keys.len * sizeof(*hdb.keys.val)); hdb.keys.val[0].mkvno = 0; /* XXX */ hdb.keys.val[0].salt = calloc(1, sizeof(*hdb.keys.val[0].salt)); hdb.keys.val[0].salt->type = hdb_afs3_salt; hdb.keys.val[0].salt->salt.data = strdup(cell); hdb.keys.val[0].salt->salt.length = strlen(cell); - hdb.kvno = ntohl(ent->kvno); - hdb.keys.val[0].key.keytype = KEYTYPE_DES; + hdb.keys.val[0].key.keytype = ETYPE_DES_CBC_MD5; krb5_data_copy(&hdb.keys.val[0].key.keyvalue, ent->key, sizeof(ent->key)); + copy_Key(&hdb.keys.val[0], &hdb.keys.val[1]); + hdb.keys.val[1].key.keytype = ETYPE_DES_CBC_MD4; + copy_Key(&hdb.keys.val[0], &hdb.keys.val[2]); + hdb.keys.val[2].key.keytype = ETYPE_DES_CBC_CRC; ALLOC(hdb.max_life); *hdb.max_life = ntohl(ent->max_life); diff --git a/kdc/kaserver.c b/kdc/kaserver.c index fbc75a9df..6f91fcb70 100644 --- a/kdc/kaserver.c +++ b/kdc/kaserver.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997 Kungliga Tekniska Högskolan + * Copyright (c) 1997, 1998 Kungliga Tekniska Högskolan * (Royal Institute of Technology, Stockholm, Sweden). * All rights reserved. * @@ -422,7 +422,7 @@ do_authenticate (struct rx_header *hdr, } /* find a DES key */ - ret = hdb_keytype2key(context, client_entry, KEYTYPE_DES, &ckey); + ret = get_des_key(client_entry, &ckey); if(ret){ kdc_log(0, "%s", krb5_get_err_text(context, ret)); make_error_reply (hdr, KANOKEYS, reply); @@ -430,7 +430,7 @@ do_authenticate (struct rx_header *hdr, } /* find a DES key */ - ret = hdb_keytype2key(context, server_entry, KEYTYPE_DES, &skey); + ret = get_des_key(server_entry, &skey); if(ret){ kdc_log(0, "%s", krb5_get_err_text(context, ret)); make_error_reply (hdr, KANOKEYS, reply); @@ -595,7 +595,7 @@ do_getticket (struct rx_header *hdr, } /* find a DES key */ - ret = hdb_keytype2key(context, krbtgt_entry, KEYTYPE_DES, &kkey); + ret = get_des_key(krbtgt_entry, &kkey); if(ret){ kdc_log(0, "%s", krb5_get_err_text(context, ret)); make_error_reply (hdr, KANOKEYS, reply); @@ -603,7 +603,7 @@ do_getticket (struct rx_header *hdr, } /* find a DES key */ - ret = hdb_keytype2key(context, server_entry, KEYTYPE_DES, &skey); + ret = get_des_key(server_entry, &skey); if(ret){ kdc_log(0, "%s", krb5_get_err_text(context, ret)); make_error_reply (hdr, KANOKEYS, reply); diff --git a/kdc/kdc_locl.h b/kdc/kdc_locl.h index aab50bb3d..b1c679bf3 100644 --- a/kdc/kdc_locl.h +++ b/kdc/kdc_locl.h @@ -87,6 +87,7 @@ krb5_error_code do_version4 (unsigned char*, size_t, krb5_data*, const char*, krb5_error_code encode_v4_ticket (void*, size_t, EncTicketPart*, PrincipalName*, size_t*); krb5_error_code encrypt_v4_ticket (void*, size_t, des_cblock*, EncryptedData*); +krb5_error_code get_des_key(hdb_entry*, Key**); int maybe_version4 (unsigned char*, int); #endif diff --git a/kdc/kerberos4.c b/kdc/kerberos4.c index 4fdb042b8..d14020fbf 100644 --- a/kdc/kerberos4.c +++ b/kdc/kerberos4.c @@ -111,6 +111,18 @@ db_fetch4(const char *name, const char *instance, const char *realm) return ent; } +krb5_error_code +get_des_key(hdb_entry *principal, Key **key) +{ + krb5_error_code ret; + ret = hdb_enctype2key(context, principal, ETYPE_DES_CBC_MD5, key); + if(ret) + ret = hdb_enctype2key(context, principal, ETYPE_DES_CBC_MD4, key); + if(ret) + ret = hdb_enctype2key(context, principal, ETYPE_DES_CBC_CRC, key); + return ret; +} + #define RCHECK(X, L) if(X){make_err_reply(reply, KFAILURE, "Packet too short"); goto L;} krb5_error_code @@ -172,7 +184,7 @@ do_version4(unsigned char *buf, goto out1; } - ret = hdb_keytype2key(context, client, KEYTYPE_DES, &ckey); + ret = get_des_key(client, &ckey); if(ret){ kdc_log(0, "%s", krb5_get_err_text(context, ret)); /* XXX */ @@ -195,7 +207,7 @@ do_version4(unsigned char *buf, } #endif - ret = hdb_keytype2key(context, server, KEYTYPE_DES, &skey); + ret = get_des_key(server, &skey); if(ret){ kdc_log(0, "%s", krb5_get_err_text(context, ret)); /* XXX */ @@ -275,7 +287,7 @@ do_version4(unsigned char *buf, goto out2; } - ret = hdb_keytype2key(context, tgt, KEYTYPE_DES, &tkey); + ret = get_des_key(tgt, &tkey); if(ret){ kdc_log(0, "%s", krb5_get_err_text(context, ret)); /* XXX */ @@ -283,7 +295,6 @@ do_version4(unsigned char *buf, "No DES key in database (krbtgt)"); goto out2; } - RCHECK(krb5_ret_int8(sp, &ticket_len), out2); RCHECK(krb5_ret_int8(sp, &req_len), out2); @@ -347,12 +358,12 @@ do_version4(unsigned char *buf, goto out2; } - ret = hdb_keytype2key(context, server, KEYTYPE_DES, &skey); + ret = get_des_key(server, &skey); if(ret){ kdc_log(0, "%s", krb5_get_err_text(context, ret)); /* XXX */ make_err_reply(reply, KDC_NULL_KEY, - "Server has no DES key"); + "No DES key in database (server)"); goto out2; } @@ -513,7 +524,9 @@ encode_v4_ticket(void *buf, size_t len, EncTicketPart *et, sp->store(sp, tmp, sizeof(tmp)); } - if(et->key.keytype != KEYTYPE_DES || + if((et->key.keytype != ETYPE_DES_CBC_MD5 && + et->key.keytype != ETYPE_DES_CBC_MD4 && + et->key.keytype != ETYPE_DES_CBC_CRC) || et->key.keyvalue.length != 8) return -1; sp->store(sp, et->key.keyvalue.data, 8); diff --git a/kdc/kerberos5.c b/kdc/kerberos5.c index c7f918129..3a13c2ca5 100644 --- a/kdc/kerberos5.c +++ b/kdc/kerberos5.c @@ -76,6 +76,40 @@ find_padata(KDC_REQ *req, int *start, int type) return NULL; } +#if 0 + +static krb5_error_code +find_keys(hdb_entry *client, + hdb_entry *server, + Key **ckey, + krb5_enctype *cetype, + Key **skey, + krb5_enctype *setype, + unsigned *etypes, + unsigned num_etypes) +{ + int i; + krb5_error_code ret; + for(i = 0; i < num_etypes; i++) { + if(client){ + ret = hdb_enctype2key(context, client, etypes[i], ckey); + if(ret) + continue; + } + if(server){ + ret = hdb_enctype2key(context, server, etypes[i], skey); + if(ret) + continue; + } + if(etype) + *cetype = *setype = etypes[i]; + return 0; + } + return KRB5KDC_ERR_ETYPE_NOSUPP; +} + +#else + static krb5_error_code find_etype(hdb_entry *princ, unsigned *etypes, unsigned len, Key **key, int *index) @@ -83,49 +117,21 @@ find_etype(hdb_entry *princ, unsigned *etypes, unsigned len, int i; krb5_error_code ret = -1; for(i = 0; i < len ; i++) - if((ret = hdb_etype2key(context, princ, etypes[i], key)) == 0) + if((ret = hdb_enctype2key(context, princ, etypes[i], key)) == 0) break; if(index) *index = i; return ret; } static krb5_error_code -find_keys1(hdb_entry *client, hdb_entry *server, - Key **ckey, krb5_enctype *cetype, - Key **skey, krb5_enctype *setype, - krb5_enctype *sess_ktype, - unsigned *etypes, unsigned num_etypes) -{ - int i; - krb5_error_code ret; - for(i = 0; i < num_etypes; i++) { - if(client){ - ret = hdb_etype2key(context, client, etypes[i], ckey); - if(ret) - continue; - } - if(server){ - ret = hdb_etype2key(context, server, etypes[i], skey); - if(ret) - continue; - } - if(cetype) - *cetype = etypes[i]; - if(setype) - *setype = etypes[i]; - if(sess_ktype) - *sess_ktype = etypes[i]; - return 0; - } - return KRB5KDC_ERR_ETYPE_NOSUPP; -} - -static krb5_error_code -find_keys2(hdb_entry *client, hdb_entry *server, - Key **ckey, krb5_enctype *cetype, - Key **skey, krb5_enctype *setype, - krb5_keytype *sess_ktype, - unsigned *etypes, unsigned num_etypes) +find_keys(hdb_entry *client, + hdb_entry *server, + Key **ckey, + krb5_enctype *cetype, + Key **skey, + krb5_enctype *setype, + unsigned *etypes, + unsigned num_etypes) { int i; krb5_error_code ret; @@ -140,43 +146,29 @@ find_keys2(hdb_entry *client, hdb_entry *server, } if(server){ - /* find session key type */ + /* find server key */ ret = find_etype(server, etypes, num_etypes, skey, NULL); if(ret){ kdc_log(0, "Server has no support for etypes"); return KRB5KDC_ERR_ETYPE_NOSUPP; } - *sess_ktype = (*skey)->key.keytype; - } - if(server){ - /* find server key */ - *skey = NULL; -#define is_better(x, y) ((x) > (y)) - for(i = 0; i < server->keys.len; i++){ - if(*skey == NULL || is_better(server->keys.val[i].key.keytype, - (*skey)->key.keytype)) - *skey = &server->keys.val[i]; - } - if(*skey == NULL){ - kdc_log(0, "No key found for server"); - return KRB5KDC_ERR_NULL_KEY; - } - ret = krb5_keytype_to_etype(context, (*skey)->key.keytype, setype); - if(ret) - return ret; + *setype = (*skey)->key.keytype; } return 0; } +#endif static krb5_error_code encode_reply(KDC_REP *rep, EncTicketPart *et, EncKDCRepPart *ek, - krb5_enctype setype, int skvno, EncryptionKey *skey, - krb5_enctype cetype, int ckvno, EncryptionKey *ckey, + krb5_enctype etype, + int skvno, EncryptionKey *skey, + int ckvno, EncryptionKey *ckey, krb5_data *reply) { unsigned char buf[8192]; /* XXX The data could be indefinite */ size_t len; krb5_error_code ret; + krb5_crypto crypto; ret = encode_EncTicketPart(buf + sizeof(buf) - 1, sizeof(buf), et, &len); if(ret) { @@ -185,13 +177,18 @@ encode_reply(KDC_REP *rep, EncTicketPart *et, EncKDCRepPart *ek, return ret; } + + krb5_crypto_init(context, skey, etype, &crypto); + krb5_encrypt_EncryptedData(context, + crypto, + KRB5_KU_TICKET, buf + sizeof(buf) - len, len, - setype, skvno, - skey, &rep->ticket.enc_part); + + krb5_crypto_destroy(context, crypto); if(rep->msg_type == krb_as_rep && !encode_as_rep_as_tgs_rep) ret = encode_EncASRepPart(buf + sizeof(buf) - 1, sizeof(buf), @@ -204,18 +201,27 @@ encode_reply(KDC_REP *rep, EncTicketPart *et, EncKDCRepPart *ek, krb5_get_err_text(context, ret)); return ret; } - krb5_encrypt_EncryptedData(context, - buf + sizeof(buf) - len, - len, - cetype, - ckvno, - ckey, - &rep->enc_part); - - if(rep->msg_type == krb_as_rep) + krb5_crypto_init(context, ckey, 0, &crypto); + if(rep->msg_type == krb_as_rep) { + krb5_encrypt_EncryptedData(context, + crypto, + KRB5_KU_AS_REP_ENC_PART, + buf + sizeof(buf) - len, + len, + ckvno, + &rep->enc_part); ret = encode_AS_REP(buf + sizeof(buf) - 1, sizeof(buf), rep, &len); - else + } else { + krb5_encrypt_EncryptedData(context, + crypto, + KRB5_KU_TGS_REP_ENC_PART_SESSION, + buf + sizeof(buf) - len, + len, + ckvno, + &rep->enc_part); ret = encode_TGS_REP(buf + sizeof(buf) - 1, sizeof(buf), rep, &len); + } + krb5_crypto_destroy(context, crypto); if(ret) { kdc_log(0, "Failed to encode KDC-REP: %s", krb5_get_err_text(context, ret)); @@ -243,51 +249,47 @@ get_pa_etype_info(METHOD_DATA *md, hdb_entry *client) krb5_error_code ret = 0; int i; ETYPE_INFO pa; - ETYPE_INFO_ENTRY *tmp; unsigned char *buf; size_t len; - pa.val = NULL; - pa.len = 0; - for(i = 0; i < client->keys.len; i++){ - krb5_enctype *etypes, *e; - krb5_enctype ex[2]; - ex[0] = client->keys.val[i].key.keytype; - ex[1] = 0; - if(context->ktype_is_etype) - ret = krb5_keytype_to_etypes(context, - client->keys.val[i].key.keytype, - &etypes); - else - etypes = ex; - for(e = etypes; *e; e++){ - tmp = realloc(pa.val, (pa.len + 1) * sizeof(*pa.val)); - if(tmp == NULL) { - free_ETYPE_INFO(&pa); - return ret; - } - pa.val = tmp; - pa.val[pa.len].etype = *e; - ALLOC(pa.val[pa.len].salttype); - if(client->keys.val[i].salt){ - *pa.val[pa.len].salttype = client->keys.val[i].salt->type; - ALLOC(pa.val[pa.len].salt); - ret = copy_octet_string(&client->keys.val[i].salt->salt, - pa.val[pa.len].salt); - if(tmp == NULL) { - free_ETYPE_INFO(&pa); - return ret; - } - } + pa.len = client->keys.len; + pa.val = malloc(pa.len * sizeof(*pa.val)); + if(pa.val == NULL) + return ENOMEM; + for(i = 0; i < client->keys.len; i++) { + pa.val[i].etype = client->keys.val[i].key.keytype; + ALLOC(pa.val[i].salttype); + if(client->keys.val[i].salt){ +#if 0 + if(client->keys.val[i].salt->type == hdb_pw_salt) + *pa.val[i].salttype = 0; /* or 1? or NULL? */ + else if(client->keys.val[i].salt->type == hdb_afs3_salt) + *pa.val[i].salttype = 2; else { - *pa.val[pa.len].salttype = pa_pw_salt; - pa.val[pa.len].salt = NULL; + free_ETYPE_INFO(&pa); + kdc_log(0, "unknown salt-type: %d", + client->keys.val[i].salt->type); + return KRB5KRB_ERR_GENERIC; } - pa.len++; + /* according to `the specs', we can't send a salt if + we have AFS3 salted key, but that requires that you + *know* what cell you are using (e.g by assuming + that the cell is the same as the realm in lower + case) */ +#else + *pa.val[i].salttype = client->keys.val[i].salt->type; +#endif + krb5_copy_data(context, &client->keys.val[i].salt->salt, + &pa.val[i].salt); + } else { +#if 0 + *pa.val[i].salttype = 1; /* or 0 with salt? */ +#else + *pa.val[i].salttype = pa_pw_salt; +#endif + pa.val[i].salt = NULL; } - if(context->ktype_is_etype) - free(etypes); } len = length_ETYPE_INFO(&pa); buf = malloc(len); @@ -313,29 +315,29 @@ check_flags(hdb_entry *client, const char *client_name, hdb_entry *server, const char *server_name, krb5_boolean is_as_req) { - /* check client */ - if (client != NULL) { + if(client != NULL) { + /* check client */ if (client->flags.invalid) { kdc_log(0, "Client (%s) has invalid bit set", client_name); return KRB5KDC_ERR_POLICY; } - + if(!client->flags.client){ kdc_log(0, "Principal may not act as client -- %s", client_name); return KRB5KDC_ERR_POLICY; } - + if (client->valid_start && *client->valid_start > kdc_time) { kdc_log(0, "Client not yet valid -- %s", client_name); return KRB5KDC_ERR_CLIENT_NOTYET; } - + if (client->valid_end && *client->valid_end < kdc_time) { kdc_log(0, "Client expired -- %s", client_name); return KRB5KDC_ERR_NAME_EXP; } - + if (client->pw_end && *client->pw_end < kdc_time && !server->flags.change_pw) { kdc_log(0, "Client's key has expired -- %s", client_name); @@ -410,17 +412,13 @@ as_rep(KDC_REQ *req, KDCOptions f = b->kdc_options; hdb_entry *client = NULL, *server = NULL; krb5_enctype cetype, setype; -#ifndef KTYPE_IS_ETYPE - krb5_keytype sess_ktype; -#else - krb5_enctype sess_ktype; -#endif EncTicketPart et; EncKDCRepPart ek; krb5_principal client_princ, server_princ; char *client_name, *server_name; krb5_error_code ret = 0; const char *e_text = NULL; + krb5_crypto crypto; Key *ckey, *skey; @@ -495,7 +493,7 @@ as_rep(KDC_REQ *req, goto out; } - ret = hdb_etype2key(context, client, enc_data.etype, &pa_key); + ret = hdb_enctype2key(context, client, enc_data.etype, &pa_key); if(ret){ e_text = "No key matches pa-data"; ret = KRB5KDC_ERR_PREAUTH_FAILED; @@ -505,10 +503,13 @@ as_rep(KDC_REQ *req, continue; } + krb5_crypto_init(context, &pa_key->key, 0, &crypto); ret = krb5_decrypt_EncryptedData (context, + crypto, + KRB5_KU_PA_ENC_TIMESTAMP, &enc_data, - &pa_key->key, &ts_data); + krb5_crypto_destroy(context, crypto); free_EncryptedData(&enc_data); if(ret){ e_text = "Failed to decrypt PA-DATA"; @@ -567,7 +568,7 @@ as_rep(KDC_REQ *req, pa->padata_value.length = 0; pa->padata_value.data = NULL; - ret = get_pa_etype_info(&method_data, client); + ret = get_pa_etype_info(&method_data, client); /* XXX check ret */ len = length_METHOD_DATA(&method_data); buf = malloc(len); @@ -593,35 +594,22 @@ as_rep(KDC_REQ *req, ret = 0; goto out2; } - - if(context->ktype_is_etype) - ret = find_keys1(client, server, &ckey, &cetype, &skey, &setype, - &sess_ktype, b->etype.val, b->etype.len); - else - ret = find_keys2(client, server, &ckey, &cetype, &skey, &setype, - &sess_ktype, b->etype.val, b->etype.len); + + ret = find_keys(client, server, &ckey, &cetype, &skey, &setype, + b->etype.val, b->etype.len); if(ret) { kdc_log(0, "Server/client has no support for etypes"); goto out; } { - char *cet, *set = NULL, *skt = NULL; - krb5_etype_to_string(context, cetype, &cet); - if(context->ktype_is_etype){ - kdc_log(5, "Using %s", cet); - }else{ - if(cetype != setype) - krb5_etype_to_string(context, setype, &set); - krb5_keytype_to_string(context, sess_ktype, &skt); - if(set) - kdc_log(5, "Using %s/%s/%s", cet, set, skt); - else - kdc_log(5, "Using %s/%s", cet, skt); - } - free(skt); - free(set); + char *cet; + char *set; + krb5_enctype_to_string(context, cetype, &cet); + krb5_enctype_to_string(context, setype, &set); + kdc_log(5, "Using %s/%s", cet, set); free(cet); + free(set); } @@ -678,13 +666,7 @@ as_rep(KDC_REQ *req, goto out; } - if(context->ktype_is_etype) { - krb5_keytype kt; - ret = krb5_etype_to_keytype(context, sess_ktype, &kt); - krb5_generate_random_keyblock(context, kt, &et.key); - et.key.keytype = sess_ktype; - }else - krb5_generate_random_keyblock(context, sess_ktype, &et.key); + krb5_generate_random_keyblock(context, setype, &et.key); copy_PrincipalName(b->cname, &et.cname); copy_Realm(&b->realm, &et.crealm); @@ -774,12 +756,12 @@ as_rep(KDC_REQ *req, ek.nonce = b->nonce; if (client->valid_end || client->pw_end) { ALLOC(ek.key_expiration); - if (client->valid_end) + if (client->valid_end) { if (client->pw_end) *ek.key_expiration = min(*client->valid_end, *client->pw_end); else *ek.key_expiration = *client->valid_end; - else + } else *ek.key_expiration = *client->pw_end; } else ek.key_expiration = NULL; @@ -803,7 +785,7 @@ as_rep(KDC_REQ *req, set_salt_padata (&rep.padata, ckey->salt); ret = encode_reply(&rep, &et, &ek, setype, server->kvno, &skey->key, - cetype, client->kvno, &ckey->key, reply); + client->kvno, &ckey->key, reply); free_EncTicketPart(&et); free_EncKDCRepPart(&ek); free_AS_REP(&rep); @@ -1017,21 +999,16 @@ tgs_make_reply(KDC_REQ_BODY *b, EncTicketPart et; KDCOptions f = b->kdc_options; krb5_error_code ret; - krb5_enctype setype; + krb5_enctype etype; Key *skey; EncryptionKey *ekey; -#ifndef KTYPE_IS_ETYPE - krb5_keytype sess_ktype; -#else - krb5_enctype sess_ktype; -#endif if(adtkt) { int i; krb5_keytype kt; ekey = &adtkt->key; for(i = 0; i < b->etype.len; i++){ - ret = krb5_etype_to_keytype(context, b->etype.val[i], &kt); + ret = krb5_enctype_to_keytype(context, b->etype.val[i], &kt); if(ret) continue; if(adtkt->key.keytype == kt) @@ -1039,18 +1016,10 @@ tgs_make_reply(KDC_REQ_BODY *b, } if(i == b->etype.len) return KRB5KDC_ERR_ETYPE_NOSUPP; - setype = b->etype.val[i]; - if(context->ktype_is_etype) - sess_ktype = b->etype.val[i]; - else - sess_ktype = kt; + etype = b->etype.val[i]; }else{ - if(context->ktype_is_etype) - ret = find_keys1(NULL, server, NULL, NULL, &skey, &setype, - &sess_ktype, b->etype.val, b->etype.len); - else - ret = find_keys2(NULL, server, NULL, NULL, &skey, &setype, - &sess_ktype, b->etype.val, b->etype.len); + ret = find_keys(NULL, server, NULL, NULL, &skey, &etype, + b->etype.val, b->etype.len); if(ret) { kdc_log(0, "Server has no support for etypes"); return ret; @@ -1146,13 +1115,7 @@ tgs_make_reply(KDC_REQ_BODY *b, /* XXX Check enc-authorization-data */ et.authorization_data = auth_data; - if(context->ktype_is_etype) { - krb5_keytype kt; - ret = krb5_etype_to_keytype(context, sess_ktype, &kt); - krb5_generate_random_keyblock(context, kt, &et.key); - et.key.keytype = sess_ktype; - }else - krb5_generate_random_keyblock(context, sess_ktype, &et.key); + krb5_generate_random_keyblock(context, etype, &et.key); et.crealm = tgt->crealm; et.cname = tgt->cname; @@ -1179,8 +1142,8 @@ tgs_make_reply(KDC_REQ_BODY *b, CAST session key. Should the DES3 etype be added to the etype list, even if we don't want a session key with DES3? */ - ret = encode_reply(&rep, &et, &ek, setype, adtkt ? 0 : server->kvno, ekey, - cetype, 0, &tgt->key, reply); + ret = encode_reply(&rep, &et, &ek, etype, adtkt ? 0 : server->kvno, ekey, + 0, &tgt->key, reply); out: free_TGS_REP(&rep); free_TransitedEncoding(&et.transited); @@ -1196,12 +1159,14 @@ out: static krb5_error_code tgs_check_authenticator(krb5_auth_context ac, - KDC_REQ_BODY *b, krb5_keyblock *key) + KDC_REQ_BODY *b, + krb5_keyblock *key) { krb5_authenticator auth; size_t len; unsigned char buf[8192]; krb5_error_code ret; + krb5_crypto crypto; krb5_auth_getauthenticator(context, ac, &auth); if(auth->cksum == NULL){ @@ -1215,10 +1180,10 @@ tgs_check_authenticator(krb5_auth_context ac, */ if ( #if 0 -!krb5_checksum_is_keyed(auth->cksum->cksumtype) +!krb5_checksum_is_keyed(context, auth->cksum->cksumtype) || #endif - !krb5_checksum_is_collision_proof(auth->cksum->cksumtype)) { + !krb5_checksum_is_collision_proof(context, auth->cksum->cksumtype)) { kdc_log(0, "Bad checksum type in authenticator: %d", auth->cksum->cksumtype); ret = KRB5KRB_AP_ERR_INAPP_CKSUM; @@ -1233,9 +1198,14 @@ tgs_check_authenticator(krb5_auth_context ac, krb5_get_err_text(context, ret)); goto out; } - ret = krb5_verify_checksum(context, buf + sizeof(buf) - len, len, - key, + krb5_crypto_init(context, key, 0, &crypto); + ret = krb5_verify_checksum(context, + crypto, + KRB5_KU_TGS_REQ_AUTH_CKSUM, + buf + sizeof(buf) - len, + len, auth->cksum); + krb5_crypto_destroy(context, crypto); if(ret){ kdc_log(0, "Failed to verify checksum: %s", krb5_get_err_text(context, ret)); @@ -1282,6 +1252,7 @@ tgs_rep2(KDC_REQ_BODY *b, krb5_ticket *ticket = NULL; krb5_flags ap_req_options; const char *e_text = NULL; + krb5_crypto crypto; hdb_entry *krbtgt = NULL; EncTicketPart *tgt; @@ -1335,10 +1306,10 @@ tgs_rep2(KDC_REQ_BODY *b, goto out2; } - ret = hdb_etype2key(context, krbtgt, ap_req.ticket.enc_part.etype, &tkey); + ret = hdb_enctype2key(context, krbtgt, ap_req.ticket.enc_part.etype, &tkey); if(ret){ char *str; - krb5_etype_to_string(context, ap_req.ticket.enc_part.etype, &str); + krb5_enctype_to_string(context, ap_req.ticket.enc_part.etype, &str); kdc_log(0, "No server key found for %s", str); free(str); ret = KRB5KRB_AP_ERR_BADKEYVER; @@ -1390,10 +1361,13 @@ tgs_rep2(KDC_REQ_BODY *b, ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; /* ? */ goto out2; } + krb5_crypto_init(context, subkey, 0, &crypto); ret = krb5_decrypt_EncryptedData (context, + crypto, + KRB5_KU_TGS_REQ_AUTH_DAT_SUBKEY, b->enc_authorization_data, - subkey, &ad); + krb5_crypto_destroy(context, crypto); if(ret){ kdc_log(0, "Failed to decrypt enc-authorization-data"); ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; /* ? */ @@ -1455,7 +1429,7 @@ tgs_rep2(KDC_REQ_BODY *b, ret = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN; goto out; } - ret = hdb_etype2key(context, uu, t->enc_part.etype, &tkey); + ret = hdb_enctype2key(context, uu, t->enc_part.etype, &tkey); if(ret){ ret = KRB5KDC_ERR_ETYPE_NOSUPP; /* XXX */ goto out; diff --git a/kdc/kstash.c b/kdc/kstash.c index a99f20eba..fa2a0ba74 100644 --- a/kdc/kstash.c +++ b/kdc/kstash.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997 Kungliga Tekniska Högskolan + * Copyright (c) 1997, 1998 Kungliga Tekniska Högskolan * (Royal Institute of Technology, Stockholm, Sweden). * All rights reserved. * @@ -71,18 +71,23 @@ int main(int argc, char **argv) krb5_errx(context, 0, "%s", heimdal_version); - key.keytype = KEYTYPE_DES; - key.keyvalue.length = sizeof(des_cblock); - key.keyvalue.data = malloc(key.keyvalue.length); + key.keytype = ETYPE_DES_CBC_MD5; /* XXX */ if(v4_keyfile){ f = fopen(v4_keyfile, "r"); if(f == NULL) krb5_err(context, 1, errno, "fopen(%s)", v4_keyfile); + key.keyvalue.length = sizeof(des_cblock); + key.keyvalue.data = malloc(key.keyvalue.length); fread(key.keyvalue.data, 1, key.keyvalue.length, f); fclose(f); }else{ + krb5_salt salt; + salt.salttype = KRB5_PW_SALT; + /* XXX better value? */ + salt.saltvalue.data = NULL; + salt.saltvalue.length = 0; des_read_pw_string(buf, sizeof(buf), "Master key: ", 1); - des_string_to_key(buf, key.keyvalue.data); + krb5_string_to_key_salt(context, key.keytype, buf, salt, &key); } #ifdef HAVE_UMASK diff --git a/kdc/string2key.c b/kdc/string2key.c index 2f92560ef..199ef1d6d 100644 --- a/kdc/string2key.c +++ b/kdc/string2key.c @@ -47,7 +47,7 @@ int afs; char *principal; char *cell; char *password; -char *keytype_str = "des"; +char *keytype_str = "des-cbc-md5"; int version; int help; @@ -73,12 +73,15 @@ usage(int status) } static void -tokey(krb5_context context, const char *password, krb5_data *salt, - krb5_keytype keytype, const char *label) +tokey(krb5_context context, + krb5_enctype enctype, + const char *password, + krb5_salt salt, + const char *label) { int i; krb5_keyblock key; - krb5_string_to_key(password, salt, keytype, &key); + krb5_string_to_key_salt(context, enctype, password, salt, &key); printf("%s: ", label); for(i = 0; i < key.keyvalue.length; i++) printf("%02x", ((unsigned char*)key.keyvalue.data)[i]); @@ -91,10 +94,10 @@ main(int argc, char **argv) { krb5_context context; krb5_principal princ; - krb5_data salt; + krb5_salt salt; int optind; char buf[1024]; - krb5_keytype keytype; + krb5_enctype etype; krb5_error_code ret; set_progname(argv[0]); @@ -120,11 +123,21 @@ main(int argc, char **argv) if(!version5 && !version4 && !afs) version5 = 1; - ret = krb5_string_to_keytype(context, keytype_str, &keytype); + ret = krb5_string_to_enctype(context, keytype_str, &etype); +#if 0 + if(ret) { + krb5_keytype keytype; + ret = krb5_string_to_keytype(context, keytype_str, &keytype); + ret = krb5_keytype_to_enctype(context, keytype, &etype); + } +#endif if(ret) - krb5_err(context, 1, ret, "%s", keytype); + krb5_err(context, 1, ret, "%s", keytype_str); - if(keytype != KEYTYPE_DES && (afs || version4)) + if((etype != ETYPE_DES_CBC_CRC && + etype != ETYPE_DES_CBC_MD4 && + etype != ETYPE_DES_CBC_MD5) && + (afs || version4)) krb5_errx(context, 1, "DES is the only valid keytype for AFS and Kerberos 4"); @@ -150,20 +163,21 @@ main(int argc, char **argv) if(version5){ krb5_parse_name(context, principal, &princ); - salt.length = 0; - salt.data = NULL; - krb5_get_salt(princ, &salt); - tokey(context, password, &salt, keytype, "Kerberos v5 key"); + krb5_get_pw_salt(context, princ, &salt); + tokey(context, etype, password, salt, "Kerberos v5 key"); + krb5_free_salt(context, salt); } if(version4){ - salt.length = 0; - salt.data = NULL; - tokey(context, password, &salt, KEYTYPE_DES, "Kerberos v4 key"); + salt.salttype = KRB5_PW_SALT; + salt.saltvalue.length = 0; + salt.saltvalue.data = NULL; + tokey(context, ETYPE_DES_CBC_MD5, password, salt, "Kerberos v4 key"); } if(afs){ - salt.length = strlen(cell); - salt.data = cell; - tokey(context, password, &salt, KEYTYPE_DES_AFS3, "AFS key"); + salt.salttype = KRB5_AFS3_SALT; + salt.saltvalue.length = strlen(cell); + salt.saltvalue.data = cell; + tokey(context, ETYPE_DES_CBC_MD5, password, salt, "AFS key"); } return 0; } diff --git a/kpasswd/kpasswdd.c b/kpasswd/kpasswdd.c index 0a4378f95..9d53e305e 100644 --- a/kpasswd/kpasswdd.c +++ b/kpasswd/kpasswdd.c @@ -212,7 +212,7 @@ change (krb5_auth_context auth_context, char *c; kadm5_principal_ent_rec ent; krb5_key_data *kd; - krb5_data salt; + krb5_salt salt; krb5_keyblock new_keyblock; char *pwd_reason; int unchanged; @@ -247,15 +247,17 @@ change (krb5_auth_context auth_context, */ kd = &ent.key_data[0]; - - salt.length = kd->key_data_length[1]; - salt.data = kd->key_data_contents[1]; + + salt.salttype = KRB5_PW_SALT; + salt.saltvalue.length = kd->key_data_length[1]; + salt.saltvalue.data = kd->key_data_contents[1]; memset (&new_keyblock, 0, sizeof(new_keyblock)); - krb5_string_to_key_data (pwd_data, - &salt, - kd->key_data_type[0], - &new_keyblock); + krb5_string_to_key_data_salt (context, + kd->key_data_type[0], + *pwd_data, + salt, + &new_keyblock); unchanged = new_keyblock.keytype == kd->key_data_type[0] && new_keyblock.keyvalue.length == kd->key_data_length[0] diff --git a/kuser/Makefile.am b/kuser/Makefile.am index 767cb30b1..a0ef112bc 100644 --- a/kuser/Makefile.am +++ b/kuser/Makefile.am @@ -15,7 +15,7 @@ kauth_SOURCES = kinit.c kauth_options.c noinst_PROGRAMS = kfoo kverify if KRB4 -AFSLIB=$(top_builddir)/lib/kafs/libkafs.a +AFSLIB=$(top_builddir)/lib/kafs/libkafs.a $(AIX_EXTRA_KAFS) else AFSLIB= endif diff --git a/kuser/kinit.c b/kuser/kinit.c index 4635c6963..0a9e60c60 100644 --- a/kuser/kinit.c +++ b/kuser/kinit.c @@ -55,6 +55,7 @@ char *renew_life = NULL; char *server = NULL; char *cred_cache = NULL; char *start_str = NULL; +struct getarg_strings etype_str; int use_keytab = 0; char *keytab_str = NULL; #ifdef KRB4 @@ -73,9 +74,6 @@ struct getargs args[] = { { "cache", 'c', arg_string, &cred_cache, "credentials cache", "cachename" }, - { "cache", 'c', arg_string, &cred_cache, - "credentials cache", "cachename" }, - { "forwardable", 'f', arg_flag, &forwardable, "get forwardable tickets"}, @@ -109,6 +107,9 @@ struct getargs args[] = { { "validate", 'v', arg_flag, &validate_flag, "validate TGT" }, + { "enctypes", 'e', arg_strings, &etype_str, + "encryption type to use", "enctype" }, + { "version", 0, arg_flag, &version_flag }, { "help", 0, arg_flag, &help_flag } }; @@ -272,6 +273,23 @@ main (int argc, char **argv) start_time = tmp; } + if(etype_str.num_strings) { + krb5_enctype *enctype = NULL; + int i; + enctype = malloc(etype_str.num_strings * sizeof(*enctype)); + if(enctype == NULL) + errx(1, "out of memory"); + for(i = 0; i < etype_str.num_strings; i++) { + ret = krb5_string_to_enctype(context, + etype_str.strings[i], + &enctype[i]); + if(ret) + errx(1, "unrecognized enctype: %s", etype_str.strings[i]); + } + krb5_get_init_creds_opt_set_etype_list(&opt, enctype, + etype_str.num_strings); + } + argc -= optind; argv += optind; diff --git a/kuser/klist.c b/kuser/klist.c index d58b3359d..aa59cb7b6 100644 --- a/kuser/klist.c +++ b/kuser/klist.c @@ -104,17 +104,26 @@ print_cred_verbose(krb5_context context, krb5_creds *cred) size_t len; char *s; decode_Ticket(cred->ticket.data, cred->ticket.length, &t, &len); - krb5_etype_to_string(context, t.enc_part.etype, &s); + krb5_enctype_to_string(context, t.enc_part.etype, &s); printf("Ticket etype: %s", s); free(s); if(t.enc_part.kvno) printf(", kvno %d", *t.enc_part.kvno); printf("\n"); + if(cred->session.keytype != t.enc_part.etype) { + ret = krb5_keytype_to_string(context, cred->session.keytype, &str); + if(ret == KRB5_PROG_KEYTYPE_NOSUPP) + ret = krb5_enctype_to_string(context, cred->session.keytype, + &str); + if(ret) + krb5_warn(context, ret, "session keytype"); + else { + printf("Session key: %s\n", str); + free(str); + } + } free_Ticket(&t); } - krb5_keytype_to_string(context, cred->session.keytype, &str); - printf("Session key: %s\n", str); - free(str); printf("Auth time: %s\n", printable_time_long(cred->times.authtime)); if(cred->times.authtime != cred->times.starttime) printf("Start time: %s\n", printable_time_long(cred->times.starttime)); diff --git a/lib/gssapi/init_sec_context.c b/lib/gssapi/init_sec_context.c index 3b7c8f576..41afe6464 100644 --- a/lib/gssapi/init_sec_context.c +++ b/lib/gssapi/init_sec_context.c @@ -182,15 +182,19 @@ init_auth goto failure; } +#if 1 + enctype = (*context_handle)->auth_context->keyblock->keytype; +#else if ((*context_handle)->auth_context->enctype) enctype = (*context_handle)->auth_context->enctype; else { - kret = krb5_keytype_to_etype(gssapi_krb5_context, + kret = krb5_keytype_to_enctype(gssapi_krb5_context, (*context_handle)->auth_context->keyblock->keytype, &enctype); if (kret) return kret; } +#endif diff --git a/lib/gssapi/krb5/init_sec_context.c b/lib/gssapi/krb5/init_sec_context.c index 3b7c8f576..41afe6464 100644 --- a/lib/gssapi/krb5/init_sec_context.c +++ b/lib/gssapi/krb5/init_sec_context.c @@ -182,15 +182,19 @@ init_auth goto failure; } +#if 1 + enctype = (*context_handle)->auth_context->keyblock->keytype; +#else if ((*context_handle)->auth_context->enctype) enctype = (*context_handle)->auth_context->enctype; else { - kret = krb5_keytype_to_etype(gssapi_krb5_context, + kret = krb5_keytype_to_enctype(gssapi_krb5_context, (*context_handle)->auth_context->keyblock->keytype, &enctype); if (kret) return kret; } +#endif diff --git a/lib/hdb/hdb.c b/lib/hdb/hdb.c index a1059a076..8b0606bb5 100644 --- a/lib/hdb/hdb.c +++ b/lib/hdb/hdb.c @@ -41,65 +41,31 @@ RCSID("$Id$"); krb5_error_code -hdb_next_keytype2key(krb5_context context, +hdb_next_enctype2key(krb5_context context, hdb_entry *e, - krb5_keytype keytype, + krb5_enctype enctype, Key **key) { - int i; - if(*key) - i = *key - e->keys.val + 1; - else - i = 0; - for(; i < e->keys.len; i++) - if(e->keys.val[i].key.keytype == keytype){ - *key = &e->keys.val[i]; + Key *k; + + for (k = *key ? *key : e->keys.val; + k < e->keys.val + e->keys.len; + k++) + if(k->key.keytype == enctype){ + *key = k; return 0; } return KRB5_PROG_ETYPE_NOSUPP; /* XXX */ } krb5_error_code -hdb_keytype2key(krb5_context context, +hdb_enctype2key(krb5_context context, hdb_entry *e, - krb5_keytype keytype, + krb5_enctype enctype, Key **key) { *key = NULL; - return hdb_next_keytype2key(context,e, keytype, key); -} - -krb5_error_code -hdb_next_etype2key(krb5_context context, - hdb_entry *e, - krb5_enctype etype, - Key **key) -{ - krb5_keytype keytype; - krb5_error_code ret; - if(e->etypes) { - /* check if the etype is listed as `supported' by this principal */ - int i; - for(i = 0; i < e->etypes->len; i++) - if(etype == e->etypes->val[i]) - break; - if(i == e->etypes->len) - return KRB5_PROG_ETYPE_NOSUPP; - } - ret = krb5_etype_to_keytype(context, etype, &keytype); - if(ret) - return ret; - return hdb_next_keytype2key(context, e, keytype, key); -} - -krb5_error_code -hdb_etype2key(krb5_context context, - hdb_entry *e, - krb5_enctype etype, - Key **key) -{ - *key = NULL; - return hdb_next_etype2key(context,e, etype, key); + return hdb_next_enctype2key(context, e, enctype, key); } /* this is a bit ugly, but will get better when the crypto framework @@ -109,7 +75,7 @@ krb5_error_code hdb_process_master_key(krb5_context context, EncryptionKey key, krb5_data *schedule) { - if(key.keytype != KEYTYPE_DES) + if(key.keytype != ETYPE_DES_CBC_MD5) return KRB5_PROG_KEYTYPE_NOSUPP; schedule->length = sizeof(des_key_schedule); schedule->data = malloc(schedule->length); diff --git a/lib/kadm5/create_s.c b/lib/kadm5/create_s.c index 0704e3c53..97792664f 100644 --- a/lib/kadm5/create_s.c +++ b/lib/kadm5/create_s.c @@ -91,15 +91,16 @@ kadm5_s_create_principal(void *server_handle, kadm5_free_principal_ent(server_handle, defent); /* XXX this should be fixed */ - ent.keys.len = 2; + ent.keys.len = 4; ent.keys.val = calloc(ent.keys.len, sizeof(*ent.keys.val)); - ent.keys.val[0].key.keytype = KEYTYPE_DES; + ent.keys.val[0].key.keytype = ETYPE_DES_CBC_CRC; /* flag as version 4 compatible salt; ignored by _kadm5_set_keys if we don't want to be compatible */ ent.keys.val[0].salt = calloc(1, sizeof(*ent.keys.val[0].salt)); ent.keys.val[0].salt->type = hdb_pw_salt; - ent.keys.val[1].key.keytype = KEYTYPE_DES3; - + ent.keys.val[1].key.keytype = ETYPE_DES_CBC_MD4; + ent.keys.val[2].key.keytype = ETYPE_DES_CBC_MD5; + ent.keys.val[3].key.keytype = ETYPE_DES3_CBC_SHA1; ret = _kadm5_set_keys(context, &ent, password); ent.created_by.time = time(NULL); diff --git a/lib/kadm5/get_s.c b/lib/kadm5/get_s.c index d119b0f2a..38c117d32 100644 --- a/lib/kadm5/get_s.c +++ b/lib/kadm5/get_s.c @@ -121,8 +121,9 @@ kadm5_s_get_principal(void *server_handle, int i; Key *key; krb5_key_data *kd; - krb5_data salt, *sp; - krb5_get_salt(ent.principal, &salt); + krb5_salt salt; + krb5_data *sp; + krb5_get_pw_salt(context->context, ent.principal, &salt); out->key_data = malloc(ent.keys.len * sizeof(*out->key_data)); for(i = 0; i < ent.keys.len; i++){ key = &ent.keys.val[i]; @@ -147,7 +148,7 @@ kadm5_s_get_principal(void *server_handle, if(key->salt) sp = &key->salt->salt; else - sp = &salt; + sp = &salt.saltvalue; kd->key_data_length[1] = sp->length; kd->key_data_contents[1] = malloc(kd->key_data_length[1]); if(kd->key_data_length[1] != 0 @@ -159,7 +160,7 @@ kadm5_s_get_principal(void *server_handle, memcpy(kd->key_data_contents[1], sp->data, kd->key_data_length[1]); out->n_key_data = i + 1; } - krb5_data_free(&salt); + krb5_free_salt(context->context, salt); } if(ret){ kadm5_free_principal_ent(context, out); diff --git a/lib/kadm5/rename_s.c b/lib/kadm5/rename_s.c index 04c625365..4cc3d2b4e 100644 --- a/lib/kadm5/rename_s.c +++ b/lib/kadm5/rename_s.c @@ -68,8 +68,10 @@ kadm5_s_rename_principal(void *server_handle, /* fix salt */ int i; Salt salt; - krb5_get_salt(source, &salt.salt); + krb5_salt salt2; + krb5_get_pw_salt(context->context, source, &salt2); salt.type = hdb_pw_salt; + salt.salt = salt2.saltvalue; for(i = 0; i < ent.keys.len; i++){ if(ent.keys.val[i].salt == NULL){ ent.keys.val[i].salt = malloc(sizeof(*ent.keys.val[i].salt)); @@ -78,7 +80,7 @@ kadm5_s_rename_principal(void *server_handle, break; } } - free_Salt(&salt); + krb5_free_salt(context->context, salt2); } if(ret) goto out2; diff --git a/lib/kadm5/set_keys.c b/lib/kadm5/set_keys.c index 63cc3171e..efed1a4b8 100644 --- a/lib/kadm5/set_keys.c +++ b/lib/kadm5/set_keys.c @@ -42,14 +42,13 @@ RCSID("$Id$"); kadm5_ret_t _kadm5_set_keys(kadm5_server_context *context, - hdb_entry *ent, const char *password) + hdb_entry *ent, + const char *password) { int i; - krb5_data salt; kadm5_ret_t ret = 0; Key *key; - krb5_get_salt(ent->principal, &salt); for(i = 0; i < ent->keys.len; i++) { key = &ent->keys.val[i]; if(key->salt && @@ -62,21 +61,27 @@ _kadm5_set_keys(kadm5_server_context *context, key->salt = NULL; } krb5_free_keyblock_contents(context->context, &key->key); - { - krb5_keytype kt = key->key.keytype; - if(kt == KEYTYPE_DES && - key->salt && - key->salt->type == hdb_afs3_salt) - kt |= KEYTYPE_USE_AFS3_SALT; - ret = krb5_string_to_key(password, - key->salt ? &key->salt->salt : &salt, - kt, + /* XXX check for DES key and AFS3 salt? */ + if(key->salt) { + krb5_salt salt; + salt.salttype = key->salt->type; + salt.saltvalue = key->salt->salt; + ret = krb5_string_to_key_salt(context->context, + key->key.keytype, + password, + salt, + &key->key); + } else + ret = krb5_string_to_key(context->context, + key->key.keytype, + password, + ent->principal, &key->key); - } - if(ret) + if(ret) { + krb5_warn(context->context, ret, "string-to-key failed"); break; + } } ent->kvno++; - krb5_data_free(&salt); return ret; } diff --git a/lib/kafs/ChangeLog b/lib/kafs/ChangeLog index 7751c699b..5ebbcfc7f 100644 --- a/lib/kafs/ChangeLog +++ b/lib/kafs/ChangeLog @@ -1,7 +1,15 @@ +Tue Dec 1 14:45:15 1998 Johan Danielsson + + * Makefile.am: fix AIX linkage + Sun Nov 22 10:40:44 1998 Assar Westerlund * Makefile.in (WFLAGS): set +Sat Nov 21 16:55:19 1998 Johan Danielsson + + * afskrb5.c: add homedir support + Sun Sep 6 20:16:27 1998 Assar Westerlund * add new functionality for specifying the homedir to krb_afslog diff --git a/lib/kafs/Makefile.am b/lib/kafs/Makefile.am index d5751ca81..e511fd56f 100644 --- a/lib/kafs/Makefile.am +++ b/lib/kafs/Makefile.am @@ -2,33 +2,60 @@ AUTOMAKE_OPTIONS = no-dependencies foreign -INCLUDES = -I$(top_builddir)/include $(INCLUDE_krb4) -DLIBDIR=\"$(libdir)\" +INCLUDES = \ + -I$(top_builddir)/include \ + $(INCLUDE_krb4) \ + -DLIBDIR=\"$(libdir)\" \ + $(AFS_EXTRA_DEFS) if KRB4 AFSLIBS = libkafs.a -if AIX -AFS_EXTRA_LIBS = afslib.so -else -AFS_EXTRA_LIBS = -endif else AFSLIBS = -AFS_EXTRA_LIBS = endif + +if AIX +AFSL_EXP = $(srcdir)/afsl.exp + +if AIX4 +AFS_EXTRA_LD = -bnoentry +else +AFS_EXTRA_LD = -e _nostart +endif + +if AIX_DYNAMIC_AFS +if HAVE_DLOPEN +AIX_SRC = +else +AIX_SRC = dlfcn.c +endif +AFS_EXTRA_LIBS = afslib.so +AFS_EXTRA_DEFS = +else +AIX_SRC = afslib.c +AFS_EXTRA_LIBS = +AFS_EXTRA_DEFS = -DSTATIC_AFS +endif + +else +AFSL_EXP = +endif # AIX + + lib_LIBRARIES = $(AFSLIBS) -foodir=$(libdir) +foodir = $(libdir) foo_DATA = $(AFS_EXTRA_LIBS) EXTRA_DATA = afslib.so CLEANFILES= $(AFS_EXTRA_LIBS) -libkafs_a_SOURCES = afssys.c afskrb.c afskrb5.c common.c +libkafs_a_SOURCES = afssys.c afskrb.c afskrb5.c common.c $(AIX_SRC) #afslib_so_SOURCES = afslib.c # AIX: this almost works with gcc, but somehow it fails to use the # correct ld, use ld instead afslib.so: afslib.o - ld -o $@ -bM:SRE -bI:$(srcdir)/afsl.exp -bE:$(srcdir)/afslib.exp -bnoentry afslib.o -lc + ld -o $@ -bM:SRE -bI:$(srcdir)/afsl.exp -bE:$(srcdir)/afslib.exp $(AFS_EXTRA_LD) afslib.o -lc $(OBJECTS): ../../include/config.h diff --git a/lib/krb5/Makefile.am b/lib/krb5/Makefile.am index b1841b81a..3a27165d7 100644 --- a/lib/krb5/Makefile.am +++ b/lib/krb5/Makefile.am @@ -24,7 +24,6 @@ libkrb5_la_SOURCES = \ build_auth.c \ cache.c \ changepw.c \ - checksum.c \ codec.c \ config_file.c \ convert_creds.c \ @@ -32,8 +31,8 @@ libkrb5_la_SOURCES = \ context.c \ crc.c \ creds.c \ + crypto.c \ data.c \ - encrypt.c \ fcache.c \ free.c \ free_host_realm.c \ @@ -67,6 +66,7 @@ libkrb5_la_SOURCES = \ mk_safe.c \ net_read.c \ net_write.c \ + n-fold.c \ padata.c \ principal.c \ prog_setup.c \ @@ -87,7 +87,6 @@ libkrb5_la_SOURCES = \ store_emem.c \ store_fd.c \ store_mem.c \ - str2key.c \ ticket.c \ time.c \ transited.c \ diff --git a/lib/krb5/auth_context.c b/lib/krb5/auth_context.c index 2503f5b36..9eeed5a60 100644 --- a/lib/krb5/auth_context.c +++ b/lib/krb5/auth_context.c @@ -58,8 +58,6 @@ krb5_auth_con_init(krb5_context context, memset (p->authenticator, 0, sizeof(*p->authenticator)); p->flags = KRB5_AUTH_CONTEXT_DO_TIME; - p->cksumtype = CKSUMTYPE_NONE; /* CKSUMTYPE_RSA_MD5_DES */ - p->enctype = ETYPE_NULL; /* ETYPE_DES_CBC_MD5 */ p->local_address = NULL; p->remote_address = NULL; *auth_context = p; @@ -282,8 +280,7 @@ krb5_auth_setcksumtype(krb5_context context, krb5_auth_context auth_context, krb5_cksumtype cksumtype) { - auth_context->cksumtype = cksumtype; - return 0; + abort(); } krb5_error_code @@ -291,8 +288,7 @@ krb5_auth_getcksumtype(krb5_context context, krb5_auth_context auth_context, krb5_cksumtype *cksumtype) { - *cksumtype = auth_context->cksumtype; - return 0; + abort(); } krb5_error_code @@ -300,7 +296,12 @@ krb5_auth_setenctype(krb5_context context, krb5_auth_context auth_context, krb5_enctype etype) { - auth_context->enctype = etype; + if(auth_context->keyblock) + krb5_free_keyblock(context, auth_context->keyblock); + ALLOC(auth_context->keyblock, 1); + if(auth_context->keyblock == NULL) + return ENOMEM; + auth_context->keyblock->keytype = etype; return 0; } @@ -309,8 +310,7 @@ krb5_auth_getenctype(krb5_context context, krb5_auth_context auth_context, krb5_enctype *etype) { - *etype = auth_context->enctype; - return 0; + abort(); } krb5_error_code diff --git a/lib/krb5/build_auth.c b/lib/krb5/build_auth.c index e8627f796..ed6d673dd 100644 --- a/lib/krb5/build_auth.c +++ b/lib/krb5/build_auth.c @@ -54,6 +54,7 @@ krb5_build_authenticator (krb5_context context, size_t buf_size; size_t len; krb5_error_code ret; + krb5_crypto crypto; auth = malloc(sizeof(*auth)); if (auth == NULL) @@ -129,10 +130,14 @@ krb5_build_authenticator (krb5_context context, } } while(ret == ASN1_OVERFLOW); - ret = krb5_encrypt (context, buf + buf_size - len, len, - enctype, - &cred->session, + ret = krb5_crypto_init(context, &cred->session, enctype, &crypto); + ret = krb5_encrypt (context, + crypto, + KRB5_KU_AP_REQ_AUTH, + buf + buf_size - len, + len, result); + krb5_crypto_destroy(context, crypto); if (ret) goto fail; diff --git a/lib/krb5/cache.c b/lib/krb5/cache.c index 2913b1bc9..245767d95 100644 --- a/lib/krb5/cache.c +++ b/lib/krb5/cache.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997 Kungliga Tekniska Högskolan + * Copyright (c) 1997, 1998 Kungliga Tekniska Högskolan * (Royal Institute of Technology, Stockholm, Sweden). * All rights reserved. * @@ -93,7 +93,7 @@ krb5_cc_resolve(krb5_context context, if(ret) return ret; } - for(i = 0; context->cc_ops[i].prefix && i < context->num_ops; i++) + for(i = 0; i < context->num_ops && context->cc_ops[i].prefix; i++) if(strncmp(context->cc_ops[i].prefix, residual, strlen(context->cc_ops[i].prefix)) == 0){ krb5_ccache p; @@ -187,9 +187,6 @@ krb5_cc_close(krb5_context context, { krb5_error_code ret; ret = id->ops->close(context, id); -#if 0 /* XXX */ - free(id->residual); -#endif free(id); return ret; } diff --git a/lib/krb5/codec.c b/lib/krb5/codec.c index a7927ab42..cf7feaddc 100644 --- a/lib/krb5/codec.c +++ b/lib/krb5/codec.c @@ -40,9 +40,13 @@ RCSID("$Id$"); -/* these functions convert does what the normal asn.1-functions does, - but converts the keytype to/from the on-the-wire enctypes */ +/* these functions does what the normal asn.1-functions does, but + converts the keytype to/from the on-the-wire enctypes */ +#if 1 +#define DECODE(T, K) return decode_ ## T((void*)data, length, t, len) +#define ENCODE(T, K) return encode_ ## T(data, length, t, len) +#else #define DECODE(T, K) \ { \ krb5_error_code ret; \ @@ -63,6 +67,7 @@ RCSID("$Id$"); return ret; \ return encode_ ## T(data, length, t, len); \ } +#endif krb5_error_code krb5_decode_EncTicketPart (krb5_context context, @@ -171,6 +176,9 @@ krb5_decode_EncKrbCredPart (krb5_context context, EncKrbCredPart *t, size_t *len) { +#if 1 + return decode_EncKrbCredPart((void*)data, length, t, len); +#else krb5_error_code ret; int i; ret = decode_EncKrbCredPart((void*)data, length, t, len); @@ -180,6 +188,7 @@ krb5_decode_EncKrbCredPart (krb5_context context, if((ret = krb5_decode_keyblock(context, &t->ticket_info.val[i].key, 1))) break; return ret; +#endif } krb5_error_code @@ -189,6 +198,7 @@ krb5_encode_EncKrbCredPart (krb5_context context, EncKrbCredPart *t, size_t *len) { +#if 0 krb5_error_code ret = 0; int i; @@ -196,6 +206,7 @@ krb5_encode_EncKrbCredPart (krb5_context context, if((ret = krb5_decode_keyblock(context, &t->ticket_info.val[i].key, 0))) break; if(ret) return ret; +#endif return encode_EncKrbCredPart (data, length, t, len); } @@ -206,6 +217,9 @@ krb5_decode_ETYPE_INFO (krb5_context context, ETYPE_INFO *t, size_t *len) { +#if 1 + return decode_ETYPE_INFO((void*)data, length, t, len); +#else krb5_error_code ret; int i; @@ -217,6 +231,7 @@ krb5_decode_ETYPE_INFO (krb5_context context, break; } return ret; +#endif } krb5_error_code @@ -226,6 +241,7 @@ krb5_encode_ETYPE_INFO (krb5_context context, ETYPE_INFO *t, size_t *len) { +#if 0 krb5_error_code ret = 0; int i; @@ -235,5 +251,6 @@ krb5_encode_ETYPE_INFO (krb5_context context, if((ret = krb5_decode_keytype(context, &t->val[i].etype, 0))) break; if(ret) return ret; +#endif return encode_ETYPE_INFO (data, length, t, len); } diff --git a/lib/krb5/context.c b/lib/krb5/context.c index 0f32198b6..acf8f7c39 100644 --- a/lib/krb5/context.c +++ b/lib/krb5/context.c @@ -40,6 +40,8 @@ RCSID("$Id$"); +int issuid(void); /* XXX */ + krb5_error_code krb5_init_context(krb5_context *context) { @@ -86,9 +88,6 @@ krb5_init_context(krb5_context *context) if (val >= 0) p->max_retries = val; - p->ktype_is_etype = krb5_config_get_bool(p, NULL, "libdefaults", - "ktype_is_etype", NULL); - p->http_proxy = krb5_config_get_string(p, NULL, "libdefaults", "http_proxy", NULL); @@ -101,7 +100,7 @@ krb5_init_context(krb5_context *context) for(i = 0; etypes[i]; i++); p->etypes = malloc((i+1) * sizeof(*p->etypes)); for(j = 0, k = 0; j < i; j++) { - if(krb5_string_to_etype(p, etypes[j], &p->etypes[k]) == 0) + if(krb5_string_to_enctype(p, etypes[j], &p->etypes[k]) == 0) k++; } p->etypes[k] = ETYPE_NULL; @@ -169,24 +168,24 @@ krb5_error_code krb5_set_default_in_tkt_etypes(krb5_context context, const krb5_enctype *etypes) { - int i; - krb5_enctype *p = NULL; + int i; + krb5_enctype *p = NULL; - if(etypes) { - i = 0; - while(etypes[i]) - if(!krb5_etype_valid(context, etypes[i++])) - return KRB5_PROG_ETYPE_NOSUPP; - ++i; - ALLOC(p, i); - if(!p) - return ENOMEM; - memmove(p, etypes, i * sizeof(krb5_enctype)); - } - if(context->etypes) - free(context->etypes); - context->etypes = p; - return 0; + if(etypes) { + i = 0; + while(etypes[i]) + if(!krb5_enctype_valid(context, etypes[i++])) + return KRB5_PROG_ETYPE_NOSUPP; + ++i; + ALLOC(p, i); + if(!p) + return ENOMEM; + memmove(p, etypes, i * sizeof(krb5_enctype)); + } + if(context->etypes) + free(context->etypes); + context->etypes = p; + return 0; } diff --git a/lib/krb5/crypto.c b/lib/krb5/crypto.c new file mode 100644 index 000000000..90a6a5b48 --- /dev/null +++ b/lib/krb5/crypto.c @@ -0,0 +1,2108 @@ +/* + * Copyright (c) 1997, 1998 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Kungliga Tekniska + * Högskolan and its contributors. + * + * 4. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "krb5_locl.h" +RCSID("$Id$"); + +#undef CRYPTO_DEBUG +#ifdef CRYPTO_DEBUG +static void krb5_crypto_debug(krb5_context, int, size_t, krb5_keyblock*); +#endif + + +struct key_data { + krb5_keyblock *key; + krb5_data *schedule; +}; + +struct key_usage { + unsigned usage; + struct key_data key; +}; + +struct krb5_crypto_data { + struct encryption_type *et; + struct key_data key; + int num_key_usage; + struct key_usage *key_usage; +}; + +#define CRYPTO_ETYPE(C) ((C)->et->type) + +/* bits for `flags' below */ +#define F_KEYED 1 /* checksum is keyed */ +#define F_CPROOF 2 /* checksum is collision proof */ +#define F_DERIVED 4 /* uses derived keys */ +#define F_VARIANT 8 /* uses `variant' keys (6.4.3) */ + +struct salt_type { + krb5_salttype type; + const char *name; + krb5_error_code (*string_to_key)(krb5_context, krb5_enctype, krb5_data, + krb5_salt, krb5_keyblock*); +}; + +struct key_type { + krb5_keytype type; /* XXX */ + const char *name; + size_t bits; + size_t size; + size_t schedule_size; +#if 0 + krb5_enctype best_etype; +#endif + void (*random_key)(krb5_context, krb5_keyblock*); + void (*schedule)(krb5_context, struct key_data *); + struct salt_type *string_to_key; +}; + +struct checksum_type { + krb5_cksumtype type; + const char *name; + size_t blocksize; + size_t checksumsize; + unsigned flags; + void (*checksum)(krb5_context, struct key_data*, void*, size_t, Checksum*); + krb5_error_code (*verify)(krb5_context, struct key_data*, + void*, size_t, Checksum*); +}; + +struct encryption_type { + krb5_enctype type; + const char *name; + size_t blocksize; + size_t confoundersize; + struct key_type *keytype; + struct checksum_type *cksumtype; + struct checksum_type *keyed_checksum; + unsigned flags; + void (*encrypt)(struct key_data *, void *, size_t, int); +}; + +#define ENCRYPTION_USAGE(U) (((U) << 8) | 0xAA) +#define INTEGRITY_USAGE(U) (((U) << 8) | 0x55) +#define CHECKSUM_USAGE(U) (((U) << 8) | 0x99) + +static struct checksum_type *_find_checksum(krb5_cksumtype type); +static struct encryption_type *_find_enctype(krb5_enctype type); +static struct key_type *_find_keytype(krb5_keytype type); +static krb5_error_code _get_derived_key(krb5_context, krb5_crypto, + unsigned, struct key_data**); +static struct key_data *_new_derived_key(krb5_crypto crypto, unsigned usage); + +/************************************************************ + * * + ************************************************************/ + +static void +DES_random_key(krb5_context context, + krb5_keyblock *key) +{ + des_cblock *k = key->keyvalue.data; + do { + krb5_generate_random_block(k, sizeof(des_cblock)); + des_set_odd_parity(k); + } while(des_is_weak_key(k)); +} + +static void +DES_schedule(krb5_context context, + struct key_data *key) +{ + des_set_key(key->key->keyvalue.data, key->schedule->data); +} + +static krb5_error_code +DES_string_to_key(krb5_context context, + krb5_enctype enctype, + krb5_data password, + krb5_salt salt, + krb5_keyblock *key) +{ + char *s; + size_t len; + des_cblock tmp; + len = password.length + salt.saltvalue.length + 1; + s = malloc(len); + if(s == NULL) + return ENOMEM; + memcpy(s, password.data, password.length); + memcpy(s + password.length, salt.saltvalue.data, salt.saltvalue.length); + s[len - 1] = '\0'; + des_string_to_key(s, &tmp); + key->keytype = enctype; + krb5_data_copy(&key->keyvalue, tmp, sizeof(tmp)); + memset(&tmp, 0, sizeof(tmp)); + memset(s, 0, len); + free(s); + return 0; +} + +/* This defines the Andrew string_to_key function. It accepts a password + * string as input and converts its via a one-way encryption algorithm to a DES + * encryption key. It is compatible with the original Andrew authentication + * service password database. + */ + +/* + * Short passwords, i.e 8 characters or less. + */ +static void +DES_AFS3_CMU_string_to_key (krb5_data pw, + krb5_data cell, + des_cblock *key) +{ + char password[8+1]; /* crypt is limited to 8 chars anyway */ + int i; + + for(i = 0; i < 8; i++) { + char c = ((i < pw.length) ? ((char*)pw.data)[i] : 0) ^ + ((i < cell.length) ? ((char*)cell.data)[i] : 0); + password[i] = c ? c : 'X'; + } + password[8] = '\0'; + + memcpy(key, crypt(password, "#~") + 2, sizeof(des_cblock)); + + /* parity is inserted into the LSB so left shift each byte up one + bit. This allows ascii characters with a zero MSB to retain as + much significance as possible. */ + for (i = 0; i < sizeof(des_cblock); i++) + ((unsigned char*)key)[i] <<= 1; + des_set_odd_parity (key); +} + +/* + * Long passwords, i.e 9 characters or more. + */ +static void +DES_AFS3_Transarc_string_to_key (krb5_data pw, + krb5_data cell, + des_cblock *key) +{ + des_key_schedule schedule; + des_cblock temp_key; + des_cblock ivec; + char password[512]; + size_t passlen; + + memcpy(password, pw.data, min(pw.length, sizeof(password))); + if(pw.length < sizeof(password)) + memcpy(password + pw.length, + cell.data, min(cell.length, + sizeof(password) - pw.length)); + passlen = min(sizeof(password), pw.length + cell.length); + memcpy(&ivec, "kerberos", 8); + memcpy(&temp_key, "kerberos", 8); + des_set_odd_parity (&temp_key); + des_set_key (&temp_key, schedule); + des_cbc_cksum ((des_cblock *)password, &ivec, passlen, schedule, &ivec); + + memcpy(&temp_key, &ivec, 8); + des_set_odd_parity (&temp_key); + des_set_key (&temp_key, schedule); + des_cbc_cksum ((des_cblock *)password, key, passlen, schedule, &ivec); + memset(&schedule, 0, sizeof(schedule)); + memset(&temp_key, 0, sizeof(temp_key)); + memset(&ivec, 0, sizeof(ivec)); + memset(password, 0, sizeof(password)); + + des_set_odd_parity (key); +} + +static krb5_error_code +DES_AFS3_string_to_key(krb5_context context, + krb5_enctype enctype, + krb5_data password, + krb5_salt salt, + krb5_keyblock *key) +{ + des_cblock tmp; + if(password.length > 8) + DES_AFS3_Transarc_string_to_key(password, salt.saltvalue, &tmp); + else + DES_AFS3_CMU_string_to_key(password, salt.saltvalue, &tmp); + key->keytype = enctype; + krb5_data_copy(&key->keyvalue, tmp, sizeof(tmp)); + memset(&key, 0, sizeof(key)); + return 0; +} + +static void +DES3_random_key(krb5_context context, + krb5_keyblock *key) +{ + des_cblock *k = key->keyvalue.data; + do { + krb5_generate_random_block(k, 3 * sizeof(des_cblock)); + des_set_odd_parity(&k[0]); + des_set_odd_parity(&k[1]); + des_set_odd_parity(&k[2]); + } while(des_is_weak_key(&k[0]) || + des_is_weak_key(&k[1]) || + des_is_weak_key(&k[2])); +} + +static void +DES3_schedule(krb5_context context, + struct key_data *key) +{ + des_cblock *k = key->key->keyvalue.data; + des_key_schedule *s = key->schedule->data; + des_set_key(&k[0], s[0]); + des_set_key(&k[1], s[1]); + des_set_key(&k[2], s[2]); +} + +/* + * A = A xor B. A & B are 8 bytes. + */ + +static void +xor (des_cblock *key, const unsigned char *b) +{ + unsigned char *a = (unsigned char*)key; + a[0] ^= b[0]; + a[1] ^= b[1]; + a[2] ^= b[2]; + a[3] ^= b[3]; + a[4] ^= b[4]; + a[5] ^= b[5]; + a[6] ^= b[6]; + a[7] ^= b[7]; +} + +static krb5_error_code +DES3_string_to_key(krb5_context context, + krb5_enctype enctype, + krb5_data password, + krb5_salt salt, + krb5_keyblock *key) +{ + char *str; + size_t len; + des_cblock keys[3]; + + len = password.length + salt.saltvalue.length; + str = malloc(len); + if(str == NULL) + return ENOMEM; + memcpy(str, password.data, password.length); + memcpy(str + password.length, salt.saltvalue.data, salt.saltvalue.length); + { + des_cblock ivec; + des_key_schedule s[3]; + int i; + + n_fold(str, len, keys, 24); + + for(i = 0; i < 3; i++){ + des_set_odd_parity(keys + i); + if(des_is_weak_key(keys + i)) + xor(keys + i, (unsigned char*)"\0\0\0\0\0\0\0\xf0"); + des_set_key(keys + i, s[i]); + } + memset(&ivec, 0, sizeof(ivec)); + des_ede3_cbc_encrypt(keys, keys, sizeof(keys), + s[0], s[1], s[2], &ivec, DES_ENCRYPT); + memset(s, 0, sizeof(s)); + memset(&ivec, 0, sizeof(ivec)); + for(i = 0; i < 3; i++){ + des_set_odd_parity(keys + i); + if(des_is_weak_key(keys + i)) + xor(keys + i, (unsigned char*)"\0\0\0\0\0\0\0\xf0"); + } + } + key->keytype = enctype; + krb5_data_copy(&key->keyvalue, keys, sizeof(keys)); + memset(keys, 0, sizeof(keys)); + memset(str, 0, len); + free(str); + return 0; +} + +static krb5_error_code +DES3_string_to_key_derived(krb5_context context, + krb5_enctype enctype, + krb5_data password, + krb5_salt salt, + krb5_keyblock *key) +{ + krb5_error_code ret; + size_t len = password.length + salt.saltvalue.length; + char *s = malloc(len); + + if(s == NULL) + return ENOMEM; + memcpy(s, password.data, password.length); + memcpy(s + password.length, salt.saltvalue.data, salt.saltvalue.length); + ret = krb5_string_to_key_derived(context, + s, + len, + enctype, + key); + memset(s, 0, len); + free(s); + return ret; +} + +extern struct salt_type des_salt[], + des3_salt[], des3_salt_derived[]; + +struct key_type keytype_null = { + KEYTYPE_NULL, + "null", + 0, + 0, + 0, + NULL, + NULL, + NULL +}; + +struct key_type keytype_des = { + KEYTYPE_DES, + "des", + 56, + sizeof(des_cblock), + sizeof(des_key_schedule), + DES_random_key, + DES_schedule, + des_salt +}; + +struct key_type keytype_des3 = { + KEYTYPE_DES3, + "des3", + 168, + 3 * sizeof(des_cblock), + 3 * sizeof(des_key_schedule), + DES3_random_key, + DES3_schedule, + des3_salt +}; + +struct key_type keytype_des3_derived = { + KEYTYPE_DES3, + "des3", + 168, + 3 * sizeof(des_cblock), + 3 * sizeof(des_key_schedule), + DES3_random_key, + DES3_schedule, + des3_salt_derived +}; + +struct key_type *keytypes[] = { + &keytype_null, + &keytype_des, + &keytype_des3_derived, + &keytype_des3 +}; + +static int num_keytypes = sizeof(keytypes) / sizeof(keytypes[0]); + +static struct key_type * +_find_keytype(krb5_keytype type) +{ + int i; + for(i = 0; i < num_keytypes; i++) + if(keytypes[i]->type == type) + return keytypes[i]; + return NULL; +} + + +struct salt_type des_salt[] = { + { + KRB5_PW_SALT, + "pw-salt", + DES_string_to_key + }, + { + KRB5_AFS3_SALT, + "afs3-salt", + DES_AFS3_string_to_key + }, + { 0 } +}; + +struct salt_type des3_salt[] = { + { + KRB5_PW_SALT, + "pw-salt", + DES3_string_to_key + }, + { 0 } +}; + +struct salt_type des3_salt_derived[] = { + { + KRB5_PW_SALT, + "pw-salt", + DES3_string_to_key_derived + }, + { 0 } +}; + +krb5_error_code +krb5_get_pw_salt(krb5_context context, + krb5_const_principal principal, + krb5_salt *salt) +{ + size_t len; + int i; + krb5_error_code ret; + char *p; + + salt->salttype = KRB5_PW_SALT; + len = strlen(principal->realm); + for (i = 0; i < principal->name.name_string.len; ++i) + len += strlen(principal->name.name_string.val[i]); + ret = krb5_data_alloc (&salt->saltvalue, len); + if (ret) + return ret; + p = salt->saltvalue.data; + memcpy (p, principal->realm, strlen(principal->realm)); + p += strlen(principal->realm); + for (i = 0; i < principal->name.name_string.len; ++i) { + memcpy (p, + principal->name.name_string.val[i], + strlen(principal->name.name_string.val[i])); + p += strlen(principal->name.name_string.val[i]); + } + return 0; +} + +krb5_error_code +krb5_free_salt(krb5_context context, + krb5_salt salt) +{ + krb5_data_free(&salt.saltvalue); + return 0; +} + +krb5_error_code +krb5_string_to_key_data (krb5_context context, + krb5_enctype enctype, + krb5_data password, + krb5_principal principal, + krb5_keyblock *key) +{ + krb5_error_code ret; + krb5_salt salt; + + ret = krb5_get_pw_salt(context, principal, &salt); + if(ret) + return ret; + ret = krb5_string_to_key_data_salt(context, enctype, password, salt, key); + krb5_free_salt(context, salt); + return ret; +} + +krb5_error_code +krb5_string_to_key (krb5_context context, + krb5_enctype enctype, + const char *password, + krb5_principal principal, + krb5_keyblock *key) +{ + krb5_data pw; + pw.data = (void*)password; + pw.length = strlen(password); + return krb5_string_to_key_data(context, enctype, pw, principal, key); +} + +krb5_error_code +krb5_string_to_key_data_salt (krb5_context context, + krb5_enctype enctype, + krb5_data password, + krb5_salt salt, + krb5_keyblock *key) +{ + struct encryption_type *et =_find_enctype(enctype); + struct salt_type *st; + if(et == NULL) + return KRB5_PROG_ETYPE_NOSUPP; + for(st = et->keytype->string_to_key; st && st->type; st++) + if(st->type == salt.salttype) + return (*st->string_to_key)(context, enctype, password, salt, key); + return HEIM_ERR_SALTTYPE_NOSUPP; +} + +krb5_error_code +krb5_string_to_key_salt (krb5_context context, + krb5_enctype enctype, + const char *password, + krb5_salt salt, + krb5_keyblock *key) +{ + krb5_data pw; + pw.data = (void*)password; + pw.length = strlen(password); + return krb5_string_to_key_data_salt(context, enctype, pw, salt, key); +} + +krb5_error_code +krb5_keytype_to_string(krb5_context context, + krb5_keytype keytype, + char **string) +{ + struct key_type *kt = _find_keytype(keytype); + if(kt == NULL) + return KRB5_PROG_KEYTYPE_NOSUPP; + *string = strdup(kt->name); + if(*string == NULL) + return ENOMEM; + return 0; +} + +krb5_error_code +krb5_string_to_keytype(krb5_context context, + const char *string, + krb5_keytype *keytype) +{ + int i; + for(i = 0; i < num_keytypes; i++) + if(strcasecmp(keytypes[i]->name, string) == 0){ + *keytype = keytypes[i]->type; + return 0; + } + return KRB5_PROG_KEYTYPE_NOSUPP; +} + +krb5_error_code +krb5_generate_random_keyblock(krb5_context context, + krb5_enctype type, + krb5_keyblock *key) +{ + krb5_error_code ret; + struct encryption_type *et = _find_enctype(type); + if(et == NULL) + return KRB5_PROG_ETYPE_NOSUPP; + ret = krb5_data_alloc(&key->keyvalue, et->keytype->size); + if(ret) + return ret; + key->keytype = type; + if(et->keytype->random_key) + (*et->keytype->random_key)(context, key); + else + krb5_generate_random_block(key->keyvalue.data, + key->keyvalue.length); + return 0; +} + +static krb5_error_code +_key_schedule(krb5_context context, + struct key_data *key) +{ + krb5_error_code ret; + struct encryption_type *et = _find_enctype(key->key->keytype); + struct key_type *kt = et->keytype; + + if(kt->schedule == NULL) + return 0; + ALLOC(key->schedule, 1); + if(key->schedule == NULL) + return ENOMEM; + ret = krb5_data_alloc(key->schedule, kt->schedule_size); + if(ret) { + free(key->schedule); + key->schedule = NULL; + return ret; + } + (*kt->schedule)(context, key); + return 0; +} + +/************************************************************ + * * + ************************************************************/ + +static void +NONE_checksum(krb5_context context, + struct key_data *key, + void *data, + size_t len, + Checksum *C) +{ +} + +static void +CRC32_checksum(krb5_context context, + struct key_data *key, + void *data, + size_t len, + Checksum *C) +{ + u_int32_t crc; + unsigned char *r = C->checksum.data; + crc_init_table (); + crc = crc_update (data, len, 0); + r[0] = crc & 0xff; + r[1] = (crc >> 8) & 0xff; + r[2] = (crc >> 16) & 0xff; + r[3] = (crc >> 24) & 0xff; +} + +static void +RSA_MD4_checksum(krb5_context context, + struct key_data *key, + void *data, + size_t len, + Checksum *C) +{ + struct md4 m; + md4_init(&m); + md4_update(&m, data, len); + md4_finito(&m, C->checksum.data); +} + +static void +RSA_MD4_DES_checksum(krb5_context context, + struct key_data *key, + void *data, + size_t len, + Checksum *cksum) +{ + struct md4 md4; + des_cblock ivec; + unsigned char *p = cksum->checksum.data; + + krb5_generate_random_block(p, 8); + md4_init(&md4); + md4_update(&md4, p, 8); + md4_update(&md4, data, len); + md4_finito(&md4, p + 8); + memset (&ivec, 0, sizeof(ivec)); + des_cbc_encrypt((des_cblock*)p, + (des_cblock*)p, + 24, + key->schedule->data, + &ivec, + DES_ENCRYPT); +} + +static krb5_error_code +RSA_MD4_DES_verify(krb5_context context, + struct key_data *key, + void *data, + size_t len, + Checksum *C) +{ + struct md4 md4; + unsigned char tmp[24]; + unsigned char res[16]; + des_cblock ivec; + krb5_error_code ret = 0; + + memset(&ivec, 0, sizeof(ivec)); + des_cbc_encrypt(C->checksum.data, + (void*)tmp, + C->checksum.length, + key->schedule->data, + &ivec, + DES_DECRYPT); + md4_init(&md4); + md4_update(&md4, tmp, 8); /* confounder */ + md4_update(&md4, data, len); + md4_finito(&md4, res); + if(memcmp(res, tmp + 8, sizeof(res)) != 0) + ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; + memset(tmp, 0, sizeof(tmp)); + memset(res, 0, sizeof(res)); + return ret; +} + +static void +RSA_MD5_checksum(krb5_context context, + struct key_data *key, + void *data, + size_t len, + Checksum *C) +{ + struct md5 m; + md5_init(&m); + md5_update(&m, data, len); + md5_finito(&m, C->checksum.data); +} + +static void +RSA_MD5_DES_checksum(krb5_context context, + struct key_data *key, + void *data, + size_t len, + Checksum *C) +{ + struct md5 md5; + des_cblock ivec; + unsigned char *p = C->checksum.data; + + krb5_generate_random_block(p, 8); + md5_init(&md5); + md5_update(&md5, p, 8); + md5_update(&md5, data, len); + md5_finito(&md5, p + 8); + memset (&ivec, 0, sizeof(ivec)); + des_cbc_encrypt((des_cblock*)p, + (des_cblock*)p, + 24, + key->schedule->data, + &ivec, + DES_ENCRYPT); +} + +static krb5_error_code +RSA_MD5_DES_verify(krb5_context context, + struct key_data *key, + void *data, + size_t len, + Checksum *C) +{ + struct md5 md5; + unsigned char tmp[24]; + unsigned char res[16]; + des_cblock ivec; + des_key_schedule *sched = key->schedule->data; + krb5_error_code ret; + + memset(&ivec, 0, sizeof(ivec)); + des_cbc_encrypt(C->checksum.data, + (void*)tmp, + C->checksum.length, + sched[0], + &ivec, + DES_DECRYPT); + md5_init(&md5); + md5_update(&md5, tmp, 8); /* confounder */ + md5_update(&md5, data, len); + md5_finito(&md5, res); + if(memcmp(res, tmp + 8, sizeof(res)) != 0) + ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; + memset(tmp, 0, sizeof(tmp)); + memset(res, 0, sizeof(res)); + return ret; +} + +static void +RSA_MD5_DES3_checksum(krb5_context context, + struct key_data *key, + void *data, + size_t len, + Checksum *C) +{ + struct md5 md5; + des_cblock ivec; + unsigned char *p = C->checksum.data; + des_key_schedule *sched = key->schedule->data; + + krb5_generate_random_block(p, 8); + md5_init(&md5); + md5_update(&md5, p, 8); + md5_update(&md5, data, len); + md5_finito(&md5, p + 8); + memset (&ivec, 0, sizeof(ivec)); + des_ede3_cbc_encrypt((des_cblock*)p, + (des_cblock*)p, + 24, + sched[0], sched[1], sched[2], + &ivec, + DES_ENCRYPT); +} + +static krb5_error_code +RSA_MD5_DES3_verify(krb5_context context, + struct key_data *key, + void *data, + size_t len, + Checksum *C) +{ + struct md5 md5; + unsigned char tmp[24]; + unsigned char res[16]; + des_cblock ivec; + des_key_schedule *sched = key->schedule->data; + krb5_error_code ret; + + memset(&ivec, 0, sizeof(ivec)); + des_ede3_cbc_encrypt(C->checksum.data, + (void*)tmp, + C->checksum.length, + sched[0], sched[1], sched[2], + &ivec, + DES_DECRYPT); + md5_init(&md5); + md5_update(&md5, tmp, 8); /* confounder */ + md5_update(&md5, data, len); + md5_finito(&md5, res); + if(memcmp(res, tmp + 8, sizeof(res)) != 0) + ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; + memset(tmp, 0, sizeof(tmp)); + memset(res, 0, sizeof(res)); + return ret; +} + +static void +SHA1_checksum(krb5_context context, + struct key_data *key, + void *data, + size_t len, + Checksum *C) +{ + struct sha m; + sha_init(&m); + sha_update(&m, data, len); + sha_finito(&m, C->checksum.data); +} + +/* HMAC according to RFC2104 */ +static void +hmac(krb5_context context, + struct checksum_type *cm, + void *data, + size_t len, + struct key_data *keyblock, + Checksum *result) +{ + unsigned char *ipad, *opad; + unsigned char *key; + size_t key_len; + int i; + + if(keyblock->key->keyvalue.length > cm->blocksize){ + (*cm->checksum)(context, + keyblock, + keyblock->key->keyvalue.data, + keyblock->key->keyvalue.length, + result); + key = result->checksum.data; + key_len = result->checksum.length; + } else { + key = keyblock->key->keyvalue.data; + key_len = keyblock->key->keyvalue.length; + } + ipad = malloc(cm->blocksize + len); + opad = malloc(cm->blocksize + cm->checksumsize); + memset(ipad, 0x36, cm->blocksize); + memset(opad, 0x5c, cm->blocksize); + for(i = 0; i < key_len; i++){ + ipad[i] ^= key[i]; + opad[i] ^= key[i]; + } + memcpy(ipad + cm->blocksize, data, len); + (*cm->checksum)(context, keyblock, ipad, cm->blocksize + len, result); + memcpy(opad + cm->blocksize, result->checksum.data, + result->checksum.length); + (*cm->checksum)(context, keyblock, opad, + cm->blocksize + cm->checksumsize, result); + memset(ipad, 0, cm->blocksize + len); + free(ipad); + memset(opad, 0, cm->blocksize + cm->checksumsize); + free(opad); +} + +static void +HMAC_SHA1_DES3_checksum(krb5_context context, + struct key_data *key, + void *data, + size_t len, + Checksum *result) +{ + struct checksum_type *c = _find_checksum(CKSUMTYPE_SHA1); + /* iovec? */ + unsigned char *p = malloc(4 + len); + k_put_int(p, len, 4); + memcpy(p + 4, data , len); + hmac(context, c, p, 4 + len, key, result); + memset(p, 0, 4 + len); + free(p); +} + +struct checksum_type checksum_none = { + CKSUMTYPE_NONE, + "none", + 1, + 0, + 0, + NONE_checksum, + NULL +}; +struct checksum_type checksum_crc32 = { + CKSUMTYPE_CRC32, + "crc32", + 1, + 4, + 0, + CRC32_checksum, + NULL +}; +struct checksum_type checksum_rsa_md4 = { + CKSUMTYPE_RSA_MD4, + "rsa-md4", + 64, + 16, + F_CPROOF, + RSA_MD4_checksum, + NULL +}; +struct checksum_type checksum_rsa_md4_des = { + CKSUMTYPE_RSA_MD4_DES, + "rsa-md4-des", + 64, + 24, + F_KEYED | F_CPROOF | F_VARIANT, + RSA_MD4_DES_checksum, + RSA_MD4_DES_verify +}; +#if 0 +struct checksum_type checksum_des_mac = { + CKSUMTYPE_DES_MAC, + "des-mac", + 0, + 0, + 0, + DES_MAC_checksum, +}; +struct checksum_type checksum_des_mac_k = { + CKSUMTYPE_DES_MAC_K, + "des-mac-k", + 0, + 0, + 0, + DES_MAC_K_checksum, +}; +struct checksum_type checksum_rsa_md4_des_k = { + CKSUMTYPE_RSA_MD4_DES_K, + "rsa-md4-des-k", + 0, + 0, + 0, + RSA_MD4_DES_K_checksum, + RSA_MD4_DES_K_verify, +}; +#endif +struct checksum_type checksum_rsa_md5 = { + CKSUMTYPE_RSA_MD5, + "rsa-md5", + 64, + 16, + F_CPROOF, + RSA_MD5_checksum, + NULL +}; +struct checksum_type checksum_rsa_md5_des = { + CKSUMTYPE_RSA_MD5_DES, + "rsa-md5-des", + 64, + 24, + F_KEYED | F_CPROOF | F_VARIANT, + RSA_MD5_DES_checksum, + RSA_MD5_DES_verify, +}; +struct checksum_type checksum_rsa_md5_des3 = { + CKSUMTYPE_RSA_MD5_DES3, + "rsa-md5-des3", + 64, + 24, + F_KEYED | F_CPROOF | F_VARIANT, + RSA_MD5_DES3_checksum, + RSA_MD5_DES3_verify, +}; +struct checksum_type checksum_sha1 = { + CKSUMTYPE_SHA1, + "sha1", + 80, + 20, + F_CPROOF, + SHA1_checksum, + NULL +}; +struct checksum_type checksum_hmac_sha1_des3 = { + CKSUMTYPE_HMAC_SHA1_DES3, + "hmac-sha1-des3", + 80, + 20, + F_KEYED | F_CPROOF | F_DERIVED, + HMAC_SHA1_DES3_checksum, + NULL +}; + +struct checksum_type *checksum_types[] = { + &checksum_none, + &checksum_crc32, + &checksum_rsa_md4, + &checksum_rsa_md4_des, +#if 0 + &checksum_des_mac, + &checksum_des_mac_k, + &checksum_rsa_md4_des_k, +#endif + &checksum_rsa_md5, + &checksum_rsa_md5_des, + &checksum_rsa_md5_des3, + &checksum_sha1, + &checksum_hmac_sha1_des3 +}; + +static int num_checksums = sizeof(checksum_types) / sizeof(checksum_types[0]); + +static struct checksum_type * +_find_checksum(krb5_cksumtype type) +{ + int i; + for(i = 0; i < num_checksums; i++) + if(checksum_types[i]->type == type) + return checksum_types[i]; + return NULL; +} + +static krb5_error_code +get_checksum_key(krb5_context context, + krb5_crypto crypto, + unsigned usage, /* not krb5_key_usage */ + struct checksum_type *ct, + struct key_data **key) +{ + krb5_error_code ret = 0; + if(ct->flags & F_DERIVED) + ret = _get_derived_key(context, crypto, usage, key); + else { + if(ct->flags & F_VARIANT) { + int i; + *key = _new_derived_key(crypto, 0xff/* KRB5_KU_RFC1510_VARIANT */); + if(*key == NULL) + return ENOMEM; + ret = krb5_copy_keyblock(context, crypto->key.key, &(*key)->key); + if(ret) + return ret; + for(i = 0; i < (*key)->key->keyvalue.length; i++) + ((unsigned char*)(*key)->key->keyvalue.data)[i] ^= 0xF0; + } else + *key = &crypto->key; + } + if(ret == 0) + ret = _key_schedule(context, *key); + return ret; +} + +static krb5_error_code +create_checksum(krb5_context context, + krb5_crypto crypto, + unsigned usage, /* not krb5_key_usage */ + krb5_cksumtype type, /* if crypto == NULL */ + void *data, + size_t len, + Checksum *result) +{ + krb5_error_code ret; + struct checksum_type *ct; + struct key_data *dkey; + int keyed_checksum; + if(crypto) { + ct = crypto->et->keyed_checksum; + if(ct == NULL) + ct = crypto->et->cksumtype; + } else + ct = _find_checksum(type); + if(ct == NULL) + return KRB5_PROG_SUMTYPE_NOSUPP; + keyed_checksum = (ct->flags & F_KEYED) != 0; + if(keyed_checksum && crypto == NULL) + return KRB5_PROG_SUMTYPE_NOSUPP; /* XXX */ + if(keyed_checksum) + ret = get_checksum_key(context, crypto, usage, ct, &dkey); + else + dkey = NULL; + result->cksumtype = ct->type; + krb5_data_alloc(&result->checksum, ct->checksumsize); + (*ct->checksum)(context, dkey, data, len, result); + return 0; +} + +krb5_error_code +krb5_create_checksum(krb5_context context, + krb5_crypto crypto, + unsigned usage_or_type, + void *data, + size_t len, + Checksum *result) +{ + return create_checksum(context, crypto, + CHECKSUM_USAGE(usage_or_type), + usage_or_type, data, len, result); +} + +static krb5_error_code +verify_checksum(krb5_context context, + krb5_crypto crypto, + unsigned usage, /* not krb5_key_usage */ + void *data, + size_t len, + Checksum *C) +{ + krb5_error_code ret; + struct key_data *dkey; + int keyed_checksum; + Checksum c; + struct checksum_type *ct; + if(crypto) { + ct = crypto->et->keyed_checksum; + if(ct == NULL) + ct = crypto->et->cksumtype; + } else + ct = _find_checksum(C->cksumtype); + if(ct == NULL) + return KRB5_PROG_SUMTYPE_NOSUPP; + if(ct->checksumsize != C->checksum.length) + return KRB5KRB_AP_ERR_BAD_INTEGRITY; /* XXX */ + keyed_checksum = (ct->flags & F_KEYED) != 0; + if(keyed_checksum && crypto == NULL) + return KRB5_PROG_SUMTYPE_NOSUPP; /* XXX */ + if(keyed_checksum) + ret = get_checksum_key(context, crypto, usage, ct, &dkey); + else + dkey = NULL; + if(ct->verify) + return (*ct->verify)(context, dkey, data, len, C); + + ret = create_checksum(context, crypto, usage, ct->type, data, len, &c); + if(ret) + return ret; + + if(c.checksum.length != C->checksum.length || + memcmp(c.checksum.data, C->checksum.data, c.checksum.length)) + ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; + else + ret = 0; + free_Checksum(&c); + return ret; +} + +krb5_error_code +krb5_verify_checksum(krb5_context context, + krb5_crypto crypto, + krb5_key_usage usage, + void *data, + size_t len, + Checksum *C) +{ + return verify_checksum(context, crypto, + CHECKSUM_USAGE(usage), data, len, C); +} + +krb5_error_code +krb5_checksumsize(krb5_context context, + krb5_cksumtype type, + size_t *size) +{ + struct checksum_type *ct = _find_checksum(type); + if(ct == NULL) + return KRB5_PROG_SUMTYPE_NOSUPP; + *size = ct->checksumsize; + return 0; +} + +krb5_boolean +krb5_checksum_is_keyed(krb5_context context, + krb5_cksumtype type) +{ + struct checksum_type *ct = _find_checksum(type); + if(ct == NULL) + return KRB5_PROG_SUMTYPE_NOSUPP; + return ct->flags & F_KEYED; +} + +krb5_boolean +krb5_checksum_is_collision_proof(krb5_context context, + krb5_cksumtype type) +{ + struct checksum_type *ct = _find_checksum(type); + if(ct == NULL) + return KRB5_PROG_SUMTYPE_NOSUPP; + return ct->flags & F_CPROOF; +} + +/************************************************************ + * * + ************************************************************/ + +static void +NULL_encrypt(struct key_data *key, + void *data, + size_t len, + krb5_boolean encrypt) +{ +} + +static void +DES_CBC_encrypt_null_ivec(struct key_data *key, + void *data, + size_t len, + krb5_boolean encrypt) +{ + des_cblock ivec; + des_key_schedule *s = key->schedule->data; + memset(&ivec, 0, sizeof(ivec)); + des_cbc_encrypt(data, data, len, *s, &ivec, encrypt); +} + +static void +DES_CBC_encrypt_key_ivec(struct key_data *key, + void *data, + size_t len, + krb5_boolean encrypt) +{ + des_cblock ivec; + des_key_schedule *s = key->schedule->data; + memcpy(&ivec, key->key->keyvalue.data, sizeof(ivec)); + des_cbc_encrypt(data, data, len, *s, &ivec, encrypt); +} + +static void +DES3_CBC_encrypt(struct key_data *key, + void *data, + size_t len, + krb5_boolean encrypt) +{ + des_cblock ivec; + des_key_schedule *s = key->schedule->data; + memset(&ivec, 0, sizeof(ivec)); + des_ede3_cbc_encrypt(data, data, len, s[0], s[1], s[2], &ivec, encrypt); +} + +static struct encryption_type etypes[] = { + { + ETYPE_NULL, + "null", + 1, + 0, + &keytype_null, + &checksum_none, + NULL, + 0, + NULL_encrypt, + }, + { + ETYPE_DES_CBC_CRC, + "des-cbc-crc", + 8, + 8, + &keytype_des, + &checksum_crc32, + NULL, + 0, + DES_CBC_encrypt_key_ivec, + }, + { + ETYPE_DES_CBC_MD4, + "des-cbc-md4", + 8, + 8, + &keytype_des, + &checksum_rsa_md4, + &checksum_rsa_md4_des, + 0, + DES_CBC_encrypt_null_ivec, + }, + { + ETYPE_DES_CBC_MD5, + "des-cbc-md5", + 8, + 8, + &keytype_des, + &checksum_rsa_md5, + &checksum_rsa_md5_des, + 0, + DES_CBC_encrypt_null_ivec, + }, + { + ETYPE_DES3_CBC_MD5, + "des3-cbc-md5", + 8, + 8, + &keytype_des3, + &checksum_rsa_md5, + &checksum_rsa_md5_des3, + 0, + DES3_CBC_encrypt, + }, +#if NEW_DES3_CODE + { + ETYPE_DES3_CBC_SHA1, + "des3-cbc-sha1", + 8, + 8, + &keytype_des3_derived, + &checksum_sha1, + &checksum_hmac_sha1_des3, + F_DERIVED, + DES3_CBC_encrypt, + }, +#else + { + ETYPE_NEW_DES3_CBC_SHA1, + "new-des3-cbc-sha1", + 8, + 8, + &keytype_des3_derived, + &checksum_sha1, + &checksum_hmac_sha1_des3, + F_DERIVED, + DES3_CBC_encrypt, + }, + { + ETYPE_DES3_CBC_SHA1, + "des3-cbc-sha1", + 8, + 8, + &keytype_des3, + &checksum_sha1, + &checksum_hmac_sha1_des3, + 0, + DES3_CBC_encrypt, + }, +#endif + { + ETYPE_DES_CBC_NONE, + "des-cbc-none", + 8, + 0, + &keytype_des, + &checksum_none, + NULL, + 0, + DES_CBC_encrypt_null_ivec, + }, + { + ETYPE_DES3_CBC_NONE, + "des3-cbc-none", + 8, + 0, + &keytype_des3_derived, + &checksum_none, + NULL, + 0, + DES_CBC_encrypt_null_ivec, + }, +}; + +static unsigned num_etypes = sizeof(etypes) / sizeof(etypes[0]); + + +static struct encryption_type * +_find_enctype(krb5_enctype type) +{ + int i; + for(i = 0; i < num_etypes; i++) + if(etypes[i].type == type) + return &etypes[i]; + return NULL; +} + + +krb5_error_code +krb5_enctype_to_string(krb5_context context, + krb5_enctype etype, + char **string) +{ + struct encryption_type *e; + e = _find_enctype(etype); + if(e == NULL) + return KRB5_PROG_ETYPE_NOSUPP; + *string = strdup(e->name); + if(*string == NULL) + return ENOMEM; + return 0; +} + +krb5_error_code +krb5_string_to_enctype(krb5_context context, + const char *string, + krb5_enctype *etype) +{ + int i; + for(i = 0; i < num_etypes; i++) + if(strcasecmp(etypes[i].name, string) == 0){ + *etype = etypes[i].type; + return 0; + } + return KRB5_PROG_ETYPE_NOSUPP; +} + +krb5_error_code +krb5_enctype_to_keytype(krb5_context context, + krb5_enctype etype, + krb5_keytype *keytype) +{ + struct encryption_type *e = _find_enctype(etype); + krb5_warnx(context, "krb5_enctype_to_keytype(%u)", etype); + if(e == NULL) + return KRB5_PROG_ETYPE_NOSUPP; + *keytype = e->keytype->type; /* XXX */ + return 0; +} + +#if 0 +krb5_error_code +krb5_keytype_to_enctype(krb5_context context, + krb5_keytype keytype, + krb5_enctype *etype) +{ + struct key_type *kt = _find_keytype(keytype); + krb5_warnx(context, "krb5_keytype_to_enctype(%u)", keytype); + if(kt == NULL) + return KRB5_PROG_KEYTYPE_NOSUPP; + *etype = kt->best_etype; + return 0; +} +#endif + + +krb5_error_code +krb5_enctype_valid(krb5_context context, + krb5_enctype etype) +{ + return _find_enctype(etype) != NULL; +} + +/* if two enctypes have compatible keys */ +krb5_boolean +krb5_enctypes_comptible_keys(krb5_context context, + krb5_enctype etype1, + krb5_enctype etype2) +{ + struct encryption_type *e1 = _find_enctype(etype1); + struct encryption_type *e2 = _find_enctype(etype2); + return e1 != NULL && e2 != NULL && e1->keytype == e2->keytype; +} + +static krb5_boolean +derived_crypto(krb5_context context, + krb5_crypto crypto) +{ + return (crypto->et->flags & F_DERIVED) != 0; +} + + +#define CHECKSUMSIZE(C) ((C)->checksumsize) +#define CHECKSUMTYPE(C) ((C)->type) + +static krb5_error_code +encrypt_internal_derived(krb5_context context, + krb5_crypto crypto, + unsigned usage, + void *data, + size_t len, + krb5_data *result) +{ + size_t sz, block_sz, checksum_sz; + Checksum cksum; + unsigned char *p, *q; + krb5_error_code ret; + struct key_data *dkey; + struct encryption_type *et = crypto->et; + + checksum_sz = CHECKSUMSIZE(et->keyed_checksum); + + sz = et->confoundersize + 4 /* length */ + len; + block_sz = (sz + et->blocksize - 1) &~ (et->blocksize - 1); /* pad */ + p = calloc(1, block_sz + checksum_sz); + if(p == NULL) + return ENOMEM; + + q = p; + krb5_generate_random_block(q, et->confoundersize); /* XXX */ + q += et->confoundersize; + k_put_int(q, len, 4); + q += 4; + memcpy(q, data, len); + + ret = create_checksum(context, + crypto, + INTEGRITY_USAGE(usage), + 0, + p, + block_sz, + &cksum); + if(ret == 0 && cksum.checksum.length != checksum_sz) + ret = KRB5_CRYPTO_INTERNAL; + if(ret) { + memset(p, 0, block_sz + checksum_sz); + free(p); + return ret; + } + memcpy(p + block_sz, cksum.checksum.data, cksum.checksum.length); + ret = _get_derived_key(context, crypto, ENCRYPTION_USAGE(usage), &dkey); + if(ret) { + memset(p, 0, block_sz + checksum_sz); + free(p); + return ret; + } + ret = _key_schedule(context, dkey); + if(ret) { + memset(p, 0, block_sz); + free(p); + return ret; + } +#ifdef CRYPTO_DEBUG + krb5_crypto_debug(context, 1, block_sz, dkey->key); +#endif + (*et->encrypt)(dkey, p, block_sz, 1); + result->data = p; + result->length = block_sz + checksum_sz; + return 0; +} + +static krb5_error_code +encrypt_internal(krb5_context context, + krb5_crypto crypto, + void *data, + size_t len, + krb5_data *result) +{ + size_t sz, block_sz, checksum_sz; + Checksum cksum; + unsigned char *p, *q; + krb5_error_code ret; + struct encryption_type *et = crypto->et; + + checksum_sz = CHECKSUMSIZE(et->cksumtype); + + sz = et->confoundersize + checksum_sz + len; + block_sz = (sz + et->blocksize - 1) &~ (et->blocksize - 1); /* pad */ + p = calloc(1, block_sz); + if(p == NULL) + return ENOMEM; + + q = p; + krb5_generate_random_block(q, et->confoundersize); /* XXX */ + q += et->confoundersize; + memset(q, 0, checksum_sz); + q += checksum_sz; + memcpy(q, data, len); + + ret = create_checksum(context, + NULL, + 0, + CHECKSUMTYPE(et->cksumtype), + p, + block_sz, + &cksum); + if(ret == 0 && cksum.checksum.length != checksum_sz) + ret = KRB5_CRYPTO_INTERNAL; + if(ret) { + memset(p, 0, block_sz); + free(p); + return ret; + } + memcpy(p + et->confoundersize, cksum.checksum.data, cksum.checksum.length); + ret = _key_schedule(context, &crypto->key); + if(ret) { + memset(p, 0, block_sz); + free(p); + return ret; + } +#ifdef CRYPTO_DEBUG + krb5_crypto_debug(context, 1, block_sz, crypto->key.key); +#endif + (*et->encrypt)(&crypto->key, p, block_sz, 1); + result->data = p; + result->length = block_sz; + return 0; +} + +static krb5_error_code +decrypt_internal_derived(krb5_context context, + krb5_crypto crypto, + unsigned usage, + void *data, + size_t len, + krb5_data *result) +{ + size_t checksum_sz; + Checksum cksum; + unsigned char *p; + krb5_error_code ret; + struct key_data *dkey; + struct encryption_type *et = crypto->et; + unsigned long l; + + p = malloc(len); + if(p == NULL) + return ENOMEM; + memcpy(p, data, len); + + checksum_sz = CHECKSUMSIZE(et->keyed_checksum); + len -= checksum_sz; + + ret = _get_derived_key(context, crypto, ENCRYPTION_USAGE(usage), &dkey); + if(ret) { + free(p); + return ret; + } + ret = _key_schedule(context, dkey); + if(ret) { + free(p); + return ret; + } +#ifdef CRYPTO_DEBUG + krb5_crypto_debug(context, 0, len, dkey->key); +#endif + (*et->encrypt)(dkey, p, len, 0); + + cksum.checksum.data = p + len; + cksum.checksum.length = checksum_sz; + + ret = verify_checksum(context, + crypto, + INTEGRITY_USAGE(usage), + p, + len, + &cksum); + if(ret) { + free(p); + return ret; + } + k_get_int(p + et->confoundersize, &l, 4); + memmove(p, p + et->confoundersize + 4, l); + result->data = realloc(p, l); + if(p == NULL) { + free(p); + return ENOMEM; + } + result->length = l; + return 0; +} + +static krb5_error_code +decrypt_internal(krb5_context context, + krb5_crypto crypto, + void *data, + size_t len, + krb5_data *result) +{ + krb5_error_code ret; + unsigned char *p; + Checksum cksum; + size_t checksum_sz, l; + struct encryption_type *et = crypto->et; + + checksum_sz = CHECKSUMSIZE(et->cksumtype); + p = malloc(len); + if(p == NULL) + return ENOMEM; + memcpy(p, data, len); + + ret = _key_schedule(context, &crypto->key); + if(ret) { + free(p); + return ret; + } +#ifdef CRYPTO_DEBUG + krb5_crypto_debug(context, 0, len, crypto->key.key); +#endif + (*et->encrypt)(&crypto->key, p, len, 0); + ret = krb5_data_copy(&cksum.checksum, p + et->confoundersize, checksum_sz); + if(ret) { + free(p); + return ret; + } + memset(p + et->confoundersize, 0, checksum_sz); + cksum.cksumtype = CHECKSUMTYPE(et->cksumtype); + ret = verify_checksum(context, NULL, 0, p, len, &cksum); + free_Checksum(&cksum); + if(ret) { + free(p); + return ret; + } + l = len - et->confoundersize - checksum_sz; + memmove(p, p + et->confoundersize + checksum_sz, l); + result->data = realloc(p, l); + if(result->data == NULL) { + free(p); + return ENOMEM; + } + result->length = l; + return 0; +} + +krb5_error_code +krb5_encrypt(krb5_context context, + krb5_crypto crypto, + unsigned usage, + void *data, + size_t len, + krb5_data *result) +{ + if(derived_crypto(context, crypto)) + return encrypt_internal_derived(context, crypto, usage, + data, len, result); + else + return encrypt_internal(context, crypto, data, len, result); +} + +krb5_error_code +krb5_encrypt_EncryptedData(krb5_context context, + krb5_crypto crypto, + unsigned usage, + void *data, + size_t len, + int kvno, + EncryptedData *result) +{ + result->etype = CRYPTO_ETYPE(crypto); + if(kvno){ + ALLOC(result->kvno, 1); + *result->kvno = kvno; + }else + result->kvno = NULL; + return krb5_encrypt(context, crypto, usage, data, len, &result->cipher); +} + +krb5_error_code +krb5_decrypt(krb5_context context, + krb5_crypto crypto, + unsigned usage, + void *data, + size_t len, + krb5_data *result) +{ + if(derived_crypto(context, crypto)) + return decrypt_internal_derived(context, crypto, usage, + data, len, result); + else + return decrypt_internal(context, crypto, data, len, result); +} + +krb5_error_code +krb5_decrypt_EncryptedData(krb5_context context, + krb5_crypto crypto, + unsigned usage, + EncryptedData *e, + krb5_data *result) +{ + return krb5_decrypt(context, crypto, usage, + e->cipher.data, e->cipher.length, result); +} + +/************************************************************ + * * + ************************************************************/ + +void +krb5_generate_random_block(void *buf, size_t len) +{ + des_cblock key, out; + static des_cblock counter; + static des_key_schedule schedule; + int i; + static int initialized = 0; + + if(!initialized) { + des_new_random_key(&key); + des_set_key(&key, schedule); + memset(&key, 0, sizeof(key)); + des_new_random_key(&counter); + } + while(len > 0) { + des_ecb_encrypt(&counter, &out, schedule, DES_ENCRYPT); + for(i = 7; i >=0; i--) + if(counter[i]++) + break; + memcpy(buf, out, min(len, sizeof(out))); + len -= min(len, sizeof(out)); + buf = (char*)buf + sizeof(out); + } +} + +/* XXX should be moved someplace else */ +static void +DES3_postproc(unsigned char *k, size_t len, struct key_data *key) +{ + unsigned char x[24]; + int ki = 0, xi = 0, kb = 8, xb = 8; + memset(x, 0, sizeof(x)); + /* insert a parity bit after every seven bits (I'm not + convinced that the first 21 bytes has more entropy than the + who 24 byte block...) */ + while(xi < 24) { + unsigned u = k[ki] & ((1 << kb) - 1); + if(kb == xb) + x[xi] |= u; + else if(kb > xb) + x[xi] |= u >> (kb - xb); + else /* kb < xb */ + x[xi] |= u << (xb - kb); + + if(kb < xb - 1) { + xb -= kb; + kb = 8; + ki++; + } else { + kb -= xb - 1; + xb = 8; + xi++; + } + } + k = key->key->keyvalue.data; + memcpy(k, x, 24); + memset(x, 0, sizeof(x)); + krb5_data_free(key->schedule); + free(key->schedule); + key->schedule = NULL; + des_set_odd_parity((des_cblock*)k); + des_set_odd_parity((des_cblock*)(k + 8)); + des_set_odd_parity((des_cblock*)(k + 16)); +} + +static krb5_error_code +derive_key(krb5_context context, + struct encryption_type *et, + struct key_data *key, + void *constant, + size_t len) +{ + unsigned char *k; + unsigned int nblocks = 0, i; + krb5_error_code ret = 0; + + struct key_type *kt = et->keytype; + ret = _key_schedule(context, key); + if(ret) + return ret; + if(et->blocksize * 8 < kt->bits || + len != et->blocksize) { + nblocks = (kt->bits + et->blocksize * 8 - 1) / (et->blocksize * 8); + k = malloc(nblocks * et->blocksize); + if(k == NULL) + return ENOMEM; + n_fold(constant, len, k, et->blocksize); + for(i = 0; i < nblocks; i++) { + if(i > 0) + memcpy(k + i * et->blocksize, + k + (i - 1) * et->blocksize, + et->blocksize); + (*et->encrypt)(key, k + i * et->blocksize, et->blocksize, 1); + } + } else { + void *c = malloc(len); + if(c == NULL) + return ENOMEM; + memcpy(c, constant, len); + (*et->encrypt)(key, c, len, 1); + k = malloc((kt->bits + 7) / 8); + if(k == NULL) + return ENOMEM; + n_fold(c, len, k, kt->bits); + free(c); + } + + /* XXX keytype dependent post-processing */ + switch(kt->type) { + case KEYTYPE_DES3: + DES3_postproc(k, nblocks * et->blocksize, key); + break; + default: + krb5_warnx(context, "derive_key() called with unknown keytype (%u)", + kt->type); + ret = KRB5_CRYPTO_INTERNAL; + break; + } + memset(k, 0, nblocks * et->blocksize); + free(k); + return ret; +} + +static struct key_data * +_new_derived_key(krb5_crypto crypto, unsigned usage) +{ + struct key_usage *d = crypto->key_usage; + d = realloc(d, (crypto->num_key_usage + 1) * sizeof(*d)); + if(d == NULL) + return NULL; + crypto->key_usage = d; + d += crypto->num_key_usage++; + memset(d, 0, sizeof(*d)); + d->usage = usage; + return &d->key; +} + +static krb5_error_code +_get_derived_key(krb5_context context, + krb5_crypto crypto, + unsigned usage, + struct key_data **key) +{ + int i; + struct key_data *d; + unsigned char constant[4]; + for(i = 0; i < crypto->num_key_usage; i++) + if(crypto->key_usage[i].usage == usage) { + *key = &crypto->key_usage[i].key; + return 0; + } + d = _new_derived_key(crypto, usage); + if(d == NULL) + return ENOMEM; + krb5_copy_keyblock(context, crypto->key.key, &d->key); + k_put_int(constant, usage, 4); + derive_key(context, crypto->et, d, constant, sizeof(constant)); + *key = d; + return 0; +} + + +krb5_error_code +krb5_crypto_init(krb5_context context, + krb5_keyblock *key, + krb5_enctype etype, + krb5_crypto *crypto) +{ + krb5_error_code ret; + ALLOC(*crypto, 1); + if(*crypto == NULL) + return ENOMEM; + if(etype == ETYPE_NULL) + etype = key->keytype; + (*crypto)->et = _find_enctype(etype); + if((*crypto)->et == NULL) { + free(*crypto); + return KRB5_PROG_ETYPE_NOSUPP; + } + ret = krb5_copy_keyblock(context, key, &(*crypto)->key.key); + if(ret) { + free(*crypto); + return ret; + } + (*crypto)->key.schedule = NULL; + (*crypto)->num_key_usage = 0; + (*crypto)->key_usage = NULL; + return 0; +} + +static void +free_key_data(krb5_context context, struct key_data *key) +{ + krb5_free_keyblock(context, key->key); + if(key->schedule) { + memset(key->schedule->data, 0, key->schedule->length); + krb5_free_data(context, key->schedule); + } +} + +static void +free_key_usage(krb5_context context, struct key_usage *ku) +{ + free_key_data(context, &ku->key); +} + +krb5_error_code +krb5_crypto_destroy(krb5_context context, + krb5_crypto crypto) +{ + int i; + + for(i = 0; i < crypto->num_key_usage; i++) + free_key_usage(context, &crypto->key_usage[i]); + free(crypto->key_usage); + free_key_data(context, &crypto->key); + return 0; +} + +krb5_error_code +krb5_string_to_key_derived(krb5_context context, + const void *str, + size_t len, + krb5_enctype etype, + krb5_keyblock *key) +{ + struct encryption_type *et = _find_enctype(etype); + krb5_error_code ret; + struct key_data kd; + + if(et == NULL) + return KRB5_PROG_ETYPE_NOSUPP; + ALLOC(kd.key, 1); + kd.key->keytype = etype; + krb5_data_alloc(&kd.key->keyvalue, et->keytype->size); + n_fold(str, len, kd.key->keyvalue.data, kd.key->keyvalue.length); + ret = derive_key(context, + et, + &kd, + "kerberos", /* XXX well known constant */ + strlen("kerberos")); + ret = krb5_copy_keyblock_contents(context, kd.key, key); + free_key_data(context, &kd); + return ret; +} + +#ifdef CRYPTO_DEBUG + +static krb5_error_code +krb5_get_keyid(krb5_context context, + krb5_keyblock *key, + u_int32_t *keyid) +{ + struct md5 md5; + unsigned char tmp[16]; + md5_init(&md5); + md5_update(&md5, key->keyvalue.data, key->keyvalue.length); + md5_finito(&md5, tmp); + *keyid = (tmp[12] << 24) | (tmp[13] << 16) | (tmp[14] << 8) | tmp[15]; + return 0; +} + +static void +krb5_crypto_debug(krb5_context context, + int encrypt, + size_t len, + krb5_keyblock *key) +{ + u_int32_t keyid; + char *kt; + krb5_get_keyid(context, key, &keyid); + krb5_enctype_to_string(context, key->keytype, &kt); + krb5_warnx(context, "%s %lu bytes with key-id %#x (%s)", + encrypt ? "encrypting" : "decrypting", + (unsigned long)len, + keyid, + kt); + free(kt); +} + +#endif /* CRYPTO_DEBUG */ diff --git a/lib/krb5/generate_subkey.c b/lib/krb5/generate_subkey.c index e285862dc..e6f7256c9 100644 --- a/lib/krb5/generate_subkey.c +++ b/lib/krb5/generate_subkey.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997 Kungliga Tekniska Högskolan + * Copyright (c) 1997, 1998 Kungliga Tekniska Högskolan * (Royal Institute of Technology, Stockholm, Sweden). * All rights reserved. * @@ -46,17 +46,9 @@ krb5_generate_subkey(krb5_context context, krb5_keyblock **subkey) { krb5_error_code ret; - krb5_keyblock *k; - - k = malloc(sizeof(**subkey)); - if (k == NULL) - return ENOMEM; - - ret = krb5_generate_random_keyblock(context, key->keytype, k); - if(ret){ - free(k); - return ret; - } - *subkey = k; - return 0; + ALLOC(*subkey, 1); + ret = krb5_generate_random_keyblock(context, key->keytype, *subkey); + if(ret) + free(*subkey); + return ret; } diff --git a/lib/krb5/get_cred.c b/lib/krb5/get_cred.c index 447055496..aaf7b1444 100644 --- a/lib/krb5/get_cred.c +++ b/lib/krb5/get_cred.c @@ -103,8 +103,10 @@ make_pa_tgs_req(krb5_context context, } free_Ticket(&ticket); - ret = krb5_mk_req_extended(context, &ac, 0, &in_data, creds, - &padata->padata_value); + + ret = krb5_mk_req_internal(context, &ac, 0, &in_data, creds, + &padata->padata_value, + KRB5_KU_TGS_REQ_AUTH_CKSUM); } out: @@ -115,71 +117,6 @@ out: return 0; } -/* - * - */ - -static krb5_error_code -init_tgs_req1(krb5_context context, - krb5_authdata *authdata, - krb5_creds *krbtgt, - krb5_keyblock **subkey, - TGS_REQ *t) -{ - krb5_error_code ret; - krb5_auth_context ac; - krb5_keyblock *key = NULL; - - ret = krb5_auth_con_init(context, &ac); - if(ret) - return ret; - ret = krb5_generate_subkey (context, &krbtgt->session, &key); - if (ret) - goto out; - ret = krb5_auth_con_setlocalsubkey(context, ac, key); - if (ret) - goto out; - - if(authdata->len){ - size_t len; - unsigned char *buf; - krb5_enctype etype; - - len = length_AuthorizationData(authdata); - buf = malloc(len); - if (buf == NULL) { - ret = ENOMEM; - goto out; - } - ret = encode_AuthorizationData(buf + len - 1, len, authdata, &len); - ALLOC(t->req_body.enc_authorization_data, 1); - if (t->req_body.enc_authorization_data == NULL) { - free (buf); - ret = ENOMEM; - goto out; - } - krb5_keytype_to_etype(context, key->keytype, &etype); - krb5_encrypt_EncryptedData(context, buf, len, etype, 0, - key, t->req_body.enc_authorization_data); - free (buf); - } else { - t->req_body.enc_authorization_data = NULL; - } - - ret = make_pa_tgs_req(context, - ac, - &t->req_body, - t->padata->val, - krbtgt); -out: - if (ret == 0) - *subkey = key; - else - krb5_free_keyblock (context, key); - krb5_auth_con_free(context, ac); - return ret; -} - /* * Create a tgs-req in `t' with `addresses', `flags', `second_ticket' * (if not-NULL), `in_creds', `krbtgt', and returning the generated @@ -204,19 +141,13 @@ init_tgs_req (krb5_context context, t->pvno = 5; t->msg_type = krb_tgs_req; if (in_creds->session.keytype) { - krb5_enctype *etypes; - - ret = krb5_keytype_to_etypes(context, - in_creds->session.keytype, - &etypes); - if (ret) - return ret; - + krb5_enctype foo[2]; + foo[0] = in_creds->session.keytype; + foo[1] = 0; ret = krb5_init_etype(context, &t->req_body.etype.len, &t->req_body.etype.val, - etypes); - free (etypes); + foo); } else { ret = krb5_init_etype(context, &t->req_body.etype.len, @@ -224,27 +155,27 @@ init_tgs_req (krb5_context context, NULL); } if (ret) - goto out; + goto fail; t->req_body.addresses = addresses; t->req_body.kdc_options = flags.b; ret = copy_Realm(&in_creds->server->realm, &t->req_body.realm); if (ret) - goto out; + goto fail; ALLOC(t->req_body.sname, 1); if (t->req_body.sname == NULL) { ret = ENOMEM; - goto out; + goto fail; } ret = copy_PrincipalName(&in_creds->server->name, t->req_body.sname); if (ret) - goto out; + goto fail; /* req_body.till should be NULL if there is no endtime specified, but old MIT code (like DCE secd) doesn't like that */ ALLOC(t->req_body.till, 1); if(t->req_body.till == NULL){ ret = ENOMEM; - goto out; + goto fail; } *t->req_body.till = in_creds->times.endtime; @@ -253,31 +184,73 @@ init_tgs_req (krb5_context context, ALLOC(t->req_body.additional_tickets, 1); if (t->req_body.additional_tickets == NULL) { ret = ENOMEM; - goto out; + goto fail; } ALLOC_SEQ(t->req_body.additional_tickets, 1); if (t->req_body.additional_tickets->val == NULL) { ret = ENOMEM; - goto out; + goto fail; } ret = copy_Ticket(second_ticket, t->req_body.additional_tickets->val); if (ret) - goto out; + goto fail; } ALLOC(t->padata, 1); if (t->padata == NULL) { ret = ENOMEM; - goto out; + goto fail; } ALLOC_SEQ(t->padata, 1); if (t->padata->val == NULL) { ret = ENOMEM; - goto out; + goto fail; } - ret = init_tgs_req1 (context, &in_creds->authdata, krbtgt, subkey, t); + { + krb5_auth_context ac; + krb5_keyblock *key; + ret = krb5_auth_con_init(context, &ac); + if(ret) + return ret; + ret = krb5_generate_subkey (context, &krbtgt->session, &key); + ret = krb5_auth_con_setlocalsubkey(context, ac, key); + if(ret == ENOMEM) + /* XXX */; -out: + if(in_creds->authdata.len){ + size_t len; + unsigned char *buf; + krb5_crypto crypto; + len = length_AuthorizationData(&in_creds->authdata); + buf = malloc(len); + ret = encode_AuthorizationData(buf + len - 1, len, &in_creds->authdata, &len); + ALLOC(t->req_body.enc_authorization_data, 1); + ret = krb5_crypto_init(context, key, 0, &crypto); + krb5_encrypt_EncryptedData(context, + crypto, + KRB5_KU_TGS_REQ_AUTH_DAT_SUBKEY, + /* KRB5_KU_TGS_REQ_AUTH_DAT_SESSION? */ + buf, + len, + 0, + t->req_body.enc_authorization_data); + krb5_crypto_destroy(context, crypto); + }else + t->req_body.enc_authorization_data = NULL; + + + ret = make_pa_tgs_req(context, + ac, + &t->req_body, + t->padata->val, + krbtgt); + if(ret) + goto fail; + *subkey = key; + + krb5_auth_con_free(context, ac); + } +fail: if (ret) free_TGS_REQ (t); return ret; @@ -316,36 +289,36 @@ get_krbtgt(krb5_context context, /* DCE compatible decrypt proc */ static krb5_error_code decrypt_tkt_with_subkey (krb5_context context, - const krb5_keyblock *key, + krb5_keyblock *key, + krb5_key_usage usage, krb5_const_pointer subkey, krb5_kdc_rep *dec_rep) { krb5_error_code ret; krb5_data data; size_t size; - krb5_data save; + krb5_crypto crypto; - ret = krb5_data_copy(&save, dec_rep->kdc_rep.enc_part.cipher.data, - dec_rep->kdc_rep.enc_part.cipher.length); - if(ret) - return ret; - - ret = krb5_decrypt (context, - dec_rep->kdc_rep.enc_part.cipher.data, - dec_rep->kdc_rep.enc_part.cipher.length, - dec_rep->kdc_rep.enc_part.etype, - key, - &data); + krb5_crypto_init(context, key, 0, &crypto); + ret = krb5_decrypt_EncryptedData (context, + crypto, + usage, + &dec_rep->kdc_rep.enc_part, + &data); + krb5_crypto_destroy(context, crypto); if(ret && subkey){ - ret = krb5_decrypt (context, save.data, save.length, - dec_rep->kdc_rep.enc_part.etype, - (krb5_keyblock*)subkey, /* local subkey */ - &data); + /* DCE compat -- try to decrypt with subkey */ + krb5_crypto_init(context, (krb5_keyblock*)subkey, 0, &crypto); + ret = krb5_decrypt_EncryptedData (context, + crypto, + KRB5_KU_TGS_REP_ENC_PART_SUB_KEY, + &dec_rep->kdc_rep.enc_part, + &data); + krb5_crypto_destroy(context, crypto); } - krb5_data_free(&save); if (ret) return ret; - + ret = krb5_decode_EncASRepPart(context, data.data, data.length, @@ -473,6 +446,7 @@ get_cred_kdc(krb5_context context, *out_creds, &krbtgt->session, NULL, + KRB5_KU_TGS_REP_ENC_PART_SESSION, &krbtgt->addresses, nonce, TRUE, diff --git a/lib/krb5/get_default_realm.c b/lib/krb5/get_default_realm.c index 0777f6338..ad3adfbad 100644 --- a/lib/krb5/get_default_realm.c +++ b/lib/krb5/get_default_realm.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997 Kungliga Tekniska Högskolan + * Copyright (c) 1997, 1998 Kungliga Tekniska Högskolan * (Royal Institute of Technology, Stockholm, Sweden). * All rights reserved. * diff --git a/lib/krb5/get_for_creds.c b/lib/krb5/get_for_creds.c index ed894626d..91b0c15c8 100644 --- a/lib/krb5/get_for_creds.c +++ b/lib/krb5/get_for_creds.c @@ -95,17 +95,7 @@ krb5_get_forwarded_creds (krb5_context context, u_char buf[1024]; int32_t sec, usec; krb5_kdc_flags kdc_flags; - krb5_enctype enctype; - - if (auth_context->enctype) - enctype = auth_context->enctype; - else { - ret = krb5_keytype_to_etype (context, - auth_context->local_subkey->keytype, - &enctype); - if (ret) - return ret; - } + krb5_crypto crypto; addrs.len = 0; addrs.val = NULL; @@ -226,13 +216,15 @@ krb5_get_forwarded_creds (krb5_context context, return ret; } + krb5_crypto_init(context, auth_context->local_subkey, 0, &crypto); ret = krb5_encrypt_EncryptedData (context, + crypto, + KRB5_KU_KRB_CRED, buf + sizeof(buf) - len, len, - enctype, 0, - auth_context->local_subkey, &cred.enc_part); + krb5_crypto_destroy(context, crypto); if (ret) { free_KRB_CRED(&cred); return ret; diff --git a/lib/krb5/get_host_realm.c b/lib/krb5/get_host_realm.c index c28df32e5..f439c5c57 100644 --- a/lib/krb5/get_host_realm.c +++ b/lib/krb5/get_host_realm.c @@ -65,6 +65,7 @@ krb5_get_host_realm(krb5_context context, const krb5_config_binding *l; struct in_addr addr; struct hostent *hostent; + char *orig_host; if (host == NULL) { if (gethostname (hostname, sizeof(hostname))) @@ -72,6 +73,8 @@ krb5_get_host_realm(krb5_context context, host = hostname; } + orig_host = host; + addr.s_addr = inet_addr(host); hostent = roken_gethostbyname (host); if (hostent == NULL && addr.s_addr != INADDR_NONE) @@ -111,6 +114,9 @@ krb5_get_host_realm(krb5_context context, } else { const char *dot = strchr (host, '.'); + if (dot == NULL) + dot = strchr (orig_host, '.'); + if (dot != NULL) { (*realms)[0] = strdup (dot + 1); if ((*realms)[0] == NULL) { diff --git a/lib/krb5/get_in_tkt.c b/lib/krb5/get_in_tkt.c index b999a9c50..04d9a4a79 100644 --- a/lib/krb5/get_in_tkt.c +++ b/lib/krb5/get_in_tkt.c @@ -80,20 +80,25 @@ cleanup: static krb5_error_code decrypt_tkt (krb5_context context, - const krb5_keyblock *key, + krb5_keyblock *key, + unsigned usage, krb5_const_pointer decrypt_arg, krb5_kdc_rep *dec_rep) { krb5_error_code ret; krb5_data data; size_t size; + krb5_crypto crypto; + + krb5_crypto_init(context, key, 0, &crypto); + + ret = krb5_decrypt_EncryptedData (context, + crypto, + usage, + &dec_rep->kdc_rep.enc_part, + &data); + krb5_crypto_destroy(context, crypto); - ret = krb5_decrypt (context, - dec_rep->kdc_rep.enc_part.cipher.data, - dec_rep->kdc_rep.enc_part.cipher.length, - dec_rep->kdc_rep.enc_part.etype, - key, - &data); if (ret) return ret; @@ -119,6 +124,7 @@ _krb5_extract_ticket(krb5_context context, krb5_creds *creds, krb5_keyblock *key, krb5_const_pointer keyseed, + krb5_key_usage key_usage, krb5_addresses *addrs, unsigned nonce, krb5_boolean allow_server_mismatch, @@ -147,12 +153,16 @@ _krb5_extract_ticket(krb5_context context, /* extract ticket */ { - unsigned char buf[1024]; + unsigned char *buf; size_t len; - encode_Ticket(buf + sizeof(buf) - 1, sizeof(buf), - &rep->kdc_rep.ticket, &len); - creds->ticket.data = malloc(len); - memcpy(creds->ticket.data, buf + sizeof(buf) - len, len); + len = length_Ticket(&rep->kdc_rep.ticket); + buf = malloc(len); + if(buf == NULL) { + ret = ENOMEM; + goto out; + } + encode_Ticket(buf + len - 1, len, &rep->kdc_rep.ticket, &len); + creds->ticket.data = buf; creds->ticket.length = len; creds->second_ticket.length = 0; creds->second_ticket.data = NULL; @@ -183,7 +193,7 @@ _krb5_extract_ticket(krb5_context context, if (decrypt_proc == NULL) decrypt_proc = decrypt_tkt; - ret = (*decrypt_proc)(context, key, decryptarg, rep); + ret = (*decrypt_proc)(context, key, key_usage, decryptarg, rep); if (ret) goto out; @@ -294,6 +304,7 @@ make_pa_enc_timestamp(krb5_context context, PA_DATA *pa, krb5_error_code ret; int32_t sec, usec; unsigned usec2; + krb5_crypto crypto; krb5_us_timeofday (context, &sec, &usec); p.patimestamp = sec; @@ -307,13 +318,15 @@ make_pa_enc_timestamp(krb5_context context, PA_DATA *pa, if (ret) return ret; + krb5_crypto_init(context, key, 0, &crypto); ret = krb5_encrypt_EncryptedData(context, + crypto, + KRB5_KU_PA_ENC_TIMESTAMP, buf + sizeof(buf) - len, len, - etype, 0, - key, &encdata); + krb5_crypto_destroy(context, crypto); if (ret) return ret; @@ -338,31 +351,29 @@ add_padata(krb5_context context, krb5_principal client, krb5_key_proc key_proc, krb5_const_pointer keyseed, - krb5_keytype keytype, - krb5_data *salt) + krb5_enctype enctype, + krb5_salt *salt) { krb5_error_code ret; PA_DATA *pa2; krb5_keyblock *key; - krb5_enctype etype; - krb5_data salt2; + krb5_salt salt2; - krb5_data_zero(&salt2); if(salt == NULL) { /* default to standard salt */ - ret = krb5_get_salt (client, &salt2); + ret = krb5_get_pw_salt (context, client, &salt2); salt = &salt2; } - ret = (*key_proc)(context, keytype, salt, keyseed, &key); - krb5_data_free(&salt2); + ret = (*key_proc)(context, enctype, *salt, keyseed, &key); + if(salt == &salt2) + krb5_free_salt(context, salt2); if (ret) return ret; pa2 = realloc(md->val, (md->len + 1) * sizeof(*md->val)); if(pa2 == NULL) return ENOMEM; md->val = pa2; - krb5_keytype_to_etype(context, keytype, &etype); - ret = make_pa_enc_timestamp(context, &md->val[md->len], etype, key); + ret = make_pa_enc_timestamp(context, &md->val[md->len], enctype, key); krb5_free_keyblock (context, key); if(ret) return ret; @@ -384,7 +395,7 @@ init_as_req (krb5_context context, AS_REQ *a) { krb5_error_code ret; - krb5_data salt; + krb5_salt salt; krb5_enctype etype; memset(a, 0, sizeof(*a)); @@ -478,29 +489,30 @@ init_as_req (krb5_context context, } a->padata->val = tmp; for(j = 0; j < preauth->val[i].info.len; j++) { - krb5_keytype keytype = preauth->val[i].info.val[j].etype; - if(preauth->val[i].info.val[j].salttype && - *preauth->val[i].info.val[j].salttype == - KRB5_PA_AFS3_SALT) { - if(keytype != KEYTYPE_DES) { - ret = KRB5_PROG_KEYTYPE_NOSUPP; - goto fail; - } - keytype = KEYTYPE_DES_AFS3; - } + krb5_salt *sp = &salt; + if(preauth->val[i].info.val[j].salttype) + salt.salttype = *preauth->val[i].info.val[j].salttype; + else + salt.salttype = KRB5_PW_SALT; + if(preauth->val[i].info.val[j].salt) + salt.saltvalue = *preauth->val[i].info.val[j].salt; + else + if(salt.salttype == KRB5_PW_SALT) + sp = NULL; + else + krb5_data_zero(&salt.saltvalue); add_padata(context, a->padata, creds->client, - key_proc, keyseed, keytype, - preauth->val[i].info.val[j].salt); + key_proc, keyseed, + preauth->val[i].info.val[j].etype, + sp); } } } - } else /* not sure this is the way to use `ptypes' */ if (ptypes == NULL || *ptypes == KRB5_PADATA_NONE) a->padata = NULL; else if (*ptypes == KRB5_PADATA_ENC_TIMESTAMP) { - krb5_keytype keytype; ALLOC(a->padata, 1); if (a->padata == NULL) { ret = ENOMEM; @@ -509,18 +521,15 @@ init_as_req (krb5_context context, a->padata->len = 0; a->padata->val = NULL; - ret = krb5_etype_to_keytype(context, etype, &keytype); - if(ret) - goto fail; - /* make a v5 salted pa-data */ add_padata(context, a->padata, creds->client, - key_proc, keyseed, keytype, NULL); + key_proc, keyseed, etype, NULL); /* make a v4 salted pa-data */ - krb5_data_zero(&salt); + salt.salttype = KRB5_PW_SALT; + krb5_data_zero(&salt.saltvalue); add_padata(context, a->padata, creds->client, - key_proc, keyseed, keytype, &salt); + key_proc, keyseed, etype, &salt); } else { ret = KRB5_PREAUTH_BAD_TYPE; goto fail; @@ -550,7 +559,7 @@ krb5_get_in_cred(krb5_context context, krb5_kdc_rep rep; krb5_data req, resp; char buf[BUFSIZ]; - krb5_data salt; + krb5_salt salt; krb5_keyblock *key; size_t size; krb5_kdc_flags opts; @@ -627,32 +636,33 @@ krb5_get_in_cred(krb5_context context, } } if(pa) { - krb5_keytype keytype; - ret = krb5_etype_to_keytype(context, etype, &keytype); - if(pa->padata_type == pa_afs3_salt){ - if(keytype != KEYTYPE_DES) - return KRB5_PROG_KEYTYPE_NOSUPP; - keytype = KEYTYPE_DES_AFS3; - } - ret = (*key_proc)(context, keytype, &pa->padata_value, keyseed, &key); + salt.salttype = pa->padata_type; + salt.saltvalue = pa->padata_value; + + ret = (*key_proc)(context, etype, salt, keyseed, &key); } else { /* make a v5 salted pa-data */ - krb5_keytype keytype; - salt.length = 0; - salt.data = NULL; - ret = krb5_get_salt (creds->client, &salt); + ret = krb5_get_pw_salt (context, creds->client, &salt); if (ret) return ret; - ret = krb5_etype_to_keytype(context, etype, &keytype); - ret = (*key_proc)(context, keytype, &salt, keyseed, &key); - krb5_data_free (&salt); + ret = (*key_proc)(context, etype, salt, keyseed, &key); + krb5_free_salt(context, salt); } if (ret) return ret; - ret = _krb5_extract_ticket(context, &rep, creds, key, keyseed, - NULL, nonce, FALSE, decrypt_proc, decryptarg); + ret = _krb5_extract_ticket(context, + &rep, + creds, + key, + keyseed, + KRB5_KU_AS_REP_ENC_PART, + NULL, + nonce, + FALSE, + decrypt_proc, + decryptarg); memset (key->keyvalue.data, 0, key->keyvalue.length); krb5_free_keyblock_contents (context, key); free (key); diff --git a/lib/krb5/get_in_tkt_pw.c b/lib/krb5/get_in_tkt_pw.c index 1f4cfd4e3..18a255152 100644 --- a/lib/krb5/get_in_tkt_pw.c +++ b/lib/krb5/get_in_tkt_pw.c @@ -42,28 +42,25 @@ RCSID("$Id$"); krb5_error_code krb5_password_key_proc (krb5_context context, - krb5_keytype type, - krb5_data *salt, + krb5_enctype type, + krb5_salt salt, krb5_const_pointer keyseed, krb5_keyblock **key) { - krb5_error_code ret; - char *password = (char *)keyseed; - char buf[BUFSIZ]; + krb5_error_code ret; + char *password = (char *)keyseed; + char buf[BUFSIZ]; - *key = malloc (sizeof (**key)); - if (*key == NULL) - return ENOMEM; - (*key)->keytype = type; - (*key)->keyvalue.length = 0; - (*key)->keyvalue.data = NULL; - if (password == NULL) { - des_read_pw_string (buf, sizeof(buf), "Password: ", 0); - password = buf; - } - ret = krb5_string_to_key (password, salt, type, *key); - memset (buf, 0, sizeof(buf)); - return ret; + *key = malloc (sizeof (**key)); + if (*key == NULL) + return ENOMEM; + if (password == NULL) { + des_read_pw_string (buf, sizeof(buf), "Password: ", 0); + password = buf; + } + ret = krb5_string_to_key_salt (context, type, password, salt, *key); + memset (buf, 0, sizeof(buf)); + return ret; } krb5_error_code diff --git a/lib/krb5/get_in_tkt_with_keytab.c b/lib/krb5/get_in_tkt_with_keytab.c index d3d04eca5..7216d28fd 100644 --- a/lib/krb5/get_in_tkt_with_keytab.c +++ b/lib/krb5/get_in_tkt_with_keytab.c @@ -42,8 +42,8 @@ RCSID("$Id$"); krb5_error_code krb5_keytab_key_proc (krb5_context context, - krb5_keytype type, - krb5_data *salt, + krb5_enctype enctype, + krb5_salt salt, krb5_const_pointer keyseed, krb5_keyblock **key) { @@ -60,7 +60,7 @@ krb5_keytab_key_proc (krb5_context context, real_keytab = keytab; ret = krb5_kt_get_entry (context, real_keytab, principal, - 0, type, &entry); + 0, enctype, &entry); if (keytab == NULL) krb5_kt_close (context, real_keytab); diff --git a/lib/krb5/get_in_tkt_with_skey.c b/lib/krb5/get_in_tkt_with_skey.c index bdff76042..6ad275070 100644 --- a/lib/krb5/get_in_tkt_with_skey.c +++ b/lib/krb5/get_in_tkt_with_skey.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997 Kungliga Tekniska Högskolan + * Copyright (c) 1997, 1998 Kungliga Tekniska Högskolan * (Royal Institute of Technology, Stockholm, Sweden). * All rights reserved. * @@ -42,8 +42,8 @@ RCSID("$Id$"); static krb5_error_code krb5_skey_key_proc (krb5_context context, - krb5_keytype type, - krb5_data *salt, + krb5_enctype type, + krb5_salt salt, krb5_const_pointer keyseed, krb5_keyblock **key) { diff --git a/lib/krb5/heim_err.et b/lib/krb5/heim_err.et index 9211771d0..6aa376d6e 100644 --- a/lib/krb5/heim_err.et +++ b/lib/krb5/heim_err.et @@ -11,5 +11,6 @@ prefix HEIM_ERR error_code LOG_PARSE, "Error parsing log destination" error_code V4_PRINC_NO_CONV, "Failed to convert v4 principal" +error_code SALTTYPE_NOSUPP, "Salt type is not supported by enctype" end diff --git a/lib/krb5/keytab.c b/lib/krb5/keytab.c index a7ee7cb37..f9a3eb6cd 100644 --- a/lib/krb5/keytab.c +++ b/lib/krb5/keytab.c @@ -132,7 +132,7 @@ krb5_kt_read_service_key(krb5_context context, krb5_pointer keyprocarg, krb5_principal principal, krb5_kvno vno, - krb5_keytype keytype, + krb5_enctype enctype, krb5_keyblock **key) { krb5_keytab keytab; @@ -147,7 +147,7 @@ krb5_kt_read_service_key(krb5_context context, if (r) return r; - r = krb5_kt_get_entry (context, keytab, principal, vno, keytype, &entry); + r = krb5_kt_get_entry (context, keytab, principal, vno, enctype, &entry); krb5_kt_close (context, keytab); if (r) return r; @@ -191,14 +191,14 @@ kt_compare(krb5_context context, krb5_keytab_entry *entry, krb5_const_principal principal, krb5_kvno vno, - krb5_keytype keytype) + krb5_enctype enctype) { if(principal != NULL && !krb5_principal_compare(context, entry->principal, principal)) return FALSE; if(vno && vno != entry->vno) return FALSE; - if(keytype && keytype != entry->keyblock.keytype) + if(enctype && enctype != entry->keyblock.keytype) return FALSE; return TRUE; } @@ -208,14 +208,14 @@ krb5_kt_get_entry(krb5_context context, krb5_keytab id, krb5_const_principal principal, krb5_kvno kvno, - krb5_keytype keytype, + krb5_enctype enctype, krb5_keytab_entry *entry) { krb5_keytab_entry tmp; krb5_error_code r; krb5_kt_cursor cursor; - if(id->get) return (*id->get)(context, id, principal, kvno, keytype, entry); + if(id->get) return (*id->get)(context, id, principal, kvno, enctype, entry); r = krb5_kt_start_seq_get (context, id, &cursor); if (r) @@ -223,7 +223,7 @@ krb5_kt_get_entry(krb5_context context, entry->vno = 0; while (krb5_kt_next_entry(context, id, &tmp, &cursor) == 0) { - if (kt_compare(context, &tmp, principal, 0, keytype)) { + if (kt_compare(context, &tmp, principal, 0, enctype)) { if (kvno == tmp.vno) { krb5_kt_copy_entry_contents (context, &tmp, entry); krb5_kt_free_entry (context, &tmp); diff --git a/lib/krb5/krb5.h b/lib/krb5/krb5.h index 4438c93cb..a6176f18d 100644 --- a/lib/krb5/krb5.h +++ b/lib/krb5/krb5.h @@ -71,6 +71,9 @@ typedef const void *krb5_const_pointer; typedef octet_string krb5_data; +struct krb5_crypto_data; +typedef struct krb5_crypto_data *krb5_crypto; + typedef enum krb5_cksumtype { CKSUMTYPE_NONE = 0, CKSUMTYPE_CRC32 = 1, @@ -93,11 +96,20 @@ typedef enum krb5_enctype { ETYPE_DES_CBC_MD4 = 2, ETYPE_DES_CBC_MD5 = 3, ETYPE_DES3_CBC_MD5 = 5, - ETYPE_DES3_CBC_SHA1 = 7, +#if NEW_DES3_CODE + ETYPE_NEW_DES3_CBC_SHA1 = 7, + ETYPE_DES3_CBC_SHA1 = ETYPE_NEW_DES3_CBC_SHA1, +#else + ETYPE_OLD_DES3_CBC_SHA1 = 7, + ETYPE_NEW_DES3_CBC_SHA1 = 99, + ETYPE_DES3_CBC_SHA1 = ETYPE_OLD_DES3_CBC_SHA1, +#endif ETYPE_SIGN_DSA_GENERATE = 8, ETYPE_ENCRYPT_RSA_PRIV = 9, ETYPE_ENCRYPT_RSA_PUB = 10, - ETYPE_ENCTYPE_PK_CROSS = 48 + ETYPE_ENCTYPE_PK_CROSS = 48, + ETYPE_DES_CBC_NONE = 0x1000, + ETYPE_DES3_CBC_NONE = 0x1001 } krb5_enctype; typedef enum krb5_preauthtype { @@ -108,11 +120,73 @@ typedef enum krb5_preauthtype { KRB5_PADATA_ENC_SECURID } krb5_preauthtype; +typedef enum krb5_key_usage { + KRB5_KU_PA_ENC_TIMESTAMP = 1, + /* AS-REQ PA-ENC-TIMESTAMP padata timestamp, encrypted with the + client key (section 5.4.1) */ + KRB5_KU_TICKET = 2, + /* AS-REP Ticket and TGS-REP Ticket (includes tgs session key or + application session key), encrypted with the service key + (section 5.4.2) */ + KRB5_KU_AS_REP_ENC_PART = 3, + /* AS-REP encrypted part (includes tgs session key or application + session key), encrypted with the client key (section 5.4.2) */ + KRB5_KU_TGS_REQ_AUTH_DAT_SESSION = 4, + /* TGS-REQ KDC-REQ-BODY AuthorizationData, encrypted with the tgs + session key (section 5.4.1) */ + KRB5_KU_TGS_REQ_AUTH_DAT_SUBKEY = 5, + /* TGS-REQ KDC-REQ-BODY AuthorizationData, encrypted with the tgs + authenticator subkey (section 5.4.1) */ + KRB5_KU_TGS_REQ_AUTH_CKSUM = 6, + /* TGS-REQ PA-TGS-REQ padata AP-REQ Authenticator cksum, keyed + with the tgs session key (sections 5.3.2, 5.4.1) */ + KRB5_KU_TGS_REQ_AUTH = 7, + /* TGS-REQ PA-TGS-REQ padata AP-REQ Authenticator (includes tgs + authenticator subkey), encrypted with the tgs session key + (section 5.3.2) */ + KRB5_KU_TGS_REP_ENC_PART_SESSION = 8, + /* TGS-REP encrypted part (includes application session key), + encrypted with the tgs session key (section 5.4.2) */ + KRB5_KU_TGS_REP_ENC_PART_SUB_KEY = 9, + /* TGS-REP encrypted part (includes application session key), + encrypted with the tgs authenticator subkey (section 5.4.2) */ + KRB5_KU_AP_REQ_AUTH_CKSUM = 10, + /* AP-REQ Authenticator cksum, keyed with the application session + key (section 5.3.2) */ + KRB5_KU_AP_REQ_AUTH = 11, + /* AP-REQ Authenticator (includes application authenticator + subkey), encrypted with the application session key (section + 5.3.2) */ + KRB5_KU_AP_REQ_ENC_PART = 12, + /* AP-REP encrypted part (includes application session subkey), + encrypted with the application session key (section 5.5.2) */ + KRB5_KU_KRB_PRIV = 13, + /* KRB-PRIV encrypted part, encrypted with a key chosen by the + application (section 5.7.1) */ + KRB5_KU_KRB_CRED = 14, + /* KRB-CRED encrypted part, encrypted with a key chosen by the + application (section 5.8.1) */ + KRB5_KU_KRB_SAFE_CKSUM = 15, + /* KRB-SAFE cksum, keyed with a key chosen by the application + (section 5.6.1) */ + KRB5_KU_OTHER_ENCRYPTED = 16, + /* Data which is defined in some specification outside of + Kerberos to be encrypted using an RFC1510 encryption type. */ + KRB5_KU_OTHER_CKSUM = 17 + /* Data which is defined in some specification outside of + Kerberos to be checksummed using an RFC1510 checksum type. */ +} krb5_key_usage; + typedef enum krb5_salttype { - KRB5_PA_PW_SALT = pa_pw_salt, - KRB5_PA_AFS3_SALT = pa_afs3_salt + KRB5_PW_SALT = pa_pw_salt, + KRB5_AFS3_SALT = pa_afs3_salt }krb5_salttype; +typedef struct krb5_salt { + krb5_salttype salttype; + krb5_data saltvalue; +} krb5_salt; + typedef ETYPE_INFO krb5_preauthinfo; typedef struct { @@ -139,14 +213,10 @@ typedef HostAddress krb5_address; typedef HostAddresses krb5_addresses; -#define KEYTYPE_USE_AFS3_SALT 0x10000 /* XXX */ -#define KEYTYPE_KEYTYPE_MASK 0xffff /* XXX */ - typedef enum krb5_keytype { KEYTYPE_NULL = 0, KEYTYPE_DES = 1, - KEYTYPE_DES3 = 7, - KEYTYPE_DES_AFS3 = KEYTYPE_DES | KEYTYPE_USE_AFS3_SALT + KEYTYPE_DES3 = 7 } krb5_keytype; typedef EncryptionKey krb5_keyblock; @@ -158,7 +228,6 @@ struct krb5_cc_ops; #define KRB5_DEFAULT_CCROOT "FILE:/tmp/krb5cc_" typedef struct krb5_ccache_data { - char *residual; struct krb5_cc_ops *ops; krb5_data data; }krb5_ccache_data; @@ -289,7 +358,6 @@ typedef struct krb5_context_data { struct krb5_log_facility *warn_dest; krb5_cc_ops *cc_ops; int num_ops; - krb5_boolean ktype_is_etype; const char *http_proxy; const char *time_fmt; krb5_boolean log_utc; @@ -351,7 +419,7 @@ struct krb5_keytab_data { krb5_error_code (*get_name)(krb5_context, krb5_keytab, char*, size_t); krb5_error_code (*close)(krb5_context, krb5_keytab); krb5_error_code (*get)(krb5_context, krb5_keytab, krb5_const_principal, - krb5_kvno, krb5_keytype, krb5_keytab_entry*); + krb5_kvno, krb5_enctype, krb5_keytab_entry*); krb5_error_code (*start_seq_get)(krb5_context, krb5_keytab, krb5_kt_cursor*); krb5_error_code (*next_entry)(krb5_context, krb5_keytab, krb5_keytab_entry*, krb5_kt_cursor*); @@ -378,9 +446,7 @@ enum { }; typedef struct krb5_auth_context_data { - int32_t flags; - krb5_cksumtype cksumtype; - krb5_enctype enctype; + unsigned int flags; krb5_address *local_address; krb5_address *remote_address; @@ -443,12 +509,13 @@ typedef int (*krb5_prompter_fct)(krb5_context context, krb5_prompt prompts[]); typedef krb5_error_code (*krb5_key_proc)(krb5_context context, - krb5_keytype type, - krb5_data *salt, + krb5_enctype type, + krb5_salt salt, krb5_const_pointer keyseed, krb5_keyblock **key); typedef krb5_error_code (*krb5_decrypt_proc)(krb5_context context, - const krb5_keyblock *key, + krb5_keyblock *key, + krb5_key_usage usage, krb5_const_pointer decrypt_arg, krb5_kdc_rep *dec_rep); diff --git a/lib/krb5/krb5_err.et b/lib/krb5/krb5_err.et index a429ca0e2..d332f1b0e 100644 --- a/lib/krb5/krb5_err.et +++ b/lib/krb5/krb5_err.et @@ -38,31 +38,33 @@ error_code SERVER_NOMATCH, "Requested server and ticket don't match" # 27-30 are reserved index 31 -prefix KRB5KRB_AP_ERR -error_code BAD_INTEGRITY, "Decrypt integrity check failed" -error_code TKT_EXPIRED, "Ticket expired" -error_code TKT_NYV, "Ticket not yet valid" -error_code REPEAT, "Request is a replay" -error_code NOT_US, "The ticket isn't for us" -error_code BADMATCH, "Ticket/authenticator don't match" -error_code SKEW, "Clock skew too great" -error_code BADADDR, "Incorrect net address" -error_code BADVERSION, "Protocol version mismatch" -error_code MSG_TYPE, "Invalid message type" -error_code MODIFIED, "Message stream modified" -error_code BADORDER, "Message out of order" -error_code ILL_CR_TKT, "Illegal cross-realm ticket" -error_code BADKEYVER, "Key version is not available" -error_code NOKEY, "Service key not available" -error_code MUT_FAIL, "Mutual authentication failed" -error_code BADDIRECTION, "Incorrect message direction" -error_code METHOD, "Alternative authentication method required" -error_code BADSEQ, "Incorrect sequence number in message" -error_code INAPP_CKSUM, "Inappropriate type of checksum in message" +prefix KRB5KRB_AP +error_code ERR_BAD_INTEGRITY, "Decrypt integrity check failed" +error_code ERR_TKT_EXPIRED, "Ticket expired" +error_code ERR_TKT_NYV, "Ticket not yet valid" +error_code ERR_REPEAT, "Request is a replay" +error_code ERR_NOT_US, "The ticket isn't for us" +error_code ERR_BADMATCH, "Ticket/authenticator don't match" +error_code ERR_SKEW, "Clock skew too great" +error_code ERR_BADADDR, "Incorrect net address" +error_code ERR_BADVERSION, "Protocol version mismatch" +error_code ERR_MSG_TYPE, "Invalid message type" +error_code ERR_MODIFIED, "Message stream modified" +error_code ERR_BADORDER, "Message out of order" +error_code ERR_ILL_CR_TKT, "Illegal cross-realm ticket" +error_code ERR_BADKEYVER, "Key version is not available" +error_code ERR_NOKEY, "Service key not available" +error_code ERR_MUT_FAIL, "Mutual authentication failed" +error_code ERR_BADDIRECTION, "Incorrect message direction" +error_code ERR_METHOD, "Alternative authentication method required" +error_code ERR_BADSEQ, "Incorrect sequence number in message" +error_code ERR_INAPP_CKSUM, "Inappropriate type of checksum in message" +error_code PATH_NOT_ACCEPTED, "Policy rejects transited path" -# 51-59 are reserved -index 60 prefix KRB5KRB_ERR +error_code RESPONSE_TOO_BIG, "Response too big for UDP, retry with TCP" +# 53-59 are reserved +index 60 error_code GENERIC, "Generic error (see e-text)" error_code FIELD_TOOLONG, "Field is too long for this implementation" diff --git a/lib/krb5/mk_priv.c b/lib/krb5/mk_priv.c index 2c8079e8b..5e3c9809e 100644 --- a/lib/krb5/mk_priv.c +++ b/lib/krb5/mk_priv.c @@ -62,7 +62,7 @@ krb5_mk_priv(krb5_context context, int32_t sec, usec; KerberosTime sec2; unsigned usec2; - krb5_enctype enctype; + krb5_crypto crypto; /* XXX - Is this right? */ @@ -73,14 +73,6 @@ krb5_mk_priv(krb5_context context, else key = auth_context->keyblock; - if (auth_context->enctype) - enctype = auth_context->enctype; - else { - ret = krb5_keytype_to_etype (context, key->keytype, &enctype); - if (ret) - return ret; - } - krb5_us_timeofday (context, &sec, &usec); part.user_data = *userdata; @@ -127,11 +119,17 @@ krb5_mk_priv(krb5_context context, s.pvno = 5; s.msg_type = krb_priv; - s.enc_part.etype = enctype; + s.enc_part.etype = key->keytype; s.enc_part.kvno = NULL; - ret = krb5_encrypt (context, buf + buf_size - len, len, - enctype, key, &s.enc_part.cipher); + krb5_crypto_init(context, key, 0, &crypto); + ret = krb5_encrypt (context, + crypto, + KRB5_KU_KRB_PRIV, + buf + buf_size - len, + len, + &s.enc_part.cipher); + krb5_crypto_destroy(context, crypto); if (ret) { free(buf); return ret; diff --git a/lib/krb5/mk_rep.c b/lib/krb5/mk_rep.c index dd0cac1a9..491e480d2 100644 --- a/lib/krb5/mk_rep.c +++ b/lib/krb5/mk_rep.c @@ -48,10 +48,10 @@ krb5_mk_rep(krb5_context context, krb5_error_code ret; AP_REP ap; EncAPRepPart body; - krb5_enctype etype; u_char *buf = NULL; size_t buf_size; size_t len; + krb5_crypto crypto; ap.pvno = 5; ap.msg_type = krb_ap_rep; @@ -72,86 +72,50 @@ krb5_mk_rep(krb5_context context, } else body.seq_number = NULL; - krb5_keytype_to_etype(context, (*auth_context)->keyblock->keytype, &etype); - ap.enc_part.etype = etype; + ap.enc_part.etype = (*auth_context)->keyblock->keytype; ap.enc_part.kvno = NULL; - buf_size = 1024; + buf_size = length_EncAPRepPart(&body); buf = malloc (buf_size); if (buf == NULL) { free_EncAPRepPart (&body); return ENOMEM; } - do { - ret = krb5_encode_EncAPRepPart (context, buf + buf_size - 1, - buf_size, - &body, &len); - if (ret) { - if (ret == ASN1_OVERFLOW) { - u_char *tmp; - - buf_size *= 2; - tmp = realloc (buf, buf_size); - if (tmp == NULL) { - free(buf); - free_EncAPRepPart (&body); - return ENOMEM; - } - buf = tmp; - } else { - free_EncAPRepPart (&body); - free(buf); - return ret; - } - } - } while(ret == ASN1_OVERFLOW); + ret = krb5_encode_EncAPRepPart (context, + buf + buf_size - 1, + buf_size, + &body, + &len); + free_EncAPRepPart (&body); + krb5_crypto_init(context, (*auth_context)->keyblock, + 0 /* ap.enc_part.etype */, &crypto); ret = krb5_encrypt (context, - buf + buf_size - len, len, - ap.enc_part.etype, - (*auth_context)->keyblock, + crypto, + KRB5_KU_AP_REQ_ENC_PART, + buf + buf_size - len, + len, &ap.enc_part.cipher); + krb5_crypto_destroy(context, crypto); if (ret) { free(buf); - free_EncAPRepPart (&body); return ret; } - do { - ret = encode_AP_REP (buf + buf_size - 1, buf_size, &ap, &len); - if (ret) { - if (ret == ASN1_OVERFLOW) { - u_char *tmp; - - buf_size *= 2; - tmp = realloc (buf, buf_size); - if (tmp == NULL) { - free_AP_REP (&ap); - free_EncAPRepPart (&body); - free (buf); - return ENOMEM; - } - buf = tmp; - } else { - free_AP_REP (&ap); - free_EncAPRepPart (&body); - free(buf); - return ret; - } - } - } while (ret == ASN1_OVERFLOW); - - free_AP_REP (&ap); - free_EncAPRepPart (&body); - - outbuf->length = len; - outbuf->data = malloc(len); - if (outbuf->data == NULL) { - free (buf); + buf_size = length_AP_REP(&ap); + buf = realloc(buf, buf_size); + if(buf == NULL) { + free_AP_REP (&ap); return ENOMEM; } - memcpy(outbuf->data, buf + buf_size - len, len); - free (buf); + ret = encode_AP_REP (buf + buf_size - 1, buf_size, &ap, &len); + + free_AP_REP (&ap); + + if(len != buf_size) + abort(); + outbuf->data = buf; + outbuf->length = len; return 0; } diff --git a/lib/krb5/mk_req.c b/lib/krb5/mk_req.c index acbfaf49a..61a41a4da 100644 --- a/lib/krb5/mk_req.c +++ b/lib/krb5/mk_req.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997 Kungliga Tekniska Högskolan + * Copyright (c) 1997, 1998 Kungliga Tekniska Högskolan * (Royal Institute of Technology, Stockholm, Sweden). * All rights reserved. * @@ -82,9 +82,8 @@ krb5_mk_req(krb5_context context, if (r) return r; this_cred.times.endtime = 0; - if (auth_context && *auth_context && (*auth_context)->enctype) - krb5_etype_to_keytype(context, (*auth_context)->enctype, - &this_cred.session.keytype); + if (auth_context && *auth_context && (*auth_context)->keyblock) + this_cred.session.keytype = (*auth_context)->keyblock->keytype; r = krb5_get_credentials (context, 0, ccache, &this_cred, &cred); if (r) diff --git a/lib/krb5/mk_req_ext.c b/lib/krb5/mk_req_ext.c index 6328afe60..d72cb273e 100644 --- a/lib/krb5/mk_req_ext.c +++ b/lib/krb5/mk_req_ext.c @@ -41,20 +41,19 @@ RCSID("$Id$"); krb5_error_code -krb5_mk_req_extended(krb5_context context, +krb5_mk_req_internal(krb5_context context, krb5_auth_context *auth_context, const krb5_flags ap_req_options, krb5_data *in_data, krb5_creds *in_creds, - krb5_data *outbuf) + krb5_data *outbuf, + krb5_key_usage usage) { krb5_error_code ret; krb5_data authenticator; Checksum c; Checksum *c_opt; - krb5_cksumtype cksumtype; krb5_auth_context ac; - krb5_enctype enctype; if(auth_context) { if(*auth_context == NULL) @@ -67,6 +66,7 @@ krb5_mk_req_extended(krb5_context context, if(ret) return ret; +#if 0 { /* This is somewhat bogus since we're possibly overwriting a value specified by the user, but it's the easiest way to make @@ -78,9 +78,9 @@ krb5_mk_req_extended(krb5_context context, in_creds->ticket.length, &ticket, NULL); - krb5_etype_to_keytype (context, - ticket.enc_part.etype, - &ticket_keytype); + krb5_enctype_to_keytype (context, + ticket.enc_part.etype, + &ticket_keytype); if (ticket_keytype == in_creds->session.keytype) krb5_auth_setenctype(context, @@ -88,32 +88,22 @@ krb5_mk_req_extended(krb5_context context, ticket.enc_part.etype); free_Ticket(&ticket); } +#endif krb5_free_keyblock(context, ac->keyblock); krb5_copy_keyblock(context, &in_creds->session, &ac->keyblock); - if (ac->enctype) - enctype = ac->enctype; - else { - ret = krb5_keytype_to_etype(context, - ac->keyblock->keytype, - &enctype); - if (ret) - return ret; - } - - if (ac->cksumtype) - cksumtype = ac->cksumtype; - else - krb5_keytype_to_cksumtype (context, ac->keyblock->keytype, &cksumtype); - if (in_data) { - ret = krb5_create_checksum (context, - cksumtype, - in_data->data, - in_data->length, - ac->keyblock, - &c); + krb5_crypto crypto; + krb5_crypto_init(context, ac->keyblock, 0, &crypto); + ret = krb5_create_checksum(context, + crypto, + usage, + in_data->data, + in_data->length, + &c); + + krb5_crypto_destroy(context, crypto); c_opt = &c; } else { c_opt = NULL; @@ -121,7 +111,7 @@ krb5_mk_req_extended(krb5_context context, ret = krb5_build_authenticator (context, ac, - enctype, + ac->keyblock->keytype, in_creds, c_opt, NULL, @@ -131,9 +121,26 @@ krb5_mk_req_extended(krb5_context context, if (ret) return ret; - ret = krb5_build_ap_req (context, enctype, in_creds, ap_req_options, - authenticator, outbuf); + ret = krb5_build_ap_req (context, ac->keyblock->keytype, + in_creds, ap_req_options, authenticator, outbuf); if(auth_context == NULL) krb5_auth_con_free(context, ac); return ret; } + +krb5_error_code +krb5_mk_req_extended(krb5_context context, + krb5_auth_context *auth_context, + const krb5_flags ap_req_options, + krb5_data *in_data, + krb5_creds *in_creds, + krb5_data *outbuf) +{ + return krb5_mk_req_internal (context, + auth_context, + ap_req_options, + in_data, + in_creds, + outbuf, + KRB5_KU_AP_REQ_AUTH_CKSUM); +} diff --git a/lib/krb5/mk_safe.c b/lib/krb5/mk_safe.c index ca87c80e4..cd98a6c0f 100644 --- a/lib/krb5/mk_safe.c +++ b/lib/krb5/mk_safe.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997 Kungliga Tekniska Högskolan + * Copyright (c) 1997, 1998 Kungliga Tekniska Högskolan * (Royal Institute of Technology, Stockholm, Sweden). * All rights reserved. * @@ -56,17 +56,7 @@ krb5_mk_safe(krb5_context context, size_t buf_size; size_t len; unsigned tmp_seq; - krb5_cksumtype cksumtype; - - if (auth_context->cksumtype) - cksumtype = auth_context->cksumtype; - else { - ret = krb5_keytype_to_cksumtype (context, - auth_context->keyblock->keytype, - &cksumtype); - if (ret) - return ret; - } + krb5_crypto crypto; s.pvno = 5; s.msg_type = krb_safe; @@ -92,68 +82,30 @@ krb5_mk_safe(krb5_context context, s.cksum.checksum.length = 0; - buf_size = 1024; - buf = malloc (buf_size); - if (buf == NULL) { + buf_size = length_KRB_SAFE(&s); + buf = malloc(buf_size + 128); /* add some for checksum */ + if(buf == NULL) return ENOMEM; - } - - do { - ret = encode_KRB_SAFE (buf + buf_size - 1, - buf_size, - &s, - &len); - if (ret) { - if (ret == ASN1_OVERFLOW) { - u_char *tmp; - - buf_size *= 2; - tmp = realloc (buf, buf_size); - if (tmp == NULL) { - free (buf); - return ENOMEM; - } - buf = tmp; - } else { - free (buf); - return ENOMEM; - } - } - } while (ret == ASN1_OVERFLOW); - - ret = krb5_create_checksum (context, - cksumtype, - buf + buf_size - len, - len, - auth_context->keyblock, - &s.cksum); + ret = encode_KRB_SAFE (buf + buf_size - 1, buf_size, &s, &len); + ret = krb5_crypto_init(context, auth_context->keyblock, 0, &crypto); + ret = krb5_create_checksum(context, + crypto, + KRB5_KU_KRB_SAFE_CKSUM, + buf + buf_size - len, + len, + &s.cksum); + krb5_crypto_destroy(context, crypto); if (ret) { free (buf); return ret; } - do { - ret = encode_KRB_SAFE (buf + buf_size - 1, buf_size, &s, &len); - if (ret) { - if (ret == ASN1_OVERFLOW) { - u_char *tmp; - - buf_size *= 2; - tmp = realloc (buf, buf_size); - if (tmp == NULL) { - free (buf); - free_Checksum (&s.cksum); - return ENOMEM; - } - buf = tmp; - } else { - free (buf); - free_Checksum (&s.cksum); - return ret; - } - } - } while (ret == ASN1_OVERFLOW); - + buf_size = length_KRB_SAFE(&s); + buf = realloc(buf, buf_size); + if(buf == NULL) + return ENOMEM; + + ret = encode_KRB_SAFE (buf + buf_size - 1, buf_size, &s, &len); free_Checksum (&s.cksum); outbuf->length = len; diff --git a/lib/krb5/n-fold.c b/lib/krb5/n-fold.c new file mode 100644 index 000000000..c6e4321d1 --- /dev/null +++ b/lib/krb5/n-fold.c @@ -0,0 +1,88 @@ +#include "krb5_locl.h" + +static void +rr13(unsigned char *buf, size_t len) +{ + unsigned char *tmp; + int bytes = (len + 7) / 8; + int i; + const int bits = 13 % len; + const int lbit = len % 8; + + tmp = malloc(bytes); + memcpy(tmp, buf, bytes); + if(lbit) { + /* pad final byte with inital bits */ + tmp[bytes - 1] &= 0xff << (8 - lbit); + for(i = lbit; i < 8; i += len) + tmp[bytes - 1] |= buf[0] >> i; + } + for(i = 0; i < bytes; i++) { + int bb; + int b1, s1, b2, s2; + /* calculate first bit position of this byte */ + bb = 8 * i - bits; + while(bb < 0) + bb += len; + /* byte offset and shift count */ + b1 = bb / 8; + s1 = bb % 8; + + if(bb + 8 > bytes * 8) + /* watch for wraparound */ + s2 = (len + 8 - s1) % 8; + else + s2 = 8 - s1; + b2 = (b1 + 1) % bytes; + buf[i] = (tmp[b1] << s1) | (tmp[b2] >> s2); + } + free(tmp); +} + +/* Add `b' to `a', both beeing one's complement numbers. */ +static void +add1(unsigned char *a, unsigned char *b, size_t len) +{ + int i; + int carry = 0; + for(i = len - 1; i >= 0; i--){ + int x = a[i] + b[i] + carry; + carry = x > 0xff; + a[i] = x & 0xff; + } + for(i = len - 1; carry && i >= 0; i--){ + int x = a[i] + carry; + carry = x > 0xff; + a[i] = carry & 0xff; + } +} + +void +n_fold(const void *str, size_t len, void *key, size_t size) +{ + /* if len < size we need at most N * len bytes, ie < 2 * size; + if len > size we need at most 2 * len */ + size_t maxlen = 2 * max(size, len); + size_t l = 0; + unsigned char *tmp = malloc(maxlen); + unsigned char *buf = malloc(len); + + memcpy(buf, str, len); + memset(key, 0, size); + do { + memcpy(tmp + l, buf, len); + l += len; + rr13(buf, len * 8); + while(l >= size) { + add1(key, tmp, size); + l -= size; + if(l == 0) + break; + memmove(tmp, tmp + size, l); + } + } while(l != 0); + memset(buf, 0, len); + free(buf); + memset(tmp, 0, maxlen); + free(tmp); +} diff --git a/lib/krb5/principal.c b/lib/krb5/principal.c index 2a673e0ae..8cc1d1cb4 100644 --- a/lib/krb5/principal.c +++ b/lib/krb5/principal.c @@ -186,6 +186,8 @@ unparse_name_fixed(krb5_context context, if(i) add_char(name, index, len, '/'); index = quote_string(princ_ncomp(principal, i), name, index, len); + if(index == len) + return ERANGE; } /* add realm if different from default realm */ if(short_form) { @@ -202,7 +204,7 @@ unparse_name_fixed(krb5_context context, add_char(name, index, len, '@'); index = quote_string(princ_realm(principal), name, index, len); if(index == len) - return ENOMEM; /* XXX */ + return ERANGE; } return 0; } diff --git a/lib/krb5/rd_cred.c b/lib/krb5/rd_cred.c index ee84eb0ac..f3aa4f2fd 100644 --- a/lib/krb5/rd_cred.c +++ b/lib/krb5/rd_cred.c @@ -51,6 +51,7 @@ krb5_rd_cred (krb5_context context, KRB_CRED cred; EncKrbCredPart enc_krb_cred_part; krb5_data enc_krb_cred_part_data; + krb5_crypto crypto; int i; ret = decode_KRB_CRED (in_data->data, in_data->length, @@ -68,12 +69,13 @@ krb5_rd_cred (krb5_context context, goto out; } - ret = krb5_decrypt (context, - cred.enc_part.cipher.data, - cred.enc_part.cipher.length, - cred.enc_part.etype, - auth_context->remote_subkey, - &enc_krb_cred_part_data); + krb5_crypto_init(context, auth_context->remote_subkey, 0, &crypto); + ret = krb5_decrypt_EncryptedData(context, + crypto, + KRB5_KU_KRB_CRED, + &cred.enc_part, + &enc_krb_cred_part_data); + krb5_crypto_destroy(context, crypto); if (ret) goto out; diff --git a/lib/krb5/rd_priv.c b/lib/krb5/rd_priv.c index 0a6610275..511190372 100644 --- a/lib/krb5/rd_priv.c +++ b/lib/krb5/rd_priv.c @@ -53,6 +53,7 @@ krb5_rd_priv(krb5_context context, size_t len; krb5_data plain; krb5_keyblock *key; + krb5_crypto crypto; memset(&priv, 0, sizeof(priv)); ret = decode_KRB_PRIV (inbuf->data, inbuf->length, &priv, &len); @@ -76,12 +77,13 @@ krb5_rd_priv(krb5_context context, else key = auth_context->keyblock; - ret = krb5_decrypt (context, - priv.enc_part.cipher.data, - priv.enc_part.cipher.length, - priv.enc_part.etype, - key, - &plain); + krb5_crypto_init(context, key, 0, &crypto); + ret = krb5_decrypt_EncryptedData(context, + crypto, + KRB5_KU_KRB_PRIV, + &priv.enc_part, + &plain); + krb5_crypto_destroy(context, crypto); if (ret) goto failure; diff --git a/lib/krb5/rd_rep.c b/lib/krb5/rd_rep.c index fc4c914a0..659832b35 100644 --- a/lib/krb5/rd_rep.c +++ b/lib/krb5/rd_rep.c @@ -50,6 +50,7 @@ krb5_rd_rep(krb5_context context, AP_REP ap_rep; size_t len; krb5_data data; + krb5_crypto crypto; krb5_data_zero (&data); ret = 0; @@ -66,10 +67,13 @@ krb5_rd_rep(krb5_context context, goto out; } + krb5_crypto_init(context, auth_context->keyblock, 0, &crypto); ret = krb5_decrypt_EncryptedData (context, + crypto, + KRB5_KU_AP_REQ_ENC_PART, &ap_rep.enc_part, - auth_context->keyblock, &data); + krb5_crypto_destroy(context, crypto); if (ret) goto out; diff --git a/lib/krb5/rd_req.c b/lib/krb5/rd_req.c index c57bd5ddf..19e1818ad 100644 --- a/lib/krb5/rd_req.c +++ b/lib/krb5/rd_req.c @@ -42,19 +42,22 @@ RCSID("$Id$"); static krb5_error_code decrypt_tkt_enc_part (krb5_context context, - const krb5_keyblock *key, + krb5_keyblock *key, EncryptedData *enc_part, EncTicketPart *decr_part) { krb5_error_code ret; krb5_data plain; size_t len; + krb5_crypto crypto; - ret = krb5_decrypt (context, - enc_part->cipher.data, - enc_part->cipher.length, - enc_part->etype, - key, &plain); + krb5_crypto_init(context, key, 0, &crypto); + ret = krb5_decrypt_EncryptedData (context, + crypto, + KRB5_KU_TICKET, + enc_part, + &plain); + krb5_crypto_destroy(context, crypto); if (ret) return ret; @@ -73,12 +76,15 @@ decrypt_authenticator (krb5_context context, krb5_error_code ret; krb5_data plain; size_t len; + krb5_crypto crypto; - ret = krb5_decrypt (context, - enc_part->cipher.data, - enc_part->cipher.length, - enc_part->etype, - key, &plain); + krb5_crypto_init(context, key, 0, &crypto); + ret = krb5_decrypt_EncryptedData (context, + crypto, + KRB5_KU_AP_REQ_AUTH, + enc_part, + &plain); + krb5_crypto_destroy(context, crypto); if (ret) return ret; @@ -145,6 +151,45 @@ krb5_decrypt_ticket(krb5_context context, return 0; } +krb5_error_code +krb5_verify_authenticator_checksum(krb5_context context, + krb5_auth_context ac, + void *data, + size_t len) +{ + krb5_error_code ret; + krb5_keyblock *key; + krb5_authenticator authenticator; + krb5_crypto crypto; + + ret = krb5_auth_getauthenticator (context, + ac, + &authenticator); + if(ret) + return ret; + if(authenticator->cksum == NULL) + return -17; + ret = krb5_auth_con_getkey(context, ac, &key); + if(ret) { + krb5_free_authenticator(context, &authenticator); + return ret; + } + ret = krb5_crypto_init(context, key, 0, &crypto); + if(ret) + goto out; + ret = krb5_verify_checksum (context, + crypto, + KRB5_KU_AP_REQ_AUTH_CKSUM, + data, + len, + authenticator->cksum); + krb5_crypto_destroy(context, crypto); +out: + krb5_free_authenticator(context, &authenticator); + krb5_free_keyblock(context, key); + return ret; +} + krb5_error_code krb5_verify_ap_req(krb5_context context, krb5_auth_context *auth_context, @@ -303,7 +348,6 @@ get_key_from_keytab(krb5_context context, krb5_keytab_entry entry; krb5_error_code ret; int kvno; - krb5_keytype keytype; krb5_keytab real_keytab; if(keytab == NULL) @@ -316,17 +360,11 @@ get_key_from_keytab(krb5_context context, else kvno = 0; - ret = krb5_etype_to_keytype (context, - ap_req->ticket.enc_part.etype, - &keytype); - if (ret) - goto out; - ret = krb5_kt_get_entry (context, real_keytab, server, kvno, - keytype, + ap_req->ticket.enc_part.etype, &entry); if(ret) goto out; diff --git a/lib/krb5/rd_safe.c b/lib/krb5/rd_safe.c index a35156d26..bb37d17cd 100644 --- a/lib/krb5/rd_safe.c +++ b/lib/krb5/rd_safe.c @@ -50,48 +50,36 @@ verify_checksum(krb5_context context, size_t buf_size; size_t len; Checksum c; + krb5_crypto crypto; c = safe->cksum; safe->cksum.cksumtype = 0; safe->cksum.checksum.data = NULL; safe->cksum.checksum.length = 0; - buf_size = 1024; - buf = malloc (buf_size); + + buf_size = length_KRB_SAFE(safe); + buf = malloc(buf_size); + if (buf == NULL) { - free_Checksum(&c); - return ENOMEM; + ret = ENOMEM; + goto out; } - do { - ret = encode_KRB_SAFE (buf + buf_size - 1, - buf_size, - safe, - &len); - if (ret) { - if (ret == ASN1_OVERFLOW) { - u_char *tmp; - - buf_size *= 2; - tmp = realloc (buf, buf_size); - if (tmp == NULL) { - ret = ENOMEM; - goto out; - } - buf = tmp; - } else { - goto out; - } - } - } while(ret == ASN1_OVERFLOW); - + ret = encode_KRB_SAFE (buf + buf_size - 1, + buf_size, + safe, + &len); + krb5_crypto_init(context, auth_context->keyblock, 0, &crypto); ret = krb5_verify_checksum (context, + crypto, + KRB5_KU_KRB_SAFE_CKSUM, buf + buf_size - len, len, - auth_context->keyblock, &c); + krb5_crypto_destroy(context, crypto); out: - free_Checksum (&c); + safe->cksum = c; free (buf); return ret; } @@ -118,8 +106,8 @@ krb5_rd_safe(krb5_context context, ret = KRB5KRB_AP_ERR_MSG_TYPE; goto failure; } - if (!krb5_checksum_is_keyed(safe.cksum.cksumtype) - || !krb5_checksum_is_collision_proof(safe.cksum.cksumtype)) { + if (!krb5_checksum_is_keyed(context, safe.cksum.cksumtype) + || !krb5_checksum_is_collision_proof(context, safe.cksum.cksumtype)) { ret = KRB5KRB_AP_ERR_INAPP_CKSUM; goto failure; } diff --git a/lib/krb5/str2key.c b/lib/krb5/str2key.c deleted file mode 100644 index c35ade510..000000000 --- a/lib/krb5/str2key.c +++ /dev/null @@ -1,462 +0,0 @@ -/* - * Copyright (c) 1997, 1998 Kungliga Tekniska Högskolan - * (Royal Institute of Technology, Stockholm, Sweden). - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by Kungliga Tekniska - * Högskolan and its contributors. - * - * 4. Neither the name of the Institute nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include - -RCSID("$Id$"); - -/* - * Reverse 8 bytes - */ - -static void -reverse (unsigned char *s) -{ - static const unsigned char tbl[] = { - 0x0, - 0x8, - 0x4, - 0xC, - 0x2, - 0xA, - 0x6, - 0xE, - 0x1, - 0x9, - 0x5, - 0xD, - 0x3, - 0xB, - 0x7, - 0xF - }; - - char tmp; - -#define REVONE(str, i, j) \ -do { tmp = str[i]; str[i] = str[j]; str[j] = tmp;} while(0) - - REVONE(s,0,7); - REVONE(s,1,6); - REVONE(s,2,5); - REVONE(s,3,4); -#undef REVONE - -#define REVTWO(q) \ -q = (tbl[q & 0x0F] << 4) | (tbl[q >> 4]) - - REVTWO(s[0]); - REVTWO(s[1]); - REVTWO(s[2]); - REVTWO(s[3]); - REVTWO(s[4]); - REVTWO(s[5]); - REVTWO(s[6]); - REVTWO(s[7]); - -#undef REVTWO -} - -/* - * A = A xor B. A & B is 8 bytes. - */ - -static void -xor (des_cblock *key, const unsigned char *b) -{ - unsigned char *a = (unsigned char*)key; - a[0] ^= b[0]; - a[1] ^= b[1]; - a[2] ^= b[2]; - a[3] ^= b[3]; - a[4] ^= b[4]; - a[5] ^= b[5]; - a[6] ^= b[6]; - a[7] ^= b[7]; -} - -/* - * Init a from b - */ - -static void -init (unsigned char *a, const unsigned char *b) -{ - a[0] = b[0] << 1; - a[1] = b[1] << 1; - a[2] = b[2] << 1; - a[3] = b[3] << 1; - a[4] = b[4] << 1; - a[5] = b[5] << 1; - a[6] = b[6] << 1; - a[7] = b[7] << 1; -} - -static void -DES_string_to_key(const char *str, size_t len, des_cblock *key) -{ - /* could use des_string_to_key here, but then `str' must be zero - terminated, and the final weak-key check has to be added */ - int even, i; - des_key_schedule sched; - - memset (key, 0, sizeof(des_cblock)); - - even = 0; - for (i = 0; i < len; i += 8) { - unsigned char tmp[8]; - - init (tmp, (const unsigned char*)(str + i)); - - if (even) { - reverse (tmp); - init (tmp, tmp); - } - even = !even; - xor (key, tmp); - } - des_set_odd_parity (key); - des_set_key (key, sched); - des_cbc_cksum ((des_cblock *)str, key, len, sched, key); - des_set_odd_parity (key); - if (des_is_weak_key (key)) - xor (key, (unsigned char*)"\0\0\0\0\0\0\0\xf0"); -} - -static void -rr13(unsigned char *buf, size_t len) -{ - int i; - /* assert(len >= 3); */ - unsigned a = buf[0], b = buf[len-1]; -#define F(A, B) ((((A) << 3) | ((B) >> 5)) & 0xff) - buf[0] = F(buf[len-2], buf[len-1]); - for(i = len - 3; i >= 1; i--) - buf[i + 2] = F(buf[i], buf[i+1]); - buf[2] = F(a, buf[1]); - buf[1] = F(b, a); -#undef F -} - -/* Add `b' to `a', both beeing one's complement numbers. */ -static void -add1(unsigned char *a, unsigned char *b, size_t len) -{ - int i; - int carry = 0; - for(i = len - 1; i >= 0; i--){ - int x = a[i] + b[i] + carry; - carry = x > 0xff; - a[i] = x & 0xff; - } - for(i = len - 1; carry && i >= 0; i--){ - int x = a[i] + carry; - carry = x > 0xff; - a[i] = carry & 0xff; - } -} - -/* key should point to a buffer of at least size (24) bytes */ -static void -fold(const unsigned char *str, size_t len, unsigned char *key) -{ - const int size = 24; - /* if len < size we need at most N * len bytes, ie < 2 * size; - if len > size we need at most 2 * len */ - size_t maxlen = 2 * max(size, len); - size_t l = 0; - unsigned char *tmp = malloc(maxlen); - unsigned char *buf = malloc(len); - - memcpy(buf, str, len); - memset(key, 0, size); - do { - memcpy(tmp + l, buf, len); - l += len; - rr13(buf, len); - while(l >= size) { - add1(key, tmp, size); - l -= size; - if(l == 0) - break; - memmove(tmp, tmp + size, l); - } - } while(l != 0); - memset(buf, 0, len); - free(buf); - memset(tmp, 0, maxlen); - free(tmp); -} - -static void -DES3_string_to_key(const unsigned char *str, size_t len, des_cblock *keys) -{ - unsigned char tmp[24]; - des_cblock ivec; - des_key_schedule s[3]; - int i; - - fold(str, len, tmp); - for(i = 0; i < 3; i++){ - memcpy(keys + i, tmp + 8 * i, 8); - des_set_odd_parity(keys + i); - if(des_is_weak_key(keys + i)) - xor(keys + i, (unsigned char*)"\0\0\0\0\0\0\0\xf0"); - des_set_key(keys + i, s[i]); - } - memset(&ivec, 0, sizeof(ivec)); - des_ede3_cbc_encrypt((void*)tmp, (void*)tmp, sizeof(tmp), - s[0], s[1], s[2], &ivec, 1); - memset(s, 0, sizeof(s)); - for(i = 0; i < 3; i++){ - memcpy(keys + i, tmp + 8 * i, 8); - des_set_odd_parity(keys + i); - if(des_is_weak_key(keys + i)) - xor(keys + i, (unsigned char*)"\0\0\0\0\0\0\0\xf0"); - } - memset(tmp, 0, sizeof(tmp)); -} - -/* This defines the Andrew string_to_key function. It accepts a password - * string as input and converts its via a one-way encryption algorithm to a DES - * encryption key. It is compatible with the original Andrew authentication - * service password database. - */ - -/* - * Short passwords, i.e 8 characters or less. - */ -static void -afs_cmu_StringToKey (const char *pw, size_t pw_len, - const char *cell, size_t cell_len, - des_cblock *key) -{ - char password[8+1]; /* crypt is limited to 8 chars anyway */ - int i; - - memset (password, 0, sizeof(password)); - - if(cell_len > 8) cell_len = 8; - strncpy (password, cell, cell_len); - - if(pw_len > 8) pw_len = 8; - for (i=0; i < pw_len; i++) - password[i] ^= pw[i]; - - for (i=0; i<8; i++) - if (password[i] == '\0') password[i] = 'X'; - - /* crypt only considers the first 8 characters of password but for some - reason returns eleven characters of result (plus the two salt chars). */ - strncpy((char *)key, (char *)crypt(password, "#~") + 2, sizeof(des_cblock)); - - /* parity is inserted into the LSB so leftshift each byte up one bit. This - allows ascii characters with a zero MSB to retain as much significance - as possible. */ - { char *keybytes = (char *)key; - unsigned int temp; - - for (i = 0; i < 8; i++) { - temp = (unsigned int) keybytes[i]; - keybytes[i] = (unsigned char) (temp << 1); - } - } - des_fixup_key_parity (key); -} - -/* - * Long passwords, i.e 9 characters or more. - */ -static void -afs_transarc_StringToKey (const char *pw, size_t pw_len, - const char *cell, size_t cell_len, - des_cblock *key) -{ - des_key_schedule schedule; - des_cblock temp_key; - des_cblock ivec; - char password[512]; - size_t passlen; - - memcpy(password, pw, min(pw_len, sizeof(password))); - if(pw_len < sizeof(password)) - memcpy(password + pw_len, cell, min(cell_len, - sizeof(password) - pw_len)); - passlen = min(sizeof(password), pw_len + cell_len); - memcpy(&ivec, "kerberos", 8); - memcpy(&temp_key, "kerberos", 8); - des_fixup_key_parity (&temp_key); - des_key_sched (&temp_key, schedule); - des_cbc_cksum ((des_cblock *)password, &ivec, passlen, schedule, &ivec); - - memcpy(&temp_key, &ivec, 8); - des_fixup_key_parity (&temp_key); - des_key_sched (&temp_key, schedule); - des_cbc_cksum ((des_cblock *)password, key, passlen, schedule, &ivec); - memset(&schedule, 0, sizeof(schedule)); - memset(&temp_key, 0, sizeof(temp_key)); - memset(&ivec, 0, sizeof(ivec)); - memset(password, 0, sizeof(password)); - - des_fixup_key_parity (key); -} - -static void -AFS3_string_to_key(const char *pw, size_t pw_len, - const char *cell, size_t cell_len, - des_cblock *key) -{ - if(pw_len > 8) - afs_transarc_StringToKey (pw, pw_len, cell, cell_len, key); - else - afs_cmu_StringToKey (pw, pw_len, cell, cell_len, key); -} - -static void * -get_str(const void *pw, size_t pw_len, const void *salt, size_t salt_len, - size_t *ret_len) -{ - char *p; - size_t len = pw_len + salt_len; - len = (len + 7) & ~7; - p = calloc(len, 1); - if(p == NULL) - return NULL; - memcpy(p, pw, pw_len); - memcpy(p + pw_len, salt, salt_len); - *ret_len = len; - return p; -} - -static krb5_error_code -string_to_key_internal (const unsigned char *str, - size_t str_len, - krb5_data *salt, - krb5_keytype ktype, - krb5_keyblock *key) -{ - size_t len; - unsigned char *s = NULL; - krb5_error_code ret; - - switch(ktype & KEYTYPE_KEYTYPE_MASK){ - case KEYTYPE_DES:{ - des_cblock tmpkey; - if(ktype & KEYTYPE_USE_AFS3_SALT) - AFS3_string_to_key(str, str_len, salt->data, salt->length, &tmpkey); - else{ - s = get_str(str, str_len, salt->data, salt->length, &len); - if(s == NULL) - return ENOMEM; - DES_string_to_key(s, len, &tmpkey); - } - ret = krb5_data_copy(&key->keyvalue, tmpkey, sizeof(des_cblock)); - memset(&tmpkey, 0, sizeof(tmpkey)); - break; - } - case KEYTYPE_DES3:{ - des_cblock keys[3]; - s = get_str(str, str_len, salt->data, salt->length, &len); - if(s == NULL) - return ENOMEM; - /* only des should pad to 8 */ - DES3_string_to_key(s, str_len + salt->length, keys); - ret = krb5_data_copy(&key->keyvalue, keys, sizeof(keys)); - memset(keys, 0, sizeof(keys)); - break; - } - default: - ret = KRB5_PROG_KEYTYPE_NOSUPP; - break; - } - if(s){ - memset(s, 0, len); - free(s); - } - if(ret) - return ret; - key->keytype = ktype & KEYTYPE_KEYTYPE_MASK; - return 0; -} - -krb5_error_code -krb5_string_to_key (const char *str, - krb5_data *salt, - krb5_keytype ktype, - krb5_keyblock *key) -{ - return string_to_key_internal ((const unsigned char *)str, - strlen(str), salt, ktype, key); -} - -krb5_error_code -krb5_string_to_key_data (krb5_data *str, - krb5_data *salt, - krb5_keytype ktype, - krb5_keyblock *key) -{ - return string_to_key_internal (str->data, str->length, salt, ktype, key); -} - -krb5_error_code -krb5_get_salt (krb5_principal princ, - krb5_data *salt) -{ - size_t len; - int i; - krb5_error_code err; - char *p; - - len = strlen(princ->realm); - for (i = 0; i < princ->name.name_string.len; ++i) - len += strlen(princ->name.name_string.val[i]); - err = krb5_data_alloc (salt, len); - if (err) - return err; - p = salt->data; - strncpy (p, princ->realm, strlen(princ->realm)); - p += strlen(princ->realm); - for (i = 0; i < princ->name.name_string.len; ++i) { - strncpy (p, - princ->name.name_string.val[i], - strlen(princ->name.name_string.val[i])); - p += strlen(princ->name.name_string.val[i]); - } - return 0; -} - diff --git a/lib/krb5/transited.c b/lib/krb5/transited.c index 9e55c6eb0..1b9df487c 100644 --- a/lib/krb5/transited.c +++ b/lib/krb5/transited.c @@ -114,7 +114,7 @@ make_path(struct tr_realm *r, const char *from, const char *to) return ENOMEM; } strncpy(path->realm, from, p - from); - path->realm[p - from] = 0; + path->realm[p - from] = '\0'; p--; } }else @@ -136,8 +136,8 @@ make_paths(struct tr_realm *realms, const char *client_realm, /* it *might* be that you can have more than one empty component in a row, at least that's how I interpret the "," exception in 1510 */ - if(r->realm[0] == 0){ - while(r->next && r->next->realm[0] == 0) + if(r->realm[0] == '\0'){ + while(r->next && r->next->realm[0] == '\0') r = r->next; if(r->next) next_realm = r->next->realm; @@ -218,11 +218,11 @@ make_realm(char *realm) quote = 1; continue; } - if(p[0] == '.' && p[1] == 0) + if(p[0] == '.' && p[1] == '\0') r->trailing_dot = 1; *q++ = *p; } - *q = 0; + *q = '\0'; return r; } @@ -262,7 +262,7 @@ decode_realms(const char *tr, int length, struct tr_realm **realms) if(tr[i] == ','){ tmp = malloc(tr + i - start + 1); strncpy(tmp, start, tr + i - start); - tmp[tr + i - start] = 0; + tmp[tr + i - start] = '\0'; r = make_realm(tmp); if(r == NULL){ free_realms(*realms); @@ -274,7 +274,7 @@ decode_realms(const char *tr, int length, struct tr_realm **realms) } tmp = malloc(tr + i - start + 1); strncpy(tmp, start, tr + i - start); - tmp[tr + i - start] = 0; + tmp[tr + i - start] = '\0'; r = make_realm(tmp); if(r == NULL){ free_realms(*realms); @@ -311,7 +311,7 @@ krb5_domain_x500_decode(krb5_data tr, char ***realms, int *num_realms, /* remove empty components */ q = &r; for(p = r; p; ){ - if(p->realm[0] == 0){ + if(p->realm[0] == '\0'){ free(p->realm); *q = p->next; free(p); @@ -354,7 +354,7 @@ krb5_domain_x500_encode(char **realms, int num_realms, krb5_data *encoding) } len += num_realms - 1; s = malloc(len + 1); - *s = 0; + *s = '\0'; for(i = 0; i < num_realms; i++){ if(i && i < num_realms - 1) strcat(s, ","); diff --git a/lib/roken/ChangeLog b/lib/roken/ChangeLog index 757a79c73..c413ffb78 100644 --- a/lib/roken/ChangeLog +++ b/lib/roken/ChangeLog @@ -31,6 +31,10 @@ Tue Sep 8 05:18:31 1998 Assar Westerlund * recvmsg.c (recvmsg): patch from bpreece@unity.ncsu.edu +Fri Sep 4 16:29:27 1998 Johan Danielsson + + * vsyslog.c: asprintf -> vasprintf + Tue Aug 18 22:25:52 1998 Assar Westerlund * getarg.h (arg_printusage): new signature @@ -47,6 +51,10 @@ Fri Jul 24 21:56:02 1998 Assar Westerlund * simple_exec.c (simple_execvp): loop around waitpid when errno == EINTR +Thu Jul 23 20:24:35 1998 Johan Danielsson + + * Makefile.am: net_{read,write}.c + Wed Jul 22 21:38:35 1998 Assar Westerlund * simple_exec.c (simple_execlp): initialize `argv' diff --git a/lib/roken/Makefile.am b/lib/roken/Makefile.am index 937610f9c..bdacfc14f 100644 --- a/lib/roken/Makefile.am +++ b/lib/roken/Makefile.am @@ -21,9 +21,9 @@ libroken_la_SOURCES = \ issuid.c \ k_getpwnam.c \ k_getpwuid.c \ + mini_inetd.c \ net_read.c \ net_write.c \ - mini_inetd.c \ parse_time.c \ parse_units.c \ print_version.c \ diff --git a/lib/roken/vsyslog.c b/lib/roken/vsyslog.c index e8882ccb5..0256189cb 100644 --- a/lib/roken/vsyslog.c +++ b/lib/roken/vsyslog.c @@ -54,7 +54,7 @@ vsyslog(int pri, const char *fmt, va_list ap) { char *p; - asprintf (&p, fmt, ap); + vasprintf (&p, fmt, ap); syslog (pri, "%s", p); free (p); }