diff --git a/cf/crypto.m4 b/cf/crypto.m4 index 5a6cb01f2..da989053b 100644 --- a/cf/crypto.m4 +++ b/cf/crypto.m4 @@ -171,4 +171,51 @@ fi AC_SUBST(INCLUDE_openssl_crypto) AC_SUBST(LIB_openssl_crypto) + +dnl +dnl Legacy/weak encryption type options +dnl + +dnl Single DES (weak crypto) - disabled by default for security +AC_ARG_WITH([1des], + AS_HELP_STRING([--with-1des], [enable single DES encryption (weak, for legacy compatibility)]), + [with_1des=$withval], + [with_1des=no]) +AC_MSG_CHECKING([whether to enable single DES encryption]) +if test "$with_1des" = "yes"; then + AC_DEFINE([HEIM_WEAK_CRYPTO], 1, [Define to enable single DES encryption support]) + AC_MSG_RESULT([yes]) +else + AC_MSG_RESULT([no]) +fi +AM_CONDITIONAL([HEIM_WEAK_CRYPTO], [test "$with_1des" = "yes"]) + +dnl Triple DES - enabled by default for legacy compatibility +AC_ARG_WITH([3des], + AS_HELP_STRING([--with-3des], [enable triple DES encryption (default: yes)]), + [with_3des=$withval], + [with_3des=yes]) +AC_MSG_CHECKING([whether to enable triple DES encryption]) +if test "$with_3des" = "yes"; then + AC_DEFINE([HEIM_DES3], 1, [Define to enable triple DES encryption support]) + AC_MSG_RESULT([yes]) +else + AC_MSG_RESULT([no]) +fi +AM_CONDITIONAL([HEIM_DES3], [test "$with_3des" = "yes"]) + +dnl ARCFOUR/RC4 - enabled by default (still used by some Windows systems) +AC_ARG_WITH([arcfour], + AS_HELP_STRING([--with-arcfour], [enable ARCFOUR/RC4 encryption (default: yes)]), + [with_arcfour=$withval], + [with_arcfour=yes]) +AC_MSG_CHECKING([whether to enable ARCFOUR encryption]) +if test "$with_arcfour" = "yes"; then + AC_DEFINE([HEIM_ARCFOUR], 1, [Define to enable ARCFOUR/RC4 encryption support]) + AC_MSG_RESULT([yes]) +else + AC_MSG_RESULT([no]) +fi +AM_CONDITIONAL([HEIM_ARCFOUR], [test "$with_arcfour" = "yes"]) + ]) diff --git a/configure.ac b/configure.ac index f807fdda2..77315be2f 100644 --- a/configure.ac +++ b/configure.ac @@ -130,7 +130,7 @@ AC_SUBST([SLC_DEP]) dnl --- -AC_DEFINE(HEIM_WEAK_CRYPTO, 1, [Define if you want support for weak crypto]) +dnl HEIM_WEAK_CRYPTO is now controlled by --with-1des in cf/crypto.m4 rk_TEST_PACKAGE(openldap, [#include diff --git a/include/NTMakefile b/include/NTMakefile index 060aadf60..8be0e0c55 100644 --- a/include/NTMakefile +++ b/include/NTMakefile @@ -62,6 +62,9 @@ while(<>) { if ("$(KRB5)") { print "#define KRB5 1\n"; } if ("$(KRB4)") { print "#define KRB4 1\n"; } if ("$(WEAK_CRYPTO)") { print "#define HEIM_WEAK_CRYPTO 1\n"; } + # Always enable 3DES and ARCFOUR for Windows builds (needed for interop) + print "#define HEIM_DES3 1\n"; + print "#define HEIM_ARCFOUR 1\n"; if ("$(PKINIT)") { print "#define PKINIT 1\n"; } if ("$(NO_AFS)") { print "#define NO_AFS 1\n"; } if ("$(OPENLDAP)") { print "#define OPENLDAP 1\n"; } diff --git a/lib/hdb/data-mkey.mit.des3.be b/lib/hdb/data-mkey.mit.des3.be new file mode 100644 index 000000000..4278ed339 Binary files /dev/null and b/lib/hdb/data-mkey.mit.des3.be differ diff --git a/lib/hdb/data-mkey.mit.des3.le b/lib/hdb/data-mkey.mit.des3.le new file mode 100644 index 000000000..19fdc93b4 Binary files /dev/null and b/lib/hdb/data-mkey.mit.des3.le differ diff --git a/lib/krb5/Makefile.am b/lib/krb5/Makefile.am index ecb075bd5..17a911847 100644 --- a/lib/krb5/Makefile.am +++ b/lib/krb5/Makefile.am @@ -144,6 +144,7 @@ dist_libkrb5_la_SOURCES = \ creds.c \ crypto-des-common.c \ crypto-des.c \ + crypto-des3.c \ crypto.c \ crypto.h \ crypto-aes-sha1.c \ @@ -230,6 +231,8 @@ dist_libkrb5_la_SOURCES = \ salt-aes-sha1.c \ salt-aes-sha2.c \ salt-arcfour.c \ + salt-des.c \ + salt-des3.c \ sp800-108-kdf.c \ scache.c \ send_to_kdc.c \ @@ -291,6 +294,7 @@ librfc3961_la_SOURCES = \ crc.c \ crypto-des-common.c \ crypto-des.c \ + crypto-des3.c \ crypto.c \ crypto.h \ crypto-aes-sha1.c \ @@ -311,6 +315,8 @@ librfc3961_la_SOURCES = \ salt-aes-sha1.c \ salt-aes-sha2.c \ salt-arcfour.c \ + salt-des.c \ + salt-des3.c \ sp800-108-kdf.c \ store-int.c \ warn.c diff --git a/lib/krb5/NTMakefile b/lib/krb5/NTMakefile index 081aedd43..866774b9c 100644 --- a/lib/krb5/NTMakefile +++ b/lib/krb5/NTMakefile @@ -64,6 +64,7 @@ libkrb5_OBJS = \ $(OBJ)\crypto-arcfour.obj \ $(OBJ)\crypto-des-common.obj \ $(OBJ)\crypto-des.obj \ + $(OBJ)\crypto-des3.obj \ $(OBJ)\crypto-evp.obj \ $(OBJ)\crypto-null.obj \ $(OBJ)\crypto-pk.obj \ @@ -139,6 +140,8 @@ libkrb5_OBJS = \ $(OBJ)\salt-aes-sha1.obj \ $(OBJ)\salt-aes-sha2.obj \ $(OBJ)\salt-arcfour.obj \ + $(OBJ)\salt-des.obj \ + $(OBJ)\salt-des3.obj \ $(OBJ)\salt.obj \ $(OBJ)\scache.obj \ $(OBJ)\send_to_kdc.obj \ @@ -221,6 +224,7 @@ dist_libkrb5_la_SOURCES = \ crypto-algs.c \ crypto-arcfour.c \ crypto-des.c \ + crypto-des3.c \ crypto-des-common.c \ crypto-evp.c \ crypto-pk.c \ @@ -298,6 +302,8 @@ dist_libkrb5_la_SOURCES = \ salt-aes-sha1.c \ salt-aes-sha2.c \ salt-arcfour.c \ + salt-des.c \ + salt-des3.c \ scache.c \ send_to_kdc.c \ sendauth.c \ @@ -389,6 +395,7 @@ librfc3961_OBJS=\ $(OBJ)\crypto-algs.obj \ $(OBJ)\crypto-arcfour.obj \ $(OBJ)\crypto-des.obj \ + $(OBJ)\crypto-des3.obj \ $(OBJ)\crypto-des-common.obj \ $(OBJ)\crypto-evp.obj \ $(OBJ)\crypto-null.obj \ @@ -403,6 +410,8 @@ librfc3961_OBJS=\ $(OBJ)\salt-aes-sha1.obj \ $(OBJ)\salt-aes-sha2.obj \ $(OBJ)\salt-arcfour.obj \ + $(OBJ)\salt-des.obj \ + $(OBJ)\salt-des3.obj \ $(OBJ)\sp800-108-kdf.obj \ $(OBJ)\store-int.obj \ $(OBJ)\warn.obj diff --git a/lib/krb5/context.c b/lib/krb5/context.c index 2868c07e2..57aba54df 100644 --- a/lib/krb5/context.c +++ b/lib/krb5/context.c @@ -177,7 +177,10 @@ make_openssl_context(krb5_context context, ossl->aes128_cts = EVP_CIPHER_fetch(ossl->libctx, "AES-128-CBC-CTS", ossl->propq); ossl->aes192_cts = EVP_CIPHER_fetch(ossl->libctx, "AES-192-CBC-CTS", ossl->propq); ossl->aes256_cts = EVP_CIPHER_fetch(ossl->libctx, "AES-256-CBC-CTS", ossl->propq); + ossl->des_cbc = EVP_CIPHER_fetch(ossl->libctx, "DES-CBC", ossl->propq); + ossl->des_ede3_cbc = EVP_CIPHER_fetch(ossl->libctx, "DES-EDE3-CBC", ossl->propq); ossl->hmac = EVP_MAC_fetch(ossl->libctx, "HMAC", ossl->propq); + ossl->md4 = EVP_MD_fetch(ossl->libctx, "MD4", ossl->propq); ossl->md5 = EVP_MD_fetch(ossl->libctx, "MD5", ossl->propq); ossl->sha1 = EVP_MD_fetch(ossl->libctx, "SHA1", ossl->propq); ossl->sha256 = EVP_MD_fetch(ossl->libctx, "SHA256", ossl->propq); @@ -204,7 +207,10 @@ free_openssl(krb5_context_ossl *osslp) EVP_CIPHER_free(p->aes128_cts); EVP_CIPHER_free(p->aes192_cts); EVP_CIPHER_free(p->aes256_cts); + EVP_CIPHER_free(p->des_cbc); + EVP_CIPHER_free(p->des_ede3_cbc); EVP_MAC_free(p->hmac); + EVP_MD_free(p->md4); EVP_MD_free(p->md5); EVP_MD_free(p->sha1); EVP_MD_free(p->sha256); diff --git a/lib/krb5/crypto-algs.c b/lib/krb5/crypto-algs.c index 8e2482d51..3e13dc460 100644 --- a/lib/krb5/crypto-algs.c +++ b/lib/krb5/crypto-algs.c @@ -33,14 +33,19 @@ #include "krb5_locl.h" -#ifndef HEIMDAL_SMALLER -#define DES3_OLD_ENCTYPE 1 -#endif - struct _krb5_checksum_type *_krb5_checksum_types[] = { &_krb5_checksum_none, #ifdef HEIM_WEAK_CRYPTO &_krb5_checksum_crc32, + &_krb5_checksum_rsa_md4, + &_krb5_checksum_rsa_md4_des, + &_krb5_checksum_rsa_md5_des, +#endif +#ifdef HEIM_DES3 + &_krb5_checksum_rsa_md5_des3, +#endif +#if defined(HEIM_DES3) || defined(HEIM_WEAK_CRYPTO) + &_krb5_checksum_hmac_sha1_des3, #endif &_krb5_checksum_rsa_md5, &_krb5_checksum_sha1, @@ -48,7 +53,9 @@ struct _krb5_checksum_type *_krb5_checksum_types[] = { &_krb5_checksum_hmac_sha1_aes256, &_krb5_checksum_hmac_sha256_128_aes128, &_krb5_checksum_hmac_sha384_192_aes256, +#ifdef HEIM_ARCFOUR &_krb5_checksum_hmac_md5, +#endif &_krb5_checksum_sha256, &_krb5_checksum_sha384, &_krb5_checksum_sha512 @@ -66,7 +73,25 @@ struct _krb5_encryption_type *_krb5_etypes[] = { &_krb5_enctype_aes128_cts_hmac_sha256_128, &_krb5_enctype_aes256_cts_hmac_sha1, &_krb5_enctype_aes128_cts_hmac_sha1, +#ifdef HEIM_ARCFOUR &_krb5_enctype_arcfour_hmac_md5, +#endif +#if defined(HEIM_DES3) || defined(HEIM_WEAK_CRYPTO) + &_krb5_enctype_des3_cbc_sha1, + &_krb5_enctype_des3_cbc_none, +#endif +#ifdef HEIM_DES3 + &_krb5_enctype_des3_cbc_md5, + &_krb5_enctype_old_des3_cbc_sha1, +#endif +#ifdef HEIM_WEAK_CRYPTO + &_krb5_enctype_des_cbc_crc, + &_krb5_enctype_des_cbc_md4, + &_krb5_enctype_des_cbc_md5, + &_krb5_enctype_des_cbc_none, + &_krb5_enctype_des_cfb64_none, + &_krb5_enctype_des_pcbc_none, +#endif &_krb5_enctype_null }; diff --git a/lib/krb5/crypto-arcfour.c b/lib/krb5/crypto-arcfour.c index acc6c7ddd..0b5c7c25d 100644 --- a/lib/krb5/crypto-arcfour.c +++ b/lib/krb5/crypto-arcfour.c @@ -37,6 +37,8 @@ #include "krb5_locl.h" +#ifdef HEIM_ARCFOUR + static EVP_CIPHER * heim_EVP_rc4(krb5_context context) { @@ -406,3 +408,5 @@ struct _krb5_encryption_type _krb5_enctype_arcfour_hmac_md5 = { 0, ARCFOUR_prf }; + +#endif /* HEIM_ARCFOUR */ diff --git a/lib/krb5/crypto-des-common.c b/lib/krb5/crypto-des-common.c index c7bc8916c..a592a2717 100644 --- a/lib/krb5/crypto-des-common.c +++ b/lib/krb5/crypto-des-common.c @@ -31,6 +31,8 @@ * SUCH DAMAGE. */ +/* Functions which are used by both single and triple DES enctypes */ + #include "krb5_locl.h" /* @@ -50,6 +52,114 @@ _krb5_xor8(unsigned char *a, const unsigned char *b) a[7] ^= b[7]; } +#if defined(HEIM_DES3) || defined(HEIM_WEAK_CRYPTO) +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +_krb5_des_checksum(krb5_context context, + const EVP_MD *evp_md, + struct _krb5_key_data *key, + const struct krb5_crypto_iov *iov, + int niov, + Checksum *cksum) +{ + struct _krb5_evp_schedule *ctx = key->schedule->data; + EVP_MD_CTX *m; + DES_cblock ivec; + int i; + unsigned char *p = cksum->checksum.data; + + if (evp_md == NULL) { + krb5_set_error_message(context, KRB5_PROG_ETYPE_NOSUPP, + "1DES not supported"); + return KRB5_PROG_ETYPE_NOSUPP; + } + + krb5_generate_random_block(p, 8); + + m = EVP_MD_CTX_new(); + if (m == NULL) + return krb5_enomem(context); + + if (EVP_DigestInit_ex(m, evp_md, NULL) != 1 || + EVP_DigestUpdate(m, p, 8) != 1) + goto err; + for (i = 0; i < niov; i++) { + if (_krb5_crypto_iov_should_sign(&iov[i]) && + EVP_DigestUpdate(m, iov[i].data.data, iov[i].data.length) != 1) + goto err; + } + if (EVP_DigestFinal_ex(m, p + 8, NULL) != 1) + goto err; + EVP_MD_CTX_free(m); + memset_s(&ivec, sizeof(ivec), 0, sizeof(ivec)); + if (EVP_CipherInit_ex(ctx->ectx, NULL, NULL, NULL, (void *)&ivec, -1) != 1 || + EVP_Cipher(ctx->ectx, p, p, 24) < 0) + return KRB5_CRYPTO_INTERNAL; + + return 0; + +err: + EVP_MD_CTX_free(m); + return KRB5_CRYPTO_INTERNAL; +} + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +_krb5_des_verify(krb5_context context, + const EVP_MD *evp_md, + struct _krb5_key_data *key, + const struct krb5_crypto_iov *iov, + int niov, + Checksum *C) +{ + struct _krb5_evp_schedule *ctx = key->schedule->data; + EVP_MD_CTX *m; + unsigned char tmp[24]; + unsigned char res[16]; + DES_cblock ivec; + krb5_error_code ret = 0; + int i; + + if (evp_md == NULL) { + krb5_set_error_message(context, KRB5_PROG_ETYPE_NOSUPP, + "1DES not supported"); + return KRB5_PROG_ETYPE_NOSUPP; + } + + m = EVP_MD_CTX_new(); + if (m == NULL) + return krb5_enomem(context); + + memset_s(&ivec, sizeof(ivec), 0, sizeof(ivec)); + if (EVP_CipherInit_ex(ctx->dctx, NULL, NULL, NULL, (void *)&ivec, -1) != 1 || + EVP_Cipher(ctx->dctx, tmp, C->checksum.data, 24) < 0) + goto err; + + if (EVP_DigestInit_ex(m, evp_md, NULL) != 1 || + EVP_DigestUpdate(m, tmp, 8) != 1) /* confounder */ + goto err; + for (i = 0; i < niov; i++) { + if (_krb5_crypto_iov_should_sign(&iov[i]) && + EVP_DigestUpdate(m, iov[i].data.data, iov[i].data.length) != 1) + goto err; + } + if (EVP_DigestFinal_ex(m, res, NULL) != 1) + goto err; + EVP_MD_CTX_free(m); + if(ct_memcmp(res, tmp + 8, sizeof(res)) != 0) { + krb5_clear_error_message (context); + ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; + } + memset_s(tmp, sizeof(tmp), 0, sizeof(tmp)); + memset_s(res, sizeof(res), 0, sizeof(res)); + return ret; + +err: + EVP_MD_CTX_free(m); + memset_s(tmp, sizeof(tmp), 0, sizeof(tmp)); + return KRB5_CRYPTO_INTERNAL; +} + +#endif + static krb5_error_code RSA_MD5_checksum(krb5_context context, krb5_crypto crypto, @@ -60,7 +170,7 @@ RSA_MD5_checksum(krb5_context context, Checksum *C) { if (_krb5_evp_digest_iov(crypto, iov, niov, C->checksum.data, - NULL, EVP_md5(), NULL) != 1) + NULL, context->ossl->md5, NULL) != 1) krb5_abortx(context, "md5 checksum failed"); return 0; diff --git a/lib/krb5/crypto-des.c b/lib/krb5/crypto-des.c index 2b0aa5e2a..d257d228d 100644 --- a/lib/krb5/crypto-des.c +++ b/lib/krb5/crypto-des.c @@ -31,10 +31,84 @@ * SUCH DAMAGE. */ +/* + * Suppress OpenSSL deprecation warnings - we need these legacy DES functions + * for backward compatibility with old Kerberos encryption types. + */ +#define OPENSSL_SUPPRESS_DEPRECATED + #include "krb5_locl.h" #ifdef HEIM_WEAK_CRYPTO + +static void +krb5_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 int +krb5_DES_schedule_old(krb5_context context, + struct _krb5_key_type *kt, + struct _krb5_key_data *key) +{ + DES_set_key_unchecked(key->key->keyvalue.data, key->schedule->data); + return 0; +} + +static void +krb5_DES_random_to_key(krb5_context context, + krb5_keyblock *key, + const void *data, + size_t size) +{ + DES_cblock *k = key->keyvalue.data; + memcpy(k, data, key->keyvalue.length); + DES_set_odd_parity(k); + if(DES_is_weak_key(k)) + _krb5_xor8(*k, (const unsigned char*)"\0\0\0\0\0\0\0\xf0"); +} + +static struct _krb5_key_type keytype_des_old = { + ETYPE_DES_CBC_CRC, + "des-old", + 56, + 8, + sizeof(DES_key_schedule), + krb5_DES_random_key, + krb5_DES_schedule_old, + _krb5_des_salt, + krb5_DES_random_to_key, + NULL, + NULL +}; + +static EVP_CIPHER * +_krb5_evp_des_cbc(krb5_context context) +{ + return context->ossl->des_cbc; +} + +static struct _krb5_key_type keytype_des = { + ETYPE_DES_CBC_CRC, + "des", + 56, + 8, + sizeof(struct _krb5_evp_schedule), + krb5_DES_random_key, + _krb5_evp_schedule, + _krb5_des_salt, + krb5_DES_random_to_key, + _krb5_evp_cleanup, + _krb5_evp_des_cbc +}; + static krb5_error_code CRC32_checksum(krb5_context context, krb5_crypto crypto, @@ -72,11 +146,59 @@ RSA_MD4_checksum(krb5_context context, Checksum *C) { if (_krb5_evp_digest_iov(crypto, iov, niov, C->checksum.data, - NULL, EVP_md4(), NULL) != 1) + NULL, context->ossl->md4, NULL) != 1) krb5_abortx(context, "md4 checksum failed"); return 0; } +static krb5_error_code +RSA_MD4_DES_checksum(krb5_context context, + krb5_crypto crypto, + struct _krb5_key_data *key, + unsigned usage, + const struct krb5_crypto_iov *iov, + int niov, + Checksum *cksum) +{ + return _krb5_des_checksum(context, context->ossl->md4, key, iov, niov, cksum); +} + +static krb5_error_code +RSA_MD4_DES_verify(krb5_context context, + krb5_crypto crypto, + struct _krb5_key_data *key, + unsigned usage, + const struct krb5_crypto_iov *iov, + int niov, + Checksum *C) +{ + return _krb5_des_verify(context, context->ossl->md4, key, iov, niov, C); +} + +static krb5_error_code +RSA_MD5_DES_checksum(krb5_context context, + krb5_crypto crypto, + struct _krb5_key_data *key, + unsigned usage, + const struct krb5_crypto_iov *iov, + int niov, + Checksum *C) +{ + return _krb5_des_checksum(context, context->ossl->md5, key, iov, niov, C); +} + +static krb5_error_code +RSA_MD5_DES_verify(krb5_context context, + krb5_crypto crypto, + struct _krb5_key_data *key, + unsigned usage, + const struct krb5_crypto_iov *iov, + int niov, + Checksum *C) +{ + return _krb5_des_verify(context, context->ossl->md5, key, iov, niov, C); +} + struct _krb5_checksum_type _krb5_checksum_crc32 = { CKSUMTYPE_CRC32, "crc32", @@ -97,4 +219,200 @@ struct _krb5_checksum_type _krb5_checksum_rsa_md4 = { NULL }; +struct _krb5_checksum_type _krb5_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 +}; + +struct _krb5_checksum_type _krb5_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 +}; + +static krb5_error_code +evp_des_encrypt_null_ivec(krb5_context context, + struct _krb5_key_data *key, + void *data, + size_t len, + krb5_boolean encryptp, + int usage, + void *ignore_ivec) +{ + struct _krb5_evp_schedule *ctx = key->schedule->data; + EVP_CIPHER_CTX *c; + DES_cblock ivec; + memset(&ivec, 0, sizeof(ivec)); + c = encryptp ? ctx->ectx : ctx->dctx; + if (EVP_CipherInit_ex(c, NULL, NULL, NULL, (void *)&ivec, -1) != 1 || + EVP_Cipher(c, data, data, len) < 0) + return KRB5_CRYPTO_INTERNAL; + return 0; +} + +static krb5_error_code +evp_des_encrypt_key_ivec(krb5_context context, + struct _krb5_key_data *key, + void *data, + size_t len, + krb5_boolean encryptp, + int usage, + void *ignore_ivec) +{ + struct _krb5_evp_schedule *ctx = key->schedule->data; + EVP_CIPHER_CTX *c; + DES_cblock ivec; + memcpy(&ivec, key->key->keyvalue.data, sizeof(ivec)); + c = encryptp ? ctx->ectx : ctx->dctx; + if (EVP_CipherInit_ex(c, NULL, NULL, NULL, (void *)&ivec, -1) != 1 || + EVP_Cipher(c, data, data, len) < 0) + return KRB5_CRYPTO_INTERNAL; + return 0; +} + +static krb5_error_code +DES_CFB64_encrypt_null_ivec(krb5_context context, + struct _krb5_key_data *key, + void *data, + size_t len, + krb5_boolean encryptp, + int usage, + void *ignore_ivec) +{ + DES_cblock ivec; + int num = 0; + DES_key_schedule *s = key->schedule->data; + memset(&ivec, 0, sizeof(ivec)); + + DES_cfb64_encrypt(data, data, len, s, &ivec, &num, encryptp); + return 0; +} + +static krb5_error_code +DES_PCBC_encrypt_key_ivec(krb5_context context, + struct _krb5_key_data *key, + void *data, + size_t len, + krb5_boolean encryptp, + int usage, + void *ignore_ivec) +{ + DES_cblock ivec; + DES_key_schedule *s = key->schedule->data; + memcpy(&ivec, key->key->keyvalue.data, sizeof(ivec)); + + DES_pcbc_encrypt(data, data, len, s, &ivec, encryptp); + return 0; +} + +struct _krb5_encryption_type _krb5_enctype_des_cbc_crc = { + ETYPE_DES_CBC_CRC, + "des-cbc-crc", + NULL, + 8, + 8, + 8, + &keytype_des, + &_krb5_checksum_crc32, + NULL, + F_DISABLED|F_WEAK|F_OLD, + evp_des_encrypt_key_ivec, + NULL, + 0, + NULL +}; + +struct _krb5_encryption_type _krb5_enctype_des_cbc_md4 = { + ETYPE_DES_CBC_MD4, + "des-cbc-md4", + NULL, + 8, + 8, + 8, + &keytype_des, + &_krb5_checksum_rsa_md4, + &_krb5_checksum_rsa_md4_des, + F_DISABLED|F_WEAK|F_OLD, + evp_des_encrypt_null_ivec, + NULL, + 0, + NULL +}; + +struct _krb5_encryption_type _krb5_enctype_des_cbc_md5 = { + ETYPE_DES_CBC_MD5, + "des-cbc-md5", + NULL, + 8, + 8, + 8, + &keytype_des, + &_krb5_checksum_rsa_md5, + &_krb5_checksum_rsa_md5_des, + F_DISABLED|F_WEAK|F_OLD, + evp_des_encrypt_null_ivec, + NULL, + 0, + NULL +}; + +struct _krb5_encryption_type _krb5_enctype_des_cbc_none = { + ETYPE_DES_CBC_NONE, + "des-cbc-none", + NULL, + 8, + 8, + 0, + &keytype_des, + &_krb5_checksum_none, + NULL, + F_PSEUDO|F_DISABLED|F_WEAK|F_OLD, + evp_des_encrypt_null_ivec, + NULL, + 0, + NULL +}; + +struct _krb5_encryption_type _krb5_enctype_des_cfb64_none = { + ETYPE_DES_CFB64_NONE, + "des-cfb64-none", + NULL, + 1, + 1, + 0, + &keytype_des_old, + &_krb5_checksum_none, + NULL, + F_PSEUDO|F_DISABLED|F_WEAK|F_OLD, + DES_CFB64_encrypt_null_ivec, + NULL, + 0, + NULL +}; + +struct _krb5_encryption_type _krb5_enctype_des_pcbc_none = { + ETYPE_DES_PCBC_NONE, + "des-pcbc-none", + NULL, + 8, + 8, + 0, + &keytype_des_old, + &_krb5_checksum_none, + NULL, + F_PSEUDO|F_DISABLED|F_WEAK|F_OLD, + DES_PCBC_encrypt_key_ivec, + NULL, + 0, + NULL +}; #endif /* HEIM_WEAK_CRYPTO */ diff --git a/lib/krb5/crypto-des3.c b/lib/krb5/crypto-des3.c new file mode 100644 index 000000000..1d49eebf5 --- /dev/null +++ b/lib/krb5/crypto-des3.c @@ -0,0 +1,339 @@ +/* + * Copyright (c) 1997 - 2008 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. 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. + */ + +/* + * Suppress OpenSSL deprecation warnings - we need these legacy DES functions + * for backward compatibility with old Kerberos encryption types. + */ +#define OPENSSL_SUPPRESS_DEPRECATED + +#include "krb5_locl.h" + +#if defined(HEIM_DES3) || defined(HEIM_WEAK_CRYPTO) + +/* + * + */ + +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 krb5_error_code +DES3_prf(krb5_context context, + krb5_crypto crypto, + const krb5_data *in, + krb5_data *out) +{ + struct _krb5_checksum_type *ct = crypto->et->checksum; + struct krb5_crypto_iov iov[1]; + krb5_error_code ret; + Checksum result; + krb5_keyblock *derived; + + result.cksumtype = ct->type; + ret = krb5_data_alloc(&result.checksum, ct->checksumsize); + if (ret) { + krb5_set_error_message(context, ret, N_("malloc: out memory", "")); + return ret; + } + + iov[0].data = *in; + iov[0].flags = KRB5_CRYPTO_TYPE_DATA; + ret = (*ct->checksum)(context, crypto, NULL, 0, iov, 1, &result); + if (ret) { + krb5_data_free(&result.checksum); + return ret; + } + + if (result.checksum.length < crypto->et->blocksize) + krb5_abortx(context, "internal prf error"); + + derived = NULL; + ret = krb5_derive_key(context, crypto->key.key, + crypto->et->type, "prf", 3, &derived); + if (ret) + krb5_abortx(context, "krb5_derive_key"); + + ret = krb5_data_alloc(out, crypto->et->prf_length); + if (ret) + krb5_abortx(context, "malloc failed"); + + { + const EVP_CIPHER *c = (*crypto->et->keytype->evp)(context); + EVP_CIPHER_CTX *ctx; + unsigned char zero_ivec[EVP_MAX_IV_LENGTH] = { 0 }; + + if (c == NULL) { + krb5_data_free(out); + krb5_data_free(&result.checksum); + krb5_free_keyblock(context, derived); + krb5_set_error_message(context, KRB5_PROG_ETYPE_NOSUPP, + "Encryption type not supported: %s", + crypto->et->keytype->name); + return KRB5_PROG_ETYPE_NOSUPP; + } + ctx = EVP_CIPHER_CTX_new(); + if (ctx == NULL) { + krb5_data_free(out); + krb5_data_free(&result.checksum); + krb5_free_keyblock(context, derived); + return krb5_enomem(context); + } + if (EVP_CipherInit_ex(ctx, c, NULL, derived->keyvalue.data, zero_ivec, 1) != 1 || + EVP_Cipher(ctx, out->data, result.checksum.data, + crypto->et->prf_length) < 0) { + EVP_CIPHER_CTX_free(ctx); + krb5_data_free(out); + krb5_data_free(&result.checksum); + krb5_free_keyblock(context, derived); + return KRB5_CRYPTO_INTERNAL; + } + EVP_CIPHER_CTX_free(ctx); + } + + krb5_data_free(&result.checksum); + krb5_free_keyblock(context, derived); + + return ret; +} + +static EVP_CIPHER * +_krb5_evp_des_ede3_cbc(krb5_context context) +{ + return context->ossl->des_ede3_cbc; +} +#endif /* HEIM_DES3 || HEIM_WEAK_CRYPTO */ + +#ifdef HEIM_DES3 +static struct _krb5_key_type keytype_des3 = { + ETYPE_OLD_DES3_CBC_SHA1, + "des3", + 168, + 24, + sizeof(struct _krb5_evp_schedule), + DES3_random_key, + _krb5_evp_schedule, + _krb5_des3_salt, + _krb5_DES3_random_to_key, + _krb5_evp_cleanup, + _krb5_evp_des_ede3_cbc +}; +#endif + +#if defined(HEIM_DES3) || defined(HEIM_WEAK_CRYPTO) +static struct _krb5_key_type keytype_des3_derived = { + ETYPE_OLD_DES3_CBC_SHA1, + "des3", + 168, + 24, + sizeof(struct _krb5_evp_schedule), + DES3_random_key, + _krb5_evp_schedule, + _krb5_des3_salt_derived, + _krb5_DES3_random_to_key, + _krb5_evp_cleanup, + _krb5_evp_des_ede3_cbc +}; +#endif + +#ifdef HEIM_DES3 +static krb5_error_code +RSA_MD5_DES3_checksum(krb5_context context, + krb5_crypto crypto, + struct _krb5_key_data *key, + unsigned usage, + const struct krb5_crypto_iov *iov, + int niov, + Checksum *C) +{ + return _krb5_des_checksum(context, context->ossl->md5, key, iov, niov, C); +} + +static krb5_error_code +RSA_MD5_DES3_verify(krb5_context context, + krb5_crypto crypto, + struct _krb5_key_data *key, + unsigned usage, + const struct krb5_crypto_iov *iov, + int niov, + Checksum *C) +{ + return _krb5_des_verify(context, context->ossl->md5, key, iov, niov, C); +} + +struct _krb5_checksum_type _krb5_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 +}; +#endif + +#if defined(HEIM_DES3) || defined(HEIM_WEAK_CRYPTO) +struct _krb5_checksum_type _krb5_checksum_hmac_sha1_des3 = { + CKSUMTYPE_HMAC_SHA1_DES3, + "hmac-sha1-des3", + 64, + 20, + F_KEYED | F_CPROOF | F_DERIVED, + _krb5_SP_HMAC_SHA1_checksum, + NULL +}; +#endif + +#ifdef HEIM_DES3 +struct _krb5_encryption_type _krb5_enctype_des3_cbc_md5 = { + ETYPE_DES3_CBC_MD5, + "des3-cbc-md5", + NULL, + 8, + 8, + 8, + &keytype_des3, + &_krb5_checksum_rsa_md5, + &_krb5_checksum_rsa_md5_des3, + F_OLD, + _krb5_evp_encrypt, + _krb5_evp_encrypt_iov, + 0, + NULL +}; +#endif + +#if defined(HEIM_DES3) || defined(HEIM_WEAK_CRYPTO) +struct _krb5_encryption_type _krb5_enctype_des3_cbc_sha1 = { + ETYPE_DES3_CBC_SHA1, + "des3-cbc-sha1", + NULL, + 8, + 8, + 8, + &keytype_des3_derived, + &_krb5_checksum_sha1, + &_krb5_checksum_hmac_sha1_des3, + F_DERIVED | F_RFC3961_ENC | F_RFC3961_KDF | F_OLD, + _krb5_evp_encrypt, + _krb5_evp_encrypt_iov, + 16, + DES3_prf +}; +#endif + +#ifdef HEIM_DES3 +struct _krb5_encryption_type _krb5_enctype_old_des3_cbc_sha1 = { + ETYPE_OLD_DES3_CBC_SHA1, + "old-des3-cbc-sha1", + NULL, + 8, + 8, + 8, + &keytype_des3, + &_krb5_checksum_sha1, + &_krb5_checksum_hmac_sha1_des3, + F_OLD, + _krb5_evp_encrypt, + _krb5_evp_encrypt_iov, + 0, + NULL +}; +#endif + +#if defined(HEIM_DES3) || defined(HEIM_WEAK_CRYPTO) +struct _krb5_encryption_type _krb5_enctype_des3_cbc_none = { + ETYPE_DES3_CBC_NONE, + "des3-cbc-none", + NULL, + 8, + 8, + 0, + &keytype_des3_derived, + &_krb5_checksum_none, + NULL, + F_PSEUDO | F_OLD, + _krb5_evp_encrypt, + _krb5_evp_encrypt_iov, + 0, + NULL +}; +#endif + +#if defined(HEIM_DES3) || defined(HEIM_WEAK_CRYPTO) +void +_krb5_DES3_random_to_key(krb5_context context, + krb5_keyblock *key, + const void *data, + size_t size) +{ + unsigned char *x = key->keyvalue.data; + const u_char *q = data; + DES_cblock *k; + int i, j; + + memset(key->keyvalue.data, 0, key->keyvalue.length); + for (i = 0; i < 3; ++i) { + unsigned char foo; + for (j = 0; j < 7; ++j) { + unsigned char b = q[7 * i + j]; + + x[8 * i + j] = b; + } + foo = 0; + for (j = 6; j >= 0; --j) { + foo |= q[7 * i + j] & 1; + foo <<= 1; + } + x[8 * i + 7] = foo; + } + k = key->keyvalue.data; + for (i = 0; i < 3; i++) { + DES_set_odd_parity(&k[i]); + if(DES_is_weak_key(&k[i])) + _krb5_xor8(k[i], (const unsigned char*)"\0\0\0\0\0\0\0\xf0"); + } +} +#endif /* HEIM_DES3 || HEIM_WEAK_CRYPTO */ diff --git a/lib/krb5/crypto-evp.c b/lib/krb5/crypto-evp.c index 2d7b7d1d2..2d2da950a 100644 --- a/lib/krb5/crypto-evp.c +++ b/lib/krb5/crypto-evp.c @@ -248,7 +248,6 @@ _krb5_evp_encrypt(krb5_context context, { struct _krb5_evp_schedule *ctx = key->schedule->data; EVP_CIPHER_CTX *c; - int ret = 0; c = encryptp ? ctx->ectx : ctx->dctx; if (ivec == NULL) { @@ -259,16 +258,18 @@ _krb5_evp_encrypt(krb5_context context, return krb5_enomem(context); memset(loiv, 0, len2); if (EVP_CipherInit_ex(c, NULL, NULL, NULL, loiv, -1) != 1) { - ret = _krb5_set_error_message_openssl(context, KRB5_CRYPTO_INTERNAL, - "Failed to initialize cipher"); + free(loiv); + return _krb5_set_error_message_openssl(context, KRB5_CRYPTO_INTERNAL, + "Failed to initialize cipher"); } free(loiv); } else if (EVP_CipherInit_ex(c, NULL, NULL, NULL, ivec, -1) != 1) { - ret = _krb5_set_error_message_openssl(context, KRB5_CRYPTO_INTERNAL, - "Failed to initialize cipher"); + return _krb5_set_error_message_openssl(context, KRB5_CRYPTO_INTERNAL, + "Failed to initialize cipher"); } - EVP_Cipher(c, data, data, len); - return ret; + if (EVP_Cipher(c, data, data, len) < 0) + return KRB5_CRYPTO_INTERNAL; + return 0; } struct _krb5_evp_iov_cursor @@ -755,7 +756,9 @@ _krb5_evp_encrypt_cts(krb5_context context, if (encryptp) { p = data; i = ((len - 1) / blocksize) * blocksize; - EVP_Cipher(c, p, p, i); + if (EVP_Cipher(c, p, p, i) != (int)i) + return _krb5_set_error_message_openssl(context, EINVAL, + "Failed to encrypt"); p += i - blocksize; len -= i; memcpy(ivec2, p, blocksize); @@ -781,7 +784,9 @@ _krb5_evp_encrypt_cts(krb5_context context, /* remove last two blocks and round up, decrypt this with cbc, then do cts dance */ i = ((((len - blocksize * 2) + blocksize - 1) / blocksize) * blocksize); memcpy(ivec2, p + i - blocksize, blocksize); - EVP_Cipher(c, p, p, i); + if (EVP_Cipher(c, p, p, i) != (int)i) + return _krb5_set_error_message_openssl(context, EINVAL, + "Failed to decrypt"); p += i; len -= i + blocksize; } else { diff --git a/lib/krb5/crypto-null.c b/lib/krb5/crypto-null.c index a62a57ffc..a1fab4b46 100644 --- a/lib/krb5/crypto-null.c +++ b/lib/krb5/crypto-null.c @@ -33,10 +33,6 @@ #include "krb5_locl.h" -#ifndef HEIMDAL_SMALLER -#define DES3_OLD_ENCTYPE 1 -#endif - static struct _krb5_key_type keytype_null = { KRB5_ENCTYPE_NULL, "null", diff --git a/lib/krb5/crypto-stubs.c b/lib/krb5/crypto-stubs.c index 5251f8857..64aa625f2 100644 --- a/lib/krb5/crypto-stubs.c +++ b/lib/krb5/crypto-stubs.c @@ -39,6 +39,7 @@ KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL krb5_init_context(krb5_context *context) { krb5_context p; + krb5_context_ossl ossl; *context = NULL; @@ -49,6 +50,27 @@ krb5_init_context(krb5_context *context) if(!p) return ENOMEM; + /* Initialize minimal OpenSSL context for crypto operations */ + ossl = calloc(1, sizeof(*ossl)); + if (ossl == NULL) { + free(p); + return ENOMEM; + } + ossl->libctx = OSSL_LIB_CTX_get0_global_default(); + ossl->openssl_leg = OSSL_PROVIDER_load(ossl->libctx, "legacy"); + ossl->openssl_def = OSSL_PROVIDER_load(ossl->libctx, "default"); + ossl->des_cbc = EVP_CIPHER_fetch(ossl->libctx, "DES-CBC", NULL); + ossl->des_ede3_cbc = EVP_CIPHER_fetch(ossl->libctx, "DES-EDE3-CBC", NULL); + ossl->rc4 = EVP_CIPHER_fetch(ossl->libctx, "RC4", NULL); + ossl->aes128_cbc = EVP_CIPHER_fetch(ossl->libctx, "AES-128-CBC", NULL); + ossl->aes256_cbc = EVP_CIPHER_fetch(ossl->libctx, "AES-256-CBC", NULL); + ossl->md4 = EVP_MD_fetch(ossl->libctx, "MD4", NULL); + ossl->md5 = EVP_MD_fetch(ossl->libctx, "MD5", NULL); + ossl->sha1 = EVP_MD_fetch(ossl->libctx, "SHA1", NULL); + ossl->sha256 = EVP_MD_fetch(ossl->libctx, "SHA256", NULL); + ossl->sha384 = EVP_MD_fetch(ossl->libctx, "SHA384", NULL); + p->ossl = ossl; + *context = p; return 0; } @@ -62,6 +84,25 @@ krb5_free_context(krb5_context context) rk_SOCK_EXIT(); } + /* Clean up OpenSSL context */ + if (context->ossl) { + EVP_CIPHER_free(context->ossl->des_cbc); + EVP_CIPHER_free(context->ossl->des_ede3_cbc); + EVP_CIPHER_free(context->ossl->rc4); + EVP_CIPHER_free(context->ossl->aes128_cbc); + EVP_CIPHER_free(context->ossl->aes256_cbc); + EVP_MD_free(context->ossl->md4); + EVP_MD_free(context->ossl->md5); + EVP_MD_free(context->ossl->sha1); + EVP_MD_free(context->ossl->sha256); + EVP_MD_free(context->ossl->sha384); + if (context->ossl->openssl_leg) + OSSL_PROVIDER_unload(context->ossl->openssl_leg); + if (context->ossl->openssl_def) + OSSL_PROVIDER_unload(context->ossl->openssl_def); + free(context->ossl); + } + memset(context, 0, sizeof(*context)); free(context); } diff --git a/lib/krb5/crypto.c b/lib/krb5/crypto.c index 352082ef9..1363e8029 100644 --- a/lib/krb5/crypto.c +++ b/lib/krb5/crypto.c @@ -39,10 +39,6 @@ struct _krb5_key_usage { }; -#ifndef HEIMDAL_SMALLER -#define DES3_OLD_ENCTYPE 1 -#endif - static krb5_error_code _get_derived_key(krb5_context, krb5_crypto, unsigned, struct _krb5_key_data**); static struct _krb5_key_data *_new_derived_key(krb5_crypto crypto, unsigned usage); @@ -2408,7 +2404,20 @@ derive_key_rfc3961(krb5_context context, } } - memcpy(key->key->keyvalue.data, k, key->key->keyvalue.length); + /* + * RFC 3961: DK(Key, Constant) = random-to-key(DR(Key, Constant)) + * + * For keytypes where bits != size*8 (e.g., DES3: 168 bits, 24 bytes), + * we need to truncate the DR output to bits/8 bytes and apply + * random-to-key to convert to the final key. + */ + if (kt->random_to_key) { + /* Truncate DR output to key-generation-seed-length and apply random-to-key */ + (*kt->random_to_key)(context, key->key, k, kt->bits / 8); + } else { + /* For keytypes like AES where bits == size*8, just copy */ + memcpy(key->key->keyvalue.data, k, key->key->keyvalue.length); + } out: if (k) { diff --git a/lib/krb5/crypto.h b/lib/krb5/crypto.h index 05b2d8d4a..10a8d77f7 100644 --- a/lib/krb5/crypto.h +++ b/lib/krb5/crypto.h @@ -31,9 +31,12 @@ * SUCH DAMAGE. */ -#ifndef HEIMDAL_SMALLER -#define DES3_OLD_ENCTYPE 1 -#endif +/* + * Legacy encryption type support is controlled by config.h macros: + * HEIM_WEAK_CRYPTO - enables single DES (--with-1des) + * HEIM_DES3 - enables triple DES (--with-3des) + * HEIM_ARCFOUR - enables ARCFOUR/RC4 (--with-arcfour) + */ struct _krb5_key_data { krb5_keyblock *key; @@ -140,7 +143,12 @@ struct _krb5_encryption_type { extern struct _krb5_checksum_type _krb5_checksum_none; extern struct _krb5_checksum_type _krb5_checksum_crc32; +extern struct _krb5_checksum_type _krb5_checksum_rsa_md4; +extern struct _krb5_checksum_type _krb5_checksum_rsa_md4_des; extern struct _krb5_checksum_type _krb5_checksum_rsa_md5; +extern struct _krb5_checksum_type _krb5_checksum_rsa_md5_des; +extern struct _krb5_checksum_type _krb5_checksum_rsa_md5_des3; +extern struct _krb5_checksum_type _krb5_checksum_hmac_sha1_des3; extern struct _krb5_checksum_type _krb5_checksum_hmac_sha1_aes128; extern struct _krb5_checksum_type _krb5_checksum_hmac_sha1_aes256; extern struct _krb5_checksum_type _krb5_checksum_hmac_sha256_128_aes128; @@ -158,7 +166,16 @@ extern int _krb5_num_checksums; extern struct salt_type _krb5_AES_SHA1_salt[]; extern struct salt_type _krb5_AES_SHA2_salt[]; +#ifdef HEIM_ARCFOUR extern struct salt_type _krb5_arcfour_salt[]; +#endif +#ifdef HEIM_WEAK_CRYPTO +extern struct salt_type _krb5_des_salt[]; +#endif +#if defined(HEIM_DES3) || defined(HEIM_WEAK_CRYPTO) +extern struct salt_type _krb5_des3_salt[]; +extern struct salt_type _krb5_des3_salt_derived[]; +#endif /* Encryption types */ @@ -166,7 +183,25 @@ extern struct _krb5_encryption_type _krb5_enctype_aes256_cts_hmac_sha1; extern struct _krb5_encryption_type _krb5_enctype_aes128_cts_hmac_sha1; extern struct _krb5_encryption_type _krb5_enctype_aes128_cts_hmac_sha256_128; extern struct _krb5_encryption_type _krb5_enctype_aes256_cts_hmac_sha384_192; +#ifdef HEIM_ARCFOUR extern struct _krb5_encryption_type _krb5_enctype_arcfour_hmac_md5; +#endif +#if defined(HEIM_DES3) || defined(HEIM_WEAK_CRYPTO) +extern struct _krb5_encryption_type _krb5_enctype_des3_cbc_sha1; +extern struct _krb5_encryption_type _krb5_enctype_des3_cbc_none; +#endif +#ifdef HEIM_DES3 +extern struct _krb5_encryption_type _krb5_enctype_des3_cbc_md5; +extern struct _krb5_encryption_type _krb5_enctype_old_des3_cbc_sha1; +#endif +#ifdef HEIM_WEAK_CRYPTO +extern struct _krb5_encryption_type _krb5_enctype_des_cbc_crc; +extern struct _krb5_encryption_type _krb5_enctype_des_cbc_md4; +extern struct _krb5_encryption_type _krb5_enctype_des_cbc_md5; +extern struct _krb5_encryption_type _krb5_enctype_des_cbc_none; +extern struct _krb5_encryption_type _krb5_enctype_des_cfb64_none; +extern struct _krb5_encryption_type _krb5_enctype_des_pcbc_none; +#endif extern struct _krb5_encryption_type _krb5_enctype_null; extern struct _krb5_encryption_type *_krb5_etypes[]; @@ -207,3 +242,19 @@ struct krb5_crypto_data { * key material is available. */ #define KRB5_CRYPTO_FLAG_ALLOW_UNKEYED_CHECKSUM 0x01 + +/* DES/3DES helper functions */ +#if defined(HEIM_DES3) || defined(HEIM_WEAK_CRYPTO) +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +_krb5_des_checksum(krb5_context, const EVP_MD *, + struct _krb5_key_data *, + const struct krb5_crypto_iov *, int, + Checksum *); +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +_krb5_des_verify(krb5_context, const EVP_MD *, + struct _krb5_key_data *, + const struct krb5_crypto_iov *, int, + Checksum *); +void _krb5_DES3_random_to_key(krb5_context, krb5_keyblock *, + const void *, size_t); +#endif diff --git a/lib/krb5/krb5_locl.h b/lib/krb5/krb5_locl.h index e52a54c9d..fb7fcaf6e 100644 --- a/lib/krb5/krb5_locl.h +++ b/lib/krb5/krb5_locl.h @@ -298,7 +298,10 @@ struct krb5_context_ossl_data { EVP_CIPHER *aes128_cts; EVP_CIPHER *aes192_cts; EVP_CIPHER *aes256_cts; + EVP_CIPHER *des_cbc; + EVP_CIPHER *des_ede3_cbc; EVP_MAC *hmac; + EVP_MD *md4; EVP_MD *md5; EVP_MD *sha1; EVP_MD *sha256; diff --git a/lib/krb5/salt-arcfour.c b/lib/krb5/salt-arcfour.c index 033128ed8..61cd8c2c9 100644 --- a/lib/krb5/salt-arcfour.c +++ b/lib/krb5/salt-arcfour.c @@ -33,6 +33,8 @@ #include "krb5_locl.h" +#ifdef HEIM_ARCFOUR + static krb5_error_code ARCFOUR_string_to_key(krb5_context context, krb5_enctype enctype, @@ -105,3 +107,5 @@ struct salt_type _krb5_arcfour_salt[] = { }, { 0, NULL, NULL } }; + +#endif /* HEIM_ARCFOUR */ diff --git a/lib/krb5/salt-des.c b/lib/krb5/salt-des.c index cb727c15d..0a8b0bad9 100644 --- a/lib/krb5/salt-des.c +++ b/lib/krb5/salt-des.c @@ -31,6 +31,12 @@ * SUCH DAMAGE. */ +/* + * Suppress OpenSSL deprecation warnings - we need these legacy DES functions + * for backward compatibility with old Kerberos encryption types. + */ +#define OPENSSL_SUPPRESS_DEPRECATED + #include "krb5_locl.h" #ifdef HEIM_WEAK_CRYPTO diff --git a/lib/krb5/salt-des3.c b/lib/krb5/salt-des3.c index a9293ccec..0dbc3cec8 100644 --- a/lib/krb5/salt-des3.c +++ b/lib/krb5/salt-des3.c @@ -31,9 +31,15 @@ * SUCH DAMAGE. */ +/* + * Suppress OpenSSL deprecation warnings - we need these legacy DES functions + * for backward compatibility with old Kerberos encryption types. + */ +#define OPENSSL_SUPPRESS_DEPRECATED + #include "krb5_locl.h" -#ifdef DES3_OLD_ENCTYPE +#ifdef HEIM_DES3 static krb5_error_code DES3_string_to_key(krb5_context context, krb5_enctype enctype, @@ -126,7 +132,7 @@ DES3_string_to_key_derived(krb5_context context, } -#ifdef DES3_OLD_ENCTYPE +#ifdef HEIM_DES3 struct salt_type _krb5_des3_salt[] = { { KRB5_PW_SALT, diff --git a/lib/krb5/salt.c b/lib/krb5/salt.c index e2ebfc182..5fe270017 100644 --- a/lib/krb5/salt.c +++ b/lib/krb5/salt.c @@ -309,8 +309,61 @@ krb5_string_to_key_derived(krb5_context context, krb5_enctype etype, krb5_keyblock *key) { +#if defined(HEIM_DES3) || defined(HEIM_WEAK_CRYPTO) + struct _krb5_encryption_type *et = _krb5_find_enctype(etype); + krb5_error_code ret; + struct _krb5_key_data kd; + size_t keylen; + u_char *tmp; + + if(et == NULL) { + krb5_set_error_message (context, KRB5_PROG_ETYPE_NOSUPP, + N_("encryption type %d not supported", ""), + etype); + return KRB5_PROG_ETYPE_NOSUPP; + } + keylen = et->keytype->bits / 8; + + ALLOC(kd.key, 1); + if(kd.key == NULL) + return krb5_enomem(context); + ret = krb5_data_alloc(&kd.key->keyvalue, et->keytype->size); + if(ret) { + free(kd.key); + return ret; + } + kd.key->keytype = etype; + tmp = malloc (keylen); + if(tmp == NULL) { + krb5_free_keyblock(context, kd.key); + return krb5_enomem(context); + } + ret = _krb5_n_fold(str, len, tmp, keylen); + if (ret) { + free(tmp); + krb5_free_keyblock(context, kd.key); + return ret; + } + kd.schedule = NULL; + _krb5_DES3_random_to_key(context, kd.key, tmp, keylen); + memset(tmp, 0, keylen); + free(tmp); + ret = _krb5_derive_key(context, + et, + &kd, + "kerberos", + strlen("kerberos")); + if (ret) { + _krb5_free_key_data(context, &kd, et); + return ret; + } + ret = krb5_copy_keyblock_contents(context, kd.key, key); + _krb5_free_key_data(context, &kd, et); + return ret; +#else krb5_set_error_message (context, KRB5_PROG_ETYPE_NOSUPP, N_("encryption type %d not supported", ""), etype); return KRB5_PROG_ETYPE_NOSUPP; +#endif } diff --git a/lib/krb5/test_rfc3961.c b/lib/krb5/test_rfc3961.c index ed8ee9b5f..15422f86d 100644 --- a/lib/krb5/test_rfc3961.c +++ b/lib/krb5/test_rfc3961.c @@ -374,6 +374,211 @@ static struct rfc2202 rfc2202_vectors[] = } }; +/* RFC 3961 A.2: DES string-to-key test vectors */ +struct des_s2k_test { + const char *password; + size_t password_len; + const char *salt; + size_t salt_len; + unsigned char expected_key[8]; +}; + +static struct des_s2k_test rfc3961_des_vectors[] = { + { + "password", 8, + "ATHENA.MIT.EDUraeburn", 21, + {0xcb, 0xc2, 0x2f, 0xae, 0x23, 0x52, 0x98, 0xe3} + }, + { + "potatoe", 7, + "WHITEHOUSE.GOVdanny", 19, + {0xdf, 0x3d, 0x32, 0xa7, 0x4f, 0xd9, 0x2a, 0x01} + }, + { + /* password: g-clef U+1011E encoded as UTF-8 */ + "\xf0\x9d\x84\x9e", 4, + "EXAMPLE.COMpianist", 18, + {0x4f, 0xfb, 0x26, 0xba, 0xb0, 0xcd, 0x94, 0x13} + }, + { + /* password: eszett U+00DF encoded as UTF-8 */ + "\xc3\x9f", 2, + /* salt: "ATHENA.MIT.EDUJuri" + s-caron(U+0161) + "i" + c-acute(U+0107) */ + "ATHENA.MIT.EDUJuri\xc5\xa1i\xc4\x87", 23, + {0x62, 0xc8, 0x1a, 0x52, 0x32, 0xb5, 0xe6, 0x9d} + }, + { + /* Weak key fixup test case 1 */ + "11119999", 8, + "AAAAAAAA", 8, + {0x98, 0x40, 0x54, 0xd0, 0xf1, 0xa7, 0x3e, 0x31} + }, + { + /* Weak key fixup test case 2 */ + "NNNN6666", 8, + "FFFFAAAA", 8, + {0xc4, 0xbf, 0x6b, 0x25, 0xad, 0xf7, 0xa4, 0xf8} + } +}; + +/* RFC 3961 A.4: DES3 string-to-key test vectors */ +struct des3_s2k_test { + const char *password; + size_t password_len; + const char *salt; + size_t salt_len; + unsigned char expected_key[24]; +}; + +static struct des3_s2k_test rfc3961_des3_vectors[] = { + { + "password", 8, + "ATHENA.MIT.EDUraeburn", 21, + {0x85, 0x0b, 0xb5, 0x13, 0x58, 0x54, 0x8c, 0xd0, + 0x5e, 0x86, 0x76, 0x8c, 0x31, 0x3e, 0x3b, 0xfe, + 0xf7, 0x51, 0x19, 0x37, 0xdc, 0xf7, 0x2c, 0x3e} + }, + { + "potatoe", 7, + "WHITEHOUSE.GOVdanny", 19, + {0xdf, 0xcd, 0x23, 0x3d, 0xd0, 0xa4, 0x32, 0x04, + 0xea, 0x6d, 0xc4, 0x37, 0xfb, 0x15, 0xe0, 0x61, + 0xb0, 0x29, 0x79, 0xc1, 0xf7, 0x4f, 0x37, 0x7a} + }, + { + "penny", 5, + "EXAMPLE.COMbuckaroo", 19, + {0x6d, 0x2f, 0xcd, 0xf2, 0xd6, 0xfb, 0xbc, 0x3d, + 0xdc, 0xad, 0xb5, 0xda, 0x57, 0x10, 0xa2, 0x34, + 0x89, 0xb0, 0xd3, 0xb6, 0x9d, 0x5d, 0x9d, 0x4a} + }, + { + /* password: eszett U+00DF encoded as UTF-8 */ + "\xc3\x9f", 2, + /* salt: "ATHENA.MIT.EDUJuri" + s-caron(U+0161) + "i" + c-acute(U+0107) */ + "ATHENA.MIT.EDUJuri\xc5\xa1i\xc4\x87", 23, + {0x16, 0xd5, 0xa4, 0x0e, 0x1c, 0xe3, 0xba, 0xcb, + 0x61, 0xb9, 0xdc, 0xe0, 0x04, 0x70, 0x32, 0x4c, + 0x83, 0x19, 0x73, 0xa7, 0xb9, 0x52, 0xfe, 0xb0} + }, + { + /* password: g-clef U+1011E encoded as UTF-8 */ + "\xf0\x9d\x84\x9e", 4, + "EXAMPLE.COMpianist", 18, + {0x85, 0x76, 0x37, 0x26, 0x58, 0x5d, 0xbc, 0x1c, + 0xce, 0x6e, 0xc4, 0x3e, 0x1f, 0x75, 0x1f, 0x07, + 0xf1, 0xc4, 0xcb, 0xb0, 0x98, 0xf4, 0x0b, 0x19} + } +}; + +/* RFC 3961 test for DES string-to-key */ +static void +test_rfc3961_des_s2k(krb5_context context) +{ + size_t num_tests; + size_t i; + krb5_error_code ret; + + num_tests = sizeof(rfc3961_des_vectors) / sizeof(rfc3961_des_vectors[0]); + + printf("Running %zu RFC3961 DES string-to-key tests\n", num_tests); + + krb5_enctype_enable(context, ETYPE_DES_CBC_CRC); + + for (i = 0; i < num_tests; i++) { + krb5_keyblock key; + krb5_salt salt; + krb5_data opaque; + + salt.salttype = KRB5_PW_SALT; + salt.saltvalue.data = rk_UNCONST(rfc3961_des_vectors[i].salt); + salt.saltvalue.length = rfc3961_des_vectors[i].salt_len; + + opaque.data = NULL; + opaque.length = 0; + + ret = krb5_string_to_key_salt_opaque(context, + ETYPE_DES_CBC_CRC, + rfc3961_des_vectors[i].password, + salt, opaque, &key); + if (ret) + errx(1, "DES string-to-key failed on test %zu: %d", i + 1, ret); + + if (key.keyvalue.length != 8) + errx(1, "DES key length wrong on test %zu: got %zu, expected 8", + i + 1, key.keyvalue.length); + + if (memcmp(key.keyvalue.data, rfc3961_des_vectors[i].expected_key, 8) != 0) { + printf("DES test %zu FAILED\n", i + 1); + printf(" Expected: "); + for (size_t j = 0; j < 8; j++) + printf("%02x", rfc3961_des_vectors[i].expected_key[j]); + printf("\n Got: "); + for (size_t j = 0; j < 8; j++) + printf("%02x", ((unsigned char *)key.keyvalue.data)[j]); + printf("\n"); + errx(1, "DES key mismatch on test %zu", i + 1); + } + + krb5_free_keyblock_contents(context, &key); + printf("DES string-to-key test %zu okay\n", i + 1); + } +} + +/* RFC 3961 test for DES3 string-to-key */ +static void +test_rfc3961_des3_s2k(krb5_context context) +{ + size_t num_tests; + size_t i; + krb5_error_code ret; + + num_tests = sizeof(rfc3961_des3_vectors) / sizeof(rfc3961_des3_vectors[0]); + + printf("Running %zu RFC3961 DES3 string-to-key tests\n", num_tests); + + krb5_enctype_enable(context, ETYPE_DES3_CBC_SHA1); + + for (i = 0; i < num_tests; i++) { + krb5_keyblock key; + krb5_salt salt; + krb5_data opaque; + + salt.salttype = KRB5_PW_SALT; + salt.saltvalue.data = rk_UNCONST(rfc3961_des3_vectors[i].salt); + salt.saltvalue.length = rfc3961_des3_vectors[i].salt_len; + + opaque.data = NULL; + opaque.length = 0; + + ret = krb5_string_to_key_salt_opaque(context, + ETYPE_DES3_CBC_SHA1, + rfc3961_des3_vectors[i].password, + salt, opaque, &key); + if (ret) + errx(1, "DES3 string-to-key failed on test %zu: %d", i + 1, ret); + + if (key.keyvalue.length != 24) + errx(1, "DES3 key length wrong on test %zu: got %zu, expected 24", + i + 1, key.keyvalue.length); + + if (memcmp(key.keyvalue.data, rfc3961_des3_vectors[i].expected_key, 24) != 0) { + printf("DES3 test %zu FAILED\n", i + 1); + printf(" Expected: "); + for (size_t j = 0; j < 24; j++) + printf("%02x", rfc3961_des3_vectors[i].expected_key[j]); + printf("\n Got: "); + for (size_t j = 0; j < 24; j++) + printf("%02x", ((unsigned char *)key.keyvalue.data)[j]); + printf("\n"); + errx(1, "DES3 key mismatch on test %zu", i + 1); + } + + krb5_free_keyblock_contents(context, &key); + printf("DES3 string-to-key test %zu okay\n", i + 1); + } +} + /* RFC 2202 test vectors for HMAC-SHA1 */ static void test_rfc2202(krb5_context context) @@ -474,6 +679,8 @@ main(int argc, char **argv) errx (1, "krb5_init_context failed: %d", ret); test_rfc2202(context); + test_rfc3961_des_s2k(context); + test_rfc3961_des3_s2k(context); enciter = 1000; hmaciter = 10000;