From d7d716f3270235529995e0d28b8d6c89f4171045 Mon Sep 17 00:00:00 2001
From: Robbie Harwood <rharwood@redhat.com>
Date: Fri, 9 Nov 2018 15:12:21 -0500
Subject: [PATCH 01/21] FIPS: Add support for PRNG, RADIUS (krad), and crypto
 providers

In FIPS mode:
- Use OpenSSL's RAND_bytes() for entropy instead of OS sources
- Track FIPS "tainted" packets in krad that skip MD5 encryption
- Block sending tainted RADIUS packets over network (only allow
  local UNIX sockets)
- Block Camellia and RC4 operations (not FIPS-approved)
- Add radius_md5_fips_override config option to allow MD5 in
  protected RADIUS connections

The is_fips flag in krad packets prevents accidentally sending
cleartext passwords over the network when MD5 encryption is
skipped in FIPS mode.

Uses EVP_default_properties_is_fips_enabled() for FIPS mode
detection, which is the OpenSSL 3.0+ API (replacing the deprecated
FIPS_mode() function).

Based on Fedora patch by Robbie Harwood, updated for krb5-1.22.1
with Message-Authenticator support merge.

Last-updated: krb5-1.22.1
Forward-ported-by: Andreas Schneider <asn@redhat.com>
---
 doc/admin/conf_files/krb5_conf.rst            |  6 +++
 src/lib/crypto/krb/prng.c                     | 19 ++++++--
 .../crypto/openssl/enc_provider/camellia.c    |  6 +++
 src/lib/crypto/openssl/enc_provider/rc4.c     | 13 +++++-
 .../crypto/openssl/hash_provider/hash_evp.c   | 12 +++++
 src/lib/crypto/openssl/hmac.c                 |  6 ++-
 src/lib/krad/attr.c                           | 46 ++++++++++++++-----
 src/lib/krad/attrset.c                        | 12 +++--
 src/lib/krad/internal.h                       | 31 +++++++++++--
 src/lib/krad/packet.c                         | 23 ++++++----
 src/lib/krad/remote.c                         | 10 +++-
 src/lib/krad/t_attr.c                         |  3 +-
 src/lib/krad/t_attrset.c                      |  4 +-
 src/plugins/preauth/spake/spake_client.c      |  6 +++
 src/plugins/preauth/spake/spake_kdc.c         |  6 +++
 15 files changed, 164 insertions(+), 39 deletions(-)

diff --git a/doc/admin/conf_files/krb5_conf.rst b/doc/admin/conf_files/krb5_conf.rst
index e0c7a63309..603b902def 100644
--- a/doc/admin/conf_files/krb5_conf.rst
+++ b/doc/admin/conf_files/krb5_conf.rst
@@ -352,6 +352,12 @@ The libdefaults section may contain any of the following relations:
     qualification of shortnames, set this relation to the empty string
     with ``qualify_shortname = ""``.  (New in release 1.18.)
 
+**radius_md5_fips_override**
+    Downstream-only option to enable use of MD5 in RADIUS
+    communication (libkrad).  This allows for local (or protected
+    tunnel) communication with a RADIUS server that doesn't use krad
+    (e.g., freeradius) while in FIPS mode.
+
 **rdns**
     If this flag is true, reverse name lookup will be used in addition
     to forward name lookup to canonicalizing hostnames for use in
diff --git a/src/lib/crypto/krb/prng.c b/src/lib/crypto/krb/prng.c
index 4a6464558c..b058b75132 100644
--- a/src/lib/crypto/krb/prng.c
+++ b/src/lib/crypto/krb/prng.c
@@ -26,6 +26,9 @@
 
 #include "crypto_int.h"
 
+#include <openssl/evp.h>
+#include <openssl/rand.h>
+
 krb5_error_code KRB5_CALLCONV
 krb5_c_random_seed(krb5_context context, krb5_data *data)
 {
@@ -99,10 +102,22 @@ cleanup:
 static krb5_boolean
 get_os_entropy(unsigned char *buf, size_t len)
 {
-#if defined(HAVE_GETENTROPY)
     int r;
+#if defined(HAVE_GETENTROPY)
     size_t seg;
+#endif
 
+    /*
+     * In FIPS mode, use OpenSSL's FIPS-validated DRBG via RAND_bytes()
+     * instead of OS entropy sources.  This ensures all random number
+     * generation goes through the FIPS-approved mechanism.
+     */
+    if (EVP_default_properties_is_fips_enabled(NULL)) {
+        r = RAND_bytes(buf, len);
+        return r == 1;
+    }
+
+#if defined(HAVE_GETENTROPY)
     /* getentropy() has a maximum length of 256. */
     while (len > 0) {
         seg = (len > 256) ? 256 : len;
@@ -121,8 +136,6 @@ get_os_entropy(unsigned char *buf, size_t len)
      * is far in the past, along with the conditional include of
      * <sys/syscall.h> above.
      */
-    int r;
-
     while (len > 0) {
         /*
          * Pull from the /dev/urandom pool, but require it to have been seeded.
diff --git a/src/lib/crypto/openssl/enc_provider/camellia.c b/src/lib/crypto/openssl/enc_provider/camellia.c
index 01920e6ce1..20e45def61 100644
--- a/src/lib/crypto/openssl/enc_provider/camellia.c
+++ b/src/lib/crypto/openssl/enc_provider/camellia.c
@@ -387,6 +387,9 @@ krb5int_camellia_cbc_mac(krb5_key key, const krb5_crypto_iov *data,
     unsigned char blockY[CAMELLIA_BLOCK_SIZE], blockB[CAMELLIA_BLOCK_SIZE];
     struct iov_cursor cursor;
 
+    if (EVP_default_properties_is_fips_enabled(NULL))
+        return KRB5_CRYPTO_INTERNAL;
+
     if (output->length < CAMELLIA_BLOCK_SIZE)
         return KRB5_BAD_MSIZE;
 
@@ -418,6 +421,9 @@ static krb5_error_code
 krb5int_camellia_init_state (const krb5_keyblock *key, krb5_keyusage usage,
                              krb5_data *state)
 {
+    if (EVP_default_properties_is_fips_enabled(NULL))
+        return KRB5_CRYPTO_INTERNAL;
+
     state->length = 16;
     state->data = (void *) malloc(16);
     if (state->data == NULL)
diff --git a/src/lib/crypto/openssl/enc_provider/rc4.c b/src/lib/crypto/openssl/enc_provider/rc4.c
index 448d563348..028cd09ff0 100644
--- a/src/lib/crypto/openssl/enc_provider/rc4.c
+++ b/src/lib/crypto/openssl/enc_provider/rc4.c
@@ -69,6 +69,9 @@ k5_arcfour_docrypt(krb5_key key, const krb5_data *state, krb5_crypto_iov *data,
     EVP_CIPHER_CTX *ctx = NULL;
     struct arcfour_state *arcstate;
 
+    if (EVP_default_properties_is_fips_enabled(NULL))
+        return KRB5_CRYPTO_INTERNAL;
+
     arcstate = (state != NULL) ? (void *)state->data : NULL;
     if (arcstate != NULL) {
         ctx = arcstate->ctx;
@@ -116,7 +119,12 @@ k5_arcfour_docrypt(krb5_key key, const krb5_data *state, krb5_crypto_iov *data,
 static void
 k5_arcfour_free_state(krb5_data *state)
 {
-    struct arcfour_state *arcstate = (void *)state->data;
+    struct arcfour_state *arcstate;
+
+    if (EVP_default_properties_is_fips_enabled(NULL))
+        return;
+
+    arcstate = (void *) state->data;
 
     EVP_CIPHER_CTX_free(arcstate->ctx);
     free(arcstate);
@@ -128,6 +136,9 @@ k5_arcfour_init_state(const krb5_keyblock *key,
 {
     struct arcfour_state *arcstate;
 
+    if (EVP_default_properties_is_fips_enabled(NULL))
+        return KRB5_CRYPTO_INTERNAL;
+
     /*
      * The cipher state here is a saved pointer to a struct arcfour_state
      * object, rather than a flat byte array as in most enc providers.  The
diff --git a/src/lib/crypto/openssl/hash_provider/hash_evp.c b/src/lib/crypto/openssl/hash_provider/hash_evp.c
index f2fbffdb29..11659908bb 100644
--- a/src/lib/crypto/openssl/hash_provider/hash_evp.c
+++ b/src/lib/crypto/openssl/hash_provider/hash_evp.c
@@ -60,6 +60,11 @@ hash_evp(const EVP_MD *type, const krb5_crypto_iov *data, size_t num_data,
     if (ctx == NULL)
         return ENOMEM;
 
+    if (type == EVP_md4() || type == EVP_md5()) {
+        /* See comments below in hash_md4() and hash_md5(). */
+        EVP_MD_CTX_set_flags(ctx, EVP_MD_CTX_FLAG_NON_FIPS_ALLOW);
+    }
+
     ok = EVP_DigestInit_ex(ctx, type, NULL);
     for (i = 0; i < num_data; i++) {
         if (!SIGN_IOV(&data[i]))
@@ -78,6 +83,11 @@ hash_evp(const EVP_MD *type, const krb5_crypto_iov *data, size_t num_data,
 static krb5_error_code
 hash_md4(const krb5_crypto_iov *data, size_t num_data, krb5_data *output)
 {
+    /*
+     * MD4 is needed in FIPS mode to perform key generation for RC4 keys used
+     * by IPA.  These keys are only used along a (separately) secured channel
+     * for legacy reasons when performing trusts to Active Directory.
+     */
     return hash_evp(EVP_md4(), data, num_data, output);
 }
 
@@ -90,6 +100,8 @@ const struct krb5_hash_provider krb5int_hash_md4 = {
 static krb5_error_code
 hash_md5(const krb5_crypto_iov *data, size_t num_data, krb5_data *output)
 {
+    /* MD5 is needed in FIPS mode for communication with RADIUS servers.  This
+     * is gated in libkrad by libdefaults->radius_md5_fips_override. */
     return hash_evp(EVP_md5(), data, num_data, output);
 }
 
diff --git a/src/lib/crypto/openssl/hmac.c b/src/lib/crypto/openssl/hmac.c
index 799d7005ba..bfbbc53fd2 100644
--- a/src/lib/crypto/openssl/hmac.c
+++ b/src/lib/crypto/openssl/hmac.c
@@ -111,7 +111,11 @@ map_digest(const struct krb5_hash_provider *hash)
         return EVP_sha256();
     else if (hash == &krb5int_hash_sha384)
         return EVP_sha384();
-    else if (hash == &krb5int_hash_md5)
+
+    if (EVP_default_properties_is_fips_enabled(NULL))
+        return NULL;
+
+    if (hash == &krb5int_hash_md5)
         return EVP_md5();
     else if (hash == &krb5int_hash_md4)
         return EVP_md4();
diff --git a/src/lib/krad/attr.c b/src/lib/krad/attr.c
index 4ad32122a8..65ed1d35e7 100644
--- a/src/lib/krad/attr.c
+++ b/src/lib/krad/attr.c
@@ -38,7 +38,8 @@
 typedef krb5_error_code
 (*attribute_transform_fn)(krb5_context ctx, const char *secret,
                           const unsigned char *auth, const krb5_data *in,
-                          unsigned char outbuf[MAX_ATTRSIZE], size_t *outlen);
+                          unsigned char outbuf[MAX_ATTRSIZE], size_t *outlen,
+                          krb5_boolean *is_fips);
 
 typedef struct {
     const char *name;
@@ -51,12 +52,14 @@ typedef struct {
 static krb5_error_code
 user_password_encode(krb5_context ctx, const char *secret,
                      const unsigned char *auth, const krb5_data *in,
-                     unsigned char outbuf[MAX_ATTRSIZE], size_t *outlen);
+                     unsigned char outbuf[MAX_ATTRSIZE], size_t *outlen,
+                     krb5_boolean *is_fips);
 
 static krb5_error_code
 user_password_decode(krb5_context ctx, const char *secret,
                      const unsigned char *auth, const krb5_data *in,
-                     unsigned char outbuf[MAX_ATTRSIZE], size_t *outlen);
+                     unsigned char outbuf[MAX_ATTRSIZE], size_t *outlen,
+                     krb5_boolean *ignored);
 
 static const attribute_record attributes[UCHAR_MAX] = {
     {"User-Name", 1, MAX_ATTRSIZE, NULL, NULL},
@@ -145,7 +148,8 @@ static const attribute_record attributes[UCHAR_MAX] = {
 static krb5_error_code
 user_password_encode(krb5_context ctx, const char *secret,
                      const unsigned char *auth, const krb5_data *in,
-                     unsigned char outbuf[MAX_ATTRSIZE], size_t *outlen)
+                     unsigned char outbuf[MAX_ATTRSIZE], size_t *outlen,
+                     krb5_boolean *is_fips)
 {
     const unsigned char *indx;
     krb5_error_code retval;
@@ -171,8 +175,15 @@ user_password_encode(krb5_context ctx, const char *secret,
     for (blck = 0, indx = auth; blck * BLOCKSIZE < len; blck++) {
         memcpy(tmp.data + seclen, indx, BLOCKSIZE);
 
-        retval = krb5_c_make_checksum(ctx, CKSUMTYPE_RSA_MD5, NULL, 0, &tmp,
-                                      &sum);
+        if (kr_use_fips(ctx)) {
+            /* Skip encryption here.  Taint so that we won't pass it out of
+             * the machine by accident. */
+            *is_fips = TRUE;
+            sum.contents = calloc(1, BLOCKSIZE);
+        } else {
+            retval = krb5_c_make_checksum(ctx, CKSUMTYPE_RSA_MD5, NULL, 0, &tmp,
+                                          &sum);
+        }
         if (retval != 0) {
             zap(tmp.data, tmp.length);
             zap(outbuf, len);
@@ -197,7 +208,8 @@ user_password_encode(krb5_context ctx, const char *secret,
 static krb5_error_code
 user_password_decode(krb5_context ctx, const char *secret,
                      const unsigned char *auth, const krb5_data *in,
-                     unsigned char outbuf[MAX_ATTRSIZE], size_t *outlen)
+                     unsigned char outbuf[MAX_ATTRSIZE], size_t *outlen,
+                     krb5_boolean *is_fips)
 {
     const unsigned char *indx;
     krb5_error_code retval;
@@ -221,8 +233,15 @@ user_password_decode(krb5_context ctx, const char *secret,
     for (blck = 0, indx = auth; blck * BLOCKSIZE < in->length; blck++) {
         memcpy(tmp.data + seclen, indx, BLOCKSIZE);
 
-        retval = krb5_c_make_checksum(ctx, CKSUMTYPE_RSA_MD5, NULL, 0,
-                                      &tmp, &sum);
+        if (kr_use_fips(ctx)) {
+            /* Skip encryption here.  Taint so that we won't pass it out of
+             * the machine by accident. */
+            *is_fips = TRUE;
+            sum.contents = calloc(1, BLOCKSIZE);
+        } else {
+            retval = krb5_c_make_checksum(ctx, CKSUMTYPE_RSA_MD5, NULL, 0,
+                                          &tmp, &sum);
+        }
         if (retval != 0) {
             zap(tmp.data, tmp.length);
             zap(outbuf, in->length);
@@ -265,7 +284,7 @@ krb5_error_code
 kr_attr_encode(krb5_context ctx, const char *secret,
                const unsigned char *auth, krad_attr type,
                const krb5_data *in, unsigned char outbuf[MAX_ATTRSIZE],
-               size_t *outlen)
+               size_t *outlen, krb5_boolean *is_fips)
 {
     krb5_error_code retval;
 
@@ -282,7 +301,8 @@ kr_attr_encode(krb5_context ctx, const char *secret,
         return 0;
     }
 
-    return attributes[type - 1].encode(ctx, secret, auth, in, outbuf, outlen);
+    return attributes[type - 1].encode(ctx, secret, auth, in, outbuf, outlen,
+                                       is_fips);
 }
 
 krb5_error_code
@@ -291,6 +311,7 @@ kr_attr_decode(krb5_context ctx, const char *secret, const unsigned char *auth,
                unsigned char outbuf[MAX_ATTRSIZE], size_t *outlen)
 {
     krb5_error_code retval;
+    krb5_boolean ignored;
 
     retval = kr_attr_valid(type, in);
     if (retval != 0)
@@ -305,7 +326,8 @@ kr_attr_decode(krb5_context ctx, const char *secret, const unsigned char *auth,
         return 0;
     }
 
-    return attributes[type - 1].decode(ctx, secret, auth, in, outbuf, outlen);
+    return attributes[type - 1].decode(ctx, secret, auth, in, outbuf, outlen,
+                                       &ignored);
 }
 
 krad_attr
diff --git a/src/lib/krad/attrset.c b/src/lib/krad/attrset.c
index d52622ff94..6bccd52ac7 100644
--- a/src/lib/krad/attrset.c
+++ b/src/lib/krad/attrset.c
@@ -169,13 +169,14 @@ krad_attrset_copy(const krad_attrset *set, krad_attrset **copy)
 static krb5_error_code
 append_attr(krb5_context ctx, const char *secret,
             const uint8_t *auth, krad_attr type, const krb5_data *data,
-            uint8_t outbuf[MAX_ATTRSETSIZE], size_t *i)
+            uint8_t outbuf[MAX_ATTRSETSIZE], size_t *i, krb5_boolean *is_fips)
 {
     uint8_t buffer[MAX_ATTRSIZE];
     size_t attrlen;
     krb5_error_code retval;
 
-    retval = kr_attr_encode(ctx, secret, auth, type, data, buffer, &attrlen);
+    retval = kr_attr_encode(ctx, secret, auth, type, data, buffer, &attrlen,
+                            is_fips);
     if (retval)
         return retval;
 
@@ -193,7 +194,8 @@ append_attr(krb5_context ctx, const char *secret,
 krb5_error_code
 kr_attrset_encode(const krad_attrset *set, const char *secret,
                   const uint8_t *auth, krb5_boolean add_msgauth,
-                  unsigned char outbuf[MAX_ATTRSETSIZE], size_t *outlen)
+                  unsigned char outbuf[MAX_ATTRSETSIZE], size_t *outlen,
+                  krb5_boolean *is_fips)
 {
     krb5_error_code retval;
     const uint8_t zeroes[MD5_DIGEST_SIZE] = { 0 };
@@ -212,14 +214,14 @@ kr_attrset_encode(const krad_attrset *set, const char *secret,
         zerodata = make_data((uint8_t *)zeroes, MD5_DIGEST_SIZE);
         retval = append_attr(set->ctx, secret, auth,
                              KRAD_ATTR_MESSAGE_AUTHENTICATOR, &zerodata,
-                             outbuf, &i);
+                             outbuf, &i, is_fips);
         if (retval)
             return retval;
     }
 
     K5_TAILQ_FOREACH(a, &set->list, list) {
         retval = append_attr(set->ctx, secret, auth, a->type, &a->attr,
-                             outbuf, &i);
+                             outbuf, &i, is_fips);
         if (retval)
             return retval;
     }
diff --git a/src/lib/krad/internal.h b/src/lib/krad/internal.h
index e2a16c77a6..5c5418b209 100644
--- a/src/lib/krad/internal.h
+++ b/src/lib/krad/internal.h
@@ -39,6 +39,8 @@
 #include <sys/socket.h>
 #include <netdb.h>
 
+#include <openssl/evp.h>
+
 #ifndef UCHAR_MAX
 #define UCHAR_MAX 255
 #endif
@@ -51,6 +53,13 @@
 
 typedef struct krad_remote_st krad_remote;
 
+struct krad_packet_st {
+    char buffer[KRAD_PACKET_SIZE_MAX];
+    krad_attrset *attrset;
+    krb5_data pkt;
+    krb5_boolean is_fips;
+};
+
 /* Validate constraints of an attribute. */
 krb5_error_code
 kr_attr_valid(krad_attr type, const krb5_data *data);
@@ -59,7 +68,8 @@ kr_attr_valid(krad_attr type, const krb5_data *data);
 krb5_error_code
 kr_attr_encode(krb5_context ctx, const char *secret, const unsigned char *auth,
                krad_attr type, const krb5_data *in,
-               unsigned char outbuf[MAX_ATTRSIZE], size_t *outlen);
+               unsigned char outbuf[MAX_ATTRSIZE], size_t *outlen,
+               krb5_boolean *is_fips);
 
 /* Decode an attribute. */
 krb5_error_code
@@ -68,11 +78,13 @@ kr_attr_decode(krb5_context ctx, const char *secret, const unsigned char *auth,
                unsigned char outbuf[MAX_ATTRSIZE], size_t *outlen);
 
 /* Encode set into outbuf.  If add_msgauth is true, include a zeroed
- * Message-Authenticator as the first attribute. */
+ * Message-Authenticator as the first attribute.  If is_fips is non-NULL and
+ * FIPS mode is active, *is_fips will be set to TRUE if MD5 was skipped. */
 krb5_error_code
 kr_attrset_encode(const krad_attrset *set, const char *secret,
                   const uint8_t *auth, krb5_boolean add_msgauth,
-                  unsigned char outbuf[MAX_ATTRSETSIZE], size_t *outlen);
+                  unsigned char outbuf[MAX_ATTRSETSIZE], size_t *outlen,
+                  krb5_boolean *is_fips);
 
 /* Decode attributes from a buffer. */
 krb5_error_code
@@ -159,4 +171,17 @@ gai_error_code(int err)
     }
 }
 
+static inline krb5_boolean
+kr_use_fips(krb5_context ctx)
+{
+    int val = 0;
+
+    if (!EVP_default_properties_is_fips_enabled(NULL))
+        return 0;
+
+    (void)profile_get_boolean(ctx->profile, "libdefaults",
+                              "radius_md5_fips_override", NULL, 0, &val);
+    return !val;
+}
+
 #endif /* INTERNAL_H_ */
diff --git a/src/lib/krad/packet.c b/src/lib/krad/packet.c
index ae1f6df7df..7e4fd72203 100644
--- a/src/lib/krad/packet.c
+++ b/src/lib/krad/packet.c
@@ -54,12 +54,6 @@ typedef unsigned char uchar;
 #define pkt_auth(p) ((uchar *)offset(&(p)->pkt, OFFSET_AUTH))
 #define pkt_attr(p) ((unsigned char *)offset(&(p)->pkt, OFFSET_ATTR))
 
-struct krad_packet_st {
-    char buffer[KRAD_PACKET_SIZE_MAX];
-    krad_attrset *attrset;
-    krb5_data pkt;
-};
-
 typedef struct {
     uchar x[(UCHAR_MAX + 1) / 8];
 } idmap;
@@ -188,8 +182,14 @@ auth_generate_response(krb5_context ctx, const char *secret,
     memcpy(data.data + response->pkt.length, secret, strlen(secret));
 
     /* Hash it. */
-    retval = krb5_c_make_checksum(ctx, CKSUMTYPE_RSA_MD5, NULL, 0, &data,
-                                  &hash);
+    if (kr_use_fips(ctx)) {
+        /* This checksum does very little security-wise anyway, so don't
+         * taint. */
+        hash.contents = calloc(1, AUTH_FIELD_SIZE);
+    } else {
+        retval = krb5_c_make_checksum(ctx, CKSUMTYPE_RSA_MD5, NULL, 0, &data,
+                                      &hash);
+    }
     free(data.data);
     if (retval != 0)
         return retval;
@@ -376,7 +376,7 @@ krad_packet_new_request(krb5_context ctx, const char *secret, krad_code code,
 
     /* Encode the attributes. */
     retval = kr_attrset_encode(set, secret, pkt_auth(pkt), msgauth_required,
-                               pkt_attr(pkt), &attrset_len);
+                               pkt_attr(pkt), &attrset_len, &pkt->is_fips);
     if (retval != 0)
         goto error;
 
@@ -425,7 +425,8 @@ krad_packet_new_response(krb5_context ctx, const char *secret, krad_code code,
 
     /* Encode the attributes. */
     retval = kr_attrset_encode(set, secret, pkt_auth(request),
-                               msgauth_required, pkt_attr(pkt), &attrset_len);
+                               msgauth_required, pkt_attr(pkt), &attrset_len,
+                               &pkt->is_fips);
     if (retval != 0)
         goto error;
 
@@ -623,6 +624,8 @@ krad_packet_decode_response(krb5_context ctx, const char *secret,
 const krb5_data *
 krad_packet_encode(const krad_packet *pkt)
 {
+    if (pkt->is_fips)
+        return NULL;
     return &pkt->pkt;
 }
 
diff --git a/src/lib/krad/remote.c b/src/lib/krad/remote.c
index 28f2e83d0d..891404d5b7 100644
--- a/src/lib/krad/remote.c
+++ b/src/lib/krad/remote.c
@@ -263,7 +263,7 @@ on_io_write(krad_remote *rr)
     request *r;
 
     K5_TAILQ_FOREACH(r, &rr->list, list) {
-        tmp = krad_packet_encode(r->request);
+        tmp = &r->request->pkt;
 
         /* If the packet has already been sent, do nothing. */
         if (r->sent == tmp->length)
@@ -358,7 +358,7 @@ on_io_read(krad_remote *rr)
     if (req != NULL) {
         K5_TAILQ_FOREACH(r, &rr->list, list) {
             if (r->request == req &&
-                r->sent == krad_packet_encode(req)->length) {
+                r->sent == req->pkt.length) {
                 request_finish(r, 0, rsp);
                 break;
             }
@@ -459,6 +459,12 @@ kr_remote_send(krad_remote *rr, krad_code code, krad_attrset *attrs,
                                      iterator, &r, &tmp);
     if (retval != 0)
         goto error;
+    else if (tmp->is_fips && rr->info->ai_family != AF_LOCAL &&
+        rr->info->ai_family != AF_UNIX) {
+        /* This would expose cleartext passwords, so abort. */
+        retval = ESOCKTNOSUPPORT;
+        goto error;
+    }
 
     K5_TAILQ_FOREACH(r, &rr->list, list) {
         if (r->request == tmp) {
diff --git a/src/lib/krad/t_attr.c b/src/lib/krad/t_attr.c
index f8940862d6..a302f2a208 100644
--- a/src/lib/krad/t_attr.c
+++ b/src/lib/krad/t_attr.c
@@ -50,6 +50,7 @@ main(void)
     const char *tmp;
     krb5_data in;
     size_t len;
+    krb5_boolean is_fips = FALSE;
 
     noerror(krb5_init_context(&ctx));
 
@@ -71,7 +72,7 @@ main(void)
     /* Test encoding. */
     in = string2data((char *)decoded);
     retval = kr_attr_encode(ctx, secret, auth, KRAD_ATTR_USER_PASSWORD,
-                            &in, outbuf, &len);
+                            &in, outbuf, &len, &is_fips);
     insist(retval == 0);
     insist(len == sizeof(encoded));
     insist(memcmp(outbuf, encoded, len) == 0);
diff --git a/src/lib/krad/t_attrset.c b/src/lib/krad/t_attrset.c
index 17a281f15f..7e43078660 100644
--- a/src/lib/krad/t_attrset.c
+++ b/src/lib/krad/t_attrset.c
@@ -49,6 +49,7 @@ main(void)
     krb5_context ctx;
     size_t len = 0, encode_len;
     krb5_data tmp;
+    krb5_boolean is_fips = FALSE;
 
     noerror(krb5_init_context(&ctx));
     noerror(krad_attrset_new(ctx, &set));
@@ -62,7 +63,8 @@ main(void)
     noerror(krad_attrset_add(set, KRAD_ATTR_USER_PASSWORD, &tmp));
 
     /* Encode attrset. */
-    noerror(kr_attrset_encode(set, "foo", auth, FALSE, buffer, &encode_len));
+    noerror(kr_attrset_encode(set, "foo", auth, FALSE, buffer, &encode_len,
+                              &is_fips));
     krad_attrset_free(set);
 
     /* Manually encode User-Name. */
diff --git a/src/plugins/preauth/spake/spake_client.c b/src/plugins/preauth/spake/spake_client.c
index 00734a13b5..196e7112c9 100644
--- a/src/plugins/preauth/spake/spake_client.c
+++ b/src/plugins/preauth/spake/spake_client.c
@@ -38,6 +38,8 @@
 #include "groups.h"
 #include <krb5/clpreauth_plugin.h>
 
+#include <openssl/evp.h>
+
 typedef struct reqstate_st {
     krb5_pa_spake *msg;         /* set in prep_questions, used in process */
     krb5_keyblock *initial_key;
@@ -375,6 +377,10 @@ clpreauth_spake_initvt(krb5_context context, int maj_ver, int min_ver,
 
     if (maj_ver != 1)
         return KRB5_PLUGIN_VER_NOTSUPP;
+
+    if (EVP_default_properties_is_fips_enabled(NULL))
+        return KRB5_CRYPTO_INTERNAL;
+
     vt = (krb5_clpreauth_vtable)vtable;
     vt->name = "spake";
     vt->pa_type_list = pa_types;
diff --git a/src/plugins/preauth/spake/spake_kdc.c b/src/plugins/preauth/spake/spake_kdc.c
index 1a772d450f..32baaecbb8 100644
--- a/src/plugins/preauth/spake/spake_kdc.c
+++ b/src/plugins/preauth/spake/spake_kdc.c
@@ -41,6 +41,8 @@
 
 #include <krb5/kdcpreauth_plugin.h>
 
+#include <openssl/evp.h>
+
 /*
  * The SPAKE kdcpreauth module uses a secure cookie containing the following
  * concatenated fields (all integer fields are big-endian):
@@ -551,6 +553,10 @@ kdcpreauth_spake_initvt(krb5_context context, int maj_ver, int min_ver,
 
     if (maj_ver != 1)
         return KRB5_PLUGIN_VER_NOTSUPP;
+
+    if (EVP_default_properties_is_fips_enabled(NULL))
+        return KRB5_CRYPTO_INTERNAL;
+
     vt = (krb5_kdcpreauth_vtable)vtable;
     vt->name = "spake";
     vt->pa_type_list = pa_types;
-- 
2.53.0


From 1a4d6a7393887bf5372674942eea53030de0fed9 Mon Sep 17 00:00:00 2001
From: Julien Rische <jrische@redhat.com>
Date: Thu, 5 May 2022 17:15:12 +0200
Subject: [PATCH 02/21] FIPS: Allow krad UDP/TCP localhost connection

libkrad allows to establish connections only to UNIX socket in FIPS
mode, because MD5 digest is not considered safe enough to be used for
network communication. However, FreeRadius requires connection on TCP or
UDP ports.

This commit allows TCP or UDP connections in FIPS mode if destination is
localhost.

Resolves: rhbz#2082189
Last-updated: krb5-1.22.1
Forward-ported-by: Andreas Schneider <asn@redhat.com>
---
 src/lib/krad/remote.c | 35 +++++++++++++++++++++++++++++++++--
 1 file changed, 33 insertions(+), 2 deletions(-)

diff --git a/src/lib/krad/remote.c b/src/lib/krad/remote.c
index 891404d5b7..7654bab21b 100644
--- a/src/lib/krad/remote.c
+++ b/src/lib/krad/remote.c
@@ -33,6 +33,7 @@
 
 #include <string.h>
 #include <unistd.h>
+#include <stdbool.h>
 
 #include <sys/un.h>
 
@@ -74,6 +75,35 @@ on_io(verto_ctx *ctx, verto_ev *ev);
 static void
 on_timeout(verto_ctx *ctx, verto_ev *ev);
 
+static in_addr_t get_in_addr(struct addrinfo *info)
+{ return ((struct sockaddr_in *)(info->ai_addr))->sin_addr.s_addr; }
+
+static struct in6_addr *get_in6_addr(struct addrinfo *info)
+{ return &(((struct sockaddr_in6 *)(info->ai_addr))->sin6_addr); }
+
+static bool is_inet_localhost(struct addrinfo *info)
+{
+    struct addrinfo *p;
+
+    for (p = info; p; p = p->ai_next) {
+        switch (p->ai_family) {
+            case AF_INET:
+                if (IN_LOOPBACKNET != (get_in_addr(p) & IN_CLASSA_NET
+                                                      >> IN_CLASSA_NSHIFT))
+                    return false;
+                break;
+            case AF_INET6:
+                if (!IN6_IS_ADDR_LOOPBACK(get_in6_addr(p)))
+                    return false;
+                break;
+            default:
+                return false;
+        }
+    }
+
+    return true;
+}
+
 /* Iterate over the set of outstanding packets. */
 static const krad_packet *
 iterator(void *data, krb5_boolean cancel)
@@ -459,8 +489,9 @@ kr_remote_send(krad_remote *rr, krad_code code, krad_attrset *attrs,
                                      iterator, &r, &tmp);
     if (retval != 0)
         goto error;
-    else if (tmp->is_fips && rr->info->ai_family != AF_LOCAL &&
-        rr->info->ai_family != AF_UNIX) {
+    else if (tmp->is_fips && rr->info->ai_family != AF_LOCAL
+                          && rr->info->ai_family != AF_UNIX
+                          && !is_inet_localhost(rr->info)) {
         /* This would expose cleartext passwords, so abort. */
         retval = ESOCKTNOSUPPORT;
         goto error;
-- 
2.53.0


From 9b5aa1ecb9b49d684534bffbad39f08358f797e3 Mon Sep 17 00:00:00 2001
From: Julien Rische <jrische@redhat.com>
Date: Tue, 23 May 2023 12:19:54 +0200
Subject: [PATCH 03/21] FIPS: Make PKINIT CMS SHA-1 signature verification
 available

We recommend using the SHA1 crypto-module in order to allow the
verification of SHA-1 signature for CMS messages. However, this module
does not work in FIPS mode, because the SHA-1 algorithm is absent from
the OpenSSL FIPS provider.

This commit enables the signature verification process to fetch the
algorithm from a non-FIPS OpenSSL provider.

Support for SHA-1 CMS signature is still required, especially in order
to interoperate with Active Directory. At least it is until elliptic
curve cryptography is implemented for PKINIT in MIT krb5.
---
 src/plugins/preauth/pkinit/pkinit_crypto_openssl.c | 9 ++++++++-
 1 file changed, 8 insertions(+), 1 deletion(-)

diff --git a/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c b/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c
index f222dbdf92..1d99559485 100644
--- a/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c
+++ b/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c
@@ -1985,8 +1985,15 @@ cms_signeddata_verify(krb5_context context,
     if (oid == NULL)
         goto cleanup;
 
+    /* Do not use FIPS provider (even in FIPS mode) because it keeps from
+     * allowing SHA-1 signature verification using the SHA1 crypto-module
+     */
+    cms = CMS_ContentInfo_new_ex(NULL, "-fips");
+    if (!cms)
+        goto cleanup;
+
     /* decode received CMS message */
-    if ((cms = d2i_CMS_ContentInfo(NULL, &p, (int)signed_data_len)) == NULL) {
+    if (!d2i_CMS_ContentInfo(&cms, &p, (int)signed_data_len)) {
         retval = oerr(context, 0, _("Failed to decode CMS message"));
         goto cleanup;
     }
-- 
2.53.0


From c082c835672d41b9a68d1d3195fe0c44cb689fd7 Mon Sep 17 00:00:00 2001
From: Julien Rische <jrische@redhat.com>
Date: Thu, 19 Jan 2023 19:22:27 +0100
Subject: [PATCH 04/21] FIPS: Allow KRB5KDF, MD5, MD4 and HMAC-MD4/5

OpenSSL's restrictions to use KRB5KDF, MD5, and MD4 in FIPS mode are
bypassed in case AES SHA-1 HMAC or RC4 encryption types are allowed by
the crypto policy.

To ensure RC4 HMAC-MD5 was not used in FIPS mode, access to HMAC-MD4/5
was not allowed in this mode. However, since we provide the
"radius_md5_fips_override" configuration parameter to allow using RADIUS
regardless to the FIPS restrictions, we should allow HMAC-MD5 to be used
too in this case, because it is required for the newly supported
Message-Authenticator attribute.

A FIPS mode check is added in calculate_mac() which will fail if
"radius_md5_fips_override" is not true. It will not affect interactions
between krb5kdc and ipa-otpd, because the Message-Authenticator
attribute is not generated in this case.

Last-updated: krb5-1.22.1
Forward-ported-by: Andreas Schneider <asn@redhat.com>
---
 src/lib/crypto/krb/crypto_int.h               |   9 ++
 src/lib/crypto/openssl/Makefile.in            |   9 +-
 src/lib/crypto/openssl/common.c               | 105 ++++++++++++++++++
 .../crypto/openssl/hash_provider/hash_evp.c   |  45 ++++++--
 src/lib/crypto/openssl/hmac.c                 |  14 ++-
 src/lib/crypto/openssl/kdf.c                  |   2 +-
 src/lib/krad/packet.c                         |  19 ++--
 src/lib/krad/remote.c                         |   6 +-
 8 files changed, 180 insertions(+), 29 deletions(-)
 create mode 100644 src/lib/crypto/openssl/common.c

diff --git a/src/lib/crypto/krb/crypto_int.h b/src/lib/crypto/krb/crypto_int.h
index 3629616d96..0e6263bf15 100644
--- a/src/lib/crypto/krb/crypto_int.h
+++ b/src/lib/crypto/krb/crypto_int.h
@@ -36,6 +36,9 @@
 
 #include <openssl/opensslv.h>
 #if OPENSSL_VERSION_NUMBER >= 0x30000000L
+
+#include <openssl/provider.h>
+
 /*
  * OpenSSL 3.0 relegates MD4 and RC4 to the legacy provider, which must be
  * explicitly loaded into a library context.  Performing this loading within a
@@ -671,4 +674,10 @@ iov_cursor_advance(struct iov_cursor *c, size_t nblocks)
     c->out_pos += nblocks * c->block_size;
 }
 
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+
+krb5_error_code k5_get_ossl_legacy_libctx(OSSL_LIB_CTX **libctx);
+
+#endif /* OPENSSL_VERSION_NUMBER >= 0x30000000L */
+
 #endif /* CRYPTO_INT_H */
diff --git a/src/lib/crypto/openssl/Makefile.in b/src/lib/crypto/openssl/Makefile.in
index cf11f6847b..fe9ad8619a 100644
--- a/src/lib/crypto/openssl/Makefile.in
+++ b/src/lib/crypto/openssl/Makefile.in
@@ -8,21 +8,24 @@ STLIBOBJS=\
 	hmac.o	\
 	kdf.o	\
 	pbkdf2.o \
-	sha256.o
+	sha256.o \
+	common.o
 
 OBJS=\
 	$(OUTPRE)cmac.$(OBJEXT)	\
 	$(OUTPRE)hmac.$(OBJEXT)	\
 	$(OUTPRE)kdf.$(OBJEXT)	\
 	$(OUTPRE)pbkdf2.$(OBJEXT) \
-	$(OUTPRE)sha256.$(OBJEXT)
+	$(OUTPRE)sha256.$(OBJEXT) \
+	$(OUTPRE)common.$(OBJEXT)
 
 SRCS=\
 	$(srcdir)/cmac.c	\
 	$(srcdir)/hmac.c	\
 	$(srcdir)/kdf.c		\
 	$(srcdir)/pbkdf2.c	\
-	$(srcdir)/sha256.c
+	$(srcdir)/sha256.c	\
+	$(srcdir)/common.c
 
 SUBDIROBJLISTS= des/OBJS.ST md4/OBJS.ST 	\
 		md5/OBJS.ST sha1/OBJS.ST sha2/OBJS.ST 	\
diff --git a/src/lib/crypto/openssl/common.c b/src/lib/crypto/openssl/common.c
new file mode 100644
index 0000000000..144346c231
--- /dev/null
+++ b/src/lib/crypto/openssl/common.c
@@ -0,0 +1,105 @@
+/*
+ * OpenSSL 3.0 Legacy Provider Support
+ *
+ * OpenSSL 3.0 moved older cryptographic algorithms (MD4, MD5, RC4) to a
+ * separate "legacy provider" that must be explicitly loaded. These algorithms
+ * are considered deprecated but are still needed for backward compatibility:
+ *
+ *   - MD4/MD5: Used by older Kerberos encryption types and RADIUS
+ *   - RC4: Used by RC4-HMAC encryption type
+ *   - HMAC-MD5: Required for RADIUS Message-Authenticator attribute
+ *
+ * In FIPS mode, these algorithms are normally blocked. However, when the
+ * "radius_md5_fips_override" configuration option is enabled, we need to
+ * allow HMAC-MD5 for RADIUS compatibility. This module provides a shared
+ * OpenSSL library context with the legacy provider loaded, enabling access
+ * to these algorithms when explicitly required.
+ *
+ * The context is stored in thread-local storage to avoid concurrency issues.
+ */
+
+#include "crypto_int.h"
+
+#include <openssl/provider.h>
+#include <openssl/evp.h>
+#include <threads.h>
+#include <stdbool.h>
+
+/* Thread-local context holding the OpenSSL legacy provider state. */
+typedef struct ossl_legacy_context {
+    bool initialized;
+    OSSL_LIB_CTX *libctx;
+    OSSL_PROVIDER *default_provider;
+    OSSL_PROVIDER *legacy_provider;
+} ossl_legacy_context_t;
+
+static thread_local ossl_legacy_context_t g_ossl_legacy_ctx;
+
+/* Initialize an OpenSSL library context with both default and legacy providers. */
+static krb5_error_code
+init_ossl_legacy_ctx(ossl_legacy_context_t *ctx)
+{
+    ctx->libctx = OSSL_LIB_CTX_new();
+    if (!ctx->libctx)
+        return KRB5_CRYPTO_INTERNAL;
+
+    /* Load both legacy and default provider as both may be needed. */
+    ctx->default_provider = OSSL_PROVIDER_load(ctx->libctx, "default");
+    ctx->legacy_provider = OSSL_PROVIDER_load(ctx->libctx, "legacy");
+
+    if (!(ctx->default_provider && ctx->legacy_provider))
+        return KRB5_CRYPTO_INTERNAL;
+
+    ctx->initialized = true;
+    return 0;
+}
+
+static void
+deinit_ossl_legacy_ctx(ossl_legacy_context_t *ctx)
+{
+    if (ctx->legacy_provider)
+        OSSL_PROVIDER_unload(ctx->legacy_provider);
+
+    if (ctx->default_provider)
+        OSSL_PROVIDER_unload(ctx->default_provider);
+
+    if (ctx->libctx)
+        OSSL_LIB_CTX_free(ctx->libctx);
+
+    ctx->initialized = false;
+}
+
+/*
+ * Get an OpenSSL library context with the legacy provider loaded.
+ *
+ * In non-FIPS mode, returns NULL (use the default context).
+ * In FIPS mode, returns a dedicated context with the legacy provider,
+ * allowing access to deprecated algorithms like MD4/MD5 when explicitly needed.
+ */
+krb5_error_code
+k5_get_ossl_legacy_libctx(OSSL_LIB_CTX **libctx)
+{
+    krb5_error_code err;
+
+    if (!EVP_default_properties_is_fips_enabled(NULL)) {
+        if (libctx)
+            *libctx = NULL;
+        err = 0;
+        goto end;
+    }
+
+    if (!g_ossl_legacy_ctx.initialized) {
+        err = init_ossl_legacy_ctx(&g_ossl_legacy_ctx);
+        if (err) {
+            deinit_ossl_legacy_ctx(&g_ossl_legacy_ctx);
+            goto end;
+        }
+    }
+
+    if (libctx)
+        *libctx = g_ossl_legacy_ctx.libctx;
+    err = 0;
+
+end:
+    return err;
+}
diff --git a/src/lib/crypto/openssl/hash_provider/hash_evp.c b/src/lib/crypto/openssl/hash_provider/hash_evp.c
index 11659908bb..498967d07c 100644
--- a/src/lib/crypto/openssl/hash_provider/hash_evp.c
+++ b/src/lib/crypto/openssl/hash_provider/hash_evp.c
@@ -60,11 +60,6 @@ hash_evp(const EVP_MD *type, const krb5_crypto_iov *data, size_t num_data,
     if (ctx == NULL)
         return ENOMEM;
 
-    if (type == EVP_md4() || type == EVP_md5()) {
-        /* See comments below in hash_md4() and hash_md5(). */
-        EVP_MD_CTX_set_flags(ctx, EVP_MD_CTX_FLAG_NON_FIPS_ALLOW);
-    }
-
     ok = EVP_DigestInit_ex(ctx, type, NULL);
     for (i = 0; i < num_data; i++) {
         if (!SIGN_IOV(&data[i]))
@@ -77,6 +72,32 @@ hash_evp(const EVP_MD *type, const krb5_crypto_iov *data, size_t num_data,
     return ok ? 0 : KRB5_CRYPTO_INTERNAL;
 }
 
+static krb5_error_code
+hash_legacy_evp(const char *algo, const krb5_crypto_iov *data, size_t num_data,
+                krb5_data *output)
+{
+    krb5_error_code err;
+    OSSL_LIB_CTX *ossl_libctx;
+    EVP_MD *md = NULL;
+
+    err = k5_get_ossl_legacy_libctx(&ossl_libctx);
+    if (err)
+        goto end;
+
+    md = EVP_MD_fetch(ossl_libctx, algo, NULL);
+    if (!md) {
+        err = KRB5_CRYPTO_INTERNAL;
+        goto end;
+    }
+
+    err = hash_evp(md, data, num_data, output);
+
+end:
+    if (md)
+        EVP_MD_free(md);
+
+    return err;
+}
 #endif
 
 #ifdef K5_OPENSSL_MD4
@@ -88,7 +109,9 @@ hash_md4(const krb5_crypto_iov *data, size_t num_data, krb5_data *output)
      * by IPA.  These keys are only used along a (separately) secured channel
      * for legacy reasons when performing trusts to Active Directory.
      */
-    return hash_evp(EVP_md4(), data, num_data, output);
+    return EVP_default_properties_is_fips_enabled(NULL)
+        ? hash_legacy_evp("MD4", data, num_data, output)
+            : hash_evp(EVP_md4(), data, num_data, output);
 }
 
 const struct krb5_hash_provider krb5int_hash_md4 = {
@@ -100,9 +123,13 @@ const struct krb5_hash_provider krb5int_hash_md4 = {
 static krb5_error_code
 hash_md5(const krb5_crypto_iov *data, size_t num_data, krb5_data *output)
 {
-    /* MD5 is needed in FIPS mode for communication with RADIUS servers.  This
-     * is gated in libkrad by libdefaults->radius_md5_fips_override. */
-    return hash_evp(EVP_md5(), data, num_data, output);
+    /*
+     * MD5 is needed in FIPS mode for communication with RADIUS servers.  This
+     * is gated in libkrad by libdefaults->radius_md5_fips_override.
+     */
+    return EVP_default_properties_is_fips_enabled(NULL)
+        ? hash_legacy_evp("MD5", data, num_data, output)
+            : hash_evp(EVP_md5(), data, num_data, output);
 }
 
 const struct krb5_hash_provider krb5int_hash_md5 = {
diff --git a/src/lib/crypto/openssl/hmac.c b/src/lib/crypto/openssl/hmac.c
index bfbbc53fd2..945586a525 100644
--- a/src/lib/crypto/openssl/hmac.c
+++ b/src/lib/crypto/openssl/hmac.c
@@ -111,11 +111,7 @@ map_digest(const struct krb5_hash_provider *hash)
         return EVP_sha256();
     else if (hash == &krb5int_hash_sha384)
         return EVP_sha384();
-
-    if (EVP_default_properties_is_fips_enabled(NULL))
-        return NULL;
-
-    if (hash == &krb5int_hash_md5)
+    else if (hash == &krb5int_hash_md5)
         return EVP_md5();
     else if (hash == &krb5int_hash_md4)
         return EVP_md4();
@@ -137,13 +133,19 @@ krb5int_hmac_keyblock(const struct krb5_hash_provider *hash,
     EVP_MAC_CTX *ctx = NULL;
     OSSL_PARAM params[2], *p = params;
     size_t i = 0, md_len;
+    OSSL_LIB_CTX *ossl_libctx;
+    krb5_error_code err;
 
     if (md == NULL || keyblock->length > hash->blocksize)
         return KRB5_CRYPTO_INTERNAL;
     if (output->length < hash->hashsize)
         return KRB5_BAD_MSIZE;
 
-    mac = EVP_MAC_fetch(NULL, "HMAC", NULL);
+    err = k5_get_ossl_legacy_libctx(&ossl_libctx);
+    if (err)
+        return err;
+
+    mac = EVP_MAC_fetch(ossl_libctx, "HMAC", NULL);
     if (mac == NULL)
         return KRB5_CRYPTO_INTERNAL;
 
diff --git a/src/lib/crypto/openssl/kdf.c b/src/lib/crypto/openssl/kdf.c
index 41e845eae0..2713850997 100644
--- a/src/lib/crypto/openssl/kdf.c
+++ b/src/lib/crypto/openssl/kdf.c
@@ -200,7 +200,7 @@ k5_derive_random_rfc3961(const struct krb5_enc_provider *enc, krb5_key key,
         goto done;
     }
 
-    kdf = EVP_KDF_fetch(NULL, "KRB5KDF", NULL);
+    kdf = EVP_KDF_fetch(NULL, "KRB5KDF", "-fips");
     if (kdf == NULL) {
         ret = KRB5_CRYPTO_INTERNAL;
         goto done;
diff --git a/src/lib/krad/packet.c b/src/lib/krad/packet.c
index 7e4fd72203..a04b6b57f9 100644
--- a/src/lib/krad/packet.c
+++ b/src/lib/krad/packet.c
@@ -275,7 +275,7 @@ lookup_msgauth_addr(const krad_packet *pkt)
  * auth, which may be from pkt or from a corresponding request.
  */
 static krb5_error_code
-calculate_mac(const char *secret, const krad_packet *pkt,
+calculate_mac(krb5_context ctx, const char *secret, const krad_packet *pkt,
               const uint8_t auth[AUTH_FIELD_SIZE],
               uint8_t mac_out[MD5_DIGEST_SIZE])
 {
@@ -286,6 +286,10 @@ calculate_mac(const char *secret, const krad_packet *pkt,
         KRAD_ATTR_MESSAGE_AUTHENTICATOR, MSGAUTH_SIZE
     };
 
+    /* Do not use HMAC-MD5 if not explicitly allowed */
+    if (kr_use_fips(ctx))
+        return KRB5_CRYPTO_INTERNAL;
+
     msgauth_attr = lookup_msgauth_addr(pkt);
     if (msgauth_attr == NULL)
         return EINVAL;
@@ -387,7 +391,8 @@ krad_packet_new_request(krb5_context ctx, const char *secret, krad_code code,
 
     if (msgauth_required) {
         /* Calculate and set the Message-Authenticator MAC. */
-        retval = calculate_mac(secret, pkt, pkt_auth(pkt), pkt_attr(pkt) + 2);
+        retval = calculate_mac(ctx, secret, pkt, pkt_auth(pkt),
+                               pkt_attr(pkt) + 2);
         if (retval != 0)
             goto error;
     }
@@ -448,7 +453,7 @@ krad_packet_new_response(krb5_context ctx, const char *secret, krad_code code,
          * section 5.14, use the authenticator from the request, not from the
          * response.
          */
-        retval = calculate_mac(secret, pkt, pkt_auth(request),
+        retval = calculate_mac(ctx, secret, pkt, pkt_auth(request),
                                pkt_attr(pkt) + 2);
         if (retval != 0)
             goto error;
@@ -470,7 +475,7 @@ error:
 /* Verify the Message-Authenticator value in pkt, using the provided
  * authenticator (which may be from pkt or from a corresponding request). */
 static krb5_error_code
-verify_msgauth(const char *secret, const krad_packet *pkt,
+verify_msgauth(krb5_context ctx, const char *secret, const krad_packet *pkt,
                const uint8_t auth[AUTH_FIELD_SIZE])
 {
     uint8_t mac[MD5_DIGEST_SIZE];
@@ -481,7 +486,7 @@ verify_msgauth(const char *secret, const krad_packet *pkt,
     if (msgauth == NULL)
         return ENODATA;
 
-    retval = calculate_mac(secret, pkt, auth, mac);
+    retval = calculate_mac(ctx, secret, pkt, auth, mac);
     if (retval)
         return retval;
 
@@ -554,7 +559,7 @@ krad_packet_decode_request(krb5_context ctx, const char *secret,
 
     /* Verify Message-Authenticator if present. */
     if (has_pkt_msgauth(req)) {
-        retval = verify_msgauth(secret, req, pkt_auth(req));
+        retval = verify_msgauth(ctx, secret, req, pkt_auth(req));
         if (retval) {
             krad_packet_free(req);
             return retval;
@@ -606,7 +611,7 @@ krad_packet_decode_response(krb5_context ctx, const char *secret,
 
             /* Verify Message-Authenticator if present. */
             if (has_pkt_msgauth(*rsppkt)) {
-                if (verify_msgauth(secret, *rsppkt, pkt_auth(tmp)) != 0)
+                if (verify_msgauth(ctx, secret, *rsppkt, pkt_auth(tmp)) != 0)
                     continue;
             }
 
diff --git a/src/lib/krad/remote.c b/src/lib/krad/remote.c
index 7654bab21b..96da3c451d 100644
--- a/src/lib/krad/remote.c
+++ b/src/lib/krad/remote.c
@@ -76,10 +76,10 @@ static void
 on_timeout(verto_ctx *ctx, verto_ev *ev);
 
 static in_addr_t get_in_addr(struct addrinfo *info)
-{ return ((struct sockaddr_in *)(info->ai_addr))->sin_addr.s_addr; }
+{ return sa2sin(info->ai_addr)->sin_addr.s_addr; }
 
-static struct in6_addr *get_in6_addr(struct addrinfo *info)
-{ return &(((struct sockaddr_in6 *)(info->ai_addr))->sin6_addr); }
+static const struct in6_addr *get_in6_addr(struct addrinfo *info)
+{ return &sa2sin6(info->ai_addr)->sin6_addr; }
 
 static bool is_inet_localhost(struct addrinfo *info)
 {
-- 
2.53.0


From c64ff3431496d96f30ac1303be3a5aedf518cab1 Mon Sep 17 00:00:00 2001
From: Robbie Harwood <rharwood@redhat.com>
Date: Tue, 26 Mar 2019 18:51:10 -0400
Subject: [PATCH 05/21] 3DES: Remove support

Completely remove support for all DES3 enctypes (des3-cbc-raw,
des3-hmac-sha1, des3-cbc-sha1-kd).  Update all tests and documentation
to user other enctypes.  Mark the 3DES enctypes UNSUPPORTED and retain
their constants.

[antorres@redhat.com: remove diffs for:
     - src/kdamin/testing/proto/kdc.conf.proto
     - src/lib/kadm5/unit-test/api.current/chpass-principal-v2.exp
     - src/lib/kadm5/unit-test/api.current/get-principal-v2.exp
     - src/lib/kadm5/unit-test/api.current/randkey-principal-v2.exp
 since they were removed by Remove-TCL-based-libkadm5-API-tests.patch]
[jrische@redhat.com: restore supportedCMSTypes (not using 3DES any more):
    - src/plugins/preauth/pkinit/pkinit_crypto.h
    - src/plugins/preauth/pkinit/pkinit_crypto_openssl.c
    - src/plugins/preauth/pkinit/pkinit_clnt.c]

Last-updated: krb5-1.22.1-final
Forward-ported-by: Andreas Schneider <asn@redhat.com>
---
 README                                        |  13 +-
 doc/admin/advanced/retiring-des.rst           |  11 +
 doc/admin/conf_files/kdc_conf.rst             |   7 +-
 doc/admin/conf_files/krb5_conf.rst            |   6 -
 doc/admin/enctypes.rst                        |  21 +-
 doc/admin/troubleshoot.rst                    |   9 +-
 doc/appdev/refs/macros/index.rst              |   2 +-
 doc/conf.py                                   |   2 +-
 doc/mitK5features.rst                         |   7 +-
 src/Makefile.in                               |   4 +-
 src/configure.ac                              |   4 +-
 src/include/k5-int.h                          |   2 -
 src/include/krb5/krb5.hin                     |  10 +-
 src/kdc/kdc_util.c                            |   6 -
 src/lib/crypto/Makefile.in                    |   8 +-
 src/lib/crypto/builtin/Makefile.in            |   4 +-
 src/lib/crypto/builtin/des/Makefile.in        |  82 ----
 src/lib/crypto/builtin/des/d3_aead.c          | 137 -------
 src/lib/crypto/builtin/des/d3_kysched.c       |  55 ---
 src/lib/crypto/builtin/des/deps               | 146 -------
 src/lib/crypto/builtin/des/des_int.h          | 282 -------------
 src/lib/crypto/builtin/des/des_keys.c         |  38 --
 src/lib/crypto/builtin/des/destest.c          | 231 -----------
 src/lib/crypto/builtin/des/doc/libdes.doc     | 208 ----------
 src/lib/crypto/builtin/des/f_aead.c           | 177 --------
 src/lib/crypto/builtin/des/f_cbc.c            | 256 ------------
 src/lib/crypto/builtin/des/f_cksum.c          | 141 -------
 src/lib/crypto/builtin/des/f_parity.c         |  64 ---
 src/lib/crypto/builtin/des/f_sched.c          | 363 ----------------
 src/lib/crypto/builtin/des/f_tables.c         | 375 -----------------
 src/lib/crypto/builtin/des/f_tables.h         | 285 -------------
 src/lib/crypto/builtin/des/key_sched.c        |  66 ---
 src/lib/crypto/builtin/des/keytest.data       | 171 --------
 src/lib/crypto/builtin/des/t_verify.c         | 388 ------------------
 src/lib/crypto/builtin/des/weak_key.c         |  90 ----
 .../crypto/builtin/enc_provider/Makefile.in   |   5 +-
 src/lib/crypto/builtin/enc_provider/deps      |  11 -
 src/lib/crypto/builtin/enc_provider/des3.c    | 109 -----
 src/lib/crypto/crypto_tests/t_cf2.expected    |   1 -
 src/lib/crypto/crypto_tests/t_cf2.in          |   5 -
 src/lib/crypto/crypto_tests/t_cksums.c        |  10 -
 src/lib/crypto/crypto_tests/t_decrypt.c       |  57 ---
 src/lib/crypto/crypto_tests/t_derive.c        |  36 --
 src/lib/crypto/crypto_tests/t_encrypt.c       |   1 -
 src/lib/crypto/crypto_tests/t_short.c         |   1 -
 src/lib/crypto/crypto_tests/t_str2key.c       |  52 ---
 src/lib/crypto/crypto_tests/vectors.c         |   4 -
 src/lib/crypto/krb/Makefile.in                |   3 -
 src/lib/crypto/krb/cksumtypes.c               |   6 -
 src/lib/crypto/krb/crypto_int.h               |  11 -
 src/lib/crypto/krb/default_state.c            |  10 -
 src/lib/crypto/krb/enctype_util.c             |   3 +
 src/lib/crypto/krb/etypes.c                   |  21 -
 src/lib/crypto/krb/prf_des.c                  |  47 ---
 src/lib/crypto/krb/random_to_key.c            |  28 --
 src/lib/crypto/libk5crypto.exports            |   1 -
 src/lib/crypto/openssl/Makefile.in            |   4 +-
 src/lib/crypto/openssl/des/Makefile.in        |  20 -
 src/lib/crypto/openssl/des/deps               |  14 -
 src/lib/crypto/openssl/des/des_keys.c         |  39 --
 .../crypto/openssl/enc_provider/Makefile.in   |   3 -
 src/lib/crypto/openssl/enc_provider/deps      |  11 -
 src/lib/crypto/openssl/enc_provider/des3.c    | 188 ---------
 src/lib/crypto/openssl/kdf.c                  |   2 -
 src/lib/gssapi/krb5/accept_sec_context.c      |   1 -
 src/lib/gssapi/krb5/gssapiP_krb5.h            |   6 +-
 src/lib/gssapi/krb5/k5seal.c                  |  35 +-
 src/lib/gssapi/krb5/k5sealiov.c               |  27 +-
 src/lib/gssapi/krb5/k5unsealiov.c             |  38 +-
 src/lib/gssapi/krb5/unwrap.c                  |   6 +-
 src/lib/gssapi/krb5/util_crypt.c              |  18 +-
 src/lib/gssapi/krb5/verify_mic.c              |   2 +-
 src/lib/krb5/krb/init_ctx.c                   |   8 -
 src/lib/krb5/krb/s4u_creds.c                  |   2 -
 src/lib/krb5/krb/t_etypes.c                   |  48 +--
 src/lib/krb5/os/t_trace.c                     |   4 +-
 src/lib/krb5/os/t_trace.ref                   |   2 +-
 src/man/krb5.conf.man                         |   6 -
 src/plugins/preauth/pkinit/pkcs11.h           |   6 +-
 src/plugins/preauth/pkinit/pkinit_crypto.h    |  10 +-
 src/plugins/preauth/pkinit/pkinit_kdf_test.c  |  27 --
 src/plugins/preauth/spake/t_vectors.c         |  25 --
 src/tests/gssapi/t_enctypes.py                |  34 +-
 src/tests/gssapi/t_invalid.c                  |  26 --
 src/tests/gssapi/t_pcontok.c                  |  16 +-
 src/tests/gssapi/t_prf.c                      |   7 -
 src/tests/t_authdata.py                       |   2 +-
 src/tests/t_etype_info.py                     |  20 +-
 src/tests/t_keyrollover.py                    |   8 +-
 src/tests/t_mkey.py                           |  35 --
 src/tests/t_salt.py                           |   5 +-
 src/tests/t_sesskeynego.py                    |   8 -
 src/util/k5test.py                            |   7 -
 .../leash/htmlhelp/html/Encryption_Types.htm  |  13 -
 94 files changed, 133 insertions(+), 4693 deletions(-)
 delete mode 100644 src/lib/crypto/builtin/des/Makefile.in
 delete mode 100644 src/lib/crypto/builtin/des/d3_aead.c
 delete mode 100644 src/lib/crypto/builtin/des/d3_kysched.c
 delete mode 100644 src/lib/crypto/builtin/des/deps
 delete mode 100644 src/lib/crypto/builtin/des/des_int.h
 delete mode 100644 src/lib/crypto/builtin/des/des_keys.c
 delete mode 100644 src/lib/crypto/builtin/des/destest.c
 delete mode 100644 src/lib/crypto/builtin/des/doc/libdes.doc
 delete mode 100644 src/lib/crypto/builtin/des/f_aead.c
 delete mode 100644 src/lib/crypto/builtin/des/f_cbc.c
 delete mode 100644 src/lib/crypto/builtin/des/f_cksum.c
 delete mode 100644 src/lib/crypto/builtin/des/f_parity.c
 delete mode 100644 src/lib/crypto/builtin/des/f_sched.c
 delete mode 100644 src/lib/crypto/builtin/des/f_tables.c
 delete mode 100644 src/lib/crypto/builtin/des/f_tables.h
 delete mode 100644 src/lib/crypto/builtin/des/key_sched.c
 delete mode 100644 src/lib/crypto/builtin/des/keytest.data
 delete mode 100644 src/lib/crypto/builtin/des/t_verify.c
 delete mode 100644 src/lib/crypto/builtin/des/weak_key.c
 delete mode 100644 src/lib/crypto/builtin/enc_provider/des3.c
 delete mode 100644 src/lib/crypto/krb/prf_des.c
 delete mode 100644 src/lib/crypto/openssl/des/Makefile.in
 delete mode 100644 src/lib/crypto/openssl/des/deps
 delete mode 100644 src/lib/crypto/openssl/des/des_keys.c
 delete mode 100644 src/lib/crypto/openssl/enc_provider/des3.c

diff --git a/README b/README
index 73eafa585d..6dc3769373 100644
--- a/README
+++ b/README
@@ -81,11 +81,11 @@ Triple-DES and RC4 transitions
 ------------------------------
 
 Beginning with the krb5-1.21 release, the KDC will not issue tickets
-with triple-DES or RC4 session keys unless explicitly configured using
-the new allow_des3 and allow_rc4 variables in [libdefaults].  To
-facilitate the negotiation of session keys, the KDC will assume that
-all services can handle aes256-sha1 session keys unless the service
-principal has a session_enctypes string attribute.
+with RC4 session keys unless explicitly configured using the new
+allow_rc4 variable in [libdefaults].  To facilitate the negotiation of
+session keys, the KDC will assume that all services can handle
+aes256-sha1 session keys unless the service principal has a
+session_enctypes string attribute.
 
 Beginning with the krb5-1.19 release, a warning will be issued if
 initial credentials are acquired using the des3-cbc-sha1 encryption
@@ -172,6 +172,9 @@ Protocol evolution:
   certificates, ECDH key exchange, and the Microsoft paChecksum2
   field.
 
+* The KDC will no longer issue tickets with RC4 session keys unless
+  explicitly configured with the new allow_rc4 variable.
+
 * The IAKERB implementation has been changed to comply with the most
   recent draft standard and to support realm discovery.
 
diff --git a/doc/admin/advanced/retiring-des.rst b/doc/admin/advanced/retiring-des.rst
index 38f76d3f45..d5e3c30c04 100644
--- a/doc/admin/advanced/retiring-des.rst
+++ b/doc/admin/advanced/retiring-des.rst
@@ -10,6 +10,13 @@ ability have rendered DES vulnerable to brute force attacks on its 56-bit
 keyspace.  As such, it is now considered insecure and should not be
 used (:rfc:`6649`).
 
+In 1999, MIT krb5 added support for Triple-DES (3DES) encryption types.
+However, due to weakenings of DES and other security concerns, it is now also
+considered insecure and should not be used (:rfc:`8429`).  AES encryption
+types were added to MIT in 2003, meaning that the number of deployments with
+3DES as the strongest encryption type is hopefully small.  The rotation
+procedure described herein works for both DES and 3DES.
+
 History
 -------
 
@@ -27,6 +34,10 @@ and removed DES (single-DES) support in release 1.18.  As a
 consequence, a release prior to 1.18 is required to perform these
 migrations.
 
+3DES (a flagged deprecated encryption type) was also removed downstream by
+rharwood@redhat.com starting in 1.18; likewise, a pre-1.18 release is required
+to perform these migrations.
+
 Types of keys
 -------------
 
diff --git a/doc/admin/conf_files/kdc_conf.rst b/doc/admin/conf_files/kdc_conf.rst
index 63bdb8d48c..2e62e2acdd 100644
--- a/doc/admin/conf_files/kdc_conf.rst
+++ b/doc/admin/conf_files/kdc_conf.rst
@@ -859,8 +859,6 @@ Encryption types marked as "weak" and "deprecated" are available for
 compatibility but not recommended for use.
 
 ==================================================== =========================================================
-des3-cbc-raw                                         Triple DES cbc mode raw (weak)
-des3-cbc-sha1 des3-hmac-sha1 des3-cbc-sha1-kd        Triple DES cbc mode with HMAC/sha1 (deprecated)
 aes256-cts-hmac-sha1-96 aes256-cts aes256-sha1       AES-256 CTS mode with 96-bit SHA-1 HMAC
 aes128-cts-hmac-sha1-96 aes128-cts aes128-sha1       AES-128 CTS mode with 96-bit SHA-1 HMAC
 aes256-cts-hmac-sha384-192 aes256-sha2               AES-256 CTS mode with 192-bit SHA-384 HMAC
@@ -869,7 +867,6 @@ arcfour-hmac rc4-hmac arcfour-hmac-md5               RC4 with HMAC/MD5 (deprecat
 arcfour-hmac-exp rc4-hmac-exp arcfour-hmac-md5-exp   Exportable RC4 with HMAC/MD5 (weak)
 camellia256-cts-cmac camellia256-cts                 Camellia-256 CTS mode with CMAC
 camellia128-cts-cmac camellia128-cts                 Camellia-128 CTS mode with CMAC
-des3                                                 The triple DES family: des3-cbc-sha1
 aes                                                  The AES family: aes256-cts-hmac-sha1-96, aes128-cts-hmac-sha1-96, aes256-cts-hmac-sha384-192, and aes128-cts-hmac-sha256-128
 rc4                                                  The RC4 family: arcfour-hmac
 camellia                                             The Camellia family: camellia256-cts-cmac and camellia128-cts-cmac
@@ -881,8 +878,8 @@ from the current list by prefixing them with a minus sign ("-").
 Types or families can be prefixed with a plus sign ("+") for symmetry;
 it has the same meaning as just listing the type or family.  For
 example, "``DEFAULT -rc4``" would be the default set of encryption
-types with RC4 types removed, and "``des3 DEFAULT``" would be the
-default set of encryption types with triple DES types moved to the
+types with RC4 types removed, and "``aes128-sha2 DEFAULT``" would be
+the default set of encryption types with aes128-sha2 moved to the
 front.
 
 While **aes128-cts** and **aes256-cts** are supported for all Kerberos
diff --git a/doc/admin/conf_files/krb5_conf.rst b/doc/admin/conf_files/krb5_conf.rst
index 603b902def..160a8f1fd4 100644
--- a/doc/admin/conf_files/krb5_conf.rst
+++ b/doc/admin/conf_files/krb5_conf.rst
@@ -99,12 +99,6 @@ Additionally, krb5.conf may include any of the relations described in
 
 The libdefaults section may contain any of the following relations:
 
-**allow_des3**
-    Permit the KDC to issue tickets with des3-cbc-sha1 session keys.
-    In future releases, this flag will allow des3-cbc-sha1 to be used
-    at all.  The default value for this tag is false.  (Added in
-    release 1.21.)
-
 **allow_rc4**
     Permit the KDC to issue tickets with arcfour-hmac session keys.
     In future releases, this flag will allow arcfour-hmac to be used
diff --git a/doc/admin/enctypes.rst b/doc/admin/enctypes.rst
index dce19ad43e..6ce4638d5e 100644
--- a/doc/admin/enctypes.rst
+++ b/doc/admin/enctypes.rst
@@ -49,8 +49,8 @@ The KDC chooses the session key enctype by taking the intersection of
 its **permitted_enctypes** list, the list of long-term keys for the
 most recent kvno of the service, and the client's requested list of
 enctypes.  Starting in krb5-1.21, all services are assumed to support
-aes256-cts-hmac-sha1-96; also, des3-cbc-sha1 and arcfour-hmac session
-keys will not be issued by default.
+aes256-cts-hmac-sha1-96; also, arcfour-hmac session keys will not be
+issued by default.
 
 Starting in krb5-1.11, it is possible to set a string attribute on a
 service principal to control what session key enctypes the KDC may
@@ -90,13 +90,6 @@ affect how enctypes are chosen.
     acceptable risk for your environment and the weak enctypes are
     required for backward compatibility.
 
-**allow_des3**
-    was added in release 1.21 and defaults to *false*.  Unless this
-    flag is set to *true*, the KDC will not issue tickets with
-    des3-cbc-sha1 session keys.  In a future release, this flag will
-    control whether des3-cbc-sha1 is permitted in similar fashion to
-    weak enctypes.
-
 **allow_rc4**
     was added in release 1.21 and defaults to *false*.  Unless this
     flag is set to *true*, the KDC will not issue tickets with
@@ -146,7 +139,7 @@ enctype                    weak?      krb5     Windows
 des-cbc-crc                weak       <1.18    >=2000
 des-cbc-md4                weak       <1.18    ?
 des-cbc-md5                weak       <1.18    >=2000
-des3-cbc-sha1              deprecated >=1.1    none
+des3-cbc-sha1              deprecated <1.18    none
 arcfour-hmac               deprecated >=1.3    >=2000
 arcfour-hmac-exp           weak       >=1.3    >=2000
 aes128-cts-hmac-sha1-96               >=1.3    >=Vista
@@ -165,9 +158,11 @@ default.
 krb5 releases 1.17 and later flag deprecated encryption types
 (including ``des3-cbc-sha1`` and ``arcfour-hmac``) in KDC logs and
 kadmin output.  krb5 release 1.19 issues a warning during initial
-authentication if ``des3-cbc-sha1`` is used.  Future releases will
-disable ``des3-cbc-sha1`` by default and eventually remove support for
-it.
+authentication if ``des3-cbc-sha1`` is used.
+
+krb5 releases 1.18 and later remove single-DES and 3DES
+(downstream-only patch) enctype support.  Microsoft Windows never
+supported 3DES.
 
 
 Migrating away from older encryption types
diff --git a/doc/admin/troubleshoot.rst b/doc/admin/troubleshoot.rst
index ade5e1f87a..e4dc54f7e5 100644
--- a/doc/admin/troubleshoot.rst
+++ b/doc/admin/troubleshoot.rst
@@ -73,11 +73,10 @@ credential verification failed: KDC has no support for encryption type
 ......................................................................
 
 This most commonly happens when trying to use a principal with only
-DES keys, in a release (MIT krb5 1.7 or later) which disables DES by
-default.  DES encryption is considered weak due to its inadequate key
-size.  If you cannot migrate away from its use, you can re-enable DES
-by adding ``allow_weak_crypto = true`` to the :ref:`libdefaults`
-section of :ref:`krb5.conf(5)`.
+DES/3DES keys, in a release (MIT krb5 1.7 or later) which disables DES
+by default.  DES encryption is considered weak due to its inadequate
+key size and has been removed upstream; 3DES is not recommended, and
+has been removed downstream by rharwood@redhat.com.
 
 
 .. _err_cert_chain_cert_expired:
diff --git a/doc/appdev/refs/macros/index.rst b/doc/appdev/refs/macros/index.rst
index c1bda5c6c4..9f9b7e5233 100644
--- a/doc/appdev/refs/macros/index.rst
+++ b/doc/appdev/refs/macros/index.rst
@@ -39,7 +39,6 @@ Public
    CKSUMTYPE_HMAC_SHA1_96_AES256.rst
    CKSUMTYPE_HMAC_SHA256_128_AES128.rst
    CKSUMTYPE_HMAC_SHA384_192_AES256.rst
-   CKSUMTYPE_HMAC_SHA1_DES3.rst
    CKSUMTYPE_MD5_HMAC_ARCFOUR.rst
    CKSUMTYPE_NIST_SHA.rst
    CKSUMTYPE_RSA_MD4.rst
@@ -397,5 +396,6 @@ Deprecated macros
 .. toctree::
    :maxdepth: 1
 
+   CKSUMTYPE_HMAC_SHA1_DES3.rst
    krb524_convert_creds_kdc.rst
    krb524_init_ets.rst
diff --git a/doc/conf.py b/doc/conf.py
index 2fa3d8b358..16e0adb5e3 100644
--- a/doc/conf.py
+++ b/doc/conf.py
@@ -281,7 +281,7 @@ else:
     rst_epilog += '''
 .. |krb5conf| replace:: ``/etc/krb5.conf``
 .. |defkeysalts| replace:: ``aes256-cts-hmac-sha1-96:normal aes128-cts-hmac-sha1-96:normal``
-.. |defetypes| replace:: ``aes256-cts-hmac-sha1-96 aes128-cts-hmac-sha1-96 aes256-cts-hmac-sha384-192 aes128-cts-hmac-sha256-128 des3-cbc-sha1 arcfour-hmac-md5 camellia256-cts-cmac camellia128-cts-cmac``
+.. |defetypes| replace:: ``aes256-cts-hmac-sha1-96 aes128-cts-hmac-sha1-96 aes256-cts-hmac-sha384-192 aes128-cts-hmac-sha256-128 arcfour-hmac-md5 camellia256-cts-cmac camellia128-cts-cmac``
 .. |defmkey| replace:: ``aes256-cts-hmac-sha1-96``
 .. |copy| unicode:: U+000A9
 '''
diff --git a/doc/mitK5features.rst b/doc/mitK5features.rst
index e260e8e083..6f7ded76ff 100644
--- a/doc/mitK5features.rst
+++ b/doc/mitK5features.rst
@@ -37,7 +37,7 @@ Database backends: LDAP, DB2, LMDB
 
 krb4 support: Kerberos 5 release < 1.8
 
-DES support: Kerberos 5 release < 1.18 (See :ref:`retiring-des`)
+DES/3DES support: Kerberos 5 release < 1.18 (See :ref:`retiring-des`)
 
 Interoperability
 ----------------
@@ -659,9 +659,8 @@ Release 1.21
 
 * Protocol evolution:
 
-  - The KDC will no longer issue tickets with RC4 or triple-DES
-    session keys unless explicitly configured with the new allow_rc4
-    or allow_des3 variables respectively.
+  - The KDC will no longer issue tickets with RC4 session keys unless
+    explicitly configured with the new allow_rc4 variable.
 
   - The KDC will assume that all services can handle aes256-sha1
     session keys unless the service principal has a session_enctypes
diff --git a/src/Makefile.in b/src/Makefile.in
index 01fb060f73..f1ebde39b1 100644
--- a/src/Makefile.in
+++ b/src/Makefile.in
@@ -142,7 +142,7 @@ WINMAKEFILES=Makefile \
 	lib\Makefile lib\crypto\Makefile lib\crypto\krb\Makefile \
 	lib\crypto\builtin\Makefile lib\crypto\builtin\aes\Makefile \
 	lib\crypto\builtin\enc_provider\Makefile \
-	lib\crypto\builtin\des\Makefile lib\crypto\builtin\md5\Makefile \
+	lib\crypto\builtin\md5\Makefile \
 	lib\crypto\builtin\camellia\Makefile lib\crypto\builtin\md4\Makefile \
 	lib\crypto\builtin\hash_provider\Makefile \
 	lib\crypto\builtin\sha2\Makefile lib\crypto\builtin\sha1\Makefile \
@@ -214,8 +214,6 @@ WINMAKEFILES=Makefile \
 ##DOS##	$(WCONFIG) config < $@.in > $@
 ##DOS##lib\crypto\builtin\enc_provider\Makefile: lib\crypto\builtin\enc_provider\Makefile.in $(MKFDEP)
 ##DOS##	$(WCONFIG) config < $@.in > $@
-##DOS##lib\crypto\builtin\des\Makefile: lib\crypto\builtin\des\Makefile.in $(MKFDEP)
-##DOS##	$(WCONFIG) config < $@.in > $@
 ##DOS##lib\crypto\builtin\md5\Makefile: lib\crypto\builtin\md5\Makefile.in $(MKFDEP)
 ##DOS##	$(WCONFIG) config < $@.in > $@
 ##DOS##lib\crypto\builtin\camellia\Makefile: lib\crypto\builtin\camellia\Makefile.in $(MKFDEP)
diff --git a/src/configure.ac b/src/configure.ac
index 4325fae992..9fc569f195 100644
--- a/src/configure.ac
+++ b/src/configure.ac
@@ -1517,12 +1517,12 @@ V5_AC_OUTPUT_MAKEFILE(.
 	lib lib/kdb
 
 	lib/crypto lib/crypto/krb lib/crypto/crypto_tests
-	lib/crypto/builtin lib/crypto/builtin/des
+	lib/crypto/builtin
 	lib/crypto/builtin/aes lib/crypto/builtin/camellia
 	lib/crypto/builtin/md4 lib/crypto/builtin/md5
 	lib/crypto/builtin/sha1 lib/crypto/builtin/sha2
 	lib/crypto/builtin/enc_provider lib/crypto/builtin/hash_provider
-	lib/crypto/openssl lib/crypto/openssl/des
+	lib/crypto/openssl
 	lib/crypto/openssl/enc_provider lib/crypto/openssl/hash_provider
 
 	lib/krb5 lib/krb5/error_tables lib/krb5/asn.1 lib/krb5/ccache
diff --git a/src/include/k5-int.h b/src/include/k5-int.h
index cfd2cc9393..a430e4eec9 100644
--- a/src/include/k5-int.h
+++ b/src/include/k5-int.h
@@ -180,7 +180,6 @@ typedef unsigned char   u_char;
  * matches the variable name.  Keep these alphabetized. */
 #define KRB5_CONF_ACL_FILE                     "acl_file"
 #define KRB5_CONF_ADMIN_SERVER                 "admin_server"
-#define KRB5_CONF_ALLOW_DES3                   "allow_des3"
 #define KRB5_CONF_ALLOW_RC4                    "allow_rc4"
 #define KRB5_CONF_ALLOW_WEAK_CRYPTO            "allow_weak_crypto"
 #define KRB5_CONF_AUTH_TO_LOCAL                "auth_to_local"
@@ -1245,7 +1244,6 @@ struct _krb5_context {
     struct _kdb_log_context *kdblog_context;
 
     krb5_boolean allow_weak_crypto;
-    krb5_boolean allow_des3;
     krb5_boolean allow_rc4;
     krb5_boolean ignore_acceptor_hostname;
     krb5_boolean enforce_ok_as_delegate;
diff --git a/src/include/krb5/krb5.hin b/src/include/krb5/krb5.hin
index b5d295f331..81c3844605 100644
--- a/src/include/krb5/krb5.hin
+++ b/src/include/krb5/krb5.hin
@@ -425,8 +425,8 @@ typedef struct _krb5_crypto_iov {
 #define ENCTYPE_DES_CBC_MD4     0x0002  /**< @deprecated no longer supported */
 #define ENCTYPE_DES_CBC_MD5     0x0003  /**< @deprecated no longer supported */
 #define ENCTYPE_DES_CBC_RAW     0x0004  /**< @deprecated no longer supported */
-#define ENCTYPE_DES3_CBC_SHA    0x0005  /**< @deprecated DES-3 cbc with SHA1 */
-#define ENCTYPE_DES3_CBC_RAW    0x0006  /**< @deprecated DES-3 cbc mode raw */
+#define ENCTYPE_DES3_CBC_SHA    0x0005  /**< @deprecated no longer supported */
+#define ENCTYPE_DES3_CBC_RAW    0x0006  /**< @deprecated no longer supported */
 #define ENCTYPE_DES_HMAC_SHA1   0x0008  /**< @deprecated no longer supported */
 /* PKINIT */
 #define ENCTYPE_DSA_SHA1_CMS    0x0009  /**< DSA with SHA1, CMS signature */
@@ -435,9 +435,9 @@ typedef struct _krb5_crypto_iov {
 #define ENCTYPE_RC2_CBC_ENV     0x000c  /**< RC2 cbc mode, CMS enveloped data */
 #define ENCTYPE_RSA_ENV         0x000d  /**< RSA encryption, CMS enveloped data */
 #define ENCTYPE_RSA_ES_OAEP_ENV 0x000e  /**< RSA w/OEAP encryption, CMS enveloped data */
-#define ENCTYPE_DES3_CBC_ENV    0x000f  /**< DES-3 cbc mode, CMS enveloped data */
+#define ENCTYPE_DES3_CBC_ENV    0x000f  /**< @deprecated no longer supported */
 
-#define ENCTYPE_DES3_CBC_SHA1               0x0010
+#define ENCTYPE_DES3_CBC_SHA1               0x0010 /**< @deprecated removed */
 #define ENCTYPE_AES128_CTS_HMAC_SHA1_96     0x0011 /**< RFC 3962 */
 #define ENCTYPE_AES256_CTS_HMAC_SHA1_96     0x0012 /**< RFC 3962 */
 #define ENCTYPE_AES128_CTS_HMAC_SHA256_128  0x0013 /**< RFC 8009 */
@@ -462,7 +462,7 @@ typedef struct _krb5_crypto_iov {
 #define CKSUMTYPE_RSA_MD5       0x0007
 #define CKSUMTYPE_RSA_MD5_DES   0x0008
 #define CKSUMTYPE_NIST_SHA      0x0009
-#define CKSUMTYPE_HMAC_SHA1_DES3      0x000c
+#define CKSUMTYPE_HMAC_SHA1_DES3      0x000c /* @deprecated removed */
 #define CKSUMTYPE_SHA1          0x000e /**< RFC 3961 */
 #define CKSUMTYPE_HMAC_SHA1_96_AES128 0x000f /**< RFC 3962. Used with
                                                 ENCTYPE_AES128_CTS_HMAC_SHA1_96 */
diff --git a/src/kdc/kdc_util.c b/src/kdc/kdc_util.c
index 6f88afa2d7..89f34ca06e 100644
--- a/src/kdc/kdc_util.c
+++ b/src/kdc/kdc_util.c
@@ -1099,8 +1099,6 @@ select_session_keytype(krb5_context context, krb5_db_entry *server,
          * unless they are explicitly allowed.  In the future they will be more
          * comprehensively disabled and eventually removed.
          */
-        if (ktype[i] == ENCTYPE_DES3_CBC_SHA1 && !context->allow_des3)
-            continue;
         if (ktype[i] == ENCTYPE_ARCFOUR_HMAC && !context->allow_rc4)
             continue;
 
@@ -1170,8 +1168,6 @@ enctype_name(krb5_enctype ktype, char *buf, size_t buflen)
         name = "rsaEncryption-EnvOID";
     else if (ktype == ENCTYPE_RSA_ES_OAEP_ENV)
         name = "id-RSAES-OAEP-EnvOID";
-    else if (ktype == ENCTYPE_DES3_CBC_ENV)
-        name = "des-ede3-cbc-EnvOID";
     else
         return krb5_enctype_to_name(ktype, FALSE, buf, buflen);
 
@@ -1663,8 +1659,6 @@ krb5_boolean
 enctype_requires_etype_info_2(krb5_enctype enctype)
 {
     switch(enctype) {
-    case ENCTYPE_DES3_CBC_SHA1:
-    case ENCTYPE_DES3_CBC_RAW:
     case ENCTYPE_ARCFOUR_HMAC:
     case ENCTYPE_ARCFOUR_HMAC_EXP :
         return 0;
diff --git a/src/lib/crypto/Makefile.in b/src/lib/crypto/Makefile.in
index 10e8c74cf8..25c4f40cc3 100644
--- a/src/lib/crypto/Makefile.in
+++ b/src/lib/crypto/Makefile.in
@@ -10,12 +10,12 @@ LIBMINOR=1
 RELDIR=crypto
 
 STOBJLISTS=krb/OBJS.ST						\
-	builtin/OBJS.ST builtin/des/OBJS.ST			\
+	builtin/OBJS.ST						\
 	builtin/aes/OBJS.ST builtin/camellia/OBJS.ST		\
 	builtin/md4/OBJS.ST builtin/md5/OBJS.ST			\
 	builtin/sha1/OBJS.ST builtin/sha2/OBJS.ST		\
 	builtin/enc_provider/OBJS.ST builtin/hash_provider/OBJS.ST \
-	openssl/OBJS.ST openssl/des/OBJS.ST			\
+	openssl/OBJS.ST						\
 	openssl/enc_provider/OBJS.ST openssl/hash_provider/OBJS.ST
 
 SUBDIROBJLISTS=$(STOBJLISTS)
@@ -28,8 +28,8 @@ SHLIB_EXPDEPLIBS= $(SUPPORT_DEPLIB)
 SHLIB_LDFLAGS= $(LDFLAGS) @SHLIB_RPATH_DIRS@
 
 ##DOS##LIBNAME=$(OUTPRE)crypto.lib
-##DOS##OBJFILEDEP=$(OUTPRE)krb.lst $(OUTPRE)aes.lst $(OUTPRE)enc_provider.lst $(OUTPRE)des.lst $(OUTPRE)md5.lst $(OUTPRE)camellia.lst $(OUTPRE)md4.lst $(OUTPRE)hash_provider.lst $(OUTPRE)sha2.lst $(OUTPRE)sha1.lst $(OUTPRE)builtin.lst
-##DOS##OBJFILELIST=@$(OUTPRE)krb.lst @$(OUTPRE)aes.lst @$(OUTPRE)enc_provider.lst @$(OUTPRE)des.lst @$(OUTPRE)md5.lst @$(OUTPRE)camellia.lst @$(OUTPRE)md4.lst @$(OUTPRE)hash_provider.lst @$(OUTPRE)sha2.lst @$(OUTPRE)sha1.lst @$(OUTPRE)builtin.lst
+##DOS##OBJFILEDEP=$(OUTPRE)krb.lst $(OUTPRE)aes.lst $(OUTPRE)enc_provider.lst $(OUTPRE)md5.lst $(OUTPRE)camellia.lst $(OUTPRE)md4.lst $(OUTPRE)hash_provider.lst $(OUTPRE)sha2.lst $(OUTPRE)sha1.lst $(OUTPRE)builtin.lst
+##DOS##OBJFILELIST=@$(OUTPRE)krb.lst @$(OUTPRE)aes.lst @$(OUTPRE)enc_provider.lst @$(OUTPRE)md5.lst @$(OUTPRE)camellia.lst @$(OUTPRE)md4.lst @$(OUTPRE)hash_provider.lst @$(OUTPRE)sha2.lst @$(OUTPRE)sha1.lst @$(OUTPRE)builtin.lst
 
 all-unix: all-liblinks
 install-unix: install-libs
diff --git a/src/lib/crypto/builtin/Makefile.in b/src/lib/crypto/builtin/Makefile.in
index 243bb17ba3..30bfcd30c0 100644
--- a/src/lib/crypto/builtin/Makefile.in
+++ b/src/lib/crypto/builtin/Makefile.in
@@ -1,6 +1,6 @@
 mydir=lib$(S)crypto$(S)builtin
 BUILDTOP=$(REL)..$(S)..$(S)..
-SUBDIRS=camellia des aes md4 md5 sha1 sha2 enc_provider hash_provider
+SUBDIRS=camellia aes md4 md5 sha1 sha2 enc_provider hash_provider
 LOCALINCLUDES=-I$(srcdir)/../krb $(CRYPTO_IMPL_CFLAGS)
 
 ##DOS##BUILDTOP = ..\..\..
@@ -25,7 +25,7 @@ SRCS=\
 	$(srcdir)/kdf.c		\
 	$(srcdir)/pbkdf2.c	
 
-SUBDIROBJLISTS= des/OBJS.ST md4/OBJS.ST 	\
+SUBDIROBJLISTS= md4/OBJS.ST	 	\
 		md5/OBJS.ST sha1/OBJS.ST sha2/OBJS.ST 	\
 		enc_provider/OBJS.ST 		\
 		hash_provider/OBJS.ST 		\
diff --git a/src/lib/crypto/builtin/des/Makefile.in b/src/lib/crypto/builtin/des/Makefile.in
deleted file mode 100644
index 397ac87ed4..0000000000
--- a/src/lib/crypto/builtin/des/Makefile.in
+++ /dev/null
@@ -1,82 +0,0 @@
-mydir=lib$(S)crypto$(S)builtin$(S)des
-BUILDTOP=$(REL)..$(S)..$(S)..$(S)..
-LOCALINCLUDES=-I$(srcdir)/../../krb $(CRYPTO_IMPL_CFLAGS)
-
-##DOS##BUILDTOP = ..\..\..\..
-##DOS##PREFIXDIR = builtin\des
-##DOS##OBJFILE = ..\..\$(OUTPRE)des.lst
-
-STLIBOBJS=\
-	d3_aead.o	\
-	d3_kysched.o	\
-	des_keys.o	\
-	f_aead.o 	\
-	f_cksum.o	\
-	f_parity.o 	\
-	f_sched.o 	\
-	f_tables.o	\
-	key_sched.o	\
-	weak_key.o
-
-OBJS=	$(OUTPRE)d3_aead.$(OBJEXT)	\
-	$(OUTPRE)d3_kysched.$(OBJEXT)	\
-	$(OUTPRE)des_keys.$(OBJEXT)	\
-	$(OUTPRE)f_aead.$(OBJEXT) 	\
-	$(OUTPRE)f_cksum.$(OBJEXT)	\
-	$(OUTPRE)f_parity.$(OBJEXT) 	\
-	$(OUTPRE)f_sched.$(OBJEXT) 	\
-	$(OUTPRE)f_tables.$(OBJEXT)	\
-	$(OUTPRE)key_sched.$(OBJEXT)	\
-	$(OUTPRE)weak_key.$(OBJEXT)
-
-SRCS=	$(srcdir)/d3_aead.c	\
-	$(srcdir)/d3_kysched.c	\
-	$(srcdir)/des_keys.c	\
-	$(srcdir)/f_aead.c	\
-	$(srcdir)/f_cksum.c	\
-	$(srcdir)/f_parity.c	\
-	$(srcdir)/f_sched.c	\
-	$(srcdir)/f_tables.c	\
-	$(srcdir)/key_sched.c	\
-	$(srcdir)/weak_key.c
-
-EXTRADEPSRCS = $(srcdir)/destest.c $(srcdir)/f_cbc.c $(srcdir)/t_verify.c
-
-##DOS##LIBOBJS = $(OBJS)
-
-TOBJS = $(OUTPRE)key_sched.$(OBJEXT) $(OUTPRE)f_sched.$(OBJEXT) \
-	$(OUTPRE)f_cbc.$(OBJEXT) $(OUTPRE)f_tables.$(OBJEXT) \
-	$(OUTPRE)f_cksum.$(OBJEXT)
-
-verify$(EXEEXT): t_verify.$(OBJEXT) $(TOBJS) f_parity.$(OBJEXT) \
-	$(COM_ERR_DEPLIB) $(SUPPORT_DEPLIB)
-	$(CC_LINK) -o $@ t_verify.$(OBJEXT) $(TOBJS) f_parity.$(OBJEXT) \
-		$(COM_ERR_LIB) $(SUPPORT_LIB)
-
-destest$(EXEEXT): destest.$(OBJEXT) $(TOBJS) $(SUPPORT_DEPLIB)
-	$(CC_LINK) -o $@ destest.$(OBJEXT) $(TOBJS) $(SUPPORT_LIB)
-
-all-unix: all-libobjs
-
-check-unix: check-unix-@CRYPTO_BUILTIN_TESTS@
-check-unix-no:
-check-unix-yes: verify destest
-	$(RUN_TEST) ./verify -z
-	$(RUN_TEST) ./verify -m
-	$(RUN_TEST) ./verify
-	$(RUN_TEST) ./destest < $(srcdir)/keytest.data
-
-includes: depend
-
-depend: $(SRCS)
-
-check-windows:
-
-clean:
-	$(RM) destest.$(OBJEXT) destest$(EXEEXT) verify$(EXEEXT) \
-	t_verify.$(OBJEXT) $(TOBJS)
-
-clean-unix:: clean-libobjs
-
-@libobj_frag@
-
diff --git a/src/lib/crypto/builtin/des/d3_aead.c b/src/lib/crypto/builtin/des/d3_aead.c
deleted file mode 100644
index fb83f73b43..0000000000
--- a/src/lib/crypto/builtin/des/d3_aead.c
+++ /dev/null
@@ -1,137 +0,0 @@
-/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
-/*
- * Copyright (C) 2008 by the Massachusetts Institute of Technology.
- * Copyright 1995 by Richard P. Basch.  All Rights Reserved.
- * Copyright 1995 by Lehman Brothers, Inc.  All Rights Reserved.
- *
- * Export of this software from the United States of America may
- *   require a specific license from the United States Government.
- *   It is the responsibility of any person or organization contemplating
- *   export to obtain such a license before exporting.
- *
- * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
- * distribute this software and its documentation for any purpose and
- * without fee is hereby granted, provided that the above copyright
- * notice appear in all copies and that both that copyright notice and
- * this permission notice appear in supporting documentation, and that
- * the name of Richard P. Basch, Lehman Brothers and M.I.T. not be used
- * in advertising or publicity pertaining to distribution of the software
- * without specific, written prior permission.  Richard P. Basch,
- * Lehman Brothers and M.I.T. make no representations about the suitability
- * of this software for any purpose.  It is provided "as is" without
- * express or implied warranty.
- */
-
-#include "crypto_int.h"
-#include "des_int.h"
-#include "f_tables.h"
-
-#ifdef K5_BUILTIN_DES
-
-void
-krb5int_des3_cbc_encrypt(krb5_crypto_iov *data, unsigned long num_data,
-                         const mit_des_key_schedule ks1,
-                         const mit_des_key_schedule ks2,
-                         const mit_des_key_schedule ks3,
-                         mit_des_cblock ivec)
-{
-    unsigned DES_INT32 left, right;
-    const unsigned DES_INT32 *kp1, *kp2, *kp3;
-    const unsigned char *ip;
-    struct iov_cursor cursor;
-    unsigned char block[MIT_DES_BLOCK_LENGTH];
-
-    /* Get key pointers here.  These won't need to be reinitialized. */
-    kp1 = (const unsigned DES_INT32 *)ks1;
-    kp2 = (const unsigned DES_INT32 *)ks2;
-    kp3 = (const unsigned DES_INT32 *)ks3;
-
-    /* Initialize left and right with the contents of the initial vector. */
-    ip = (ivec != NULL) ? ivec : mit_des_zeroblock;
-    left = load_32_be(ip);
-    right = load_32_be(ip + 4);
-
-    k5_iov_cursor_init(&cursor, data, num_data, MIT_DES_BLOCK_LENGTH, FALSE);
-    while (k5_iov_cursor_get(&cursor, block)) {
-        /* xor this block with the previous ciphertext. */
-        left ^= load_32_be(block);
-        right ^= load_32_be(block + 4);
-
-        /* Encrypt what we have and store it back into block. */
-        DES_DO_ENCRYPT(left, right, kp1);
-        DES_DO_DECRYPT(left, right, kp2);
-        DES_DO_ENCRYPT(left, right, kp3);
-        store_32_be(left, block);
-        store_32_be(right, block + 4);
-
-        k5_iov_cursor_put(&cursor, block);
-    }
-
-    if (ivec != NULL) {
-        store_32_be(left, ivec);
-        store_32_be(right, ivec + 4);
-    }
-}
-
-void
-krb5int_des3_cbc_decrypt(krb5_crypto_iov *data, unsigned long num_data,
-                         const mit_des_key_schedule ks1,
-                         const mit_des_key_schedule ks2,
-                         const mit_des_key_schedule ks3,
-                         mit_des_cblock ivec)
-{
-    unsigned DES_INT32 left, right;
-    const unsigned DES_INT32 *kp1, *kp2, *kp3;
-    const unsigned char *ip;
-    unsigned DES_INT32 ocipherl, ocipherr;
-    unsigned DES_INT32 cipherl, cipherr;
-    struct iov_cursor cursor;
-    unsigned char block[MIT_DES_BLOCK_LENGTH];
-
-    /* Get key pointers here.  These won't need to be reinitialized. */
-    kp1 = (const unsigned DES_INT32 *)ks1;
-    kp2 = (const unsigned DES_INT32 *)ks2;
-    kp3 = (const unsigned DES_INT32 *)ks3;
-
-    /*
-     * Decrypting is harder than encrypting because of
-     * the necessity of remembering a lot more things.
-     * Should think about this a little more...
-     */
-
-    /* Prime the old cipher with ivec.*/
-    ip = (ivec != NULL) ? ivec : mit_des_zeroblock;
-    ocipherl = load_32_be(ip);
-    ocipherr = load_32_be(ip + 4);
-
-    k5_iov_cursor_init(&cursor, data, num_data, MIT_DES_BLOCK_LENGTH, FALSE);
-    while (k5_iov_cursor_get(&cursor, block)) {
-        /* Split this block into left and right. */
-        cipherl = left = load_32_be(block);
-        cipherr = right = load_32_be(block + 4);
-
-        /* Decrypt and xor with the old cipher to get plain text. */
-        DES_DO_DECRYPT(left, right, kp3);
-        DES_DO_ENCRYPT(left, right, kp2);
-        DES_DO_DECRYPT(left, right, kp1);
-        left ^= ocipherl;
-        right ^= ocipherr;
-
-        /* Store the encrypted halves back into block. */
-        store_32_be(left, block);
-        store_32_be(right, block + 4);
-
-        /* Save current cipher block halves. */
-        ocipherl = cipherl;
-        ocipherr = cipherr;
-
-        k5_iov_cursor_put(&cursor, block);
-    }
-
-    if (ivec != NULL) {
-        store_32_be(ocipherl, ivec);
-        store_32_be(ocipherr, ivec + 4);
-    }
-}
-
-#endif /* K5_BUILTIN_DES */
diff --git a/src/lib/crypto/builtin/des/d3_kysched.c b/src/lib/crypto/builtin/des/d3_kysched.c
deleted file mode 100644
index 55fb9449b5..0000000000
--- a/src/lib/crypto/builtin/des/d3_kysched.c
+++ /dev/null
@@ -1,55 +0,0 @@
-/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
-/*
- * Copyright 1995 by Richard P. Basch.  All Rights Reserved.
- * Copyright 1995 by Lehman Brothers, Inc.  All Rights Reserved.
- *
- * Export of this software from the United States of America may
- *   require a specific license from the United States Government.
- *   It is the responsibility of any person or organization contemplating
- *   export to obtain such a license before exporting.
- *
- * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
- * distribute this software and its documentation for any purpose and
- * without fee is hereby granted, provided that the above copyright
- * notice appear in all copies and that both that copyright notice and
- * this permission notice appear in supporting documentation, and that
- * the name of Richard P. Basch, Lehman Brothers and M.I.T. not be used
- * in advertising or publicity pertaining to distribution of the software
- * without specific, written prior permission.  Richard P. Basch,
- * Lehman Brothers and M.I.T. make no representations about the suitability
- * of this software for any purpose.  It is provided "as is" without
- * express or implied warranty.
- */
-
-#include "crypto_int.h"
-#include "des_int.h"
-
-#ifdef K5_BUILTIN_DES
-
-int
-mit_des3_key_sched(mit_des3_cblock k, mit_des3_key_schedule schedule)
-{
-    mit_des_make_key_sched(k[0],schedule[0]);
-    mit_des_make_key_sched(k[1],schedule[1]);
-    mit_des_make_key_sched(k[2],schedule[2]);
-
-    if (!mit_des_check_key_parity(k[0]))        /* bad parity --> return -1 */
-        return(-1);
-    if (mit_des_is_weak_key(k[0]))
-        return(-2);
-
-    if (!mit_des_check_key_parity(k[1]))
-        return(-1);
-    if (mit_des_is_weak_key(k[1]))
-        return(-2);
-
-    if (!mit_des_check_key_parity(k[2]))
-        return(-1);
-    if (mit_des_is_weak_key(k[2]))
-        return(-2);
-
-    /* if key was good, return 0 */
-    return 0;
-}
-
-#endif /* K5_BUILTIN_DES */
diff --git a/src/lib/crypto/builtin/des/deps b/src/lib/crypto/builtin/des/deps
deleted file mode 100644
index 1c1239d696..0000000000
--- a/src/lib/crypto/builtin/des/deps
+++ /dev/null
@@ -1,146 +0,0 @@
-#
-# Generated makefile dependencies follow.
-#
-d3_aead.so d3_aead.po $(OUTPRE)d3_aead.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \
-  $(BUILDTOP)/include/krb5/krb5.h $(BUILDTOP)/include/osconf.h \
-  $(BUILDTOP)/include/profile.h $(COM_ERR_DEPS) $(srcdir)/../../krb/crypto_int.h \
-  $(top_srcdir)/include/k5-buf.h $(top_srcdir)/include/k5-err.h \
-  $(top_srcdir)/include/k5-gmt_mktime.h $(top_srcdir)/include/k5-int-pkinit.h \
-  $(top_srcdir)/include/k5-int.h $(top_srcdir)/include/k5-platform.h \
-  $(top_srcdir)/include/k5-plugin.h $(top_srcdir)/include/k5-thread.h \
-  $(top_srcdir)/include/k5-trace.h $(top_srcdir)/include/krb5.h \
-  $(top_srcdir)/include/krb5/authdata_plugin.h $(top_srcdir)/include/krb5/plugin.h \
-  $(top_srcdir)/include/port-sockets.h $(top_srcdir)/include/socket-utils.h \
-  d3_aead.c des_int.h f_tables.h
-d3_kysched.so d3_kysched.po $(OUTPRE)d3_kysched.$(OBJEXT): \
-  $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/krb5/krb5.h \
-  $(BUILDTOP)/include/osconf.h $(BUILDTOP)/include/profile.h \
-  $(COM_ERR_DEPS) $(srcdir)/../../krb/crypto_int.h $(top_srcdir)/include/k5-buf.h \
-  $(top_srcdir)/include/k5-err.h $(top_srcdir)/include/k5-gmt_mktime.h \
-  $(top_srcdir)/include/k5-int-pkinit.h $(top_srcdir)/include/k5-int.h \
-  $(top_srcdir)/include/k5-platform.h $(top_srcdir)/include/k5-plugin.h \
-  $(top_srcdir)/include/k5-thread.h $(top_srcdir)/include/k5-trace.h \
-  $(top_srcdir)/include/krb5.h $(top_srcdir)/include/krb5/authdata_plugin.h \
-  $(top_srcdir)/include/krb5/plugin.h $(top_srcdir)/include/port-sockets.h \
-  $(top_srcdir)/include/socket-utils.h d3_kysched.c des_int.h
-des_keys.so des_keys.po $(OUTPRE)des_keys.$(OBJEXT): \
-  $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/krb5/krb5.h \
-  $(BUILDTOP)/include/osconf.h $(BUILDTOP)/include/profile.h \
-  $(COM_ERR_DEPS) $(srcdir)/../../krb/crypto_int.h $(top_srcdir)/include/k5-buf.h \
-  $(top_srcdir)/include/k5-err.h $(top_srcdir)/include/k5-gmt_mktime.h \
-  $(top_srcdir)/include/k5-int-pkinit.h $(top_srcdir)/include/k5-int.h \
-  $(top_srcdir)/include/k5-platform.h $(top_srcdir)/include/k5-plugin.h \
-  $(top_srcdir)/include/k5-thread.h $(top_srcdir)/include/k5-trace.h \
-  $(top_srcdir)/include/krb5.h $(top_srcdir)/include/krb5/authdata_plugin.h \
-  $(top_srcdir)/include/krb5/plugin.h $(top_srcdir)/include/port-sockets.h \
-  $(top_srcdir)/include/socket-utils.h des_int.h des_keys.c
-f_aead.so f_aead.po $(OUTPRE)f_aead.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \
-  $(BUILDTOP)/include/krb5/krb5.h $(BUILDTOP)/include/osconf.h \
-  $(BUILDTOP)/include/profile.h $(COM_ERR_DEPS) $(srcdir)/../../krb/crypto_int.h \
-  $(top_srcdir)/include/k5-buf.h $(top_srcdir)/include/k5-err.h \
-  $(top_srcdir)/include/k5-gmt_mktime.h $(top_srcdir)/include/k5-int-pkinit.h \
-  $(top_srcdir)/include/k5-int.h $(top_srcdir)/include/k5-platform.h \
-  $(top_srcdir)/include/k5-plugin.h $(top_srcdir)/include/k5-thread.h \
-  $(top_srcdir)/include/k5-trace.h $(top_srcdir)/include/krb5.h \
-  $(top_srcdir)/include/krb5/authdata_plugin.h $(top_srcdir)/include/krb5/plugin.h \
-  $(top_srcdir)/include/port-sockets.h $(top_srcdir)/include/socket-utils.h \
-  des_int.h f_aead.c f_tables.h
-f_cksum.so f_cksum.po $(OUTPRE)f_cksum.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \
-  $(BUILDTOP)/include/krb5/krb5.h $(BUILDTOP)/include/osconf.h \
-  $(BUILDTOP)/include/profile.h $(COM_ERR_DEPS) $(srcdir)/../../krb/crypto_int.h \
-  $(top_srcdir)/include/k5-buf.h $(top_srcdir)/include/k5-err.h \
-  $(top_srcdir)/include/k5-gmt_mktime.h $(top_srcdir)/include/k5-int-pkinit.h \
-  $(top_srcdir)/include/k5-int.h $(top_srcdir)/include/k5-platform.h \
-  $(top_srcdir)/include/k5-plugin.h $(top_srcdir)/include/k5-thread.h \
-  $(top_srcdir)/include/k5-trace.h $(top_srcdir)/include/krb5.h \
-  $(top_srcdir)/include/krb5/authdata_plugin.h $(top_srcdir)/include/krb5/plugin.h \
-  $(top_srcdir)/include/port-sockets.h $(top_srcdir)/include/socket-utils.h \
-  des_int.h f_cksum.c f_tables.h
-f_parity.so f_parity.po $(OUTPRE)f_parity.$(OBJEXT): \
-  $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/krb5/krb5.h \
-  $(BUILDTOP)/include/osconf.h $(BUILDTOP)/include/profile.h \
-  $(COM_ERR_DEPS) $(srcdir)/../../krb/crypto_int.h $(top_srcdir)/include/k5-buf.h \
-  $(top_srcdir)/include/k5-err.h $(top_srcdir)/include/k5-gmt_mktime.h \
-  $(top_srcdir)/include/k5-int-pkinit.h $(top_srcdir)/include/k5-int.h \
-  $(top_srcdir)/include/k5-platform.h $(top_srcdir)/include/k5-plugin.h \
-  $(top_srcdir)/include/k5-thread.h $(top_srcdir)/include/k5-trace.h \
-  $(top_srcdir)/include/krb5.h $(top_srcdir)/include/krb5/authdata_plugin.h \
-  $(top_srcdir)/include/krb5/plugin.h $(top_srcdir)/include/port-sockets.h \
-  $(top_srcdir)/include/socket-utils.h des_int.h f_parity.c
-f_sched.so f_sched.po $(OUTPRE)f_sched.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \
-  $(BUILDTOP)/include/krb5/krb5.h $(BUILDTOP)/include/osconf.h \
-  $(BUILDTOP)/include/profile.h $(COM_ERR_DEPS) $(srcdir)/../../krb/crypto_int.h \
-  $(top_srcdir)/include/k5-buf.h $(top_srcdir)/include/k5-err.h \
-  $(top_srcdir)/include/k5-gmt_mktime.h $(top_srcdir)/include/k5-int-pkinit.h \
-  $(top_srcdir)/include/k5-int.h $(top_srcdir)/include/k5-platform.h \
-  $(top_srcdir)/include/k5-plugin.h $(top_srcdir)/include/k5-thread.h \
-  $(top_srcdir)/include/k5-trace.h $(top_srcdir)/include/krb5.h \
-  $(top_srcdir)/include/krb5/authdata_plugin.h $(top_srcdir)/include/krb5/plugin.h \
-  $(top_srcdir)/include/port-sockets.h $(top_srcdir)/include/socket-utils.h \
-  des_int.h f_sched.c
-f_tables.so f_tables.po $(OUTPRE)f_tables.$(OBJEXT): \
-  $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/krb5/krb5.h \
-  $(BUILDTOP)/include/osconf.h $(BUILDTOP)/include/profile.h \
-  $(COM_ERR_DEPS) $(srcdir)/../../krb/crypto_int.h $(top_srcdir)/include/k5-buf.h \
-  $(top_srcdir)/include/k5-err.h $(top_srcdir)/include/k5-gmt_mktime.h \
-  $(top_srcdir)/include/k5-int-pkinit.h $(top_srcdir)/include/k5-int.h \
-  $(top_srcdir)/include/k5-platform.h $(top_srcdir)/include/k5-plugin.h \
-  $(top_srcdir)/include/k5-thread.h $(top_srcdir)/include/k5-trace.h \
-  $(top_srcdir)/include/krb5.h $(top_srcdir)/include/krb5/authdata_plugin.h \
-  $(top_srcdir)/include/krb5/plugin.h $(top_srcdir)/include/port-sockets.h \
-  $(top_srcdir)/include/socket-utils.h des_int.h f_tables.c \
-  f_tables.h
-key_sched.so key_sched.po $(OUTPRE)key_sched.$(OBJEXT): \
-  $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/krb5/krb5.h \
-  $(BUILDTOP)/include/osconf.h $(BUILDTOP)/include/profile.h \
-  $(COM_ERR_DEPS) $(srcdir)/../../krb/crypto_int.h $(top_srcdir)/include/k5-buf.h \
-  $(top_srcdir)/include/k5-err.h $(top_srcdir)/include/k5-gmt_mktime.h \
-  $(top_srcdir)/include/k5-int-pkinit.h $(top_srcdir)/include/k5-int.h \
-  $(top_srcdir)/include/k5-platform.h $(top_srcdir)/include/k5-plugin.h \
-  $(top_srcdir)/include/k5-thread.h $(top_srcdir)/include/k5-trace.h \
-  $(top_srcdir)/include/krb5.h $(top_srcdir)/include/krb5/authdata_plugin.h \
-  $(top_srcdir)/include/krb5/plugin.h $(top_srcdir)/include/port-sockets.h \
-  $(top_srcdir)/include/socket-utils.h des_int.h key_sched.c
-weak_key.so weak_key.po $(OUTPRE)weak_key.$(OBJEXT): \
-  $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/krb5/krb5.h \
-  $(BUILDTOP)/include/osconf.h $(BUILDTOP)/include/profile.h \
-  $(COM_ERR_DEPS) $(srcdir)/../../krb/crypto_int.h $(top_srcdir)/include/k5-buf.h \
-  $(top_srcdir)/include/k5-err.h $(top_srcdir)/include/k5-gmt_mktime.h \
-  $(top_srcdir)/include/k5-int-pkinit.h $(top_srcdir)/include/k5-int.h \
-  $(top_srcdir)/include/k5-platform.h $(top_srcdir)/include/k5-plugin.h \
-  $(top_srcdir)/include/k5-thread.h $(top_srcdir)/include/k5-trace.h \
-  $(top_srcdir)/include/krb5.h $(top_srcdir)/include/krb5/authdata_plugin.h \
-  $(top_srcdir)/include/krb5/plugin.h $(top_srcdir)/include/port-sockets.h \
-  $(top_srcdir)/include/socket-utils.h des_int.h weak_key.c
-destest.so destest.po $(OUTPRE)destest.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \
-  $(BUILDTOP)/include/krb5/krb5.h $(BUILDTOP)/include/osconf.h \
-  $(BUILDTOP)/include/profile.h $(COM_ERR_DEPS) $(top_srcdir)/include/k5-buf.h \
-  $(top_srcdir)/include/k5-err.h $(top_srcdir)/include/k5-gmt_mktime.h \
-  $(top_srcdir)/include/k5-int-pkinit.h $(top_srcdir)/include/k5-int.h \
-  $(top_srcdir)/include/k5-platform.h $(top_srcdir)/include/k5-plugin.h \
-  $(top_srcdir)/include/k5-thread.h $(top_srcdir)/include/k5-trace.h \
-  $(top_srcdir)/include/krb5.h $(top_srcdir)/include/krb5/authdata_plugin.h \
-  $(top_srcdir)/include/krb5/plugin.h $(top_srcdir)/include/port-sockets.h \
-  $(top_srcdir)/include/socket-utils.h des_int.h destest.c
-f_cbc.so f_cbc.po $(OUTPRE)f_cbc.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \
-  $(BUILDTOP)/include/krb5/krb5.h $(BUILDTOP)/include/osconf.h \
-  $(BUILDTOP)/include/profile.h $(COM_ERR_DEPS) $(top_srcdir)/include/k5-buf.h \
-  $(top_srcdir)/include/k5-err.h $(top_srcdir)/include/k5-gmt_mktime.h \
-  $(top_srcdir)/include/k5-int-pkinit.h $(top_srcdir)/include/k5-int.h \
-  $(top_srcdir)/include/k5-platform.h $(top_srcdir)/include/k5-plugin.h \
-  $(top_srcdir)/include/k5-thread.h $(top_srcdir)/include/k5-trace.h \
-  $(top_srcdir)/include/krb5.h $(top_srcdir)/include/krb5/authdata_plugin.h \
-  $(top_srcdir)/include/krb5/plugin.h $(top_srcdir)/include/port-sockets.h \
-  $(top_srcdir)/include/socket-utils.h des_int.h f_cbc.c \
-  f_tables.h
-t_verify.so t_verify.po $(OUTPRE)t_verify.$(OBJEXT): \
-  $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/krb5/krb5.h \
-  $(BUILDTOP)/include/osconf.h $(BUILDTOP)/include/profile.h \
-  $(COM_ERR_DEPS) $(top_srcdir)/include/k5-buf.h $(top_srcdir)/include/k5-err.h \
-  $(top_srcdir)/include/k5-gmt_mktime.h $(top_srcdir)/include/k5-int-pkinit.h \
-  $(top_srcdir)/include/k5-int.h $(top_srcdir)/include/k5-platform.h \
-  $(top_srcdir)/include/k5-plugin.h $(top_srcdir)/include/k5-thread.h \
-  $(top_srcdir)/include/k5-trace.h $(top_srcdir)/include/krb5.h \
-  $(top_srcdir)/include/krb5/authdata_plugin.h $(top_srcdir)/include/krb5/plugin.h \
-  $(top_srcdir)/include/port-sockets.h $(top_srcdir)/include/socket-utils.h \
-  des_int.h t_verify.c
diff --git a/src/lib/crypto/builtin/des/des_int.h b/src/lib/crypto/builtin/des/des_int.h
deleted file mode 100644
index 46fed7dbd6..0000000000
--- a/src/lib/crypto/builtin/des/des_int.h
+++ /dev/null
@@ -1,282 +0,0 @@
-/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
-/* lib/crypto/builtin/des/des_int.h */
-/*
- * Copyright 1987, 1988, 1990, 2002 by the Massachusetts Institute of
- * Technology.  All Rights Reserved.
- *
- * Export of this software from the United States of America may
- *   require a specific license from the United States Government.
- *   It is the responsibility of any person or organization contemplating
- *   export to obtain such a license before exporting.
- *
- * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
- * distribute this software and its documentation for any purpose and
- * without fee is hereby granted, provided that the above copyright
- * notice appear in all copies and that both that copyright notice and
- * this permission notice appear in supporting documentation, and that
- * the name of M.I.T. not be used in advertising or publicity pertaining
- * to distribution of the software without specific, written prior
- * permission.  Furthermore if you modify this software you must label
- * your software as modified software and not distribute it in such a
- * fashion that it might be confused with the original M.I.T. software.
- * M.I.T. makes no representations about the suitability of
- * this software for any purpose.  It is provided "as is" without express
- * or implied warranty.
- */
-/*
- * Copyright (C) 1998 by the FundsXpress, INC.
- *
- * All rights reserved.
- *
- * Export of this software from the United States of America may require
- * a specific license from the United States Government.  It is the
- * responsibility of any person or organization contemplating export to
- * obtain such a license before exporting.
- *
- * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
- * distribute this software and its documentation for any purpose and
- * without fee is hereby granted, provided that the above copyright
- * notice appear in all copies and that both that copyright notice and
- * this permission notice appear in supporting documentation, and that
- * the name of FundsXpress. not be used in advertising or publicity pertaining
- * to distribution of the software without specific, written prior
- * permission.  FundsXpress makes no representations about the suitability of
- * this software for any purpose.  It is provided "as is" without express
- * or implied warranty.
- *
- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
- * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
- */
-
-/* Private include file for the Data Encryption Standard library. */
-
-/* only do the whole thing once  */
-#ifndef DES_INTERNAL_DEFS
-#define DES_INTERNAL_DEFS
-
-#include "k5-int.h"
-/*
- * Begin "mit-des.h"
- */
-#ifndef KRB5_MIT_DES__
-#define KRB5_MIT_DES__
-
-#if defined(__MACH__) && defined(__APPLE__)
-#include <TargetConditionals.h>
-#include <AvailabilityMacros.h>
-#if TARGET_RT_MAC_CFM
-#error "Use KfM 4.0 SDK headers for CFM compilation."
-#endif
-#if defined(DEPRECATED_IN_MAC_OS_X_VERSION_10_5) && !defined(KRB5_SUPRESS_DEPRECATED_WARNINGS)
-#define KRB5INT_DES_DEPRECATED DEPRECATED_IN_MAC_OS_X_VERSION_10_5
-#endif
-#endif /* defined(__MACH__) && defined(__APPLE__) */
-
-/* Macro to add deprecated attribute to DES types and functions */
-/* Currently only defined on macOS 10.5 and later.              */
-#ifndef KRB5INT_DES_DEPRECATED
-#define KRB5INT_DES_DEPRECATED
-#endif
-
-#include <limits.h>
-
-#if UINT_MAX >= 0xFFFFFFFFUL
-#define DES_INT32 int
-#define DES_UINT32 unsigned int
-#else
-#define DES_INT32 long
-#define DES_UINT32 unsigned long
-#endif
-
-typedef unsigned char des_cblock[8]     /* crypto-block size */
-KRB5INT_DES_DEPRECATED;
-
-/*
- * Key schedule.
- *
- * This used to be
- *
- * typedef struct des_ks_struct {
- *     union { DES_INT32 pad; des_cblock _;} __;
- * } des_key_schedule[16];
- *
- * but it would cause trouble if DES_INT32 were ever more than 4
- * bytes.  The reason is that all the encryption functions cast it to
- * (DES_INT32 *), and treat it as if it were DES_INT32[32].  If
- * 2*sizeof(DES_INT32) is ever more than sizeof(des_cblock), the
- * caller-allocated des_key_schedule will be overflowed by the key
- * scheduling functions.  We can't assume that every platform will
- * have an exact 32-bit int, and nothing should be looking inside a
- * des_key_schedule anyway.
- */
-typedef struct des_ks_struct {  DES_INT32 _[2]; } des_key_schedule[16]
-KRB5INT_DES_DEPRECATED;
-
-typedef des_cblock mit_des_cblock;
-typedef des_key_schedule mit_des_key_schedule;
-
-/* Triple-DES structures */
-typedef mit_des_cblock          mit_des3_cblock[3];
-typedef mit_des_key_schedule    mit_des3_key_schedule[3];
-
-#define MIT_DES_ENCRYPT 1
-#define MIT_DES_DECRYPT 0
-
-typedef struct mit_des_ran_key_seed {
-    krb5_encrypt_block eblock;
-    krb5_data sequence;
-} mit_des_random_state;
-
-/* the first byte of the key is already in the keyblock */
-
-#define MIT_DES_BLOCK_LENGTH            (8*sizeof(krb5_octet))
-/* This used to be 8*sizeof(krb5_octet) */
-#define MIT_DES_KEYSIZE                 8
-
-#define MIT_DES_CBC_CKSUM_LENGTH        (4*sizeof(krb5_octet))
-
-#endif /* KRB5_MIT_DES__ */
-/*
- * End "mit-des.h"
- */
-
-/* afsstring2key.c */
-krb5_error_code mit_afs_string_to_key(krb5_keyblock *keyblock,
-                                      const krb5_data *data,
-                                      const krb5_data *salt);
-char *mit_afs_crypt(const char *pw, const char *salt, char *iobuf);
-
-/* f_cksum.c */
-unsigned long mit_des_cbc_cksum(const krb5_octet *, krb5_octet *,
-                                unsigned long, const mit_des_key_schedule,
-                                const krb5_octet *);
-
-/* f_cbc.c (used by test programs) */
-int
-mit_des_cbc_encrypt(const mit_des_cblock *in, mit_des_cblock *out,
-                    unsigned long length, const mit_des_key_schedule schedule,
-                    const mit_des_cblock ivec, int enc);
-
-#define mit_des_zeroblock krb5int_c_mit_des_zeroblock
-extern const mit_des_cblock mit_des_zeroblock;
-
-/* fin_rndkey.c */
-krb5_error_code mit_des_finish_random_key(const krb5_encrypt_block *,
-                                          krb5_pointer *);
-
-/* finish_key.c */
-krb5_error_code mit_des_finish_key(krb5_encrypt_block *);
-
-/* init_rkey.c */
-krb5_error_code mit_des_init_random_key(const krb5_encrypt_block *,
-                                        const krb5_keyblock *,
-                                        krb5_pointer *);
-
-/* key_parity.c */
-void mit_des_fixup_key_parity(mit_des_cblock);
-int mit_des_check_key_parity(mit_des_cblock);
-
-/* key_sched.c */
-int mit_des_key_sched(mit_des_cblock, mit_des_key_schedule);
-
-/* process_ky.c */
-krb5_error_code mit_des_process_key(krb5_encrypt_block *,
-                                    const krb5_keyblock *);
-
-/* random_key.c */
-krb5_error_code mit_des_random_key(const krb5_encrypt_block *,
-                                   krb5_pointer, krb5_keyblock **);
-
-/* string2key.c */
-krb5_error_code mit_des_string_to_key(const krb5_encrypt_block *,
-                                      krb5_keyblock *, const krb5_data *,
-                                      const krb5_data *);
-krb5_error_code mit_des_string_to_key_int(krb5_keyblock *, const krb5_data *,
-                                          const krb5_data *);
-
-/* weak_key.c */
-int mit_des_is_weak_key(mit_des_cblock);
-
-/* cmb_keys.c */
-krb5_error_code mit_des_combine_subkeys(const krb5_keyblock *,
-                                        const krb5_keyblock *,
-                                        krb5_keyblock **);
-
-/* f_sched.c */
-int mit_des_make_key_sched(mit_des_cblock, mit_des_key_schedule);
-
-
-/* misc.c */
-extern void swap_bits(char *);
-extern unsigned long long_swap_bits(unsigned long);
-extern unsigned long swap_six_bits_to_ansi(unsigned long);
-extern unsigned long swap_four_bits_to_ansi(unsigned long);
-extern unsigned long swap_bit_pos_1(unsigned long);
-extern unsigned long swap_bit_pos_0(unsigned long);
-extern unsigned long swap_bit_pos_0_to_ansi(unsigned long);
-extern unsigned long rev_swap_bit_pos_0(unsigned long);
-extern unsigned long swap_byte_bits(unsigned long);
-extern unsigned long swap_long_bytes_bit_number(unsigned long);
-#ifdef FILE
-/* XXX depends on FILE being a #define! */
-extern void test_set(FILE *, const char *, int, const char *, int);
-#endif
-
-void
-krb5int_des3_cbc_encrypt(krb5_crypto_iov *data, unsigned long num_data,
-                         const mit_des_key_schedule ks1,
-                         const mit_des_key_schedule ks2,
-                         const mit_des_key_schedule ks3,
-                         mit_des_cblock ivec);
-
-void
-krb5int_des3_cbc_decrypt(krb5_crypto_iov *data, unsigned long num_data,
-                         const mit_des_key_schedule ks1,
-                         const mit_des_key_schedule ks2,
-                         const mit_des_key_schedule ks3,
-                         mit_des_cblock ivec);
-
-void
-krb5int_des_cbc_encrypt(krb5_crypto_iov *data, unsigned long num_data,
-                        const mit_des_key_schedule schedule,
-                        mit_des_cblock ivec);
-
-void
-krb5int_des_cbc_decrypt(krb5_crypto_iov *data, unsigned long num_data,
-                        const mit_des_key_schedule schedule,
-                        mit_des_cblock ivec);
-
-void
-krb5int_des_cbc_mac(const krb5_crypto_iov *data, unsigned long num_data,
-                    const mit_des_key_schedule schedule, mit_des_cblock ivec,
-                    mit_des_cblock out);
-
-/* d3_procky.c */
-krb5_error_code mit_des3_process_key(krb5_encrypt_block *eblock,
-                                     const krb5_keyblock *keyblock);
-
-/* d3_kysched.c */
-int mit_des3_key_sched(mit_des3_cblock key, mit_des3_key_schedule schedule);
-
-/* d3_str2ky.c */
-krb5_error_code mit_des3_string_to_key(const krb5_encrypt_block *eblock,
-                                       krb5_keyblock *keyblock,
-                                       const krb5_data *data,
-                                       const krb5_data *salt);
-
-/* u_nfold.c */
-krb5_error_code mit_des_n_fold(const krb5_octet *input, const size_t in_len,
-                               krb5_octet *output, const size_t out_len);
-
-/* u_rn_key.c */
-int mit_des_is_weak_keyblock(krb5_keyblock *keyblock);
-
-void mit_des_fixup_keyblock_parity(krb5_keyblock *keyblock);
-
-krb5_error_code mit_des_set_random_generator_seed(const krb5_data *seed,
-                                                  krb5_pointer random_state);
-
-krb5_error_code mit_des_set_random_sequence_number(const krb5_data *sequence,
-                                                   krb5_pointer random_state);
-#endif  /*DES_INTERNAL_DEFS*/
diff --git a/src/lib/crypto/builtin/des/des_keys.c b/src/lib/crypto/builtin/des/des_keys.c
deleted file mode 100644
index 027b09d728..0000000000
--- a/src/lib/crypto/builtin/des/des_keys.c
+++ /dev/null
@@ -1,38 +0,0 @@
-/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
-/* lib/crypto/builtin/des/des_keys.c - Key functions used by Kerberos code */
-/*
- * Copyright (C) 2011 by the Massachusetts Institute of Technology.
- * All rights reserved.
- *
- * Export of this software from the United States of America may
- *   require a specific license from the United States Government.
- *   It is the responsibility of any person or organization contemplating
- *   export to obtain such a license before exporting.
- *
- * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
- * distribute this software and its documentation for any purpose and
- * without fee is hereby granted, provided that the above copyright
- * notice appear in all copies and that both that copyright notice and
- * this permission notice appear in supporting documentation, and that
- * the name of M.I.T. not be used in advertising or publicity pertaining
- * to distribution of the software without specific, written prior
- * permission.  Furthermore if you modify this software you must label
- * your software as modified software and not distribute it in such a
- * fashion that it might be confused with the original M.I.T. software.
- * M.I.T. makes no representations about the suitability of
- * this software for any purpose.  It is provided "as is" without express
- * or implied warranty.
- */
-
-#include "crypto_int.h"
-#include "des_int.h"
-
-#ifdef K5_BUILTIN_DES_KEY_PARITY
-
-void
-k5_des_fixup_key_parity(unsigned char *keybits)
-{
-    mit_des_fixup_key_parity(keybits);
-}
-
-#endif /* K5_BUILTIN_DES_KEY_PARITY */
diff --git a/src/lib/crypto/builtin/des/destest.c b/src/lib/crypto/builtin/des/destest.c
deleted file mode 100644
index 0a1a5be81b..0000000000
--- a/src/lib/crypto/builtin/des/destest.c
+++ /dev/null
@@ -1,231 +0,0 @@
-/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
-/* lib/crypto/builtin/des/destest.c */
-/*
- * Copyright 1990,1991 by the Massachusetts Institute of Technology.
- * All Rights Reserved.
- *
- * Export of this software from the United States of America may
- *   require a specific license from the United States Government.
- *   It is the responsibility of any person or organization contemplating
- *   export to obtain such a license before exporting.
- *
- * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
- * distribute this software and its documentation for any purpose and
- * without fee is hereby granted, provided that the above copyright
- * notice appear in all copies and that both that copyright notice and
- * this permission notice appear in supporting documentation, and that
- * the name of M.I.T. not be used in advertising or publicity pertaining
- * to distribution of the software without specific, written prior
- * permission.  Furthermore if you modify this software you must label
- * your software as modified software and not distribute it in such a
- * fashion that it might be confused with the original M.I.T. software.
- * M.I.T. makes no representations about the suitability of
- * this software for any purpose.  It is provided "as is" without express
- * or implied warranty.
- */
-/*
- * Copyright (C) 1998 by the FundsXpress, INC.
- *
- * All rights reserved.
- *
- * Export of this software from the United States of America may require
- * a specific license from the United States Government.  It is the
- * responsibility of any person or organization contemplating export to
- * obtain such a license before exporting.
- *
- * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
- * distribute this software and its documentation for any purpose and
- * without fee is hereby granted, provided that the above copyright
- * notice appear in all copies and that both that copyright notice and
- * this permission notice appear in supporting documentation, and that
- * the name of FundsXpress. not be used in advertising or publicity pertaining
- * to distribution of the software without specific, written prior
- * permission.  FundsXpress makes no representations about the suitability of
- * this software for any purpose.  It is provided "as is" without express
- * or implied warranty.
- *
- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
- * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
- */
-
-/* Test a DES implementation against known inputs & outputs. */
-
-#include "des_int.h"
-#include <ctype.h>
-#include <stdio.h>
-
-void convert (char *, unsigned char []);
-
-void des_cblock_print_file (mit_des_cblock, FILE *);
-
-krb5_octet zeroblock[8] = {0,0,0,0,0,0,0,0};
-
-int
-main(int argc, char *argv[])
-{
-    char block1[17], block2[17], block3[17];
-    /* Force tests of unaligned accesses.  */
-    union { unsigned char c[8*4+3]; long l; } u;
-    unsigned char *ioblocks = u.c;
-    unsigned char *input = ioblocks+1;
-    unsigned char *output = ioblocks+10;
-    unsigned char *output2 = ioblocks+19;
-    unsigned char *key = ioblocks+27;
-    mit_des_key_schedule sched;
-    int num = 0;
-    int retval;
-
-    int error = 0;
-
-    while (scanf("%16s %16s %16s", block1, block2, block3) == 3) {
-        convert(block1, key);
-        convert(block2, input);
-        convert(block3, output);
-
-        retval = mit_des_key_sched(key, sched);
-        if (retval) {
-            fprintf(stderr, "des test: can't process key: %d\n", retval);
-            fprintf(stderr, "des test: %s %s %s\n", block1, block2, block3);
-            exit(1);
-        }
-        mit_des_cbc_encrypt((const mit_des_cblock *) input,
-                            (mit_des_cblock *) output2, 8,
-                            sched, zeroblock, 1);
-
-        if (memcmp((char *)output2, (char *)output, 8)) {
-            fprintf(stderr,
-                    "DES ENCRYPT ERROR, key %s, text %s, real cipher %s, computed cyphertext %02X%02X%02X%02X%02X%02X%02X%02X\n",
-                    block1, block2, block3,
-                    output2[0],output2[1],output2[2],output2[3],
-                    output2[4],output2[5],output2[6],output2[7]);
-            error++;
-        }
-
-        /*
-         * Now try decrypting....
-         */
-        mit_des_cbc_encrypt((const mit_des_cblock *) output,
-                            (mit_des_cblock *) output2, 8,
-                            sched, zeroblock, 0);
-
-        if (memcmp((char *)output2, (char *)input, 8)) {
-            fprintf(stderr,
-                    "DES DECRYPT ERROR, key %s, text %s, real cipher %s, computed cleartext %02X%02X%02X%02X%02X%02X%02X%02X\n",
-                    block1, block2, block3,
-                    output2[0],output2[1],output2[2],output2[3],
-                    output2[4],output2[5],output2[6],output2[7]);
-            error++;
-        }
-
-        num++;
-    }
-
-    if (error)
-        printf("destest: failed to pass the test\n");
-    else
-        printf("destest: %d tests passed successfully\n", num);
-
-    exit( (error > 256 && error % 256) ? 1 : error);
-}
-
-int value[128] = {
-    -1, -1, -1, -1, -1, -1, -1, -1,
-    -1, -1, -1, -1, -1, -1, -1, -1,
-    -1, -1, -1, -1, -1, -1, -1, -1,
-    -1, -1, -1, -1, -1, -1, -1, -1,
-    -1, -1, -1, -1, -1, -1, -1, -1,
-    -1, -1, -1, -1, -1, -1, -1, -1,
-    0, 1, 2, 3, 4, 5, 6, 7,
-    8, 9, -1, -1, -1, -1, -1, -1,
-    -1, 10, 11, 12, 13, 14, 15, -1,
-    -1, -1, -1, -1, -1, -1, -1, -1,
-    -1, -1, -1, -1, -1, -1, -1, -1,
-    -1, -1, -1, -1, -1, -1, -1, -1,
-    -1, -1, -1, -1, -1, -1, -1, -1,
-    -1, -1, -1, -1, -1, -1, -1, -1,
-    -1, -1, -1, -1, -1, -1, -1, -1,
-    -1, -1, -1, -1, -1, -1, -1, -1,
-};
-
-void
-convert(char *text, unsigned char cblock[])
-{
-    int i;
-    for (i = 0; i < 8; i++) {
-        if (!isascii((unsigned char)text[i * 2]))
-            abort ();
-        if (value[(int) text[i*2]] == -1 || value[(int) text[i*2+1]] == -1) {
-            printf("Bad value byte %d in %s\n", i, text);
-            exit(1);
-        }
-        cblock[i] = 16*value[(int) text[i*2]] + value[(int) text[i*2+1]];
-    }
-    return;
-}
-
-/*
- * Fake out the DES library, for the purposes of testing.
- */
-
-int
-mit_des_is_weak_key(mit_des_cblock key)
-{
-    return 0;                           /* fake it out for testing */
-}
-
-void
-des_cblock_print_file(mit_des_cblock x, FILE *fp)
-{
-    unsigned char *y = (unsigned char *) x;
-    int i = 0;
-    fprintf(fp," 0x { ");
-
-    while (i++ < 8) {
-        fprintf(fp,"%x",*y++);
-        if (i < 8)
-            fprintf(fp,", ");
-    }
-    fprintf(fp," }");
-}
-
-
-#define smask(step) ((1<<step)-1)
-#define pstep(x,step) (((x)&smask(step))^(((x)>>step)&smask(step)))
-#define parity_char(x) pstep(pstep(pstep((x),4),2),1)
-
-/*
- * des_check_key_parity: returns true iff key has the correct des parity.
- *                       See des_fix_key_parity for the definition of
- *                       correct des parity.
- */
-int
-mit_des_check_key_parity(mit_des_cblock key)
-{
-    unsigned int i;
-
-    for (i=0; i<sizeof(mit_des_cblock); i++) {
-        if ((key[i] & 1) == parity_char(0xfe&key[i])) {
-            printf("warning: bad parity key:");
-            des_cblock_print_file(key, stdout);
-            putchar('\n');
-
-            return 1;
-        }
-    }
-
-    return(1);
-}
-
-void
-mit_des_fixup_key_parity(mit_des_cblock key)
-{
-    unsigned int i;
-    for (i=0; i<sizeof(mit_des_cblock); i++)
-    {
-        key[i] &= 0xfe;
-        key[i] |= 1^parity_char(key[i]);
-    }
-
-    return;
-}
diff --git a/src/lib/crypto/builtin/des/doc/libdes.doc b/src/lib/crypto/builtin/des/doc/libdes.doc
deleted file mode 100644
index 6e9431ed2e..0000000000
--- a/src/lib/crypto/builtin/des/doc/libdes.doc
+++ /dev/null
@@ -1,208 +0,0 @@
-
-	How to use the Kerberos encryption library.
-
-			Revised		10/15/85	spm
-
-1)	The following include file is needed:
-	
-	/projects/auth/include/des.h	(VAX)
-	---------------					(PC8086)
-
-2)	The encryption library that should be linked to is:
-	
-	/projects/auth/lib/libdes.a		(VAX)
-|	/projects/auth/ibm/lib/libdes.a	(PC8086 cross-compilation environment)
-
-3)	For each key that may be simultaneously active,
-	allocate (either compile or malloc) a "Key_schedule" struct, 
-	defined in "des.h"
-
-4)	Create key schedules, as needed, prior to using the encryption
-	routines, via "des_set_key()".
-
-5)  Setup the input and output areas.  Make sure to note the restrictions
-	on lengths being multiples of eight bytes.
-
-6)	Invoke the encryption/decryption routines, "ecb_encrypt()"
-	 or "cbc_encrypt()"
-
-7)	To generate a cryptographic checksum, use "cbc_cksum()"
-/*	----------------------------------------------------------------	*/
-	
-	Routine Interfaces--
-
-/*	-----------------------------------------------------------------	*/
-
-int
-	des_set_key(k,schedule)
-		C_Block			*k;
-		Key_schedule	schedule;
-
-	Calculates a key schedule from (all) eight bytes of the input key, and
-	puts it into the indicated "Key_schedule" struct;
-
-	Make sure to pass valid eight bytes, no padding or other processing
-	it done.
-
-	The key schedule is then used in subsequent encryption/decryption
-	operations.  Many key schedules may be created and cached for later
-	use.
-
-	The user is responsible to clear keys and schedules no longer needed
-	to prevent their disclosure.
-
-|	Checks the parity of the key provided, to make sure it is odd per
-|	FIPS spec.  Returns 0 value for key ok, 1 for key_parity error.
-
-/*	----------------------------------------------------------------	*/
-	
-int
-	ecb_encrypt(input,output,schedule,encrypt)
-		C_Block			*input;		/* ptr to eight byte input value */
-		C_Block			*output;	/* ptr to eight byte output value */
-		int				encrypt;	/* 0 ==> decrypt, else encrypt */
-		Key_schedule	schedule;	/* addr of key schedule */
-
-This is the low level routine that encrypts or decrypts a single 8-byte
-block in electronic code book mode.  Always transforms the input
-data into the output data.
-
-If encrypt is non-zero, the input (cleartext) is encrypted into the
-output (ciphertext) using the specified key_schedule, pre-set via "des_set_key".
-
-If encrypt is zero, the input (now ciphertext) is decrypted into
-the output (now cleartext).
-
-Input and output may be the same space.
-
-Does not return any meaningful value.  Void is not used for compatibility
-with other compilers.
-
-/*	--------------------------------------------------------------	*/
-
-int	
-	cbc_encrypt(input,output,length,schedule,ivec,encrypt)
-
-		C_Block			*input;		/* ptr to input data */
-		C_Block			*output;	/* ptr to output data */
-		int				length;		/* desired length, in bytes */
-		Key_schedule	schedule;		/* addr of precomputed schedule */
-		C_Block			*ivec;		/* pointer to 8 byte initialization
-									 * vector
-									 */
-		int				encrypt		/* 0 ==> decrypt; else encrypt*/
-
-
-	If encrypt is non-zero, the routine cipher-block-chain encrypts
-	the INPUT (cleartext) into the OUTPUT (ciphertext) using the provided
-	key schedule and initialization vector.  If the length is not an integral
-	multiple of eight bytes, the last block is copied to a temp and zero 
-	filled (highest addresses).  The output is ALWAYS an integral multiple
-	of eight bytes.
-
-	If encrypt is zero, the routine cipher-block chain decrypts the INPUT
-	(ciphertext) into the OUTPUT (cleartext) using the provided key schedule
-	and	initialization vector.	Decryption ALWAYS operates on integral
-	multiples of 8 bytes, so will round the length provided up to the
-	appropriate	multiple. Consequently,	it will always produce the rounded-up
-	number of bytes of output cleartext. The application must determine if
-	the output cleartext was zero-padded due to cleartext lengths not integral
-	multiples of 8.
-
-	No errors or meaningful value are returned.  Void is not used for
-	compatibility with other compilers.
-
-
-/* cbc checksum (MAC) only routine  ---------------------------------------- */
-int	
-	cbc_cksum(input,output,length,schedule,ivec)
-
-	C_Block		 	*input;		/* >= length bytes of inputtext	 */
-	C_Block		 	*output;	/* >= length bytes of outputtext */
-	int				length;		/* in bytes						*/
-	Key_schedule	schedule;	/* precomputed key schedule	   */
-	C_Block			*ivec;		/* 8 bytes of ivec			   */
-
-
-	Produces a cryptographic checksum, 8 bytes, by cipher-block-chain
-	encrypting the input, discarding the ciphertext output, and only retaining
-	the last ciphertext 8-byte block.  Uses the provided key schedule and ivec.
-	The input is effectively zero-padded to an integral multiple of
-	eight bytes, though the original input is not modified.
-
-	No meaningful value is returned.  Void is not used for compatibility
-	with other compilers.
-
-
-/*	random_key ----------------------------------------*/
-int
-	random_key(key)
-
-	C_Block	*key;
-
-	The start for the random number generated is set from the current time
-	in microseconds, then the random number generator is invoked
-	to create an eight byte output key (not a schedule).  The key
-	generated is set to odd parity per FIPS spec.
-
-	The caller must	supply space for the output key, pointed to 
-	by "*key", then after getting a new key, call the des_set_key() 
-	routine when needed.
-
-	No meaningful value is returned.  Void is not used for compatibility
-	with other compilers.
-
-
-/* string_to_key --------------------------------------------*/
-
-int
-	string_to_key(str,key)
-	char		*str;
-	C_Block	*key;
-
-	This routines converts an arbitrary length, null terminated string
-	to an 8 byte DES key, with each byte parity set to odd, per FIPS spec.
-
-	The algorithm is as follows:
-
-|	Take the first 8 bytes and remove the parity (leaving 56 bits).
-|	Do the same for the second 8 bytes, and the third, etc.  Do this for
-|	as many sets of 8 bytes as necessary, filling in the remainder of the
-|	last set with nulls.  Fold the second set back on the first (i.e. bit
-|	0 over bit 55, and bit 55 over bit 0).  Fold the third over the second
-|	(bit 0 of the third set is now over bit 0 of the first set).  Repeat
-|	until you have done this to all sets.  Xor the folded sets.  Break the
-|	result into 8 7 bit bytes, and generate odd parity for each byte.  You
-|	now have 64 bits.  Note that DES takes a 64 bit key, and uses only the
-|	non parity bits.
-
-
-/* read_password -------------------------------------------*/
-
-read_password(k,prompt,verify)
-	C_Block	*k;
-	char *prompt;
-	int	verify;
-
-This routine issues the supplied prompt, turns off echo, if possible, and
-reads an input string.  If verify is non-zero, it does it again, for use
-in applications such as changing a password. If verify is non-zero, both
-versions are compared, and the input is requested repeatedly until they
-match.  Then, the input string is mapped into a valid DES key, internally
-using the string_to_key routine.  The newly created key is copied to the
-area pointed to by parameter "k".  
-
-No meaningful value is returned.  If an error occurs trying to manipulate
-the terminal echo, the routine forces the process to exit.
-
-/* get_line ------------------------*/
-long get_line(p,max)
-	char	*p;
-	long	max;
-
-Reads input characters from standard input until either a newline appears or
-else the max length is reached.  The characters read are stuffed into
-the string pointed to, which will always be null terminated.  The newline
-is not inserted in the string.  The max parameter includes the byte needed
-for the null terminator, so allocate and pass one more than the maximum
-string length desired.
diff --git a/src/lib/crypto/builtin/des/f_aead.c b/src/lib/crypto/builtin/des/f_aead.c
deleted file mode 100644
index f887735820..0000000000
--- a/src/lib/crypto/builtin/des/f_aead.c
+++ /dev/null
@@ -1,177 +0,0 @@
-/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
-/*
- * Copyright (C) 2008 by the Massachusetts Institute of Technology.
- * Copyright 1995 by Richard P. Basch.  All Rights Reserved.
- * Copyright 1995 by Lehman Brothers, Inc.  All Rights Reserved.
- *
- * Export of this software from the United States of America may
- *   require a specific license from the United States Government.
- *   It is the responsibility of any person or organization contemplating
- *   export to obtain such a license before exporting.
- *
- * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
- * distribute this software and its documentation for any purpose and
- * without fee is hereby granted, provided that the above copyright
- * notice appear in all copies and that both that copyright notice and
- * this permission notice appear in supporting documentation, and that
- * the name of Richard P. Basch, Lehman Brothers and M.I.T. not be used
- * in advertising or publicity pertaining to distribution of the software
- * without specific, written prior permission.  Richard P. Basch,
- * Lehman Brothers and M.I.T. make no representations about the suitability
- * of this software for any purpose.  It is provided "as is" without
- * express or implied warranty.
- */
-
-#include "crypto_int.h"
-#include "des_int.h"
-#include "f_tables.h"
-
-#ifdef K5_BUILTIN_DES
-
-const mit_des_cblock mit_des_zeroblock /* = all zero */;
-
-void
-krb5int_des_cbc_encrypt(krb5_crypto_iov *data, unsigned long num_data,
-                        const mit_des_key_schedule schedule,
-                        mit_des_cblock ivec)
-{
-    unsigned DES_INT32 left, right;
-    const unsigned DES_INT32 *kp;
-    const unsigned char *ip;
-    struct iov_cursor cursor;
-    unsigned char block[MIT_DES_BLOCK_LENGTH];
-
-    /* Get key pointer here.  This won't need to be reinitialized. */
-    kp = (const unsigned DES_INT32 *)schedule;
-
-    /* Initialize left and right with the contents of the initial vector. */
-    ip = (ivec != NULL) ? ivec : mit_des_zeroblock;
-    left = load_32_be(ip);
-    right = load_32_be(ip + 4);
-
-    k5_iov_cursor_init(&cursor, data, num_data, MIT_DES_BLOCK_LENGTH, FALSE);
-    while (k5_iov_cursor_get(&cursor, block)) {
-        /* Decompose this block and xor it with the previous ciphertext. */
-        left ^= load_32_be(block);
-        right ^= load_32_be(block + 4);
-
-        /* Encrypt what we have and put back into block. */
-        DES_DO_ENCRYPT(left, right, kp);
-        store_32_be(left, block);
-        store_32_be(right, block + 4);
-
-        k5_iov_cursor_put(&cursor, block);
-    }
-
-    if (ivec != NULL) {
-        store_32_be(left, ivec);
-        store_32_be(right, ivec + 4);
-    }
-}
-
-void
-krb5int_des_cbc_decrypt(krb5_crypto_iov *data, unsigned long num_data,
-                        const mit_des_key_schedule schedule,
-                        mit_des_cblock ivec)
-{
-    unsigned DES_INT32 left, right;
-    const unsigned DES_INT32 *kp;
-    const unsigned char *ip;
-    unsigned DES_INT32 ocipherl, ocipherr;
-    unsigned DES_INT32 cipherl, cipherr;
-    struct iov_cursor cursor;
-    unsigned char block[MIT_DES_BLOCK_LENGTH];
-
-    /* Get key pointer here.  This won't need to be reinitialized. */
-    kp = (const unsigned DES_INT32 *)schedule;
-
-    /*
-     * Decrypting is harder than encrypting because of
-     * the necessity of remembering a lot more things.
-     * Should think about this a little more...
-     */
-
-    /* Prime the old cipher with ivec. */
-    ip = (ivec != NULL) ? ivec : mit_des_zeroblock;
-    ocipherl = load_32_be(ip);
-    ocipherr = load_32_be(ip + 4);
-
-    k5_iov_cursor_init(&cursor, data, num_data, MIT_DES_BLOCK_LENGTH, FALSE);
-    while (k5_iov_cursor_get(&cursor, block)) {
-        /* Split this block into left and right. */
-        cipherl = left = load_32_be(block);
-        cipherr = right = load_32_be(block + 4);
-
-        /* Decrypt and xor with the old cipher to get plain text. */
-        DES_DO_DECRYPT(left, right, kp);
-        left ^= ocipherl;
-        right ^= ocipherr;
-
-        /* Store the encrypted halves back into block. */
-        store_32_be(left, block);
-        store_32_be(right, block + 4);
-
-        /* Save current cipher block halves. */
-        ocipherl = cipherl;
-        ocipherr = cipherr;
-
-        k5_iov_cursor_put(&cursor, block);
-    }
-
-    if (ivec != NULL) {
-        store_32_be(ocipherl, ivec);
-        store_32_be(ocipherr, ivec + 4);
-    }
-}
-
-void
-krb5int_des_cbc_mac(const krb5_crypto_iov *data, unsigned long num_data,
-                    const mit_des_key_schedule schedule, mit_des_cblock ivec,
-                    mit_des_cblock out)
-{
-    unsigned DES_INT32 left, right;
-    const unsigned DES_INT32 *kp;
-    const unsigned char *ip;
-    struct iov_cursor cursor;
-    unsigned char block[MIT_DES_BLOCK_LENGTH];
-
-    /* Get key pointer here.  This won't need to be reinitialized. */
-    kp = (const unsigned DES_INT32 *)schedule;
-
-    /* Initialize left and right with the contents of the initial vector. */
-    ip = (ivec != NULL) ? ivec : mit_des_zeroblock;
-    left = load_32_be(ip);
-    right = load_32_be(ip + 4);
-
-    k5_iov_cursor_init(&cursor, data, num_data, MIT_DES_BLOCK_LENGTH, TRUE);
-    while (k5_iov_cursor_get(&cursor, block)) {
-        /* Decompose this block and xor it with the previous ciphertext. */
-        left ^= load_32_be(block);
-        right ^= load_32_be(block + 4);
-
-        /* Encrypt what we have. */
-        DES_DO_ENCRYPT(left, right, kp);
-    }
-
-    /* Output the final ciphertext block. */
-    store_32_be(left, out);
-    store_32_be(right, out + 4);
-}
-
-#if defined(CONFIG_SMALL) && !defined(CONFIG_SMALL_NO_CRYPTO)
-void krb5int_des_do_encrypt_2 (unsigned DES_INT32 *left,
-                               unsigned DES_INT32 *right,
-                               const unsigned DES_INT32 *kp)
-{
-    DES_DO_ENCRYPT_1 (*left, *right, kp);
-}
-
-void krb5int_des_do_decrypt_2 (unsigned DES_INT32 *left,
-                               unsigned DES_INT32 *right,
-                               const unsigned DES_INT32 *kp)
-{
-    DES_DO_DECRYPT_1 (*left, *right, kp);
-}
-#endif
-
-#endif /* K5_BUILTIN_DES */
diff --git a/src/lib/crypto/builtin/des/f_cbc.c b/src/lib/crypto/builtin/des/f_cbc.c
deleted file mode 100644
index 84d5382f22..0000000000
--- a/src/lib/crypto/builtin/des/f_cbc.c
+++ /dev/null
@@ -1,256 +0,0 @@
-/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
-/* lib/crypto/builtin/des/f_cbc.c */
-/*
- * Copyright (C) 1990 by the Massachusetts Institute of Technology.
- * All rights reserved.
- *
- * Export of this software from the United States of America may
- *   require a specific license from the United States Government.
- *   It is the responsibility of any person or organization contemplating
- *   export to obtain such a license before exporting.
- *
- * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
- * distribute this software and its documentation for any purpose and
- * without fee is hereby granted, provided that the above copyright
- * notice appear in all copies and that both that copyright notice and
- * this permission notice appear in supporting documentation, and that
- * the name of M.I.T. not be used in advertising or publicity pertaining
- * to distribution of the software without specific, written prior
- * permission.  Furthermore if you modify this software you must label
- * your software as modified software and not distribute it in such a
- * fashion that it might be confused with the original M.I.T. software.
- * M.I.T. makes no representations about the suitability of
- * this software for any purpose.  It is provided "as is" without express
- * or implied warranty.
- */
-
-/*
- * CBC functions; used only by the test programs at this time.  (krb5 uses the
- * functions in f_aead.c instead.)
- */
-
-/*
- * des_cbc_encrypt.c - an implementation of the DES cipher function in cbc mode
- */
-#include "des_int.h"
-#include "f_tables.h"
-
-/*
- * des_cbc_encrypt - {en,de}crypt a stream in CBC mode
- */
-
-/*
- * This routine performs DES cipher-block-chaining operation, either
- * encrypting from cleartext to ciphertext, if encrypt != 0 or
- * decrypting from ciphertext to cleartext, if encrypt == 0.
- *
- * The key schedule is passed as an arg, as well as the cleartext or
- * ciphertext.  The cleartext and ciphertext should be in host order.
- *
- * NOTE-- the output is ALWAYS an multiple of 8 bytes long.  If not
- * enough space was provided, your program will get trashed.
- *
- * For encryption, the cleartext string is null padded, at the end, to
- * an integral multiple of eight bytes.
- *
- * For decryption, the ciphertext will be used in integral multiples
- * of 8 bytes, but only the first "length" bytes returned into the
- * cleartext.
- */
-
-const mit_des_cblock mit_des_zeroblock /* = all zero */;
-
-static void
-des_cbc_encrypt(const mit_des_cblock *in, mit_des_cblock *out,
-                unsigned long length, const mit_des_key_schedule schedule,
-                const mit_des_cblock ivec)
-{
-    unsigned DES_INT32 left, right;
-    const unsigned DES_INT32 *kp;
-    const unsigned char *ip;
-    unsigned char *op;
-
-    /*
-     * Get key pointer here.  This won't need to be reinitialized
-     */
-    kp = (const unsigned DES_INT32 *)schedule;
-
-    /*
-     * Initialize left and right with the contents of the initial
-     * vector.
-     */
-    ip = ivec;
-    GET_HALF_BLOCK(left, ip);
-    GET_HALF_BLOCK(right, ip);
-
-    /*
-     * Suitably initialized, now work the length down 8 bytes
-     * at a time.
-     */
-    ip = *in;
-    op = *out;
-    while (length > 0) {
-        /*
-         * Get more input, xor it in.  If the length is
-         * greater than or equal to 8 this is straight
-         * forward.  Otherwise we have to fart around.
-         */
-        if (length >= 8) {
-            unsigned DES_INT32 temp;
-            GET_HALF_BLOCK(temp, ip);
-            left  ^= temp;
-            GET_HALF_BLOCK(temp, ip);
-            right ^= temp;
-            length -= 8;
-        } else {
-            /*
-             * Oh, shoot.  We need to pad the
-             * end with zeroes.  Work backwards
-             * to do this.
-             */
-            ip += (int) length;
-            switch(length) {
-            case 7:
-                right ^= (*(--ip) & FF_UINT32) <<  8;
-            case 6:
-                right ^= (*(--ip) & FF_UINT32) << 16;
-            case 5:
-                right ^= (*(--ip) & FF_UINT32) << 24;
-            case 4:
-                left  ^=  *(--ip) & FF_UINT32;
-            case 3:
-                left  ^= (*(--ip) & FF_UINT32) <<  8;
-            case 2:
-                left  ^= (*(--ip) & FF_UINT32) << 16;
-            case 1:
-                left  ^= (*(--ip) & FF_UINT32) << 24;
-                break;
-            }
-            length = 0;
-        }
-
-        /*
-         * Encrypt what we have
-         */
-        DES_DO_ENCRYPT(left, right, kp);
-
-        /*
-         * Copy the results out
-         */
-        PUT_HALF_BLOCK(left, op);
-        PUT_HALF_BLOCK(right, op);
-    }
-}
-
-static void
-des_cbc_decrypt(const mit_des_cblock *in, mit_des_cblock *out,
-                unsigned long length, const mit_des_key_schedule schedule,
-                const mit_des_cblock ivec)
-{
-    unsigned DES_INT32 left, right;
-    const unsigned DES_INT32 *kp;
-    const unsigned char *ip;
-    unsigned char *op;
-    unsigned DES_INT32 ocipherl, ocipherr;
-    unsigned DES_INT32 cipherl, cipherr;
-
-    /*
-     * Get key pointer here.  This won't need to be reinitialized
-     */
-    kp = (const unsigned DES_INT32 *)schedule;
-
-    /*
-     * Decrypting is harder than encrypting because of
-     * the necessity of remembering a lot more things.
-     * Should think about this a little more...
-     */
-
-    if (length <= 0)
-        return;
-
-    /*
-     * Prime the old cipher with ivec.
-     */
-    ip = ivec;
-    GET_HALF_BLOCK(ocipherl, ip);
-    GET_HALF_BLOCK(ocipherr, ip);
-
-    /*
-     * Now do this in earnest until we run out of length.
-     */
-    ip = *in;
-    op = *out;
-    for (;;) {              /* check done inside loop */
-        /*
-         * Read a block from the input into left and
-         * right.  Save this cipher block for later.
-         */
-        GET_HALF_BLOCK(left, ip);
-        GET_HALF_BLOCK(right, ip);
-        cipherl = left;
-        cipherr = right;
-
-        /*
-         * Decrypt this.
-         */
-        DES_DO_DECRYPT(left, right, kp);
-
-        /*
-         * Xor with the old cipher to get plain
-         * text.  Output 8 or less bytes of this.
-         */
-        left ^= ocipherl;
-        right ^= ocipherr;
-        if (length > 8) {
-            length -= 8;
-            PUT_HALF_BLOCK(left, op);
-            PUT_HALF_BLOCK(right, op);
-            /*
-             * Save current cipher block here
-             */
-            ocipherl = cipherl;
-            ocipherr = cipherr;
-        } else {
-            /*
-             * Trouble here.  Start at end of output,
-             * work backwards.
-             */
-            op += (int) length;
-            switch(length) {
-            case 8:
-                *(--op) = (unsigned char) (right & 0xff);
-            case 7:
-                *(--op) = (unsigned char) ((right >> 8) & 0xff);
-            case 6:
-                *(--op) = (unsigned char) ((right >> 16) & 0xff);
-            case 5:
-                *(--op) = (unsigned char) ((right >> 24) & 0xff);
-            case 4:
-                *(--op) = (unsigned char) (left & 0xff);
-            case 3:
-                *(--op) = (unsigned char) ((left >> 8) & 0xff);
-            case 2:
-                *(--op) = (unsigned char) ((left >> 16) & 0xff);
-            case 1:
-                *(--op) = (unsigned char) ((left >> 24) & 0xff);
-                break;
-            }
-            break;          /* we're done */
-        }
-    }
-}
-
-int
-mit_des_cbc_encrypt(const mit_des_cblock *in, mit_des_cblock *out,
-                    unsigned long length, const mit_des_key_schedule schedule,
-                    const mit_des_cblock ivec, int enc)
-{
-    /*
-     * Deal with encryption and decryption separately.
-     */
-    if (enc)
-        des_cbc_encrypt(in, out, length, schedule, ivec);
-    else
-        des_cbc_decrypt(in, out, length, schedule, ivec);
-    return 0;
-}
diff --git a/src/lib/crypto/builtin/des/f_cksum.c b/src/lib/crypto/builtin/des/f_cksum.c
deleted file mode 100644
index 615a947f4a..0000000000
--- a/src/lib/crypto/builtin/des/f_cksum.c
+++ /dev/null
@@ -1,141 +0,0 @@
-/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
-/* lib/crypto/builtin/des/f_cksum.c */
-/*
- * Copyright (C) 1990 by the Massachusetts Institute of Technology.
- * All rights reserved.
- *
- * Export of this software from the United States of America may
- *   require a specific license from the United States Government.
- *   It is the responsibility of any person or organization contemplating
- *   export to obtain such a license before exporting.
- *
- * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
- * distribute this software and its documentation for any purpose and
- * without fee is hereby granted, provided that the above copyright
- * notice appear in all copies and that both that copyright notice and
- * this permission notice appear in supporting documentation, and that
- * the name of M.I.T. not be used in advertising or publicity pertaining
- * to distribution of the software without specific, written prior
- * permission.  Furthermore if you modify this software you must label
- * your software as modified software and not distribute it in such a
- * fashion that it might be confused with the original M.I.T. software.
- * M.I.T. makes no representations about the suitability of
- * this software for any purpose.  It is provided "as is" without express
- * or implied warranty.
- */
-
-/* DES implementation donated by Dennis Ferguson */
-
-/*
- * des_cbc_cksum.c - compute an 8 byte checksum using DES in CBC mode
- */
-#include "crypto_int.h"
-#include "des_int.h"
-#include "f_tables.h"
-
-#ifdef K5_BUILTIN_DES
-
-/*
- * This routine performs DES cipher-block-chaining checksum operation,
- * a.k.a.  Message Authentication Code.  It ALWAYS encrypts from input
- * to a single 64 bit output MAC checksum.
- *
- * The key schedule is passed as an arg, as well as the cleartext or
- * ciphertext. The cleartext and ciphertext should be in host order.
- *
- * NOTE-- the output is ALWAYS 8 bytes long.  If not enough space was
- * provided, your program will get trashed.
- *
- * The input is null padded, at the end (highest addr), to an integral
- * multiple of eight bytes.
- */
-
-unsigned long
-mit_des_cbc_cksum(const krb5_octet *in, krb5_octet *out,
-                  unsigned long length, const mit_des_key_schedule schedule,
-                  const krb5_octet *ivec)
-{
-    unsigned DES_INT32 left, right;
-    const unsigned DES_INT32 *kp;
-    const unsigned char *ip;
-    unsigned char *op;
-    DES_INT32 len;
-
-    /*
-     * Initialize left and right with the contents of the initial
-     * vector.
-     */
-    ip = ivec;
-    GET_HALF_BLOCK(left, ip);
-    GET_HALF_BLOCK(right, ip);
-
-    /*
-     * Suitably initialized, now work the length down 8 bytes
-     * at a time.
-     */
-    ip = in;
-    len = length;
-    while (len > 0) {
-        /*
-         * Get more input, xor it in.  If the length is
-         * greater than or equal to 8 this is straight
-         * forward.  Otherwise we have to fart around.
-         */
-        if (len >= 8) {
-            unsigned DES_INT32 temp;
-            GET_HALF_BLOCK(temp, ip);
-            left  ^= temp;
-            GET_HALF_BLOCK(temp, ip);
-            right ^= temp;
-            len -= 8;
-        } else {
-            /*
-             * Oh, shoot.  We need to pad the
-             * end with zeroes.  Work backwards
-             * to do this.
-             */
-            ip += (int) len;
-            switch(len) {
-            case 7:
-                right ^= (*(--ip) & FF_UINT32) <<  8;
-            case 6:
-                right ^= (*(--ip) & FF_UINT32) << 16;
-            case 5:
-                right ^= (*(--ip) & FF_UINT32) << 24;
-            case 4:
-                left  ^=  *(--ip) & FF_UINT32;
-            case 3:
-                left  ^= (*(--ip) & FF_UINT32) <<  8;
-            case 2:
-                left  ^= (*(--ip) & FF_UINT32) << 16;
-            case 1:
-                left  ^= (*(--ip) & FF_UINT32) << 24;
-                break;
-            }
-            len = 0;
-        }
-
-        /*
-         * Encrypt what we have
-         */
-        kp = (const unsigned DES_INT32 *)schedule;
-        DES_DO_ENCRYPT(left, right, kp);
-    }
-
-    /*
-     * Done.  Left and right have the checksum.  Put it into
-     * the output.
-     */
-    op = out;
-    PUT_HALF_BLOCK(left, op);
-    PUT_HALF_BLOCK(right, op);
-
-    /*
-     * Return right.  I'll bet the MIT code returns this
-     * inconsistantly (with the low order byte of the checksum
-     * not always in the low order byte of the DES_INT32).  We won't.
-     */
-    return right & 0xFFFFFFFFUL;
-}
-
-#endif /* K5_BUILTIN_DES */
diff --git a/src/lib/crypto/builtin/des/f_parity.c b/src/lib/crypto/builtin/des/f_parity.c
deleted file mode 100644
index a658878f6f..0000000000
--- a/src/lib/crypto/builtin/des/f_parity.c
+++ /dev/null
@@ -1,64 +0,0 @@
-/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
-/*
- * These routines check and fix parity of encryption keys for the DES
- * algorithm.
- *
- * They are a replacement for routines in key_parity.c, that don't require
- * the table building that they do.
- *
- * Mark Eichin -- Cygnus Support
- */
-
-#include "crypto_int.h"
-#include "des_int.h"
-
-#ifdef K5_BUILTIN_DES_KEY_PARITY
-
-/*
- * des_fixup_key_parity: Forces odd parity per byte; parity is bits
- *                       8,16,...64 in des order, implies 0, 8, 16, ...
- *                       vax order.
- */
-#define smask(step) ((1<<step)-1)
-#define pstep(x,step) (((x)&smask(step))^(((x)>>step)&smask(step)))
-#define parity_char(x) pstep(pstep(pstep((x),4),2),1)
-
-void
-mit_des_fixup_key_parity(mit_des_cblock key)
-{
-    unsigned int i;
-    for (i=0; i<sizeof(mit_des_cblock); i++)
-    {
-        key[i] &= 0xfe;
-        key[i] |= 1^parity_char(key[i]);
-    }
-
-    return;
-}
-
-#endif /* K5_BUILTIN_DES_KEY_PARITY */
-
-#ifdef K5_BUILTIN_DES
-
-/*
- * des_check_key_parity: returns true iff key has the correct des parity.
- *                       See des_fix_key_parity for the definition of
- *                       correct des parity.
- */
-int
-mit_des_check_key_parity(mit_des_cblock key)
-{
-    unsigned int i;
-
-    for (i=0; i<sizeof(mit_des_cblock); i++)
-    {
-        if((key[i] & 1) == parity_char(0xfe&key[i]))
-        {
-            return 0;
-        }
-    }
-
-    return(1);
-}
-
-#endif /* K5_BUILTIN_DES */
diff --git a/src/lib/crypto/builtin/des/f_sched.c b/src/lib/crypto/builtin/des/f_sched.c
deleted file mode 100644
index bbc88a1c8d..0000000000
--- a/src/lib/crypto/builtin/des/f_sched.c
+++ /dev/null
@@ -1,363 +0,0 @@
-/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
-/* lib/crypto/builtin/des/f_sched.c */
-/*
- * Copyright (C) 1990 by the Massachusetts Institute of Technology.
- * All rights reserved.
- *
- * Export of this software from the United States of America may
- *   require a specific license from the United States Government.
- *   It is the responsibility of any person or organization contemplating
- *   export to obtain such a license before exporting.
- *
- * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
- * distribute this software and its documentation for any purpose and
- * without fee is hereby granted, provided that the above copyright
- * notice appear in all copies and that both that copyright notice and
- * this permission notice appear in supporting documentation, and that
- * the name of M.I.T. not be used in advertising or publicity pertaining
- * to distribution of the software without specific, written prior
- * permission.  Furthermore if you modify this software you must label
- * your software as modified software and not distribute it in such a
- * fashion that it might be confused with the original M.I.T. software.
- * M.I.T. makes no representations about the suitability of
- * this software for any purpose.  It is provided "as is" without express
- * or implied warranty.
- */
-
-/* DES implementation donated by Dennis Ferguson */
-
-/*
- * des_make_sched.c - permute a DES key, returning the resulting key schedule
- */
-#include "crypto_int.h"
-#include "des_int.h"
-
-#ifdef K5_BUILTIN_DES
-
-/*
- * Permuted choice 1 tables.  These are used to extract bits
- * from the left and right parts of the key to form Ci and Di.
- * The code that uses these tables knows which bits from which
- * part of each key are used to form Ci and Di.
- */
-static const unsigned DES_INT32 PC1_CL[8] = {
-    0x00000000, 0x00000010, 0x00001000, 0x00001010,
-    0x00100000, 0x00100010, 0x00101000, 0x00101010
-};
-
-static const unsigned DES_INT32 PC1_DL[16] = {
-    0x00000000, 0x00100000, 0x00001000, 0x00101000,
-    0x00000010, 0x00100010, 0x00001010, 0x00101010,
-    0x00000001, 0x00100001, 0x00001001, 0x00101001,
-    0x00000011, 0x00100011, 0x00001011, 0x00101011
-};
-
-static const unsigned DES_INT32 PC1_CR[16] = {
-    0x00000000, 0x00000001, 0x00000100, 0x00000101,
-    0x00010000, 0x00010001, 0x00010100, 0x00010101,
-    0x01000000, 0x01000001, 0x01000100, 0x01000101,
-    0x01010000, 0x01010001, 0x01010100, 0x01010101
-};
-
-static const unsigned DES_INT32 PC1_DR[8] = {
-    0x00000000, 0x01000000, 0x00010000, 0x01010000,
-    0x00000100, 0x01000100, 0x00010100, 0x01010100
-};
-
-
-/*
- * At the start of some iterations of the key schedule we do
- * a circular left shift by one place, while for others we do a shift by
- * two places.  This has bits set for the iterations where we do 2 bit
- * shifts, starting at the low order bit.
- */
-#define TWO_BIT_SHIFTS  0x7efc
-
-/*
- * Permuted choice 2 tables.  The first actually produces the low order
- * 24 bits of the subkey Ki from the 28 bit value of Ci.  The second produces
- * the high order 24 bits from Di.  The tables are indexed by six bit
- * segments of Ci and Di respectively.  The code is handcrafted to compute
- * the appropriate 6 bit chunks.
- *
- * Note that for ease of computation, the 24 bit values are produced with
- * six bits going into each byte.  Note also that the table has been byte
- * rearranged to produce keys which match the order we will apply them
- * in in the des code.
- */
-static const unsigned DES_INT32 PC2_C[4][64] = {
-    {
-        0x00000000, 0x00000004, 0x00010000, 0x00010004,
-        0x00000400, 0x00000404, 0x00010400, 0x00010404,
-        0x00000020, 0x00000024, 0x00010020, 0x00010024,
-        0x00000420, 0x00000424, 0x00010420, 0x00010424,
-        0x01000000, 0x01000004, 0x01010000, 0x01010004,
-        0x01000400, 0x01000404, 0x01010400, 0x01010404,
-        0x01000020, 0x01000024, 0x01010020, 0x01010024,
-        0x01000420, 0x01000424, 0x01010420, 0x01010424,
-        0x00020000, 0x00020004, 0x00030000, 0x00030004,
-        0x00020400, 0x00020404, 0x00030400, 0x00030404,
-        0x00020020, 0x00020024, 0x00030020, 0x00030024,
-        0x00020420, 0x00020424, 0x00030420, 0x00030424,
-        0x01020000, 0x01020004, 0x01030000, 0x01030004,
-        0x01020400, 0x01020404, 0x01030400, 0x01030404,
-        0x01020020, 0x01020024, 0x01030020, 0x01030024,
-        0x01020420, 0x01020424, 0x01030420, 0x01030424,
-    },
-    {
-        0x00000000, 0x02000000, 0x00000800, 0x02000800,
-        0x00080000, 0x02080000, 0x00080800, 0x02080800,
-        0x00000001, 0x02000001, 0x00000801, 0x02000801,
-        0x00080001, 0x02080001, 0x00080801, 0x02080801,
-        0x00000100, 0x02000100, 0x00000900, 0x02000900,
-        0x00080100, 0x02080100, 0x00080900, 0x02080900,
-        0x00000101, 0x02000101, 0x00000901, 0x02000901,
-        0x00080101, 0x02080101, 0x00080901, 0x02080901,
-        0x10000000, 0x12000000, 0x10000800, 0x12000800,
-        0x10080000, 0x12080000, 0x10080800, 0x12080800,
-        0x10000001, 0x12000001, 0x10000801, 0x12000801,
-        0x10080001, 0x12080001, 0x10080801, 0x12080801,
-        0x10000100, 0x12000100, 0x10000900, 0x12000900,
-        0x10080100, 0x12080100, 0x10080900, 0x12080900,
-        0x10000101, 0x12000101, 0x10000901, 0x12000901,
-        0x10080101, 0x12080101, 0x10080901, 0x12080901,
-    },
-    {
-        0x00000000, 0x00040000, 0x00002000, 0x00042000,
-        0x00100000, 0x00140000, 0x00102000, 0x00142000,
-        0x20000000, 0x20040000, 0x20002000, 0x20042000,
-        0x20100000, 0x20140000, 0x20102000, 0x20142000,
-        0x00000008, 0x00040008, 0x00002008, 0x00042008,
-        0x00100008, 0x00140008, 0x00102008, 0x00142008,
-        0x20000008, 0x20040008, 0x20002008, 0x20042008,
-        0x20100008, 0x20140008, 0x20102008, 0x20142008,
-        0x00200000, 0x00240000, 0x00202000, 0x00242000,
-        0x00300000, 0x00340000, 0x00302000, 0x00342000,
-        0x20200000, 0x20240000, 0x20202000, 0x20242000,
-        0x20300000, 0x20340000, 0x20302000, 0x20342000,
-        0x00200008, 0x00240008, 0x00202008, 0x00242008,
-        0x00300008, 0x00340008, 0x00302008, 0x00342008,
-        0x20200008, 0x20240008, 0x20202008, 0x20242008,
-        0x20300008, 0x20340008, 0x20302008, 0x20342008,
-    },
-    {
-        0x00000000, 0x00000010, 0x08000000, 0x08000010,
-        0x00000200, 0x00000210, 0x08000200, 0x08000210,
-        0x00000002, 0x00000012, 0x08000002, 0x08000012,
-        0x00000202, 0x00000212, 0x08000202, 0x08000212,
-        0x04000000, 0x04000010, 0x0c000000, 0x0c000010,
-        0x04000200, 0x04000210, 0x0c000200, 0x0c000210,
-        0x04000002, 0x04000012, 0x0c000002, 0x0c000012,
-        0x04000202, 0x04000212, 0x0c000202, 0x0c000212,
-        0x00001000, 0x00001010, 0x08001000, 0x08001010,
-        0x00001200, 0x00001210, 0x08001200, 0x08001210,
-        0x00001002, 0x00001012, 0x08001002, 0x08001012,
-        0x00001202, 0x00001212, 0x08001202, 0x08001212,
-        0x04001000, 0x04001010, 0x0c001000, 0x0c001010,
-        0x04001200, 0x04001210, 0x0c001200, 0x0c001210,
-        0x04001002, 0x04001012, 0x0c001002, 0x0c001012,
-        0x04001202, 0x04001212, 0x0c001202, 0x0c001212
-    },
-};
-
-static const unsigned DES_INT32 PC2_D[4][64] = {
-    {
-        0x00000000, 0x02000000, 0x00020000, 0x02020000,
-        0x00000100, 0x02000100, 0x00020100, 0x02020100,
-        0x00000008, 0x02000008, 0x00020008, 0x02020008,
-        0x00000108, 0x02000108, 0x00020108, 0x02020108,
-        0x00200000, 0x02200000, 0x00220000, 0x02220000,
-        0x00200100, 0x02200100, 0x00220100, 0x02220100,
-        0x00200008, 0x02200008, 0x00220008, 0x02220008,
-        0x00200108, 0x02200108, 0x00220108, 0x02220108,
-        0x00000200, 0x02000200, 0x00020200, 0x02020200,
-        0x00000300, 0x02000300, 0x00020300, 0x02020300,
-        0x00000208, 0x02000208, 0x00020208, 0x02020208,
-        0x00000308, 0x02000308, 0x00020308, 0x02020308,
-        0x00200200, 0x02200200, 0x00220200, 0x02220200,
-        0x00200300, 0x02200300, 0x00220300, 0x02220300,
-        0x00200208, 0x02200208, 0x00220208, 0x02220208,
-        0x00200308, 0x02200308, 0x00220308, 0x02220308,
-    },
-    {
-        0x00000000, 0x00001000, 0x00000020, 0x00001020,
-        0x00100000, 0x00101000, 0x00100020, 0x00101020,
-        0x08000000, 0x08001000, 0x08000020, 0x08001020,
-        0x08100000, 0x08101000, 0x08100020, 0x08101020,
-        0x00000004, 0x00001004, 0x00000024, 0x00001024,
-        0x00100004, 0x00101004, 0x00100024, 0x00101024,
-        0x08000004, 0x08001004, 0x08000024, 0x08001024,
-        0x08100004, 0x08101004, 0x08100024, 0x08101024,
-        0x00000400, 0x00001400, 0x00000420, 0x00001420,
-        0x00100400, 0x00101400, 0x00100420, 0x00101420,
-        0x08000400, 0x08001400, 0x08000420, 0x08001420,
-        0x08100400, 0x08101400, 0x08100420, 0x08101420,
-        0x00000404, 0x00001404, 0x00000424, 0x00001424,
-        0x00100404, 0x00101404, 0x00100424, 0x00101424,
-        0x08000404, 0x08001404, 0x08000424, 0x08001424,
-        0x08100404, 0x08101404, 0x08100424, 0x08101424,
-    },
-    {
-        0x00000000, 0x10000000, 0x00010000, 0x10010000,
-        0x00000002, 0x10000002, 0x00010002, 0x10010002,
-        0x00002000, 0x10002000, 0x00012000, 0x10012000,
-        0x00002002, 0x10002002, 0x00012002, 0x10012002,
-        0x00040000, 0x10040000, 0x00050000, 0x10050000,
-        0x00040002, 0x10040002, 0x00050002, 0x10050002,
-        0x00042000, 0x10042000, 0x00052000, 0x10052000,
-        0x00042002, 0x10042002, 0x00052002, 0x10052002,
-        0x20000000, 0x30000000, 0x20010000, 0x30010000,
-        0x20000002, 0x30000002, 0x20010002, 0x30010002,
-        0x20002000, 0x30002000, 0x20012000, 0x30012000,
-        0x20002002, 0x30002002, 0x20012002, 0x30012002,
-        0x20040000, 0x30040000, 0x20050000, 0x30050000,
-        0x20040002, 0x30040002, 0x20050002, 0x30050002,
-        0x20042000, 0x30042000, 0x20052000, 0x30052000,
-        0x20042002, 0x30042002, 0x20052002, 0x30052002,
-    },
-    {
-        0x00000000, 0x04000000, 0x00000001, 0x04000001,
-        0x01000000, 0x05000000, 0x01000001, 0x05000001,
-        0x00000010, 0x04000010, 0x00000011, 0x04000011,
-        0x01000010, 0x05000010, 0x01000011, 0x05000011,
-        0x00080000, 0x04080000, 0x00080001, 0x04080001,
-        0x01080000, 0x05080000, 0x01080001, 0x05080001,
-        0x00080010, 0x04080010, 0x00080011, 0x04080011,
-        0x01080010, 0x05080010, 0x01080011, 0x05080011,
-        0x00000800, 0x04000800, 0x00000801, 0x04000801,
-        0x01000800, 0x05000800, 0x01000801, 0x05000801,
-        0x00000810, 0x04000810, 0x00000811, 0x04000811,
-        0x01000810, 0x05000810, 0x01000811, 0x05000811,
-        0x00080800, 0x04080800, 0x00080801, 0x04080801,
-        0x01080800, 0x05080800, 0x01080801, 0x05080801,
-        0x00080810, 0x04080810, 0x00080811, 0x04080811,
-        0x01080810, 0x05080810, 0x01080811, 0x05080811
-    },
-};
-
-
-
-/*
- * Permute the key to give us our key schedule.
- */
-int
-mit_des_make_key_sched(mit_des_cblock key, mit_des_key_schedule schedule)
-{
-    unsigned DES_INT32 c, d;
-
-    {
-        /*
-         * Need a pointer for the keys and a temporary DES_INT32
-         */
-        const unsigned char *k;
-        unsigned DES_INT32 tmp;
-
-        /*
-         * Fetch the key into something we can work with
-         */
-        k = key;
-
-        /*
-         * The first permutted choice gives us the 28 bits for C0 and
-         * 28 for D0.  C0 gets 12 bits from the left key and 16 from
-         * the right, while D0 gets 16 from the left and 12 from the
-         * right.  The code knows which bits go where.
-         */
-        tmp = load_32_be(k), k += 4;
-
-        c =  PC1_CL[(tmp >> 29) & 0x7]
-            | (PC1_CL[(tmp >> 21) & 0x7] << 1)
-            | (PC1_CL[(tmp >> 13) & 0x7] << 2)
-            | (PC1_CL[(tmp >>  5) & 0x7] << 3);
-        d =  PC1_DL[(tmp >> 25) & 0xf]
-            | (PC1_DL[(tmp >> 17) & 0xf] << 1)
-            | (PC1_DL[(tmp >>  9) & 0xf] << 2)
-            | (PC1_DL[(tmp >>  1) & 0xf] << 3);
-
-        tmp = load_32_be(k), k += 4;
-
-        c |= PC1_CR[(tmp >> 28) & 0xf]
-            | (PC1_CR[(tmp >> 20) & 0xf] << 1)
-            | (PC1_CR[(tmp >> 12) & 0xf] << 2)
-            | (PC1_CR[(tmp >>  4) & 0xf] << 3);
-        d |= PC1_DR[(tmp >> 25) & 0x7]
-            | (PC1_DR[(tmp >> 17) & 0x7] << 1)
-            | (PC1_DR[(tmp >>  9) & 0x7] << 2)
-            | (PC1_DR[(tmp >>  1) & 0x7] << 3);
-    }
-
-    {
-        /*
-         * Need several temporaries in here
-         */
-        unsigned DES_INT32 ltmp, rtmp;
-        unsigned DES_INT32 *k;
-        int two_bit_shifts;
-        int i;
-        /*
-         * Now iterate to compute the key schedule.  Note that we
-         * record the entire set of subkeys in 6 bit chunks since
-         * they are used that way.  At 6 bits/char, we need
-         * 48/6 char's/subkey * 16 subkeys/encryption == 128 bytes.
-         * The schedule must be this big.
-         */
-        k = (unsigned DES_INT32 *)schedule;
-        two_bit_shifts = TWO_BIT_SHIFTS;
-        for (i = 16; i > 0; i--) {
-            /*
-             * Do the rotation.  One bit and two bit rotations
-             * are done separately.  Note C and D are 28 bits.
-             */
-            if (two_bit_shifts & 0x1) {
-                c = ((c << 2) & 0xffffffc) | (c >> 26);
-                d = ((d << 2) & 0xffffffc) | (d >> 26);
-            } else {
-                c = ((c << 1) & 0xffffffe) | (c >> 27);
-                d = ((d << 1) & 0xffffffe) | (d >> 27);
-            }
-            two_bit_shifts >>= 1;
-
-            /*
-             * Apply permutted choice 2 to C to get the first
-             * 24 bits worth of keys.  Note that bits 9, 18, 22
-             * and 25 (using DES numbering) in C are unused.  The
-             * shift-mask stuff is done to delete these bits from
-             * the indices, since this cuts the table size in half.
-             *
-             * The table is torqued, by the way.  If the standard
-             * byte order for this (high to low order) is 1234,
-             * the table actually gives us 4132.
-             */
-            ltmp = PC2_C[0][((c >> 22) & 0x3f)]
-                | PC2_C[1][((c >> 15) & 0xf) | ((c >> 16) & 0x30)]
-                | PC2_C[2][((c >>  4) & 0x3) | ((c >>  9) & 0x3c)]
-                | PC2_C[3][((c      ) & 0x7) | ((c >>  4) & 0x38)];
-            /*
-             * Apply permutted choice 2 to D to get the other half.
-             * Here, bits 7, 10, 15 and 26 go unused.  The sqeezing
-             * actually turns out to be cheaper here.
-             *
-             * This table is similarly torqued.  If the standard
-             * byte order is 5678, the table has the bytes permuted
-             * to give us 7685.
-             */
-            rtmp = PC2_D[0][((d >> 22) & 0x3f)]
-                | PC2_D[1][((d >> 14) & 0xf) | ((d >> 15) & 0x30)]
-                | PC2_D[2][((d >>  7) & 0x3f)]
-                | PC2_D[3][((d      ) & 0x3) | ((d >>  1) & 0x3c)];
-
-            /*
-             * Make up two words of the key schedule, with a
-             * byte order which is convenient for the DES
-             * inner loop.  The high order (first) word will
-             * hold bytes 7135 (high to low order) while the
-             * second holds bytes 4682.
-             */
-            *k++ = (ltmp & 0x00ffff00) | (rtmp & 0xff0000ff);
-            *k++ = (ltmp & 0xff0000ff) | (rtmp & 0x00ffff00);
-        }
-    }
-    return (0);
-}
-
-#endif /* K5_BUILTIN_DES */
diff --git a/src/lib/crypto/builtin/des/f_tables.c b/src/lib/crypto/builtin/des/f_tables.c
deleted file mode 100644
index e50ab1fc60..0000000000
--- a/src/lib/crypto/builtin/des/f_tables.c
+++ /dev/null
@@ -1,375 +0,0 @@
-/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
-/* lib/crypto/builtin/des/f_tables.c */
-/*
- * Copyright (C) 1990 by the Massachusetts Institute of Technology.
- * All rights reserved.
- *
- * Export of this software from the United States of America may
- *   require a specific license from the United States Government.
- *   It is the responsibility of any person or organization contemplating
- *   export to obtain such a license before exporting.
- *
- * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
- * distribute this software and its documentation for any purpose and
- * without fee is hereby granted, provided that the above copyright
- * notice appear in all copies and that both that copyright notice and
- * this permission notice appear in supporting documentation, and that
- * the name of M.I.T. not be used in advertising or publicity pertaining
- * to distribution of the software without specific, written prior
- * permission.  Furthermore if you modify this software you must label
- * your software as modified software and not distribute it in such a
- * fashion that it might be confused with the original M.I.T. software.
- * M.I.T. makes no representations about the suitability of
- * this software for any purpose.  It is provided "as is" without express
- * or implied warranty.
- */
-
-/* DES implementation donated by Dennis Ferguson */
-
-/*
- * des_tables.c - precomputed tables used for the DES cipher function
- */
-
-/*
- * Include the header file so something will complain if the
- * declarations get out of sync
- */
-#include "crypto_int.h"
-#include "des_int.h"
-#include "f_tables.h"
-
-#ifdef K5_BUILTIN_DES
-
-/*
- * These tables may be declared const if you want.  Many compilers
- * don't support this, though.
- */
-
-/*
- * The DES algorithm which uses these is intended to be fairly speedy
- * at the expense of some memory.  All the standard hacks are used.
- * The S boxes and the P permutation are precomputed into one table.
- * The E box never actually appears explicitly since it is easy to apply
- * this algorithmically as needed.  The initial permutation and final
- * (inverse initial) permutation are computed from tables designed to
- * permute one byte at a time.  This should run pretty fast on machines
- * with 32 bit words and bit field/multiple bit shift instructions which
- * are fast.
- */
-
-/*
- * The initial permutation array.  This is used to compute both the
- * left and the right halves of the initial permutation using bytes
- * from words made from the following operations:
- *
- * ((left & 0x55555555) << 1) | (right & 0x55555555)  for left half
- * (left & 0xaaaaaaaa) | ((right & 0xaaaaaaaa) >> 1)  for right half
- *
- * The scheme is that we index into the table using each byte.  The
- * result from the high order byte is or'd with the result from the
- * next byte shifted left once is or'd with the result from the next
- * byte shifted left twice if or'd with the result from the low order
- * byte shifted left by three.  Clear?
- */
-
-const unsigned DES_INT32 des_IP_table[256] = {
-    0x00000000, 0x00000010, 0x00000001, 0x00000011,
-    0x00001000, 0x00001010, 0x00001001, 0x00001011,
-    0x00000100, 0x00000110, 0x00000101, 0x00000111,
-    0x00001100, 0x00001110, 0x00001101, 0x00001111,
-    0x00100000, 0x00100010, 0x00100001, 0x00100011,
-    0x00101000, 0x00101010, 0x00101001, 0x00101011,
-    0x00100100, 0x00100110, 0x00100101, 0x00100111,
-    0x00101100, 0x00101110, 0x00101101, 0x00101111,
-    0x00010000, 0x00010010, 0x00010001, 0x00010011,
-    0x00011000, 0x00011010, 0x00011001, 0x00011011,
-    0x00010100, 0x00010110, 0x00010101, 0x00010111,
-    0x00011100, 0x00011110, 0x00011101, 0x00011111,
-    0x00110000, 0x00110010, 0x00110001, 0x00110011,
-    0x00111000, 0x00111010, 0x00111001, 0x00111011,
-    0x00110100, 0x00110110, 0x00110101, 0x00110111,
-    0x00111100, 0x00111110, 0x00111101, 0x00111111,
-    0x10000000, 0x10000010, 0x10000001, 0x10000011,
-    0x10001000, 0x10001010, 0x10001001, 0x10001011,
-    0x10000100, 0x10000110, 0x10000101, 0x10000111,
-    0x10001100, 0x10001110, 0x10001101, 0x10001111,
-    0x10100000, 0x10100010, 0x10100001, 0x10100011,
-    0x10101000, 0x10101010, 0x10101001, 0x10101011,
-    0x10100100, 0x10100110, 0x10100101, 0x10100111,
-    0x10101100, 0x10101110, 0x10101101, 0x10101111,
-    0x10010000, 0x10010010, 0x10010001, 0x10010011,
-    0x10011000, 0x10011010, 0x10011001, 0x10011011,
-    0x10010100, 0x10010110, 0x10010101, 0x10010111,
-    0x10011100, 0x10011110, 0x10011101, 0x10011111,
-    0x10110000, 0x10110010, 0x10110001, 0x10110011,
-    0x10111000, 0x10111010, 0x10111001, 0x10111011,
-    0x10110100, 0x10110110, 0x10110101, 0x10110111,
-    0x10111100, 0x10111110, 0x10111101, 0x10111111,
-    0x01000000, 0x01000010, 0x01000001, 0x01000011,
-    0x01001000, 0x01001010, 0x01001001, 0x01001011,
-    0x01000100, 0x01000110, 0x01000101, 0x01000111,
-    0x01001100, 0x01001110, 0x01001101, 0x01001111,
-    0x01100000, 0x01100010, 0x01100001, 0x01100011,
-    0x01101000, 0x01101010, 0x01101001, 0x01101011,
-    0x01100100, 0x01100110, 0x01100101, 0x01100111,
-    0x01101100, 0x01101110, 0x01101101, 0x01101111,
-    0x01010000, 0x01010010, 0x01010001, 0x01010011,
-    0x01011000, 0x01011010, 0x01011001, 0x01011011,
-    0x01010100, 0x01010110, 0x01010101, 0x01010111,
-    0x01011100, 0x01011110, 0x01011101, 0x01011111,
-    0x01110000, 0x01110010, 0x01110001, 0x01110011,
-    0x01111000, 0x01111010, 0x01111001, 0x01111011,
-    0x01110100, 0x01110110, 0x01110101, 0x01110111,
-    0x01111100, 0x01111110, 0x01111101, 0x01111111,
-    0x11000000, 0x11000010, 0x11000001, 0x11000011,
-    0x11001000, 0x11001010, 0x11001001, 0x11001011,
-    0x11000100, 0x11000110, 0x11000101, 0x11000111,
-    0x11001100, 0x11001110, 0x11001101, 0x11001111,
-    0x11100000, 0x11100010, 0x11100001, 0x11100011,
-    0x11101000, 0x11101010, 0x11101001, 0x11101011,
-    0x11100100, 0x11100110, 0x11100101, 0x11100111,
-    0x11101100, 0x11101110, 0x11101101, 0x11101111,
-    0x11010000, 0x11010010, 0x11010001, 0x11010011,
-    0x11011000, 0x11011010, 0x11011001, 0x11011011,
-    0x11010100, 0x11010110, 0x11010101, 0x11010111,
-    0x11011100, 0x11011110, 0x11011101, 0x11011111,
-    0x11110000, 0x11110010, 0x11110001, 0x11110011,
-    0x11111000, 0x11111010, 0x11111001, 0x11111011,
-    0x11110100, 0x11110110, 0x11110101, 0x11110111,
-    0x11111100, 0x11111110, 0x11111101, 0x11111111
-};
-
-/*
- * The final permutation array.  Like the IP array, used
- * to compute both the left and right results from the bytes
- * of words computed from:
- *
- * ((left & 0x0f0f0f0f) << 4) | (right & 0x0f0f0f0f)  for left result
- * (left & 0xf0f0f0f0) | ((right & 0xf0f0f0f0) >> 4)  for right result
- *
- * The result from the high order byte is shifted left 6 bits and
- * or'd with the result from the next byte shifted left 4 bits, which
- * is or'd with the result from the next byte shifted left 2 bits,
- * which is or'd with the result from the low byte.
- */
-const unsigned DES_INT32 des_FP_table[256] = {
-    0x00000000, 0x02000000, 0x00020000, 0x02020000,
-    0x00000200, 0x02000200, 0x00020200, 0x02020200,
-    0x00000002, 0x02000002, 0x00020002, 0x02020002,
-    0x00000202, 0x02000202, 0x00020202, 0x02020202,
-    0x01000000, 0x03000000, 0x01020000, 0x03020000,
-    0x01000200, 0x03000200, 0x01020200, 0x03020200,
-    0x01000002, 0x03000002, 0x01020002, 0x03020002,
-    0x01000202, 0x03000202, 0x01020202, 0x03020202,
-    0x00010000, 0x02010000, 0x00030000, 0x02030000,
-    0x00010200, 0x02010200, 0x00030200, 0x02030200,
-    0x00010002, 0x02010002, 0x00030002, 0x02030002,
-    0x00010202, 0x02010202, 0x00030202, 0x02030202,
-    0x01010000, 0x03010000, 0x01030000, 0x03030000,
-    0x01010200, 0x03010200, 0x01030200, 0x03030200,
-    0x01010002, 0x03010002, 0x01030002, 0x03030002,
-    0x01010202, 0x03010202, 0x01030202, 0x03030202,
-    0x00000100, 0x02000100, 0x00020100, 0x02020100,
-    0x00000300, 0x02000300, 0x00020300, 0x02020300,
-    0x00000102, 0x02000102, 0x00020102, 0x02020102,
-    0x00000302, 0x02000302, 0x00020302, 0x02020302,
-    0x01000100, 0x03000100, 0x01020100, 0x03020100,
-    0x01000300, 0x03000300, 0x01020300, 0x03020300,
-    0x01000102, 0x03000102, 0x01020102, 0x03020102,
-    0x01000302, 0x03000302, 0x01020302, 0x03020302,
-    0x00010100, 0x02010100, 0x00030100, 0x02030100,
-    0x00010300, 0x02010300, 0x00030300, 0x02030300,
-    0x00010102, 0x02010102, 0x00030102, 0x02030102,
-    0x00010302, 0x02010302, 0x00030302, 0x02030302,
-    0x01010100, 0x03010100, 0x01030100, 0x03030100,
-    0x01010300, 0x03010300, 0x01030300, 0x03030300,
-    0x01010102, 0x03010102, 0x01030102, 0x03030102,
-    0x01010302, 0x03010302, 0x01030302, 0x03030302,
-    0x00000001, 0x02000001, 0x00020001, 0x02020001,
-    0x00000201, 0x02000201, 0x00020201, 0x02020201,
-    0x00000003, 0x02000003, 0x00020003, 0x02020003,
-    0x00000203, 0x02000203, 0x00020203, 0x02020203,
-    0x01000001, 0x03000001, 0x01020001, 0x03020001,
-    0x01000201, 0x03000201, 0x01020201, 0x03020201,
-    0x01000003, 0x03000003, 0x01020003, 0x03020003,
-    0x01000203, 0x03000203, 0x01020203, 0x03020203,
-    0x00010001, 0x02010001, 0x00030001, 0x02030001,
-    0x00010201, 0x02010201, 0x00030201, 0x02030201,
-    0x00010003, 0x02010003, 0x00030003, 0x02030003,
-    0x00010203, 0x02010203, 0x00030203, 0x02030203,
-    0x01010001, 0x03010001, 0x01030001, 0x03030001,
-    0x01010201, 0x03010201, 0x01030201, 0x03030201,
-    0x01010003, 0x03010003, 0x01030003, 0x03030003,
-    0x01010203, 0x03010203, 0x01030203, 0x03030203,
-    0x00000101, 0x02000101, 0x00020101, 0x02020101,
-    0x00000301, 0x02000301, 0x00020301, 0x02020301,
-    0x00000103, 0x02000103, 0x00020103, 0x02020103,
-    0x00000303, 0x02000303, 0x00020303, 0x02020303,
-    0x01000101, 0x03000101, 0x01020101, 0x03020101,
-    0x01000301, 0x03000301, 0x01020301, 0x03020301,
-    0x01000103, 0x03000103, 0x01020103, 0x03020103,
-    0x01000303, 0x03000303, 0x01020303, 0x03020303,
-    0x00010101, 0x02010101, 0x00030101, 0x02030101,
-    0x00010301, 0x02010301, 0x00030301, 0x02030301,
-    0x00010103, 0x02010103, 0x00030103, 0x02030103,
-    0x00010303, 0x02010303, 0x00030303, 0x02030303,
-    0x01010101, 0x03010101, 0x01030101, 0x03030101,
-    0x01010301, 0x03010301, 0x01030301, 0x03030301,
-    0x01010103, 0x03010103, 0x01030103, 0x03030103,
-    0x01010303, 0x03010303, 0x01030303, 0x03030303
-};
-
-
-/*
- * The SP table is actually the S boxes and the P permutation
- * table combined.  This table is actually reordered from the
- * spec, to match the order of key application we follow.
- */
-const unsigned DES_INT32 des_SP_table[8][64] = {
-    {
-        0x00100000, 0x02100001, 0x02000401, 0x00000000, /* 7 */
-        0x00000400, 0x02000401, 0x00100401, 0x02100400,
-        0x02100401, 0x00100000, 0x00000000, 0x02000001,
-        0x00000001, 0x02000000, 0x02100001, 0x00000401,
-        0x02000400, 0x00100401, 0x00100001, 0x02000400,
-        0x02000001, 0x02100000, 0x02100400, 0x00100001,
-        0x02100000, 0x00000400, 0x00000401, 0x02100401,
-        0x00100400, 0x00000001, 0x02000000, 0x00100400,
-        0x02000000, 0x00100400, 0x00100000, 0x02000401,
-        0x02000401, 0x02100001, 0x02100001, 0x00000001,
-        0x00100001, 0x02000000, 0x02000400, 0x00100000,
-        0x02100400, 0x00000401, 0x00100401, 0x02100400,
-        0x00000401, 0x02000001, 0x02100401, 0x02100000,
-        0x00100400, 0x00000000, 0x00000001, 0x02100401,
-        0x00000000, 0x00100401, 0x02100000, 0x00000400,
-        0x02000001, 0x02000400, 0x00000400, 0x00100001,
-    },
-    {
-        0x00808200, 0x00000000, 0x00008000, 0x00808202, /* 1 */
-        0x00808002, 0x00008202, 0x00000002, 0x00008000,
-        0x00000200, 0x00808200, 0x00808202, 0x00000200,
-        0x00800202, 0x00808002, 0x00800000, 0x00000002,
-        0x00000202, 0x00800200, 0x00800200, 0x00008200,
-        0x00008200, 0x00808000, 0x00808000, 0x00800202,
-        0x00008002, 0x00800002, 0x00800002, 0x00008002,
-        0x00000000, 0x00000202, 0x00008202, 0x00800000,
-        0x00008000, 0x00808202, 0x00000002, 0x00808000,
-        0x00808200, 0x00800000, 0x00800000, 0x00000200,
-        0x00808002, 0x00008000, 0x00008200, 0x00800002,
-        0x00000200, 0x00000002, 0x00800202, 0x00008202,
-        0x00808202, 0x00008002, 0x00808000, 0x00800202,
-        0x00800002, 0x00000202, 0x00008202, 0x00808200,
-        0x00000202, 0x00800200, 0x00800200, 0x00000000,
-        0x00008002, 0x00008200, 0x00000000, 0x00808002,
-    },
-    {
-        0x00000104, 0x04010100, 0x00000000, 0x04010004, /* 3 */
-        0x04000100, 0x00000000, 0x00010104, 0x04000100,
-        0x00010004, 0x04000004, 0x04000004, 0x00010000,
-        0x04010104, 0x00010004, 0x04010000, 0x00000104,
-        0x04000000, 0x00000004, 0x04010100, 0x00000100,
-        0x00010100, 0x04010000, 0x04010004, 0x00010104,
-        0x04000104, 0x00010100, 0x00010000, 0x04000104,
-        0x00000004, 0x04010104, 0x00000100, 0x04000000,
-        0x04010100, 0x04000000, 0x00010004, 0x00000104,
-        0x00010000, 0x04010100, 0x04000100, 0x00000000,
-        0x00000100, 0x00010004, 0x04010104, 0x04000100,
-        0x04000004, 0x00000100, 0x00000000, 0x04010004,
-        0x04000104, 0x00010000, 0x04000000, 0x04010104,
-        0x00000004, 0x00010104, 0x00010100, 0x04000004,
-        0x04010000, 0x04000104, 0x00000104, 0x04010000,
-        0x00010104, 0x00000004, 0x04010004, 0x00010100,
-    },
-    {
-        0x00000080, 0x01040080, 0x01040000, 0x21000080, /* 5 */
-        0x00040000, 0x00000080, 0x20000000, 0x01040000,
-        0x20040080, 0x00040000, 0x01000080, 0x20040080,
-        0x21000080, 0x21040000, 0x00040080, 0x20000000,
-        0x01000000, 0x20040000, 0x20040000, 0x00000000,
-        0x20000080, 0x21040080, 0x21040080, 0x01000080,
-        0x21040000, 0x20000080, 0x00000000, 0x21000000,
-        0x01040080, 0x01000000, 0x21000000, 0x00040080,
-        0x00040000, 0x21000080, 0x00000080, 0x01000000,
-        0x20000000, 0x01040000, 0x21000080, 0x20040080,
-        0x01000080, 0x20000000, 0x21040000, 0x01040080,
-        0x20040080, 0x00000080, 0x01000000, 0x21040000,
-        0x21040080, 0x00040080, 0x21000000, 0x21040080,
-        0x01040000, 0x00000000, 0x20040000, 0x21000000,
-        0x00040080, 0x01000080, 0x20000080, 0x00040000,
-        0x00000000, 0x20040000, 0x01040080, 0x20000080,
-    },
-    {
-        0x80401000, 0x80001040, 0x80001040, 0x00000040, /* 4 */
-        0x00401040, 0x80400040, 0x80400000, 0x80001000,
-        0x00000000, 0x00401000, 0x00401000, 0x80401040,
-        0x80000040, 0x00000000, 0x00400040, 0x80400000,
-        0x80000000, 0x00001000, 0x00400000, 0x80401000,
-        0x00000040, 0x00400000, 0x80001000, 0x00001040,
-        0x80400040, 0x80000000, 0x00001040, 0x00400040,
-        0x00001000, 0x00401040, 0x80401040, 0x80000040,
-        0x00400040, 0x80400000, 0x00401000, 0x80401040,
-        0x80000040, 0x00000000, 0x00000000, 0x00401000,
-        0x00001040, 0x00400040, 0x80400040, 0x80000000,
-        0x80401000, 0x80001040, 0x80001040, 0x00000040,
-        0x80401040, 0x80000040, 0x80000000, 0x00001000,
-        0x80400000, 0x80001000, 0x00401040, 0x80400040,
-        0x80001000, 0x00001040, 0x00400000, 0x80401000,
-        0x00000040, 0x00400000, 0x00001000, 0x00401040,
-    },
-    {
-        0x10000008, 0x10200000, 0x00002000, 0x10202008, /* 6 */
-        0x10200000, 0x00000008, 0x10202008, 0x00200000,
-        0x10002000, 0x00202008, 0x00200000, 0x10000008,
-        0x00200008, 0x10002000, 0x10000000, 0x00002008,
-        0x00000000, 0x00200008, 0x10002008, 0x00002000,
-        0x00202000, 0x10002008, 0x00000008, 0x10200008,
-        0x10200008, 0x00000000, 0x00202008, 0x10202000,
-        0x00002008, 0x00202000, 0x10202000, 0x10000000,
-        0x10002000, 0x00000008, 0x10200008, 0x00202000,
-        0x10202008, 0x00200000, 0x00002008, 0x10000008,
-        0x00200000, 0x10002000, 0x10000000, 0x00002008,
-        0x10000008, 0x10202008, 0x00202000, 0x10200000,
-        0x00202008, 0x10202000, 0x00000000, 0x10200008,
-        0x00000008, 0x00002000, 0x10200000, 0x00202008,
-        0x00002000, 0x00200008, 0x10002008, 0x00000000,
-        0x10202000, 0x10000000, 0x00200008, 0x10002008,
-    },
-    {
-        0x08000820, 0x00000800, 0x00020000, 0x08020820, /* 8 */
-        0x08000000, 0x08000820, 0x00000020, 0x08000000,
-        0x00020020, 0x08020000, 0x08020820, 0x00020800,
-        0x08020800, 0x00020820, 0x00000800, 0x00000020,
-        0x08020000, 0x08000020, 0x08000800, 0x00000820,
-        0x00020800, 0x00020020, 0x08020020, 0x08020800,
-        0x00000820, 0x00000000, 0x00000000, 0x08020020,
-        0x08000020, 0x08000800, 0x00020820, 0x00020000,
-        0x00020820, 0x00020000, 0x08020800, 0x00000800,
-        0x00000020, 0x08020020, 0x00000800, 0x00020820,
-        0x08000800, 0x00000020, 0x08000020, 0x08020000,
-        0x08020020, 0x08000000, 0x00020000, 0x08000820,
-        0x00000000, 0x08020820, 0x00020020, 0x08000020,
-        0x08020000, 0x08000800, 0x08000820, 0x00000000,
-        0x08020820, 0x00020800, 0x00020800, 0x00000820,
-        0x00000820, 0x00020020, 0x08000000, 0x08020800,
-    },
-    {
-        0x40084010, 0x40004000, 0x00004000, 0x00084010, /* 2 */
-        0x00080000, 0x00000010, 0x40080010, 0x40004010,
-        0x40000010, 0x40084010, 0x40084000, 0x40000000,
-        0x40004000, 0x00080000, 0x00000010, 0x40080010,
-        0x00084000, 0x00080010, 0x40004010, 0x00000000,
-        0x40000000, 0x00004000, 0x00084010, 0x40080000,
-        0x00080010, 0x40000010, 0x00000000, 0x00084000,
-        0x00004010, 0x40084000, 0x40080000, 0x00004010,
-        0x00000000, 0x00084010, 0x40080010, 0x00080000,
-        0x40004010, 0x40080000, 0x40084000, 0x00004000,
-        0x40080000, 0x40004000, 0x00000010, 0x40084010,
-        0x00084010, 0x00000010, 0x00004000, 0x40000000,
-        0x00004010, 0x40084000, 0x00080000, 0x40000010,
-        0x00080010, 0x40004010, 0x40000010, 0x00080010,
-        0x00084000, 0x00000000, 0x40004000, 0x00004010,
-        0x40000000, 0x40080010, 0x40084010, 0x00084000
-    },
-};
-
-#endif /* K5_BUILTIN_DES */
diff --git a/src/lib/crypto/builtin/des/f_tables.h b/src/lib/crypto/builtin/des/f_tables.h
deleted file mode 100644
index fc91b566cf..0000000000
--- a/src/lib/crypto/builtin/des/f_tables.h
+++ /dev/null
@@ -1,285 +0,0 @@
-/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
-/* lib/crypto/builtin/des/f_tables.h */
-/*
- * Copyright (C) 1990 by the Massachusetts Institute of Technology.
- * All rights reserved.
- *
- * Export of this software from the United States of America may
- *   require a specific license from the United States Government.
- *   It is the responsibility of any person or organization contemplating
- *   export to obtain such a license before exporting.
- *
- * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
- * distribute this software and its documentation for any purpose and
- * without fee is hereby granted, provided that the above copyright
- * notice appear in all copies and that both that copyright notice and
- * this permission notice appear in supporting documentation, and that
- * the name of M.I.T. not be used in advertising or publicity pertaining
- * to distribution of the software without specific, written prior
- * permission.  Furthermore if you modify this software you must label
- * your software as modified software and not distribute it in such a
- * fashion that it might be confused with the original M.I.T. software.
- * M.I.T. makes no representations about the suitability of
- * this software for any purpose.  It is provided "as is" without express
- * or implied warranty.
- */
-
-/*
- * DES implementation donated by Dennis Ferguson
- */
-
-/*
- * des_tables.h - declarations to import the DES tables, used internally
- *                by some of the library routines.
- */
-#ifndef __DES_TABLES_H__
-#define __DES_TABLES_H__        /* nothing */
-
-#include "k5-platform.h"
-/*
- * These may be declared const if you wish.  Be sure to change the
- * declarations in des_tables.c as well.
- */
-extern const unsigned DES_INT32 des_IP_table[256];
-extern const unsigned DES_INT32 des_FP_table[256];
-extern const unsigned DES_INT32 des_SP_table[8][64];
-
-/*
- * Use standard shortforms to reference these to save typing
- */
-#define IP      des_IP_table
-#define FP      des_FP_table
-#define SP      des_SP_table
-
-#ifdef DEBUG
-#define DEB(foofraw)    printf foofraw
-#else
-#define DEB(foofraw)    /* nothing */
-#endif
-
-/*
- * Code to do a DES round using the tables.  Note that the E expansion
- * is easy to compute algorithmically, especially if done out-of-order.
- * Take a look at its form and compare it to everything involving temp
- * below.  Since SP[0-7] don't have any bits in common set it is okay
- * to do the successive xor's.
- *
- * Note too that the SP table has been reordered to match the order of
- * the keys (if the original order of SP was 12345678, the reordered
- * table is 71354682).  This is unnecessary, but was done since some
- * compilers seem to like you going through the matrix from beginning
- * to end.
- *
- * There is a difference in the best way to do this depending on whether
- * one is encrypting or decrypting.  If encrypting we move forward through
- * the keys and hence should move forward through the table.  If decrypting
- * we go back.  Part of the need for this comes from trying to emulate
- * existing software which generates a single key schedule and uses it
- * both for encrypting and decrypting.  Generating separate encryption
- * and decryption key schedules would allow one to use the same code
- * for both.
- *
- * left, right and temp should be unsigned DES_INT32 values.  left and right
- * should be the high and low order parts of the cipher block at the
- * current stage of processing (this makes sense if you read the spec).
- * kp should be an unsigned DES_INT32 pointer which points at the current
- * set of subkeys in the key schedule.  It is advanced to the next set
- * (i.e. by 8 bytes) when this is done.
- *
- * This occurs in the innermost loop of the DES function.  The four
- * variables should really be in registers.
- *
- * When using this, the inner loop of the DES function might look like:
- *
- *      for (i = 0; i < 8; i++) {
- *              DES_SP_{EN,DE}CRYPT_ROUND(left, right, temp, kp);
- *              DES_SP_{EN,DE}CRYPT_ROUND(right, left, temp, kp);
- *      }
- *
- * Note the trick above.  You are supposed to do 16 rounds, swapping
- * left and right at the end of each round.  By doing two rounds at
- * a time and swapping left and right in the code we can avoid the
- * swaps altogether.
- */
-#define DES_SP_ENCRYPT_ROUND(left, right, temp, kp) do {        \
-        (temp) = (((right) >> 11) | ((right) << 21)) ^ *(kp)++; \
-        (left) ^= SP[0][((temp) >> 24) & 0x3f]                  \
-            | SP[1][((temp) >> 16) & 0x3f]                      \
-            | SP[2][((temp) >>  8) & 0x3f]                      \
-            | SP[3][((temp)      ) & 0x3f];                     \
-        (temp) = (((right) >> 23) | ((right) << 9)) ^ *(kp)++;  \
-        (left) ^= SP[4][((temp) >> 24) & 0x3f]                  \
-            | SP[5][((temp) >> 16) & 0x3f]                      \
-            | SP[6][((temp) >>  8) & 0x3f]                      \
-            | SP[7][((temp)      ) & 0x3f];                     \
-    } while(0);
-
-#define DES_SP_DECRYPT_ROUND(left, right, temp, kp) do {                \
-        (temp) = (((right) >> 23) | ((right) << 9)) ^ *(--(kp));        \
-        (left) ^= SP[7][((temp)      ) & 0x3f]                          \
-            | SP[6][((temp) >>  8) & 0x3f]                              \
-            | SP[5][((temp) >> 16) & 0x3f]                              \
-            | SP[4][((temp) >> 24) & 0x3f];                             \
-        (temp) = (((right) >> 11) | ((right) << 21)) ^ *(--(kp));       \
-        (left) ^= SP[3][((temp)      ) & 0x3f]                          \
-            | SP[2][((temp) >>  8) & 0x3f]                              \
-            | SP[1][((temp) >> 16) & 0x3f]                              \
-            | SP[0][((temp) >> 24) & 0x3f];                             \
-    } while (0);
-
-/*
- * Macros to help deal with the initial permutation table.  Note
- * the IP table only deals with 32 bits at a time, allowing us to
- * collect the bits we need to deal with each half into an unsigned
- * DES_INT32.  By carefully selecting how the bits are ordered we also
- * take advantages of symmetries in the table so that we can use a
- * single table to compute the permutation of all bytes.  This sounds
- * complicated, but if you go through the process of designing the
- * table you'll find the symmetries fall right out.
- *
- * The follow macros compute the set of bits used to index the
- * table for produce the left and right permuted result.
- *
- * The inserted cast to unsigned DES_INT32 circumvents a bug in
- * the Macintosh MPW 3.2 C compiler which loses the unsignedness and
- * propagates the high-order bit in the shift.
- */
-#define DES_IP_LEFT_BITS(left, right)                           \
-    ((((left) & 0x55555555) << 1) | ((right) & 0x55555555))
-#define DES_IP_RIGHT_BITS(left, right)                          \
-    (((left) & 0xaaaaaaaa) |                                    \
-     ( ( (unsigned DES_INT32) ((right) & 0xaaaaaaaa) ) >> 1))
-
-/*
- * The following macro does an in-place initial permutation given
- * the current left and right parts of the block and a single
- * temporary.  Use this more as a guide for rolling your own, though.
- * The best way to do the IP depends on the form of the data you
- * are dealing with.  If you use this, though, try to make left,
- * right and temp unsigned DES_INT32s.
- */
-#define DES_INITIAL_PERM(left, right, temp) do {        \
-        (temp) = DES_IP_RIGHT_BITS((left), (right));    \
-        (right) = DES_IP_LEFT_BITS((left), (right));    \
-        (left) = IP[((right) >> 24) & 0xff]             \
-            | (IP[((right) >> 16) & 0xff] << 1)         \
-            | (IP[((right) >>  8) & 0xff] << 2)         \
-            | (IP[(right) & 0xff] << 3);                \
-        (right) = IP[((temp) >> 24) & 0xff]             \
-            | (IP[((temp) >> 16) & 0xff] << 1)          \
-            | (IP[((temp) >>  8) & 0xff] << 2)          \
-            | (IP[(temp) & 0xff] << 3);                 \
-    } while(0);
-
-/*
- * Now the final permutation stuff.  The same comments apply to
- * this as to the initial permutation, except that we use different
- * bits and shifts.
- *
- * The inserted cast to unsigned DES_INT32 circumvents a bug in
- * the Macintosh MPW 3.2 C compiler which loses the unsignedness and
- * propagates the high-order bit in the shift.
- */
-#define DES_FP_LEFT_BITS(left, right)                           \
-    ((((left) & 0x0f0f0f0f) << 4) | ((right) & 0x0f0f0f0f))
-#define DES_FP_RIGHT_BITS(left, right)                          \
-    (((left) & 0xf0f0f0f0) |                                    \
-     ( ( (unsigned DES_INT32) ((right) & 0xf0f0f0f0) ) >> 4))
-
-
-/*
- * Here is a sample final permutation.  Note that there is a trick
- * here.  DES requires swapping the left and right parts after the
- * last cipher round but before the final permutation.  We do this
- * swapping internally, which is why left and right are confused
- * at the beginning.
- */
-#define DES_FINAL_PERM(left, right, temp) do {          \
-        (temp) = DES_FP_RIGHT_BITS((right), (left));    \
-        (right) = DES_FP_LEFT_BITS((right), (left));    \
-        (left) = (FP[((right) >> 24) & 0xff] << 6)      \
-            | (FP[((right) >> 16) & 0xff] << 4)         \
-            | (FP[((right) >>  8) & 0xff] << 2)         \
-            |  FP[(right) & 0xff];                      \
-        (right) = (FP[((temp) >> 24) & 0xff] << 6)      \
-            | (FP[((temp) >> 16) & 0xff] << 4)          \
-            | (FP[((temp) >>  8) & 0xff] << 2)          \
-            |  FP[temp & 0xff];                         \
-    } while(0);
-
-
-/*
- * Finally, as a sample of how all this might be held together, the
- * following two macros do in-place encryptions and decryptions.  left
- * and right are two unsigned DES_INT32 variables which at the beginning
- * are expected to hold the clear (encrypted) block in host byte order
- * (left the high order four bytes, right the low order).  At the end
- * they will contain the encrypted (clear) block.  temp is an unsigned DES_INT32
- * used as a temporary.  kp is an unsigned DES_INT32 pointer pointing at
- * the start of the key schedule.  All these should be in registers.
- *
- * You can probably do better than these by rewriting for particular
- * situations.  These aren't bad, though.
- *
- * The DEB macros enable debugging when this code breaks (typically
- * when a buggy compiler breaks it), by printing the intermediate values
- * at each stage of the encryption, so that by comparing the output to
- * a known good machine, the location of the first error can be found.
- */
-#define DES_DO_ENCRYPT_1(left, right, kp)                               \
-    do {                                                                \
-        int i;                                                          \
-        unsigned DES_INT32 temp1;                                       \
-        DEB (("do_encrypt %8lX %8lX \n", left, right));                 \
-        DES_INITIAL_PERM((left), (right), (temp1));                     \
-        DEB (("  after IP %8lX %8lX\n", left, right));                  \
-        for (i = 0; i < 8; i++) {                                       \
-            DES_SP_ENCRYPT_ROUND((left), (right), (temp1), (kp));       \
-            DEB (("  round %2d %8lX %8lX \n", i*2, left, right));       \
-            DES_SP_ENCRYPT_ROUND((right), (left), (temp1), (kp));       \
-            DEB (("  round %2d %8lX %8lX \n", 1+i*2, left, right));     \
-        }                                                               \
-        DES_FINAL_PERM((left), (right), (temp1));                       \
-        (kp) -= (2 * 16);                                               \
-        DEB (("  after FP %8lX %8lX \n", left, right));                 \
-    } while (0)
-
-#define DES_DO_DECRYPT_1(left, right, kp)                               \
-    do {                                                                \
-        int i;                                                          \
-        unsigned DES_INT32 temp2;                                       \
-        DES_INITIAL_PERM((left), (right), (temp2));                     \
-        (kp) += (2 * 16);                                               \
-        for (i = 0; i < 8; i++) {                                       \
-            DES_SP_DECRYPT_ROUND((left), (right), (temp2), (kp));       \
-            DES_SP_DECRYPT_ROUND((right), (left), (temp2), (kp));       \
-        }                                                               \
-        DES_FINAL_PERM((left), (right), (temp2));                       \
-    } while (0)
-
-#if defined(CONFIG_SMALL) && !defined(CONFIG_SMALL_NO_CRYPTO)
-extern void krb5int_des_do_encrypt_2(unsigned DES_INT32 *l,
-                                     unsigned DES_INT32 *r,
-                                     const unsigned DES_INT32 *k);
-extern void krb5int_des_do_decrypt_2(unsigned DES_INT32 *l,
-                                     unsigned DES_INT32 *r,
-                                     const unsigned DES_INT32 *k);
-#define DES_DO_ENCRYPT(L,R,K) krb5int_des_do_encrypt_2(&(L), &(R), (K))
-#define DES_DO_DECRYPT(L,R,K) krb5int_des_do_decrypt_2(&(L), &(R), (K))
-#else
-#define DES_DO_ENCRYPT DES_DO_ENCRYPT_1
-#define DES_DO_DECRYPT DES_DO_DECRYPT_1
-#endif
-
-/*
- * These are handy dandy utility thingies for straightening out bytes.
- * Included here because they're used a couple of places.
- */
-#define GET_HALF_BLOCK(lr, ip)  ((lr) = load_32_be(ip), (ip) += 4)
-#define PUT_HALF_BLOCK(lr, op)  (store_32_be(lr, op), (op) += 4)
-
-/* Shorthand that we'll need in several places, for creating values that
-   really can hold 32 bits regardless of the prevailing int size.  */
-#define FF_UINT32       ((unsigned DES_INT32) 0xFF)
-
-#endif  /* __DES_TABLES_H__ */
diff --git a/src/lib/crypto/builtin/des/key_sched.c b/src/lib/crypto/builtin/des/key_sched.c
deleted file mode 100644
index d6dedd93c6..0000000000
--- a/src/lib/crypto/builtin/des/key_sched.c
+++ /dev/null
@@ -1,66 +0,0 @@
-/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
-/* lib/crypto/builtin/des/key_sched.c */
-/*
- * Copyright 1985, 1986, 1987, 1988, 1990 by the Massachusetts Institute
- * of Technology.
- * All Rights Reserved.
- *
- * Export of this software from the United States of America may
- *   require a specific license from the United States Government.
- *   It is the responsibility of any person or organization contemplating
- *   export to obtain such a license before exporting.
- *
- * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
- * distribute this software and its documentation for any purpose and
- * without fee is hereby granted, provided that the above copyright
- * notice appear in all copies and that both that copyright notice and
- * this permission notice appear in supporting documentation, and that
- * the name of M.I.T. not be used in advertising or publicity pertaining
- * to distribution of the software without specific, written prior
- * permission.  Furthermore if you modify this software you must label
- * your software as modified software and not distribute it in such a
- * fashion that it might be confused with the original M.I.T. software.
- * M.I.T. makes no representations about the suitability of
- * this software for any purpose.  It is provided "as is" without express
- * or implied warranty.
- */
-
-/*
- * This routine computes the DES key schedule given a key.  The
- * permutations and shifts have been done at compile time, resulting
- * in a direct one-step mapping from the input key to the key
- * schedule.
- *
- * Also checks parity and weak keys.
- *
- * Watch out for the subscripts -- most effectively start at 1 instead
- * of at zero.  Maybe some bugs in that area.
- *
- * In case the user wants to cache the computed key schedule, it is
- * passed as an arg.  Also implies that caller has explicit control
- * over zeroing both the key schedule and the key.
- *
- * Originally written 6/85 by Steve Miller, MIT Project Athena.
- */
-
-#include "crypto_int.h"
-#include "des_int.h"
-
-#ifdef K5_BUILTIN_DES
-
-int
-mit_des_key_sched(mit_des_cblock k, mit_des_key_schedule schedule)
-{
-    mit_des_make_key_sched(k,schedule);
-
-    if (!mit_des_check_key_parity(k))   /* bad parity --> return -1 */
-        return(-1);
-
-    if (mit_des_is_weak_key(k))
-        return(-2);
-
-    /* if key was good, return 0 */
-    return 0;
-}
-
-#endif /* K5_BUILTIN_DES */
diff --git a/src/lib/crypto/builtin/des/keytest.data b/src/lib/crypto/builtin/des/keytest.data
deleted file mode 100644
index 7ff34eedcf..0000000000
--- a/src/lib/crypto/builtin/des/keytest.data
+++ /dev/null
@@ -1,171 +0,0 @@
-0101010101010101 95F8A5E5DD31D900 8000000000000000
-0101010101010101 DD7F121CA5015619 4000000000000000
-0101010101010101 2E8653104F3834EA 2000000000000000
-0101010101010101 4BD388FF6CD81D4F 1000000000000000
-0101010101010101 20B9E767B2FB1456 0800000000000000
-0101010101010101 55579380D77138EF 0400000000000000
-0101010101010101 6CC5DEFAAF04512F 0200000000000000
-0101010101010101 0D9F279BA5D87260 0100000000000000
-0101010101010101 D9031B0271BD5A0A 0080000000000000
-0101010101010101 424250B37C3DD951 0040000000000000
-0101010101010101 B8061B7ECD9A21E5 0020000000000000
-0101010101010101 F15D0F286B65BD28 0010000000000000
-0101010101010101 ADD0CC8D6E5DEBA1 0008000000000000
-0101010101010101 E6D5F82752AD63D1 0004000000000000
-0101010101010101 ECBFE3BD3F591A5E 0002000000000000
-0101010101010101 F356834379D165CD 0001000000000000
-0101010101010101 2B9F982F20037FA9 0000800000000000
-0101010101010101 889DE068A16F0BE6 0000400000000000
-0101010101010101 E19E275D846A1298 0000200000000000
-0101010101010101 329A8ED523D71AEC 0000100000000000
-0101010101010101 E7FCE22557D23C97 0000080000000000
-0101010101010101 12A9F5817FF2D65D 0000040000000000
-0101010101010101 A484C3AD38DC9C19 0000020000000000
-0101010101010101 FBE00A8A1EF8AD72 0000010000000000
-0101010101010101 750D079407521363 0000008000000000
-0101010101010101 64FEED9C724C2FAF 0000004000000000
-0101010101010101 F02B263B328E2B60 0000002000000000
-0101010101010101 9D64555A9A10B852 0000001000000000
-0101010101010101 D106FF0BED5255D7 0000000800000000
-0101010101010101 E1652C6B138C64A5 0000000400000000
-0101010101010101 E428581186EC8F46 0000000200000000
-0101010101010101 AEB5F5EDE22D1A36 0000000100000000
-0101010101010101 E943D7568AEC0C5C 0000000080000000
-0101010101010101 DF98C8276F54B04B 0000000040000000
-0101010101010101 B160E4680F6C696F 0000000020000000
-0101010101010101 FA0752B07D9C4AB8 0000000010000000
-0101010101010101 CA3A2B036DBC8502 0000000008000000
-0101010101010101 5E0905517BB59BCF 0000000004000000
-0101010101010101 814EEB3B91D90726 0000000002000000
-0101010101010101 4D49DB1532919C9F 0000000001000000
-0101010101010101 25EB5FC3F8CF0621 0000000000800000
-0101010101010101 AB6A20C0620D1C6F 0000000000400000
-0101010101010101 79E90DBC98F92CCA 0000000000200000
-0101010101010101 866ECEDD8072BB0E 0000000000100000
-0101010101010101 8B54536F2F3E64A8 0000000000080000
-0101010101010101 EA51D3975595B86B 0000000000040000
-0101010101010101 CAFFC6AC4542DE31 0000000000020000
-0101010101010101 8DD45A2DDF90796C 0000000000010000
-0101010101010101 1029D55E880EC2D0 0000000000008000
-0101010101010101 5D86CB23639DBEA9 0000000000004000
-0101010101010101 1D1CA853AE7C0C5F 0000000000002000
-0101010101010101 CE332329248F3228 0000000000001000
-0101010101010101 8405D1ABE24FB942 0000000000000800
-0101010101010101 E643D78090CA4207 0000000000000400
-0101010101010101 48221B9937748A23 0000000000000200
-0101010101010101 DD7C0BBD61FAFD54 0000000000000100
-0101010101010101 2FBC291A570DB5C4 0000000000000080
-0101010101010101 E07C30D7E4E26E12 0000000000000040
-0101010101010101 0953E2258E8E90A1 0000000000000020
-0101010101010101 5B711BC4CEEBF2EE 0000000000000010
-0101010101010101 CC083F1E6D9E85F6 0000000000000008
-0101010101010101 D2FD8867D50D2DFE 0000000000000004
-0101010101010101 06E7EA22CE92708F 0000000000000002
-0101010101010101 166B40B44ABA4BD6 0000000000000001
-8001010101010101 0000000000000000 95A8D72813DAA94D
-4001010101010101 0000000000000000 0EEC1487DD8C26D5
-2001010101010101 0000000000000000 7AD16FFB79C45926
-1001010101010101 0000000000000000 D3746294CA6A6CF3
-0801010101010101 0000000000000000 809F5F873C1FD761
-0401010101010101 0000000000000000 C02FAFFEC989D1FC
-0201010101010101 0000000000000000 4615AA1D33E72F10
-0180010101010101 0000000000000000 2055123350C00858
-0140010101010101 0000000000000000 DF3B99D6577397C8
-0120010101010101 0000000000000000 31FE17369B5288C9
-0110010101010101 0000000000000000 DFDD3CC64DAE1642
-0108010101010101 0000000000000000 178C83CE2B399D94
-0104010101010101 0000000000000000 50F636324A9B7F80
-0102010101010101 0000000000000000 A8468EE3BC18F06D
-0101800101010101 0000000000000000 A2DC9E92FD3CDE92
-0101400101010101 0000000000000000 CAC09F797D031287
-0101200101010101 0000000000000000 90BA680B22AEB525
-0101100101010101 0000000000000000 CE7A24F350E280B6
-0101080101010101 0000000000000000 882BFF0AA01A0B87
-0101040101010101 0000000000000000 25610288924511C2
-0101020101010101 0000000000000000 C71516C29C75D170
-0101018001010101 0000000000000000 5199C29A52C9F059
-0101014001010101 0000000000000000 C22F0A294A71F29F
-0101012001010101 0000000000000000 EE371483714C02EA
-0101011001010101 0000000000000000 A81FBD448F9E522F
-0101010801010101 0000000000000000 4F644C92E192DFED
-0101010401010101 0000000000000000 1AFA9A66A6DF92AE
-0101010201010101 0000000000000000 B3C1CC715CB879D8
-0101010180010101 0000000000000000 19D032E64AB0BD8B
-0101010140010101 0000000000000000 3CFAA7A7DC8720DC
-0101010120010101 0000000000000000 B7265F7F447AC6F3
-0101010110010101 0000000000000000 9DB73B3C0D163F54
-0101010108010101 0000000000000000 8181B65BABF4A975
-0101010104010101 0000000000000000 93C9B64042EAA240
-0101010102010101 0000000000000000 5570530829705592
-0101010101800101 0000000000000000 8638809E878787A0
-0101010101400101 0000000000000000 41B9A79AF79AC208
-0101010101200101 0000000000000000 7A9BE42F2009A892
-0101010101100101 0000000000000000 29038D56BA6D2745
-0101010101080101 0000000000000000 5495C6ABF1E5DF51
-0101010101040101 0000000000000000 AE13DBD561488933
-0101010101020101 0000000000000000 024D1FFA8904E389
-0101010101018001 0000000000000000 D1399712F99BF02E
-0101010101014001 0000000000000000 14C1D7C1CFFEC79E
-0101010101012001 0000000000000000 1DE5279DAE3BED6F
-0101010101011001 0000000000000000 E941A33F85501303
-0101010101010801 0000000000000000 DA99DBBC9A03F379
-0101010101010401 0000000000000000 B7FC92F91D8E92E9
-0101010101010201 0000000000000000 AE8E5CAA3CA04E85
-0101010101010180 0000000000000000 9CC62DF43B6EED74
-0101010101010140 0000000000000000 D863DBB5C59A91A0
-0101010101010120 0000000000000000 A1AB2190545B91D7
-0101010101010110 0000000000000000 0875041E64C570F7
-0101010101010108 0000000000000000 5A594528BEBEF1CC
-0101010101010104 0000000000000000 FCDB3291DE21F0C0
-0101010101010102 0000000000000000 869EFD7F9F265A09
-1046913489980131 0000000000000000 88D55E54F54C97B4
-1007103489988020 0000000000000000 0C0CC00C83EA48FD
-10071034C8980120 0000000000000000 83BC8EF3A6570183
-1046103489988020 0000000000000000 DF725DCAD94EA2E9
-1086911519190101 0000000000000000 E652B53B550BE8B0
-1086911519580101 0000000000000000 AF527120C485CBB0
-5107B01519580101 0000000000000000 0F04CE393DB926D5
-1007B01519190101 0000000000000000 C9F00FFC74079067
-3107915498080101 0000000000000000 7CFD82A593252B4E
-3107919498080101 0000000000000000 CB49A2F9E91363E3
-10079115B9080140 0000000000000000 00B588BE70D23F56
-3107911598080140 0000000000000000 406A9A6AB43399AE
-1007D01589980101 0000000000000000 6CB773611DCA9ADA
-9107911589980101 0000000000000000 67FD21C17DBB5D70
-9107D01589190101 0000000000000000 9592CB4110430787
-1007D01598980120 0000000000000000 A6B7FF68A318DDD3
-1007940498190101 0000000000000000 4D102196C914CA16
-0107910491190401 0000000000000000 2DFA9F4573594965
-0107910491190101 0000000000000000 B46604816C0E0774
-0107940491190401 0000000000000000 6E7E6221A4F34E87
-19079210981A0101 0000000000000000 AA85E74643233199
-1007911998190801 0000000000000000 2E5A19DB4D1962D6
-10079119981A0801 0000000000000000 23A866A809D30894
-1007921098190101 0000000000000000 D812D961F017D320
-100791159819010B 0000000000000000 055605816E58608F
-1004801598190101 0000000000000000 ABD88E8B1B7716F1
-1004801598190102 0000000000000000 537AC95BE69DA1E1
-1004801598190108 0000000000000000 AED0F6AE3C25CDD8
-1002911598100104 0000000000000000 B3E35A5EE53E7B8D
-1002911598190104 0000000000000000 61C79C71921A2EF8
-1002911598100201 0000000000000000 E2F5728F0995013C
-1002911698100101 0000000000000000 1AEAC39A61F0A464
-7CA110454A1A6E57 01A1D6D039776742 690F5B0D9A26939B
-0131D9619DC1376E 5CD54CA83DEF57DA 7A389D10354BD271
-07A1133E4A0B2686 0248D43806F67172 868EBB51CAB4599A
-3849674C2602319E 51454B582DDF440A 7178876E01F19B2A
-04B915BA43FEB5B6 42FD443059577FA2 AF37FB421F8C4095
-0113B970FD34F2CE 059B5E0851CF143A 86A560F10EC6D85B
-0170F175468FB5E6 0756D8E0774761D2 0CD3DA020021DC09
-43297FAD38E373FE 762514B829BF486A EA676B2CB7DB2B7A
-07A7137045DA2A16 3BDD119049372802 DFD64A815CAF1A0F
-04689104C2FD3B2F 26955F6835AF609A 5C513C9C4886C088
-37D06BB516CB7546 164D5E404F275232 0A2AEEAE3FF4AB77
-1F08260D1AC2465E 6B056E18759F5CCA EF1BF03E5DFA575A
-584023641ABA6176 004BD6EF09176062 88BF0DB6D70DEE56
-025816164629B007 480D39006EE762F2 A1F9915541020B56
-49793EBC79B3258F 437540C8698F3CFA 6FBF1CAFCFFD0556
-4FB05E1515AB73A7 072D43A077075292 2F22E49BAB7CA1AC
-49E95D6D4CA229BF 02FE55778117F12A 5A6B612CC26CCE4A
-018310DC409B26D6 1D9D5C5018F728C2 5F4C038ED12B2E41
-1C587F1C13924FEF 305532286D6F295A 63FAC0D034D9F793
diff --git a/src/lib/crypto/builtin/des/t_verify.c b/src/lib/crypto/builtin/des/t_verify.c
deleted file mode 100644
index 11f1a404dd..0000000000
--- a/src/lib/crypto/builtin/des/t_verify.c
+++ /dev/null
@@ -1,388 +0,0 @@
-/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
-/* lib/crypto/builtin/des/t_verify.c */
-/*
- * Copyright 1988, 1990 by the Massachusetts Institute of Technology.
- * All Rights Reserved.
- *
- * Export of this software from the United States of America may
- *   require a specific license from the United States Government.
- *   It is the responsibility of any person or organization contemplating
- *   export to obtain such a license before exporting.
- *
- * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
- * distribute this software and its documentation for any purpose and
- * without fee is hereby granted, provided that the above copyright
- * notice appear in all copies and that both that copyright notice and
- * this permission notice appear in supporting documentation, and that
- * the name of M.I.T. not be used in advertising or publicity pertaining
- * to distribution of the software without specific, written prior
- * permission.  Furthermore if you modify this software you must label
- * your software as modified software and not distribute it in such a
- * fashion that it might be confused with the original M.I.T. software.
- * M.I.T. makes no representations about the suitability of
- * this software for any purpose.  It is provided "as is" without express
- * or implied warranty.
- */
-/*
- * Copyright (C) 1998 by the FundsXpress, INC.
- *
- * All rights reserved.
- *
- * Export of this software from the United States of America may require
- * a specific license from the United States Government.  It is the
- * responsibility of any person or organization contemplating export to
- * obtain such a license before exporting.
- *
- * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
- * distribute this software and its documentation for any purpose and
- * without fee is hereby granted, provided that the above copyright
- * notice appear in all copies and that both that copyright notice and
- * this permission notice appear in supporting documentation, and that
- * the name of FundsXpress. not be used in advertising or publicity pertaining
- * to distribution of the software without specific, written prior
- * permission.  FundsXpress makes no representations about the suitability of
- * this software for any purpose.  It is provided "as is" without express
- * or implied warranty.
- *
- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
- * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
- */
-
-/*
- *
- * Program to test the correctness of the DES library
- * implementation.
- *
- * exit returns  0 ==> success
- *              -1 ==> error
- */
-
-#include "k5-int.h"
-#include "des_int.h"
-#include <stdio.h>
-#include "com_err.h"
-
-static void do_encrypt(unsigned char *, unsigned char *);
-static void do_decrypt(unsigned char *, unsigned char *);
-
-char *progname;
-int nflag = 2;
-int vflag;
-int mflag;
-int zflag;
-int pid;
-int mit_des_debug;
-
-unsigned char cipher_text[64];
-unsigned char clear_text[64] = "Now is the time for all " ;
-unsigned char clear_text2[64] = "7654321 Now is the time for ";
-unsigned char clear_text3[64] = {2,0,0,0, 1,0,0,0};
-unsigned char output[64];
-unsigned char zero_text[8] = {0x0,0,0,0,0,0,0,0};
-unsigned char msb_text[8] = {0x0,0,0,0, 0,0,0,0x40}; /* to ANSI MSB */
-unsigned char *input;
-
-/* 0x0123456789abcdef */
-unsigned char default_key[8] = {
-    0x01,0x23,0x45,0x67,0x89,0xab,0xcd,0xef
-};
-unsigned char key2[8] = { 0x08,0x19,0x2a,0x3b,0x4c,0x5d,0x6e,0x7f };
-unsigned char key3[8] = { 0x80,1,1,1,1,1,1,1 };
-mit_des_cblock s_key;
-unsigned char default_ivec[8] = {
-    0x12,0x34,0x56,0x78,0x90,0xab,0xcd,0xef
-};
-unsigned char *ivec;
-unsigned char zero_key[8] = {1,1,1,1,1,1,1,1}; /* just parity bits */
-
-unsigned char cipher1[8] = {
-    0x25,0xdd,0xac,0x3e,0x96,0x17,0x64,0x67
-};
-unsigned char cipher2[8] = {
-    0x3f,0xa4,0x0e,0x8a,0x98,0x4d,0x48,0x15
-};
-unsigned char cipher3[64] = {
-    0xe5,0xc7,0xcd,0xde,0x87,0x2b,0xf2,0x7c,
-    0x43,0xe9,0x34,0x00,0x8c,0x38,0x9c,0x0f,
-    0x68,0x37,0x88,0x49,0x9a,0x7c,0x05,0xf6
-};
-unsigned char checksum[8] = {
-    0x58,0xd2,0xe7,0x7e,0x86,0x06,0x27,0x33
-};
-
-unsigned char zresult[8] = {
-    0x8c, 0xa6, 0x4d, 0xe9, 0xc1, 0xb1, 0x23, 0xa7
-};
-
-unsigned char mresult[8] = {
-    0xa3, 0x80, 0xe0, 0x2a, 0x6b, 0xe5, 0x46, 0x96
-};
-
-
-/*
- * Can also add :
- * plaintext = 0, key = 0, cipher = 0x8ca64de9c1b123a7 (or is it a 1?)
- */
-
-mit_des_key_schedule sched;
-
-int
-main(int argc, char *argv[])
-{
-    /* Local Declarations */
-    size_t  in_length;
-    int  retval;
-    int i, j;
-
-#ifdef WINDOWS
-    /* Set screen window buffer to infinite size -- MS default is tiny.  */
-    _wsetscreenbuf (fileno (stdout), _WINBUFINF);
-#endif
-    progname=argv[0];           /* salt away invoking program */
-
-    while (--argc > 0 && (*++argv)[0] == '-')
-        for (i=1; argv[0][i] != '\0'; i++) {
-            switch (argv[0][i]) {
-
-                /* debug flag */
-            case 'd':
-                mit_des_debug=3;
-                continue;
-
-            case 'z':
-                zflag = 1;
-                continue;
-
-            case 'm':
-                mflag = 1;
-                continue;
-
-            default:
-                printf("%s: illegal flag \"%c\" ",
-                       progname,argv[0][i]);
-                exit(1);
-            }
-        };
-
-    if (argc) {
-        fprintf(stderr, "Usage: %s [-dmz]\n", progname);
-        exit(1);
-    }
-
-    /* do some initialisation */
-
-    /* use known input and key */
-
-    /* ECB zero text zero key */
-    if (zflag) {
-        input = zero_text;
-        mit_des_key_sched(zero_key, sched);
-        printf("plaintext = key = 0, cipher = 0x8ca64de9c1b123a7\n");
-        do_encrypt(input,cipher_text);
-        printf("\tcipher  = (low to high bytes)\n\t\t");
-        for (j = 0; j<=7; j++)
-            printf("%02x ",cipher_text[j]);
-        printf("\n");
-        do_decrypt(output,cipher_text);
-        if ( memcmp((char *)cipher_text, (char *)zresult, 8) ) {
-            printf("verify: error in zero key test\n");
-            exit(-1);
-        }
-
-        exit(0);
-    }
-
-    if (mflag) {
-        input = msb_text;
-        mit_des_key_sched(key3, sched);
-        printf("plaintext = 0x00 00 00 00 00 00 00 40, ");
-        printf("key = 0x80 01 01 01 01 01 01 01\n");
-        printf("        cipher = 0xa380e02a6be54696\n");
-        do_encrypt(input,cipher_text);
-        printf("\tcipher  = (low to high bytes)\n\t\t");
-        for (j = 0; j<=7; j++) {
-            printf("%02x ",cipher_text[j]);
-        }
-        printf("\n");
-        do_decrypt(output,cipher_text);
-        if ( memcmp((char *)cipher_text, (char *)mresult, 8) ) {
-            printf("verify: error in msb test\n");
-            exit(-1);
-        }
-        exit(0);
-    }
-
-    /* ECB mode Davies and Price */
-    {
-        input = zero_text;
-        mit_des_key_sched(key2, sched);
-        printf("Examples per FIPS publication 81, keys ivs and cipher\n");
-        printf("in hex.  These are the correct answers, see below for\n");
-        printf("the actual answers.\n\n");
-        printf("Examples per Davies and Price.\n\n");
-        printf("EXAMPLE ECB\tkey = 08192a3b4c5d6e7f\n");
-        printf("\tclear = 0\n");
-        printf("\tcipher = 25 dd ac 3e 96 17 64 67\n");
-        printf("ACTUAL ECB\n");
-        printf("\tclear \"%s\"\n", input);
-        do_encrypt(input,cipher_text);
-        printf("\tcipher  = (low to high bytes)\n\t\t");
-        for (j = 0; j<=7; j++)
-            printf("%02x ",cipher_text[j]);
-        printf("\n\n");
-        do_decrypt(output,cipher_text);
-        if ( memcmp((char *)cipher_text, (char *)cipher1, 8) ) {
-            printf("verify: error in ECB encryption\n");
-            exit(-1);
-        }
-        else
-            printf("verify: ECB encryption is correct\n\n");
-    }
-
-    /* ECB mode */
-    {
-        mit_des_key_sched(default_key, sched);
-        input = clear_text;
-        ivec = default_ivec;
-        printf("EXAMPLE ECB\tkey = 0123456789abcdef\n");
-        printf("\tclear = \"Now is the time for all \"\n");
-        printf("\tcipher = 3f a4 0e 8a 98 4d 48 15 ...\n");
-        printf("ACTUAL ECB\n\tclear \"%s\"",input);
-        do_encrypt(input,cipher_text);
-        printf("\n\tcipher      = (low to high bytes)\n\t\t");
-        for (j = 0; j<=7; j++) {
-            printf("%02x ",cipher_text[j]);
-        }
-        printf("\n\n");
-        do_decrypt(output,cipher_text);
-        if ( memcmp((char *)cipher_text, (char *)cipher2, 8) ) {
-            printf("verify: error in ECB encryption\n");
-            exit(-1);
-        }
-        else
-            printf("verify: ECB encryption is correct\n\n");
-    }
-
-    /* CBC mode */
-    printf("EXAMPLE CBC\tkey = 0123456789abcdef");
-    printf("\tiv = 1234567890abcdef\n");
-    printf("\tclear = \"Now is the time for all \"\n");
-    printf("\tcipher =\te5 c7 cd de 87 2b f2 7c\n");
-    printf("\t\t\t43 e9 34 00 8c 38 9c 0f\n");
-    printf("\t\t\t68 37 88 49 9a 7c 05 f6\n");
-
-    printf("ACTUAL CBC\n\tclear \"%s\"\n",input);
-    in_length =  strlen((char *)input);
-    if ((retval = mit_des_cbc_encrypt((const mit_des_cblock *) input,
-                                      (mit_des_cblock *) cipher_text,
-                                      (size_t) in_length,
-                                      sched,
-                                      ivec,
-                                      MIT_DES_ENCRYPT))) {
-        com_err("des verify", retval, "can't encrypt");
-        exit(-1);
-    }
-    printf("\tciphertext = (low to high bytes)\n");
-    for (i = 0; i <= 2; i++) {
-        printf("\t\t");
-        for (j = 0; j <= 7; j++) {
-            printf("%02x ",cipher_text[i*8+j]);
-        }
-        printf("\n");
-    }
-    if ((retval = mit_des_cbc_encrypt((const mit_des_cblock *) cipher_text,
-                                      (mit_des_cblock *) clear_text,
-                                      (size_t) in_length,
-                                      sched,
-                                      ivec,
-                                      MIT_DES_DECRYPT))) {
-        com_err("des verify", retval, "can't decrypt");
-        exit(-1);
-    }
-    printf("\tdecrypted clear_text = \"%s\"\n",clear_text);
-
-    if ( memcmp((char *)cipher_text, (char *)cipher3, in_length) ) {
-        printf("verify: error in CBC encryption\n");
-        exit(-1);
-    }
-    else
-        printf("verify: CBC encryption is correct\n\n");
-
-    printf("EXAMPLE CBC checksum");
-    printf("\tkey =  0123456789abcdef\tiv =  1234567890abcdef\n");
-    printf("\tclear =\t\t\"7654321 Now is the time for \"\n");
-    printf("\tchecksum\t58 d2 e7 7e 86 06 27 33, ");
-    printf("or some part thereof\n");
-    input = clear_text2;
-    mit_des_cbc_cksum(input,cipher_text, strlen((char *)input),
-                      sched,ivec);
-    printf("ACTUAL CBC checksum\n");
-    printf("\t\tencrypted cksum = (low to high bytes)\n\t\t");
-    for (j = 0; j<=7; j++)
-        printf("%02x ",cipher_text[j]);
-    printf("\n\n");
-    if ( memcmp((char *)cipher_text, (char *)checksum, 8) ) {
-        printf("verify: error in CBC checksum\n");
-        exit(-1);
-    }
-    else
-        printf("verify: CBC checksum is correct\n\n");
-
-    exit(0);
-}
-
-static void
-do_encrypt(unsigned char *in, unsigned char *out)
-{
-    int i, j;
-    for (i =1; i<=nflag; i++) {
-        mit_des_cbc_encrypt((const mit_des_cblock *)in,
-                            (mit_des_cblock *)out,
-                            8,
-                            sched,
-                            zero_text,
-                            MIT_DES_ENCRYPT);
-        if (mit_des_debug) {
-            printf("\nclear %s\n",in);
-            for (j = 0; j<=7; j++)
-                printf("%02X ",in[j] & 0xff);
-            printf("\tcipher ");
-            for (j = 0; j<=7; j++)
-                printf("%02X ",out[j] & 0xff);
-        }
-    }
-}
-
-static void
-do_decrypt(unsigned char *in, unsigned char *out)
-    /* try to invert it */
-{
-    int i, j;
-    for (i =1; i<=nflag; i++) {
-        mit_des_cbc_encrypt((const mit_des_cblock *)out,
-                            (mit_des_cblock *)in,
-                            8,
-                            sched,
-                            zero_text,
-                            MIT_DES_DECRYPT);
-        if (mit_des_debug) {
-            printf("clear %s\n",in);
-            for (j = 0; j<=7; j++)
-                printf("%02X ",in[j] & 0xff);
-            printf("\tcipher ");
-            for (j = 0; j<=7; j++)
-                printf("%02X ",out[j] & 0xff);
-        }
-    }
-}
-
-/*
- * Fake out the DES library, for the purposes of testing.
- */
-
-int
-mit_des_is_weak_key(mit_des_cblock key)
-{
-    return 0;                           /* fake it out for testing */
-}
diff --git a/src/lib/crypto/builtin/des/weak_key.c b/src/lib/crypto/builtin/des/weak_key.c
deleted file mode 100644
index f8304a3638..0000000000
--- a/src/lib/crypto/builtin/des/weak_key.c
+++ /dev/null
@@ -1,90 +0,0 @@
-/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
-/* lib/crypto/builtin/des/weak_key.c */
-/*
- * Copyright 1989,1990 by the Massachusetts Institute of Technology.
- * All Rights Reserved.
- *
- * Export of this software from the United States of America may
- *   require a specific license from the United States Government.
- *   It is the responsibility of any person or organization contemplating
- *   export to obtain such a license before exporting.
- *
- * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
- * distribute this software and its documentation for any purpose and
- * without fee is hereby granted, provided that the above copyright
- * notice appear in all copies and that both that copyright notice and
- * this permission notice appear in supporting documentation, and that
- * the name of M.I.T. not be used in advertising or publicity pertaining
- * to distribution of the software without specific, written prior
- * permission.  Furthermore if you modify this software you must label
- * your software as modified software and not distribute it in such a
- * fashion that it might be confused with the original M.I.T. software.
- * M.I.T. makes no representations about the suitability of
- * this software for any purpose.  It is provided "as is" without express
- * or implied warranty.
- */
-
-/*
- * Under U.S. law, this software may not be exported outside the US
- * without license from the U.S. Commerce department.
- *
- * These routines form the library interface to the DES facilities.
- *
- * Originally written 8/85 by Steve Miller, MIT Project Athena.
- */
-
-#include "crypto_int.h"
-#include "des_int.h"
-
-#ifdef K5_BUILTIN_DES
-
-/*
- * The following are the weak DES keys:
- */
-static const mit_des_cblock weak[16] = {
-    /* weak keys */
-    {0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01},
-    {0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe},
-    {0x1f,0x1f,0x1f,0x1f,0x0e,0x0e,0x0e,0x0e},
-    {0xe0,0xe0,0xe0,0xe0,0xf1,0xf1,0xf1,0xf1},
-
-    /* semi-weak */
-    {0x01,0xfe,0x01,0xfe,0x01,0xfe,0x01,0xfe},
-    {0xfe,0x01,0xfe,0x01,0xfe,0x01,0xfe,0x01},
-
-    {0x1f,0xe0,0x1f,0xe0,0x0e,0xf1,0x0e,0xf1},
-    {0xe0,0x1f,0xe0,0x1f,0xf1,0x0e,0xf1,0x0e},
-
-    {0x01,0xe0,0x01,0xe0,0x01,0xf1,0x01,0xf1},
-    {0xe0,0x01,0xe0,0x01,0xf1,0x01,0xf1,0x01},
-
-    {0x1f,0xfe,0x1f,0xfe,0x0e,0xfe,0x0e,0xfe},
-    {0xfe,0x1f,0xfe,0x1f,0xfe,0x0e,0xfe,0x0e},
-
-    {0x01,0x1f,0x01,0x1f,0x01,0x0e,0x01,0x0e},
-    {0x1f,0x01,0x1f,0x01,0x0e,0x01,0x0e,0x01},
-
-    {0xe0,0xfe,0xe0,0xfe,0xf1,0xfe,0xf1,0xfe},
-    {0xfe,0xe0,0xfe,0xe0,0xfe,0xf1,0xfe,0xf1}
-};
-
-/*
- * mit_des_is_weak_key: returns true iff key is a [semi-]weak des key.
- *
- * Requires: key has correct odd parity.
- */
-int
-mit_des_is_weak_key(mit_des_cblock key)
-{
-    unsigned int i;
-    const mit_des_cblock *weak_p = weak;
-
-    for (i = 0; i < (sizeof(weak)/sizeof(mit_des_cblock)); i++) {
-        if (!memcmp(weak_p++,key,sizeof(mit_des_cblock)))
-            return 1;
-    }
-
-    return 0;
-}
-
-#endif /* K5_BUILTIN_DES */
diff --git a/src/lib/crypto/builtin/enc_provider/Makefile.in b/src/lib/crypto/builtin/enc_provider/Makefile.in
index 6ad7cbd4e0..655966b255 100644
--- a/src/lib/crypto/builtin/enc_provider/Makefile.in
+++ b/src/lib/crypto/builtin/enc_provider/Makefile.in
@@ -1,6 +1,6 @@
 mydir=lib$(S)crypto$(S)builtin$(S)enc_provider
 BUILDTOP=$(REL)..$(S)..$(S)..$(S)..
-LOCALINCLUDES = -I$(srcdir)/../des -I$(srcdir)/../aes -I$(srcdir)/../camellia \
+LOCALINCLUDES = -I$(srcdir)/../aes -I$(srcdir)/../camellia \
 		-I$(srcdir)/../../krb $(CRYPTO_IMPL_CFLAGS)
 
 ##DOS##BUILDTOP = ..\..\..\..
@@ -8,19 +8,16 @@ LOCALINCLUDES = -I$(srcdir)/../des -I$(srcdir)/../aes -I$(srcdir)/../camellia \
 ##DOS##OBJFILE = ..\..\$(OUTPRE)enc_provider.lst
 
 STLIBOBJS= \
-	des3.o 	\
 	rc4.o 	\
 	aes.o   \
 	camellia.o
 
 OBJS= \
-	$(OUTPRE)des3.$(OBJEXT) 	\
 	$(OUTPRE)aes.$(OBJEXT) 	\
 	$(OUTPRE)camellia.$(OBJEXT)	\
 	$(OUTPRE)rc4.$(OBJEXT)
 
 SRCS= \
-	$(srcdir)/des3.c 	\
 	$(srcdir)/aes.c 	\
 	$(srcdir)/camellia.c	\
 	$(srcdir)/rc4.c
diff --git a/src/lib/crypto/builtin/enc_provider/deps b/src/lib/crypto/builtin/enc_provider/deps
index a3414a38ec..dc29d9fce8 100644
--- a/src/lib/crypto/builtin/enc_provider/deps
+++ b/src/lib/crypto/builtin/enc_provider/deps
@@ -1,17 +1,6 @@
 #
 # Generated makefile dependencies follow.
 #
-des3.so des3.po $(OUTPRE)des3.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \
-  $(BUILDTOP)/include/krb5/krb5.h $(BUILDTOP)/include/osconf.h \
-  $(BUILDTOP)/include/profile.h $(COM_ERR_DEPS) $(srcdir)/../../krb/crypto_int.h \
-  $(srcdir)/../des/des_int.h $(top_srcdir)/include/k5-buf.h \
-  $(top_srcdir)/include/k5-err.h $(top_srcdir)/include/k5-gmt_mktime.h \
-  $(top_srcdir)/include/k5-int-pkinit.h $(top_srcdir)/include/k5-int.h \
-  $(top_srcdir)/include/k5-platform.h $(top_srcdir)/include/k5-plugin.h \
-  $(top_srcdir)/include/k5-thread.h $(top_srcdir)/include/k5-trace.h \
-  $(top_srcdir)/include/krb5.h $(top_srcdir)/include/krb5/authdata_plugin.h \
-  $(top_srcdir)/include/krb5/plugin.h $(top_srcdir)/include/port-sockets.h \
-  $(top_srcdir)/include/socket-utils.h des3.c
 aes.so aes.po $(OUTPRE)aes.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \
   $(BUILDTOP)/include/krb5/krb5.h $(BUILDTOP)/include/osconf.h \
   $(BUILDTOP)/include/profile.h $(COM_ERR_DEPS) $(srcdir)/../../krb/crypto_int.h \
diff --git a/src/lib/crypto/builtin/enc_provider/des3.c b/src/lib/crypto/builtin/enc_provider/des3.c
deleted file mode 100644
index c2634d5e10..0000000000
--- a/src/lib/crypto/builtin/enc_provider/des3.c
+++ /dev/null
@@ -1,109 +0,0 @@
-/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
-/*
- * Copyright (C) 1998 by the FundsXpress, INC.
- *
- * All rights reserved.
- *
- * Export of this software from the United States of America may require
- * a specific license from the United States Government.  It is the
- * responsibility of any person or organization contemplating export to
- * obtain such a license before exporting.
- *
- * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
- * distribute this software and its documentation for any purpose and
- * without fee is hereby granted, provided that the above copyright
- * notice appear in all copies and that both that copyright notice and
- * this permission notice appear in supporting documentation, and that
- * the name of FundsXpress. not be used in advertising or publicity pertaining
- * to distribution of the software without specific, written prior
- * permission.  FundsXpress makes no representations about the suitability of
- * this software for any purpose.  It is provided "as is" without express
- * or implied warranty.
- *
- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
- * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
- */
-
-#include "crypto_int.h"
-#include "des_int.h"
-
-#ifdef K5_BUILTIN_DES
-
-static krb5_error_code
-validate_and_schedule(krb5_key key, const krb5_data *ivec,
-                      const krb5_crypto_iov *data, size_t num_data,
-                      mit_des3_key_schedule *schedule)
-{
-    if (key->keyblock.length != 24)
-        return(KRB5_BAD_KEYSIZE);
-    if (iov_total_length(data, num_data, FALSE) % 8 != 0)
-        return(KRB5_BAD_MSIZE);
-    if (ivec && (ivec->length != 8))
-        return(KRB5_BAD_MSIZE);
-
-    switch (mit_des3_key_sched(*(mit_des3_cblock *)key->keyblock.contents,
-                               *schedule)) {
-    case -1:
-        return(KRB5DES_BAD_KEYPAR);
-    case -2:
-        return(KRB5DES_WEAK_KEY);
-    }
-    return 0;
-}
-
-static krb5_error_code
-k5_des3_encrypt(krb5_key key, const krb5_data *ivec, krb5_crypto_iov *data,
-                size_t num_data)
-{
-    mit_des3_key_schedule schedule;
-    krb5_error_code err;
-
-    err = validate_and_schedule(key, ivec, data, num_data, &schedule);
-    if (err)
-        return err;
-
-    /* this has a return value, but the code always returns zero */
-    krb5int_des3_cbc_encrypt(data, num_data,
-                             schedule[0], schedule[1], schedule[2],
-                             ivec != NULL ? (unsigned char *) ivec->data :
-                             NULL);
-
-    zap(schedule, sizeof(schedule));
-
-    return(0);
-}
-
-static krb5_error_code
-k5_des3_decrypt(krb5_key key, const krb5_data *ivec, krb5_crypto_iov *data,
-                size_t num_data)
-{
-    mit_des3_key_schedule schedule;
-    krb5_error_code err;
-
-    err = validate_and_schedule(key, ivec, data, num_data, &schedule);
-    if (err)
-        return err;
-
-    /* this has a return value, but the code always returns zero */
-    krb5int_des3_cbc_decrypt(data, num_data,
-                             schedule[0], schedule[1], schedule[2],
-                             ivec != NULL ? (unsigned char *) ivec->data :
-                             NULL);
-
-    zap(schedule, sizeof(schedule));
-
-    return 0;
-}
-
-const struct krb5_enc_provider krb5int_enc_des3 = {
-    8,
-    21, 24,
-    k5_des3_encrypt,
-    k5_des3_decrypt,
-    NULL,
-    krb5int_des_init_state,
-    krb5int_default_free_state
-};
-
-#endif /* K5_BUILTIN_DES */
diff --git a/src/lib/crypto/crypto_tests/t_cf2.expected b/src/lib/crypto/crypto_tests/t_cf2.expected
index f8251a16cb..bc6aa50c84 100644
--- a/src/lib/crypto/crypto_tests/t_cf2.expected
+++ b/src/lib/crypto/crypto_tests/t_cf2.expected
@@ -1,6 +1,5 @@
 97df97e4b798b29eb31ed7280287a92a
 4d6ca4e629785c1f01baf55e2e548566b9617ae3a96868c337cb93b5e72b1c7b
-e58f9eb643862c13ad38e529313462a7f73e62834fe54a01
 24d7f6b6bae4e5c00d2082c5ebab3672
 edd02a39d2dbde31611c16e610be062c
 67f6ea530aea85a37dcbb23349ea52dcc61ca8493ff557252327fd8304341584
diff --git a/src/lib/crypto/crypto_tests/t_cf2.in b/src/lib/crypto/crypto_tests/t_cf2.in
index 73e2f8fbc9..c4d23b506b 100644
--- a/src/lib/crypto/crypto_tests/t_cf2.in
+++ b/src/lib/crypto/crypto_tests/t_cf2.in
@@ -8,11 +8,6 @@ key1
 key2
 a
 b
-16
-key1
-key2
-a
-b
 23
 key1
 key2
diff --git a/src/lib/crypto/crypto_tests/t_cksums.c b/src/lib/crypto/crypto_tests/t_cksums.c
index 557340ec5e..9f9a177ef0 100644
--- a/src/lib/crypto/crypto_tests/t_cksums.c
+++ b/src/lib/crypto/crypto_tests/t_cksums.c
@@ -59,16 +59,6 @@ struct test {
           "\xDA\x39\xA3\xEE\x5E\x6B\x4B\x0D\x32\x55\xBF\xEF\x95\x60\x18\x90"
           "\xAF\xD8\x07\x09" }
     },
-    {
-        { KV5M_DATA, 9, "six seven" },
-        CKSUMTYPE_HMAC_SHA1_DES3, ENCTYPE_DES3_CBC_SHA1, 2,
-        { KV5M_DATA, 24,
-          "\x7A\x25\xDF\x89\x92\x29\x6D\xCE\xDA\x0E\x13\x5B\xC4\x04\x6E\x23"
-          "\x75\xB3\xC1\x4C\x98\xFB\xC1\x62" },
-        { KV5M_DATA, 20,
-          "\x0E\xEF\xC9\xC3\xE0\x49\xAA\xBC\x1B\xA5\xC4\x01\x67\x7D\x9A\xB6"
-          "\x99\x08\x2B\xB4" }
-    },
     {
         { KV5M_DATA, 37, "eight nine ten eleven twelve thirteen" },
         CKSUMTYPE_HMAC_SHA1_96_AES128, ENCTYPE_AES128_CTS_HMAC_SHA1_96, 3,
diff --git a/src/lib/crypto/crypto_tests/t_decrypt.c b/src/lib/crypto/crypto_tests/t_decrypt.c
index a40a855007..716f2c337a 100644
--- a/src/lib/crypto/crypto_tests/t_decrypt.c
+++ b/src/lib/crypto/crypto_tests/t_decrypt.c
@@ -39,62 +39,6 @@ struct test {
     krb5_data keybits;
     krb5_data ciphertext;
 } test_cases[] = {
-    {
-        ENCTYPE_DES3_CBC_SHA1,
-        { KV5M_DATA, 0, "", }, 0,
-        { KV5M_DATA, 24,
-          "\x7A\x25\xDF\x89\x92\x29\x6D\xCE\xDA\x0E\x13\x5B\xC4\x04\x6E\x23"
-          "\x75\xB3\xC1\x4C\x98\xFB\xC1\x62" },
-        { KV5M_DATA, 28,
-          "\x54\x8A\xF4\xD5\x04\xF7\xD7\x23\x30\x3F\x12\x17\x5F\xE8\x38\x6B"
-          "\x7B\x53\x35\xA9\x67\xBA\xD6\x1F\x3B\xF0\xB1\x43" }
-    },
-    {
-        ENCTYPE_DES3_CBC_SHA1,
-        { KV5M_DATA, 1, "1", }, 1,
-        { KV5M_DATA, 24,
-          "\xBC\x07\x83\x89\x15\x13\xD5\xCE\x57\xBC\x13\x8F\xD3\xC1\x1A\xE6"
-          "\x40\x45\x23\x85\x32\x29\x62\xB6" },
-        { KV5M_DATA, 36,
-          "\x9C\x3C\x1D\xBA\x47\x47\xD8\x5A\xF2\x91\x6E\x47\x45\xF2\xDC\xE3"
-          "\x80\x46\x79\x6E\x51\x04\xBC\xCD\xFB\x66\x9A\x91\xD4\x4B\xC3\x56"
-          "\x66\x09\x45\xC7" }
-    },
-    {
-        ENCTYPE_DES3_CBC_SHA1,
-        { KV5M_DATA, 9, "9 bytesss", }, 2,
-        { KV5M_DATA, 24,
-          "\x2F\xD0\xF7\x25\xCE\x04\x10\x0D\x2F\xC8\xA1\x80\x98\x83\x1F\x85"
-          "\x0B\x45\xD9\xEF\x85\x0B\xD9\x20" },
-        { KV5M_DATA, 44,
-          "\xCF\x91\x44\xEB\xC8\x69\x79\x81\x07\x5A\x8B\xAD\x8D\x74\xE5\xD7"
-          "\xD5\x91\xEB\x7D\x97\x70\xC7\xAD\xA2\x5E\xE8\xC5\xB3\xD6\x94\x44"
-          "\xDF\xEC\x79\xA5\xB7\xA0\x14\x82\xD9\xAF\x74\xE6" }
-    },
-    {
-        ENCTYPE_DES3_CBC_SHA1,
-        { KV5M_DATA, 13, "13 bytes byte", }, 3,
-        { KV5M_DATA, 24,
-          "\x0D\xD5\x20\x94\xE0\xF4\x1C\xEC\xCB\x5B\xE5\x10\xA7\x64\xB3\x51"
-          "\x76\xE3\x98\x13\x32\xF1\xE5\x98" },
-        { KV5M_DATA, 44,
-          "\x83\x9A\x17\x08\x1E\xCB\xAF\xBC\xDC\x91\xB8\x8C\x69\x55\xDD\x3C"
-          "\x45\x14\x02\x3C\xF1\x77\xB7\x7B\xF0\xD0\x17\x7A\x16\xF7\x05\xE8"
-          "\x49\xCB\x77\x81\xD7\x6A\x31\x6B\x19\x3F\x8D\x30" }
-    },
-    {
-        ENCTYPE_DES3_CBC_SHA1,
-        { KV5M_DATA, 30, "30 bytes bytes bytes bytes byt", }, 4,
-        { KV5M_DATA, 24,
-          "\xF1\x16\x86\xCB\xBC\x9E\x23\xEA\x54\xFE\xCD\x2A\x3D\xCD\xFB\x20"
-          "\xB6\xFE\x98\xBF\x26\x45\xC4\xC4" },
-        { KV5M_DATA, 60,
-          "\x89\x43\x3E\x83\xFD\x0E\xA3\x66\x6C\xFF\xCD\x18\xD8\xDE\xEB\xC5"
-          "\x3B\x9A\x34\xED\xBE\xB1\x59\xD9\xF6\x67\xC6\xC2\xB9\xA9\x64\x40"
-          "\x1D\x55\xE7\xE9\xC6\x8D\x64\x8D\x65\xC3\xAA\x84\xFF\xA3\x79\x0C"
-          "\x14\xA8\x64\xDA\x80\x73\xA9\xA9\x5C\x4B\xA2\xBC" }
-    },
-
     {
         ENCTYPE_ARCFOUR_HMAC,
         { KV5M_DATA, 0, "", }, 0,
@@ -524,7 +468,6 @@ printhex(const char *head, void *data, size_t len)
 
 static krb5_enctype
 enctypes[] = {
-    ENCTYPE_DES3_CBC_SHA1,
     ENCTYPE_ARCFOUR_HMAC,
     ENCTYPE_ARCFOUR_HMAC_EXP,
     ENCTYPE_AES128_CTS_HMAC_SHA1_96,
diff --git a/src/lib/crypto/crypto_tests/t_derive.c b/src/lib/crypto/crypto_tests/t_derive.c
index afbf7477f6..93ce30da20 100644
--- a/src/lib/crypto/crypto_tests/t_derive.c
+++ b/src/lib/crypto/crypto_tests/t_derive.c
@@ -38,41 +38,6 @@ struct test {
     enum deriv_alg alg;
     krb5_data expected_key;
 } test_cases[] = {
-    /* Kc, Ke, Kei for a DES3 key */
-    {
-        ENCTYPE_DES3_CBC_SHA1,
-        { KV5M_DATA, 24,
-          "\x85\x0B\xB5\x13\x58\x54\x8C\xD0\x5E\x86\x76\x8C\x31\x3E\x3B\xFE"
-          "\xF7\x51\x19\x37\xDC\xF7\x2C\x3E" },
-        { KV5M_DATA, 5, "\0\0\0\2\x99" },
-        DERIVE_RFC3961,
-        { KV5M_DATA, 24,
-          "\xF7\x8C\x49\x6D\x16\xE6\xC2\xDA\xE0\xE0\xB6\xC2\x40\x57\xA8\x4C"
-          "\x04\x26\xAE\xEF\x26\xFD\x6D\xCE" }
-    },
-    {
-        ENCTYPE_DES3_CBC_SHA1,
-        { KV5M_DATA, 24,
-          "\x85\x0B\xB5\x13\x58\x54\x8C\xD0\x5E\x86\x76\x8C\x31\x3E\x3B\xFE"
-          "\xF7\x51\x19\x37\xDC\xF7\x2C\x3E" },
-        { KV5M_DATA, 5, "\0\0\0\2\xAA" },
-        DERIVE_RFC3961,
-        { KV5M_DATA, 24,
-          "\x5B\x57\x23\xD0\xB6\x34\xCB\x68\x4C\x3E\xBA\x52\x64\xE9\xA7\x0D"
-          "\x52\xE6\x83\x23\x1A\xD3\xC4\xCE" }
-    },
-    {
-        ENCTYPE_DES3_CBC_SHA1,
-        { KV5M_DATA, 24,
-          "\x85\x0B\xB5\x13\x58\x54\x8C\xD0\x5E\x86\x76\x8C\x31\x3E\x3B\xFE"
-          "\xF7\x51\x19\x37\xDC\xF7\x2C\x3E" },
-        { KV5M_DATA, 5, "\0\0\0\2\x55" },
-        DERIVE_RFC3961,
-        { KV5M_DATA, 24,
-          "\xA7\x7C\x94\x98\x0E\x9B\x73\x45\xA8\x15\x25\xC4\x23\xA7\x37\xCE"
-          "\x67\xF4\xCD\x91\xB6\xB3\xDA\x45" }
-    },
-
     /* Kc, Ke, Ki for an AES-128 key */
     {
         ENCTYPE_AES128_CTS_HMAC_SHA1_96,
@@ -286,7 +251,6 @@ static const struct krb5_enc_provider *
 get_enc_provider(krb5_enctype enctype)
 {
     switch (enctype) {
-    case ENCTYPE_DES3_CBC_SHA1:              return &krb5int_enc_des3;
     case ENCTYPE_AES128_CTS_HMAC_SHA1_96:    return &krb5int_enc_aes128;
     case ENCTYPE_AES256_CTS_HMAC_SHA1_96:    return &krb5int_enc_aes256;
     case ENCTYPE_CAMELLIA128_CTS_CMAC:       return &krb5int_enc_camellia128;
diff --git a/src/lib/crypto/crypto_tests/t_encrypt.c b/src/lib/crypto/crypto_tests/t_encrypt.c
index 64092ef5c2..83bc98a2f1 100644
--- a/src/lib/crypto/crypto_tests/t_encrypt.c
+++ b/src/lib/crypto/crypto_tests/t_encrypt.c
@@ -37,7 +37,6 @@
 
 /* What enctypes should we test?*/
 krb5_enctype interesting_enctypes[] = {
-    ENCTYPE_DES3_CBC_SHA1,
     ENCTYPE_ARCFOUR_HMAC,
     ENCTYPE_ARCFOUR_HMAC_EXP,
     ENCTYPE_AES256_CTS_HMAC_SHA1_96,
diff --git a/src/lib/crypto/crypto_tests/t_short.c b/src/lib/crypto/crypto_tests/t_short.c
index d4c2b97dfd..4466b71158 100644
--- a/src/lib/crypto/crypto_tests/t_short.c
+++ b/src/lib/crypto/crypto_tests/t_short.c
@@ -34,7 +34,6 @@
 #include "k5-int.h"
 
 krb5_enctype interesting_enctypes[] = {
-    ENCTYPE_DES3_CBC_SHA1,
     ENCTYPE_ARCFOUR_HMAC,
     ENCTYPE_ARCFOUR_HMAC_EXP,
     ENCTYPE_AES256_CTS_HMAC_SHA1_96,
diff --git a/src/lib/crypto/crypto_tests/t_str2key.c b/src/lib/crypto/crypto_tests/t_str2key.c
index cdb1acc6d0..ef4c4a7d3b 100644
--- a/src/lib/crypto/crypto_tests/t_str2key.c
+++ b/src/lib/crypto/crypto_tests/t_str2key.c
@@ -35,58 +35,6 @@ struct test {
     krb5_error_code expected_err;
     krb5_boolean allow_weak;
 } test_cases[] = {
-    /* Test vectors from RFC 3961 appendix A.4. */
-    {
-        ENCTYPE_DES3_CBC_SHA1,
-        "password",
-        { KV5M_DATA, 21, "ATHENA.MIT.EDUraeburn" },
-        { KV5M_DATA, 0, NULL },
-        { KV5M_DATA, 24, "\x85\x0B\xB5\x13\x58\x54\x8C\xD0\x5E\x86\x76\x8C"
-          "\x31\x3E\x3B\xFE\xF7\x51\x19\x37\xDC\xF7\x2C\x3E" },
-        0,
-        FALSE
-    },
-    {
-        ENCTYPE_DES3_CBC_SHA1,
-        "potatoe",
-        { KV5M_DATA, 19, "WHITEHOUSE.GOVdanny" },
-        { KV5M_DATA, 0, NULL },
-        { KV5M_DATA, 24, "\xDF\xCD\x23\x3D\xD0\xA4\x32\x04\xEA\x6D\xC4\x37"
-          "\xFB\x15\xE0\x61\xB0\x29\x79\xC1\xF7\x4F\x37\x7A" },
-        0,
-        FALSE
-    },
-    {
-        ENCTYPE_DES3_CBC_SHA1,
-        "penny",
-        { KV5M_DATA, 19, "EXAMPLE.COMbuckaroo" },
-        { KV5M_DATA, 0, NULL },
-        { KV5M_DATA, 24, "\x6D\x2F\xCD\xF2\xD6\xFB\xBC\x3D\xDC\xAD\xB5\xDA"
-          "\x57\x10\xA2\x34\x89\xB0\xD3\xB6\x9D\x5D\x9D\x4A" },
-        0,
-        FALSE
-    },
-    {
-        ENCTYPE_DES3_CBC_SHA1,
-        "\xC3\x9F",
-        { KV5M_DATA, 23, "ATHENA.MIT.EDUJuri\xC5\xA1\x69\xC4\x87" },
-        { KV5M_DATA, 0, NULL },
-        { KV5M_DATA, 24, "\x16\xD5\xA4\x0E\x1C\xE3\xBA\xCB\x61\xB9\xDC\xE0"
-          "\x04\x70\x32\x4C\x83\x19\x73\xA7\xB9\x52\xFE\xB0" },
-        0,
-        FALSE
-    },
-    {
-        ENCTYPE_DES3_CBC_SHA1,
-        "\xF0\x9D\x84\x9E",
-        { KV5M_DATA, 18, "EXAMPLE.COMpianist" },
-        { KV5M_DATA, 0, NULL },
-        { KV5M_DATA, 24, "\x85\x76\x37\x26\x58\x5D\xBC\x1C\xCE\x6E\xC4\x3E"
-          "\x1F\x75\x1F\x07\xF1\xC4\xCB\xB0\x98\xF4\x0B\x19" },
-        0,
-        FALSE
-    },
-
     /* Test vectors from RFC 3962 appendix B. */
     {
         ENCTYPE_AES128_CTS_HMAC_SHA1_96,
diff --git a/src/lib/crypto/crypto_tests/vectors.c b/src/lib/crypto/crypto_tests/vectors.c
index 314d5c728a..b40551d998 100644
--- a/src/lib/crypto/crypto_tests/vectors.c
+++ b/src/lib/crypto/crypto_tests/vectors.c
@@ -190,8 +190,6 @@ test_s2k (krb5_enctype enctype)
     }
 }
 
-static void test_des3_s2k (void) { test_s2k (ENCTYPE_DES3_CBC_SHA1); }
-
 static void
 keyToData (krb5_keyblock *k, krb5_data *d)
 {
@@ -208,8 +206,6 @@ void check_error (int r, int line) {
 }
 #define CHECK check_error(r, __LINE__)
 
-extern struct krb5_enc_provider krb5int_enc_des3;
-struct krb5_enc_provider *enc = &krb5int_enc_des3;
 extern struct krb5_enc_provider krb5int_enc_aes128, krb5int_enc_aes256;
 
 void DK (krb5_keyblock *out, krb5_keyblock *in, const krb5_data *usage) {
diff --git a/src/lib/crypto/krb/Makefile.in b/src/lib/crypto/krb/Makefile.in
index cb2e40a3a5..f66698bd53 100644
--- a/src/lib/crypto/krb/Makefile.in
+++ b/src/lib/crypto/krb/Makefile.in
@@ -47,7 +47,6 @@ STLIBOBJS=\
 	prf.o			\
 	prf_aes2.o		\
 	prf_cmac.o		\
-	prf_des.o		\
 	prf_dk.o		\
 	prf_rc4.o		\
 	prng.o			\
@@ -103,7 +102,6 @@ OBJS=\
 	$(OUTPRE)prf.$(OBJEXT)			\
 	$(OUTPRE)prf_aes2.$(OBJEXT)		\
 	$(OUTPRE)prf_cmac.$(OBJEXT)		\
-	$(OUTPRE)prf_des.$(OBJEXT)		\
 	$(OUTPRE)prf_dk.$(OBJEXT)		\
 	$(OUTPRE)prf_rc4.$(OBJEXT)		\
 	$(OUTPRE)prng.$(OBJEXT)			\
@@ -159,7 +157,6 @@ SRCS=\
 	$(srcdir)/prf.c			\
 	$(srcdir)/prf_aes2.c		\
 	$(srcdir)/prf_cmac.c		\
-	$(srcdir)/prf_des.c		\
 	$(srcdir)/prf_dk.c		\
 	$(srcdir)/prf_rc4.c		\
 	$(srcdir)/prng.c 		\
diff --git a/src/lib/crypto/krb/cksumtypes.c b/src/lib/crypto/krb/cksumtypes.c
index f7ba322f24..25a3ffd2d2 100644
--- a/src/lib/crypto/krb/cksumtypes.c
+++ b/src/lib/crypto/krb/cksumtypes.c
@@ -52,12 +52,6 @@ const struct krb5_cksumtypes krb5int_cksumtypes_list[] = {
       krb5int_unkeyed_checksum, NULL,
       20, 20, CKSUM_UNKEYED },
 
-    { CKSUMTYPE_HMAC_SHA1_DES3,
-      "hmac-sha1-des3", { "hmac-sha1-des3-kd" }, "HMAC-SHA1 DES3 key",
-      &krb5int_enc_des3, &krb5int_hash_sha1,
-      krb5int_dk_checksum, NULL,
-      20, 20, 0 },
-
     { CKSUMTYPE_HMAC_MD5_ARCFOUR,
       "hmac-md5-rc4", { "hmac-md5-enc", "hmac-md5-earcfour" },
       "Microsoft HMAC MD5",
diff --git a/src/lib/crypto/krb/crypto_int.h b/src/lib/crypto/krb/crypto_int.h
index 0e6263bf15..ff67b6bd35 100644
--- a/src/lib/crypto/krb/crypto_int.h
+++ b/src/lib/crypto/krb/crypto_int.h
@@ -335,8 +335,6 @@ krb5_error_code krb5int_aes2_string_to_key(const struct krb5_keytypes *enc,
 /* Random to key */
 krb5_error_code k5_rand2key_direct(const krb5_data *randombits,
                                    krb5_keyblock *keyblock);
-krb5_error_code k5_rand2key_des3(const krb5_data *randombits,
-                                 krb5_keyblock *keyblock);
 
 /* Pseudo-random function */
 krb5_error_code krb5int_des_prf(const struct krb5_keytypes *ktp,
@@ -414,11 +412,6 @@ krb5_keyusage krb5int_arcfour_translate_usage(krb5_keyusage usage);
 /* Ensure library initialization has occurred. */
 int krb5int_crypto_init(void);
 
-/* DES default state initialization handler (used by module enc providers). */
-krb5_error_code krb5int_des_init_state(const krb5_keyblock *key,
-                                       krb5_keyusage keyusage,
-                                       krb5_data *state_out);
-
 /* Default state cleanup handler (used by module enc providers). */
 void krb5int_default_free_state(krb5_data *state);
 
@@ -471,7 +464,6 @@ void k5_iov_cursor_put(struct iov_cursor *cursor, unsigned char *block);
 /* Modules must implement the k5_sha256() function prototyped in k5-int.h. */
 
 /* Modules must implement the following enc_providers and hash_providers: */
-extern const struct krb5_enc_provider krb5int_enc_des3;
 extern const struct krb5_enc_provider krb5int_enc_arcfour;
 extern const struct krb5_enc_provider krb5int_enc_aes128;
 extern const struct krb5_enc_provider krb5int_enc_aes256;
@@ -488,9 +480,6 @@ extern const struct krb5_hash_provider krb5int_hash_sha384;
 
 /* Modules must implement the following functions. */
 
-/* Set the parity bits to the correct values in keybits. */
-void k5_des_fixup_key_parity(unsigned char *keybits);
-
 /* Compute an HMAC using the provided hash function, key, and data, storing the
  * result into output (caller-allocated). */
 krb5_error_code krb5int_hmac(const struct krb5_hash_provider *hash,
diff --git a/src/lib/crypto/krb/default_state.c b/src/lib/crypto/krb/default_state.c
index 0757c8b02c..f89dc79023 100644
--- a/src/lib/crypto/krb/default_state.c
+++ b/src/lib/crypto/krb/default_state.c
@@ -32,16 +32,6 @@
 
 #include "crypto_int.h"
 
-krb5_error_code
-krb5int_des_init_state(const krb5_keyblock *key, krb5_keyusage usage,
-                       krb5_data *state_out)
-{
-    if (alloc_data(state_out, 8))
-        return ENOMEM;
-
-    return 0;
-}
-
 void
 krb5int_default_free_state(krb5_data *state)
 {
diff --git a/src/lib/crypto/krb/enctype_util.c b/src/lib/crypto/krb/enctype_util.c
index 1542d40629..a0037912a7 100644
--- a/src/lib/crypto/krb/enctype_util.c
+++ b/src/lib/crypto/krb/enctype_util.c
@@ -45,6 +45,9 @@ struct {
     { ENCTYPE_DES_CBC_MD5, "des-cbc-md5" },
     { ENCTYPE_DES_CBC_RAW, "des-cbc-raw" },
     { ENCTYPE_DES_HMAC_SHA1, "des-hmac-sha1" },
+    { ENCTYPE_DES3_CBC_SHA, "des3-cbc-sha1" },
+    { ENCTYPE_DES3_CBC_RAW, "des3-cbc-raw" },
+    { ENCTYPE_DES3_CBC_SHA1, "des3-hmac-sha1" },
     { ENCTYPE_NULL, NULL }
 };
 
diff --git a/src/lib/crypto/krb/etypes.c b/src/lib/crypto/krb/etypes.c
index fc278783b9..7635393a41 100644
--- a/src/lib/crypto/krb/etypes.c
+++ b/src/lib/crypto/krb/etypes.c
@@ -35,27 +35,6 @@
 
 /* Deprecations come from RFC 6649 and RFC 8249. */
 const struct krb5_keytypes krb5int_enctypes_list[] = {
-    { ENCTYPE_DES3_CBC_RAW,
-      "des3-cbc-raw", { 0 }, "Triple DES cbc mode raw",
-      &krb5int_enc_des3, NULL,
-      16,
-      krb5int_raw_crypto_length, krb5int_raw_encrypt, krb5int_raw_decrypt,
-      krb5int_dk_string_to_key, k5_rand2key_des3,
-      NULL, /*PRF*/
-      0,
-      ETYPE_WEAK | ETYPE_DEPRECATED, 112 },
-
-    { ENCTYPE_DES3_CBC_SHA1,
-      "des3-cbc-sha1", { "des3-hmac-sha1", "des3-cbc-sha1-kd" },
-      "Triple DES cbc mode with HMAC/sha1",
-      &krb5int_enc_des3, &krb5int_hash_sha1,
-      16,
-      krb5int_dk_crypto_length, krb5int_dk_encrypt, krb5int_dk_decrypt,
-      krb5int_dk_string_to_key, k5_rand2key_des3,
-      krb5int_dk_prf,
-      CKSUMTYPE_HMAC_SHA1_DES3,
-      ETYPE_DEPRECATED, 112 },
-
     /* rc4-hmac uses a 128-bit key, but due to weaknesses in the RC4 cipher, we
      * consider its strength degraded and assign it an SSF value of 64. */
     { ENCTYPE_ARCFOUR_HMAC,
diff --git a/src/lib/crypto/krb/prf_des.c b/src/lib/crypto/krb/prf_des.c
deleted file mode 100644
index 7a2d719c5f..0000000000
--- a/src/lib/crypto/krb/prf_des.c
+++ /dev/null
@@ -1,47 +0,0 @@
-/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
-/* lib/crypto/krb/prf_des.c - RFC 3961 DES-based PRF */
-/*
- * Copyright (C) 2004, 2009  by the Massachusetts Institute of Technology.
- * All rights reserved.
- *
- * Export of this software from the United States of America may
- *   require a specific license from the United States Government.
- *   It is the responsibility of any person or organization contemplating
- *   export to obtain such a license before exporting.
- *
- * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
- * distribute this software and its documentation for any purpose and
- * without fee is hereby granted, provided that the above copyright
- * notice appear in all copies and that both that copyright notice and
- * this permission notice appear in supporting documentation, and that
- * the name of M.I.T. not be used in advertising or publicity pertaining
- * to distribution of the software without specific, written prior
- * permission.  Furthermore if you modify this software you must label
- * your software as modified software and not distribute it in such a
- * fashion that it might be confused with the original M.I.T. software.
- * M.I.T. makes no representations about the suitability of
- * this software for any purpose.  It is provided "as is" without express
- * or implied warranty.
- */
-
-#include "crypto_int.h"
-
-krb5_error_code
-krb5int_des_prf(const struct krb5_keytypes *ktp, krb5_key key,
-                const krb5_data *in, krb5_data *out)
-{
-    const struct krb5_hash_provider *hash = &krb5int_hash_md5;
-    krb5_crypto_iov iov;
-    krb5_error_code ret;
-
-    /* Compute a hash of the input, storing into the output buffer. */
-    iov.flags = KRB5_CRYPTO_TYPE_DATA;
-    iov.data = *in;
-    ret = hash->hash(&iov, 1, out);
-    if (ret != 0)
-        return ret;
-
-    /* Encrypt the hash in place. */
-    iov.data = *out;
-    return ktp->enc->encrypt(key, NULL, &iov, 1);
-}
diff --git a/src/lib/crypto/krb/random_to_key.c b/src/lib/crypto/krb/random_to_key.c
index 9394385aa0..863090beb2 100644
--- a/src/lib/crypto/krb/random_to_key.c
+++ b/src/lib/crypto/krb/random_to_key.c
@@ -71,31 +71,3 @@ k5_rand2key_direct(const krb5_data *randombits, krb5_keyblock *keyblock)
     memcpy(keyblock->contents, randombits->data, randombits->length);
     return 0;
 }
-
-static inline void
-eighth_byte(unsigned char *b)
-{
-    b[7] = (((b[0] & 1) << 1) | ((b[1] & 1) << 2) | ((b[2] & 1) << 3) |
-            ((b[3] & 1) << 4) | ((b[4] & 1) << 5) | ((b[5] & 1) << 6) |
-            ((b[6] & 1) << 7));
-}
-
-krb5_error_code
-k5_rand2key_des3(const krb5_data *randombits, krb5_keyblock *keyblock)
-{
-    int i;
-
-    if (randombits->length != 21)
-        return KRB5_CRYPTO_INTERNAL;
-
-    keyblock->magic = KV5M_KEYBLOCK;
-
-    /* Take the seven bytes, move them around into the top 7 bits of the
-     * 8 key bytes, then compute the parity bits.  Do this three times. */
-    for (i = 0; i < 3; i++) {
-        memcpy(&keyblock->contents[i * 8], &randombits->data[i * 7], 7);
-        eighth_byte(&keyblock->contents[i * 8]);
-        k5_des_fixup_key_parity(&keyblock->contents[i * 8]);
-    }
-    return 0;
-}
diff --git a/src/lib/crypto/libk5crypto.exports b/src/lib/crypto/libk5crypto.exports
index 2b27028a0f..00e0ce1812 100644
--- a/src/lib/crypto/libk5crypto.exports
+++ b/src/lib/crypto/libk5crypto.exports
@@ -86,7 +86,6 @@ krb5_k_verify_checksum
 krb5_k_verify_checksum_iov
 krb5int_aes_encrypt
 krb5int_aes_decrypt
-krb5int_enc_des3
 krb5int_arcfour_gsscrypt
 krb5int_camellia_encrypt
 krb5int_cmac_checksum
diff --git a/src/lib/crypto/openssl/Makefile.in b/src/lib/crypto/openssl/Makefile.in
index fe9ad8619a..cc131000bd 100644
--- a/src/lib/crypto/openssl/Makefile.in
+++ b/src/lib/crypto/openssl/Makefile.in
@@ -1,6 +1,6 @@
 mydir=lib$(S)crypto$(S)openssl
 BUILDTOP=$(REL)..$(S)..$(S)..
-SUBDIRS=des enc_provider hash_provider
+SUBDIRS=enc_provider hash_provider
 LOCALINCLUDES=-I$(srcdir)/../krb $(CRYPTO_IMPL_CFLAGS)
 
 STLIBOBJS=\
@@ -27,7 +27,7 @@ SRCS=\
 	$(srcdir)/sha256.c	\
 	$(srcdir)/common.c
 
-SUBDIROBJLISTS= des/OBJS.ST md4/OBJS.ST 	\
+SUBDIROBJLISTS= md4/OBJS.ST 		\
 		md5/OBJS.ST sha1/OBJS.ST sha2/OBJS.ST 	\
 		enc_provider/OBJS.ST 		\
 		hash_provider/OBJS.ST 		\
diff --git a/src/lib/crypto/openssl/des/Makefile.in b/src/lib/crypto/openssl/des/Makefile.in
deleted file mode 100644
index a6cece1dd1..0000000000
--- a/src/lib/crypto/openssl/des/Makefile.in
+++ /dev/null
@@ -1,20 +0,0 @@
-mydir=lib$(S)crypto$(S)openssl$(S)des
-BUILDTOP=$(REL)..$(S)..$(S)..$(S)..
-LOCALINCLUDES = -I$(srcdir)/../../krb $(CRYPTO_IMPL_CFLAGS)
-
-STLIBOBJS= des_keys.o
-
-OBJS= $(OUTPRE)des_keys.$(OBJEXT)
-
-SRCS= $(srcdir)/des_keys.c
-
-all-unix: all-libobjs
-
-includes: depend
-
-depend: $(SRCS)
-
-clean-unix:: clean-libobjs
-
-@libobj_frag@
-
diff --git a/src/lib/crypto/openssl/des/deps b/src/lib/crypto/openssl/des/deps
deleted file mode 100644
index 723c268082..0000000000
--- a/src/lib/crypto/openssl/des/deps
+++ /dev/null
@@ -1,14 +0,0 @@
-#
-# Generated makefile dependencies follow.
-#
-des_keys.so des_keys.po $(OUTPRE)des_keys.$(OBJEXT): \
-  $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/krb5/krb5.h \
-  $(BUILDTOP)/include/osconf.h $(BUILDTOP)/include/profile.h \
-  $(COM_ERR_DEPS) $(srcdir)/../../krb/crypto_int.h $(top_srcdir)/include/k5-buf.h \
-  $(top_srcdir)/include/k5-err.h $(top_srcdir)/include/k5-gmt_mktime.h \
-  $(top_srcdir)/include/k5-int-pkinit.h $(top_srcdir)/include/k5-int.h \
-  $(top_srcdir)/include/k5-platform.h $(top_srcdir)/include/k5-plugin.h \
-  $(top_srcdir)/include/k5-thread.h $(top_srcdir)/include/k5-trace.h \
-  $(top_srcdir)/include/krb5.h $(top_srcdir)/include/krb5/authdata_plugin.h \
-  $(top_srcdir)/include/krb5/plugin.h $(top_srcdir)/include/port-sockets.h \
-  $(top_srcdir)/include/socket-utils.h des_keys.c
diff --git a/src/lib/crypto/openssl/des/des_keys.c b/src/lib/crypto/openssl/des/des_keys.c
deleted file mode 100644
index 83f1cbf22a..0000000000
--- a/src/lib/crypto/openssl/des/des_keys.c
+++ /dev/null
@@ -1,39 +0,0 @@
-/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
-/* lib/crypto/openssl/des/des_keys.c - Key functions used by Kerberos code */
-/*
- * Copyright (C) 2011 by the Massachusetts Institute of Technology.
- * All rights reserved.
- *
- * Export of this software from the United States of America may
- *   require a specific license from the United States Government.
- *   It is the responsibility of any person or organization contemplating
- *   export to obtain such a license before exporting.
- *
- * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
- * distribute this software and its documentation for any purpose and
- * without fee is hereby granted, provided that the above copyright
- * notice appear in all copies and that both that copyright notice and
- * this permission notice appear in supporting documentation, and that
- * the name of M.I.T. not be used in advertising or publicity pertaining
- * to distribution of the software without specific, written prior
- * permission.  Furthermore if you modify this software you must label
- * your software as modified software and not distribute it in such a
- * fashion that it might be confused with the original M.I.T. software.
- * M.I.T. makes no representations about the suitability of
- * this software for any purpose.  It is provided "as is" without express
- * or implied warranty.
- */
-
-#include "crypto_int.h"
-
-#ifdef K5_OPENSSL_DES_KEY_PARITY
-
-#include <openssl/des.h>
-
-void
-k5_des_fixup_key_parity(unsigned char *keybits)
-{
-    DES_set_odd_parity((DES_cblock *)keybits);
-}
-
-#endif
diff --git a/src/lib/crypto/openssl/enc_provider/Makefile.in b/src/lib/crypto/openssl/enc_provider/Makefile.in
index 26827cfed5..f0d37c1213 100644
--- a/src/lib/crypto/openssl/enc_provider/Makefile.in
+++ b/src/lib/crypto/openssl/enc_provider/Makefile.in
@@ -3,19 +3,16 @@ BUILDTOP=$(REL)..$(S)..$(S)..$(S)..
 LOCALINCLUDES = -I$(srcdir)/../../krb $(CRYPTO_IMPL_CFLAGS)
 
 STLIBOBJS= \
-	des3.o 	\
 	rc4.o 	\
 	aes.o   \
 	camellia.o
 
 OBJS= \
-	$(OUTPRE)des3.$(OBJEXT) 	\
 	$(OUTPRE)aes.$(OBJEXT) 	\
 	$(OUTPRE)camellia.$(OBJEXT) 	\
 	$(OUTPRE)rc4.$(OBJEXT)
 
 SRCS= \
-	$(srcdir)/des3.c 	\
 	$(srcdir)/aes.c 	\
 	$(srcdir)/camellia.c 	\
 	$(srcdir)/rc4.c
diff --git a/src/lib/crypto/openssl/enc_provider/deps b/src/lib/crypto/openssl/enc_provider/deps
index 1c87a526d0..a502990a0c 100644
--- a/src/lib/crypto/openssl/enc_provider/deps
+++ b/src/lib/crypto/openssl/enc_provider/deps
@@ -1,17 +1,6 @@
 #
 # Generated makefile dependencies follow.
 #
-des3.so des3.po $(OUTPRE)des3.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \
-  $(BUILDTOP)/include/krb5/krb5.h $(BUILDTOP)/include/osconf.h \
-  $(BUILDTOP)/include/profile.h $(COM_ERR_DEPS) $(srcdir)/../../krb/crypto_int.h \
-  $(top_srcdir)/include/k5-buf.h $(top_srcdir)/include/k5-err.h \
-  $(top_srcdir)/include/k5-gmt_mktime.h $(top_srcdir)/include/k5-int-pkinit.h \
-  $(top_srcdir)/include/k5-int.h $(top_srcdir)/include/k5-platform.h \
-  $(top_srcdir)/include/k5-plugin.h $(top_srcdir)/include/k5-thread.h \
-  $(top_srcdir)/include/k5-trace.h $(top_srcdir)/include/krb5.h \
-  $(top_srcdir)/include/krb5/authdata_plugin.h $(top_srcdir)/include/krb5/plugin.h \
-  $(top_srcdir)/include/port-sockets.h $(top_srcdir)/include/socket-utils.h \
-  des3.c
 aes.so aes.po $(OUTPRE)aes.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \
   $(BUILDTOP)/include/krb5/krb5.h $(BUILDTOP)/include/osconf.h \
   $(BUILDTOP)/include/profile.h $(COM_ERR_DEPS) $(srcdir)/../../krb/crypto_int.h \
diff --git a/src/lib/crypto/openssl/enc_provider/des3.c b/src/lib/crypto/openssl/enc_provider/des3.c
deleted file mode 100644
index 90fcf9acb5..0000000000
--- a/src/lib/crypto/openssl/enc_provider/des3.c
+++ /dev/null
@@ -1,188 +0,0 @@
-/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
-/* lib/crypto/openssl/enc_provider/des3.c */
-/*
- * Copyright (C) 2009 by the Massachusetts Institute of Technology.
- * All rights reserved.
- *
- * Export of this software from the United States of America may
- *   require a specific license from the United States Government.
- *   It is the responsibility of any person or organization contemplating
- *   export to obtain such a license before exporting.
- *
- * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
- * distribute this software and its documentation for any purpose and
- * without fee is hereby granted, provided that the above copyright
- * notice appear in all copies and that both that copyright notice and
- * this permission notice appear in supporting documentation, and that
- * the name of M.I.T. not be used in advertising or publicity pertaining
- * to distribution of the software without specific, written prior
- * permission.  Furthermore if you modify this software you must label
- * your software as modified software and not distribute it in such a
- * fashion that it might be confused with the original M.I.T. software.
- * M.I.T. makes no representations about the suitability of
- * this software for any purpose.  It is provided "as is" without express
- * or implied warranty.
- */
-/*
- * Copyright (C) 1998 by the FundsXpress, INC.
- *
- * All rights reserved.
- *
- * Export of this software from the United States of America may require
- * a specific license from the United States Government.  It is the
- * responsibility of any person or organization contemplating export to
- * obtain such a license before exporting.
- *
- * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
- * distribute this software and its documentation for any purpose and
- * without fee is hereby granted, provided that the above copyright
- * notice appear in all copies and that both that copyright notice and
- * this permission notice appear in supporting documentation, and that
- * the name of FundsXpress. not be used in advertising or publicity pertaining
- * to distribution of the software without specific, written prior
- * permission.  FundsXpress makes no representations about the suitability of
- * this software for any purpose.  It is provided "as is" without express
- * or implied warranty.
- *
- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
- * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
- */
-
-#include "crypto_int.h"
-
-#ifdef K5_OPENSSL_DES
-
-#include <openssl/evp.h>
-
-#define DES3_BLOCK_SIZE 8
-#define DES3_KEY_SIZE 24
-#define DES3_KEY_BYTES 21
-
-static krb5_error_code
-validate(krb5_key key, const krb5_data *ivec, const krb5_crypto_iov *data,
-         size_t num_data, krb5_boolean *empty)
-{
-    size_t input_length = iov_total_length(data, num_data, FALSE);
-
-    if (key->keyblock.length != DES3_KEY_SIZE)
-        return(KRB5_BAD_KEYSIZE);
-    if ((input_length%DES3_BLOCK_SIZE) != 0)
-        return(KRB5_BAD_MSIZE);
-    if (ivec && (ivec->length != 8))
-        return(KRB5_BAD_MSIZE);
-
-    *empty = (input_length == 0);
-    return 0;
-}
-
-static krb5_error_code
-k5_des3_encrypt(krb5_key key, const krb5_data *ivec, krb5_crypto_iov *data,
-                size_t num_data)
-{
-    int ret, olen = DES3_BLOCK_SIZE;
-    unsigned char iblock[DES3_BLOCK_SIZE], oblock[DES3_BLOCK_SIZE];
-    struct iov_cursor cursor;
-    EVP_CIPHER_CTX *ctx;
-    krb5_boolean empty;
-
-    ret = validate(key, ivec, data, num_data, &empty);
-    if (ret != 0 || empty)
-        return ret;
-
-    ctx = EVP_CIPHER_CTX_new();
-    if (ctx == NULL)
-        return ENOMEM;
-
-    ret = EVP_EncryptInit_ex(ctx, EVP_des_ede3_cbc(), NULL,
-                             key->keyblock.contents,
-                             (ivec) ? (unsigned char*)ivec->data : NULL);
-    if (!ret) {
-        EVP_CIPHER_CTX_free(ctx);
-        return KRB5_CRYPTO_INTERNAL;
-    }
-
-    EVP_CIPHER_CTX_set_padding(ctx,0);
-
-    k5_iov_cursor_init(&cursor, data, num_data, DES3_BLOCK_SIZE, FALSE);
-    while (k5_iov_cursor_get(&cursor, iblock)) {
-        ret = EVP_EncryptUpdate(ctx, oblock, &olen, iblock, DES3_BLOCK_SIZE);
-        if (!ret)
-            break;
-        k5_iov_cursor_put(&cursor, oblock);
-    }
-
-    if (ivec != NULL)
-        memcpy(ivec->data, oblock, DES3_BLOCK_SIZE);
-
-    EVP_CIPHER_CTX_free(ctx);
-
-    zap(iblock, sizeof(iblock));
-    zap(oblock, sizeof(oblock));
-
-    if (ret != 1)
-        return KRB5_CRYPTO_INTERNAL;
-    return 0;
-}
-
-static krb5_error_code
-k5_des3_decrypt(krb5_key key, const krb5_data *ivec, krb5_crypto_iov *data,
-                size_t num_data)
-{
-    int ret, olen = DES3_BLOCK_SIZE;
-    unsigned char iblock[DES3_BLOCK_SIZE], oblock[DES3_BLOCK_SIZE];
-    struct iov_cursor cursor;
-    EVP_CIPHER_CTX *ctx;
-    krb5_boolean empty;
-
-    ret = validate(key, ivec, data, num_data, &empty);
-    if (ret != 0 || empty)
-        return ret;
-
-    ctx = EVP_CIPHER_CTX_new();
-    if (ctx == NULL)
-        return ENOMEM;
-
-    ret = EVP_DecryptInit_ex(ctx, EVP_des_ede3_cbc(), NULL,
-                             key->keyblock.contents,
-                             (ivec) ? (unsigned char*)ivec->data : NULL);
-    if (!ret) {
-        EVP_CIPHER_CTX_free(ctx);
-        return KRB5_CRYPTO_INTERNAL;
-    }
-
-    EVP_CIPHER_CTX_set_padding(ctx,0);
-
-    k5_iov_cursor_init(&cursor, data, num_data, DES3_BLOCK_SIZE, FALSE);
-    while (k5_iov_cursor_get(&cursor, iblock)) {
-        ret = EVP_DecryptUpdate(ctx, oblock, &olen,
-                                (unsigned char *)iblock, DES3_BLOCK_SIZE);
-        if (!ret)
-            break;
-        k5_iov_cursor_put(&cursor, oblock);
-    }
-
-    if (ivec != NULL)
-        memcpy(ivec->data, iblock, DES3_BLOCK_SIZE);
-
-    EVP_CIPHER_CTX_free(ctx);
-
-    zap(iblock, sizeof(iblock));
-    zap(oblock, sizeof(oblock));
-
-    if (ret != 1)
-        return KRB5_CRYPTO_INTERNAL;
-    return 0;
-}
-
-const struct krb5_enc_provider krb5int_enc_des3 = {
-    DES3_BLOCK_SIZE,
-    DES3_KEY_BYTES, DES3_KEY_SIZE,
-    k5_des3_encrypt,
-    k5_des3_decrypt,
-    NULL,
-    krb5int_des_init_state,
-    krb5int_default_free_state
-};
-
-#endif /* K5_OPENSSL_DES */
diff --git a/src/lib/crypto/openssl/kdf.c b/src/lib/crypto/openssl/kdf.c
index 2713850997..8528ddc4a9 100644
--- a/src/lib/crypto/openssl/kdf.c
+++ b/src/lib/crypto/openssl/kdf.c
@@ -60,8 +60,6 @@ enc_name(const struct krb5_enc_provider *enc)
         return "AES-128-CBC";
     if (enc == &krb5int_enc_aes256)
         return "AES-256-CBC";
-    if (enc == &krb5int_enc_des3)
-        return "DES-EDE3-CBC";
     return NULL;
 }
 
diff --git a/src/lib/gssapi/krb5/accept_sec_context.c b/src/lib/gssapi/krb5/accept_sec_context.c
index c9987b757b..edde90ff18 100644
--- a/src/lib/gssapi/krb5/accept_sec_context.c
+++ b/src/lib/gssapi/krb5/accept_sec_context.c
@@ -1007,7 +1007,6 @@ kg_accept_krb5(OM_uint32 *minor_status, gss_ctx_id_t *context_handle,
             }
 
             switch (negotiated_etype) {
-            case ENCTYPE_DES3_CBC_SHA1:
             case ENCTYPE_ARCFOUR_HMAC:
             case ENCTYPE_ARCFOUR_HMAC_EXP:
                 /* RFC 4121 accidentally omits RC4-HMAC-EXP as a "not-newer"
diff --git a/src/lib/gssapi/krb5/gssapiP_krb5.h b/src/lib/gssapi/krb5/gssapiP_krb5.h
index 1ed71fc81f..b01fecf1b6 100644
--- a/src/lib/gssapi/krb5/gssapiP_krb5.h
+++ b/src/lib/gssapi/krb5/gssapiP_krb5.h
@@ -125,14 +125,14 @@ enum sgn_alg {
     /* SGN_ALG_DES_MAC               = 0x0002, */
     /* SGN_ALG_3                     = 0x0003, /\* not published *\/ */
     SGN_ALG_HMAC_MD5              = 0x0011, /* microsoft w2k;  */
-    SGN_ALG_HMAC_SHA1_DES3_KD     = 0x0004
+    /* SGN_ALG_HMAC_SHA1_DES3_KD     = 0x0004 */
 };
 enum seal_alg {
     SEAL_ALG_NONE            = 0xffff,
     /* SEAL_ALG_DES             = 0x0000, */
     /* SEAL_ALG_1               = 0x0001, /\* not published *\/ */
     SEAL_ALG_MICROSOFT_RC4   = 0x0010, /* microsoft w2k;  */
-    SEAL_ALG_DES3KD          = 0x0002
+    /* SEAL_ALG_DES3KD          = 0x0002 */
 };
 
 /* for 3DES */
@@ -153,7 +153,7 @@ enum qop {
     GSS_KRB5_INTEG_C_QOP_HMAC_SHA1 = 0x0004,
     GSS_KRB5_INTEG_C_QOP_MASK      = 0x00ff,
     /* GSS_KRB5_CONF_C_QOP_DES        = 0x0100, */
-    GSS_KRB5_CONF_C_QOP_DES3_KD    = 0x0200,
+    /* GSS_KRB5_CONF_C_QOP_DES3_KD    = 0x0200, */
     GSS_KRB5_CONF_C_QOP_MASK       = 0xff00
 };
 
diff --git a/src/lib/gssapi/krb5/k5seal.c b/src/lib/gssapi/krb5/k5seal.c
index 71df11e1bc..1148f6929b 100644
--- a/src/lib/gssapi/krb5/k5seal.c
+++ b/src/lib/gssapi/krb5/k5seal.c
@@ -142,19 +142,12 @@ make_seal_token_v1 (krb5_context context,
 
     /* pad the plaintext, encrypt if needed, and stick it in the token */
 
-    /* initialize the the checksum */
-    switch (signalg) {
-    case SGN_ALG_HMAC_SHA1_DES3_KD:
-        md5cksum.checksum_type = CKSUMTYPE_HMAC_SHA1_DES3;
-        break;
-    case SGN_ALG_HMAC_MD5:
-        md5cksum.checksum_type = CKSUMTYPE_HMAC_MD5_ARCFOUR;
-        if (toktype != KG_TOK_SEAL_MSG)
-            sign_usage = 15;
-        break;
-    default:
-        abort ();
-    }
+    if (signalg != SGN_ALG_HMAC_MD5)
+        abort();
+
+    md5cksum.checksum_type = CKSUMTYPE_HMAC_MD5_ARCFOUR;
+    if (toktype != KG_TOK_SEAL_MSG)
+        sign_usage = 15;
 
     code = krb5_c_checksum_length(context, md5cksum.checksum_type, &sumlen);
     if (code) {
@@ -203,20 +196,8 @@ make_seal_token_v1 (krb5_context context,
         gssalloc_free(t);
         return(code);
     }
-    switch(signalg) {
-    case SGN_ALG_HMAC_SHA1_DES3_KD:
-        /*
-         * Using key derivation, the call to krb5_c_make_checksum
-         * already dealt with encrypting.
-         */
-        if (md5cksum.length != cksum_size)
-            abort ();
-        memcpy(checksum, md5cksum.contents, md5cksum.length);
-        break;
-    case SGN_ALG_HMAC_MD5:
-        memcpy(checksum, md5cksum.contents, cksum_size);
-        break;
-    }
+
+    memcpy(checksum, md5cksum.contents, cksum_size);
 
     krb5_free_checksum_contents(context, &md5cksum);
 
diff --git a/src/lib/gssapi/krb5/k5sealiov.c b/src/lib/gssapi/krb5/k5sealiov.c
index 7bf7609a48..d5e12cb436 100644
--- a/src/lib/gssapi/krb5/k5sealiov.c
+++ b/src/lib/gssapi/krb5/k5sealiov.c
@@ -147,18 +147,11 @@ make_seal_token_v1_iov(krb5_context context,
     /* pad the plaintext, encrypt if needed, and stick it in the token */
 
     /* initialize the checksum */
-    switch (ctx->signalg) {
-    case SGN_ALG_HMAC_SHA1_DES3_KD:
-        md5cksum.checksum_type = CKSUMTYPE_HMAC_SHA1_DES3;
-        break;
-    case SGN_ALG_HMAC_MD5:
-        md5cksum.checksum_type = CKSUMTYPE_HMAC_MD5_ARCFOUR;
-        if (toktype != KG_TOK_WRAP_MSG)
-            sign_usage = 15;
-        break;
-    default:
-        abort ();
-    }
+    if (ctx->signalg != SGN_ALG_HMAC_MD5)
+        abort();
+    md5cksum.checksum_type = CKSUMTYPE_HMAC_MD5_ARCFOUR;
+    if (toktype != KG_TOK_WRAP_MSG)
+        sign_usage = 15;
 
     code = krb5_c_checksum_length(context, md5cksum.checksum_type, &k5_trailerlen);
     if (code != 0)
@@ -182,15 +175,7 @@ make_seal_token_v1_iov(krb5_context context,
     if (code != 0)
         goto cleanup;
 
-    switch (ctx->signalg) {
-    case SGN_ALG_HMAC_SHA1_DES3_KD:
-        assert(md5cksum.length == ctx->cksum_size);
-        memcpy(checksum, md5cksum.contents, md5cksum.length);
-        break;
-    case SGN_ALG_HMAC_MD5:
-        memcpy(checksum, md5cksum.contents, ctx->cksum_size);
-        break;
-    }
+    memcpy(checksum, md5cksum.contents, ctx->cksum_size);
 
     /* create the seq_num */
     code = kg_make_seq_num(context, ctx->seq, ctx->initiate ? 0 : 0xFF,
diff --git a/src/lib/gssapi/krb5/k5unsealiov.c b/src/lib/gssapi/krb5/k5unsealiov.c
index de79f3016e..897d3a4962 100644
--- a/src/lib/gssapi/krb5/k5unsealiov.c
+++ b/src/lib/gssapi/krb5/k5unsealiov.c
@@ -103,28 +103,21 @@ kg_unseal_v1_iov(krb5_context context,
     }
 
     if ((ctx->sealalg == SEAL_ALG_NONE && signalg > 1) ||
-        (ctx->sealalg == SEAL_ALG_DES3KD &&
-         signalg != SGN_ALG_HMAC_SHA1_DES3_KD)||
         (ctx->sealalg == SEAL_ALG_MICROSOFT_RC4 &&
          signalg != SGN_ALG_HMAC_MD5)) {
         *minor_status = 0;
         return GSS_S_DEFECTIVE_TOKEN;
     }
 
-    switch (signalg) {
-    case SGN_ALG_HMAC_MD5:
-        cksum_len = 8;
-        if (toktype != KG_TOK_WRAP_MSG)
-            sign_usage = 15;
-        break;
-    case SGN_ALG_HMAC_SHA1_DES3_KD:
-        cksum_len = 20;
-        break;
-    default:
+    if (signalg != SGN_ALG_HMAC_MD5) {
         *minor_status = 0;
         return GSS_S_DEFECTIVE_TOKEN;
     }
 
+    cksum_len = 8;
+    if (toktype != KG_TOK_WRAP_MSG)
+        sign_usage = 15;
+
     /* get the token parameters */
     code = kg_get_seq_num(context, ctx->seq, ptr + 14, ptr + 6, &direction,
                           &seqnum);
@@ -182,16 +175,10 @@ kg_unseal_v1_iov(krb5_context context,
 
     /* initialize the checksum */
 
-    switch (signalg) {
-    case SGN_ALG_HMAC_MD5:
-        md5cksum.checksum_type = CKSUMTYPE_HMAC_MD5_ARCFOUR;
-        break;
-    case SGN_ALG_HMAC_SHA1_DES3_KD:
-        md5cksum.checksum_type = CKSUMTYPE_HMAC_SHA1_DES3;
-        break;
-    default:
+    if (signalg != SGN_ALG_HMAC_MD5)
         abort();
-    }
+
+    md5cksum.checksum_type = CKSUMTYPE_HMAC_MD5_ARCFOUR;
 
     code = krb5_c_checksum_length(context, md5cksum.checksum_type, &sumlen);
     if (code != 0) {
@@ -210,18 +197,13 @@ kg_unseal_v1_iov(krb5_context context,
         goto cleanup;
     }
 
-    switch (signalg) {
-    case SGN_ALG_HMAC_SHA1_DES3_KD:
-    case SGN_ALG_HMAC_MD5:
-        code = k5_bcmp(md5cksum.contents, ptr + 14, cksum_len);
-        break;
-    default:
+    if (signalg != SGN_ALG_HMAC_MD5) {
         code = 0;
         retval = GSS_S_DEFECTIVE_TOKEN;
         goto cleanup;
-        break;
     }
 
+    code = k5_bcmp(md5cksum.contents, ptr + 14, cksum_len);
     if (code != 0) {
         code = 0;
         retval = GSS_S_BAD_SIG;
diff --git a/src/lib/gssapi/krb5/unwrap.c b/src/lib/gssapi/krb5/unwrap.c
index 3e962a611d..f403f277f3 100644
--- a/src/lib/gssapi/krb5/unwrap.c
+++ b/src/lib/gssapi/krb5/unwrap.c
@@ -32,8 +32,8 @@
 
 #include "gssapiP_krb5.h"
 
-/* The RFC 1964 token format is only used with DES3 and RC4, both of which use
- * an 8-byte confounder. */
+/* The RFC 1964 token format is only used with RC4, which uses an 8-byte
+ * confounder. */
 #define V1_CONFOUNDER_LEN 8
 
 #define V3_HEADER_LEN 16
@@ -109,7 +109,7 @@ unwrap_v1(krb5_context context, OM_uint32 *minor_status,
     sealalg = k5_input_get_uint16_le(in);
     filler = k5_input_get_uint16_le(in);
     seqbytes = k5_input_get_bytes(in, 8);
-    cksum_len = (signalg == SGN_ALG_HMAC_SHA1_DES3_KD) ? 20 : 8;
+    cksum_len = 8;
     cksum = k5_input_get_bytes(in, cksum_len);
 
     /* Validate the header fields, and ensure that there are enough bytes
diff --git a/src/lib/gssapi/krb5/util_crypt.c b/src/lib/gssapi/krb5/util_crypt.c
index 386842e8a6..e1b73b2720 100644
--- a/src/lib/gssapi/krb5/util_crypt.c
+++ b/src/lib/gssapi/krb5/util_crypt.c
@@ -97,17 +97,6 @@ kg_setup_keys(krb5_context context, krb5_gss_ctx_id_rec *ctx, krb5_key subkey,
         return code;
 
     switch (subkey->keyblock.enctype) {
-    case ENCTYPE_DES3_CBC_SHA1:
-        code = kg_copy_keys(context, ctx, subkey);
-        if (code != 0)
-            return code;
-
-        ctx->enc->keyblock.enctype = ENCTYPE_DES3_CBC_RAW;
-        ctx->seq->keyblock.enctype = ENCTYPE_DES3_CBC_RAW;
-        ctx->signalg = SGN_ALG_HMAC_SHA1_DES3_KD;
-        ctx->cksum_size = 20;
-        ctx->sealalg = SEAL_ALG_DES3KD;
-        break;
     case ENCTYPE_ARCFOUR_HMAC:
     case ENCTYPE_ARCFOUR_HMAC_EXP:
         /* RFC 4121 accidentally omits RC4-HMAC-EXP as a "not-newer" enctype,
@@ -287,12 +276,9 @@ kg_verify_checksum_v1(krb5_context context, uint16_t signalg, krb5_key key,
     krb5_crypto_iov iov[3];
     uint8_t ckbuf[20];
 
-    if (signalg == SGN_ALG_HMAC_MD5)
-        type = CKSUMTYPE_HMAC_MD5_ARCFOUR;
-    else if (signalg == SGN_ALG_HMAC_SHA1_DES3_KD)
-        type = CKSUMTYPE_HMAC_SHA1_DES3;
-    else
+    if (signalg != SGN_ALG_HMAC_MD5)
         abort();
+    type = CKSUMTYPE_HMAC_MD5_ARCFOUR;
 
     iov[0].flags = iov[1].flags = KRB5_CRYPTO_TYPE_SIGN_ONLY;
     iov[0].data = make_data((uint8_t *)header, 8);
diff --git a/src/lib/gssapi/krb5/verify_mic.c b/src/lib/gssapi/krb5/verify_mic.c
index 1c11d2016f..9687fa9d6a 100644
--- a/src/lib/gssapi/krb5/verify_mic.c
+++ b/src/lib/gssapi/krb5/verify_mic.c
@@ -56,7 +56,7 @@ kg_verify_mic_v1(krb5_context context, OM_uint32 *minor_status,
     signalg = k5_input_get_uint16_le(in);
     filler = k5_input_get_uint32_le(in);
     seqbytes = k5_input_get_bytes(in, 8);
-    cksum_len = (signalg == SGN_ALG_HMAC_SHA1_DES3_KD) ? 20 : 8;
+    cksum_len = 8;
     cksum = k5_input_get_bytes(in, cksum_len);
 
     if (in->status || in->len != 0 || toktype != exp_toktype ||
diff --git a/src/lib/krb5/krb/init_ctx.c b/src/lib/krb5/krb/init_ctx.c
index 1d63f32ace..e0a92d3b36 100644
--- a/src/lib/krb5/krb/init_ctx.c
+++ b/src/lib/krb5/krb/init_ctx.c
@@ -59,7 +59,6 @@
 static krb5_enctype default_enctype_list[] = {
     ENCTYPE_AES256_CTS_HMAC_SHA1_96, ENCTYPE_AES128_CTS_HMAC_SHA1_96,
     ENCTYPE_AES256_CTS_HMAC_SHA384_192, ENCTYPE_AES128_CTS_HMAC_SHA256_128,
-    ENCTYPE_DES3_CBC_SHA1,
     ENCTYPE_ARCFOUR_HMAC,
     ENCTYPE_CAMELLIA128_CTS_CMAC, ENCTYPE_CAMELLIA256_CTS_CMAC,
     0
@@ -221,11 +220,6 @@ krb5_init_context_profile(profile_t profile, krb5_flags flags,
         goto cleanup;
     ctx->allow_weak_crypto = tmp;
 
-    retval = get_boolean(ctx, KRB5_CONF_ALLOW_DES3, 0, &tmp);
-    if (retval)
-        goto cleanup;
-    ctx->allow_des3 = tmp;
-
     retval = get_boolean(ctx, KRB5_CONF_ALLOW_RC4, 0, &tmp);
     if (retval)
         goto cleanup;
@@ -472,8 +466,6 @@ krb5int_parse_enctype_list(krb5_context context, const char *profkey,
             /* Set all enctypes in the default list. */
             for (i = 0; default_list[i]; i++)
                 mod_list(default_list[i], sel, weak, &list);
-        } else if (strcasecmp(token, "des3") == 0) {
-            mod_list(ENCTYPE_DES3_CBC_SHA1, sel, weak, &list);
         } else if (strcasecmp(token, "aes") == 0) {
             mod_list(ENCTYPE_AES256_CTS_HMAC_SHA1_96, sel, weak, &list);
             mod_list(ENCTYPE_AES128_CTS_HMAC_SHA1_96, sel, weak, &list);
diff --git a/src/lib/krb5/krb/s4u_creds.c b/src/lib/krb5/krb/s4u_creds.c
index 45fd103229..20c8064e56 100644
--- a/src/lib/krb5/krb/s4u_creds.c
+++ b/src/lib/krb5/krb/s4u_creds.c
@@ -288,8 +288,6 @@ verify_s4u2self_reply(krb5_context context,
     assert(req_s4u_user != NULL);
 
     switch (subkey->enctype) {
-    case ENCTYPE_DES3_CBC_SHA1:
-    case ENCTYPE_DES3_CBC_RAW:
     case ENCTYPE_ARCFOUR_HMAC:
     case ENCTYPE_ARCFOUR_HMAC_EXP :
         not_newer = TRUE;
diff --git a/src/lib/krb5/krb/t_etypes.c b/src/lib/krb5/krb/t_etypes.c
index 90c9f626c6..935aca12f5 100644
--- a/src/lib/krb5/krb/t_etypes.c
+++ b/src/lib/krb5/krb/t_etypes.c
@@ -50,17 +50,6 @@ static struct {
       { ENCTYPE_AES256_CTS_HMAC_SHA1_96, 0 },
       0, 0
     },
-    /* Family followed by enctype */
-    { "aes des3-cbc-sha1-kd",
-      { 0 },
-      { ENCTYPE_AES256_CTS_HMAC_SHA1_96, ENCTYPE_AES128_CTS_HMAC_SHA1_96,
-        ENCTYPE_AES256_CTS_HMAC_SHA384_192, ENCTYPE_AES128_CTS_HMAC_SHA256_128,
-        ENCTYPE_DES3_CBC_SHA1, 0 },
-      { ENCTYPE_AES256_CTS_HMAC_SHA1_96, ENCTYPE_AES128_CTS_HMAC_SHA1_96,
-        ENCTYPE_AES256_CTS_HMAC_SHA384_192, ENCTYPE_AES128_CTS_HMAC_SHA256_128,
-        ENCTYPE_DES3_CBC_SHA1, 0 },
-      0, 0
-    },
     /* Family with enctype removed */
     { "camellia -camellia256-cts-cmac",
       { 0 },
@@ -69,46 +58,15 @@ static struct {
     },
     /* Default set with family added and enctype removed */
     { "DEFAULT +aes -arcfour-hmac-md5",
-      { ENCTYPE_ARCFOUR_HMAC, ENCTYPE_DES3_CBC_SHA1, 0 },
-      { ENCTYPE_DES3_CBC_SHA1, ENCTYPE_AES256_CTS_HMAC_SHA1_96,
+      { ENCTYPE_ARCFOUR_HMAC, 0 },
+      { ENCTYPE_AES256_CTS_HMAC_SHA1_96,
         ENCTYPE_AES128_CTS_HMAC_SHA1_96, ENCTYPE_AES256_CTS_HMAC_SHA384_192,
         ENCTYPE_AES128_CTS_HMAC_SHA256_128, 0 },
-      { ENCTYPE_DES3_CBC_SHA1,
-        ENCTYPE_AES256_CTS_HMAC_SHA1_96, ENCTYPE_AES128_CTS_HMAC_SHA1_96,
+      { ENCTYPE_AES256_CTS_HMAC_SHA1_96, ENCTYPE_AES128_CTS_HMAC_SHA1_96,
         ENCTYPE_AES256_CTS_HMAC_SHA384_192, ENCTYPE_AES128_CTS_HMAC_SHA256_128,
         0 },
       0, 0
     },
-    /* Default set with families removed and enctypes added (one redundant) */
-    { "DEFAULT -des3 rc4-hmac rc4-hmac-exp",
-      { ENCTYPE_AES256_CTS_HMAC_SHA1_96, ENCTYPE_AES128_CTS_HMAC_SHA1_96,
-        ENCTYPE_DES3_CBC_SHA1, ENCTYPE_ARCFOUR_HMAC, 0 },
-      { ENCTYPE_AES256_CTS_HMAC_SHA1_96, ENCTYPE_AES128_CTS_HMAC_SHA1_96,
-        ENCTYPE_ARCFOUR_HMAC, 0 },
-      { ENCTYPE_AES256_CTS_HMAC_SHA1_96, ENCTYPE_AES128_CTS_HMAC_SHA1_96,
-        ENCTYPE_ARCFOUR_HMAC, ENCTYPE_ARCFOUR_HMAC_EXP, 0 },
-      0, 0
-    },
-    /* Default set with family moved to front */
-    { "des3 +DEFAULT",
-      { ENCTYPE_AES256_CTS_HMAC_SHA1_96, ENCTYPE_AES128_CTS_HMAC_SHA1_96,
-        ENCTYPE_DES3_CBC_SHA1, 0 },
-      { ENCTYPE_DES3_CBC_SHA1, ENCTYPE_AES256_CTS_HMAC_SHA1_96,
-        ENCTYPE_AES128_CTS_HMAC_SHA1_96, 0 },
-      { ENCTYPE_DES3_CBC_SHA1, ENCTYPE_AES256_CTS_HMAC_SHA1_96,
-        ENCTYPE_AES128_CTS_HMAC_SHA1_96, 0 },
-      0, 0
-    },
-    /* Two families with default set removed (exotic case), enctype added */
-    { "aes +rc4 -DEFaulT des3-hmac-sha1",
-      { ENCTYPE_AES128_CTS_HMAC_SHA1_96, ENCTYPE_DES3_CBC_SHA1,
-        ENCTYPE_ARCFOUR_HMAC, 0 },
-      { ENCTYPE_AES256_CTS_HMAC_SHA1_96, ENCTYPE_AES256_CTS_HMAC_SHA384_192,
-        ENCTYPE_AES128_CTS_HMAC_SHA256_128, ENCTYPE_DES3_CBC_SHA1, 0 },
-      { ENCTYPE_AES256_CTS_HMAC_SHA1_96, ENCTYPE_AES256_CTS_HMAC_SHA384_192,
-        ENCTYPE_AES128_CTS_HMAC_SHA256_128, ENCTYPE_DES3_CBC_SHA1, 0 },
-      0, 0
-    },
     /* Test krb5_set_default_in_tkt_ktypes */
     { NULL,
       { ENCTYPE_AES256_CTS_HMAC_SHA1_96, 0 },
diff --git a/src/lib/krb5/os/t_trace.c b/src/lib/krb5/os/t_trace.c
index 10ba8d0ac7..24064ffcfd 100644
--- a/src/lib/krb5/os/t_trace.c
+++ b/src/lib/krb5/os/t_trace.c
@@ -65,8 +65,8 @@ main (int argc, char *argv[])
     krb5_principal princ = &principal_data;
     krb5_pa_data padata, padata2, **padatap;
     krb5_enctype enctypes[4] = {
-        ENCTYPE_DES3_CBC_SHA, ENCTYPE_ARCFOUR_HMAC_EXP, ENCTYPE_UNKNOWN,
-        ENCTYPE_NULL};
+        ENCTYPE_AES128_CTS_HMAC_SHA1_96, ENCTYPE_ARCFOUR_HMAC_EXP,
+        ENCTYPE_UNKNOWN, ENCTYPE_NULL};
     krb5_ccache ccache;
     krb5_keytab keytab;
     krb5_creds creds;
diff --git a/src/lib/krb5/os/t_trace.ref b/src/lib/krb5/os/t_trace.ref
index 79d3b7a99e..8a340123ab 100644
--- a/src/lib/krb5/os/t_trace.ref
+++ b/src/lib/krb5/os/t_trace.ref
@@ -41,7 +41,7 @@ int, krb5_principal type: ?
 krb5_pa_data **, display list of padata type numbers: PA-PW-SALT (3), 0
 krb5_pa_data **, display list of padata type numbers: (empty)
 krb5_enctype, display shortest name of enctype: aes128-cts
-krb5_enctype *, display list of enctypes: 5, rc4-hmac-exp, 511
+krb5_enctype *, display list of enctypes: aes128-cts, rc4-hmac-exp, 511
 krb5_enctype *, display list of enctypes: (empty)
 krb5_ccache, display type:name: FILE:/path/to/ccache
 krb5_keytab, display name: FILE:/etc/krb5.keytab
diff --git a/src/man/krb5.conf.man b/src/man/krb5.conf.man
index eaba2b4cda..6f7890abcd 100644
--- a/src/man/krb5.conf.man
+++ b/src/man/krb5.conf.man
@@ -175,12 +175,6 @@ Additionally, krb5.conf may include any of the relations described in
 The libdefaults section may contain any of the following relations:
 .INDENT 0.0
 .TP
-\fBallow_des3\fP
-Permit the KDC to issue tickets with des3\-cbc\-sha1 session keys.
-In future releases, this flag will allow des3\-cbc\-sha1 to be used
-at all.  The default value for this tag is false.  (Added in
-release 1.21.)
-.TP
 \fBallow_rc4\fP
 Permit the KDC to issue tickets with arcfour\-hmac session keys.
 In future releases, this flag will allow arcfour\-hmac to be used
diff --git a/src/plugins/preauth/pkinit/pkcs11.h b/src/plugins/preauth/pkinit/pkcs11.h
index e3d2846315..586661bb7e 100644
--- a/src/plugins/preauth/pkinit/pkcs11.h
+++ b/src/plugins/preauth/pkinit/pkcs11.h
@@ -339,9 +339,9 @@ typedef unsigned long ck_key_type_t;
 #define CKK_GENERIC_SECRET	(0x10)
 #define CKK_RC2			(0x11)
 #define CKK_RC4			(0x12)
-#define CKK_DES			(0x13)
-#define CKK_DES2		(0x14)
-#define CKK_DES3		(0x15)
+/* #define CKK_DES			(0x13) */
+/* #define CKK_DES2		(0x14) */
+/* #define CKK_DES3		(0x15) */
 #define CKK_CAST		(0x16)
 #define CKK_CAST3		(0x17)
 #define CKK_CAST128		(0x18)
diff --git a/src/plugins/preauth/pkinit/pkinit_crypto.h b/src/plugins/preauth/pkinit/pkinit_crypto.h
index 57bb3cb840..92ccafdfe5 100644
--- a/src/plugins/preauth/pkinit/pkinit_crypto.h
+++ b/src/plugins/preauth/pkinit/pkinit_crypto.h
@@ -316,11 +316,11 @@ krb5_error_code server_process_dh
  * krb5_algorithm_identifier
  */
 krb5_error_code create_krb5_supportedCMSTypes
-	(krb5_context context,				/* IN */
-	pkinit_plg_crypto_context plg_cryptoctx,	/* IN */
-	pkinit_req_crypto_context req_cryptoctx,	/* IN */
-	pkinit_identity_crypto_context id_cryptoctx,	/* IN */
-	krb5_algorithm_identifier ***supportedCMSTypes); /* OUT */
+       (krb5_context context,                          /* IN */
+       pkinit_plg_crypto_context plg_cryptoctx,        /* IN */
+       pkinit_req_crypto_context req_cryptoctx,        /* IN */
+       pkinit_identity_crypto_context id_cryptoctx,    /* IN */
+       krb5_algorithm_identifier ***supportedCMSTypes); /* OUT */
 
 /*
  * this functions takes in crypto specific representation of
diff --git a/src/plugins/preauth/pkinit/pkinit_kdf_test.c b/src/plugins/preauth/pkinit/pkinit_kdf_test.c
index 3d0f7198e9..122ea54853 100644
--- a/src/plugins/preauth/pkinit/pkinit_kdf_test.c
+++ b/src/plugins/preauth/pkinit/pkinit_kdf_test.c
@@ -45,7 +45,6 @@ char eighteen_bs[9];
 char party_u_name[] = "lha@SU.SE";
 char party_v_name[] = "krbtgt/SU.SE@SU.SE";
 int enctype_aes = ENCTYPE_AES256_CTS_HMAC_SHA1_96;
-int enctype_des3 = ENCTYPE_DES3_CBC_SHA1;
 const krb5_data lha_data = DATA_FROM_STRING("lha");
 
 krb5_octet key1_hex[] =
@@ -176,32 +175,6 @@ main(int argc, char **argv)
         goto cleanup;
     }
 
-    /* TEST 3: SHA-512/DES3 */
-    /* set up algorithm id */
-    alg_id.algorithm = kdf_sha512_id;
-
-    enctype = enctype_des3;
-
-    retval = pkinit_kdf(context, &secret, &alg_id.algorithm, u_principal,
-                        v_principal, enctype, &as_req, &pk_as_rep, &key_block);
-    if (retval) {
-        printf("ERROR in pkinit_kdf_test: kdf call failed, retval = %d\n",
-               retval);
-        goto cleanup;
-    }
-
-    /* compare key to expected key value */
-
-    if ((key_block.length == sizeof(key3_hex)) &&
-        (0 == memcmp(key_block.contents, key3_hex, key_block.length))) {
-        printf("SUCCESS: TEST 3 (SHA-512/DES3), Correct key value generated.\n");
-        retval = 0;
-    } else {
-        printf("FAILURE: TEST 2 (SHA-512/DES3), Incorrect key value generated!\n");
-        retval = 1;
-        goto cleanup;
-    }
-
 cleanup:
     /* release all allocated resources, whether good or bad return */
     free(secret.data);
diff --git a/src/plugins/preauth/spake/t_vectors.c b/src/plugins/preauth/spake/t_vectors.c
index 983b30597b..ecffd3d7ee 100644
--- a/src/plugins/preauth/spake/t_vectors.c
+++ b/src/plugins/preauth/spake/t_vectors.c
@@ -56,31 +56,6 @@ struct test {
     const char *K2;
     const char *K3;
 } tests[] = {
-    { ENCTYPE_DES3_CBC_SHA1, SPAKE_GROUP_EDWARDS25519,
-      /* initial key, w, x, y, T, S, K */
-      "850BB51358548CD05E86768C313E3BFEF7511937DCF72C3E",
-      "686D84730CB8679AE95416C6567C6A63F2C9CEF124F7A3371AE81E11CAD42A37",
-      "201012D07BFD48DDFA33C4AAC4FB1E229FB0D043CFE65EBFB14399091C71A723",
-      "500B294797B8B042ACA1BEDC0F5931A4F52C537B3608B2D05CC8A2372F439F25",
-      "18F511E750C97B592ACD30DB7D9E5FCA660389102E6BF610C1BFBED4616C8362",
-      "5D10705E0D1E43D5DBF30240CCFBDE4A0230C70D4C79147AB0B317EDAD2F8AE7",
-      "25BDE0D875F0FEB5755F45BA5E857889D916ECF7476F116AA31DC3E037EC4292",
-      /* support, challenge, thash, body */
-      "A0093007A0053003020101",
-      "A1363034A003020101A122042018F511E750C97B592ACD30DB7D9E5FCA660389"
-      "102E6BF610C1BFBED4616C8362A20930073005A003020101",
-      "EAAA08807D0616026FF51C849EFBF35BA0CE3C5300E7D486DA46351B13D4605B",
-      "3075A00703050000000000A1143012A003020101A10B30091B07726165627572"
-      "6EA2101B0E415448454E412E4D49542E454455A3233021A003020102A11A3018"
-      "1B066B72627467741B0E415448454E412E4D49542E454455A511180F31393730"
-      "303130313030303030305AA703020100A8053003020110",
-      /* K'[0], K'[1], K'[2], K'[3] */
-      "BAF12FAE7CD958CBF1A29BFBC71F89CE49E03E295D89DAFD",
-      "64F73DD9C41908206BCEC1F719026B574F9D13463D7A2520",
-      "0454520B086B152C455829E6BAEFF78A61DFE9E3D04A895D",
-      "4A92260B25E3EF94C125D5C24C3E5BCED5B37976E67F25C4",
-    },
-
     { ENCTYPE_ARCFOUR_HMAC, SPAKE_GROUP_EDWARDS25519,
       /* initial key, w, x, y, T, S, K */
       "8846F7EAEE8FB117AD06BDD830B7586C",
diff --git a/src/tests/gssapi/t_enctypes.py b/src/tests/gssapi/t_enctypes.py
index f5f11842e2..1bb8c40b6b 100755
--- a/src/tests/gssapi/t_enctypes.py
+++ b/src/tests/gssapi/t_enctypes.py
@@ -1,25 +1,17 @@
 from k5test import *
 
-# Define some convenience abbreviations for enctypes we will see in
-# test program output.  For background, aes256 and aes128 are "CFX
-# enctypes", meaning that they imply support for RFC 4121, while des3
-# and rc4 are not.  DES3 keys will appear as 'des3-cbc-raw' in
-# t_enctypes output because that's how GSSAPI does raw triple-DES
-# encryption without the RFC3961 framing.
+# Define some convenience abbreviations for enctypes we will see in test
+# program output.  For background, aes256 and aes128 are "CFX enctypes",
+# meaning that they imply support for RFC 4121, while rc4 does not.
 aes256 = 'aes256-cts-hmac-sha1-96'
 aes128 = 'aes128-cts-hmac-sha1-96'
-des3 = 'des3-cbc-sha1'
-d_des3 = 'DEPRECATED:des3-cbc-sha1'
-des3raw = 'des3-cbc-raw'
-d_des3raw = 'DEPRECATED:des3-cbc-raw'
 rc4 = 'arcfour-hmac'
 d_rc4 = 'DEPRECATED:arcfour-hmac'
 
 # These tests make assumptions about the default enctype lists, so set
 # them explicitly rather than relying on the library defaults.
-supp='aes256-cts:normal aes128-cts:normal des3-cbc-sha1:normal rc4-hmac:normal'
-conf = {'libdefaults': {'permitted_enctypes': 'aes des3 rc4',
-                        'allow_des3': 'true', 'allow_rc4': 'true'},
+supp='aes256-cts:normal aes128-cts:normal rc4-hmac:normal'
+conf = {'libdefaults': {'permitted_enctypes': 'aes rc4', 'allow_rc4': 'true'},
         'realms': {'$realm': {'supported_enctypes': supp}}}
 realm = K5Realm(krb5_conf=conf)
 shutil.copyfile(realm.ccache, os.path.join(realm.testdir, 'save'))
@@ -88,19 +80,12 @@ test('both aes128', 'aes128-cts', 'aes128-cts',
 test_err('acc aes128', None, 'aes128-cts',
          'Encryption type aes256-cts-hmac-sha1-96 not permitted')
 
-# If the initiator constrains the permitted session enctypes to des3,
-# no acceptor subkey will be generated because we can't upgrade to a
-# CFX enctype.
-test('init des3', 'des3', None,
-     tktenc=aes256, tktsession=d_des3,
-     proto='rfc1964', isubkey=des3raw, asubkey=None)
-
 # Force the ticket session key to be rc4, so we can test some subkey
 # upgrade cases.  The ticket encryption key remains aes256.
 realm.run([kadminl, 'setstr', realm.host_princ, 'session_enctypes', 'rc4'])
 
 # With no arguments, the initiator should send an upgrade list of
-# [aes256 aes128 des3] and the acceptor should upgrade to an aes256
+# [aes256 aes128] and the acceptor should upgrade to an aes256
 # subkey.
 test('upgrade noargs', None, None,
      tktenc=aes256, tktsession=d_rc4,
@@ -116,13 +101,6 @@ test('upgrade init aes128+rc4', 'aes128-cts rc4', None,
      tktenc=aes256, tktsession=d_rc4,
      proto='cfx', isubkey=rc4, asubkey=aes128)
 
-# If the initiator permits rc4 but prefers des3, it will send an
-# upgrade list of [des3], but the acceptor won't generate a subkey
-# because des3 isn't a CFX enctype.
-test('upgrade init des3+rc4', 'des3 rc4', None,
-     tktenc=aes256, tktsession=d_rc4,
-     proto='rfc1964', isubkey=rc4, asubkey=None)
-
 # If the acceptor permits only aes128, subkey negotiation will fail
 # because the ticket session key and initiator subkey are
 # non-permitted.  (This is unfortunate if the acceptor's restriction
diff --git a/src/tests/gssapi/t_invalid.c b/src/tests/gssapi/t_invalid.c
index a558a68132..0a38ea2b18 100644
--- a/src/tests/gssapi/t_invalid.c
+++ b/src/tests/gssapi/t_invalid.c
@@ -104,32 +104,6 @@ struct test {
     size_t wrap2len;
     const char *wrap2;
 } tests[] = {
-    {
-        ENCTYPE_DES3_CBC_SHA1, ENCTYPE_DES3_CBC_RAW,
-        SEAL_ALG_DES3KD, SGN_ALG_HMAC_SHA1_DES3_KD, 20,
-        24,
-        "\x4F\xEA\x19\x19\x5E\x0E\x10\xDF\x3D\x29\xB5\x13\x8F\x01\xC7\xA7"
-        "\x92\x3D\x38\xF7\x26\x73\x0D\x6D",
-        65,
-        "\x60\x3F\x06\x09\x2A\x86\x48\x86\xF7\x12\x01\x02\x02\x02\x01\x04"
-        "\x00\x02\x00\xFF\xFF\xEB\xF3\x9A\x89\x24\x57\xB8\x63\x95\x25\xE8"
-        "\x6E\x8E\x79\xE6\x2E\xCA\xD3\xFF\x57\x9F\x8C\xAB\xEF\xDD\x28\x10"
-        "\x2F\x93\x21\x2E\xF2\x52\xB6\x6F\xA8\xBB\x8A\x6D\xAA\x6F\xB7\xF4\xD4",
-        49,
-        "\x60\x2F\x06\x09\x2A\x86\x48\x86\xF7\x12\x01\x02\x02\x01\x01\x04"
-        "\x00\xFF\xFF\xFF\xFF\x57\xF5\x77\xC6\xC0\x72\x26\x97\x00\x89\xB2"
-        "\xEE\xD9\xD1\x90\xE7\x11\x50\x4F\xE9\x59\x18\xB1\x8F\x82\x8E\x8F\x5E",
-        65,
-        "\x60\x3F\x06\x09\x2A\x86\x48\x86\xF7\x12\x01\x02\x02\x02\x01\x04"
-        "\x00\xFF\xFF\xFF\xFF\x0B\x81\x56\x4A\x02\x1B\xBE\x83\x2B\x35\x08"
-        "\x7B\x49\x15\x07\x97\x6A\x64\xEF\xDD\x32\x52\xF0\xA2\xE2\x62\x9B"
-        "\xA7\x72\xF7\x3D\x6B\x2D\xAC\x21\xE9\x6D\x65\x73\x73\x61\x67\x65\x01",
-        65,
-        "\x60\x3F\x06\x09\x2A\x86\x48\x86\xF7\x12\x01\x02\x02\x02\x01\x04"
-        "\x00\x02\x00\xFF\xFF\x66\x5A\xE1\xC8\x4F\x69\x33\x97\x5D\x05\xE2"
-        "\x86\x40\x14\x15\x14\x27\x01\x9F\x32\x9D\x82\xF4\xE1\xC5\x3E\xFA"
-        "\x6D\x7D\x05\x39\xAE\x21\x44\xA0\x87\xA6\x24\xED\xFC\xA3\x53\xF1\x30"
-    },
     {
         ENCTYPE_ARCFOUR_HMAC, ENCTYPE_ARCFOUR_HMAC,
         SEAL_ALG_MICROSOFT_RC4, SGN_ALG_HMAC_MD5, 8,
diff --git a/src/tests/gssapi/t_pcontok.c b/src/tests/gssapi/t_pcontok.c
index 7368f752f0..bf22bd3da1 100644
--- a/src/tests/gssapi/t_pcontok.c
+++ b/src/tests/gssapi/t_pcontok.c
@@ -43,7 +43,6 @@
 #include "k5-int.h"
 #include "common.h"
 
-#define SGN_ALG_HMAC_SHA1_DES3_KD 0x04
 #define SGN_ALG_HMAC_MD5          0x11
 
 /*
@@ -77,17 +76,12 @@ make_delete_token(gss_krb5_lucid_context_v1_t *lctx, gss_buffer_desc *out)
     ret = krb5_k_create_key(context, &seqkb, &seq);
     check_k5err(context, "krb5_k_create_key", ret);
 
-    if (signalg == SGN_ALG_HMAC_SHA1_DES3_KD) {
-        cktype = CKSUMTYPE_HMAC_SHA1_DES3;
-        cksize = 20;
-        ckusage = 23;
-    } else if (signalg == SGN_ALG_HMAC_MD5) {
-        cktype = CKSUMTYPE_HMAC_MD5_ARCFOUR;
-        cksize = 8;
-        ckusage = 15;
-    } else {
+    if (signalg != SGN_ALG_HMAC_MD5)
         abort();
-    }
+
+    cktype = CKSUMTYPE_HMAC_MD5_ARCFOUR;
+    cksize = 8;
+    ckusage = 15;
 
     tlen = 20 + mech_krb5.length + cksize;
     token = malloc(tlen);
diff --git a/src/tests/gssapi/t_prf.c b/src/tests/gssapi/t_prf.c
index f71774cdc9..d1857c433f 100644
--- a/src/tests/gssapi/t_prf.c
+++ b/src/tests/gssapi/t_prf.c
@@ -41,13 +41,6 @@ static struct {
     const char *key2;
     const char *out2;
 } tests[] = {
-    { ENCTYPE_DES3_CBC_SHA1,
-      "70378A19CD64134580C27C0115D6B34A1CF2FEECEF9886A2",
-      "9F8D127C520BB826BFF3E0FE5EF352389C17E0C073D9"
-      "AC4A333D644D21BA3EF24F4A886D143F85AC9F6377FB",
-      "3452A167DF1094BA1089E0A20E9E51ABEF1525922558B69E",
-      "6BF24FABC858F8DD9752E4FCD331BB831F238B5BE190"
-      "4EEA42E38F7A60C588F075C5C96A67E7F8B7BD0AECF4" },
     { ENCTYPE_ARCFOUR_HMAC,
       "3BB3AE288C12B3B9D06B208A4151B3B6",
       "9AEA11A3BCF3C53F1F91F5A0BA2132E2501ADF5F3C28"
diff --git a/src/tests/t_authdata.py b/src/tests/t_authdata.py
index bde1c36844..8fcd30db51 100644
--- a/src/tests/t_authdata.py
+++ b/src/tests/t_authdata.py
@@ -179,7 +179,7 @@ realm.run([kvno, 'restricted'])
 # preferred krbtgt enctype changes.
 mark('#8139 regression test')
 realm.kinit(realm.user_princ, password('user'), ['-f'])
-realm.run([kadminl, 'cpw', '-randkey', '-keepold', '-e', 'des3-cbc-sha1',
+realm.run([kadminl, 'cpw', '-randkey', '-keepold', '-e', 'aes256-sha2',
            realm.krbtgt_princ])
 realm.run(['./forward'])
 realm.run([kvno, realm.host_princ])
diff --git a/src/tests/t_etype_info.py b/src/tests/t_etype_info.py
index 38cf96ca8f..e82ff7ff07 100644
--- a/src/tests/t_etype_info.py
+++ b/src/tests/t_etype_info.py
@@ -1,7 +1,7 @@
 from k5test import *
 
-supported_enctypes = 'aes128-cts des3-cbc-sha1 rc4-hmac'
-conf = {'libdefaults': {'allow_des3': 'true', 'allow_rc4': 'true'},
+supported_enctypes = 'aes128-cts rc4-hmac'
+conf = {'libdefaults': {'allow_rc4': 'true'},
         'realms': {'$realm': {'supported_enctypes': supported_enctypes}}}
 realm = K5Realm(create_host=False, get_creds=False, krb5_conf=conf)
 
@@ -26,9 +26,9 @@ def test_etinfo(princ, enctypes, expected_lines):
 # With no newer enctypes in the request, PA-ETYPE-INFO2,
 # PA-ETYPE-INFO, and PA-PW-SALT appear in the AS-REP, each listing one
 # key for the most preferred matching enctype.
-test_etinfo('user', 'rc4-hmac-exp des3 rc4',
-            ['asrep etype_info2 des3-cbc-sha1 KRBTEST.COMuser',
-             'asrep etype_info des3-cbc-sha1 KRBTEST.COMuser',
+test_etinfo('user', 'rc4-hmac-exp rc4',
+            ['asrep etype_info2 rc4-hmac KRBTEST.COMuser',
+             'asrep etype_info rc4-hmac KRBTEST.COMuser',
              'asrep pw_salt KRBTEST.COMuser'])
 
 # With a newer enctype in the request (even if it is not the most
@@ -39,9 +39,9 @@ test_etinfo('user', 'rc4 aes256-cts',
 
 # In preauth-required errors, PA-PW-SALT does not appear, but the same
 # etype-info2 values are expected.
-test_etinfo('preauthuser', 'rc4-hmac-exp des3 rc4',
-            ['error etype_info2 des3-cbc-sha1 KRBTEST.COMpreauthuser',
-             'error etype_info des3-cbc-sha1 KRBTEST.COMpreauthuser'])
+test_etinfo('preauthuser', 'rc4-hmac-exp rc4',
+            ['error etype_info2 rc4-hmac KRBTEST.COMpreauthuser',
+             'error etype_info rc4-hmac KRBTEST.COMpreauthuser'])
 test_etinfo('preauthuser', 'rc4 aes256-cts',
             ['error etype_info2 rc4-hmac KRBTEST.COMpreauthuser'])
 
@@ -50,8 +50,8 @@ test_etinfo('preauthuser', 'rc4 aes256-cts',
 # (to allow for preauth mechs which don't depend on long-term keys).
 # An AS-REP cannot be generated without preauth as there is no reply
 # key.
-test_etinfo('rc4user', 'des3', [])
-test_etinfo('nokeyuser', 'des3', [])
+test_etinfo('rc4user', 'aes128-cts', [])
+test_etinfo('nokeyuser', 'aes128-cts', [])
 
 # Verify that etype-info2 is included in a MORE_PREAUTH_DATA_REQUIRED
 # error if the client does optimistic preauth.
diff --git a/src/tests/t_keyrollover.py b/src/tests/t_keyrollover.py
index 036c0c3c6f..77481336ca 100755
--- a/src/tests/t_keyrollover.py
+++ b/src/tests/t_keyrollover.py
@@ -38,9 +38,9 @@ realm.run([klist, '-e'], expected_msg=msg)
 
 # Test that the KDC only accepts the first enctype for a kvno, for a
 # local-realm TGS request.  To set this up, we abuse an edge-case
-# behavior of modprinc -kvno.  First, set up a DES3 krbtgt entry at
+# behavior of modprinc -kvno.  First, set up an aes128-sha2 krbtgt entry at
 # kvno 1 and cache a krbtgt ticket.
-realm.run([kadminl, 'cpw', '-randkey', '-e', 'des3-cbc-sha1',
+realm.run([kadminl, 'cpw', '-randkey', '-e', 'aes128-cts-hmac-sha256-128',
            realm.krbtgt_princ])
 realm.run([kadminl, 'modprinc', '-kvno', '1', realm.krbtgt_princ])
 realm.kinit(realm.user_princ, password('user'))
@@ -51,9 +51,9 @@ realm.run([kadminl, 'cpw', '-randkey', '-keepold', '-e', 'aes256-cts',
 realm.run([kadminl, 'modprinc', '-kvno', '1', realm.krbtgt_princ])
 out = realm.run([kadminl, 'getprinc', realm.krbtgt_princ])
 if 'vno 1, aes256-cts' not in out or \
-   'vno 1, DEPRECATED:des3-cbc-sha1' not in out:
+   'vno 1, aes128-cts-hmac-sha256-128' not in out:
     fail('keyrollover: setup for TGS enctype test failed')
-# Now present the DES3 ticket to the KDC and make sure it's rejected.
+# Now present the aes128-sha2 ticket to the KDC and make sure it's rejected.
 realm.run([kvno, realm.host_princ], expected_code=1)
 
 # Test -keepold limit for self-service requests through kadmind.
diff --git a/src/tests/t_mkey.py b/src/tests/t_mkey.py
index 32f4070bcb..da0ed1831e 100755
--- a/src/tests/t_mkey.py
+++ b/src/tests/t_mkey.py
@@ -7,7 +7,6 @@ import struct
 # default enctype for master keys.
 aes256 = 'aes256-cts-hmac-sha1-96'
 aes128 = 'aes128-cts-hmac-sha1-96'
-des3 = 'des3-cbc-sha1'
 defetype = aes256
 
 realm = K5Realm(create_host=False, start_kadmind=True)
@@ -300,40 +299,6 @@ if 'Decrypt integrity check failed' in out or 'added to keytab' not in out:
 
 realm.stop()
 
-# Load a dump file created with krb5 1.6, before the master key
-# rollover changes were introduced.  Write out an old-format stash
-# file consistent with the dump's master password ("footes").  The K/M
-# entry in this database will not have actkvno tl-data because it was
-# created prior to master key rollover support.  Verify that:
-# 1. We can access the database using the old-format stash file.
-# 2. list_mkeys displays the same list as for a post-1.7 KDB.
-mark('pre-1.7 stash file')
-dumpfile = os.path.join(srctop, 'tests', 'dumpfiles', 'dump.16')
-os.remove(stash_file)
-f = open(stash_file, 'wb')
-f.write(struct.pack('=HL24s', 16, 24,
-                    b'\xF8\x3E\xFB\xBA\x6D\x80\xD9\x54\xE5\x5D\xF2\xE0'
-                    b'\x94\xAD\x6D\x86\xB5\x16\x37\xEC\x7C\x8A\xBC\x86'))
-f.close()
-realm.run([kdb5_util, 'load', dumpfile])
-nprincs = len(realm.run([kadminl, 'listprincs']).splitlines())
-check_mkvno('K/M', 1)
-check_mkey_list((1, des3, True, True))
-
-# Create a new master key and verify that, without actkvkno tl-data:
-# 1. list_mkeys displays the same as for a post-1.7 KDB.
-# 2. update_princ_encryption still targets mkvno 1.
-# 3. libkadm5 still uses mkvno 1 for key changes.
-# 4. use_mkey creates the same list as for a post-1.7 KDB.
-mark('rollover from pre-1.7 KDB')
-add_mkey([])
-check_mkey_list((2, defetype, False, False), (1, des3, True, True))
-update_princ_encryption(False, 1, 0, nprincs - 1)
-realm.run([kadminl, 'addprinc', '-randkey', realm.user_princ])
-check_mkvno(realm.user_princ, 1)
-realm.run([kdb5_util, 'use_mkey', '2', 'now-1day'])
-check_mkey_list((2, defetype, True, True), (1, des3, True, False))
-
 # Regression test for #8395.  Purge the master key and verify that a
 # master key fetch does not segfault.
 mark('#8395 regression test')
diff --git a/src/tests/t_salt.py b/src/tests/t_salt.py
index 65084bbf35..55ca897459 100755
--- a/src/tests/t_salt.py
+++ b/src/tests/t_salt.py
@@ -16,13 +16,12 @@ def test_salt(realm, e1, salt, e2):
 
 # Enctype/salt pairs chosen with non-default salt types.
 # The enctypes are mostly arbitrary.
-salts = [('des3-cbc-sha1', 'norealm'),
+salts = [('aes128-cts-hmac-sha1-96', 'norealm'),
          ('arcfour-hmac', 'onlyrealm'),
          ('aes128-cts-hmac-sha1-96', 'special')]
 # These enctypes are chosen to cover the different string-to-key routines.
 # Omit ":normal" from aes256 to check that salttype defaulting works.
-second_kstypes = ['aes256-cts-hmac-sha1-96', 'arcfour-hmac:normal',
-                  'des3-cbc-sha1:normal']
+second_kstypes = ['aes256-cts-hmac-sha1-96', 'arcfour-hmac:normal']
 
 # Test using different salt types in a principal's key list.
 # Parameters from one key in the list must not leak over to later ones.
diff --git a/src/tests/t_sesskeynego.py b/src/tests/t_sesskeynego.py
index 5a213617b5..c7dba0ff5b 100755
--- a/src/tests/t_sesskeynego.py
+++ b/src/tests/t_sesskeynego.py
@@ -26,7 +26,6 @@ conf3 = {'libdefaults': {
         'default_tgs_enctypes': 'rc4-hmac,aes128-cts'}}
 conf4 = {'libdefaults': {'permitted_enctypes': 'aes256-cts'}}
 conf5 = {'libdefaults': {'allow_rc4': 'true'}}
-conf6 = {'libdefaults': {'allow_des3': 'true'}}
 # Test with client request and session_enctypes preferring aes128, but
 # aes256 long-term key.
 realm = K5Realm(krb5_conf=conf1, create_host=False, get_creds=False)
@@ -78,13 +77,6 @@ realm.run([kadminl, 'setstr', 'server', 'session_enctypes', 'rc4-hmac'])
 test_kvno(realm, 'DEPRECATED:arcfour-hmac', 'aes256-cts-hmac-sha1-96')
 realm.stop()
 
-# 6: allow_des3 permits negotiation of des3-cbc-sha1 session key.
-realm = K5Realm(krb5_conf=conf6, create_host=False, get_creds=False)
-realm.run([kadminl, 'addprinc', '-randkey', '-e', 'aes256-cts', 'server'])
-realm.run([kadminl, 'setstr', 'server', 'session_enctypes', 'des3-cbc-sha1'])
-test_kvno(realm, 'DEPRECATED:des3-cbc-sha1', 'aes256-cts-hmac-sha1-96')
-realm.stop()
-
 # 7: default config negotiates aes256-sha1 session key for RC4-only service.
 realm = K5Realm(create_host=False, get_creds=False)
 realm.run([kadminl, 'addprinc', '-randkey', '-e', 'rc4-hmac', 'server'])
diff --git a/src/util/k5test.py b/src/util/k5test.py
index d22cb5c804..cba6ca0a61 100644
--- a/src/util/k5test.py
+++ b/src/util/k5test.py
@@ -1388,13 +1388,6 @@ _passes = [
     # No special settings; exercises AES256.
     ('default', None, None, None),
 
-    # Exercise the DES3 enctype.
-    ('des3', None,
-     {'libdefaults': {'permitted_enctypes': 'des3', 'allow_des3': 'true'}},
-     {'realms': {'$realm': {
-                    'supported_enctypes': 'des3-cbc-sha1:normal',
-                    'master_key_type': 'des3-cbc-sha1'}}}),
-
     # Exercise the arcfour enctype.
     ('arcfour', None,
      {'libdefaults': {'permitted_enctypes': 'rc4', 'allow_rc4': 'true'}},
diff --git a/src/windows/leash/htmlhelp/html/Encryption_Types.htm b/src/windows/leash/htmlhelp/html/Encryption_Types.htm
index 1aebdd0b4a..c38eefd2bd 100644
--- a/src/windows/leash/htmlhelp/html/Encryption_Types.htm
+++ b/src/windows/leash/htmlhelp/html/Encryption_Types.htm
@@ -79,19 +79,6 @@ will have an entry in the Encryption type column. <br>
 <th>Description</th>
 </tr>
 <tr>
-<th id="th2"> des3- </th>
-   <td> The triple DES family improves on
-the original DES (Data Encryption Standard) by using 3 separate 56-bit
-keys. Some modes of 3DES are considered weak while others are strong
-(if slow). <ul id="helpul">
-<li> des3-cbc-sha1</li>
-<li> des3-cbc-raw  (<b>weak</b>) </li>
-<li>des3-hmac-sha1 </li>
-<li>des3-cbc-sha1-kd </li>
-</ul>
-</td>
- </tr>
-<tr>
 <th id="th2"> aes </th>
      <td>The AES Advanced Encryption Standard
 family, like 3DES, is a symmetric block cipher and was designed
-- 
2.53.0


From f6b425e86cec7feb91d62a9d312f2660f06ac2ac Mon Sep 17 00:00:00 2001
From: Robbie Harwood <rharwood@redhat.com>
Date: Tue, 23 Aug 2016 16:29:58 -0400
Subject: [PATCH 06/21] PAM: Add integration to ksu

Modify ksu so that it performs account and session management on behalf of
the target user account, mimicking the action of regular su.  The default
service name is "ksu", because on Fedora at least the configuration used
is determined by whether or not a login shell is being opened, and so
this may need to vary, too.  At run-time, ksu's behavior can be reset to
the earlier, non-PAM behavior by setting "use_pam" to false in the [ksu]
section of /etc/krb5.conf.

When enabled, ksu gains a dependency on libpam.

Originally RT#5939, though it's changed since then to perform the account
and session management before dropping privileges, and to apply on top of
changes we're proposing for how it handles cache collections.

Last-updated: krb5-1.21.1-final
Forward-ported-by: Andreas Schneider <asn@redhat.com>
---
 src/aclocal.m4              |  69 +++++++
 src/clients/ksu/Makefile.in |   8 +-
 src/clients/ksu/main.c      |  89 ++++++++-
 src/clients/ksu/pam.c       | 389 ++++++++++++++++++++++++++++++++++++
 src/clients/ksu/pam.h       |  57 ++++++
 src/configure.ac            |   2 +
 6 files changed, 611 insertions(+), 3 deletions(-)
 create mode 100644 src/clients/ksu/pam.c
 create mode 100644 src/clients/ksu/pam.h

diff --git a/src/aclocal.m4 b/src/aclocal.m4
index 7397bdcc2b..3d9b02c21a 100644
--- a/src/aclocal.m4
+++ b/src/aclocal.m4
@@ -1413,3 +1413,72 @@ if test "$with_ldap" = yes; then
   OPENLDAP_PLUGIN=yes
 fi
 ])dnl
+dnl
+dnl
+dnl Use PAM instead of local crypt() compare for checking local passwords,
+dnl and perform PAM account, session management, and password-changing where
+dnl appropriate.
+dnl
+AC_DEFUN(KRB5_WITH_PAM,[
+AC_ARG_WITH(pam,[AC_HELP_STRING(--with-pam,[compile with PAM support])],
+	    withpam="$withval",withpam=auto)
+AC_ARG_WITH(pam-ksu-service,[AC_HELP_STRING(--with-ksu-service,[PAM service name for ksu ["ksu"]])],
+	    withksupamservice="$withval",withksupamservice=ksu)
+old_LIBS="$LIBS"
+PAM_LIBS=
+if test "$withpam" != no ; then
+	AC_MSG_RESULT([checking for PAM...])
+
+	AC_CHECK_HEADERS(security/pam_appl.h)
+	if test "x$ac_cv_header_security_pam_appl_h" != xyes ; then
+		if test "$withpam" = auto ; then
+			AC_MSG_RESULT([Unable to locate security/pam_appl.h.])
+			withpam=no
+		else
+			AC_MSG_ERROR([Unable to locate security/pam_appl.h.])
+		fi
+	else
+		LIBS=
+		unset ac_cv_func_pam_start
+		AC_CHECK_FUNCS(putenv pam_start)
+		if test "x$ac_cv_func_pam_start" = xno ; then
+			unset ac_cv_func_pam_start
+			AC_CHECK_LIB(dl,dlopen)
+			AC_CHECK_FUNCS(pam_start)
+			if test "x$ac_cv_func_pam_start" = xno ; then
+				AC_CHECK_LIB(pam,pam_start)
+				unset ac_cv_func_pam_start
+				unset ac_cv_func_pam_getenvlist
+				AC_CHECK_FUNCS(pam_start pam_getenvlist)
+				if test "x$ac_cv_func_pam_start" = xyes ; then
+					PAM_LIBS="$LIBS"
+				else
+					if test "$withpam" = auto ; then
+						AC_MSG_RESULT([Unable to locate libpam.])
+						withpam=no
+					else
+						AC_MSG_ERROR([Unable to locate libpam.])
+					fi
+				fi
+			fi
+		fi
+		if test "$withpam" != no ; then
+			AC_MSG_NOTICE([building with PAM support])
+			AC_DEFINE(USE_PAM,1,[Define if Kerberos-aware tools should support PAM])
+			AC_DEFINE_UNQUOTED(KSU_PAM_SERVICE,"$withksupamservice",
+					   [Define to the name of the PAM service name to be used by ksu.])
+			PAM_LIBS="$LIBS"
+			NON_PAM_MAN=".\\\" "
+			PAM_MAN=
+		fi
+	fi
+	if test "$withpam" = no ; then
+		PAM_MAN=".\\\" "
+		NON_PAM_MAN=
+	fi
+fi
+LIBS="$old_LIBS"
+AC_SUBST(PAM_LIBS)
+AC_SUBST(PAM_MAN)
+AC_SUBST(NON_PAM_MAN)
+])dnl
diff --git a/src/clients/ksu/Makefile.in b/src/clients/ksu/Makefile.in
index 9a892e6656..5c9845c1f7 100644
--- a/src/clients/ksu/Makefile.in
+++ b/src/clients/ksu/Makefile.in
@@ -3,12 +3,14 @@ BUILDTOP=$(REL)..$(S)..
 DEFINES = -DGET_TGT_VIA_PASSWD -DPRINC_LOOK_AHEAD -DCMD_PATH='"/usr/local/sbin /usr/local/bin /sbin /bin /usr/sbin /usr/bin"'
 
 KSU_LIBS=@KSU_LIBS@
+PAM_LIBS=@PAM_LIBS@
 
 SRCS = \
 	$(srcdir)/krb_auth_su.c \
 	$(srcdir)/ccache.c \
 	$(srcdir)/authorization.c \
 	$(srcdir)/main.c \
+	$(srcdir)/pam.c \
 	$(srcdir)/heuristic.c \
 	$(srcdir)/xmalloc.c \
 	$(srcdir)/setenv.c
@@ -17,13 +19,17 @@ OBJS = \
 	ccache.o \
 	authorization.o \
 	main.o \
+	pam.o \
 	heuristic.o \
 	xmalloc.o @SETENVOBJ@
 
 all: ksu
 
 ksu: $(OBJS) $(KRB5_BASE_DEPLIBS)
-	$(CC_LINK) -o $@ $(OBJS) $(KRB5_BASE_LIBS) $(KSU_LIBS)
+	$(CC_LINK) -o $@ $(OBJS) $(KRB5_BASE_LIBS) $(KSU_LIBS) $(PAM_LIBS)
+
+pam.o: pam.c
+	$(CC) $(ALL_CFLAGS) -c $<
 
 clean:
 	$(RM) ksu
diff --git a/src/clients/ksu/main.c b/src/clients/ksu/main.c
index ca3981ea75..443bacea16 100644
--- a/src/clients/ksu/main.c
+++ b/src/clients/ksu/main.c
@@ -26,6 +26,7 @@
  * KSU was written by:  Ari Medvinsky, ari@isi.edu
  */
 
+#include "autoconf.h"
 #include "ksu.h"
 #include "adm_proto.h"
 #include <sys/types.h>
@@ -33,6 +34,10 @@
 #include <signal.h>
 #include <grp.h>
 
+#ifdef USE_PAM
+#include "pam.h"
+#endif
+
 /* globals */
 char * prog_name;
 int auth_debug =0;
@@ -40,6 +45,7 @@ char k5login_path[MAXPATHLEN];
 char k5users_path[MAXPATHLEN];
 char * gb_err = NULL;
 int quiet = 0;
+int force_fork = 0;
 /***********/
 
 #define KS_TEMPORARY_CACHE "MEMORY:_ksu"
@@ -523,6 +529,23 @@ main(int argc, char ** argv)
                prog_name,target_user,client_name,
                source_user,ontty());
 
+#ifdef USE_PAM
+        if (appl_pam_enabled(ksu_context, "ksu")) {
+            if (appl_pam_acct_mgmt(KSU_PAM_SERVICE, 1, target_user, NULL,
+                                   NULL, source_user,
+                                   ttyname(STDERR_FILENO)) != 0) {
+                fprintf(stderr, "Access denied for %s.\n", target_user);
+                exit(1);
+            }
+            if (appl_pam_requires_chauthtok()) {
+                fprintf(stderr, "Password change required for %s.\n",
+                        target_user);
+                exit(1);
+            }
+            force_fork++;
+        }
+#endif
+
         /* Run authorization as target.*/
         if (krb5_seteuid(target_uid)) {
             com_err(prog_name, errno, _("while switching to target for "
@@ -583,6 +606,24 @@ main(int argc, char ** argv)
 
             exit(1);
         }
+#ifdef USE_PAM
+    } else {
+        /* we always do PAM account management, even for root */
+        if (appl_pam_enabled(ksu_context, "ksu")) {
+            if (appl_pam_acct_mgmt(KSU_PAM_SERVICE, 1, target_user, NULL,
+                                   NULL, source_user,
+                                   ttyname(STDERR_FILENO)) != 0) {
+                fprintf(stderr, "Access denied for %s.\n", target_user);
+                exit(1);
+            }
+            if (appl_pam_requires_chauthtok()) {
+                fprintf(stderr, "Password change required for %s.\n",
+                        target_user);
+                exit(1);
+            }
+            force_fork++;
+        }
+#endif
     }
 
     if( some_rest_copy){
@@ -640,6 +681,30 @@ main(int argc, char ** argv)
         exit(1);
     }
 
+#ifdef USE_PAM
+    if (appl_pam_enabled(ksu_context, "ksu")) {
+        if (appl_pam_session_open() != 0) {
+            fprintf(stderr, "Error opening session for %s.\n", target_user);
+            exit(1);
+        }
+#ifdef DEBUG
+        if (auth_debug){
+            printf(" Opened PAM session.\n");
+        }
+#endif
+        if (appl_pam_cred_init()) {
+            fprintf(stderr, "Error initializing credentials for %s.\n",
+                    target_user);
+            exit(1);
+        }
+#ifdef DEBUG
+        if (auth_debug){
+            printf(" Initialized PAM credentials.\n");
+        }
+#endif
+    }
+#endif
+
     /* set permissions */
     if (setgid(target_pwd->pw_gid) < 0) {
         perror("ksu: setgid");
@@ -737,7 +802,7 @@ main(int argc, char ** argv)
         fprintf(stderr, "program to be execed %s\n",params[0]);
     }
 
-    if( keep_target_cache ) {
+    if( keep_target_cache && !force_fork ) {
         execv(params[0], params);
         com_err(prog_name, errno, _("while trying to execv %s"), params[0]);
         sweep_up(ksu_context, cc_target);
@@ -767,16 +832,36 @@ main(int argc, char ** argv)
             if (ret_pid == -1) {
                 com_err(prog_name, errno, _("while calling waitpid"));
             }
-            sweep_up(ksu_context, cc_target);
+            /* Destroy the target ccache unless -k was specified. */
+            if( !keep_target_cache ) {
+                sweep_up(ksu_context, cc_target);
+            }
             exit (WIFEXITED(statusp) ? WEXITSTATUS(statusp) : 1);
         case -1:
             com_err(prog_name, errno, _("while trying to fork."));
             sweep_up(ksu_context, cc_target);
             exit (1);
         case 0:
+#ifdef USE_PAM
+            if (appl_pam_enabled(ksu_context, "ksu")) {
+                if (appl_pam_setenv() != 0) {
+                    fprintf(stderr, "Error setting up environment for %s.\n",
+                            target_user);
+                    exit (1);
+                }
+#ifdef DEBUG
+                if (auth_debug){
+                    printf(" Set up PAM environment.\n");
+                }
+#endif
+            }
+#endif
             execv(params[0], params);
             com_err(prog_name, errno, _("while trying to execv %s"),
                     params[0]);
+            if( keep_target_cache ) {
+                sweep_up(ksu_context, cc_target);
+            }
             exit (1);
         }
     }
diff --git a/src/clients/ksu/pam.c b/src/clients/ksu/pam.c
new file mode 100644
index 0000000000..eb5d03bbf2
--- /dev/null
+++ b/src/clients/ksu/pam.c
@@ -0,0 +1,389 @@
+/*
+ * src/clients/ksu/pam.c
+ *
+ * Copyright 2007,2009,2010 Red Hat, Inc.
+ *
+ * All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  Redistributions of source code must retain the above copyright notice, this
+ *  list of conditions and the following disclaimer.
+ *
+ *  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.
+ *
+ *  Neither the name of Red Hat, Inc. 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 COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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.
+ *
+ * Convenience wrappers for using PAM.
+ */
+
+#include "autoconf.h"
+#ifdef USE_PAM
+#include <sys/types.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include "k5-int.h"
+#include "pam.h"
+
+#ifndef MAXPWSIZE
+#define MAXPWSIZE 128
+#endif
+
+static int appl_pam_started;
+static pid_t appl_pam_starter = -1;
+static int appl_pam_session_opened;
+static int appl_pam_creds_initialized;
+static int appl_pam_pwchange_required;
+static pam_handle_t *appl_pamh;
+static struct pam_conv appl_pam_conv;
+static char *appl_pam_user;
+struct appl_pam_non_interactive_args {
+	const char *user;
+	const char *password;
+};
+
+int
+appl_pam_enabled(krb5_context context, const char *section)
+{
+	int enabled = 1;
+	if ((context != NULL) && (context->profile != NULL)) {
+		if (profile_get_boolean(context->profile,
+					section,
+					USE_PAM_CONFIGURATION_KEYWORD,
+					NULL,
+					enabled, &enabled) != 0) {
+			enabled = 1;
+		}
+	}
+	return enabled;
+}
+
+void
+appl_pam_cleanup(void)
+{
+	if (getpid() != appl_pam_starter) {
+		return;
+	}
+#ifdef DEBUG
+	printf("Called to clean up PAM.\n");
+#endif
+	if (appl_pam_creds_initialized) {
+#ifdef DEBUG
+		printf("Deleting PAM credentials.\n");
+#endif
+		pam_setcred(appl_pamh, PAM_DELETE_CRED);
+		appl_pam_creds_initialized = 0;
+	}
+	if (appl_pam_session_opened) {
+#ifdef DEBUG
+		printf("Closing PAM session.\n");
+#endif
+		pam_close_session(appl_pamh, 0);
+		appl_pam_session_opened = 0;
+	}
+	appl_pam_pwchange_required = 0;
+	if (appl_pam_started) {
+#ifdef DEBUG
+		printf("Shutting down PAM.\n");
+#endif
+		pam_end(appl_pamh, 0);
+		appl_pam_started = 0;
+		appl_pam_starter = -1;
+		free(appl_pam_user);
+		appl_pam_user = NULL;
+	}
+}
+static int
+appl_pam_interactive_converse(int num_msg, const struct pam_message **msg,
+			      struct pam_response **presp, void *appdata_ptr)
+{
+	const struct pam_message *message;
+	struct pam_response *resp;
+	int i, code;
+	char *pwstring, pwbuf[MAXPWSIZE];
+	unsigned int pwsize;
+	resp = malloc(sizeof(struct pam_response) * num_msg);
+	if (resp == NULL) {
+		return PAM_BUF_ERR;
+	}
+	memset(resp, 0, sizeof(struct pam_response) * num_msg);
+	code = PAM_SUCCESS;
+	for (i = 0; i < num_msg; i++) {
+		message = &(msg[0][i]); /* XXX */
+		message = msg[i]; /* XXX */
+		pwstring = NULL;
+		switch (message->msg_style) {
+		case PAM_TEXT_INFO:
+		case PAM_ERROR_MSG:
+			printf("[%s]\n", message->msg ? message->msg : "");
+			fflush(stdout);
+			resp[i].resp = NULL;
+			resp[i].resp_retcode = PAM_SUCCESS;
+			break;
+		case PAM_PROMPT_ECHO_ON:
+		case PAM_PROMPT_ECHO_OFF:
+			if (message->msg_style == PAM_PROMPT_ECHO_ON) {
+				if (fgets(pwbuf, sizeof(pwbuf),
+					  stdin) != NULL) {
+					pwbuf[strcspn(pwbuf, "\r\n")] = '\0';
+					pwstring = pwbuf;
+				}
+			} else {
+				pwstring = getpass(message->msg ?
+						   message->msg :
+						   "");
+			}
+			if ((pwstring != NULL) && (pwstring[0] != '\0')) {
+				pwsize = strlen(pwstring);
+				resp[i].resp = malloc(pwsize + 1);
+				if (resp[i].resp == NULL) {
+					resp[i].resp_retcode = PAM_BUF_ERR;
+				} else {
+					memcpy(resp[i].resp, pwstring, pwsize);
+					resp[i].resp[pwsize] = '\0';
+					resp[i].resp_retcode = PAM_SUCCESS;
+				}
+			} else {
+				resp[i].resp_retcode = PAM_CONV_ERR;
+				code = PAM_CONV_ERR;
+			}
+			break;
+		default:
+			break;
+		}
+	}
+	*presp = resp;
+	return code;
+}
+static int
+appl_pam_non_interactive_converse(int num_msg,
+				  const struct pam_message **msg,
+				  struct pam_response **presp,
+				  void *appdata_ptr)
+{
+	const struct pam_message *message;
+	struct pam_response *resp;
+	int i, code;
+	unsigned int pwsize;
+	struct appl_pam_non_interactive_args *args;
+	const char *pwstring;
+	resp = malloc(sizeof(struct pam_response) * num_msg);
+	if (resp == NULL) {
+		return PAM_BUF_ERR;
+	}
+	args = appdata_ptr;
+	memset(resp, 0, sizeof(struct pam_response) * num_msg);
+	code = PAM_SUCCESS;
+	for (i = 0; i < num_msg; i++) {
+		message = &((*msg)[i]);
+		message = msg[i];
+		pwstring = NULL;
+		switch (message->msg_style) {
+		case PAM_TEXT_INFO:
+		case PAM_ERROR_MSG:
+			break;
+		case PAM_PROMPT_ECHO_ON:
+		case PAM_PROMPT_ECHO_OFF:
+			if (message->msg_style == PAM_PROMPT_ECHO_ON) {
+				/* assume "user" */
+				pwstring = args->user;
+			} else {
+				/* assume "password" */
+				pwstring = args->password;
+			}
+			if ((pwstring != NULL) && (pwstring[0] != '\0')) {
+				pwsize = strlen(pwstring);
+				resp[i].resp = malloc(pwsize + 1);
+				if (resp[i].resp == NULL) {
+					resp[i].resp_retcode = PAM_BUF_ERR;
+				} else {
+					memcpy(resp[i].resp, pwstring, pwsize);
+					resp[i].resp[pwsize] = '\0';
+					resp[i].resp_retcode = PAM_SUCCESS;
+				}
+			} else {
+				resp[i].resp_retcode = PAM_CONV_ERR;
+				code = PAM_CONV_ERR;
+			}
+			break;
+		default:
+			break;
+		}
+	}
+	*presp = resp;
+	return code;
+}
+static int
+appl_pam_start(const char *service, int interactive,
+	       const char *login_username,
+	       const char *non_interactive_password,
+	       const char *hostname,
+	       const char *ruser,
+	       const char *tty)
+{
+	static int exit_handler_registered;
+	static struct appl_pam_non_interactive_args args;
+	int ret = 0;
+	if (appl_pam_started &&
+	    (strcmp(login_username, appl_pam_user) != 0)) {
+		appl_pam_cleanup();
+		appl_pam_user = NULL;
+	}
+	if (!appl_pam_started) {
+#ifdef DEBUG
+		printf("Starting PAM up (service=\"%s\",user=\"%s\").\n",
+		       service, login_username);
+#endif
+		memset(&appl_pam_conv, 0, sizeof(appl_pam_conv));
+		appl_pam_conv.conv = interactive ?
+				     &appl_pam_interactive_converse :
+				     &appl_pam_non_interactive_converse;
+		memset(&args, 0, sizeof(args));
+		args.user = strdup(login_username);
+		args.password = non_interactive_password ?
+				strdup(non_interactive_password) :
+				NULL;
+		appl_pam_conv.appdata_ptr = &args;
+		ret = pam_start(service, login_username,
+				&appl_pam_conv, &appl_pamh);
+		if (ret == 0) {
+			if (hostname != NULL) {
+#ifdef DEBUG
+				printf("Setting PAM_RHOST to \"%s\".\n", hostname);
+#endif
+				pam_set_item(appl_pamh, PAM_RHOST, hostname);
+			}
+			if (ruser != NULL) {
+#ifdef DEBUG
+				printf("Setting PAM_RUSER to \"%s\".\n", ruser);
+#endif
+				pam_set_item(appl_pamh, PAM_RUSER, ruser);
+			}
+			if (tty != NULL) {
+#ifdef DEBUG
+				printf("Setting PAM_TTY to \"%s\".\n", tty);
+#endif
+				pam_set_item(appl_pamh, PAM_TTY, tty);
+			}
+			if (!exit_handler_registered &&
+			    (atexit(appl_pam_cleanup) != 0)) {
+				pam_end(appl_pamh, 0);
+				appl_pamh = NULL;
+				ret = -1;
+			} else {
+				appl_pam_started = 1;
+				appl_pam_starter = getpid();
+				appl_pam_user = strdup(login_username);
+				exit_handler_registered = 1;
+			}
+		}
+	}
+	return ret;
+}
+int
+appl_pam_acct_mgmt(const char *service, int interactive,
+		   const char *login_username,
+		   const char *non_interactive_password,
+		   const char *hostname,
+		   const char *ruser,
+		   const char *tty)
+{
+	int ret;
+	appl_pam_pwchange_required = 0;
+	ret = appl_pam_start(service, interactive, login_username,
+			     non_interactive_password, hostname, ruser, tty);
+	if (ret == 0) {
+#ifdef DEBUG
+		printf("Calling pam_acct_mgmt().\n");
+#endif
+		ret = pam_acct_mgmt(appl_pamh, 0);
+		switch (ret) {
+		case PAM_IGNORE:
+			ret = 0;
+			break;
+		case PAM_NEW_AUTHTOK_REQD:
+			appl_pam_pwchange_required = 1;
+			ret = 0;
+			break;
+		default:
+			break;
+		}
+	}
+	return ret;
+}
+int
+appl_pam_requires_chauthtok(void)
+{
+	return appl_pam_pwchange_required;
+}
+int
+appl_pam_session_open(void)
+{
+	int ret = 0;
+	if (appl_pam_started) {
+#ifdef DEBUG
+		printf("Opening PAM session.\n");
+#endif
+		ret = pam_open_session(appl_pamh, 0);
+		if (ret == 0) {
+			appl_pam_session_opened = 1;
+		}
+	}
+	return ret;
+}
+int
+appl_pam_setenv(void)
+{
+	int ret = 0;
+#ifdef HAVE_PAM_GETENVLIST
+#ifdef HAVE_PUTENV
+	int i;
+	char **list;
+	if (appl_pam_started) {
+		list = pam_getenvlist(appl_pamh);
+		for (i = 0; ((list != NULL) && (list[i] != NULL)); i++) {
+#ifdef DEBUG
+			printf("Setting \"%s\" in environment.\n", list[i]);
+#endif
+			putenv(list[i]);
+		}
+	}
+#endif
+#endif
+	return ret;
+}
+int
+appl_pam_cred_init(void)
+{
+	int ret = 0;
+	if (appl_pam_started) {
+#ifdef DEBUG
+		printf("Initializing PAM credentials.\n");
+#endif
+		ret = pam_setcred(appl_pamh, PAM_ESTABLISH_CRED);
+		if (ret == 0) {
+			appl_pam_creds_initialized = 1;
+		}
+	}
+	return ret;
+}
+#endif
diff --git a/src/clients/ksu/pam.h b/src/clients/ksu/pam.h
new file mode 100644
index 0000000000..d45b9fd84b
--- /dev/null
+++ b/src/clients/ksu/pam.h
@@ -0,0 +1,57 @@
+/*
+ * src/clients/ksu/pam.h
+ *
+ * Copyright 2007,2009,2010 Red Hat, Inc.
+ *
+ * All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  Redistributions of source code must retain the above copyright notice, this
+ *  list of conditions and the following disclaimer.
+ *
+ *  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.
+ *
+ *  Neither the name of Red Hat, Inc. 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 COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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.
+ *
+ * Convenience wrappers for using PAM.
+ */
+
+#include <krb5.h>
+#ifdef HAVE_SECURITY_PAM_APPL_H
+#include <security/pam_appl.h>
+#endif
+
+#define USE_PAM_CONFIGURATION_KEYWORD "use_pam"
+
+#ifdef USE_PAM
+int appl_pam_enabled(krb5_context context, const char *section);
+int appl_pam_acct_mgmt(const char *service, int interactive,
+		       const char *local_username,
+		       const char *non_interactive_password,
+		       const char *hostname,
+		       const char *ruser,
+		       const char *tty);
+int appl_pam_requires_chauthtok(void);
+int appl_pam_session_open(void);
+int appl_pam_setenv(void);
+int appl_pam_cred_init(void);
+void appl_pam_cleanup(void);
+#endif
diff --git a/src/configure.ac b/src/configure.ac
index 9fc569f195..99268dfd78 100644
--- a/src/configure.ac
+++ b/src/configure.ac
@@ -1407,6 +1407,8 @@ AC_SUBST([VERTO_VERSION])
 
 AC_PATH_PROG(GROFF, groff)
 
+KRB5_WITH_PAM
+
 # Make localedir work in autoconf 2.5x.
 if test "${localedir+set}" != set; then
     localedir='$(datadir)/locale'
-- 
2.53.0


From dac2e975d5729d53f22dc7d77428feb55263b982 Mon Sep 17 00:00:00 2001
From: Robbie Harwood <rharwood@redhat.com>
Date: Tue, 23 Aug 2016 16:30:53 -0400
Subject: [PATCH 07/21] SELINUX: Add integration

SELinux bases access to files on the domain of the requesting process,
the operation being performed, and the context applied to the file.

In many cases, applications needn't be SELinux aware to work properly,
because SELinux can apply a default label to a file based on the label
of the directory in which it's created.

In the case of files such as /etc/krb5.keytab, however, this isn't
sufficient, as /etc/krb5.keytab will almost always need to be given a
label which differs from that of /etc/issue or /etc/resolv.conf.  The
the kdb stash file needs a different label than the database for which
it's holding a master key, even though both typically live in the same
directory.

To give the file the correct label, we can either force a "restorecon"
call to fix a file's label after it's created, or create the file with
the right label, as we attempt to do here.  We lean on THREEPARAMOPEN
and define a similar macro named WRITABLEFOPEN with which we replace
several uses of fopen().

The file creation context that we're manipulating here is a process-wide
attribute.  While for the most part, applications which need to label
files when they're created have tended to be single-threaded, there's
not much we can do to avoid interfering with an application that
manipulates the creation context directly.  Right now we're mediating
access using a library-local mutex, but that can only work for consumers
that are part of this package -- an unsuspecting application will still
stomp all over us.

The selabel APIs for looking up the context should be thread-safe (per
Red Hat #273081), so switching to using them instead of matchpathcon(),
which we used earlier, is some improvement.

[jrische@redhat.com: Replace deprecated security_context_t by char *:
    - src/util/support/selinux.c]

Last-updated: krb5-1.21.1-final
Forward-ported-by: Andreas Schneider <asn@redhat.com>

Forward-ported-by: Andreas Schneider <asn@redhat.com>
---
 src/aclocal.m4                                |  49 +++
 src/build-tools/krb5-config.in                |   3 +-
 src/config/pre.in                             |   3 +-
 src/configure.ac                              |   2 +
 src/include/k5-int.h                          |   1 +
 src/include/k5-label.h                        |  32 ++
 src/include/krb5/krb5.hin                     |   6 +
 src/kadmin/dbutil/dump.c                      |  11 +-
 src/kdc/main.c                                |   2 +-
 src/kprop/kpropd.c                            |   9 +
 src/lib/kadm5/logger.c                        |   4 +-
 src/lib/kdb/kdb_log.c                         |   2 +-
 src/lib/krb5/ccache/cc_dir.c                  |  26 +-
 src/lib/krb5/keytab/kt_file.c                 |   4 +-
 src/lib/krb5/os/trace.c                       |   2 +-
 src/plugins/kdb/db2/adb_openclose.c           |   2 +-
 src/plugins/kdb/db2/kdb_db2.c                 |   4 +-
 src/plugins/kdb/db2/libdb2/btree/bt_open.c    |   3 +-
 src/plugins/kdb/db2/libdb2/hash/hash.c        |   3 +-
 src/plugins/kdb/db2/libdb2/recno/rec_open.c   |   4 +-
 .../kdb/ldap/ldap_util/kdb5_ldap_services.c   |  11 +-
 src/util/profile/prof_file.c                  |   3 +-
 src/util/support/Makefile.in                  |   3 +-
 src/util/support/selinux.c                    | 404 ++++++++++++++++++
 24 files changed, 572 insertions(+), 21 deletions(-)
 create mode 100644 src/include/k5-label.h
 create mode 100644 src/util/support/selinux.c

diff --git a/src/aclocal.m4 b/src/aclocal.m4
index 3d9b02c21a..1782be9788 100644
--- a/src/aclocal.m4
+++ b/src/aclocal.m4
@@ -85,6 +85,7 @@ AC_SUBST_FILE(libnodeps_frag)
 dnl
 KRB5_AC_PRAGMA_WEAK_REF
 WITH_LDAP
+KRB5_WITH_SELINUX
 KRB5_LIB_PARAMS
 KRB5_AC_INITFINI
 KRB5_AC_ENABLE_THREADS
@@ -1482,3 +1483,51 @@ AC_SUBST(PAM_LIBS)
 AC_SUBST(PAM_MAN)
 AC_SUBST(NON_PAM_MAN)
 ])dnl
+dnl
+dnl Use libselinux to set file contexts on newly-created files.
+dnl
+AC_DEFUN(KRB5_WITH_SELINUX,[
+AC_ARG_WITH(selinux,[AC_HELP_STRING(--with-selinux,[compile with SELinux labeling support])],
+           withselinux="$withval",withselinux=auto)
+old_LIBS="$LIBS"
+SELINUX_LIBS=
+if test "$withselinux" != no ; then
+       AC_MSG_RESULT([checking for libselinux...])
+       AC_CHECK_HEADERS(selinux/selinux.h selinux/label.h)
+       if test "x$ac_cv_header_selinux_selinux_h" != xyes ; then
+               if test "$withselinux" = auto ; then
+                       AC_MSG_RESULT([Unable to locate selinux/selinux.h.])
+                       withselinux=no
+               else
+                       AC_MSG_ERROR([Unable to locate selinux/selinux.h.])
+               fi
+       else
+               LIBS=
+               unset ac_cv_func_setfscreatecon
+               AC_CHECK_FUNCS(setfscreatecon selabel_open)
+               if test "x$ac_cv_func_setfscreatecon" = xno ; then
+                       AC_CHECK_LIB(selinux,setfscreatecon)
+                       unset ac_cv_func_setfscreatecon
+                       AC_CHECK_FUNCS(setfscreatecon selabel_open)
+                       if test "x$ac_cv_func_setfscreatecon" = xyes ; then
+                               SELINUX_LIBS="$LIBS"
+                       else
+                               if test "$withselinux" = auto ; then
+                                       AC_MSG_RESULT([Unable to locate libselinux.])
+                                       withselinux=no
+                               else
+                                       AC_MSG_ERROR([Unable to locate libselinux.])
+                               fi
+                       fi
+               fi
+               if test "$withselinux" != no ; then
+                       AC_MSG_NOTICE([building with SELinux labeling support])
+                       AC_DEFINE(USE_SELINUX,1,[Define if Kerberos-aware tools should set SELinux file contexts when creating files.])
+                       SELINUX_LIBS="$LIBS"
+                       EXTRA_SUPPORT_SYMS="$EXTRA_SUPPORT_SYMS krb5int_labeled_open krb5int_labeled_fopen krb5int_push_fscreatecon_for krb5int_pop_fscreatecon"
+               fi
+       fi
+fi
+LIBS="$old_LIBS"
+AC_SUBST(SELINUX_LIBS)
+])dnl
diff --git a/src/build-tools/krb5-config.in b/src/build-tools/krb5-config.in
index 2cb439887d..12a698833e 100755
--- a/src/build-tools/krb5-config.in
+++ b/src/build-tools/krb5-config.in
@@ -40,6 +40,7 @@ DL_LIB='@DL_LIB@'
 DEFCCNAME='@DEFCCNAME@'
 DEFKTNAME='@DEFKTNAME@'
 DEFCKTNAME='@DEFCKTNAME@'
+SELINUX_LIBS='@SELINUX_LIBS@'
 
 LIBS='@LIBS@'
 
@@ -252,7 +253,7 @@ if test -n "$do_libs"; then
     fi
 
     # If we ever support a flag to generate output suitable for static
-    # linking, we would output "-lkrb5support $LIBS $DL_LIB" here.
+    # linking, we would output "-lkrb5support $LIBS $SELINUX_LIBS $DL_LIB" here.
 
     echo $lib_flags
 fi
diff --git a/src/config/pre.in b/src/config/pre.in
index 1197c1ffd6..9f64fd190f 100644
--- a/src/config/pre.in
+++ b/src/config/pre.in
@@ -178,6 +178,7 @@ KRB_INCLUDES = -I$(BUILDTOP)/include -I$(top_srcdir)/include
 LDFLAGS = @LDFLAGS@
 LIBS = @LIBS@
 FUZZ_LDFLAGS = @FUZZ_LDFLAGS@
+SELINUX_LIBS=@SELINUX_LIBS@
 
 INSTALL=@INSTALL@
 INSTALL_STRIP=
@@ -377,7 +378,7 @@ SUPPORT_LIB			= -l$(SUPPORT_LIBNAME)
 # HESIOD_LIBS is -lhesiod...
 HESIOD_LIBS	= @HESIOD_LIBS@
 
-KRB5_BASE_LIBS	= $(KRB5_LIB) $(K5CRYPTO_LIB) $(COM_ERR_LIB) $(SUPPORT_LIB) $(LIBS) $(DL_LIB)
+KRB5_BASE_LIBS	= $(KRB5_LIB) $(K5CRYPTO_LIB) $(COM_ERR_LIB) $(SUPPORT_LIB) $(LIBS) $(SELINUX_LIBS) $(DL_LIB)
 KDB5_LIBS	= $(KDB5_LIB) $(GSSRPC_LIBS)
 GSS_LIBS	= $(GSS_KRB5_LIB)
 # needs fixing if ever used on macOS!
diff --git a/src/configure.ac b/src/configure.ac
index 99268dfd78..33a1160657 100644
--- a/src/configure.ac
+++ b/src/configure.ac
@@ -1409,6 +1409,8 @@ AC_PATH_PROG(GROFF, groff)
 
 KRB5_WITH_PAM
 
+KRB5_WITH_SELINUX
+
 # Make localedir work in autoconf 2.5x.
 if test "${localedir+set}" != set; then
     localedir='$(datadir)/locale'
diff --git a/src/include/k5-int.h b/src/include/k5-int.h
index a430e4eec9..252c8d9b00 100644
--- a/src/include/k5-int.h
+++ b/src/include/k5-int.h
@@ -128,6 +128,7 @@ typedef unsigned char   u_char;
 
 
 #include "k5-platform.h"
+#include "k5-label.h"
 
 #define KRB5_KDB_MAX_LIFE       (60*60*24) /* one day */
 #define KRB5_KDB_MAX_RLIFE      (60*60*24*7) /* one week */
diff --git a/src/include/k5-label.h b/src/include/k5-label.h
new file mode 100644
index 0000000000..dfaaa847cb
--- /dev/null
+++ b/src/include/k5-label.h
@@ -0,0 +1,32 @@
+#ifndef _KRB5_LABEL_H
+#define _KRB5_LABEL_H
+
+#ifdef THREEPARAMOPEN
+#undef THREEPARAMOPEN
+#endif
+#ifdef WRITABLEFOPEN
+#undef WRITABLEFOPEN
+#endif
+
+/* Wrapper functions which help us create files and directories with the right
+ * context labels. */
+#ifdef USE_SELINUX
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <unistd.h>
+FILE *krb5int_labeled_fopen(const char *path, const char *mode);
+int krb5int_labeled_creat(const char *path, mode_t mode);
+int krb5int_labeled_open(const char *path, int flags, ...);
+int krb5int_labeled_mkdir(const char *path, mode_t mode);
+int krb5int_labeled_mknod(const char *path, mode_t mode, dev_t device);
+#define THREEPARAMOPEN(x,y,z) krb5int_labeled_open(x,y,z)
+#define WRITABLEFOPEN(x,y) krb5int_labeled_fopen(x,y)
+void *krb5int_push_fscreatecon_for(const char *pathname);
+void krb5int_pop_fscreatecon(void *previous);
+#else
+#define WRITABLEFOPEN(x,y) fopen(x,y)
+#define THREEPARAMOPEN(x,y,z) open(x,y,z)
+#endif
+#endif
diff --git a/src/include/krb5/krb5.hin b/src/include/krb5/krb5.hin
index 81c3844605..3d5bdf6935 100644
--- a/src/include/krb5/krb5.hin
+++ b/src/include/krb5/krb5.hin
@@ -83,6 +83,12 @@
 #define THREEPARAMOPEN(x,y,z) open(x,y,z)
 #endif
 
+#if KRB5_PRIVATE
+#ifndef WRITABLEFOPEN
+#define WRITABLEFOPEN(x,y) fopen(x,y)
+#endif
+#endif
+
 #define KRB5_OLD_CRYPTO
 
 #include <stdlib.h>
diff --git a/src/kadmin/dbutil/dump.c b/src/kadmin/dbutil/dump.c
index e45551a200..cd32ebdaf2 100644
--- a/src/kadmin/dbutil/dump.c
+++ b/src/kadmin/dbutil/dump.c
@@ -134,12 +134,21 @@ create_ofile(char *ofile, char **tmpname)
 {
     int fd = -1;
     FILE *f;
+#ifdef USE_SELINUX
+    void *selabel;
+#endif
 
     *tmpname = NULL;
     if (asprintf(tmpname, "%s-XXXXXX", ofile) < 0)
         goto error;
 
+#ifdef USE_SELINUX
+    selabel = krb5int_push_fscreatecon_for(ofile);
+#endif
     fd = mkstemp(*tmpname);
+#ifdef USE_SELINUX
+    krb5int_pop_fscreatecon(selabel);
+#endif
     if (fd == -1)
         goto error;
 
@@ -183,7 +192,7 @@ prep_ok_file(krb5_context context, char *file_name, int *fd_out)
         goto cleanup;
     }
 
-    fd = open(file_ok, O_WRONLY | O_CREAT | O_TRUNC, 0600);
+    fd = THREEPARAMOPEN(file_ok, O_WRONLY | O_CREAT | O_TRUNC, 0600);
     if (fd == -1) {
         com_err(progname, errno, _("while creating 'ok' file, '%s'"), file_ok);
         goto cleanup;
diff --git a/src/kdc/main.c b/src/kdc/main.c
index 105276601e..f48d60a774 100644
--- a/src/kdc/main.c
+++ b/src/kdc/main.c
@@ -837,7 +837,7 @@ write_pid_file(const char *path)
     unsigned long pid;
     int st1, st2;
 
-    file = fopen(path, "w");
+    file = WRITABLEFOPEN(path, "w");
     if (file == NULL)
         return errno;
     pid = (unsigned long)getpid();
diff --git a/src/kprop/kpropd.c b/src/kprop/kpropd.c
index 4b36752646..296ca2bb71 100644
--- a/src/kprop/kpropd.c
+++ b/src/kprop/kpropd.c
@@ -489,6 +489,9 @@ doit(int fd)
     krb5_enctype etype;
     int database_fd;
     char host[INET6_ADDRSTRLEN + 1];
+#ifdef USE_SELINUX
+    void *selabel;
+#endif
 
     signal_wrapper(SIGALRM, alarm_handler);
     alarm(params.iprop_resync_timeout);
@@ -544,9 +547,15 @@ doit(int fd)
         free(name);
         exit(1);
     }
+#ifdef USE_SELINUX
+    selabel = krb5int_push_fscreatecon_for(file);
+#endif
     omask = umask(077);
     lock_fd = open(temp_file_name, O_RDWR | O_CREAT, 0600);
     (void)umask(omask);
+#ifdef USE_SELINUX
+    krb5int_pop_fscreatecon(selabel);
+#endif
     retval = krb5_lock_file(kpropd_context, lock_fd,
                             KRB5_LOCKMODE_EXCLUSIVE | KRB5_LOCKMODE_DONTBLOCK);
     if (retval) {
diff --git a/src/lib/kadm5/logger.c b/src/lib/kadm5/logger.c
index e14da53790..b879a4049b 100644
--- a/src/lib/kadm5/logger.c
+++ b/src/lib/kadm5/logger.c
@@ -310,7 +310,7 @@ krb5_klog_init(krb5_context kcontext, char *ename, char *whoami, krb5_boolean do
                      */
                     append = (cp[4] == ':') ? O_APPEND : 0;
                     if (append || cp[4] == '=') {
-                        fd = open(&cp[5], O_CREAT | O_WRONLY | append,
+                        fd = THREEPARAMOPEN(&cp[5], O_CREAT | O_WRONLY | append,
                                   S_IRUSR | S_IWUSR | S_IRGRP);
                         if (fd != -1)
                             f = fdopen(fd, append ? "a" : "w");
@@ -777,7 +777,7 @@ krb5_klog_reopen(krb5_context kcontext)
              * In case the old logfile did not get moved out of the
              * way, open for append to prevent squashing the old logs.
              */
-            f = fopen(log_control.log_entries[lindex].lfu_fname, "a+");
+            f = WRITABLEFOPEN(log_control.log_entries[lindex].lfu_fname, "a+");
             if (f) {
                 set_cloexec_file(f);
                 log_control.log_entries[lindex].lfu_filep = f;
diff --git a/src/lib/kdb/kdb_log.c b/src/lib/kdb/kdb_log.c
index b840eec9a2..419beab9e4 100644
--- a/src/lib/kdb/kdb_log.c
+++ b/src/lib/kdb/kdb_log.c
@@ -512,7 +512,7 @@ ulog_map(krb5_context context, const char *logname, uint32_t ulogentries)
         return ENOMEM;
 
     if (stat(logname, &st) == -1) {
-        log_ctx->ulogfd = open(logname, O_RDWR | O_CREAT, 0600);
+        log_ctx->ulogfd = THREEPARAMOPEN(logname, O_RDWR | O_CREAT, 0600);
         if (log_ctx->ulogfd == -1) {
             retval = errno;
             goto cleanup;
diff --git a/src/lib/krb5/ccache/cc_dir.c b/src/lib/krb5/ccache/cc_dir.c
index 1da40b51d0..f3ab7340a6 100644
--- a/src/lib/krb5/ccache/cc_dir.c
+++ b/src/lib/krb5/ccache/cc_dir.c
@@ -183,10 +183,19 @@ write_primary_file(const char *primary_path, const char *contents)
     char *newpath = NULL;
     FILE *fp = NULL;
     int fd = -1, status;
+#ifdef USE_SELINUX
+    void *selabel;
+#endif
 
     if (asprintf(&newpath, "%s.XXXXXX", primary_path) < 0)
         return ENOMEM;
+#ifdef USE_SELINUX
+    selabel = krb5int_push_fscreatecon_for(primary_path);
+#endif
     fd = mkstemp(newpath);
+#ifdef USE_SELINUX
+    krb5int_pop_fscreatecon(selabel);
+#endif
     if (fd < 0)
         goto cleanup;
 #ifdef HAVE_CHMOD
@@ -221,10 +230,23 @@ static krb5_error_code
 verify_dir(krb5_context context, const char *dirname)
 {
     struct stat st;
+    int status;
+#ifdef USE_SELINUX
+    void *selabel;
+#endif
 
     if (stat(dirname, &st) < 0) {
-        if (errno == ENOENT && mkdir(dirname, S_IRWXU) == 0)
-            return 0;
+        if (errno == ENOENT) {
+#ifdef USE_SELINUX
+            selabel = krb5int_push_fscreatecon_for(dirname);
+#endif
+            status = mkdir(dirname, S_IRWXU);
+#ifdef USE_SELINUX
+            krb5int_pop_fscreatecon(selabel);
+#endif
+            if (status == 0)
+                return 0;
+        }
         k5_setmsg(context, KRB5_FCC_NOFILE,
                   _("Credential cache directory %s does not exist"),
                   dirname);
diff --git a/src/lib/krb5/keytab/kt_file.c b/src/lib/krb5/keytab/kt_file.c
index 993f902c7c..8fd1505115 100644
--- a/src/lib/krb5/keytab/kt_file.c
+++ b/src/lib/krb5/keytab/kt_file.c
@@ -736,14 +736,14 @@ krb5_ktfileint_open(krb5_context context, krb5_keytab id, int mode)
 
     KTCHECKLOCK(id);
     errno = 0;
-    KTFILEP(id) = fopen(KTFILENAME(id),
+    KTFILEP(id) = WRITABLEFOPEN(KTFILENAME(id),
                         (mode == KRB5_LOCKMODE_EXCLUSIVE) ? "rb+" : "rb");
     if (!KTFILEP(id)) {
         if ((mode == KRB5_LOCKMODE_EXCLUSIVE) && (errno == ENOENT)) {
             /* try making it first time around */
             k5_create_secure_file(context, KTFILENAME(id));
             errno = 0;
-            KTFILEP(id) = fopen(KTFILENAME(id), "rb+");
+            KTFILEP(id) = WRITABLEFOPEN(KTFILENAME(id), "rb+");
             if (!KTFILEP(id))
                 goto report_errno;
             writevno = 1;
diff --git a/src/lib/krb5/os/trace.c b/src/lib/krb5/os/trace.c
index 89699f7df5..9c7d7dad6f 100644
--- a/src/lib/krb5/os/trace.c
+++ b/src/lib/krb5/os/trace.c
@@ -455,7 +455,7 @@ krb5_set_trace_filename(krb5_context context, const char *filename)
     fd = malloc(sizeof(*fd));
     if (fd == NULL)
         return ENOMEM;
-    *fd = open(filename, O_WRONLY|O_CREAT|O_APPEND, 0600);
+    *fd = THREEPARAMOPEN(filename, O_WRONLY|O_CREAT|O_APPEND, 0600);
     if (*fd == -1) {
         free(fd);
         return errno;
diff --git a/src/plugins/kdb/db2/adb_openclose.c b/src/plugins/kdb/db2/adb_openclose.c
index 9a506e9d44..f92ab47143 100644
--- a/src/plugins/kdb/db2/adb_openclose.c
+++ b/src/plugins/kdb/db2/adb_openclose.c
@@ -152,7 +152,7 @@ osa_adb_init_db(osa_adb_db_t *dbp, char *filename, char *lockfilename,
          * needs be open read/write so that write locking can work with
          * POSIX systems
          */
-        if ((lockp->lockinfo.lockfile = fopen(lockfilename, "r+")) == NULL) {
+        if ((lockp->lockinfo.lockfile = WRITABLEFOPEN(lockfilename, "r+")) == NULL) {
             /*
              * maybe someone took away write permission so we could only
              * get shared locks?
diff --git a/src/plugins/kdb/db2/kdb_db2.c b/src/plugins/kdb/db2/kdb_db2.c
index 381228e6da..eb8610b2ae 100644
--- a/src/plugins/kdb/db2/kdb_db2.c
+++ b/src/plugins/kdb/db2/kdb_db2.c
@@ -694,8 +694,8 @@ ctx_create_db(krb5_context context, krb5_db2_context *dbc)
     if (retval)
         return retval;
 
-    dbc->db_lf_file = open(dbc->db_lf_name, O_CREAT | O_RDWR | O_TRUNC,
-                           0600);
+    dbc->db_lf_file = THREEPARAMOPEN(dbc->db_lf_name,
+                                     O_CREAT | O_RDWR | O_TRUNC, 0600);
     if (dbc->db_lf_file < 0) {
         retval = errno;
         goto cleanup;
diff --git a/src/plugins/kdb/db2/libdb2/btree/bt_open.c b/src/plugins/kdb/db2/libdb2/btree/bt_open.c
index 56bab19412..ef7515c3d4 100644
--- a/src/plugins/kdb/db2/libdb2/btree/bt_open.c
+++ b/src/plugins/kdb/db2/libdb2/btree/bt_open.c
@@ -60,6 +60,7 @@ static char sccsid[] = "@(#)bt_open.c	8.11 (Berkeley) 11/2/95";
 #include <string.h>
 #include <unistd.h>
 
+#include "k5-int.h"
 #include "db-int.h"
 #include "btree.h"
 
@@ -201,7 +202,7 @@ __bt_open(const char *fname, int flags, int mode, const BTREEINFO *openinfo,
 			goto einval;
 		}
 
-		if ((t->bt_fd = open(fname, flags | O_BINARY, mode)) < 0)
+		if ((t->bt_fd = THREEPARAMOPEN(fname, flags | O_BINARY, mode)) < 0)
 			goto err;
 
 	} else {
diff --git a/src/plugins/kdb/db2/libdb2/hash/hash.c b/src/plugins/kdb/db2/libdb2/hash/hash.c
index 7c3e951aa2..9528b62538 100644
--- a/src/plugins/kdb/db2/libdb2/hash/hash.c
+++ b/src/plugins/kdb/db2/libdb2/hash/hash.c
@@ -51,6 +51,7 @@ static char sccsid[] = "@(#)hash.c	8.12 (Berkeley) 11/7/95";
 #include <assert.h>
 #endif
 
+#include "k5-int.h"
 #include "db-int.h"
 #include "hash.h"
 #include "page.h"
@@ -127,7 +128,7 @@ __kdb2_hash_open(const char *file, int flags, int mode, const HASHINFO *info,
 		new_table = 1;
 	}
 	if (file) {
-		if ((hashp->fp = open(file, flags|O_BINARY, mode)) == -1)
+		if ((hashp->fp = THREEPARAMOPEN(file, flags|O_BINARY, mode)) == -1)
 			RETURN_ERROR(errno, error0);
 		(void)fcntl(hashp->fp, F_SETFD, 1);
 	}
diff --git a/src/plugins/kdb/db2/libdb2/recno/rec_open.c b/src/plugins/kdb/db2/libdb2/recno/rec_open.c
index acbf03d9dd..de3fc3f4d0 100644
--- a/src/plugins/kdb/db2/libdb2/recno/rec_open.c
+++ b/src/plugins/kdb/db2/libdb2/recno/rec_open.c
@@ -51,6 +51,7 @@ static char sccsid[] = "@(#)rec_open.c	8.12 (Berkeley) 11/18/94";
 #include <stdio.h>
 #include <unistd.h>
 
+#include "k5-int.h"
 #include "db-int.h"
 #include "recno.h"
 
@@ -66,7 +67,8 @@ __rec_open(const char *fname, int flags, int mode, const RECNOINFO *openinfo,
 	int rfd = -1, sverrno;
 
 	/* Open the user's file -- if this fails, we're done. */
-	if (fname != NULL && (rfd = open(fname, flags | O_BINARY, mode)) < 0)
+	if (fname != NULL &&
+            (rfd = THREEPARAMOPEN(fname, flags | O_BINARY, mode)) < 0)
 		return (NULL);
 
 	if (fname != NULL && fcntl(rfd, F_SETFD, 1) == -1) {
diff --git a/src/plugins/kdb/ldap/ldap_util/kdb5_ldap_services.c b/src/plugins/kdb/ldap/ldap_util/kdb5_ldap_services.c
index e87688d666..30f7c00ab5 100644
--- a/src/plugins/kdb/ldap/ldap_util/kdb5_ldap_services.c
+++ b/src/plugins/kdb/ldap/ldap_util/kdb5_ldap_services.c
@@ -190,7 +190,7 @@ kdb5_ldap_stash_service_password(int argc, char **argv)
 
     /* set password in the file */
     old_mode = umask(0177);
-    pfile = fopen(file_name, "a+");
+    pfile = WRITABLEFOPEN(file_name, "a+");
     if (pfile == NULL) {
         com_err(me, errno, _("Failed to open file %s: %s"), file_name,
                 strerror (errno));
@@ -231,6 +231,9 @@ kdb5_ldap_stash_service_password(int argc, char **argv)
          * Delete the existing entry and add the new entry
          */
         FILE *newfile;
+#ifdef USE_SELINUX
+        void *selabel;
+#endif
 
         mode_t omask;
 
@@ -242,7 +245,13 @@ kdb5_ldap_stash_service_password(int argc, char **argv)
         }
 
         omask = umask(077);
+#ifdef USE_SELINUX
+        selabel = krb5int_push_fscreatecon_for(file_name);
+#endif
         newfile = fopen(tmp_file, "w");
+#ifdef USE_SELINUX
+        krb5int_pop_fscreatecon(selabel);
+#endif
         umask (omask);
         if (newfile == NULL) {
             com_err(me, errno, _("Error creating file %s"), tmp_file);
diff --git a/src/util/profile/prof_file.c b/src/util/profile/prof_file.c
index 8b0b2bb441..9468e317bf 100644
--- a/src/util/profile/prof_file.c
+++ b/src/util/profile/prof_file.c
@@ -33,6 +33,7 @@
 #endif
 
 #include "k5-platform.h"
+#include "k5-label.h"
 
 struct global_shared_profile_data {
     /* This is the head of the global list of shared trees */
@@ -423,7 +424,7 @@ static errcode_t write_data_to_file(prf_data_t data, const char *outfile,
 
     errno = 0;
 
-    f = fopen(new_file, "w");
+    f = WRITABLEFOPEN(new_file, "w");
     if (!f) {
         retval = errno;
         if (retval == 0)
diff --git a/src/util/support/Makefile.in b/src/util/support/Makefile.in
index b9cd70dac4..6705681df5 100644
--- a/src/util/support/Makefile.in
+++ b/src/util/support/Makefile.in
@@ -79,6 +79,7 @@ IPC_SYMS= \
 
 STLIBOBJS= \
 	threads.o \
+	selinux.o \
 	init-addrinfo.o \
 	plugins.o \
 	errors.o \
@@ -176,7 +177,7 @@ SRCS=\
 
 SHLIB_EXPDEPS =
 # Add -lm if dumping thread stats, for sqrt.
-SHLIB_EXPLIBS= $(LIBS) $(DL_LIB)
+SHLIB_EXPLIBS= $(LIBS) $(SELINUX_LIBS) $(DL_LIB)
 
 DEPLIBS=
 
diff --git a/src/util/support/selinux.c b/src/util/support/selinux.c
new file mode 100644
index 0000000000..b10f927b2e
--- /dev/null
+++ b/src/util/support/selinux.c
@@ -0,0 +1,404 @@
+/*
+ * Copyright 2007,2008,2009,2011,2012,2013,2016 Red Hat, Inc.  All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  Redistributions of source code must retain the above copyright notice, this
+ *  list of conditions and the following disclaimer.
+ *
+ *  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.
+ *
+ *  Neither the name of Red Hat, Inc. 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 COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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.
+ *
+ * File-opening wrappers for creating correctly-labeled files.  So far, we can
+ * assume that this is Linux-specific, so we make many simplifying assumptions.
+ */
+
+#include <k5-platform.h>
+
+#ifdef USE_SELINUX
+
+#include <k5-label.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <pthread.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <selinux/selinux.h>
+#include <selinux/context.h>
+#include <selinux/label.h>
+
+/* #define DEBUG 1 */
+static void
+debug_log(const char *fmt, ...)
+{
+#ifdef DEBUG
+    va_list ap;
+    va_start(ap, fmt);
+    if (isatty(fileno(stderr))) {
+        vfprintf(stderr, fmt, ap);
+    }
+    va_end(ap);
+#endif
+
+    return;
+}
+
+/* Mutex used to serialize use of the process-global file creation context. */
+k5_mutex_t labeled_mutex = K5_MUTEX_PARTIAL_INITIALIZER;
+
+/* Make sure we finish initializing that mutex before attempting to use it. */
+k5_once_t labeled_once = K5_ONCE_INIT;
+static void
+label_mutex_init(void)
+{
+    k5_mutex_finish_init(&labeled_mutex);
+}
+
+static struct selabel_handle *selabel_ctx;
+static time_t selabel_last_changed;
+
+MAKE_FINI_FUNCTION(cleanup_fscreatecon);
+
+static void
+cleanup_fscreatecon(void)
+{
+    if (selabel_ctx != NULL) {
+        selabel_close(selabel_ctx);
+        selabel_ctx = NULL;
+    }
+}
+
+static char *
+push_fscreatecon(const char *pathname, mode_t mode)
+{
+    char *previous, *configuredsc, *currentsc, *genpath;
+    const char *derivedsc, *fullpath, *currentuser;
+    context_t current, derived;
+
+    previous = configuredsc = currentsc = genpath = NULL;
+    derivedsc = NULL;
+    current = derived = NULL;
+
+    fullpath = pathname;
+
+    if (!is_selinux_enabled()) {
+        goto fail;
+    }
+
+    if (getfscreatecon(&previous) != 0) {
+        goto fail;
+    }
+
+    /* Canonicalize pathname */
+    if (pathname[0] != '/') {
+        char *wd;
+        size_t len;
+        len = 0;
+
+        wd = getcwd(NULL, len);
+        if (wd == NULL) {
+            goto fail;
+        }
+
+        len = strlen(wd) + 1 + strlen(pathname) + 1;
+        genpath = malloc(len);
+        if (genpath == NULL) {
+            free(wd);
+            goto fail;
+        }
+
+        sprintf(genpath, "%s/%s", wd, pathname);
+        free(wd);
+        fullpath = genpath;
+    }
+
+    debug_log("Looking up context for \"%s\"(%05o).\n", fullpath, mode);
+
+    /* Check whether context file has changed under us */
+    if (selabel_ctx != NULL || selabel_last_changed == 0) {
+        const char *cpath;
+        struct stat st;
+        int i = -1;
+
+        cpath = selinux_file_context_path();
+        if (cpath == NULL || (i = stat(cpath, &st)) != 0 ||
+            st.st_mtime != selabel_last_changed) {
+            cleanup_fscreatecon();
+
+            selabel_last_changed = i ? time(NULL) : st.st_mtime;
+        }
+    }
+
+    if (selabel_ctx == NULL) {
+        selabel_ctx = selabel_open(SELABEL_CTX_FILE, NULL, 0);
+    }
+
+    if (selabel_ctx != NULL &&
+        selabel_lookup(selabel_ctx, &configuredsc, fullpath, mode) != 0) {
+        goto fail;
+    }
+
+    if (genpath != NULL) {
+        free(genpath);
+        genpath = NULL;
+    }
+
+    if (configuredsc == NULL) {
+        goto fail;
+    }
+
+    getcon(&currentsc);
+
+    /* AAAAAAAA */
+    if (currentsc != NULL) {
+        derived = context_new(configuredsc);
+
+        if (derived != NULL) {
+            current = context_new(currentsc);
+
+            if (current != NULL) {
+                currentuser = context_user_get(current);
+
+                if (currentuser != NULL) {
+                    if (context_user_set(derived,
+                                         currentuser) == 0) {
+                        derivedsc = context_str(derived);
+
+                        if (derivedsc != NULL) {
+                            freecon(configuredsc);
+                            configuredsc = strdup(derivedsc);
+                        }
+                    }
+                }
+
+                context_free(current);
+            }
+
+            context_free(derived);
+        }
+
+        freecon(currentsc);
+    }
+
+    debug_log("Setting file creation context to \"%s\".\n", configuredsc);
+    if (setfscreatecon(configuredsc) != 0) {
+        debug_log("Unable to determine current context.\n");
+        goto fail;
+    }
+
+    freecon(configuredsc);
+    return previous;
+
+fail:
+    if (previous != NULL) {
+        freecon(previous);
+    }
+    if (genpath != NULL) {
+        free(genpath);
+    }
+    if (configuredsc != NULL) {
+        freecon(configuredsc);
+    }
+
+    cleanup_fscreatecon();
+    return NULL;
+}
+
+static void
+pop_fscreatecon(char *previous)
+{
+    if (!is_selinux_enabled()) {
+        return;
+    }
+
+    if (previous != NULL) {
+        debug_log("Resetting file creation context to \"%s\".\n", previous);
+    } else {
+        debug_log("Resetting file creation context to default.\n");
+    }
+
+    /* NULL resets to default */
+    setfscreatecon(previous);
+
+    if (previous != NULL) {
+        freecon(previous);
+    }
+
+    /* Need to clean this up here otherwise it leaks */
+    cleanup_fscreatecon();
+}
+
+void *
+krb5int_push_fscreatecon_for(const char *pathname)
+{
+    struct stat st;
+    void *retval;
+
+    k5_once(&labeled_once, label_mutex_init);
+    k5_mutex_lock(&labeled_mutex);
+
+    if (stat(pathname, &st) != 0) {
+        st.st_mode = S_IRUSR | S_IWUSR;
+    }
+
+    retval = push_fscreatecon(pathname, st.st_mode);
+    return retval ? retval : (void *) -1;
+}
+
+void
+krb5int_pop_fscreatecon(void *con)
+{
+    if (con != NULL) {
+        pop_fscreatecon((con == (void *) -1) ? NULL : con);
+        k5_mutex_unlock(&labeled_mutex);
+    }
+}
+
+FILE *
+krb5int_labeled_fopen(const char *path, const char *mode)
+{
+    FILE *fp;
+    int errno_save;
+    char *ctx;
+
+    if ((strcmp(mode, "r") == 0) ||
+        (strcmp(mode, "rb") == 0)) {
+        return fopen(path, mode);
+    }
+
+    k5_once(&labeled_once, label_mutex_init);
+    k5_mutex_lock(&labeled_mutex);
+    ctx = push_fscreatecon(path, 0);
+
+    fp = fopen(path, mode);
+    errno_save = errno;
+
+    pop_fscreatecon(ctx);
+    k5_mutex_unlock(&labeled_mutex);
+
+    errno = errno_save;
+    return fp;
+}
+
+int
+krb5int_labeled_creat(const char *path, mode_t mode)
+{
+    int fd;
+    int errno_save;
+    char *ctx;
+
+    k5_once(&labeled_once, label_mutex_init);
+    k5_mutex_lock(&labeled_mutex);
+    ctx = push_fscreatecon(path, 0);
+
+    fd = creat(path, mode);
+    errno_save = errno;
+
+    pop_fscreatecon(ctx);
+    k5_mutex_unlock(&labeled_mutex);
+
+    errno = errno_save;
+    return fd;
+}
+
+int
+krb5int_labeled_mknod(const char *path, mode_t mode, dev_t dev)
+{
+    int ret;
+    int errno_save;
+    char *ctx;
+
+    k5_once(&labeled_once, label_mutex_init);
+    k5_mutex_lock(&labeled_mutex);
+    ctx = push_fscreatecon(path, mode);
+
+    ret = mknod(path, mode, dev);
+    errno_save = errno;
+
+    pop_fscreatecon(ctx);
+    k5_mutex_unlock(&labeled_mutex);
+
+    errno = errno_save;
+    return ret;
+}
+
+int
+krb5int_labeled_mkdir(const char *path, mode_t mode)
+{
+    int ret;
+    int errno_save;
+    char *ctx;
+
+    k5_once(&labeled_once, label_mutex_init);
+    k5_mutex_lock(&labeled_mutex);
+    ctx = push_fscreatecon(path, S_IFDIR);
+
+    ret = mkdir(path, mode);
+    errno_save = errno;
+
+    pop_fscreatecon(ctx);
+    k5_mutex_unlock(&labeled_mutex);
+
+    errno = errno_save;
+    return ret;
+}
+
+int
+krb5int_labeled_open(const char *path, int flags, ...)
+{
+    int fd;
+    int errno_save;
+    char *ctx;
+    mode_t mode;
+    va_list ap;
+
+    if ((flags & O_CREAT) == 0) {
+        return open(path, flags);
+    }
+
+    k5_once(&labeled_once, label_mutex_init);
+    k5_mutex_lock(&labeled_mutex);
+    ctx = push_fscreatecon(path, 0);
+
+    va_start(ap, flags);
+    mode = va_arg(ap, mode_t);
+    fd = open(path, flags, mode);
+    va_end(ap);
+
+    errno_save = errno;
+
+    pop_fscreatecon(ctx);
+    k5_mutex_unlock(&labeled_mutex);
+
+    errno = errno_save;
+    return fd;
+}
+
+#endif /* USE_SELINUX */
-- 
2.53.0


From 8523c362c7a0bc2a702ede1ec82b24555ff12ba5 Mon Sep 17 00:00:00 2001
From: Julien Rische <jrische@redhat.com>
Date: Mon, 9 Jan 2023 22:39:52 +0100
Subject: [PATCH 08/21] INSTALL: Do not set root as ksu file owner

Upstream Makefile uses the install command to set root as owner of the
ksu executable file. However, this is no longer supported on latest
versions of the Mock build environment.

In case of ksu, the owner, group, and mode are already set using %attr()
in the specfile.
---
 src/config/pre.in | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/config/pre.in b/src/config/pre.in
index 9f64fd190f..3724d26ae6 100644
--- a/src/config/pre.in
+++ b/src/config/pre.in
@@ -186,7 +186,7 @@ INSTALL_PROGRAM=@INSTALL_PROGRAM@ $(INSTALL_STRIP)
 INSTALL_SCRIPT=@INSTALL_PROGRAM@
 INSTALL_DATA=@INSTALL_DATA@
 INSTALL_SHLIB=@INSTALL_SHLIB@
-INSTALL_SETUID=$(INSTALL) $(INSTALL_STRIP) -m 4755 -o root
+INSTALL_SETUID=$(INSTALL)
 ## This is needed because autoconf will sometimes define @exec_prefix@ to be
 ## ${prefix}.
 prefix=@prefix@
-- 
2.53.0


From 307d0b16159de59092b00a109d44f68de323f5f1 Mon Sep 17 00:00:00 2001
From: Julien Rische <jrische@redhat.com>
Date: Wed, 7 Dec 2022 13:22:42 +0100
Subject: [PATCH 09/21] SSSD: Make tests compatible with
 sssd_krb5_locator_plugin.so

The sssd_krb5_locator_plugin.so plugin provided by sssd-client conflicts
with the upstream test t_discover_uri.py. The test has to be modified in
order to avoid false positive.
---
 src/lib/krb5/os/t_discover_uri.py | 9 ++++++++-
 1 file changed, 8 insertions(+), 1 deletion(-)

diff --git a/src/lib/krb5/os/t_discover_uri.py b/src/lib/krb5/os/t_discover_uri.py
index 87bac17929..26bc95a8dc 100644
--- a/src/lib/krb5/os/t_discover_uri.py
+++ b/src/lib/krb5/os/t_discover_uri.py
@@ -1,3 +1,4 @@
+from os.path import exists
 from k5test import *
 
 entries = ('URI _kerberos.TEST krb5srv::kkdcp:https://kdc1 1 1\n',
@@ -37,8 +38,14 @@ realm.env['RESOLV_WRAPPER_HOSTS'] = hosts_filename
 out = realm.run(['./t_locate_kdc', 'TEST'], env=realm.env)
 l = out.splitlines()
 
+if (exists('/usr/lib/krb5/plugins/libkrb5/sssd_krb5_locator_plugin.so')
+    or exists('/usr/lib64/krb5/plugins/libkrb5/sssd_krb5_locator_plugin.so')):
+    line_range = range(6, 14)
+else:
+    line_range = range(4, 12)
+
 j = 0
-for i in range(4, 12):
+for i in line_range:
     if l[i].strip() != expected[j]:
         fail('URI answers do not match')
     j += 1
-- 
2.53.0


From 82ec4d257ba4f0ea5e57c56b680bc888b69ae3df Mon Sep 17 00:00:00 2001
From: Julien Rische <jrische@redhat.com>
Date: Wed, 15 Mar 2023 15:56:34 +0100
Subject: [PATCH 10/21] PAC: Allow to set ticket signature as optional

MS-PAC states that "The ticket signature SHOULD be included in tickets
that are not encrypted to the krbtgt account". However, the
implementation of krb5_kdc_verify_ticket() will require the ticket
signature to be present in case the target of the request is a service
principal.

In gradual upgrade environments, it results in S4U2Proxy requests
against a 1.20 KDC using a service ticket generated by an older version
KDC to fail.

This commit adds a krb5_kdc_verify_ticket_ext() function with an extra
switch parameter to tolerate the absence of ticket signature in this
scenario. If the ticket signature is present, it has to be valid,
regardless of this parameter.

This parameter is set based on the "optional_pac_tkt_chksum" string
attribute of the TGT KDB entry.
---
 doc/admin/admin_commands/kadmin_local.rst |  6 ++++
 doc/appdev/refs/api/index.rst             |  1 +
 src/include/kdb.h                         |  1 +
 src/include/krb5/krb5.hin                 | 40 +++++++++++++++++++++++
 src/kdc/kdc_util.c                        | 32 ++++++++++++++----
 src/lib/krb5/krb/pac.c                    | 31 +++++++++++++++---
 src/lib/krb5/libkrb5.exports              |  1 +
 src/man/kadmin.man                        |  6 ++++
 8 files changed, 108 insertions(+), 10 deletions(-)

diff --git a/doc/admin/admin_commands/kadmin_local.rst b/doc/admin/admin_commands/kadmin_local.rst
index b4edc79243..a2fbaf45c2 100644
--- a/doc/admin/admin_commands/kadmin_local.rst
+++ b/doc/admin/admin_commands/kadmin_local.rst
@@ -676,6 +676,12 @@ KDC:
     Directory realm when using aes-sha2 keys on the local krbtgt
     entry.
 
+**optional_pac_tkt_chksum**
+    Boolean value defining the behavior of the KDC in case an expected
+    ticket checksum signed with one of this principal keys is not
+    present in the PAC. This is typically the case for TGS or
+    cross-realm TGS principals when processing S4U2Proxy requests.
+
 This command requires the **modify** privilege.
 
 Alias: **setstr**
diff --git a/doc/appdev/refs/api/index.rst b/doc/appdev/refs/api/index.rst
index 648dc2ed99..abc6806ca1 100644
--- a/doc/appdev/refs/api/index.rst
+++ b/doc/appdev/refs/api/index.rst
@@ -227,6 +227,7 @@ Rarely used public interfaces
    krb5_is_referral_realm.rst
    krb5_kdc_sign_ticket.rst
    krb5_kdc_verify_ticket.rst
+   krb5_kdc_verify_ticket_ext.rst
    krb5_kt_add_entry.rst
    krb5_kt_end_seq_get.rst
    krb5_kt_get_entry.rst
diff --git a/src/include/kdb.h b/src/include/kdb.h
index 17a3456822..83e22f4462 100644
--- a/src/include/kdb.h
+++ b/src/include/kdb.h
@@ -136,6 +136,7 @@
 #define KRB5_KDB_SK_PAC_PRIVSVR_ENCTYPE         "pac_privsvr_enctype"
 #define KRB5_KDB_SK_SESSION_ENCTYPES            "session_enctypes"
 #define KRB5_KDB_SK_REQUIRE_AUTH                "require_auth"
+#define KRB5_KDB_SK_OPTIONAL_PAC_TKT_CHKSUM     "optional_pac_tkt_chksum"
 
 #if !defined(_WIN32)
 
diff --git a/src/include/krb5/krb5.hin b/src/include/krb5/krb5.hin
index 3d5bdf6935..6e2d0001a0 100644
--- a/src/include/krb5/krb5.hin
+++ b/src/include/krb5/krb5.hin
@@ -8366,6 +8366,46 @@ krb5_kdc_verify_ticket(krb5_context context, const krb5_enc_tkt_part *enc_tkt,
                        const krb5_keyblock *server,
                        const krb5_keyblock *privsvr, krb5_pac *pac_out);
 
+/**
+ * Verify a PAC, possibly including ticket signature
+ *
+ * @param [in] context              Library context
+ * @param [in] enc_tkt              Ticket enc-part, possibly containing a PAC
+ * @param [in] server_princ         Canonicalized name of ticket server
+ * @param [in] server               Key to validate server checksum (or NULL)
+ * @param [in] privsvr              Key to validate KDC checksum (or NULL)
+ * @paran [in] optional_tkt_chksum  Whether to require a ticket checksum
+ * @param [out] pac_out             Verified PAC (NULL if no PAC included)
+ *
+ * This function is an extension of krb5_kdc_verify_ticket(), adding the @a
+ * optional_tkt_chksum parameter allowing to tolerate the absence of the PAC
+ * ticket signature.
+ *
+ * If a PAC is present in @a enc_tkt, verify its signatures.  If @a privsvr is
+ * not NULL and @a server_princ is not a krbtgt or kadmin/changepw service and
+ * @a optional_tkt_chksum is FALSE, require a ticket signature over @a enc_tkt
+ * in addition to the KDC signature. Place the verified PAC in @a pac_out.  If
+ * an invalid PAC signature is found, return an error matching the Windows KDC
+ * protocol code for that condition as closely as possible.
+ *
+ * If no PAC is present in @a enc_tkt, set @a pac_out to NULL and return
+ * successfully.
+ *
+ * @note This function does not validate the PAC_CLIENT_INFO buffer.  If a
+ * specific value is expected, the caller can make a separate call to
+ * krb5_pac_verify_ext() with a principal but no keys.
+ *
+ * @retval 0 Success; otherwise - Kerberos error codes
+ */
+krb5_error_code KRB5_CALLCONV
+krb5_kdc_verify_ticket_ext(krb5_context context,
+                           const krb5_enc_tkt_part *enc_tkt,
+                           krb5_const_principal server_princ,
+                           const krb5_keyblock *server,
+                           const krb5_keyblock *privsvr,
+                           krb5_boolean optional_tkt_chksum,
+                           krb5_pac *pac_out);
+
 /** @deprecated Use krb5_kdc_sign_ticket() instead. */
 krb5_error_code KRB5_CALLCONV
 krb5_pac_sign(krb5_context context, krb5_pac pac, krb5_timestamp authtime,
diff --git a/src/kdc/kdc_util.c b/src/kdc/kdc_util.c
index 89f34ca06e..c6f15639f7 100644
--- a/src/kdc/kdc_util.c
+++ b/src/kdc/kdc_util.c
@@ -566,16 +566,36 @@ cleanup:
 static krb5_error_code
 try_verify_pac(krb5_context context, const krb5_enc_tkt_part *enc_tkt,
                krb5_db_entry *server, krb5_keyblock *server_key,
-               const krb5_keyblock *tgt_key, krb5_pac *pac_out)
+               krb5_db_entry *tgt, const krb5_keyblock *tgt_key,
+               krb5_pac *pac_out)
 {
     krb5_error_code ret;
+    krb5_boolean optional_tkt_chksum;
+    char *str = NULL;
     krb5_keyblock *privsvr_key;
 
     ret = pac_privsvr_key(context, server, tgt_key, &privsvr_key);
     if (ret)
         return ret;
-    ret = krb5_kdc_verify_ticket(context, enc_tkt, server->princ, server_key,
-                                 privsvr_key, pac_out);
+
+    /* Check if the absence of ticket signature is tolerated for this realm */
+    ret = krb5_dbe_get_string(context, tgt,
+                              KRB5_KDB_SK_OPTIONAL_PAC_TKT_CHKSUM, &str);
+    /* TODO: should be using _krb5_conf_boolean(), but os-proto.h is not
+     * available here.
+     */
+    optional_tkt_chksum = !ret && str && (strncasecmp(str, "true", 4) == 0
+                                       || strncasecmp(str, "t",    1) == 0
+                                       || strncasecmp(str, "yes",  3) == 0
+                                       || strncasecmp(str, "y",    1) == 0
+                                       || strncasecmp(str, "1",    1) == 0
+                                       || strncasecmp(str, "on",   2) == 0);
+
+    krb5_dbe_free_string(context, str);
+
+    ret = krb5_kdc_verify_ticket_ext(context, enc_tkt, server->princ,
+                                     server_key, privsvr_key,
+                                     optional_tkt_chksum, pac_out);
     krb5_free_keyblock(context, privsvr_key);
     return ret;
 }
@@ -605,7 +625,7 @@ get_verified_pac(krb5_context context, const krb5_enc_tkt_part *enc_tkt,
                                       server_key, NULL, pac_out);
     }
 
-    ret = try_verify_pac(context, enc_tkt, server, server_key, tgt_key,
+    ret = try_verify_pac(context, enc_tkt, server, server_key, tgt, tgt_key,
                          pac_out);
     if (ret != KRB5KRB_AP_ERR_MODIFIED && ret != KRB5_BAD_ENCTYPE)
         return ret;
@@ -619,8 +639,8 @@ get_verified_pac(krb5_context context, const krb5_enc_tkt_part *enc_tkt,
         ret = krb5_dbe_decrypt_key_data(context, NULL, kd, &old_key, NULL);
         if (ret)
             return ret;
-        ret = try_verify_pac(context, enc_tkt, server, server_key, &old_key,
-                             pac_out);
+        ret = try_verify_pac(context, enc_tkt, server, server_key, tgt,
+                             &old_key, pac_out);
         krb5_free_keyblock_contents(context, &old_key);
         if (!ret)
             return 0;
diff --git a/src/lib/krb5/krb/pac.c b/src/lib/krb5/krb/pac.c
index 7e33387454..8b3d89631c 100644
--- a/src/lib/krb5/krb/pac.c
+++ b/src/lib/krb5/krb/pac.c
@@ -596,6 +596,19 @@ krb5_kdc_verify_ticket(krb5_context context, const krb5_enc_tkt_part *enc_tkt,
                        krb5_const_principal server_princ,
                        const krb5_keyblock *server,
                        const krb5_keyblock *privsvr, krb5_pac *pac_out)
+{
+    return krb5_kdc_verify_ticket_ext(context, enc_tkt, server_princ, server,
+                                      privsvr, FALSE, pac_out);
+}
+
+krb5_error_code KRB5_CALLCONV
+krb5_kdc_verify_ticket_ext(krb5_context context,
+                           const krb5_enc_tkt_part *enc_tkt,
+                           krb5_const_principal server_princ,
+                           const krb5_keyblock *server,
+                           const krb5_keyblock *privsvr,
+                           krb5_boolean optional_tkt_chksum,
+                           krb5_pac *pac_out)
 {
     krb5_error_code ret;
     krb5_pac pac = NULL;
@@ -604,7 +617,7 @@ krb5_kdc_verify_ticket(krb5_context context, const krb5_enc_tkt_part *enc_tkt,
     krb5_authdata *orig, **ifrel = NULL, **recoded_ifrel = NULL;
     uint8_t z = 0;
     krb5_authdata zpac = { KV5M_AUTHDATA, KRB5_AUTHDATA_WIN2K_PAC, 1, &z };
-    krb5_boolean is_service_tkt;
+    krb5_boolean is_service_tkt, has_tkt_chksum = FALSE;
     size_t i, j;
 
     *pac_out = NULL;
@@ -669,11 +682,21 @@ krb5_kdc_verify_ticket(krb5_context context, const krb5_enc_tkt_part *enc_tkt,
 
         ret = verify_checksum(context, pac, KRB5_PAC_TICKET_CHECKSUM, privsvr,
                               KRB5_KEYUSAGE_APP_DATA_CKSUM, recoded_tkt);
-        if (ret)
-            goto cleanup;
+        if (ret) {
+            if (!optional_tkt_chksum)
+                goto cleanup;
+            else if (ret != ENOENT)
+                goto cleanup;
+            /* Otherwise ticket signature is absent but optional. Proceed... */
+        } else {
+            has_tkt_chksum = TRUE;
+        }
     }
+    /* Else, we make the assumption the ticket signature is absent in case this
+     * is not a service ticket.
+     */
 
-    ret = verify_pac_checksums(context, pac, is_service_tkt, server, privsvr);
+    ret = verify_pac_checksums(context, pac, has_tkt_chksum, server, privsvr);
     if (ret)
         goto cleanup;
 
diff --git a/src/lib/krb5/libkrb5.exports b/src/lib/krb5/libkrb5.exports
index 1e7076d3ce..d48985f9fc 100644
--- a/src/lib/krb5/libkrb5.exports
+++ b/src/lib/krb5/libkrb5.exports
@@ -468,6 +468,7 @@ krb5_is_thread_safe
 krb5_kdc_rep_decrypt_proc
 krb5_kdc_sign_ticket
 krb5_kdc_verify_ticket
+krb5_kdc_verify_ticket_ext
 krb5_kt_add_entry
 krb5_kt_client_default
 krb5_kt_close
diff --git a/src/man/kadmin.man b/src/man/kadmin.man
index 15ddc17dc5..96cdd52982 100644
--- a/src/man/kadmin.man
+++ b/src/man/kadmin.man
@@ -733,6 +733,12 @@ encryption type.  It may be necessary to set this value to
 \(dqaes256\-sha1\(dq on the cross\-realm krbtgt entry for an Active
 Directory realm when using aes\-sha2 keys on the local krbtgt
 entry.
+.TP
+\fBoptional_pac_tkt_chksum\fP
+Boolean value defining the behavior of the KDC in case an expected ticket
+checksum signed with one of this principal keys is not present in the PAC. This
+is typically the case for TGS or cross-realm TGS principals when processing
+S4U2Proxy requests.
 .UNINDENT
 .sp
 This command requires the \fBmodify\fP privilege.
-- 
2.53.0


From f160430a84cdbc2f24e4e9dc32fafac04ddcb887 Mon Sep 17 00:00:00 2001
From: Robbie Harwood <rharwood@redhat.com>
Date: Tue, 23 Aug 2016 16:49:25 -0400
Subject: [PATCH 11/21] BUILD: fix debuginfo with y.tab.c

We want to keep these y.tab.c files around because the debuginfo points to
them.  It would be more elegant at the end to use symbolic links, but that
could mess up people working in the tree on other things.

Last-updated: krb5-1.22.1-final
Forward-ported-by: Andreas Schneider <asn@redhat.com>
---
 src/kadmin/cli/Makefile.in                 | 7 ++++++-
 src/plugins/kdb/ldap/ldap_util/Makefile.in | 4 ++--
 2 files changed, 8 insertions(+), 3 deletions(-)

diff --git a/src/kadmin/cli/Makefile.in b/src/kadmin/cli/Makefile.in
index adfea6e2b5..47f3338fd2 100644
--- a/src/kadmin/cli/Makefile.in
+++ b/src/kadmin/cli/Makefile.in
@@ -31,9 +31,14 @@ generate-files-mac: kadmin_ct.c getdate.c
 clean:
 	$(RM) $(PROG).local $(PROG) $(COMMON_OBJS) $(KADMIN_OBJS) $(LOCAL_OBJS)
 clean-unix::
-	$(RM) datetest getdate.c kadmin_ct.c
+	$(RM) datetest getdate.c kadmin_ct.c y.tab.c
 
 # for testing getdate.y
 # CC_LINK is not meant for compilation and this use may break in the future.
 datetest: getdate.c
 	$(CC_LINK) $(ALL_CFLAGS) -DTEST -o datetest getdate.c
+
+%.c: %.y
+	$(RM) y.tab.c $@
+	$(YACC.y) $<
+	$(CP) y.tab.c $@
diff --git a/src/plugins/kdb/ldap/ldap_util/Makefile.in b/src/plugins/kdb/ldap/ldap_util/Makefile.in
index 8669c2436c..f243017ce9 100644
--- a/src/plugins/kdb/ldap/ldap_util/Makefile.in
+++ b/src/plugins/kdb/ldap/ldap_util/Makefile.in
@@ -20,10 +20,10 @@ $(PROG): $(OBJS) $(KADMSRV_DEPLIBS) $(KRB5_BASE_DEPLIB) $(GETDATE)
 getdate.c: $(GETDATE)
 	$(RM) getdate.c y.tab.c
 	$(YACC) $(GETDATE)
-	$(MV) y.tab.c getdate.c
+	$(CP) y.tab.c getdate.c
 
 install:
 	$(INSTALL_PROGRAM) $(PROG) ${DESTDIR}$(ADMIN_BINDIR)/$(PROG)
 
 clean:
-	$(RM) $(PROG) $(OBJS) getdate.c
+	$(RM) $(PROG) $(OBJS) getdate.c y.tab.c
-- 
2.53.0


From 621dac3f7d2989adfd746d40ba74468fa0275ab5 Mon Sep 17 00:00:00 2001
From: Alexander Bokovoy <abokovoy@redhat.com>
Date: Sun, 21 Sep 2025 11:14:51 +0300
Subject: [PATCH 12/21] PKINIT: If configured, attempt Anonymous PKINIT for
 FAST

If auto_fast_armor is configured for the realm or globally, optimistically
assume that Anonymous PKINIT is supported as well and try to obtain it for
FAST use in case no pre-made FAST channel was established by the caller.

This behavior will automatically enable use of passwordless pre-authentication
methods which rely on FAST channel presence in deployments such as FreeIPA.

Notably, Microsoft Active Directory KDCs do not support Anonymous PKINIT. For
these deployments only a machine account (host keytab) can be used to build a
FAST channel. However, libkrb5 does not have access to /etc/krb5.keytab in a
general case.

Signed-off-by: Alexander Bokovoy <abokovoy@redhat.com>
PR: https://github.com/krb5/krb5/pull/1447
---
 src/lib/krb5/krb/fast.c | 118 ++++++++++++++++++++++++++++++++++++++++
 src/lib/krb5/krb/fast.h |   2 +
 src/man/krb5.conf.man   |  13 +++++
 3 files changed, 133 insertions(+)

diff --git a/src/lib/krb5/krb/fast.c b/src/lib/krb5/krb/fast.c
index 62c9f0841f..ee2e081892 100644
--- a/src/lib/krb5/krb/fast.c
+++ b/src/lib/krb5/krb/fast.c
@@ -168,6 +168,109 @@ krb5int_fast_prep_req_body(krb5_context context,
     return retval;
 }
 
+static krb5_boolean
+fast_is_pkinit_allowed(krb5_context context, krb5_data *realm)
+{
+    int value;
+    krb5_error_code retval = EINVAL;
+    char realmstr[1024];
+    const char *option = "auto_fast_armor";
+    const int def_value = FALSE;
+
+    if (realm != NULL && realm->length > sizeof(realmstr)-1)
+        return FALSE;
+
+    if (realm != NULL) {
+        strncpy(realmstr, realm->data, realm->length);
+        realmstr[realm->length] = '\0';
+
+        retval = profile_get_boolean(context->profile,
+                                     KRB5_CONF_REALMS, realmstr,
+                                     option, def_value, &value);
+    }
+
+    return retval ? FALSE : value;
+
+}
+
+static krb5_error_code
+fast_acquire_pkinit_armor(krb5_context context,
+                           struct krb5int_fast_request_state *state,
+                           krb5_get_init_creds_opt *opt, krb5_kdc_req *request)
+{
+    krb5_context ctx;
+    krb5_get_init_creds_opt *options = NULL;
+    krb5_error_code retval = 0;
+    krb5_data *target_realm = &request->server->realm;
+    krb5_creds creds;
+    krb5_principal anon_princ = NULL;
+    krb5_ccache out_cc;
+
+    /* short circuit, we are asked to perform Anonymous PKINIT already */
+    if (opt->flags & KRB5_GET_INIT_CREDS_OPT_ANONYMOUS) {
+        return EINVAL;
+    }
+
+    /* skip realms which do not allow use of automated FAST armor */
+    if (!fast_is_pkinit_allowed(context, target_realm)) {
+        return EINVAL;
+    }
+
+    retval = krb5_init_context(&ctx);
+    if (retval != 0) {
+        return retval;
+    }
+    retval = krb5_get_init_creds_opt_alloc(ctx, &options);
+    if (retval != 0) {
+        goto cleanup;
+    }
+    krb5_get_init_creds_opt_set_anonymous(options, 1);
+    retval = krb5_cc_new_unique(ctx, "MEMORY", NULL, &out_cc);
+    if (retval != 0) {
+        goto cleanup;
+    }
+
+    retval = krb5_get_init_creds_opt_set_out_ccache(ctx, options, out_cc);
+    if (retval != 0) {
+        goto cleanup;
+    }
+
+    retval = krb5_build_principal_ext(ctx, &anon_princ,
+                                      target_realm->length, target_realm->data,
+                                      strlen(KRB5_WELLKNOWN_NAMESTR),
+                                      KRB5_WELLKNOWN_NAMESTR,
+                                      strlen(KRB5_ANONYMOUS_PRINCSTR),
+                                      KRB5_ANONYMOUS_PRINCSTR, 0);
+    if (retval != 0) {
+        goto cleanup;
+    }
+
+    retval = krb5_get_init_creds_password(ctx, &creds, anon_princ, 0,
+                                          NULL /* no prompter */, NULL,
+                                          0, NULL /* service name */,
+                                          options);
+    if (retval == 0) {
+        state->fast_state_flags |= KRB5INT_FAST_OWN_ARMOR;
+        state->armor_ccache = out_cc;
+    }
+cleanup:
+    if (retval != 0 && out_cc != NULL) {
+        (void) krb5_cc_destroy(ctx, out_cc);
+    }
+    if (retval == 0) {
+        krb5_free_cred_contents(ctx, &creds);
+    }
+    if (options != NULL) {
+        krb5_get_init_creds_opt_free(ctx, options);
+    }
+    if (anon_princ != NULL) {
+        krb5_free_principal(ctx, anon_princ);
+    }
+    krb5_free_context(ctx);
+
+    return retval;
+}
+
 krb5_error_code
 krb5int_fast_as_armor(krb5_context context,
                       struct krb5int_fast_request_state *state,
@@ -178,10 +281,20 @@ krb5int_fast_as_armor(krb5_context context,
     krb5_principal target_principal = NULL;
     krb5_data *target_realm;
     const char *ccname = k5_gic_opt_get_fast_ccache_name(opt);
+    char *fast_ccname = NULL;
     krb5_flags fast_flags;
 
     krb5_clear_error_message(context);
     target_realm = &request->server->realm;
+    if (ccname == NULL) {
+        retval = fast_acquire_pkinit_armor(context, state, opt, request);
+        if (retval == 0) {
+            retval = krb5_cc_get_full_name(context, state->armor_ccache, &fast_ccname);
+            if (retval == 0 && fast_ccname != NULL)
+                ccname = fast_ccname;
+        }
+        retval = 0;
+    }
     if (ccname != NULL) {
         TRACE_FAST_ARMOR_CCACHE(context, ccname);
         state->fast_state_flags |= KRB5INT_FAST_ARMOR_AVAIL;
@@ -220,6 +333,8 @@ krb5int_fast_as_armor(krb5_context context,
         krb5_cc_close(context, ccache);
     if (target_principal)
         krb5_free_principal(context, target_principal);
+    if (fast_ccname)
+        free(fast_ccname);
     return retval;
 }
 
@@ -615,6 +730,9 @@ krb5int_fast_free_state(krb5_context context,
     /*We are responsible for none of the store in the fast_outer_req*/
     krb5_free_keyblock(context, state->armor_key);
     krb5_free_fast_armor(context, state->armor);
+    if (state->fast_state_flags & KRB5INT_FAST_OWN_ARMOR) {
+        krb5_cc_destroy(context, state->armor_ccache);
+    }
     free(state);
 }
 
diff --git a/src/lib/krb5/krb/fast.h b/src/lib/krb5/krb/fast.h
index 7156ea203f..e5fe8bd544 100644
--- a/src/lib/krb5/krb/fast.h
+++ b/src/lib/krb5/krb/fast.h
@@ -34,6 +34,7 @@ struct krb5int_fast_request_state {
     krb5_kdc_req fast_outer_request;
     krb5_keyblock *armor_key; /*non-null means fast is in use*/
     krb5_fast_armor *armor;
+    krb5_ccache armor_ccache;
     krb5_ui_4 fast_state_flags;
     krb5_ui_4 fast_options;
     krb5_int32 nonce;
@@ -41,6 +42,7 @@ struct krb5int_fast_request_state {
 
 #define KRB5INT_FAST_DO_FAST     (1l<<0)  /* Perform FAST */
 #define KRB5INT_FAST_ARMOR_AVAIL (1l<<1)
+#define KRB5INT_FAST_OWN_ARMOR   (1l<<2)
 
 krb5_error_code
 krb5int_fast_prep_req_body(krb5_context context,
diff --git a/src/man/krb5.conf.man b/src/man/krb5.conf.man
index 6f7890abcd..12c2ea1e5d 100644
--- a/src/man/krb5.conf.man
+++ b/src/man/krb5.conf.man
@@ -655,6 +655,19 @@ primary KDC, in case the user\(aqs password has just been changed, and
 the updated database has not been propagated to the replica
 servers yet.  New in release 1.19.
 .TP
+\fBauto_fast_armor\fP
+If this flag is true, then initial ticket request will use Anonymous
+PKINIT to protect the communication as a FAST channel in case an application
+did not provide its own FAST channel. This is useful for deployments where
+pre-authentication methods require use of the FAST channel, such as
+passwordless methods provided by FreeIPA. Microsoft Active Directory
+implementation of PKINIT does not support Anonymous PKINIT feature.
+As a result, \fIauto_fast_armor\fP defaults to false.
+.sp
+Use of \fIauto_fast_armor = true\fP requires properly configured PKINIT and
+WELLKNOWN/ANONYMOUS principal defined on the KDC side. Consult KDC documentation
+for details.
+.TP
 \fBsitename\fP
 Specifies the name of the host\(aqs site for the purpose of DNS\-based
 KDC discovery for this realm.  New in release 1.22.
-- 
2.53.0


From 347f81103e95536b5655bee31bb9ced05d06b098 Mon Sep 17 00:00:00 2001
From: Alexander Bokovoy <abokovoy@redhat.com>
Date: Sun, 19 Oct 2025 18:14:29 +0300
Subject: [PATCH 13/21] Fix OTP preauth crash with null prompter

In doprompt(), check if the caller provided a prompter before
dereferencing it.  Similar code returns either EIO or
KRB5_LIBOS_CANTREADPWD; use EIO for this case as OTP preauth prompts
for a PIN and not a Kerberos password.

[ghudson@mit.edu: edited commit message]

ticket: 9186 (new)
(cherry picked from commit ca97bf697ab1561af1fbd12f5fd13466ec35a962)
---
 src/lib/krb5/krb/preauth_otp.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/src/lib/krb5/krb/preauth_otp.c b/src/lib/krb5/krb/preauth_otp.c
index 07ffc15c22..48003da62f 100644
--- a/src/lib/krb5/krb/preauth_otp.c
+++ b/src/lib/krb5/krb/preauth_otp.c
@@ -479,6 +479,9 @@ doprompt(krb5_context context, krb5_prompter_fct prompter, void *prompter_data,
     krb5_error_code retval;
     krb5_prompt_type prompt_type = KRB5_PROMPT_TYPE_PREAUTH;
 
+    if (prompter == NULL)
+        return EIO;
+
     if (prompttxt == NULL || out == NULL)
         return EINVAL;
 
-- 
2.53.0


From 2073be1acd51f906ac68c1a73c4f1ae8380eee35 Mon Sep 17 00:00:00 2001
From: Alexander Bokovoy <abokovoy@redhat.com>
Date: Wed, 10 Dec 2025 10:42:02 +0200
Subject: [PATCH 14/21] Fix strchr() conformance to C23

C23 7.28.5.1 specifies search functions such as strchr() as generic,
returning const char * if the first argument is of type const char *.
Fix uses of strchr() to conform to this change.

[jrische@redhat.com: altered changes to avoid casts; fixed an
additional case]
[ghudson@mit.edu: condensed some declarations; rewrote commit message]

ticket: 9191 (new)
(cherry picked from commit ad4dcf1856dadc4b352b5c8ff08e51c7290fb41f)
---
 src/lib/krb5/ccache/ccbase.c                      |  4 ++--
 src/lib/krb5/os/expand_path.c                     |  3 ++-
 src/lib/krb5/os/locate_kdc.c                      | 15 +++++++--------
 src/plugins/preauth/pkinit/pkinit_crypto.h        |  2 +-
 .../preauth/pkinit/pkinit_crypto_openssl.c        |  6 +++---
 src/plugins/preauth/pkinit/pkinit_identity.c      |  2 +-
 src/plugins/preauth/pkinit/pkinit_matching.c      |  2 +-
 src/tests/responder.c                             |  3 +--
 8 files changed, 18 insertions(+), 19 deletions(-)

diff --git a/src/lib/krb5/ccache/ccbase.c b/src/lib/krb5/ccache/ccbase.c
index 696b681812..30a0a410c5 100644
--- a/src/lib/krb5/ccache/ccbase.c
+++ b/src/lib/krb5/ccache/ccbase.c
@@ -201,8 +201,8 @@ krb5_cc_register(krb5_context context, const krb5_cc_ops *ops,
 krb5_error_code KRB5_CALLCONV
 krb5_cc_resolve (krb5_context context, const char *name, krb5_ccache *cache)
 {
-    char *pfx, *cp;
-    const char *resid;
+    char *pfx;
+    const char *cp, *resid;
     unsigned int pfxlen;
     krb5_error_code err;
     const krb5_cc_ops *ops;
diff --git a/src/lib/krb5/os/expand_path.c b/src/lib/krb5/os/expand_path.c
index 5cbccf08c8..6569b8820b 100644
--- a/src/lib/krb5/os/expand_path.c
+++ b/src/lib/krb5/os/expand_path.c
@@ -454,7 +454,8 @@ k5_expand_path_tokens_extra(krb5_context context, const char *path_in,
 {
     krb5_error_code ret;
     struct k5buf buf;
-    char *tok_begin, *tok_end, *tok_val, **extra_tokens = NULL, *path;
+    const char *tok_begin, *tok_end;
+    char *tok_val, **extra_tokens = NULL, *path;
     const char *path_left;
     size_t nargs = 0, i;
     va_list ap;
diff --git a/src/lib/krb5/os/locate_kdc.c b/src/lib/krb5/os/locate_kdc.c
index d1df04a635..655946505e 100644
--- a/src/lib/krb5/os/locate_kdc.c
+++ b/src/lib/krb5/os/locate_kdc.c
@@ -214,8 +214,8 @@ oom:
 }
 
 static void
-parse_uri_if_https(const char *host_or_uri, k5_transport *transport,
-                   const char **host, const char **uri_path)
+parse_uri_if_https(char *host_or_uri, k5_transport *transport,
+                   char **host, const char **uri_path)
 {
     char *cp;
 
@@ -257,8 +257,7 @@ locate_srv_conf_1(krb5_context context, const krb5_data *realm,
                   k5_transport transport, int udpport)
 {
     const char *realm_srv_names[4];
-    char **hostlist = NULL, *realmstr = NULL, *host = NULL;
-    const char *hostspec;
+    char **hostlist = NULL, *realmstr = NULL, *host = NULL, *hostspec;
     krb5_error_code code;
     size_t i;
     int default_port;
@@ -587,8 +586,8 @@ prof_locate_server(krb5_context context, const krb5_data *realm,
  * Return a NULL *host_out if there are any problems parsing the URI.
  */
 static void
-parse_uri_fields(const char *uri, k5_transport *transport_out,
-                 const char **host_out, int *primary_out)
+parse_uri_fields(char *uri, k5_transport *transport_out,
+                 char **host_out, int *primary_out)
 
 {
     k5_transport transport;
@@ -656,8 +655,8 @@ locate_uri(krb5_context context, const krb5_data *realm,
     krb5_error_code ret;
     k5_transport transport, host_trans;
     struct srv_dns_entry *answers, *entry;
-    char *host, *sitename;
-    const char *host_field, *path;
+    char *host, *sitename, *host_field;
+    const char *path;
     int port, def_port, primary;
 
     ret = get_sitename(context, realm, &sitename);
diff --git a/src/plugins/preauth/pkinit/pkinit_crypto.h b/src/plugins/preauth/pkinit/pkinit_crypto.h
index 92ccafdfe5..09c5751765 100644
--- a/src/plugins/preauth/pkinit/pkinit_crypto.h
+++ b/src/plugins/preauth/pkinit/pkinit_crypto.h
@@ -440,7 +440,7 @@ krb5_error_code crypto_load_cas_and_crls
 		    defines the storage type (file, directory, etc) */
 	int catype,					/* IN
 		    defines the ca type (anchor, intermediate, crls) */
-	char *id);					/* IN
+	const char *id);				/* IN
 		    defines the location (filename, directory name, etc) */
 
 /*
diff --git a/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c b/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c
index 1d99559485..7779141943 100644
--- a/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c
+++ b/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c
@@ -5006,7 +5006,7 @@ load_cas_and_crls(krb5_context context,
                   pkinit_req_crypto_context req_cryptoctx,
                   pkinit_identity_crypto_context id_cryptoctx,
                   int catype,
-                  char *filename)
+                  const char *filename)
 {
     STACK_OF(X509_INFO) *sk = NULL;
     STACK_OF(X509) *ca_certs = NULL;
@@ -5164,7 +5164,7 @@ load_cas_and_crls_dir(krb5_context context,
                       pkinit_req_crypto_context req_cryptoctx,
                       pkinit_identity_crypto_context id_cryptoctx,
                       int catype,
-                      char *dirname)
+                      const char *dirname)
 {
     krb5_error_code retval = EINVAL;
     char **fnames = NULL, *filename;
@@ -5208,7 +5208,7 @@ crypto_load_cas_and_crls(krb5_context context,
                          pkinit_identity_crypto_context id_cryptoctx,
                          int idtype,
                          int catype,
-                         char *id)
+                         const char *id)
 {
     switch (idtype) {
     case IDTYPE_FILE:
diff --git a/src/plugins/preauth/pkinit/pkinit_identity.c b/src/plugins/preauth/pkinit/pkinit_identity.c
index 0dcfcfc46a..ad65f237b0 100644
--- a/src/plugins/preauth/pkinit/pkinit_identity.c
+++ b/src/plugins/preauth/pkinit/pkinit_identity.c
@@ -473,7 +473,7 @@ process_option_ca_crl(krb5_context context,
                       const char *value,
                       int catype)
 {
-    char *residual;
+    const char *residual;
     unsigned int typelen;
     int idtype;
 
diff --git a/src/plugins/preauth/pkinit/pkinit_matching.c b/src/plugins/preauth/pkinit/pkinit_matching.c
index 0ea072c887..b3c8df1610 100644
--- a/src/plugins/preauth/pkinit/pkinit_matching.c
+++ b/src/plugins/preauth/pkinit/pkinit_matching.c
@@ -262,7 +262,7 @@ parse_rule_component(krb5_context context,
     char err_buf[128];
     int ret;
     struct keyword_desc *kw, *nextkw;
-    char *nk;
+    const char *nk;
     int found_next_kw = 0;
     char *value = NULL;
     size_t len;
diff --git a/src/tests/responder.c b/src/tests/responder.c
index 82f870ea5d..4221a20283 100644
--- a/src/tests/responder.c
+++ b/src/tests/responder.c
@@ -282,8 +282,7 @@ responder(krb5_context ctx, void *rawdata, krb5_responder_context rctx)
     /* Provide a particular response for an OTP challenge. */
     if (data->otp_answer != NULL) {
         if (krb5_responder_otp_get_challenge(ctx, rctx, &ochl) == 0) {
-            key = strchr(data->otp_answer, '=');
-            if (key != NULL) {
+            if (strchr(data->otp_answer, '=') != NULL) {
                 /* Make a copy of the answer that we can chop up. */
                 key = strdup(data->otp_answer);
                 if (key == NULL)
-- 
2.53.0


From df905ea146a4feb39275f657918373e343cda28f Mon Sep 17 00:00:00 2001
From: Greg Hudson <ghudson@mit.edu>
Date: Sun, 28 Sep 2025 15:39:10 -0400
Subject: [PATCH 15/21] Add paChecksum2 to PKINIT ASN.1 tests

Commit 310793ba63782af5ffa3a95d20e41f8f03ca7e00 added the paChecksum2
field to krb5_pk_authenticator.  ktest_make_sample_pk_authenticator()
does not initialize this field, leading to undefined behavior in the
tests.  Initialize the field with a sample paChecksum2 value, and
amend the expected output to include its encoding.

Reported by Michael Osipov.

(cherry picked from commit 34d661676b1db04d870be3d7ad26616aa69d1f3d)
---
 src/tests/asn.1/krb5_decode_test.c |  2 +-
 src/tests/asn.1/ktest.c            | 42 ++++++++++++++++++++++--------
 src/tests/asn.1/ktest_equal.c      | 15 ++++++++++-
 src/tests/asn.1/pkinit_encode.out  |  2 +-
 src/tests/asn.1/pkinit_trval.out   |  6 +++++
 5 files changed, 53 insertions(+), 14 deletions(-)

diff --git a/src/tests/asn.1/krb5_decode_test.c b/src/tests/asn.1/krb5_decode_test.c
index 25ed30e422..daeab87c3d 100644
--- a/src/tests/asn.1/krb5_decode_test.c
+++ b/src/tests/asn.1/krb5_decode_test.c
@@ -1178,7 +1178,7 @@ main(int argc, char **argv)
     /* decode_krb5_auth_pack */
     {
         setup(krb5_auth_pack,ktest_make_sample_auth_pack);
-        decode_run("krb5_auth_pack","","30 81 89 A0 39 30 37 A0 05 02 03 01 E2 40 A1 11 18 0F 31 39 39 34 30 36 31 30 30 36 30 33 31 37 5A A2 03 02 01 2A A3 0A 04 08 6B 72 62 35 64 61 74 61 A4 0A 04 08 6B 72 62 35 64 61 74 61 A1 08 04 06 70 76 61 6C 75 65 A2 24 30 22 30 13 06 09 2A 86 48 86 F7 12 01 02 02 04 06 70 61 72 61 6D 73 30 0B 06 09 2A 86 48 86 F7 12 01 02 02 A3 0A 04 08 6B 72 62 35 64 61 74 61 A4 10 30 0E 30 0C A0 0A 06 08 6B 72 62 35 64 61 74 61",
+        decode_run("krb5_auth_pack","","30 81 B0 A0 60 30 5E A0 05 02 03 01 E2 40 A1 11 18 0F 31 39 39 34 30 36 31 30 30 36 30 33 31 37 5A A2 03 02 01 2A A3 0A 04 08 6B 72 62 35 64 61 74 61 A4 0A 04 08 6B 72 62 35 64 61 74 61 A5 25 30 23 A0 0A 04 08 6B 72 62 35 64 61 74 61 A1 15 30 13 06 09 2A 86 48 86 F7 12 01 02 02 04 06 70 61 72 61 6D 73 A1 08 04 06 70 76 61 6C 75 65 A2 24 30 22 30 13 06 09 2A 86 48 86 F7 12 01 02 02 04 06 70 61 72 61 6D 73 30 0B 06 09 2A 86 48 86 F7 12 01 02 02 A3 0A 04 08 6B 72 62 35 64 61 74 61 A4 10 30 0E 30 0C A0 0A 06 08 6B 72 62 35 64 61 74 61",
                    acc.decode_krb5_auth_pack,
                    ktest_equal_auth_pack,ktest_free_auth_pack);
         ktest_empty_auth_pack(&ref);
diff --git a/src/tests/asn.1/ktest.c b/src/tests/asn.1/ktest.c
index 20360c8ffc..d607891d3a 100644
--- a/src/tests/asn.1/ktest.c
+++ b/src/tests/asn.1/ktest.c
@@ -694,17 +694,6 @@ ktest_make_maximal_pa_otp_req(krb5_pa_otp_req *p)
 
 #ifndef DISABLE_PKINIT
 
-static void
-ktest_make_sample_pk_authenticator(krb5_pk_authenticator *p)
-{
-    p->cusec = SAMPLE_USEC;
-    p->ctime = SAMPLE_TIME;
-    p->nonce = SAMPLE_NONCE;
-    ktest_make_sample_data(&p->paChecksum);
-    p->freshnessToken = ealloc(sizeof(krb5_data));
-    ktest_make_sample_data(p->freshnessToken);
-}
-
 static void
 ktest_make_sample_oid(krb5_data *p)
 {
@@ -726,6 +715,26 @@ ktest_make_sample_algorithm_identifier_no_params(krb5_algorithm_identifier *p)
     p->parameters = empty_data();
 }
 
+static void
+ktest_make_sample_pa_checksum2(krb5_pachecksum2 *p)
+{
+    ktest_make_sample_data(&p->checksum);
+    ktest_make_sample_algorithm_identifier(&p->algorithmIdentifier);
+}
+
+static void
+ktest_make_sample_pk_authenticator(krb5_pk_authenticator *p)
+{
+    p->cusec = SAMPLE_USEC;
+    p->ctime = SAMPLE_TIME;
+    p->nonce = SAMPLE_NONCE;
+    ktest_make_sample_data(&p->paChecksum);
+    p->freshnessToken = ealloc(sizeof(krb5_data));
+    ktest_make_sample_data(p->freshnessToken);
+    p->paChecksum2 = ealloc(sizeof(krb5_pachecksum2));
+    ktest_make_sample_pa_checksum2(p->paChecksum2);
+}
+
 static void
 ktest_make_sample_external_principal_identifier(
     krb5_external_principal_identifier *p)
@@ -1599,12 +1608,23 @@ ktest_empty_pa_otp_req(krb5_pa_otp_req *p)
 
 #ifndef DISABLE_PKINIT
 
+static void
+ktest_empty_pa_checksum2(krb5_pachecksum2 *p)
+{
+    ktest_empty_data(&p->checksum);
+    ktest_empty_algorithm_identifier(&p->algorithmIdentifier);
+}
+
 static void
 ktest_empty_pk_authenticator(krb5_pk_authenticator *p)
 {
     ktest_empty_data(&p->paChecksum);
     krb5_free_data(NULL, p->freshnessToken);
     p->freshnessToken = NULL;
+    if (p->paChecksum2 != NULL)
+        ktest_empty_pa_checksum2(p->paChecksum2);
+    free(p->paChecksum2);
+    p->paChecksum2 = NULL;
 }
 
 static void
diff --git a/src/tests/asn.1/ktest_equal.c b/src/tests/asn.1/ktest_equal.c
index 13786dd1e5..72aa1ff6c6 100644
--- a/src/tests/asn.1/ktest_equal.c
+++ b/src/tests/asn.1/ktest_equal.c
@@ -834,6 +834,18 @@ ktest_equal_sequence_of_spake_factor(krb5_spake_factor **ref,
 
 #ifndef DISABLE_PKINIT
 
+static int
+ktest_equal_pachecksum2(krb5_pachecksum2 *ref, krb5_pachecksum2 *var)
+{
+    int p = TRUE;
+    if (ref == var) return TRUE;
+    else if (ref == NULL || var == NULL) return FALSE;
+    p = p && equal_str(checksum);
+    p = p && struct_equal(algorithmIdentifier,
+                          ktest_equal_algorithm_identifier);
+    return p;
+}
+
 static int
 ktest_equal_pk_authenticator(krb5_pk_authenticator *ref,
                              krb5_pk_authenticator *var)
@@ -844,7 +856,8 @@ ktest_equal_pk_authenticator(krb5_pk_authenticator *ref,
     p = p && scalar_equal(cusec);
     p = p && scalar_equal(ctime);
     p = p && scalar_equal(nonce);
-    p = p && data_eq(ref->paChecksum, var->paChecksum);
+    p = p && equal_str(paChecksum);
+    p = p && ptr_equal(paChecksum2, ktest_equal_pachecksum2);
     return p;
 }
 
diff --git a/src/tests/asn.1/pkinit_encode.out b/src/tests/asn.1/pkinit_encode.out
index a764182e15..9ab0aee772 100644
--- a/src/tests/asn.1/pkinit_encode.out
+++ b/src/tests/asn.1/pkinit_encode.out
@@ -1,7 +1,7 @@
 encode_krb5_pa_pk_as_req: 30 38 80 08 6B 72 62 35 64 61 74 61 A1 22 30 20 30 1E 80 08 6B 72 62 35 64 61 74 61 81 08 6B 72 62 35 64 61 74 61 82 08 6B 72 62 35 64 61 74 61 82 08 6B 72 62 35 64 61 74 61
 encode_krb5_pa_pk_as_rep(dhInfo): A0 28 30 26 80 08 6B 72 62 35 64 61 74 61 A1 0A 04 08 6B 72 62 35 64 61 74 61 A2 0E 30 0C A0 0A 06 08 6B 72 62 35 64 61 74 61
 encode_krb5_pa_pk_as_rep(encKeyPack): 81 08 6B 72 62 35 64 61 74 61
-encode_krb5_auth_pack: 30 81 89 A0 39 30 37 A0 05 02 03 01 E2 40 A1 11 18 0F 31 39 39 34 30 36 31 30 30 36 30 33 31 37 5A A2 03 02 01 2A A3 0A 04 08 6B 72 62 35 64 61 74 61 A4 0A 04 08 6B 72 62 35 64 61 74 61 A1 08 04 06 70 76 61 6C 75 65 A2 24 30 22 30 13 06 09 2A 86 48 86 F7 12 01 02 02 04 06 70 61 72 61 6D 73 30 0B 06 09 2A 86 48 86 F7 12 01 02 02 A3 0A 04 08 6B 72 62 35 64 61 74 61 A4 10 30 0E 30 0C A0 0A 06 08 6B 72 62 35 64 61 74 61
+encode_krb5_auth_pack: 30 81 B0 A0 60 30 5E A0 05 02 03 01 E2 40 A1 11 18 0F 31 39 39 34 30 36 31 30 30 36 30 33 31 37 5A A2 03 02 01 2A A3 0A 04 08 6B 72 62 35 64 61 74 61 A4 0A 04 08 6B 72 62 35 64 61 74 61 A5 25 30 23 A0 0A 04 08 6B 72 62 35 64 61 74 61 A1 15 30 13 06 09 2A 86 48 86 F7 12 01 02 02 04 06 70 61 72 61 6D 73 A1 08 04 06 70 76 61 6C 75 65 A2 24 30 22 30 13 06 09 2A 86 48 86 F7 12 01 02 02 04 06 70 61 72 61 6D 73 30 0B 06 09 2A 86 48 86 F7 12 01 02 02 A3 0A 04 08 6B 72 62 35 64 61 74 61 A4 10 30 0E 30 0C A0 0A 06 08 6B 72 62 35 64 61 74 61
 encode_krb5_kdc_dh_key_info: 30 25 A0 0B 03 09 00 6B 72 62 35 64 61 74 61 A1 03 02 01 2A A2 11 18 0F 31 39 39 34 30 36 31 30 30 36 30 33 31 37 5A
 encode_krb5_reply_key_pack: 30 26 A0 13 30 11 A0 03 02 01 01 A1 0A 04 08 31 32 33 34 35 36 37 38 A1 0F 30 0D A0 03 02 01 01 A1 06 04 04 31 32 33 34
 encode_krb5_sp80056a_other_info: 30 81 81 30 0B 06 09 2A 86 48 86 F7 12 01 02 02 A0 32 04 30 30 2E A0 10 1B 0E 41 54 48 45 4E 41 2E 4D 49 54 2E 45 44 55 A1 1A 30 18 A0 03 02 01 01 A1 11 30 0F 1B 06 68 66 74 73 61 69 1B 05 65 78 74 72 61 A1 32 04 30 30 2E A0 10 1B 0E 41 54 48 45 4E 41 2E 4D 49 54 2E 45 44 55 A1 1A 30 18 A0 03 02 01 01 A1 11 30 0F 1B 06 68 66 74 73 61 69 1B 05 65 78 74 72 61 A2 0A 04 08 6B 72 62 35 64 61 74 61
diff --git a/src/tests/asn.1/pkinit_trval.out b/src/tests/asn.1/pkinit_trval.out
index c47bd71f67..418be63546 100644
--- a/src/tests/asn.1/pkinit_trval.out
+++ b/src/tests/asn.1/pkinit_trval.out
@@ -40,6 +40,12 @@ encode_krb5_auth_pack:
 .  .  [2] [Integer] 42
 .  .  [3] [Octet String] "krb5data"
 .  .  [4] [Octet String] "krb5data"
+.  .  [5] [Sequence/Sequence Of]
+.  .  .  [0] [Octet String] "krb5data"
+.  .  .  [1] [Sequence/Sequence Of]
+.  .  .  .  [Object Identifier] <9>
+               2a 86 48 86 f7 12 01 02 02                    *.H......
+.  .  .  .  [Octet String] "params"
 .  [1] [Octet String] "pvalue"
 .  [2] [Sequence/Sequence Of]
 .  .  [Sequence/Sequence Of]
-- 
2.53.0


From c851405051ca0af7779a6d6f40df4f28221230f3 Mon Sep 17 00:00:00 2001
From: Dax Kelson <dakelson@redhat.com>
Date: Tue, 13 May 2025 11:54:41 -0600
Subject: [PATCH 16/21] Add xrealmauthz KDC policy module and tests

This module provides fine-grained access control for cross-realm
authentications by checking string attributes on the incoming
cross-realm TGT entry.  It supports realm-based and principal-specific
authorization rules.

The module is not installed by the build system or loaded by default,
and is documented only in the module source code.

[ghudson@mit.edu: simplified code and tests; edited commit message]

(cherry picked from commit ae8801b8e12d198f11f9279c747f8fa6d48c593e)
---
 src/Makefile.in                               |   1 +
 src/configure.ac                              |   1 +
 src/plugins/kdcpolicy/xrealmauthz/Makefile.in |  18 +
 src/plugins/kdcpolicy/xrealmauthz/deps        |  14 +
 src/plugins/kdcpolicy/xrealmauthz/main.c      | 380 ++++++++++++++++++
 .../kdcpolicy/xrealmauthz/xrealmauthz.exports |   1 +
 src/tests/Makefile.in                         |   1 +
 src/tests/t_xrealmauthz.py                    | 246 ++++++++++++
 8 files changed, 662 insertions(+)
 create mode 100644 src/plugins/kdcpolicy/xrealmauthz/Makefile.in
 create mode 100644 src/plugins/kdcpolicy/xrealmauthz/deps
 create mode 100644 src/plugins/kdcpolicy/xrealmauthz/main.c
 create mode 100644 src/plugins/kdcpolicy/xrealmauthz/xrealmauthz.exports
 create mode 100644 src/tests/t_xrealmauthz.py

diff --git a/src/Makefile.in b/src/Makefile.in
index f1ebde39b1..7fa3da923a 100644
--- a/src/Makefile.in
+++ b/src/Makefile.in
@@ -25,6 +25,7 @@ SUBDIRS=util include lib \
 	@lmdb_plugin_dir@ \
 	plugins/kdb/test \
 	plugins/kdcpolicy/test \
+	plugins/kdcpolicy/xrealmauthz \
 	plugins/preauth/otp \
 	plugins/preauth/pkinit \
 	plugins/preauth/spake \
diff --git a/src/configure.ac b/src/configure.ac
index 33a1160657..c0ccfb9be8 100644
--- a/src/configure.ac
+++ b/src/configure.ac
@@ -1563,6 +1563,7 @@ V5_AC_OUTPUT_MAKEFILE(.
 	plugins/kdb/db2/libdb2/test
 	plugins/kdb/test
 	plugins/kdcpolicy/test
+	plugins/kdcpolicy/xrealmauthz
 	plugins/preauth/otp
 	plugins/preauth/spake
 	plugins/preauth/test
diff --git a/src/plugins/kdcpolicy/xrealmauthz/Makefile.in b/src/plugins/kdcpolicy/xrealmauthz/Makefile.in
new file mode 100644
index 0000000000..78346d6572
--- /dev/null
+++ b/src/plugins/kdcpolicy/xrealmauthz/Makefile.in
@@ -0,0 +1,18 @@
+mydir=plugins$(S)kdcpolicy$(S)xrealmauthz
+BUILDTOP=$(REL)..$(S)..$(S)..
+
+LIBBASE=xrealmauthz
+LIBMAJOR=0
+LIBMINOR=0
+RELDIR=../plugins/kdcpolicy/xrealmauthz
+SHLIB_EXPDEPS=$(KRB5_BASE_DEPLIBS) $(KDB5_DEPLIB)
+SHLIB_EXPLIBS=$(KRB5_BASE_LIBS) $(KDB5_LIB)
+STLIBOBJS=main.o
+
+SRCS=$(srcdir)/main.c
+
+all-unix: all-libs
+install-unix:
+clean-unix:: clean-libs clean-libobjs
+@libnover_frag@
+@libobj_frag@
diff --git a/src/plugins/kdcpolicy/xrealmauthz/deps b/src/plugins/kdcpolicy/xrealmauthz/deps
new file mode 100644
index 0000000000..4ecf533f3f
--- /dev/null
+++ b/src/plugins/kdcpolicy/xrealmauthz/deps
@@ -0,0 +1,14 @@
+#
+# Generated makefile dependencies follow.
+#
+main.so main.po $(OUTPRE)main.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \
+  $(BUILDTOP)/include/krb5/krb5.h $(BUILDTOP)/include/osconf.h \
+  $(BUILDTOP)/include/profile.h $(COM_ERR_DEPS) $(top_srcdir)/include/k5-buf.h \
+  $(top_srcdir)/include/k5-err.h $(top_srcdir)/include/k5-gmt_mktime.h \
+  $(top_srcdir)/include/k5-int-pkinit.h $(top_srcdir)/include/k5-int.h \
+  $(top_srcdir)/include/k5-platform.h $(top_srcdir)/include/k5-plugin.h \
+  $(top_srcdir)/include/k5-thread.h $(top_srcdir)/include/k5-trace.h \
+  $(top_srcdir)/include/kdb.h $(top_srcdir)/include/krb5.h \
+  $(top_srcdir)/include/krb5/authdata_plugin.h $(top_srcdir)/include/krb5/kdcpolicy_plugin.h \
+  $(top_srcdir)/include/krb5/plugin.h $(top_srcdir)/include/port-sockets.h \
+  $(top_srcdir)/include/socket-utils.h main.c
diff --git a/src/plugins/kdcpolicy/xrealmauthz/main.c b/src/plugins/kdcpolicy/xrealmauthz/main.c
new file mode 100644
index 0000000000..72f077d434
--- /dev/null
+++ b/src/plugins/kdcpolicy/xrealmauthz/main.c
@@ -0,0 +1,380 @@
+/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/* plugins/kdcpolicy/xrealmauthz/main.c - xrealmauthz module implementation */
+/*
+ * Copyright (C) 2025 by Red Hat, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ *
+ * * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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
+ * COPYRIGHT HOLDER 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.
+ */
+
+/*
+ * The xrealmauthz module restricts authentications from clients in other
+ * realms.  It is not installed by the build system or loaded by default.  It
+ * can be loaded with the following configuration:
+ *
+ *   [plugins]
+ *     kdcpolicy = {
+ *       module = /path/to/xrealmauthz.so
+ *     }
+ *
+ * Once the module is loaded, all authentications from clients in other realms
+ * are rejected unless they are explicitly authorized, unless enforcement is
+ * turned off.  Authorization can be achieved in three ways:
+ *
+ * 1. If the xrealmauthz_allowed_realms profile variable in [kdcdefaults] has
+ *    one or more values, authentications by clients in those realms are always
+ *    permitted by this module, regardless of the authentication path.  (The
+ *    authentication path must still pass the transited check as configured in
+ *    [capaths]).  For example, the following configuration:
+ *
+ *    [kdcdefaults]
+ *      xrealmauthz_allowed_realms = REALM2.COM
+ *      xrealmauthz_allowed_realms = REALM3.COM
+ *
+ *    would cause this module to permit all authentications from clients in
+ *    REALM2.COM or REALM3.COM.
+ *
+ * 2. If the string attribute "xr:@CLIENTREALM" is present in the TGS entry
+ *    krbtgt/MYREALM@OREALM (where MYREALM is the realm served by the KDC),
+ *    then authentications from clients in CLIENTREALM are permitted via
+ *    OREALM.  The value of the string attribute is ignored.  For example, if
+ *    this KDC serves REALM1.COM, the following commands would permit
+ *    authentications via REALM2.COM for clients in both REALM2.COM itself and
+ *    REALM3.COM:
+ *
+ *      kadmin.local setstr krbtgt/REALM1.COM@REALM2.COM xr:@REALM2.COM ""
+ *      kadmin.local setstr krbtgt/REALM1.COM@REALM2.COM xr:@REALM3.COM ""
+ *
+ * 3. If the string attribute "xr:PRINC" is present in KRBTGT/MYREALM@OREALM,
+ *    authentications from the client principal PRINC are permitted.  PRINC
+ *    must contain a realm part if its realm differs from OREALM, and must
+ *    _not_ contain a realm part if its realm is the same as OREALM.  For
+ *    example, the following commands would permit authentications via
+ *    REALM2.COM for the clients u1@REALM2.COM and u2@REALM3.COM:
+ *
+ *      kadmin.local setstr krbtgt/REALM1.COM@REALM2.COM xr:u1 ""
+ *      kadmin.local setstr krbtgt/REALM1.COM@REALM2.COM xr:u2@REALM3.COM ""
+ *
+ * Enforcement may be turned off by setting the profile variable
+ * xrealmauthz_enforcing to false in [kdcdefaults]:
+ *
+ *   [kdcdefaults]
+ *     xrealmauthz_enforcing = false
+ *
+ * If enforcement is turned off, this module will permit all cross-realm
+ * authentications, but will log authentications that would otherwise be denied
+ * with a message containing:
+ *
+ *   xrealmauthz module would deny CLIENTPRINC for SERVERPRINC from REALM
+ */
+
+#include "k5-int.h"
+#include <kdb.h>
+#include <krb5/kdcpolicy_plugin.h>
+
+/* Prefix used for cross-realm authorization attributes */
+#define ATTR_PREFIX "xr:"
+
+struct xrealmauthz_data {
+    int enforcing;  /* Whether to actually enforce restrictions */
+    krb5_data *allowed_realms;
+    size_t num_allowed_realms;
+};
+
+/* Typedef for pointer to the structure */
+typedef struct xrealmauthz_data *xrealmauthz_moddata;
+
+static void
+free_moddata(xrealmauthz_moddata data)
+{
+    size_t i;
+
+    if (data == NULL)
+        return;
+    for (i = 0; i < data->num_allowed_realms; i++)
+        free(data->allowed_realms[i].data);
+    free(data->allowed_realms);
+    free(data);
+}
+
+static krb5_error_code
+xrealmauthz_init(krb5_context context, krb5_kdcpolicy_moddata *moddata_out)
+{
+    krb5_error_code ret;
+    int enforcing = 1;
+    xrealmauthz_moddata data = NULL;
+    profile_t profile = NULL;
+    char **realmlist = NULL;
+    size_t count, i;
+    const char *section[] = { "kdcdefaults", "xrealmauthz_allowed_realms",
+                              NULL };
+
+    *moddata_out = NULL;
+
+    ret = krb5_get_profile(context, &profile);
+    if (ret)
+        goto cleanup;
+
+    /* Check if enforcing mode is disabled in config, default to TRUE */
+    profile_get_boolean(profile, "kdcdefaults", "xrealmauthz_enforcing",
+                        NULL, TRUE, &enforcing);
+
+    data = k5alloc(sizeof(*data), &ret);
+    if (data == NULL)
+        goto cleanup;
+
+    /* Get array of allowed realms from config. */
+    ret = profile_get_values(profile, section, &realmlist);
+    if (ret && ret != PROF_NO_RELATION)
+        goto cleanup;
+    ret = 0;
+
+    if (realmlist != NULL) {
+        /* Count and allocate realm entries. */
+        for (count = 0; realmlist[count] != NULL; count++);
+        data->allowed_realms = k5calloc(count, sizeof(krb5_data), &ret);
+        if (data->allowed_realms == NULL)
+            goto cleanup;
+        data->num_allowed_realms = count;
+
+        /* Transfer ownership of the strings from the profile list. */
+        for (i = 0; i < count; i++)
+            data->allowed_realms[i] = string2data(realmlist[i]);
+        free(realmlist);
+        realmlist = NULL;
+    }
+
+    data->enforcing = enforcing;
+
+    com_err("", 0,
+            _("xrealmauthz cross-realm authorization module loaded "
+              "(enforcing mode: %s, pre-approved realms: %d)"),
+            enforcing ? _("enabled") : _("disabled"),
+            (int)data->num_allowed_realms);
+
+    *moddata_out = (krb5_kdcpolicy_moddata)data;
+    data = NULL;
+
+cleanup:
+    free_moddata(data);
+    profile_free_list(realmlist);
+    profile_release(profile);
+    return ret;
+}
+
+static krb5_error_code
+xrealmauthz_fini(krb5_context context, krb5_kdcpolicy_moddata moddata)
+{
+    free_moddata((xrealmauthz_moddata)moddata);
+    return 0;
+}
+
+static krb5_boolean
+is_realm_preapproved(xrealmauthz_moddata data, const krb5_data *client_realm)
+{
+    size_t i;
+
+    for (i = 0; i < data->num_allowed_realms; i++) {
+        if (data_eq(data->allowed_realms[i], *client_realm))
+            return TRUE;
+    }
+    return FALSE;
+}
+
+/* Set *result_out to true if tgt has a string attribute for attr_key with any
+ * value. */
+static krb5_error_code
+check_attr(krb5_context context, krb5_db_entry *tgt, const char *key,
+           krb5_boolean *result_out)
+{
+    krb5_error_code ret;
+    char *value;
+
+    *result_out = FALSE;
+
+    ret = krb5_dbe_get_string(context, tgt, key, &value);
+    if (!ret && value != NULL) {
+        *result_out = TRUE;
+        krb5_dbe_free_string(context, value);
+    }
+
+    return ret;
+}
+
+/* Set *result_out to true if tgt has an ACL attribute for realm
+ * ("xr:@realm"). */
+static krb5_error_code
+check_realm_attr(krb5_context context, krb5_db_entry *tgt,
+                 const krb5_data *realm, krb5_boolean *result_out)
+{
+    krb5_error_code ret;
+    char *key;
+
+    if (asprintf(&key, "%s@%.*s", ATTR_PREFIX,
+                 (int)realm->length, realm->data) < 0)
+        return ENOMEM;
+    ret = check_attr(context, tgt, key, result_out);
+    free(key);
+    return ret;
+}
+
+/* Set *result_out to true if tgt has an ACL attribute for princ ("xr:princ",
+ * with the realm omitted if princ is in tgt's realm). */
+static krb5_error_code
+check_princ_attr(krb5_context context, krb5_db_entry *tgt,
+                 krb5_const_principal princ, krb5_boolean *result_out)
+{
+    krb5_error_code ret;
+    int flags = 0, r;
+    char *princstr, *key;
+
+    /* Omit the realm if princ is in tgt's realm. */
+    if (krb5_realm_compare(context, tgt->princ, princ))
+        flags |= KRB5_PRINCIPAL_UNPARSE_NO_REALM;
+    ret = krb5_unparse_name_flags(context, princ, flags, &princstr);
+    if (ret)
+        return ret;
+
+    r = asprintf(&key, "%s%s", ATTR_PREFIX, princstr);
+    krb5_free_unparsed_name(context, princstr);
+    if (r < 0)
+        return ENOMEM;
+
+    ret = check_attr(context, tgt, key, result_out);
+    free(key);
+    return ret;
+}
+
+/* Check if cross-realm authentication is allowed from client via tgtname. */
+static krb5_error_code
+check_cross_realm_auth(krb5_context context, krb5_const_principal client,
+                       krb5_const_principal tgtname,
+                       krb5_const_principal server, xrealmauthz_moddata data,
+                       const char **status_out)
+{
+    krb5_error_code ret;
+    char *cpstr = NULL, *spstr = NULL;
+    krb5_boolean is_allowed = FALSE;
+    krb5_db_entry *tgt_entry = NULL;
+
+    *status_out = NULL;
+
+    /* Check if the client realm is pre-approved. */
+    if (is_realm_preapproved(data, &client->realm))
+        return 0;
+
+    /* Get TGT principal entry for string attribute checks. */
+    ret = krb5_db_get_principal(context, tgtname, 0, &tgt_entry);
+    if (ret) {
+        *status_out = "XREALMAUTHZ_GET_TGT";
+        goto cleanup;
+    }
+
+    /* Check if client's realm is allowed. */
+    ret = check_realm_attr(context, tgt_entry, &client->realm, &is_allowed);
+    if (ret || is_allowed)
+        goto cleanup;
+
+    /* Check if client is allowed. */
+    ret = check_princ_attr(context, tgt_entry, client, &is_allowed);
+    if (ret || is_allowed)
+        goto cleanup;
+
+    if (data->enforcing) {
+        /* The authentication is denied.  KDC logging of the error will include
+         * the client and server principal names. */
+        *status_out = "XREALMAUTHZ";
+        ret = KRB5KDC_ERR_POLICY;
+        k5_setmsg(context, ret, _("xrealmauthz module denied from %.*s"),
+                  (int)tgtname->realm.length, tgtname->realm.data);
+        goto cleanup;
+    }
+
+    /* The authentication would be denied if enforcement were turned on.
+     * Generate a log message including the client and server names. */
+    ret = krb5_unparse_name(context, client, &cpstr);
+    if (ret)
+        goto cleanup;
+    ret = krb5_unparse_name(context, server, &spstr);
+    if (ret)
+        goto cleanup;
+    com_err("", 0, _("xrealmauthz module would deny %s for %s from %.*s"),
+            cpstr, spstr, (int)tgtname->realm.length, tgtname->realm.data);
+
+cleanup:
+    krb5_db_free_principal(context, tgt_entry);
+    krb5_free_unparsed_name(context, cpstr);
+    krb5_free_unparsed_name(context, spstr);
+    return ret;
+}
+
+static krb5_error_code
+xrealmauthz_check(krb5_context context, krb5_kdcpolicy_moddata moddata,
+                  const krb5_kdc_req *request,
+                  const struct _krb5_db_entry_new *server,
+                  const krb5_ticket *ticket,
+                  const char *const *auth_indicators, const char **status_out,
+                  krb5_deltat *lifetime_out, krb5_deltat *renew_lifetime_out)
+{
+    xrealmauthz_moddata data = (xrealmauthz_moddata)moddata;
+
+    *status_out = NULL;
+    *lifetime_out = *renew_lifetime_out = 0;
+
+    /* Only check cross-realm requests. */
+    if (krb5_realm_compare(context, server->princ, ticket->enc_part2->client))
+        return 0;
+
+    /* Don't check if the header ticket isn't a TGT (such as for renewals). */
+    if (ticket->server->length != 2 ||
+        !data_eq_string(ticket->server->data[0], KRB5_TGS_NAME))
+        return 0;
+
+    return check_cross_realm_auth(context, ticket->enc_part2->client,
+                                  ticket->server, request->server, data,
+                                  status_out);
+}
+
+krb5_error_code
+kdcpolicy_xrealmauthz_initvt(krb5_context context, int maj_ver, int min_ver,
+                             krb5_plugin_vtable vtable);
+
+krb5_error_code
+kdcpolicy_xrealmauthz_initvt(krb5_context context, int maj_ver, int min_ver,
+                             krb5_plugin_vtable vtable)
+{
+    krb5_kdcpolicy_vtable vt;
+
+    if (maj_ver != 1)
+        return KRB5_PLUGIN_VER_NOTSUPP;
+
+    vt = (krb5_kdcpolicy_vtable)vtable;
+    vt->name = "xrealmauthz";
+    vt->init = xrealmauthz_init;
+    vt->fini = xrealmauthz_fini;
+    vt->check_tgs = xrealmauthz_check;
+    return 0;
+}
diff --git a/src/plugins/kdcpolicy/xrealmauthz/xrealmauthz.exports b/src/plugins/kdcpolicy/xrealmauthz/xrealmauthz.exports
new file mode 100644
index 0000000000..a5794afdbd
--- /dev/null
+++ b/src/plugins/kdcpolicy/xrealmauthz/xrealmauthz.exports
@@ -0,0 +1 @@
+kdcpolicy_xrealmauthz_initvt
diff --git a/src/tests/Makefile.in b/src/tests/Makefile.in
index 41ac0d3b2a..80ac35aacc 100644
--- a/src/tests/Makefile.in
+++ b/src/tests/Makefile.in
@@ -193,6 +193,7 @@ check-pytests: responder s2p s4u2proxy unlockiter s4u2self
 	$(RUNPYTEST) $(srcdir)/t_replay.py $(PYTESTFLAGS)
 	$(RUNPYTEST) $(srcdir)/t_sendto_kdc.py $(PYTESTFLAGS)
 	$(RUNPYTEST) $(srcdir)/t_alias.py $(PYTESTFLAGS)
+	$(RUNPYTEST) $(srcdir)/t_xrealmauthz.py $(PYTESTFLAGS)
 
 clean:
 	$(RM) adata conccache etinfo forward gcred hist hooks hrealm
diff --git a/src/tests/t_xrealmauthz.py b/src/tests/t_xrealmauthz.py
new file mode 100644
index 0000000000..3b3921f036
--- /dev/null
+++ b/src/tests/t_xrealmauthz.py
@@ -0,0 +1,246 @@
+#!/usr/bin/env python3
+
+from k5test import *
+import os
+
+# Define realm names for testing topology.
+REALM1 = 'REALM1.COM'
+REALM2 = 'REALM2.COM'
+REALM3 = 'REALM3.COM'
+
+# Name the cross-realm TGS for incoming authentications as seen by REALM1.
+cross_tgt_name = 'krbtgt/REALM1.COM@REALM2.COM'
+
+# Define capaths configuration to allow authentication from REALM3 via REALM2.
+capaths_config = {
+    'capaths': {
+        REALM3: {REALM1: [REALM2]},  # REALM3 -> REALM2 -> REALM1
+        REALM2: {REALM1: '.'}        # Direct path from REALM2 to REALM1
+    }
+}
+
+# Restart realm's KDC with xrealmauthz_enforcing set to true, false,
+# or not set at all if enforcing is None.  Clear the log and look for
+# the expected startup message.
+def set_enforcing_mode(realm, enforcing):
+    if enforcing is None:
+        kdc_conf = {}
+    else:
+        kdc_conf = {'kdcdefaults': {'xrealmauthz_enforcing': str(enforcing)}}
+    expected_msg = 'enabled' if enforcing else 'disabled'
+
+    realm.stop_kdc()
+    realm_env = realm.special_env('enforce_config', True, kdc_conf=kdc_conf)
+
+    # Clear the KDC log before starting.
+    kdc_log = os.path.join(realm.testdir, 'kdc.log')
+    with open(kdc_log, 'w') as f:
+        f.truncate(0)
+
+    realm.start_kdc(env=realm_env)
+
+    # Check for module initialization message.
+    with open(kdc_log, 'r') as f:
+        log_content = f.read()
+        expected_init_msg = 'loaded (enforcing mode: %s,' % expected_msg
+        if expected_init_msg not in log_content:
+            fail('could not find module init log message')
+
+
+# Return true if a "would deny" message is present in the KDC log file.
+def check_would_deny_log(realm):
+    kdc_log = os.path.join(realm.testdir, 'kdc.log')
+    with open(kdc_log, 'r') as f:
+        log_content = f.read()
+        return 'would deny' in log_content
+
+
+# Clear the KDC log file.
+def clear_kdc_log(realm):
+    kdc_log = os.path.join(realm.testdir, 'kdc.log')
+    with open(kdc_log, 'w') as f:
+        f.truncate(0)
+
+
+# Return a descriptive string for an enforcing mode.
+def enforcing_str(enforcing):
+    if enforcing is None:
+        return 'default mode'
+    elif enforcing:
+        return 'enforcing explicitly enabled'
+    else:
+        return 'enforcing explicitly disabled'
+
+
+# Test unauthorized cross-realm access with the given enforcing mode.
+def test_denied(src_realm, dst_realm, client_princ, service_princ,
+                enforcing=None):
+    src_realm.kinit(client_princ, password('user'))
+    if enforcing is False:
+        clear_kdc_log(dst_realm)
+        src_realm.run([kvno, service_princ])
+        if not check_would_deny_log(dst_realm):
+            fail('Expected "would deny" message in KDC log')
+    else:
+        # Both enforcing=True and enforcing=None should enforce.
+        src_realm.run([kvno, service_princ], expected_code=1,
+                      expected_msg='KDC policy rejects request')
+
+
+# Verify that access is allowed when properly authorized.
+def test_allowed(src_realm, client_princ, service_princ):
+    src_realm.kinit(client_princ, password('user'))
+    src_realm.run([kvno, service_princ])
+
+
+# Test realm-based authorization with direct trust.
+def test_direct_realm_authz(r1, r2, enforcing=None):
+    mark('direct realm authorization (%s)' % enforcing_str(enforcing))
+
+    # Verify that access is denied without authorization.
+    test_denied(r2, r1, r2.user_princ, r1.host_princ, enforcing)
+
+    # Add realm authorization and verify that access is allowed.
+    r1.run([kadminl, 'setstr', cross_tgt_name, 'xr:@' + r2.realm, '""'])
+    test_allowed(r2, r2.user_princ, r1.host_princ)
+
+    # Remove authorization and verify denial/logging again.
+    r1.run([kadminl, 'delstr', cross_tgt_name, 'xr:@' + r2.realm])
+    test_denied(r2, r1, r2.user_princ, r1.host_princ, enforcing)
+
+
+# Test principal-specific authorization with direct trust
+def test_direct_principal_authz(r1, r2, enforcing=None):
+    mark('direct princ authorization (%s)' % enforcing_str(enforcing))
+
+    # Create test principals.
+    authorized_princ = 'authz_test@' + r2.realm
+    unauthorized_princ = 'unauth_test@' + r2.realm
+    r2.addprinc(authorized_princ, password('user'))
+    r2.addprinc(unauthorized_princ, password('user'))
+
+    # Add principal authorization and verify that only
+    # authorized_princ has access.
+    r1.run([kadminl, 'setstr', cross_tgt_name, 'xr:authz_test', '""'])
+    test_allowed(r2, authorized_princ, r1.host_princ)
+    test_denied(r2, r1, unauthorized_princ, r1.host_princ, enforcing)
+
+    # Remove authorization and verify that authorized_princ is denied.
+    r1.run([kadminl, 'delstr', cross_tgt_name, 'xr:authz_test'])
+    test_denied(r2, r1, authorized_princ, r1.host_princ, enforcing)
+
+    # Clean up.
+    r2.run([kadminl, 'delprinc', '-force', authorized_princ])
+    r2.run([kadminl, 'delprinc', '-force', unauthorized_princ])
+
+
+# Test realm-based authorization with transitive trust.
+def test_transitive_realm_authz(r1, r2, r3, enforcing=None):
+    mark('transitive realm authorization (%s)' + enforcing_str(enforcing))
+
+    # Verify that access is denied/logged without authorization.
+    test_denied(r3, r1, r3.user_princ, r1.host_princ, enforcing)
+
+    # Add realm authorization and verify that access is allowed.
+    r1.run([kadminl, 'setstr', cross_tgt_name, 'xr:@' + r3.realm, '""'])
+    test_allowed(r3, r3.user_princ, r1.host_princ)
+
+    # Remove authorization and verify denial/logging again.
+    r1.run([kadminl, 'delstr', cross_tgt_name, 'xr:@' + r3.realm])
+    test_denied(r3, r1, r3.user_princ, r1.host_princ, enforcing)
+
+
+# Test principal-specific authorization with transitive trust.
+def test_transitive_principal_authz(r1, r2, r3, enforcing=None):
+    mark('transitive princ authorization (%s)' % enforcing_str(enforcing))
+
+    # Create test principals.
+    authorized_princ = 'authz_test@' + r3.realm
+    unauthorized_princ = 'unauth_test@' + r3.realm
+    r3.addprinc(authorized_princ, password('user'))
+    r3.addprinc(unauthorized_princ, password('user'))
+
+    # Add principal authorization and verify that only
+    # authorized_princ has access.
+    r1.run([kadminl, 'setstr', cross_tgt_name, 'xr:' + authorized_princ, '""'])
+    test_allowed(r3, authorized_princ, r1.host_princ)
+    test_denied(r3, r1, unauthorized_princ, r1.host_princ, enforcing)
+
+    # Remove authorization and verify that authorized_princ is denied.
+    r1.run([kadminl, 'delstr', cross_tgt_name, 'xr:' + authorized_princ])
+    test_denied(r3, r1, authorized_princ, r1.host_princ, enforcing)
+
+    # Clean up.
+    r3.run([kadminl, 'delprinc', '-force', authorized_princ])
+    r3.run([kadminl, 'delprinc', '-force', unauthorized_princ])
+
+
+# Test pre-approved realms configuration.
+def test_allowed_realms(r1, r2, r3, enforcing=None):
+    mark('pre-approved realms (%s)' % enforcing_str(enforcing))
+
+    # Configure a single allowed realm.
+    conf = {'kdcdefaults': {'xrealmauthz_allowed_realms': [REALM2]}}
+    if enforcing is not None:
+        conf['kdcdefaults']['xrealmauthz_enforcing'] = str(enforcing)
+    r1.stop_kdc()
+    realm_env = r1.special_env('allowed_realms', True, kdc_conf=conf)
+    r1.start_kdc(env=realm_env)
+
+    # Verify that REALM2 has full access, but REALM3 still goes
+    # through normal authorization and is denied.
+    test_allowed(r2, r2.user_princ, r1.host_princ)
+    test_denied(r3, r1, r3.user_princ, r1.host_princ, enforcing)
+
+    # Configure multiple allowed realms.
+    conf = {'kdcdefaults': {'xrealmauthz_allowed_realms': [REALM2, REALM3]}}
+    if enforcing is not None:
+        conf['kdcdefaults']['xrealmauthz_enforcing'] = str(enforcing)
+    r1.stop_kdc()
+    realm_env = r1.special_env('multi_allowed', True, kdc_conf=conf)
+    r1.start_kdc(env=realm_env)
+
+    # Verify that both realms have full access.
+    test_allowed(r2, r2.user_princ, r1.host_princ)
+    test_allowed(r3, r3.user_princ, r1.host_princ)
+
+
+# Configure realm1 with the xrealmauthz module enabled.
+plugin_path = os.path.join(buildtop, 'plugins', 'kdcpolicy', 'xrealmauthz',
+                           'xrealmauthz.so')
+realm1_kdc_conf = {'plugins': {'kdcpolicy':
+                               {'module': 'xrealmauthz:' + plugin_path}}}
+
+# Set up three realms for all tests.
+# REALM1 <- REALM2 <- REALM3 for transitive tests
+# REALM1 <- REALM2 direct trust is used for direct tests
+mark('creating realms')
+realms = cross_realms(3, xtgts=((1, 0), (2, 1)),
+                      args=({'realm': REALM1, 'krb5_conf': capaths_config,
+                             'kdc_conf': realm1_kdc_conf},
+                            {'realm': REALM2, 'krb5_conf': capaths_config},
+                            {'realm': REALM3, 'krb5_conf': capaths_config}))
+r1, r2, r3 = realms
+
+test_direct_realm_authz(r1, r2)
+test_direct_principal_authz(r1, r2)
+test_transitive_realm_authz(r1, r2, r3)
+test_transitive_principal_authz(r1, r2, r3)
+
+test_allowed_realms(r1, r2, r3)
+test_allowed_realms(r1, r2, r3, enforcing=True)
+test_allowed_realms(r1, r2, r3, enforcing=False)
+
+set_enforcing_mode(r1, True)
+test_direct_realm_authz(r1, r2, enforcing=True)
+test_direct_principal_authz(r1, r2, enforcing=True)
+test_transitive_realm_authz(r1, r2, r3, enforcing=True)
+test_transitive_principal_authz(r1, r2, r3, enforcing=True)
+
+set_enforcing_mode(r1, False)
+test_direct_realm_authz(r1, r2, enforcing=False)
+test_direct_principal_authz(r1, r2, enforcing=False)
+test_transitive_realm_authz(r1, r2, r3, enforcing=False)
+test_transitive_principal_authz(r1, r2, r3, enforcing=False)
+
+success('Cross-realm authorization tests completed successfully')
-- 
2.53.0


From 4634ca1f8242c24632e006d7b651064a7556cc92 Mon Sep 17 00:00:00 2001
From: Julien Rische <jrische@redhat.com>
Date: Thu, 29 Jan 2026 19:05:01 +0100
Subject: [PATCH 17/21] Install xrealmauthz like other plugins

The xrealmauthz kdcpolicy plugin was merged upstream, but it is not
installed my the Makefile. The commit adds additional configuration to
install it in the krb5 modules directory when running "make install".
---
 src/Makefile.in                               | 2 +-
 src/config/pre.in                             | 1 +
 src/plugins/kdcpolicy/xrealmauthz/Makefile.in | 4 +++-
 3 files changed, 5 insertions(+), 2 deletions(-)

diff --git a/src/Makefile.in b/src/Makefile.in
index 7fa3da923a..05c4b01761 100644
--- a/src/Makefile.in
+++ b/src/Makefile.in
@@ -71,7 +71,7 @@ INSTALLMKDIRS = $(KRB5ROOT) $(KRB5MANROOT) $(KRB5OTHERMKDIRS) \
 		$(FILE_CATDIR) $(OVERVIEW_CATDIR) \
 		$(KRB5_LIBDIR) $(KRB5_INCDIR) \
 		$(KRB5_DB_MODULE_DIR) $(KRB5_PA_MODULE_DIR) \
-		$(KRB5_AD_MODULE_DIR) \
+		$(KRB5_AD_MODULE_DIR) $(KRB5_KP_MODULE_DIR) \
 		$(KRB5_LIBKRB5_MODULE_DIR) $(KRB5_TLS_MODULE_DIR) \
 		$(localstatedir) $(localstatedir)/krb5kdc \
 		$(runstatedir) $(runstatedir)/krb5kdc \
diff --git a/src/config/pre.in b/src/config/pre.in
index 3724d26ae6..dbe692b251 100644
--- a/src/config/pre.in
+++ b/src/config/pre.in
@@ -220,6 +220,7 @@ MODULE_DIR = @libdir@/krb5/plugins
 KRB5_DB_MODULE_DIR = $(MODULE_DIR)/kdb
 KRB5_PA_MODULE_DIR = $(MODULE_DIR)/preauth
 KRB5_AD_MODULE_DIR = $(MODULE_DIR)/authdata
+KRB5_KP_MODULE_DIR = $(MODULE_DIR)/kdcpolicy
 KRB5_LIBKRB5_MODULE_DIR = $(MODULE_DIR)/libkrb5
 KRB5_TLS_MODULE_DIR = $(MODULE_DIR)/tls
 KRB5_LOCALEDIR = @localedir@
diff --git a/src/plugins/kdcpolicy/xrealmauthz/Makefile.in b/src/plugins/kdcpolicy/xrealmauthz/Makefile.in
index 78346d6572..b6740210a7 100644
--- a/src/plugins/kdcpolicy/xrealmauthz/Makefile.in
+++ b/src/plugins/kdcpolicy/xrealmauthz/Makefile.in
@@ -1,5 +1,7 @@
 mydir=plugins$(S)kdcpolicy$(S)xrealmauthz
 BUILDTOP=$(REL)..$(S)..$(S)..
+KRB5_KP_MODULE_DIR = $(MODULE_DIR)/kdcpolicy
+MODULE_INSTALL_DIR = $(KRB5_KP_MODULE_DIR)
 
 LIBBASE=xrealmauthz
 LIBMAJOR=0
@@ -12,7 +14,7 @@ STLIBOBJS=main.o
 SRCS=$(srcdir)/main.c
 
 all-unix: all-libs
-install-unix:
+install-unix: install-libs
 clean-unix:: clean-libs clean-libobjs
 @libnover_frag@
 @libobj_frag@
-- 
2.53.0


From 6d066787d23c913789dcfc220b34cd3a78ada4c7 Mon Sep 17 00:00:00 2001
From: Julien Rische <jrische@redhat.com>
Date: Mon, 16 Feb 2026 16:30:14 +0100
Subject: [PATCH 18/21] Force "fork" method for RADIUS daemon in OTP test

The RADIUS daemon used in the OTP test relies on
multiprocessing.Process. Since Python 3.14, multiprocessing changed its
start method from "fork" to "forkserver". This method is not compatible
with the t_otp.py test.

This commit explicitly sets multiprocessing's start method to "fork" for
test t_otp.py, using multiprocessing.set_start_method() (available since
Python 3.4).

Pull-request: https://github.com/krb5/krb5/pull/1483
---
 src/tests/t_otp.py | 12 ++++++++----
 1 file changed, 8 insertions(+), 4 deletions(-)

diff --git a/src/tests/t_otp.py b/src/tests/t_otp.py
index dd5cdc5c26..c173b55c41 100755
--- a/src/tests/t_otp.py
+++ b/src/tests/t_otp.py
@@ -38,10 +38,14 @@ try:
 except ImportError:
     skip_rest('OTP tests', 'Python pyrad module not found')
 try:
-    from multiprocessing import Process, Queue
+    import multiprocessing
 except ImportError:
     skip_rest('OTP tests', 'Python version 2.6 required')
 
+# Since Python 3.14, "forkserver" replaces "fork" as default method on POSIX.
+# "forkserver" is not compatible with this test, so force the "fork" method.
+multiprocessing.set_start_method('fork', force=True)
+
 # We could use a dictionary file, but since we need so few attributes,
 # we'll just include them here.
 radius_attributes = '''
@@ -52,7 +56,7 @@ ATTRIBUTE    NAS-Identifier  32    string
 ATTRIBUTE    Message-Authenticator 80 octets
 '''
 
-class RadiusDaemon(Process):
+class RadiusDaemon(multiprocessing.Process):
     MAX_PACKET_SIZE = 4096
     DICTIONARY = dictionary.Dictionary(io.StringIO(radius_attributes))
 
@@ -186,7 +190,7 @@ conf = {'plugins': {'kdcpreauth': {'enable_only': 'otp'}},
                 'unix': {'server': socket_file,
                          'strip_realm': 'false'}}}
 
-queue = Queue()
+queue = multiprocessing.Queue()
 
 realm = K5Realm(kdc_conf=conf)
 realm.run([kadminl, 'modprinc', '+requires_preauth', realm.user_princ])
@@ -259,7 +263,7 @@ verify(daemon, queue, True, realm.user_princ, 'accept')
 ## tokens configured, with the first rejecting and the second
 ## accepting.  With the bug, the KDC incorrectly rejects the request
 ## and then performs invalid memory accesses, most likely crashing.
-queue2 = Queue()
+queue2 = multiprocessing.Queue()
 daemon1 = UDPRadiusDaemon(args=(server_addr, secret_file, 'accept1', queue))
 daemon2 = UnixRadiusDaemon(args=(socket_file, None, 'accept2', queue2))
 daemon1.start()
-- 
2.53.0


From 4d8e778bdbf6476e8aa397ef046126ae532f03d6 Mon Sep 17 00:00:00 2001
From: Alexander Bokovoy <abokovoy@redhat.com>
Date: Sun, 8 Mar 2026 21:50:52 +0200
Subject: [PATCH 19/21] Fix S4U2Self ignoring time_req when acquiring
 impersonated credentials
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

gss_acquire_cred() for the service locates the existing TGT in the
ccache and records its KDC-granted endtime as cred->expire; it never
requests a shorter-lived TGT.  So when gss_acquire_cred_impersonate_name()
calls kg_impersonate_name() with a time_req, the impersonator TGT already
carries a KDC-defined lifetime, not the requested one.

kg_impersonate_name() compounds this by zero-initialising in_creds
(leaving in_creds.times.endtime = 0) and never writing time_req into it.
When that reaches send_tgs.c:

    req.till = desired->times.endtime ? desired->times.endtime
                                      : tgt->times.endtime;

the zero endtime causes the fallback to tgt->times.endtime — the
impersonator TGT's full KDC-granted lifetime.  The KDC therefore issues
the S4U2Self ticket with KDC-policy lifetime, not the requested time_req.

The subsequent S4U2Proxy request via gss_init_sec_context() gets the
correct lifetime because that is an entirely separate call with its own
time_req: kg_new_connection() converts it to an absolute timestamp
(ctx->krb_times.endtime = ts_incr(now, time_req)) and get_credentials()
places it into in_creds.times.endtime before calling krb5_get_credentials().
send_tgs.c then takes the first branch and sends the requested deadline.
This has nothing to do with what gss_acquire_cred_impersonate_name() did.

Fix kg_impersonate_name() to apply the same time_req-to-endtime
conversion that kg_new_connection() already performs, so the S4U2Self
TGS-REQ carries the caller's requested deadline rather than silently
falling back to the impersonator TGT's full lifetime.

Signed-off-by: Alexander Bokovoy <abokovoy@redhat.com>
(cherry picked from commit 083f805989b44a1692784618531fe3134c5ed715)
---
 src/lib/gssapi/krb5/s4u_gss_glue.c | 11 +++++++++++
 1 file changed, 11 insertions(+)

diff --git a/src/lib/gssapi/krb5/s4u_gss_glue.c b/src/lib/gssapi/krb5/s4u_gss_glue.c
index fa7f980af7..9f2cbebec7 100644
--- a/src/lib/gssapi/krb5/s4u_gss_glue.c
+++ b/src/lib/gssapi/krb5/s4u_gss_glue.c
@@ -53,6 +53,17 @@ kg_impersonate_name(OM_uint32 *minor_status,
     *output_cred = NULL;
     memset(&in_creds, 0, sizeof(in_creds));
 
+    if (time_req != 0 && time_req != GSS_C_INDEFINITE) {
+        krb5_timestamp now;
+
+        code = krb5_timeofday(context, &now);
+        if (code != 0) {
+            *minor_status = code;
+            return GSS_S_FAILURE;
+        }
+        in_creds.times.endtime = ts_incr(now, time_req);
+    }
+
     if (user->is_cert)
         subject_cert = user->princ->data;
     else
-- 
2.53.0


From 5b185893438f775538a8d6340e9f4f39f6383cc7 Mon Sep 17 00:00:00 2001
From: Alexander Bokovoy <abokovoy@redhat.com>
Date: Mon, 9 Mar 2026 09:16:56 +0200
Subject: [PATCH 20/21] Fix S4U2Self ignoring time_req when copying
 impersonator TGT

gss_acquire_cred_impersonate_name() with a time_req bounded the
S4U2Self evidence ticket but left the impersonator TGT in the
delegated ccache with its original unrestricted lifetime.

Replace the krb5_cc_copy_creds() call in make_proxy_cred() with a
manual iteration that caps each copied credential's endtime to the
evidence ticket's endtime when time_req was specified.

Signed-off-by: Alexander Bokovoy <abokovoy@redhat.com>
(cherry picked from commit 5ece439a6c5950314f9492e04d0441d7b14a9ebb)
---
 src/lib/gssapi/krb5/s4u_gss_glue.c | 33 ++++++++++++++++++++++++++----
 1 file changed, 29 insertions(+), 4 deletions(-)

diff --git a/src/lib/gssapi/krb5/s4u_gss_glue.c b/src/lib/gssapi/krb5/s4u_gss_glue.c
index 9f2cbebec7..10288ebe94 100644
--- a/src/lib/gssapi/krb5/s4u_gss_glue.c
+++ b/src/lib/gssapi/krb5/s4u_gss_glue.c
@@ -192,14 +192,35 @@ krb5_gss_acquire_cred_impersonate_name(OM_uint32 *minor_status,
  */
 static krb5_error_code
 make_proxy_cred(krb5_context context, krb5_gss_cred_id_t cred,
-                krb5_gss_cred_id_t impersonator_cred)
+                krb5_gss_cred_id_t impersonator_cred,
+                krb5_timestamp max_endtime)
 {
     krb5_error_code code;
     krb5_data data;
+    krb5_cc_cursor cur = 0;
+    krb5_creds cur_creds;
     char *str;
 
-    code = krb5_cc_copy_creds(context, impersonator_cred->ccache,
-                              cred->ccache);
+    /* Copy credentials from the impersonator ccache, bounding endtime when
+     * requested so copied TGTs don't outlive the S4U2Self evidence ticket. */
+    code = krb5_cc_start_seq_get(context, impersonator_cred->ccache, &cur);
+    if (code)
+        return code;
+
+    while (!(code = krb5_cc_next_cred(context, impersonator_cred->ccache,
+                                      &cur, &cur_creds))) {
+        if (max_endtime != 0 && cur_creds.times.endtime > max_endtime)
+            cur_creds.times.endtime = max_endtime;
+        code = krb5_cc_store_cred(context, cred->ccache, &cur_creds);
+        krb5_free_cred_contents(context, &cur_creds);
+        if (code)
+            break;
+    }
+
+    if (cur)
+        krb5_cc_end_seq_get(context, impersonator_cred->ccache, &cur);
+    if (code == KRB5_CC_END)
+        code = 0;
     if (code)
         return code;
 
@@ -275,7 +296,11 @@ kg_compose_deleg_cred(OM_uint32 *minor_status,
     if (code != 0)
         goto cleanup;
 
-    code = make_proxy_cred(context, cred, impersonator_cred);
+    /* Bound copied credentials to the evidence ticket's endtime when the
+     * caller specified a time_req, so TGTs don't outlive the impersonation. */
+    code = make_proxy_cred(context, cred, impersonator_cred,
+                           (time_req != 0 && time_req != GSS_C_INDEFINITE) ?
+                           subject_creds->times.endtime : 0);
     if (code != 0)
         goto cleanup;
 
-- 
2.53.0


From 8df1c41911e7179d2e6cdb72b3bb568c1db08bd3 Mon Sep 17 00:00:00 2001
From: Alexander Bokovoy <abokovoy@redhat.com>
Date: Mon, 9 Mar 2026 09:17:08 +0200
Subject: [PATCH 21/21] Add t_s4u test for time_req bounding all delegated-cred
 tickets

Add --time-req N option to t_s4u and a check_cred_endtimes() function
that exports the S4U2Self credential to a MEMORY ccache and verifies
every non-config ticket's endtime is within N seconds of now.

Add a t_s4u.py test case that exercises this with time_req=600 to
catch regressions where the impersonator TGT escapes the lifetime
bound.

Signed-off-by: Alexander Bokovoy <abokovoy@redhat.com>
(cherry picked from commit bbd23bd06efbf31757a0011e303444193df1674e)
---
 src/tests/gssapi/t_s4u.c  | 78 +++++++++++++++++++++++++++++++++++++--
 src/tests/gssapi/t_s4u.py |  5 +++
 2 files changed, 80 insertions(+), 3 deletions(-)

diff --git a/src/tests/gssapi/t_s4u.c b/src/tests/gssapi/t_s4u.c
index 0400f8f61f..c73f187b25 100644
--- a/src/tests/gssapi/t_s4u.c
+++ b/src/tests/gssapi/t_s4u.c
@@ -57,6 +57,7 @@
 #include "common.h"
 
 static int use_spnego = 0;
+static OM_uint32 time_req = GSS_C_INDEFINITE;
 
 static void
 test_greet_authz_data(gss_name_t *name)
@@ -122,6 +123,66 @@ init_accept_sec_context(gss_cred_id_t claimant_cred_handle,
     (void)gss_delete_sec_context(&minor, &acceptor_context, NULL);
 }
 
+/*
+ * Export cred to a MEMORY ccache and verify that every non-config ticket's
+ * endtime is within secs seconds of now.  Used to check that time_req is
+ * honoured for all credentials copied into the delegated-cred ccache (not
+ * just the S4U2Self evidence ticket).
+ */
+static void
+check_cred_endtimes(gss_cred_id_t cred, OM_uint32 secs)
+{
+    krb5_error_code ret;
+    krb5_context context = NULL;
+    krb5_creds kcred;
+    krb5_cc_cursor cur;
+    krb5_ccache ccache;
+    krb5_timestamp now, max_endtime;
+    gss_key_value_set_desc store;
+    gss_key_value_element_desc elem;
+    OM_uint32 major, minor;
+    const char *ccname = "MEMORY:endtime";
+
+    store.count = 1;
+    store.elements = &elem;
+    elem.key = "ccache";
+    elem.value = ccname;
+    major = gss_store_cred_into(&minor, cred, GSS_C_INITIATE, &mech_krb5, 1, 0,
+                                &store, NULL, NULL);
+    check_gsserr("gss_store_cred_into", major, minor);
+
+    ret = krb5_init_context(&context);
+    check_k5err(context, "krb5_init_context", ret);
+
+    ret = krb5_timeofday(context, &now);
+    check_k5err(context, "krb5_timeofday", ret);
+
+    /* Allow 5 seconds of slack for test overhead. */
+    max_endtime = now + (krb5_timestamp)secs + 5;
+
+    ret = krb5_cc_resolve(context, ccname, &ccache);
+    check_k5err(context, "krb5_cc_resolve", ret);
+
+    ret = krb5_cc_start_seq_get(context, ccache, &cur);
+    check_k5err(context, "krb5_cc_start_seq_get", ret);
+
+    while (!krb5_cc_next_cred(context, ccache, &cur, &kcred)) {
+        if (!krb5_is_config_principal(context, kcred.server) &&
+            kcred.times.endtime > max_endtime) {
+            printf("Credential endtime %d exceeds allowed %d (time_req=%u)\n",
+                   (int)kcred.times.endtime, (int)max_endtime, secs);
+            exit(1);
+        }
+        krb5_free_cred_contents(context, &kcred);
+    }
+
+    ret = krb5_cc_end_seq_get(context, ccache, &cur);
+    check_k5err(context, "krb5_cc_end_seq_get", ret);
+
+    krb5_cc_destroy(context, ccache);
+    krb5_free_context(context);
+}
+
 static void
 check_ticket_count(gss_cred_id_t cred, int expected)
 {
@@ -244,8 +305,8 @@ main(int argc, char *argv[])
     gss_OID_set mechs;
     gss_buffer_set_t bufset = GSS_C_NO_BUFFER_SET;
 
-    if (argc < 2 || argc > 5) {
-        fprintf(stderr, "Usage: %s [--spnego] [user] "
+    if (argc < 2 || argc > 7) {
+        fprintf(stderr, "Usage: %s [--spnego] [--time-req N] user "
                 "[proxy-target] [keytab]\n", argv[0]);
         fprintf(stderr, "       proxy-target and keytab are optional\n");
         exit(1);
@@ -257,6 +318,12 @@ main(int argc, char *argv[])
         argv++;
     }
 
+    if (argc > 2 && strcmp(argv[1], "--time-req") == 0) {
+        time_req = (OM_uint32)atol(argv[2]);
+        argc -= 2;
+        argv += 2;
+    }
+
     user = import_name(argv[1]);
 
     if (argc > 2 && strcmp(argv[2], "-"))
@@ -281,11 +348,16 @@ main(int argc, char *argv[])
 
     /* Get S4U2Self cred. */
     major = gss_acquire_cred_impersonate_name(&minor, impersonator_cred_handle,
-                                              user, GSS_C_INDEFINITE, mechs,
+                                              user, time_req, mechs,
                                               GSS_C_INITIATE,
                                               &user_cred_handle, NULL, NULL);
     check_gsserr("gss_acquire_cred_impersonate_name", major, minor);
 
+    /* When a time_req was specified, verify all ccache credentials are
+     * bounded by it, including any TGT copied from the impersonator. */
+    if (time_req != GSS_C_INDEFINITE)
+        check_cred_endtimes(user_cred_handle, time_req);
+
     init_accept_sec_context(user_cred_handle, impersonator_cred_handle,
                             &delegated_cred_handle);
     printf("\n");
diff --git a/src/tests/gssapi/t_s4u.py b/src/tests/gssapi/t_s4u.py
index 4a1cdb2355..813e27fc15 100755
--- a/src/tests/gssapi/t_s4u.py
+++ b/src/tests/gssapi/t_s4u.py
@@ -113,6 +113,11 @@ if 'auth1: user@' not in out or 'auth2: user@' not in out:
 # Successful S4U2Self -> S4U2Proxy.
 out = realm.run(['./t_s4u', puser, pservice2])
 
+# Verify that time_req bounds all credentials in the delegated ccache,
+# including the impersonator TGT copied by make_proxy_cred().
+mark('S4U2Self time_req bounds impersonator TGT in delegated ccache')
+realm.run(['./t_s4u', '--time-req', '600', puser, pservice2])
+
 # Regression test for #8139: get a user ticket directly for service1 and
 # try krb5 -> S4U2Proxy.
 realm.kinit(realm.user_princ, None, ['-f', '-k', '-c', usercache,
-- 
2.53.0

