diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..eb8378e
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,2 @@
+SOURCES/krb5-1.16.1-pdfs.tar
+SOURCES/krb5-1.16.1.tar.gz
diff --git a/.krb5.metadata b/.krb5.metadata
new file mode 100644
index 0000000..d788450
--- /dev/null
+++ b/.krb5.metadata
@@ -0,0 +1,2 @@
+494c62bea08e5d26e01d47c409ac745b65e509c8 SOURCES/krb5-1.16.1-pdfs.tar
+8353f2d900a7d52499c7c2605d5e295f71dd5e67 SOURCES/krb5-1.16.1.tar.gz
diff --git a/SOURCES/Add-ASN.1-encoders-and-decoders-for-SPAKE-types.patch b/SOURCES/Add-ASN.1-encoders-and-decoders-for-SPAKE-types.patch
new file mode 100644
index 0000000..6e78dcc
--- /dev/null
+++ b/SOURCES/Add-ASN.1-encoders-and-decoders-for-SPAKE-types.patch
@@ -0,0 +1,866 @@
+From dff5177801444307d19071fc4fac7de864fda92a Mon Sep 17 00:00:00 2001
+From: Greg Hudson <ghudson@mit.edu>
+Date: Sat, 13 Jun 2015 16:04:53 -0400
+Subject: [PATCH] Add ASN.1 encoders and decoders for SPAKE types
+
+Add a new internal header k5-spake.h.  Add ASN.1 encoder and decoder
+functions and an internal free function for SPAKE types.  Add ASN.1
+tests and asn1c test vectors the new types.
+
+The additions to to make-vectors.c use C99 designated initializers in
+order to initialize unions.  This is okay since make-vectors.c is only
+compiled as part of "make test-vectors" and not as part of the regular
+build.
+
+(cherry picked from commit 78a09d95dff6915da4079bc611f4bb95f6a95f70)
+---
+ src/include/k5-spake.h               | 107 +++++++++++++++++++++++++++
+ src/lib/krb5/asn.1/asn1_k_encode.c   |  52 ++++++++++++-
+ src/lib/krb5/krb/kfree.c             |  40 ++++++++++
+ src/lib/krb5/libkrb5.exports         |   6 ++
+ src/tests/asn.1/Makefile.in          |   2 +-
+ src/tests/asn.1/krb5_decode_test.c   |  37 +++++++++
+ src/tests/asn.1/krb5_encode_test.c   |  29 ++++++++
+ src/tests/asn.1/ktest.c              |  97 ++++++++++++++++++++++++
+ src/tests/asn.1/ktest.h              |   9 +++
+ src/tests/asn.1/ktest_equal.c        |  49 ++++++++++++
+ src/tests/asn.1/ktest_equal.h        |   6 ++
+ src/tests/asn.1/make-vectors.c       |  56 ++++++++++++++
+ src/tests/asn.1/reference_encode.out |   6 ++
+ src/tests/asn.1/spake.asn1           |  44 +++++++++++
+ src/tests/asn.1/trval_reference.out  |  50 +++++++++++++
+ 15 files changed, 588 insertions(+), 2 deletions(-)
+ create mode 100644 src/include/k5-spake.h
+ create mode 100644 src/tests/asn.1/spake.asn1
+
+diff --git a/src/include/k5-spake.h b/src/include/k5-spake.h
+new file mode 100644
+index 000000000..ddb5d810d
+--- /dev/null
++++ b/src/include/k5-spake.h
+@@ -0,0 +1,107 @@
++/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
++/* include/k5-spake.h - SPAKE preauth mech declarations */
++/*
++ * Copyright (C) 2015 by the Massachusetts Institute of Technology.
++ * 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 SPAKE preauth mechanism allows long-term client keys to be used for
++ * preauthentication without exposing them to offline dictionary attacks.  The
++ * negotiated key can also be used for second-factor authentication.  This
++ * header file declares structures and encoder/decoder functions for the
++ * mechanism's padata messages.
++ */
++
++#ifndef K5_SPAKE_H
++#define K5_SPAKE_H
++
++#include "k5-int.h"
++
++/* SPAKESecondFactor is contained within a SPAKEChallenge, SPAKEResponse, or
++ * EncryptedData message and contains a second-factor challenge or response. */
++typedef struct krb5_spake_factor_st {
++    int32_t type;
++    krb5_data *data;
++} krb5_spake_factor;
++
++/* SPAKESupport is sent from the client to the KDC to indicate which group the
++ * client supports. */
++typedef struct krb5_spake_support_st {
++    int32_t ngroups;
++    int32_t *groups;
++} krb5_spake_support;
++
++/* SPAKEChallenge is sent from the KDC to the client to communicate its group
++ * selection, public value, and second-factor challenge options. */
++typedef struct krb5_spake_challenge_st {
++    int32_t group;
++    krb5_data pubkey;
++    krb5_spake_factor **factors;
++} krb5_spake_challenge;
++
++/* SPAKEResponse is sent from the client to the KDC to communicate its public
++ * value and encrypted second-factor response. */
++typedef struct krb5_spake_response_st {
++    krb5_data pubkey;
++    krb5_enc_data factor;
++} krb5_spake_response;
++
++enum krb5_spake_msgtype {
++    SPAKE_MSGTYPE_UNKNOWN = -1,
++    SPAKE_MSGTYPE_SUPPORT = 0,
++    SPAKE_MSGTYPE_CHALLENGE = 1,
++    SPAKE_MSGTYPE_RESPONSE = 2,
++    SPAKE_MSGTYPE_ENCDATA = 3
++};
++
++/* PA-SPAKE is a choice among the message types which can appear in a PA-SPAKE
++ * padata element. */
++typedef struct krb5_pa_spake_st {
++    enum krb5_spake_msgtype choice;
++    union krb5_spake_message_choices {
++        krb5_spake_support support;
++        krb5_spake_challenge challenge;
++        krb5_spake_response response;
++        krb5_enc_data encdata;
++    } u;
++} krb5_pa_spake;
++
++krb5_error_code encode_krb5_spake_factor(const krb5_spake_factor *val,
++                                         krb5_data **code_out);
++krb5_error_code decode_krb5_spake_factor(const krb5_data *code,
++                                         krb5_spake_factor **val_out);
++void k5_free_spake_factor(krb5_context context, krb5_spake_factor *val);
++
++krb5_error_code encode_krb5_pa_spake(const krb5_pa_spake *val,
++                                     krb5_data **code_out);
++krb5_error_code decode_krb5_pa_spake(const krb5_data *code,
++                                     krb5_pa_spake **val_out);
++void k5_free_pa_spake(krb5_context context, krb5_pa_spake *val);
++
++#endif /* K5_SPAKE_H */
+diff --git a/src/lib/krb5/asn.1/asn1_k_encode.c b/src/lib/krb5/asn.1/asn1_k_encode.c
+index 3b23fe34a..29f6b903d 100644
+--- a/src/lib/krb5/asn.1/asn1_k_encode.c
++++ b/src/lib/krb5/asn.1/asn1_k_encode.c
+@@ -25,7 +25,7 @@
+  */
+ 
+ #include "asn1_encode.h"
+-#include <assert.h>
++#include "k5-spake.h"
+ 
+ DEFINT_IMMEDIATE(krb5_version, KVNO, KRB5KDC_ERR_BAD_PVNO);
+ 
+@@ -1817,3 +1817,53 @@ static const struct atype_info *secure_cookie_fields[] = {
+ DEFSEQTYPE(secure_cookie, krb5_secure_cookie, secure_cookie_fields);
+ MAKE_ENCODER(encode_krb5_secure_cookie, secure_cookie);
+ MAKE_DECODER(decode_krb5_secure_cookie, secure_cookie);
++
++DEFFIELD(spake_factor_0, krb5_spake_factor, type, 0, int32);
++DEFFIELD(spake_factor_1, krb5_spake_factor, data, 1, opt_ostring_data_ptr);
++static const struct atype_info *spake_factor_fields[] = {
++    &k5_atype_spake_factor_0, &k5_atype_spake_factor_1
++};
++DEFSEQTYPE(spake_factor, krb5_spake_factor, spake_factor_fields);
++DEFPTRTYPE(spake_factor_ptr, spake_factor);
++DEFNULLTERMSEQOFTYPE(seqof_spake_factor, spake_factor_ptr);
++DEFPTRTYPE(ptr_seqof_spake_factor, seqof_spake_factor);
++MAKE_ENCODER(encode_krb5_spake_factor, spake_factor);
++MAKE_DECODER(decode_krb5_spake_factor, spake_factor);
++
++DEFCNFIELD(spake_support_0, krb5_spake_support, groups, ngroups, 0,
++           cseqof_int32);
++static const struct atype_info *spake_support_fields[] = {
++    &k5_atype_spake_support_0
++};
++DEFSEQTYPE(spake_support, krb5_spake_support, spake_support_fields);
++
++DEFFIELD(spake_challenge_0, krb5_spake_challenge, group, 0, int32);
++DEFFIELD(spake_challenge_1, krb5_spake_challenge, pubkey, 1, ostring_data);
++DEFFIELD(spake_challenge_2, krb5_spake_challenge, factors, 2,
++         ptr_seqof_spake_factor);
++static const struct atype_info *spake_challenge_fields[] = {
++    &k5_atype_spake_challenge_0, &k5_atype_spake_challenge_1,
++    &k5_atype_spake_challenge_2
++};
++DEFSEQTYPE(spake_challenge, krb5_spake_challenge, spake_challenge_fields);
++
++DEFFIELD(spake_response_0, krb5_spake_response, pubkey, 0, ostring_data);
++DEFFIELD(spake_response_1, krb5_spake_response, factor, 1, encrypted_data);
++static const struct atype_info *spake_response_fields[] = {
++    &k5_atype_spake_response_0, &k5_atype_spake_response_1,
++};
++DEFSEQTYPE(spake_response, krb5_spake_response, spake_response_fields);
++
++DEFCTAGGEDTYPE(pa_spake_0, 0, spake_support);
++DEFCTAGGEDTYPE(pa_spake_1, 1, spake_challenge);
++DEFCTAGGEDTYPE(pa_spake_2, 2, spake_response);
++DEFCTAGGEDTYPE(pa_spake_3, 3, encrypted_data);
++static const struct atype_info *pa_spake_alternatives[] = {
++    &k5_atype_pa_spake_0, &k5_atype_pa_spake_1, &k5_atype_pa_spake_2,
++    &k5_atype_pa_spake_3
++};
++DEFCHOICETYPE(pa_spake_choice, union krb5_spake_message_choices,
++              enum krb5_spake_msgtype, pa_spake_alternatives);
++DEFCOUNTEDTYPE_SIGNED(pa_spake, krb5_pa_spake, u, choice, pa_spake_choice);
++MAKE_ENCODER(encode_krb5_pa_spake, pa_spake);
++MAKE_DECODER(decode_krb5_pa_spake, pa_spake);
+diff --git a/src/lib/krb5/krb/kfree.c b/src/lib/krb5/krb/kfree.c
+index a631807d3..e1ea1494a 100644
+--- a/src/lib/krb5/krb/kfree.c
++++ b/src/lib/krb5/krb/kfree.c
+@@ -51,6 +51,7 @@
+  */
+ 
+ #include "k5-int.h"
++#include "k5-spake.h"
+ #include <assert.h>
+ 
+ void KRB5_CALLCONV
+@@ -890,3 +891,42 @@ k5_free_secure_cookie(krb5_context context, krb5_secure_cookie *val)
+     k5_zapfree_pa_data(val->data);
+     free(val);
+ }
++
++void
++k5_free_spake_factor(krb5_context context, krb5_spake_factor *val)
++{
++    if (val == NULL)
++        return;
++    krb5_free_data(context, val->data);
++    free(val);
++}
++
++void
++k5_free_pa_spake(krb5_context context, krb5_pa_spake *val)
++{
++    krb5_spake_factor **f;
++
++    if (val == NULL)
++        return;
++    switch (val->choice) {
++    case SPAKE_MSGTYPE_SUPPORT:
++        free(val->u.support.groups);
++        break;
++    case SPAKE_MSGTYPE_CHALLENGE:
++        krb5_free_data_contents(context, &val->u.challenge.pubkey);
++        for (f = val->u.challenge.factors; f != NULL && *f != NULL; f++)
++            k5_free_spake_factor(context, *f);
++        free(val->u.challenge.factors);
++        break;
++    case SPAKE_MSGTYPE_RESPONSE:
++        krb5_free_data_contents(context, &val->u.response.pubkey);
++        krb5_free_data_contents(context, &val->u.response.factor.ciphertext);
++        break;
++    case SPAKE_MSGTYPE_ENCDATA:
++        krb5_free_data_contents(context, &val->u.encdata.ciphertext);
++        break;
++    default:
++        break;
++    }
++    free(val);
++}
+diff --git a/src/lib/krb5/libkrb5.exports b/src/lib/krb5/libkrb5.exports
+index ed6cad6ad..622bc3673 100644
+--- a/src/lib/krb5/libkrb5.exports
++++ b/src/lib/krb5/libkrb5.exports
+@@ -36,6 +36,7 @@ decode_krb5_pa_otp_req
+ decode_krb5_pa_otp_enc_req
+ decode_krb5_pa_pac_req
+ decode_krb5_pa_s4u_x509_user
++decode_krb5_pa_spake
+ decode_krb5_padata_sequence
+ decode_krb5_priv
+ decode_krb5_safe
+@@ -44,6 +45,7 @@ decode_krb5_sam_challenge_2_body
+ decode_krb5_sam_response_2
+ decode_krb5_secure_cookie
+ decode_krb5_setpw_req
++decode_krb5_spake_factor
+ decode_krb5_tgs_rep
+ decode_krb5_tgs_req
+ decode_krb5_ticket
+@@ -85,6 +87,7 @@ encode_krb5_pa_otp_challenge
+ encode_krb5_pa_otp_req
+ encode_krb5_pa_otp_enc_req
+ encode_krb5_pa_s4u_x509_user
++encode_krb5_pa_spake
+ encode_krb5_padata_sequence
+ encode_krb5_pkinit_supp_pub_info
+ encode_krb5_priv
+@@ -95,6 +98,7 @@ encode_krb5_sam_challenge_2_body
+ encode_krb5_sam_response_2
+ encode_krb5_secure_cookie
+ encode_krb5_sp80056a_other_info
++encode_krb5_spake_factor
+ encode_krb5_tgs_rep
+ encode_krb5_tgs_req
+ encode_krb5_ticket
+@@ -128,7 +132,9 @@ k5_free_kkdcp_message
+ k5_free_pa_otp_challenge
+ k5_free_pa_otp_req
+ k5_free_secure_cookie
++k5_free_pa_spake
+ k5_free_serverlist
++k5_free_spake_factor
+ k5_hostrealm_free_context
+ k5_init_trace
+ k5_is_string_numeric
+diff --git a/src/tests/asn.1/Makefile.in b/src/tests/asn.1/Makefile.in
+index fec4e109e..ec9c67495 100644
+--- a/src/tests/asn.1/Makefile.in
++++ b/src/tests/asn.1/Makefile.in
+@@ -9,7 +9,7 @@ SRCS= $(srcdir)/krb5_encode_test.c $(srcdir)/krb5_decode_test.c \
+ 
+ ASN1SRCS= $(srcdir)/krb5.asn1 $(srcdir)/pkix.asn1 $(srcdir)/otp.asn1 \
+ 	$(srcdir)/pkinit.asn1 $(srcdir)/pkinit-agility.asn1 \
+-	$(srcdir)/cammac.asn1
++	$(srcdir)/cammac.asn1 $(srcdir)/spake.asn1
+ 
+ all: krb5_encode_test krb5_decode_test krb5_decode_leak t_trval
+ 
+diff --git a/src/tests/asn.1/krb5_decode_test.c b/src/tests/asn.1/krb5_decode_test.c
+index f17f9b1f1..ee70fa4b9 100644
+--- a/src/tests/asn.1/krb5_decode_test.c
++++ b/src/tests/asn.1/krb5_decode_test.c
+@@ -25,6 +25,7 @@
+  */
+ 
+ #include "k5-int.h"
++#include "k5-spake.h"
+ #include "ktest.h"
+ #include "com_err.h"
+ #include "utility.h"
+@@ -1107,6 +1108,42 @@ int main(argc, argv)
+         ktest_empty_secure_cookie(&ref);
+     }
+ 
++    /****************************************************************/
++    /* decode_krb5_spake_factor */
++    {
++        setup(krb5_spake_factor,ktest_make_minimal_spake_factor);
++        decode_run("spake_factor","(optionals NULL)","30 05 A0 03 02 01 01",decode_krb5_spake_factor,ktest_equal_spake_factor,k5_free_spake_factor);
++        ktest_empty_spake_factor(&ref);
++    }
++    {
++        setup(krb5_spake_factor,ktest_make_maximal_spake_factor);
++        decode_run("spake_factor","","30 0E A0 03 02 01 02 A1 07 04 05 66 64 61 74 61",decode_krb5_spake_factor,ktest_equal_spake_factor,k5_free_spake_factor);
++        ktest_empty_spake_factor(&ref);
++    }
++
++    /****************************************************************/
++    /* decode_krb5_pa_spake */
++    {
++        setup(krb5_pa_spake,ktest_make_support_pa_spake);
++        decode_run("pa_spake","(support)","A0 0C 30 0A A0 08 30 06 02 01 01 02 01 02",decode_krb5_pa_spake,ktest_equal_pa_spake,k5_free_pa_spake);
++        ktest_empty_pa_spake(&ref);
++    }
++    {
++        setup(krb5_pa_spake,ktest_make_challenge_pa_spake);
++        decode_run("pa_spake","(challenge)","A1 2D 30 2B A0 03 02 01 01 A1 09 04 07 54 20 76 61 6C 75 65 A2 19 30 17 30 05 A0 03 02 01 01 30 0E A0 03 02 01 02 A1 07 04 05 66 64 61 74 61",decode_krb5_pa_spake,ktest_equal_pa_spake,k5_free_pa_spake);
++        ktest_empty_pa_spake(&ref);
++    }
++    {
++        setup(krb5_pa_spake,ktest_make_response_pa_spake);
++        decode_run("pa_spake","(response)","A2 34 30 32 A0 09 04 07 53 20 76 61 6C 75 65 A1 25 30 23 A0 03 02 01 00 A1 03 02 01 05 A2 17 04 15 6B 72 62 41 53 4E 2E 31 20 74 65 73 74 20 6D 65 73 73 61 67 65",decode_krb5_pa_spake,ktest_equal_pa_spake,k5_free_pa_spake);
++        ktest_empty_pa_spake(&ref);
++    }
++    {
++        setup(krb5_pa_spake,ktest_make_encdata_pa_spake);
++        decode_run("pa_spake","(encdata)","A3 25 30 23 A0 03 02 01 00 A1 03 02 01 05 A2 17 04 15 6B 72 62 41 53 4E 2E 31 20 74 65 73 74 20 6D 65 73 73 61 67 65",decode_krb5_pa_spake,ktest_equal_pa_spake,k5_free_pa_spake);
++        ktest_empty_pa_spake(&ref);
++    }
++
+ #ifndef DISABLE_PKINIT
+ 
+     /****************************************************************/
+diff --git a/src/tests/asn.1/krb5_encode_test.c b/src/tests/asn.1/krb5_encode_test.c
+index f5710b68c..3efbfb4c0 100644
+--- a/src/tests/asn.1/krb5_encode_test.c
++++ b/src/tests/asn.1/krb5_encode_test.c
+@@ -759,6 +759,35 @@ main(argc, argv)
+         encode_run(cookie, "secure_cookie", "", encode_krb5_secure_cookie);
+         ktest_empty_secure_cookie(&cookie);
+     }
++    /****************************************************************/
++    /* encode_krb5_spake_factor */
++    {
++        krb5_spake_factor factor;
++        ktest_make_minimal_spake_factor(&factor);
++        encode_run(factor, "spake_factor", "(optionals NULL)",
++                   encode_krb5_spake_factor);
++        ktest_empty_spake_factor(&factor);
++        ktest_make_maximal_spake_factor(&factor);
++        encode_run(factor, "spake_factor", "", encode_krb5_spake_factor);
++        ktest_empty_spake_factor(&factor);
++    }
++    /****************************************************************/
++    /* encode_krb5_pa_spake */
++    {
++        krb5_pa_spake pa_spake;
++        ktest_make_support_pa_spake(&pa_spake);
++        encode_run(pa_spake, "pa_spake", "(support)", encode_krb5_pa_spake);
++        ktest_empty_pa_spake(&pa_spake);
++        ktest_make_challenge_pa_spake(&pa_spake);
++        encode_run(pa_spake, "pa_spake", "(challenge)", encode_krb5_pa_spake);
++        ktest_empty_pa_spake(&pa_spake);
++        ktest_make_response_pa_spake(&pa_spake);
++        encode_run(pa_spake, "pa_spake", "(response)", encode_krb5_pa_spake);
++        ktest_empty_pa_spake(&pa_spake);
++        ktest_make_encdata_pa_spake(&pa_spake);
++        encode_run(pa_spake, "pa_spake", "(encdata)", encode_krb5_pa_spake);
++        ktest_empty_pa_spake(&pa_spake);
++    }
+ #ifndef DISABLE_PKINIT
+     /****************************************************************/
+     /* encode_krb5_pa_pk_as_req */
+diff --git a/src/tests/asn.1/ktest.c b/src/tests/asn.1/ktest.c
+index cf63f3f66..5bfdc5be2 100644
+--- a/src/tests/asn.1/ktest.c
++++ b/src/tests/asn.1/ktest.c
+@@ -1018,6 +1018,66 @@ ktest_make_sample_secure_cookie(krb5_secure_cookie *p)
+     p->time = SAMPLE_TIME;
+ }
+ 
++void
++ktest_make_minimal_spake_factor(krb5_spake_factor *p)
++{
++    p->type = 1;
++    p->data = NULL;
++}
++
++void
++ktest_make_maximal_spake_factor(krb5_spake_factor *p)
++{
++    p->type = 2;
++    p->data = ealloc(sizeof(*p->data));
++    krb5_data_parse(p->data, "fdata");
++}
++
++void
++ktest_make_support_pa_spake(krb5_pa_spake *p)
++{
++    krb5_spake_support *s = &p->u.support;
++
++    s->ngroups = 2;
++    s->groups = ealloc(s->ngroups * sizeof(*s->groups));
++    s->groups[0] = 1;
++    s->groups[1] = 2;
++    p->choice = SPAKE_MSGTYPE_SUPPORT;
++}
++
++void
++ktest_make_challenge_pa_spake(krb5_pa_spake *p)
++{
++    krb5_spake_challenge *c = &p->u.challenge;
++
++    c->group = 1;
++    krb5_data_parse(&c->pubkey, "T value");
++    c->factors = ealloc(3 * sizeof(*c->factors));
++    c->factors[0] = ealloc(sizeof(*c->factors[0]));
++    ktest_make_minimal_spake_factor(c->factors[0]);
++    c->factors[1] = ealloc(sizeof(*c->factors[1]));
++    ktest_make_maximal_spake_factor(c->factors[1]);
++    c->factors[2] = NULL;
++    p->choice = SPAKE_MSGTYPE_CHALLENGE;
++}
++
++void
++ktest_make_response_pa_spake(krb5_pa_spake *p)
++{
++    krb5_spake_response *r = &p->u.response;
++
++    krb5_data_parse(&r->pubkey, "S value");
++    ktest_make_sample_enc_data(&r->factor);
++    p->choice = SPAKE_MSGTYPE_RESPONSE;
++}
++
++void
++ktest_make_encdata_pa_spake(krb5_pa_spake *p)
++{
++    ktest_make_sample_enc_data(&p->u.encdata);
++    p->choice = SPAKE_MSGTYPE_ENCDATA;
++}
++
+ /****************************************************************/
+ /* destructors */
+ 
+@@ -1858,3 +1918,40 @@ ktest_empty_secure_cookie(krb5_secure_cookie *p)
+ {
+     ktest_empty_pa_data_array(p->data);
+ }
++
++void
++ktest_empty_spake_factor(krb5_spake_factor *p)
++{
++    krb5_free_data(NULL, p->data);
++    p->data = NULL;
++}
++
++void
++ktest_empty_pa_spake(krb5_pa_spake *p)
++{
++    krb5_spake_factor **f;
++
++    switch (p->choice) {
++    case SPAKE_MSGTYPE_SUPPORT:
++        free(p->u.support.groups);
++        break;
++    case SPAKE_MSGTYPE_CHALLENGE:
++        ktest_empty_data(&p->u.challenge.pubkey);
++        for (f = p->u.challenge.factors; *f != NULL; f++) {
++            ktest_empty_spake_factor(*f);
++            free(*f);
++        }
++        free(p->u.challenge.factors);
++        break;
++    case SPAKE_MSGTYPE_RESPONSE:
++        ktest_empty_data(&p->u.response.pubkey);
++        ktest_destroy_enc_data(&p->u.response.factor);
++        break;
++    case SPAKE_MSGTYPE_ENCDATA:
++        ktest_destroy_enc_data(&p->u.encdata);
++        break;
++    default:
++        break;
++    }
++    p->choice = SPAKE_MSGTYPE_UNKNOWN;
++}
+diff --git a/src/tests/asn.1/ktest.h b/src/tests/asn.1/ktest.h
+index 493303cc8..1413cfae1 100644
+--- a/src/tests/asn.1/ktest.h
++++ b/src/tests/asn.1/ktest.h
+@@ -28,6 +28,7 @@
+ #define __KTEST_H__
+ 
+ #include "k5-int.h"
++#include "k5-spake.h"
+ #include "kdb.h"
+ 
+ #define SAMPLE_USEC 123456
+@@ -124,6 +125,12 @@ void ktest_make_sample_kkdcp_message(krb5_kkdcp_message *p);
+ void ktest_make_minimal_cammac(krb5_cammac *p);
+ void ktest_make_maximal_cammac(krb5_cammac *p);
+ void ktest_make_sample_secure_cookie(krb5_secure_cookie *p);
++void ktest_make_minimal_spake_factor(krb5_spake_factor *p);
++void ktest_make_maximal_spake_factor(krb5_spake_factor *p);
++void ktest_make_support_pa_spake(krb5_pa_spake *p);
++void ktest_make_challenge_pa_spake(krb5_pa_spake *p);
++void ktest_make_response_pa_spake(krb5_pa_spake *p);
++void ktest_make_encdata_pa_spake(krb5_pa_spake *p);
+ 
+ /*----------------------------------------------------------------------*/
+ 
+@@ -209,6 +216,8 @@ void ktest_empty_ldap_seqof_key_data(krb5_context, ldap_seqof_key_data *p);
+ void ktest_empty_kkdcp_message(krb5_kkdcp_message *p);
+ void ktest_empty_cammac(krb5_cammac *p);
+ void ktest_empty_secure_cookie(krb5_secure_cookie *p);
++void ktest_empty_spake_factor(krb5_spake_factor *p);
++void ktest_empty_pa_spake(krb5_pa_spake *p);
+ 
+ extern krb5_context test_context;
+ extern char *sample_principal_name;
+diff --git a/src/tests/asn.1/ktest_equal.c b/src/tests/asn.1/ktest_equal.c
+index e8bb88944..714cc4398 100644
+--- a/src/tests/asn.1/ktest_equal.c
++++ b/src/tests/asn.1/ktest_equal.c
+@@ -853,6 +853,13 @@ ktest_equal_sequence_of_otp_tokeninfo(krb5_otp_tokeninfo **ref,
+     array_compare(ktest_equal_otp_tokeninfo);
+ }
+ 
++int
++ktest_equal_sequence_of_spake_factor(krb5_spake_factor **ref,
++                                     krb5_spake_factor **var)
++{
++    array_compare(ktest_equal_spake_factor);
++}
++
+ #ifndef DISABLE_PKINIT
+ 
+ static int
+@@ -1094,3 +1101,45 @@ ktest_equal_secure_cookie(krb5_secure_cookie *ref, krb5_secure_cookie *var)
+     p = p && ref->time == ref->time;
+     return p;
+ }
++
++int
++ktest_equal_spake_factor(krb5_spake_factor *ref, krb5_spake_factor *var)
++{
++    int p = TRUE;
++    if (ref == var) return TRUE;
++    else if (ref == NULL || var == NULL) return FALSE;
++    p = p && scalar_equal(type);
++    p = p && ptr_equal(data,ktest_equal_data);
++    return p;
++}
++
++int
++ktest_equal_pa_spake(krb5_pa_spake *ref, krb5_pa_spake *var)
++{
++    int p = TRUE;
++    if (ref == var) return TRUE;
++    else if (ref == NULL || var == NULL) return FALSE;
++    else if (ref->choice != var->choice) return FALSE;
++    switch (ref->choice) {
++    case SPAKE_MSGTYPE_SUPPORT:
++        p = p && scalar_equal(u.support.ngroups);
++        p = p && (memcmp(ref->u.support.groups,var->u.support.groups,
++                         ref->u.support.ngroups * sizeof(int32_t)) == 0);
++        break;
++    case SPAKE_MSGTYPE_CHALLENGE:
++        p = p && struct_equal(u.challenge.pubkey,ktest_equal_data);
++        p = p && ptr_equal(u.challenge.factors,
++                           ktest_equal_sequence_of_spake_factor);
++        break;
++    case SPAKE_MSGTYPE_RESPONSE:
++        p = p && struct_equal(u.response.pubkey,ktest_equal_data);
++        p = p && struct_equal(u.response.factor,ktest_equal_enc_data);
++        break;
++    case SPAKE_MSGTYPE_ENCDATA:
++        p = p && struct_equal(u.encdata,ktest_equal_enc_data);
++        break;
++    default:
++        break;
++    }
++    return p;
++}
+diff --git a/src/tests/asn.1/ktest_equal.h b/src/tests/asn.1/ktest_equal.h
+index c7b5d7467..cfa82ac6e 100644
+--- a/src/tests/asn.1/ktest_equal.h
++++ b/src/tests/asn.1/ktest_equal.h
+@@ -28,6 +28,7 @@
+ #define __KTEST_EQUAL_H__
+ 
+ #include "k5-int.h"
++#include "k5-spake.h"
+ #include "kdb.h"
+ 
+ /* int ktest_equal_structure(krb5_structure *ref, *var) */
+@@ -97,6 +98,8 @@ ktest_equal_sequence_of_algorithm_identifier(krb5_algorithm_identifier **ref,
+                                              krb5_algorithm_identifier **var);
+ int ktest_equal_sequence_of_otp_tokeninfo(krb5_otp_tokeninfo **ref,
+                                           krb5_otp_tokeninfo **var);
++int ktest_equal_sequence_of_spake_factor(krb5_spake_factor **ref,
++                                         krb5_spake_factor **var);
+ 
+ len_array(ktest_equal_array_of_enctype,krb5_enctype);
+ len_array(ktest_equal_array_of_data,krb5_data);
+@@ -152,4 +155,7 @@ int ktest_equal_cammac(krb5_cammac *ref, krb5_cammac *var);
+ int ktest_equal_secure_cookie(krb5_secure_cookie *ref,
+                               krb5_secure_cookie *var);
+ 
++generic(ktest_equal_spake_factor, krb5_spake_factor);
++generic(ktest_equal_pa_spake, krb5_pa_spake);
++
+ #endif
+diff --git a/src/tests/asn.1/make-vectors.c b/src/tests/asn.1/make-vectors.c
+index 3cb8a45ba..2fc85466b 100644
+--- a/src/tests/asn.1/make-vectors.c
++++ b/src/tests/asn.1/make-vectors.c
+@@ -40,6 +40,8 @@
+ #include <PA-OTP-REQUEST.h>
+ #include <PA-OTP-ENC-REQUEST.h>
+ #include <AD-CAMMAC.h>
++#include <SPAKESecondFactor.h>
++#include <PA-SPAKE.h>
+ 
+ static unsigned char buf[8192];
+ static size_t buf_pos;
+@@ -168,6 +170,36 @@ static struct other_verifiers overfs = { { verifiers, 2, 2 } };
+ static AD_CAMMAC_t cammac_2 = { { { (void *)adlist_2, 2, 2 } },
+                                 &vmac_1, &vmac_2, &overfs };
+ 
++/* SPAKESecondFactor */
++static SPAKESecondFactor_t factor_1 = { 1, NULL };
++static OCTET_STRING_t factor_data = { "fdata", 5 };
++static SPAKESecondFactor_t factor_2 = { 2, &factor_data };
++
++/* PA-SPAKE (support) */
++static Int32_t group_1 = 1, group_2 = 2, *groups[] = { &group_1, &group_2 };
++static PA_SPAKE_t pa_spake_1 = { PA_SPAKE_PR_support,
++                                 { .support = { { groups, 2, 2 } } } };
++
++/* PA-SPAKE (challenge) */
++static SPAKESecondFactor_t *factors[2] = { &factor_1, &factor_2 };
++static PA_SPAKE_t pa_spake_2 = { PA_SPAKE_PR_challenge,
++                                 { .challenge = { 1, { "T value", 7 },
++                                                  { factors, 2, 2 } } } };
++
++/* PA-SPAKE (response) */
++UInt32_t enctype_5 = 5;
++static PA_SPAKE_t pa_spake_3 = { PA_SPAKE_PR_response,
++                                 { .response = { { "S value", 7 },
++                                                 { 0, &enctype_5,
++                                                   { "krbASN.1 test message",
++                                                     21 } } } } };
++
++/* PA-SPAKE (encdata) */
++static PA_SPAKE_t pa_spake_4 = { PA_SPAKE_PR_encdata,
++                                 { .encdata = { 0, &enctype_5,
++                                                { "krbASN.1 test message",
++                                                  21 } } } };
++
+ static int
+ consume(const void *data, size_t size, void *dummy)
+ {
+@@ -272,6 +304,30 @@ main()
+     der_encode(&asn_DEF_AD_CAMMAC, &cammac_2, consume, NULL);
+     printbuf();
+ 
++    printf("\nMinimal SPAKESecondFactor:\n");
++    der_encode(&asn_DEF_SPAKESecondFactor, &factor_1, consume, NULL);
++    printbuf();
++
++    printf("\nMaximal SPAKESecondFactor:\n");
++    der_encode(&asn_DEF_SPAKESecondFactor, &factor_2, consume, NULL);
++    printbuf();
++
++    printf("\nPA-SPAKE (support):\n");
++    der_encode(&asn_DEF_PA_SPAKE, &pa_spake_1, consume, NULL);
++    printbuf();
++
++    printf("\nPA-SPAKE (challenge):\n");
++    der_encode(&asn_DEF_PA_SPAKE, &pa_spake_2, consume, NULL);
++    printbuf();
++
++    printf("\nPA-SPAKE (response):\n");
++    der_encode(&asn_DEF_PA_SPAKE, &pa_spake_3, consume, NULL);
++    printbuf();
++
++    printf("\nPA-SPAKE (encdata):\n");
++    der_encode(&asn_DEF_PA_SPAKE, &pa_spake_4, consume, NULL);
++    printbuf();
++
+     printf("\n");
+     return 0;
+ }
+diff --git a/src/tests/asn.1/reference_encode.out b/src/tests/asn.1/reference_encode.out
+index 824e0798b..a76deead2 100644
+--- a/src/tests/asn.1/reference_encode.out
++++ b/src/tests/asn.1/reference_encode.out
+@@ -72,3 +72,9 @@ encode_krb5_kkdcp_message: 30 82 01 FC A0 82 01 EC 04 82 01 E8 6A 82 01 E4 30 82
+ encode_krb5_cammac(optionals NULL): 30 12 A0 10 30 0E 30 0C A0 03 02 01 01 A1 05 04 03 61 64 31
+ encode_krb5_cammac: 30 81 F2 A0 1E 30 1C 30 0C A0 03 02 01 01 A1 05 04 03 61 64 31 30 0C A0 03 02 01 02 A1 05 04 03 61 64 32 A1 3D 30 3B A0 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 03 02 01 05 A2 03 02 01 10 A3 13 30 11 A0 03 02 01 01 A1 0A 04 08 63 6B 73 75 6D 6B 64 63 A2 3D 30 3B A0 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 03 02 01 05 A2 03 02 01 10 A3 13 30 11 A0 03 02 01 01 A1 0A 04 08 63 6B 73 75 6D 73 76 63 A3 52 30 50 30 13 A3 11 30 0F A0 03 02 01 01 A1 08 04 06 63 6B 73 75 6D 31 30 39 A0 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 03 02 01 05 A2 03 02 01 10 A3 11 30 0F A0 03 02 01 01 A1 08 04 06 63 6B 73 75 6D 32
+ encode_krb5_secure_cookie: 30 2C 02 04 2D F8 02 25 30 24 30 10 A1 03 02 01 0D A2 09 04 07 70 61 2D 64 61 74 61 30 10 A1 03 02 01 0D A2 09 04 07 70 61 2D 64 61 74 61
++encode_krb5_spake_factor(optionals NULL): 30 05 A0 03 02 01 01
++encode_krb5_spake_factor: 30 0E A0 03 02 01 02 A1 07 04 05 66 64 61 74 61
++encode_krb5_pa_spake(support): A0 0C 30 0A A0 08 30 06 02 01 01 02 01 02
++encode_krb5_pa_spake(challenge): A1 2D 30 2B A0 03 02 01 01 A1 09 04 07 54 20 76 61 6C 75 65 A2 19 30 17 30 05 A0 03 02 01 01 30 0E A0 03 02 01 02 A1 07 04 05 66 64 61 74 61
++encode_krb5_pa_spake(response): A2 34 30 32 A0 09 04 07 53 20 76 61 6C 75 65 A1 25 30 23 A0 03 02 01 00 A1 03 02 01 05 A2 17 04 15 6B 72 62 41 53 4E 2E 31 20 74 65 73 74 20 6D 65 73 73 61 67 65
++encode_krb5_pa_spake(encdata): A3 25 30 23 A0 03 02 01 00 A1 03 02 01 05 A2 17 04 15 6B 72 62 41 53 4E 2E 31 20 74 65 73 74 20 6D 65 73 73 61 67 65
+diff --git a/src/tests/asn.1/spake.asn1 b/src/tests/asn.1/spake.asn1
+new file mode 100644
+index 000000000..50718d8ad
+--- /dev/null
++++ b/src/tests/asn.1/spake.asn1
+@@ -0,0 +1,44 @@
++KerberosV5SPAKE {
++        iso(1) identified-organization(3) dod(6) internet(1)
++        security(5) kerberosV5(2) modules(4) spake(8)
++} DEFINITIONS EXPLICIT TAGS ::= BEGIN
++
++IMPORTS
++    EncryptedData, Int32
++      FROM KerberosV5Spec2 { iso(1) identified-organization(3)
++        dod(6) internet(1) security(5) kerberosV5(2) modules(4)
++        krb5spec2(2) };
++        -- as defined in RFC 4120.
++
++SPAKESupport ::= SEQUENCE {
++    groups      [0] SEQUENCE (SIZE(1..MAX)) OF Int32,
++    ...
++}
++
++SPAKEChallenge ::= SEQUENCE {
++    group       [0] Int32,
++    pubkey      [1] OCTET STRING,
++    factors     [2] SEQUENCE (SIZE(1..MAX)) OF SPAKESecondFactor,
++    ...
++}
++
++SPAKESecondFactor ::= SEQUENCE {
++    type        [0] Int32,
++    data        [1] OCTET STRING OPTIONAL
++}
++
++SPAKEResponse ::= SEQUENCE {
++    pubkey      [0] OCTET STRING,
++    factor      [1] EncryptedData, -- SPAKESecondFactor
++    ...
++}
++
++PA-SPAKE ::= CHOICE {
++    support     [0] SPAKESupport,
++    challenge   [1] SPAKEChallenge,
++    response    [2] SPAKEResponse,
++    encdata     [3] EncryptedData,
++    ...
++}
++
++END
+diff --git a/src/tests/asn.1/trval_reference.out b/src/tests/asn.1/trval_reference.out
+index c27a0425b..e5c715924 100644
+--- a/src/tests/asn.1/trval_reference.out
++++ b/src/tests/asn.1/trval_reference.out
+@@ -1584,3 +1584,53 @@ encode_krb5_secure_cookie:
+ .  .  [Sequence/Sequence Of]
+ .  .  .  [1] [Integer] 13
+ .  .  .  [2] [Octet String] "pa-data"
++
++encode_krb5_spake_factor(optionals NULL):
++
++[Sequence/Sequence Of]
++.  [0] [Integer] 1
++
++encode_krb5_spake_factor:
++
++[Sequence/Sequence Of]
++.  [0] [Integer] 2
++.  [1] [Octet String] "fdata"
++
++encode_krb5_pa_spake(support):
++
++[CONT 0]
++.  [Sequence/Sequence Of]
++.  .  [0] [Sequence/Sequence Of]
++.  .  .  [Integer] 1
++.  .  .  [Integer] 2
++
++encode_krb5_pa_spake(challenge):
++
++[CONT 1]
++.  [Sequence/Sequence Of]
++.  .  [0] [Integer] 1
++.  .  [1] [Octet String] "T value"
++.  .  [2] [Sequence/Sequence Of]
++.  .  .  [Sequence/Sequence Of]
++.  .  .  .  [0] [Integer] 1
++.  .  .  [Sequence/Sequence Of]
++.  .  .  .  [0] [Integer] 2
++.  .  .  .  [1] [Octet String] "fdata"
++
++encode_krb5_pa_spake(response):
++
++[CONT 2]
++.  [Sequence/Sequence Of]
++.  .  [0] [Octet String] "S value"
++.  .  [1] [Sequence/Sequence Of]
++.  .  .  [0] [Integer] 0
++.  .  .  [1] [Integer] 5
++.  .  .  [2] [Octet String] "krbASN.1 test message"
++
++encode_krb5_pa_spake(encdata):
++
++[CONT 3]
++.  [Sequence/Sequence Of]
++.  .  [0] [Integer] 0
++.  .  [1] [Integer] 5
++.  .  [2] [Octet String] "krbASN.1 test message"
diff --git a/SOURCES/Add-PKINIT-KDC-support-for-freshness-token.patch b/SOURCES/Add-PKINIT-KDC-support-for-freshness-token.patch
new file mode 100644
index 0000000..70782fb
--- /dev/null
+++ b/SOURCES/Add-PKINIT-KDC-support-for-freshness-token.patch
@@ -0,0 +1,631 @@
+From c93112a19f73b9a984cabd320129ee8f70cb4823 Mon Sep 17 00:00:00 2001
+From: Greg Hudson <ghudson@mit.edu>
+Date: Mon, 12 Mar 2018 11:31:46 -0400
+Subject: [PATCH] Add PKINIT KDC support for freshness token
+
+Send a freshness token in the preauth hint list if PKINIT is
+configured and the request padata indicates support.  Verify the
+freshness token if the client includes one in a PKINIT request, and
+log whether one was received.  If pkinit_require_freshness is set to
+true in the realm config, reject non-anonymous requests which don't
+contain a freshness token.
+
+Add freshness token tests to t_pkinit.py with some related changes.
+Remove client long-term keys after testing password preauth so we get
+better error reporting when pkinit_require_freshness is set and a
+token is not sent.  Remove ./responder invocations for test cases
+which don't ask PKINIT responder questions, or else the responder
+would fail now that it isn't being asked for the password.  Leave
+anonymous PKINIT enabled after the anonymous tests so that we can use
+it again when testing enforcement of pkinit_require_freshness.  Add
+expected trace messages for the basic test, including one for
+receiving a freshness token.  Add minimal expected trace messages for
+the RSA test.
+
+ticket: 8648
+(cherry picked from commit 4a9050df0bc34bfb08ba24462d6e2514640f4b8e)
+---
+ doc/admin/conf_files/kdc_conf.rst       |   4 +
+ doc/admin/pkinit.rst                    |  25 +++++
+ doc/appdev/refs/macros/index.rst        |   2 +
+ doc/formats/freshness_token.rst         |  19 ++++
+ doc/formats/index.rst                   |   1 +
+ src/include/krb5/kdcpreauth_plugin.h    |  17 ++++
+ src/include/krb5/krb5.hin               |   3 +
+ src/kdc/do_as_req.c                     |   2 +
+ src/kdc/kdc_preauth.c                   | 130 +++++++++++++++++++++++-
+ src/kdc/kdc_util.h                      |   2 +
+ src/plugins/preauth/pkinit/pkinit.h     |   2 +
+ src/plugins/preauth/pkinit/pkinit_srv.c |  51 +++++++++-
+ src/tests/t_pkinit.py                   |  50 ++++++---
+ 13 files changed, 292 insertions(+), 16 deletions(-)
+ create mode 100644 doc/formats/freshness_token.rst
+
+diff --git a/doc/admin/conf_files/kdc_conf.rst b/doc/admin/conf_files/kdc_conf.rst
+index 3af1c3796..1ac1a37c2 100644
+--- a/doc/admin/conf_files/kdc_conf.rst
++++ b/doc/admin/conf_files/kdc_conf.rst
+@@ -798,6 +798,10 @@ For information about the syntax of some of these options, see
+     **pkinit_require_crl_checking** should be set to true if the
+     policy is such that up-to-date CRLs must be present for every CA.
+ 
++**pkinit_require_freshness**
++    Specifies whether to require clients to include a freshness token
++    in PKINIT requests.  The default value is false.  (New in release
++    1.17.)
+ 
+ .. _Encryption_types:
+ 
+diff --git a/doc/admin/pkinit.rst b/doc/admin/pkinit.rst
+index c601c5c9e..bec4fc800 100644
+--- a/doc/admin/pkinit.rst
++++ b/doc/admin/pkinit.rst
+@@ -327,3 +327,28 @@ appropriate :ref:`kdc_realms` subsection of the KDC's
+ To obtain anonymous credentials on a client, run ``kinit -n``, or
+ ``kinit -n @REALMNAME`` to specify a realm.  The resulting tickets
+ will have the client name ``WELLKNOWN/ANONYMOUS@WELLKNOWN:ANONYMOUS``.
++
++
++Freshness tokens
++----------------
++
++Freshness tokens can ensure that the client has recently had access to
++its certificate private key.  If freshness tokens are not required by
++the KDC, a client program with temporary possession of the private key
++can compose requests for future timestamps and use them later.
++
++In release 1.17 and later, freshness tokens are supported by the
++client and are sent by the KDC when the client indicates support for
++them.  Because not all clients support freshness tokens yet, they are
++not required by default.  To check if freshness tokens are supported
++by a realm's clients, look in the KDC logs for the lines::
++
++    PKINIT: freshness token received from <client principal>
++    PKINIT: no freshness token received from <client principal>
++
++To require freshness tokens for all clients in a realm (except for
++clients authenticating anonymously), set the
++**pkinit_require_freshness** variable to ``true`` in the appropriate
++:ref:`kdc_realms` subsection of the KDC's :ref:`kdc.conf(5)` file.  To
++test that this option is in effect, run ``kinit -X disable_freshness``
++and verify that authentication is unsuccessful.
+diff --git a/doc/appdev/refs/macros/index.rst b/doc/appdev/refs/macros/index.rst
+index e76747102..dba818b26 100644
+--- a/doc/appdev/refs/macros/index.rst
++++ b/doc/appdev/refs/macros/index.rst
+@@ -181,6 +181,7 @@ Public
+    KRB5_KEYUSAGE_KRB_ERROR_CKSUM.rst
+    KRB5_KEYUSAGE_KRB_PRIV_ENCPART.rst
+    KRB5_KEYUSAGE_KRB_SAFE_CKSUM.rst
++   KRB5_KEYUSAGE_PA_AS_FRESHNESS.rst
+    KRB5_KEYUSAGE_PA_FX_COOKIE.rst
+    KRB5_KEYUSAGE_PA_OTP_REQUEST.rst
+    KRB5_KEYUSAGE_PA_PKINIT_KX.rst
+@@ -241,6 +242,7 @@ Public
+    KRB5_PADATA_AFS3_SALT.rst
+    KRB5_PADATA_AP_REQ.rst
+    KRB5_PADATA_AS_CHECKSUM.rst
++   KRB5_PADATA_AS_FRESHNESS.rst
+    KRB5_PADATA_ENCRYPTED_CHALLENGE.rst
+    KRB5_PADATA_ENC_SANDIA_SECURID.rst
+    KRB5_PADATA_ENC_TIMESTAMP.rst
+diff --git a/doc/formats/freshness_token.rst b/doc/formats/freshness_token.rst
+new file mode 100644
+index 000000000..3127621a9
+--- /dev/null
++++ b/doc/formats/freshness_token.rst
+@@ -0,0 +1,19 @@
++PKINIT freshness tokens
++=======================
++
++:rfc:`8070` specifies a pa-data type PA_AS_FRESHNESS, which clients
++should reflect within signed PKINIT data to prove recent access to the
++client certificate private key.  The contents of a freshness token are
++left to the KDC implementation.  The MIT krb5 KDC uses the following
++format for freshness tokens (starting in release 1.17):
++
++* a four-byte big-endian POSIX timestamp
++* a four-byte big-endian key version number
++* an :rfc:`3961` checksum, with no ASN.1 wrapper
++
++The checksum is computed using the first key in the local krbtgt
++principal entry for the realm (e.g. ``krbtgt/KRBTEST.COM@KRBTEST.COM``
++if the request is to the ``KRBTEST.COM`` realm) of the indicated key
++version.  The checksum type must be the mandatory checksum type for
++the encryption type of the krbtgt key.  The key usage value for the
++checksum is 514.
+diff --git a/doc/formats/index.rst b/doc/formats/index.rst
+index 8b30626d4..4ad534424 100644
+--- a/doc/formats/index.rst
++++ b/doc/formats/index.rst
+@@ -7,3 +7,4 @@ Protocols and file formats
+    ccache_file_format
+    keytab_file_format
+    cookie
++   freshness_token
+diff --git a/src/include/krb5/kdcpreauth_plugin.h b/src/include/krb5/kdcpreauth_plugin.h
+index f38820099..3a4754234 100644
+--- a/src/include/krb5/kdcpreauth_plugin.h
++++ b/src/include/krb5/kdcpreauth_plugin.h
+@@ -240,6 +240,23 @@ typedef struct krb5_kdcpreauth_callbacks_st {
+ 
+     /* End of version 4 kdcpreauth callbacks. */
+ 
++    /*
++     * Instruct the KDC to send a freshness token in the method data
++     * accompanying a PREAUTH_REQUIRED or PREAUTH_FAILED error, if the client
++     * indicated support for freshness tokens.  This callback should only be
++     * invoked from the edata method.
++     */
++    void (*send_freshness_token)(krb5_context context,
++                                 krb5_kdcpreauth_rock rock);
++
++    /* Validate a freshness token sent by the client.  Return 0 on success,
++     * KRB5KDC_ERR_PREAUTH_EXPIRED on error. */
++    krb5_error_code (*check_freshness_token)(krb5_context context,
++                                             krb5_kdcpreauth_rock rock,
++                                             const krb5_data *token);
++
++    /* End of version 5 kdcpreauth callbacks. */
++
+ } *krb5_kdcpreauth_callbacks;
+ 
+ /* Optional: preauth plugin initialization function. */
+diff --git a/src/include/krb5/krb5.hin b/src/include/krb5/krb5.hin
+index 833e72335..a650ecece 100644
+--- a/src/include/krb5/krb5.hin
++++ b/src/include/krb5/krb5.hin
+@@ -1035,7 +1035,10 @@ krb5_c_keyed_checksum_types(krb5_context context, krb5_enctype enctype,
+ #define KRB5_KEYUSAGE_AS_REQ 56
+ #define KRB5_KEYUSAGE_CAMMAC 64
+ 
++/* Key usage values 512-1023 are reserved for uses internal to a Kerberos
++ * implementation. */
+ #define KRB5_KEYUSAGE_PA_FX_COOKIE 513  /**< Used for encrypted FAST cookies */
++#define KRB5_KEYUSAGE_PA_AS_FRESHNESS 514  /**< Used for freshness tokens */
+ /** @} */ /* end of KRB5_KEYUSAGE group */
+ 
+ /**
+diff --git a/src/kdc/do_as_req.c b/src/kdc/do_as_req.c
+index 7c8da63e1..588c1375a 100644
+--- a/src/kdc/do_as_req.c
++++ b/src/kdc/do_as_req.c
+@@ -563,6 +563,7 @@ process_as_req(krb5_kdc_req *request, krb5_data *req_pkt,
+     state->rock.rstate = state->rstate;
+     state->rock.vctx = vctx;
+     state->rock.auth_indicators = &state->auth_indicators;
++    state->rock.send_freshness_token = FALSE;
+     if (!state->request->client) {
+         state->status = "NULL_CLIENT";
+         errcode = KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN;
+@@ -659,6 +660,7 @@ process_as_req(krb5_kdc_req *request, krb5_data *req_pkt,
+         state->status = "GET_LOCAL_TGT";
+         goto errout;
+     }
++    state->rock.local_tgt = state->local_tgt;
+ 
+     au_state->stage = VALIDATE_POL;
+ 
+diff --git a/src/kdc/kdc_preauth.c b/src/kdc/kdc_preauth.c
+index 6f34dc289..80b130222 100644
+--- a/src/kdc/kdc_preauth.c
++++ b/src/kdc/kdc_preauth.c
+@@ -87,6 +87,9 @@
+ #include <assert.h>
+ #include <krb5/kdcpreauth_plugin.h>
+ 
++/* Let freshness tokens be valid for ten minutes. */
++#define FRESHNESS_LIFETIME 600
++
+ typedef struct preauth_system_st {
+     const char *name;
+     int type;
+@@ -497,8 +500,68 @@ client_name(krb5_context context, krb5_kdcpreauth_rock rock)
+     return rock->client->princ;
+ }
+ 
++static void
++send_freshness_token(krb5_context context, krb5_kdcpreauth_rock rock)
++{
++    rock->send_freshness_token = TRUE;
++}
++
++static krb5_error_code
++check_freshness_token(krb5_context context, krb5_kdcpreauth_rock rock,
++                      const krb5_data *token)
++{
++    krb5_timestamp token_ts, now;
++    krb5_key_data *kd;
++    krb5_keyblock kb;
++    krb5_kvno token_kvno;
++    krb5_checksum cksum;
++    krb5_data d;
++    uint8_t *token_cksum;
++    size_t token_cksum_len;
++    krb5_boolean valid = FALSE;
++    char ckbuf[4];
++
++    memset(&kb, 0, sizeof(kb));
++
++    if (krb5_timeofday(context, &now) != 0)
++        goto cleanup;
++
++    if (token->length <= 8)
++        goto cleanup;
++    token_ts = load_32_be(token->data);
++    token_kvno = load_32_be(token->data + 4);
++    token_cksum = (uint8_t *)token->data + 8;
++    token_cksum_len = token->length - 8;
++
++    /* Check if the token timestamp is too old. */
++    if (ts_after(now, ts_incr(token_ts, FRESHNESS_LIFETIME)))
++        goto cleanup;
++
++    /* Fetch and decrypt the local krbtgt key of the token's kvno. */
++    if (krb5_dbe_find_enctype(context, rock->local_tgt, -1, -1, token_kvno,
++                              &kd) != 0)
++        goto cleanup;
++    if (krb5_dbe_decrypt_key_data(context, NULL, kd, &kb, NULL) != 0)
++        goto cleanup;
++
++    /* Verify the token checksum against the current KDC time.  The checksum
++     * must use the mandatory checksum type of the krbtgt key's enctype. */
++    store_32_be(token_ts, ckbuf);
++    d = make_data(ckbuf, sizeof(ckbuf));
++    cksum.magic = KV5M_CHECKSUM;
++    cksum.checksum_type = 0;
++    cksum.length = token_cksum_len;
++    cksum.contents = token_cksum;
++    (void)krb5_c_verify_checksum(context, &kb, KRB5_KEYUSAGE_PA_AS_FRESHNESS,
++                                 &d, &cksum, &valid);
++
++cleanup:
++    krb5_free_keyblock_contents(context, &kb);
++    return valid ? 0 : KRB5KDC_ERR_PREAUTH_EXPIRED;
++}
++
+ static struct krb5_kdcpreauth_callbacks_st callbacks = {
+-    4,
++    5,
+     max_time_skew,
+     client_keys,
+     free_keys,
+@@ -514,7 +577,9 @@ static struct krb5_kdcpreauth_callbacks_st callbacks = {
+     get_cookie,
+     set_cookie,
+     match_client,
+-    client_name
++    client_name,
++    send_freshness_token,
++    check_freshness_token
+ };
+ 
+ static krb5_error_code
+@@ -770,6 +835,62 @@ cleanup:
+     return ret;
+ }
+ 
++static krb5_error_code
++add_freshness_token(krb5_context context, krb5_kdcpreauth_rock rock,
++                    krb5_pa_data ***pa_list)
++{
++    krb5_error_code ret;
++    krb5_timestamp now;
++    krb5_key_data *kd;
++    krb5_keyblock kb;
++    krb5_checksum cksum;
++    krb5_data d;
++    krb5_pa_data *pa;
++    char ckbuf[4];
++
++    memset(&cksum, 0, sizeof(cksum));
++    memset(&kb, 0, sizeof(kb));
++
++    if (!rock->send_freshness_token)
++        return 0;
++    if (krb5int_find_pa_data(context, rock->request->padata,
++                             KRB5_PADATA_AS_FRESHNESS) == NULL)
++        return 0;
++
++    /* Fetch and decrypt the current local krbtgt key. */
++    ret = krb5_dbe_find_enctype(context, rock->local_tgt, -1, -1, 0, &kd);
++    if (ret)
++        goto cleanup;
++    ret = krb5_dbe_decrypt_key_data(context, NULL, kd, &kb, NULL);
++    if (ret)
++        goto cleanup;
++
++    /* Compute a checksum over the current KDC time. */
++    ret = krb5_timeofday(context, &now);
++    if (ret)
++        goto cleanup;
++    store_32_be(now, ckbuf);
++    d = make_data(ckbuf, sizeof(ckbuf));
++    ret = krb5_c_make_checksum(context, 0, &kb, KRB5_KEYUSAGE_PA_AS_FRESHNESS,
++                               &d, &cksum);
++
++    /* Compose a freshness token from the time, krbtgt kvno, and checksum. */
++    ret = alloc_pa_data(KRB5_PADATA_AS_FRESHNESS, 8 + cksum.length, &pa);
++    if (ret)
++        goto cleanup;
++    store_32_be(now, pa->contents);
++    store_32_be(kd->key_data_kvno, pa->contents + 4);
++    memcpy(pa->contents + 8, cksum.contents, cksum.length);
++
++    /* add_pa_data_element() claims pa on success or failure. */
++    ret = add_pa_data_element(pa_list, pa);
++
++cleanup:
++    krb5_free_keyblock_contents(context, &kb);
++    krb5_free_checksum_contents(context, &cksum);
++    return ret;
++}
++
+ struct hint_state {
+     kdc_hint_respond_fn respond;
+     void *arg;
+@@ -792,6 +913,11 @@ hint_list_finish(struct hint_state *state, krb5_error_code code)
+     void *oldarg = state->arg;
+     kdc_realm_t *kdc_active_realm = state->realm;
+ 
++    /* Add a freshness token if a preauth module requested it and the client
++     * request indicates support for it. */
++    if (!code)
++        code = add_freshness_token(kdc_context, state->rock, &state->pa_data);
++
+     if (!code) {
+         if (state->pa_data == NULL) {
+             krb5_klog_syslog(LOG_INFO,
+diff --git a/src/kdc/kdc_util.h b/src/kdc/kdc_util.h
+index 198eab9c4..1885c9f80 100644
+--- a/src/kdc/kdc_util.h
++++ b/src/kdc/kdc_util.h
+@@ -426,11 +426,13 @@ struct krb5_kdcpreauth_rock_st {
+     krb5_kdc_req *request;
+     krb5_data *inner_body;
+     krb5_db_entry *client;
++    krb5_db_entry *local_tgt;
+     krb5_key_data *client_key;
+     krb5_keyblock *client_keyblock;
+     struct kdc_request_state *rstate;
+     verto_ctx *vctx;
+     krb5_data ***auth_indicators;
++    krb5_boolean send_freshness_token;
+ };
+ 
+ #define isflagset(flagfield, flag) (flagfield & (flag))
+diff --git a/src/plugins/preauth/pkinit/pkinit.h b/src/plugins/preauth/pkinit/pkinit.h
+index 8489a3e23..fe2ec0d31 100644
+--- a/src/plugins/preauth/pkinit/pkinit.h
++++ b/src/plugins/preauth/pkinit/pkinit.h
+@@ -77,6 +77,7 @@
+ #define KRB5_CONF_PKINIT_KDC_OCSP               "pkinit_kdc_ocsp"
+ #define KRB5_CONF_PKINIT_POOL                   "pkinit_pool"
+ #define KRB5_CONF_PKINIT_REQUIRE_CRL_CHECKING   "pkinit_require_crl_checking"
++#define KRB5_CONF_PKINIT_REQUIRE_FRESHNESS      "pkinit_require_freshness"
+ #define KRB5_CONF_PKINIT_REVOKE                 "pkinit_revoke"
+ 
+ /* Make pkiDebug(fmt,...) print, or not.  */
+@@ -148,6 +149,7 @@ typedef struct _pkinit_plg_opts {
+     int allow_upn;	    /* allow UPN-SAN instead of pkinit-SAN */
+     int dh_or_rsa;	    /* selects DH or RSA based pkinit */
+     int require_crl_checking; /* require CRL for a CA (default is false) */
++    int require_freshness;  /* require freshness token (default is false) */
+     int disable_freshness;  /* disable freshness token on client for testing */
+     int dh_min_bits;	    /* minimum DH modulus size allowed */
+ } pkinit_plg_opts;
+diff --git a/src/plugins/preauth/pkinit/pkinit_srv.c b/src/plugins/preauth/pkinit/pkinit_srv.c
+index 8aa4d8b49..76ad5bf19 100644
+--- a/src/plugins/preauth/pkinit/pkinit_srv.c
++++ b/src/plugins/preauth/pkinit/pkinit_srv.c
+@@ -161,6 +161,10 @@ pkinit_server_get_edata(krb5_context context,
+     if (plgctx == NULL)
+         retval = EINVAL;
+ 
++    /* Send a freshness token if the client requested one. */
++    if (!retval)
++        cb->send_freshness_token(context, rock);
++
+     (*respond)(arg, retval, NULL);
+ }
+ 
+@@ -403,6 +407,31 @@ cleanup:
+     return ret;
+ }
+ 
++/* Return an error if freshness tokens are required and one was not received.
++ * Log an appropriate message indicating whether a valid token was received. */
++static krb5_error_code
++check_log_freshness(krb5_context context, pkinit_kdc_context plgctx,
++                    krb5_kdc_req *request, krb5_boolean valid_freshness_token)
++{
++    krb5_error_code ret;
++    char *name = NULL;
++
++    ret = krb5_unparse_name(context, request->client, &name);
++    if (ret)
++        return ret;
++    if (plgctx->opts->require_freshness && !valid_freshness_token) {
++        com_err("", 0, _("PKINIT: no freshness token, rejecting auth from %s"),
++                name);
++        ret = KRB5KDC_ERR_PREAUTH_FAILED;
++    } else if (valid_freshness_token) {
++        com_err("", 0, _("PKINIT: freshness token received from %s"), name);
++    } else {
++        com_err("", 0, _("PKINIT: no freshness token received from %s"), name);
++    }
++    krb5_free_unparsed_name(context, name);
++    return ret;
++}
++
+ static void
+ pkinit_server_verify_padata(krb5_context context,
+                             krb5_data *req_pkt,
+@@ -425,10 +454,11 @@ pkinit_server_verify_padata(krb5_context context,
+     pkinit_kdc_req_context reqctx = NULL;
+     krb5_checksum cksum = {0, 0, 0, NULL};
+     krb5_data *der_req = NULL;
+-    krb5_data k5data;
++    krb5_data k5data, *ftoken;
+     int is_signed = 1;
+     krb5_pa_data **e_data = NULL;
+     krb5_kdcpreauth_modreq modreq = NULL;
++    krb5_boolean valid_freshness_token = FALSE;
+     char **sp;
+ 
+     pkiDebug("pkinit_verify_padata: entered!\n");
+@@ -599,6 +629,14 @@ pkinit_server_verify_padata(krb5_context context,
+             goto cleanup;
+         }
+ 
++        ftoken = auth_pack->pkAuthenticator.freshnessToken;
++        if (ftoken != NULL) {
++            retval = cb->check_freshness_token(context, rock, ftoken);
++            if (retval)
++                goto cleanup;
++            valid_freshness_token = TRUE;
++        }
++
+         /* check if kdcPkId present and match KDC's subjectIdentifier */
+         if (reqp->kdcPkId.data != NULL) {
+             int valid_kdcPkId = 0;
+@@ -641,6 +679,13 @@ pkinit_server_verify_padata(krb5_context context,
+         break;
+     }
+ 
++    if (is_signed) {
++        retval = check_log_freshness(context, plgctx, request,
++                                     valid_freshness_token);
++        if (retval)
++            goto cleanup;
++    }
++
+     if (is_signed && plgctx->auth_indicators != NULL) {
+         /* Assert configured authentication indicators. */
+         for (sp = plgctx->auth_indicators; *sp != NULL; sp++) {
+@@ -1330,6 +1375,10 @@ pkinit_init_kdc_profile(krb5_context context, pkinit_kdc_context plgctx)
+                               KRB5_CONF_PKINIT_REQUIRE_CRL_CHECKING,
+                               0, &plgctx->opts->require_crl_checking);
+ 
++    pkinit_kdcdefault_boolean(context, plgctx->realmname,
++                              KRB5_CONF_PKINIT_REQUIRE_FRESHNESS,
++                              0, &plgctx->opts->require_freshness);
++
+     pkinit_kdcdefault_string(context, plgctx->realmname,
+                              KRB5_CONF_PKINIT_EKU_CHECKING,
+                              &eku_string);
+diff --git a/src/tests/t_pkinit.py b/src/tests/t_pkinit.py
+index 86fe661a0..5bc60cb1e 100755
+--- a/src/tests/t_pkinit.py
++++ b/src/tests/t_pkinit.py
+@@ -39,6 +39,8 @@ pkinit_kdc_conf = {'realms': {'$realm': {
+             'pkinit_indicator': ['indpkinit1', 'indpkinit2']}}}
+ restrictive_kdc_conf = {'realms': {'$realm': {
+             'restrict_anonymous_to_tgt': 'true' }}}
++freshness_kdc_conf = {'realms': {'$realm': {
++            'pkinit_require_freshness': 'true'}}}
+ 
+ testprincs = {'krbtgt/KRBTEST.COM': {'keys': 'aes128-cts'},
+               'user': {'keys': 'aes128-cts', 'flags': '+preauth'},
+@@ -118,6 +120,10 @@ realm.kinit(realm.user_princ, password=password('user'))
+ realm.klist(realm.user_princ)
+ realm.run([kvno, realm.host_princ])
+ 
++# Having tested password preauth, remove the keys for better error
++# reporting.
++realm.run([kadminl, 'purgekeys', '-all', realm.user_princ])
++
+ # Test anonymous PKINIT.
+ realm.kinit('@%s' % realm.realm, flags=['-n'], expected_code=1,
+             expected_msg='not found in Kerberos database')
+@@ -153,23 +159,32 @@ realm.run([kvno, realm.host_princ], expected_code=1,
+ realm.kinit(realm.host_princ, flags=['-k'])
+ realm.run([kvno, '-U', 'user', realm.host_princ])
+ 
+-# Go back to a normal KDC and disable anonymous PKINIT.
++# Go back to the normal KDC environment.
+ realm.stop_kdc()
+ realm.start_kdc()
+-realm.run([kadminl, 'delprinc', 'WELLKNOWN/ANONYMOUS'])
+ 
+ # Run the basic test - PKINIT with FILE: identity, with no password on the key.
+-realm.run(['./responder', '-x', 'pkinit=',
+-           '-X', 'X509_user_identity=%s' % file_identity, realm.user_princ])
+ realm.kinit(realm.user_princ,
+-            flags=['-X', 'X509_user_identity=%s' % file_identity])
++            flags=['-X', 'X509_user_identity=%s' % file_identity],
++            expected_trace=('Sending unauthenticated request',
++                            '/Additional pre-authentication required',
++                            'Preauthenticating using KDC method data',
++                            'PKINIT client received freshness token from KDC',
++                            'PKINIT loading CA certs and CRLs from FILE',
++                            'PKINIT client making DH request',
++                            'Produced preauth for next request: 133, 16',
++                            'PKINIT client verified DH reply',
++                            'PKINIT client found id-pkinit-san in KDC cert',
++                            'PKINIT client matched KDC principal krbtgt/'))
+ realm.klist(realm.user_princ)
+ realm.run([kvno, realm.host_princ])
+ 
+ # Try again using RSA instead of DH.
+ realm.kinit(realm.user_princ,
+             flags=['-X', 'X509_user_identity=%s' % file_identity,
+-                   '-X', 'flag_RSA_PROTOCOL=yes'])
++                   '-X', 'flag_RSA_PROTOCOL=yes'],
++            expected_trace=('PKINIT client making RSA request',
++                            'PKINIT client verified RSA reply'))
+ realm.klist(realm.user_princ)
+ 
+ # Test a DH parameter renegotiation by temporarily setting a 4096-bit
+@@ -192,8 +207,23 @@ expected_trace = ('Sending unauthenticated request',
+ realm.kinit(realm.user_princ,
+             flags=['-X', 'X509_user_identity=%s' % file_identity],
+             expected_trace=expected_trace)
++
++# Test enforcement of required freshness tokens.  (We can leave
++# freshness tokens required after this test.)
++realm.kinit(realm.user_princ,
++            flags=['-X', 'X509_user_identity=%s' % file_identity,
++                   '-X', 'disable_freshness=yes'])
++f_env = realm.special_env('freshness', True, kdc_conf=freshness_kdc_conf)
+ realm.stop_kdc()
+-realm.start_kdc()
++realm.start_kdc(env=f_env)
++realm.kinit(realm.user_princ,
++            flags=['-X', 'X509_user_identity=%s' % file_identity])
++realm.kinit(realm.user_princ,
++            flags=['-X', 'X509_user_identity=%s' % file_identity,
++                   '-X', 'disable_freshness=yes'],
++            expected_code=1, expected_msg='Preauthentication failed')
++# Anonymous should never require a freshness token.
++realm.kinit('@%s' % realm.realm, flags=['-n', '-X', 'disable_freshness=yes'])
+ 
+ # Run the basic test - PKINIT with FILE: identity, with a password on the key,
+ # supplied by the prompter.
+@@ -229,8 +259,6 @@ shutil.copy(privkey_pem, os.path.join(path, 'user.key'))
+ shutil.copy(privkey_enc_pem, os.path.join(path_enc, 'user.key'))
+ shutil.copy(user_pem, os.path.join(path, 'user.crt'))
+ shutil.copy(user_pem, os.path.join(path_enc, 'user.crt'))
+-realm.run(['./responder', '-x', 'pkinit=', '-X',
+-           'X509_user_identity=%s' % dir_identity, realm.user_princ])
+ realm.kinit(realm.user_princ,
+             flags=['-X', 'X509_user_identity=%s' % dir_identity])
+ realm.klist(realm.user_princ)
+@@ -262,8 +290,6 @@ realm.klist(realm.user_princ)
+ realm.run([kvno, realm.host_princ])
+ 
+ # PKINIT with PKCS12: identity, with no password on the bundle.
+-realm.run(['./responder', '-x', 'pkinit=',
+-           '-X', 'X509_user_identity=%s' % p12_identity, realm.user_princ])
+ realm.kinit(realm.user_princ,
+             flags=['-X', 'X509_user_identity=%s' % p12_identity])
+ realm.klist(realm.user_princ)
+@@ -357,8 +383,6 @@ conf = open(softpkcs11rc, 'w')
+ conf.write("%s\t%s\t%s\t%s\n" % ('user', 'user token', user_pem, privkey_pem))
+ conf.close()
+ # Expect to succeed without having to supply any more information.
+-realm.run(['./responder', '-x', 'pkinit=',
+-           '-X', 'X509_user_identity=%s' % p11_identity, realm.user_princ])
+ realm.kinit(realm.user_princ,
+             flags=['-X', 'X509_user_identity=%s' % p11_identity])
+ realm.klist(realm.user_princ)
diff --git a/SOURCES/Add-PKINIT-client-support-for-freshness-token.patch b/SOURCES/Add-PKINIT-client-support-for-freshness-token.patch
new file mode 100644
index 0000000..1a00819
--- /dev/null
+++ b/SOURCES/Add-PKINIT-client-support-for-freshness-token.patch
@@ -0,0 +1,336 @@
+From 5edc6de93196b4f07da6695a4b271a067000c84d Mon Sep 17 00:00:00 2001
+From: Greg Hudson <ghudson@mit.edu>
+Date: Tue, 31 Jan 2017 17:02:34 -0500
+Subject: [PATCH] Add PKINIT client support for freshness token
+
+Send an empty PA_AS_FRESHNESS padata item in unauthenticated AS
+requests to indicate support for RFC 8070.  If the KDC includes a
+PA_AS_FRESHNESS value in its method data, echo it back in the new
+freshnessToken field of pkAuthenticator
+
+ticket: 8648
+(cherry picked from commit 085785362e01467cb25c79a90dcebfba9ea019d8)
+---
+ doc/user/user_commands/kinit.rst          |  3 +++
+ src/include/k5-int-pkinit.h               |  1 +
+ src/include/krb5/krb5.hin                 |  1 +
+ src/lib/krb5/asn.1/asn1_k_encode.c        |  5 ++++-
+ src/lib/krb5/krb/get_in_tkt.c             | 12 ++++++++----
+ src/lib/krb5/krb/init_creds_ctx.h         |  2 +-
+ src/plugins/preauth/pkinit/pkinit.h       |  3 +++
+ src/plugins/preauth/pkinit/pkinit_clnt.c  | 19 ++++++++++++++++++-
+ src/plugins/preauth/pkinit/pkinit_lib.c   |  3 +++
+ src/plugins/preauth/pkinit/pkinit_trace.h |  2 ++
+ src/tests/asn.1/ktest.c                   |  4 ++++
+ src/tests/asn.1/pkinit_encode.out         |  2 +-
+ src/tests/asn.1/pkinit_trval.out          |  1 +
+ 13 files changed, 50 insertions(+), 8 deletions(-)
+
+diff --git a/doc/user/user_commands/kinit.rst b/doc/user/user_commands/kinit.rst
+index 3f9d5340f..1f696920f 100644
+--- a/doc/user/user_commands/kinit.rst
++++ b/doc/user/user_commands/kinit.rst
+@@ -197,6 +197,9 @@ OPTIONS
+         specify use of RSA, rather than the default Diffie-Hellman
+         protocol
+ 
++    **disable_freshness**\ [**=yes**]
++        disable sending freshness tokens (for testing purposes only)
++
+ 
+ ENVIRONMENT
+ -----------
+diff --git a/src/include/k5-int-pkinit.h b/src/include/k5-int-pkinit.h
+index 7b2f595cb..4622a629e 100644
+--- a/src/include/k5-int-pkinit.h
++++ b/src/include/k5-int-pkinit.h
+@@ -42,6 +42,7 @@ typedef struct _krb5_pk_authenticator {
+     krb5_timestamp  ctime;
+     krb5_int32      nonce;  /* (0..4294967295) */
+     krb5_checksum   paChecksum;
++    krb5_data      *freshnessToken;
+ } krb5_pk_authenticator;
+ 
+ /* PKAuthenticator draft9 */
+diff --git a/src/include/krb5/krb5.hin b/src/include/krb5/krb5.hin
+index e81bb0a6d..833e72335 100644
+--- a/src/include/krb5/krb5.hin
++++ b/src/include/krb5/krb5.hin
+@@ -1879,6 +1879,7 @@ krb5_verify_checksum(krb5_context context, krb5_cksumtype ctype,
+ #define KRB5_PADATA_OTP_PIN_CHANGE      144 /**< RFC 6560 section 4.3 */
+ #define KRB5_PADATA_PKINIT_KX           147 /**< RFC 6112 */
+ #define KRB5_ENCPADATA_REQ_ENC_PA_REP   149 /**< RFC 6806 */
++#define KRB5_PADATA_AS_FRESHNESS        150 /**< RFC 8070 */
+ 
+ #define KRB5_SAM_USE_SAD_AS_KEY         0x80000000
+ #define KRB5_SAM_SEND_ENCRYPTED_SAD     0x40000000
+diff --git a/src/lib/krb5/asn.1/asn1_k_encode.c b/src/lib/krb5/asn.1/asn1_k_encode.c
+index 889460989..3b23fe34a 100644
+--- a/src/lib/krb5/asn.1/asn1_k_encode.c
++++ b/src/lib/krb5/asn.1/asn1_k_encode.c
+@@ -1442,9 +1442,12 @@ DEFFIELD(pk_authenticator_1, krb5_pk_authenticator, ctime, 1, kerberos_time);
+ DEFFIELD(pk_authenticator_2, krb5_pk_authenticator, nonce, 2, int32);
+ DEFFIELD(pk_authenticator_3, krb5_pk_authenticator, paChecksum, 3,
+          ostring_checksum);
++DEFFIELD(pk_authenticator_4, krb5_pk_authenticator, freshnessToken, 4,
++         opt_ostring_data_ptr);
+ static const struct atype_info *pk_authenticator_fields[] = {
+     &k5_atype_pk_authenticator_0, &k5_atype_pk_authenticator_1,
+-    &k5_atype_pk_authenticator_2, &k5_atype_pk_authenticator_3
++    &k5_atype_pk_authenticator_2, &k5_atype_pk_authenticator_3,
++    &k5_atype_pk_authenticator_4
+ };
+ DEFSEQTYPE(pk_authenticator, krb5_pk_authenticator, pk_authenticator_fields);
+ 
+diff --git a/src/lib/krb5/krb/get_in_tkt.c b/src/lib/krb5/krb/get_in_tkt.c
+index 47a00bf2c..1d96ff163 100644
+--- a/src/lib/krb5/krb/get_in_tkt.c
++++ b/src/lib/krb5/krb/get_in_tkt.c
+@@ -895,7 +895,7 @@ krb5_init_creds_init(krb5_context context,
+     ctx->request = k5alloc(sizeof(krb5_kdc_req), &code);
+     if (code != 0)
+         goto cleanup;
+-    ctx->enc_pa_rep_permitted = TRUE;
++    ctx->info_pa_permitted = TRUE;
+     code = krb5_copy_principal(context, client, &ctx->request->client);
+     if (code != 0)
+         goto cleanup;
+@@ -1389,7 +1389,11 @@ init_creds_step_request(krb5_context context,
+         krb5_free_data(context, ctx->encoded_previous_request);
+         ctx->encoded_previous_request = NULL;
+     }
+-    if (ctx->enc_pa_rep_permitted) {
++    if (ctx->info_pa_permitted) {
++        code = add_padata(&ctx->request->padata, KRB5_PADATA_AS_FRESHNESS,
++                          NULL, 0);
++        if (code)
++            goto cleanup;
+         code = add_padata(&ctx->request->padata, KRB5_ENCPADATA_REQ_ENC_PA_REP,
+                           NULL, 0);
+     }
+@@ -1530,7 +1534,7 @@ init_creds_step_reply(krb5_context context,
+                    ctx->selected_preauth_type == KRB5_PADATA_NONE) {
+             /* The KDC didn't like our informational padata (probably a pre-1.7
+              * MIT krb5 KDC).  Retry without it. */
+-            ctx->enc_pa_rep_permitted = FALSE;
++            ctx->info_pa_permitted = FALSE;
+             ctx->restarted = TRUE;
+             code = restart_init_creds_loop(context, ctx, FALSE);
+         } else if (reply_code == KDC_ERR_PREAUTH_EXPIRED) {
+@@ -1574,7 +1578,7 @@ init_creds_step_reply(krb5_context context,
+                 goto cleanup;
+             /* Reset per-realm negotiation state. */
+             ctx->restarted = FALSE;
+-            ctx->enc_pa_rep_permitted = TRUE;
++            ctx->info_pa_permitted = TRUE;
+             code = restart_init_creds_loop(context, ctx, FALSE);
+         } else {
+             if (retry && ctx->selected_preauth_type != KRB5_PADATA_NONE) {
+diff --git a/src/lib/krb5/krb/init_creds_ctx.h b/src/lib/krb5/krb/init_creds_ctx.h
+index fe769685b..b19410a13 100644
+--- a/src/lib/krb5/krb/init_creds_ctx.h
++++ b/src/lib/krb5/krb/init_creds_ctx.h
+@@ -58,7 +58,7 @@ struct _krb5_init_creds_context {
+     krb5_data s2kparams;
+     krb5_keyblock as_key;
+     krb5_enctype etype;
+-    krb5_boolean enc_pa_rep_permitted;
++    krb5_boolean info_pa_permitted;
+     krb5_boolean restarted;
+     struct krb5_responder_context_st rctx;
+     krb5_preauthtype selected_preauth_type;
+diff --git a/src/plugins/preauth/pkinit/pkinit.h b/src/plugins/preauth/pkinit/pkinit.h
+index f3de9ad7a..8489a3e23 100644
+--- a/src/plugins/preauth/pkinit/pkinit.h
++++ b/src/plugins/preauth/pkinit/pkinit.h
+@@ -148,6 +148,7 @@ typedef struct _pkinit_plg_opts {
+     int allow_upn;	    /* allow UPN-SAN instead of pkinit-SAN */
+     int dh_or_rsa;	    /* selects DH or RSA based pkinit */
+     int require_crl_checking; /* require CRL for a CA (default is false) */
++    int disable_freshness;  /* disable freshness token on client for testing */
+     int dh_min_bits;	    /* minimum DH modulus size allowed */
+ } pkinit_plg_opts;
+ 
+@@ -162,6 +163,7 @@ typedef struct _pkinit_req_opts {
+     int require_crl_checking;
+     int dh_size;	    /* initial request DH modulus size (default=1024) */
+     int require_hostname_match;
++    int disable_freshness;
+ } pkinit_req_opts;
+ 
+ /*
+@@ -214,6 +216,7 @@ struct _pkinit_req_context {
+     int identity_initialized;
+     int identity_prompted;
+     krb5_error_code identity_prompt_retval;
++    krb5_data *freshness_token;
+ };
+ typedef struct _pkinit_req_context *pkinit_req_context;
+ 
+diff --git a/src/plugins/preauth/pkinit/pkinit_clnt.c b/src/plugins/preauth/pkinit/pkinit_clnt.c
+index f1bc6b21d..9483d69e5 100644
+--- a/src/plugins/preauth/pkinit/pkinit_clnt.c
++++ b/src/plugins/preauth/pkinit/pkinit_clnt.c
+@@ -231,6 +231,8 @@ pkinit_as_req_create(krb5_context context,
+         auth_pack.pkAuthenticator.cusec = cusec;
+         auth_pack.pkAuthenticator.nonce = nonce;
+         auth_pack.pkAuthenticator.paChecksum = *cksum;
++        if (!reqctx->opts->disable_freshness)
++            auth_pack.pkAuthenticator.freshnessToken = reqctx->freshness_token;
+         auth_pack.clientDHNonce.length = 0;
+         auth_pack.clientPublicValue = &info;
+         auth_pack.supportedKDFs = (krb5_data **)supported_kdf_alg_ids;
+@@ -1162,6 +1164,7 @@ pkinit_client_process(krb5_context context, krb5_clpreauth_moddata moddata,
+     pkinit_context plgctx = (pkinit_context)moddata;
+     pkinit_req_context reqctx = (pkinit_req_context)modreq;
+     krb5_keyblock as_key;
++    krb5_data d;
+ 
+     pkiDebug("pkinit_client_process %p %p %p %p\n",
+              context, plgctx, reqctx, request);
+@@ -1174,6 +1177,12 @@ pkinit_client_process(krb5_context context, krb5_clpreauth_moddata moddata,
+     case KRB5_PADATA_PKINIT_KX:
+         reqctx->rfc6112_kdc = 1;
+         return 0;
++    case KRB5_PADATA_AS_FRESHNESS:
++        TRACE_PKINIT_CLIENT_FRESHNESS_TOKEN(context);
++        krb5_free_data(context, reqctx->freshness_token);
++        reqctx->freshness_token = NULL;
++        d = make_data(in_padata->contents, in_padata->length);
++        return krb5_copy_data(context, &d, &reqctx->freshness_token);
+     case KRB5_PADATA_PK_AS_REQ:
+         reqctx->rfc4556_kdc = 1;
+         pkiDebug("processing KRB5_PADATA_PK_AS_REQ\n");
+@@ -1359,7 +1368,7 @@ cleanup:
+ static int
+ pkinit_client_get_flags(krb5_context kcontext, krb5_preauthtype patype)
+ {
+-    if (patype == KRB5_PADATA_PKINIT_KX)
++    if (patype == KRB5_PADATA_PKINIT_KX || patype == KRB5_PADATA_AS_FRESHNESS)
+         return PA_INFO;
+     return PA_REAL;
+ }
+@@ -1376,6 +1385,7 @@ static krb5_preauthtype supported_client_pa_types[] = {
+     KRB5_PADATA_PK_AS_REP_OLD,
+     KRB5_PADATA_PK_AS_REQ_OLD,
+     KRB5_PADATA_PKINIT_KX,
++    KRB5_PADATA_AS_FRESHNESS,
+     0
+ };
+ 
+@@ -1400,6 +1410,7 @@ pkinit_client_req_init(krb5_context context,
+     reqctx->opts = NULL;
+     reqctx->idctx = NULL;
+     reqctx->idopts = NULL;
++    reqctx->freshness_token = NULL;
+ 
+     retval = pkinit_init_req_opts(&reqctx->opts);
+     if (retval)
+@@ -1410,6 +1421,7 @@ pkinit_client_req_init(krb5_context context,
+     reqctx->opts->dh_or_rsa = plgctx->opts->dh_or_rsa;
+     reqctx->opts->allow_upn = plgctx->opts->allow_upn;
+     reqctx->opts->require_crl_checking = plgctx->opts->require_crl_checking;
++    reqctx->opts->disable_freshness = plgctx->opts->disable_freshness;
+ 
+     retval = pkinit_init_req_crypto(&reqctx->cryptoctx);
+     if (retval)
+@@ -1468,6 +1480,8 @@ pkinit_client_req_fini(krb5_context context, krb5_clpreauth_moddata moddata,
+     if (reqctx->idopts != NULL)
+         pkinit_fini_identity_opts(reqctx->idopts);
+ 
++    krb5_free_data(context, reqctx->freshness_token);
++
+     free(reqctx);
+     return;
+ }
+@@ -1580,6 +1594,9 @@ handle_gic_opt(krb5_context context,
+             pkiDebug("Setting flag to use RSA_PROTOCOL\n");
+             plgctx->opts->dh_or_rsa = RSA_PROTOCOL;
+         }
++    } else if (strcmp(attr, "disable_freshness") == 0) {
++        if (strcmp(value, "yes") == 0)
++            plgctx->opts->disable_freshness = 1;
+     }
+     return 0;
+ }
+diff --git a/src/plugins/preauth/pkinit/pkinit_lib.c b/src/plugins/preauth/pkinit/pkinit_lib.c
+index 2f88545da..d5858c424 100644
+--- a/src/plugins/preauth/pkinit/pkinit_lib.c
++++ b/src/plugins/preauth/pkinit/pkinit_lib.c
+@@ -82,6 +82,8 @@ pkinit_init_plg_opts(pkinit_plg_opts **plgopts)
+     opts->dh_or_rsa = DH_PROTOCOL;
+     opts->allow_upn = 0;
+     opts->require_crl_checking = 0;
++    opts->require_freshness = 0;
++    opts->disable_freshness = 0;
+ 
+     opts->dh_min_bits = PKINIT_DEFAULT_DH_MIN_BITS;
+ 
+@@ -145,6 +147,7 @@ free_krb5_auth_pack(krb5_auth_pack **in)
+         free((*in)->clientPublicValue);
+     }
+     free((*in)->pkAuthenticator.paChecksum.contents);
++    krb5_free_data(NULL, (*in)->pkAuthenticator.freshnessToken);
+     if ((*in)->supportedCMSTypes != NULL)
+         free_krb5_algorithm_identifiers(&((*in)->supportedCMSTypes));
+     if ((*in)->supportedKDFs) {
+diff --git a/src/plugins/preauth/pkinit/pkinit_trace.h b/src/plugins/preauth/pkinit/pkinit_trace.h
+index 2d95da94a..7f95206c0 100644
+--- a/src/plugins/preauth/pkinit/pkinit_trace.h
++++ b/src/plugins/preauth/pkinit/pkinit_trace.h
+@@ -41,6 +41,8 @@
+     TRACE(c, "PKINIT client found no acceptable EKU in KDC cert")
+ #define TRACE_PKINIT_CLIENT_EKU_SKIP(c)                                 \
+     TRACE(c, "PKINIT client skipping EKU check due to configuration")
++#define TRACE_PKINIT_CLIENT_FRESHNESS_TOKEN(c)                  \
++    TRACE(c, "PKINIT client received freshness token from KDC")
+ #define TRACE_PKINIT_CLIENT_KDF_ALG(c, kdf, keyblock)                   \
+     TRACE(c, "PKINIT client used KDF {hexdata} to compute reply key "   \
+           "{keyblock}", kdf, keyblock)
+diff --git a/src/tests/asn.1/ktest.c b/src/tests/asn.1/ktest.c
+index 43084cbbd..cf63f3f66 100644
+--- a/src/tests/asn.1/ktest.c
++++ b/src/tests/asn.1/ktest.c
+@@ -725,6 +725,8 @@ ktest_make_sample_pk_authenticator(krb5_pk_authenticator *p)
+     ktest_make_sample_checksum(&p->paChecksum);
+     /* We don't encode the checksum type, only the contents. */
+     p->paChecksum.checksum_type = 0;
++    p->freshnessToken = ealloc(sizeof(krb5_data));
++    ktest_make_sample_data(p->freshnessToken);
+ }
+ 
+ static void
+@@ -1651,6 +1653,8 @@ ktest_empty_pk_authenticator(krb5_pk_authenticator *p)
+ {
+     ktest_empty_checksum(&p->paChecksum);
+     p->paChecksum.contents = NULL;
++    krb5_free_data(NULL, p->freshnessToken);
++    p->freshnessToken = NULL;
+ }
+ 
+ static void
+diff --git a/src/tests/asn.1/pkinit_encode.out b/src/tests/asn.1/pkinit_encode.out
+index 463128de0..3b0f7190a 100644
+--- a/src/tests/asn.1/pkinit_encode.out
++++ b/src/tests/asn.1/pkinit_encode.out
+@@ -4,7 +4,7 @@ encode_krb5_pa_pk_as_rep(dhInfo): A0 28 30 26 80 08 6B 72 62 35 64 61 74 61 A1 0
+ encode_krb5_pa_pk_as_rep(encKeyPack): 81 08 6B 72 62 35 64 61 74 61
+ encode_krb5_pa_pk_as_rep_draft9(dhSignedData): 80 08 6B 72 62 35 64 61 74 61
+ encode_krb5_pa_pk_as_rep_draft9(encKeyPack): 81 08 6B 72 62 35 64 61 74 61
+-encode_krb5_auth_pack: 30 81 93 A0 29 30 27 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 06 04 04 31 32 33 34 A1 22 30 20 30 13 06 09 2A 86 48 86 F7 12 01 02 02 04 06 70 61 72 61 6D 73 03 09 00 6B 72 62 35 64 61 74 61 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 9F A0 35 30 33 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 06 04 04 31 32 33 34 A4 0A 04 08 6B 72 62 35 64 61 74 61 A1 22 30 20 30 13 06 09 2A 86 48 86 F7 12 01 02 02 04 06 70 61 72 61 6D 73 03 09 00 6B 72 62 35 64 61 74 61 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_draft9: 30 75 A0 4F 30 4D A0 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 10 1B 0E 41 54 48 45 4E 41 2E 4D 49 54 2E 45 44 55 A2 05 02 03 01 E2 40 A3 11 18 0F 31 39 39 34 30 36 31 30 30 36 30 33 31 37 5A A4 03 02 01 2A A1 22 30 20 30 13 06 09 2A 86 48 86 F7 12 01 02 02 04 06 70 61 72 61 6D 73 03 09 00 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
+diff --git a/src/tests/asn.1/pkinit_trval.out b/src/tests/asn.1/pkinit_trval.out
+index 58d870631..f9edbe154 100644
+--- a/src/tests/asn.1/pkinit_trval.out
++++ b/src/tests/asn.1/pkinit_trval.out
+@@ -57,6 +57,7 @@ encode_krb5_auth_pack:
+ .  .  [1] [Generalized Time] "19940610060317Z"
+ .  .  [2] [Integer] 42
+ .  .  [3] [Octet String] "1234"
++.  .  [4] [Octet String] "krb5data"
+ .  [1] [Sequence/Sequence Of]
+ .  .  [Sequence/Sequence Of]
+ .  .  .  [Object Identifier] <9>
diff --git a/SOURCES/Add-SPAKE-preauth-support.patch b/SOURCES/Add-SPAKE-preauth-support.patch
new file mode 100644
index 0000000..ab04539
--- /dev/null
+++ b/SOURCES/Add-SPAKE-preauth-support.patch
@@ -0,0 +1,14349 @@
+From f8f2cff0aba6ea7dd9b5fef89549aaff36ce4fee Mon Sep 17 00:00:00 2001
+From: Greg Hudson <ghudson@mit.edu>
+Date: Fri, 25 Sep 2015 17:47:35 -0400
+Subject: [PATCH] Add SPAKE preauth support
+
+This is an implementation of draft-ietf-kitten-krb-spake-preauth-05.
+SPAKE preauth authenticates using the client principal long-term key,
+but protects against offline dictionary attacks.
+
+SPAKE preauth negotiates a group for use by the SPAKE2 algorithm.  The
+edwards25519 group is implemented using code adapted from BoringSSL.
+The P-256, P-384, and P-521 groups are implemented against OpenSSL.
+edwards25519 is enabled by default on the client; no groups are
+enabled by default on the KDC.
+
+SPAKE preauth can also include a second factor.  Second factor support
+isn't included in this implementation; comments have been left to
+indicate what should change when it is added in.
+
+Integration tests (tests/t_spake.py) are included with good coverage
+of the negotiation scenarios.
+
+Test vectors from the draft are checked against the group's "result"
+operation.  The "keygen" operation is inherently random and is
+therefore not tested against the vectors, but is effectively exercised
+by the integration tests.
+
+KDC optimistic challenge is implemented.  In the future we should
+implement client optimistic SPAKE as well; this will require changes
+to the generic client preauth framework.
+
+In the future we should add per-realm configuration to deny encrypted
+timestamp and encrypted challenge on a per-realm basis.  This
+configuration should stick across client realm referrals.
+
+In the future we should avoid attempting encrypting timestamp or
+encrypted challenge if the KDC replies to a single-factor
+SPAKEResponse message with PREAUTH_FAILED.  This will require a change
+to the generic client preauth framework.
+
+In the future we should make SPAKE support apply to the Windows build,
+either by adding support for building plugin DLLs or by moving the
+edwards25519 and client code to libkrb5.
+
+[npmccallum@redhat.com: split up internal headers; split out group
+registry contents; implemented P-384 and P-521]
+
+ticket: 8647 (new)
+(cherry picked from commit 7447259401569c92b1fb2e31cb02edbbffd67d35)
+---
+ NOTICE                                        |   51 +
+ doc/admin/conf_files/kdc_conf.rst             |   22 +-
+ doc/admin/conf_files/krb5_conf.rst            |   15 +
+ doc/admin/index.rst                           |    1 +
+ doc/admin/spake.rst                           |   46 +
+ doc/formats/cookie.rst                        |   37 +
+ doc/notice.rst                                |   47 +
+ src/Makefile.in                               |    2 +
+ src/config/pre.in                             |    6 +
+ src/configure.in                              |   20 +
+ src/include/k5-int.h                          |    3 +
+ src/include/krb5/krb5.hin                     |    2 +
+ src/kdc/kdc_preauth.c                         |    2 +
+ src/lib/krb5/krb/preauth2.c                   |    2 +
+ src/lib/krb5/os/trace.c                       |    1 +
+ src/plugins/preauth/spake/AUTHORS             |   16 +
+ src/plugins/preauth/spake/Makefile.in         |   39 +
+ src/plugins/preauth/spake/deps                |   73 +
+ src/plugins/preauth/spake/edwards25519.c      | 2651 ++++++
+ .../preauth/spake/edwards25519_tables.h       | 7881 +++++++++++++++++
+ src/plugins/preauth/spake/groups.c            |  442 +
+ src/plugins/preauth/spake/groups.h            |  148 +
+ src/plugins/preauth/spake/iana.c              |  108 +
+ src/plugins/preauth/spake/iana.h              |   65 +
+ src/plugins/preauth/spake/openssl.c           |  315 +
+ src/plugins/preauth/spake/spake.exports       |    2 +
+ src/plugins/preauth/spake/spake_client.c      |  363 +
+ src/plugins/preauth/spake/spake_kdc.c         |  590 ++
+ src/plugins/preauth/spake/t_krb5.conf         |    2 +
+ src/plugins/preauth/spake/t_vectors.c         |  476 +
+ src/plugins/preauth/spake/trace.h             |   74 +
+ src/plugins/preauth/spake/util.c              |  211 +
+ src/plugins/preauth/spake/util.h              |   56 +
+ src/tests/Makefile.in                         |    1 +
+ src/tests/t_spake.py                          |  151 +
+ 35 files changed, 13917 insertions(+), 4 deletions(-)
+ create mode 100644 doc/admin/spake.rst
+ create mode 100644 src/plugins/preauth/spake/AUTHORS
+ create mode 100644 src/plugins/preauth/spake/Makefile.in
+ create mode 100644 src/plugins/preauth/spake/deps
+ create mode 100644 src/plugins/preauth/spake/edwards25519.c
+ create mode 100644 src/plugins/preauth/spake/edwards25519_tables.h
+ create mode 100644 src/plugins/preauth/spake/groups.c
+ create mode 100644 src/plugins/preauth/spake/groups.h
+ create mode 100644 src/plugins/preauth/spake/iana.c
+ create mode 100644 src/plugins/preauth/spake/iana.h
+ create mode 100644 src/plugins/preauth/spake/openssl.c
+ create mode 100644 src/plugins/preauth/spake/spake.exports
+ create mode 100644 src/plugins/preauth/spake/spake_client.c
+ create mode 100644 src/plugins/preauth/spake/spake_kdc.c
+ create mode 100644 src/plugins/preauth/spake/t_krb5.conf
+ create mode 100644 src/plugins/preauth/spake/t_vectors.c
+ create mode 100644 src/plugins/preauth/spake/trace.h
+ create mode 100644 src/plugins/preauth/spake/util.c
+ create mode 100644 src/plugins/preauth/spake/util.h
+ create mode 100644 src/tests/t_spake.py
+
+diff --git a/NOTICE b/NOTICE
+index 1f2ce6493..cb6ab462b 100644
+--- a/NOTICE
++++ b/NOTICE
+@@ -1316,3 +1316,54 @@ The following notice applies to
+    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 following notice applies to portions of
++"src/plugins/preauth/spake/edwards25519.c" and
++"src/plugins/preauth/spake/edwards25519_tables.h":
++
++The MIT License (MIT)
++
++Copyright (c) 2015-2016 the fiat-crypto authors (see the AUTHORS
++file).
++
++Permission is hereby granted, free of charge, to any person obtaining
++a copy of this software and associated documentation files (the
++"Software"), to deal in the Software without restriction, including
++without limitation the rights to use, copy, modify, merge, publish,
++distribute, sublicense, and/or sell copies of the Software, and to
++permit persons to whom the Software is furnished to do so, subject to
++the following conditions:
++
++The above copyright notice and this permission notice shall be
++included in all copies or substantial portions of the Software.
++
++THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
++EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
++MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
++IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
++CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
++TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
++SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
++
++======================================================================
++
++The following notice applies to portions of
++"src/plugins/preauth/spake/edwards25519.c":
++
++Copyright (c) 2015-2016, Google Inc.
++
++Permission to use, copy, modify, and/or distribute this software for
++any purpose with or without fee is hereby granted, provided that the
++above copyright notice and this permission notice appear in all
++copies.
++
++THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
++WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
++WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
++AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
++DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
++PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
++TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
++PERFORMANCE OF THIS SOFTWARE.
+diff --git a/doc/admin/conf_files/kdc_conf.rst b/doc/admin/conf_files/kdc_conf.rst
+index 1ac1a37c2..f8cf1be7c 100644
+--- a/doc/admin/conf_files/kdc_conf.rst
++++ b/doc/admin/conf_files/kdc_conf.rst
+@@ -43,10 +43,10 @@ The kdc.conf file may contain the following sections:
+ [kdcdefaults]
+ ~~~~~~~~~~~~~
+ 
+-With two exceptions, relations in the [kdcdefaults] section specify
+-default values for realm variables, to be used if the [realms]
+-subsection does not contain a relation for the tag.  See the
+-:ref:`kdc_realms` section for the definitions of these relations.
++Some relations in the [kdcdefaults] section specify default values for
++realm variables, to be used if the [realms] subsection does not
++contain a relation for the tag.  See the :ref:`kdc_realms` section for
++the definitions of these relations.
+ 
+ * **host_based_services**
+ * **kdc_listen**
+@@ -56,6 +56,8 @@ subsection does not contain a relation for the tag.  See the
+ * **no_host_referral**
+ * **restrict_anonymous_to_tgt**
+ 
++The following [kdcdefaults] variables have no per-realm equivalent:
++
+ **kdc_max_dgram_reply_size**
+     Specifies the maximum packet size that can be sent over UDP.  The
+     default value is 4096 bytes.
+@@ -65,6 +67,12 @@ subsection does not contain a relation for the tag.  See the
+     daemon.  The value may be limited by OS settings.  The default
+     value is 5.
+ 
++**spake_preauth_kdc_challenge**
++    (String.)  Specifies the group for a SPAKE optimistic challenge.
++    See the **spake_preauth_groups** variable in :ref:`libdefaults`
++    for possible values.  The default is not to issue an optimistic
++    challenge.  (New in release 1.17.)
++
+ 
+ .. _kdc_realms:
+ 
+@@ -403,6 +411,12 @@ The following tags may be specified in a [realms] subsection:
+     without allowing anonymous authentication to services.  The
+     default value is false.  New in release 1.9.
+ 
++**spake_preauth_indicator**
++    (String.)  Specifies an authentication indicator value that the
++    KDC asserts into tickets obtained using SPAKE pre-authentication.
++    The default is not to add any indicators.  This option may be
++    specified multiple times.  New in release 1.17.
++
+ **supported_enctypes**
+     (List of *key*:*salt* strings.)  Specifies the default key/salt
+     combinations of principals for this realm.  Any principals created
+diff --git a/doc/admin/conf_files/krb5_conf.rst b/doc/admin/conf_files/krb5_conf.rst
+index 3d33dba40..2574e5c26 100644
+--- a/doc/admin/conf_files/krb5_conf.rst
++++ b/doc/admin/conf_files/krb5_conf.rst
+@@ -367,6 +367,21 @@ The libdefaults section may contain any of the following relations:
+     with the session key type.  See the **kdc_req_checksum_type**
+     configuration option for the possible values and their meanings.
+ 
++**spake_preauth_groups**
++    A whitespace or comma-separated list of words which specifies the
++    groups allowed for SPAKE preauthentication.  The possible values
++    are:
++
++    ============ ================================
++    edwards25519 Edwards25519 curve (:rfc:`7748`)
++    P-256        NIST P-256 curve (:rfc:`5480`)
++    P-384        NIST P-384 curve (:rfc:`5480`)
++    P-521        NIST P-521 curve (:rfc:`5480`)
++    ============ ================================
++
++    The default value for the client is ``edwards25519``.  The default
++    value for the KDC is empty.  New in release 1.17.
++
+ **ticket_lifetime**
+     (:ref:`duration` string.)  Sets the default lifetime for initial
+     ticket requests.  The default value is 1 day.
+diff --git a/doc/admin/index.rst b/doc/admin/index.rst
+index b702f4021..292a64104 100644
+--- a/doc/admin/index.rst
++++ b/doc/admin/index.rst
+@@ -15,6 +15,7 @@ For administrators
+    backup_host.rst
+    pkinit.rst
+    otp.rst
++   spake.rst
+    princ_dns.rst
+    enctypes.rst
+    https.rst
+diff --git a/doc/admin/spake.rst b/doc/admin/spake.rst
+new file mode 100644
+index 000000000..b65c694aa
+--- /dev/null
++++ b/doc/admin/spake.rst
+@@ -0,0 +1,46 @@
++SPAKE Preauthentication
++=======================
++
++SPAKE preauthentication (added in release 1.17) uses public key
++cryptography techniques to protect against password dictionary
++attacks.  Unlike :ref:`PKINIT <pkinit>`, it does not require any
++additional infrastructure such as certificates; it simply needs to be
++turned on.  Using SPAKE preauthentication may modestly increase the
++CPU and network load on the KDC.
++
++SPAKE preauthentication can use one of four elliptic curve groups for
++its password-authenticated key exchange.  The recommended group is
++``edwards25519``; three NIST curves (``P-256``, ``P-384``, and
++``P-521``) are also supported.
++
++By default, SPAKE with the ``edwards25519`` group is enabled on
++clients, but the KDC does not offer SPAKE by default.  To turn it on,
++set the **spake_preauth_groups** variable in :ref:`libdefaults` to a
++list of allowed groups.  This variable affects both the client and the
++KDC.  Simply setting it to ``edwards25519`` is recommended::
++
++    [libdefaults]
++        spake_preauth_groups = edwards25519
++
++Set the **+requires_preauth** and **-allow_svr** flags on client
++principal entries, as you would for any preauthentication mechanism::
++
++    kadmin: modprinc +requires_preauth -allow_srv PRINCNAME
++
++Clients which do not implement SPAKE preauthentication will fall back
++to encrypted timestamp.
++
++By default, SPAKE preauthentication requires an extra network round
++trip to the KDC during initial authentication.  If most of the clients
++in a realm support SPAKE, this extra round trip can be eliminated
++using an optimistic challenge, by setting the
++**spake_preauth_kdc_challenge** variable in :ref:`kdcdefaults` to a
++single group name::
++
++    [kdcdefaults]
++        spake_preauth_kdc_challenge = edwards25519
++
++Using optimistic challenge will cause the KDC to do extra work for
++initial authentication requests that do not result in SPAKE
++preauthentication, but will save work when SPAKE preauthentication is
++used.
+diff --git a/doc/formats/cookie.rst b/doc/formats/cookie.rst
+index 640955c90..e32365daa 100644
+--- a/doc/formats/cookie.rst
++++ b/doc/formats/cookie.rst
+@@ -58,3 +58,40 @@ mechanisms which have separate request and reply types, the request
+ type is used; this allows the KDC to determine whether a cookie is
+ relevant to a request by comparing the request pa-data types to the
+ cookie data types.
++
++SPAKE cookie format (version 1)
++-------------------------------
++
++Inside the SecureCookie wrapper, a data value of type 151 contains
++state for SPAKE pre-authentication.  This data is the concatenation of
++the following:
++
++* a two-byte big-endian version number with the value 1
++* a two-byte big-endian stage number
++* a four-byte big-endian group number
++* a four-byte big-endian length and data for the SPAKE value
++* a four-byte big-endian length and data for the transcript hash
++* zero or more second factor records, each consisting of:
++  - a four-byte big-endian second-factor type
++  - a four-byte big-endian length and data
++
++The stage value is 0 if the cookie was sent with a challenge message.
++Otherwise it is 1 for the first encdata message sent by the KDC during
++an exchange, 2 for the second, etc..
++
++The group value indicates the group number used in the SPAKE challenge.
++
++For a stage-0 cookie, the SPAKE value is the KDC private key,
++represented in the scalar marshalling form of the group.  For other
++cookies, the SPAKE value is the SPAKE result K, represented in the
++group element marshalling form.
++
++For a stage-0 cookie, the transcript hash is the intermediate hash
++after updating with the client support message (if one was sent) and
++challenge.  For other cookies it is the final hash.
++
++For a stage-0 cookie, there may be any number of second-factor
++records, including none; a second-factor type need not create a state
++field if it does not need one, and no record is created for SF-NONE.
++For other cookies, there must be exactly one second-factor record
++corresponding to the factor type chosen by the client.
+diff --git a/doc/notice.rst b/doc/notice.rst
+index a32e55529..8f6b68638 100644
+--- a/doc/notice.rst
++++ b/doc/notice.rst
+@@ -1237,3 +1237,50 @@ The following notice applies to
+     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 following notice applies to portions of
++``src/plugins/preauth/spake/edwards25519.c`` and
++``src/plugins/preauth/spake/edwards25519_tables.h``:
++
++The MIT License (MIT)
++
++Copyright (c) 2015-2016 the fiat-crypto authors (see the AUTHORS file).
++
++Permission is hereby granted, free of charge, to any person obtaining a copy
++of this software and associated documentation files (the "Software"), to
++deal in the Software without restriction, including without limitation the
++rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
++sell copies of the Software, and to permit persons to whom the Software is
++furnished to do so, subject to the following conditions:
++
++The above copyright notice and this permission notice shall be included in
++all copies or substantial portions of the Software.
++
++THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
++IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
++FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
++AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
++LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
++FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
++IN THE SOFTWARE.
++
++-------------------
++
++The following notice applies to portions of
++``src/plugins/preauth/spake/edwards25519.c``:
++
++Copyright (c) 2015-2016, Google Inc.
++
++Permission to use, copy, modify, and/or distribute this software for any
++purpose with or without fee is hereby granted, provided that the above
++copyright notice and this permission notice appear in all copies.
++
++THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
++WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
++MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
++SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
++WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
++OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
++CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+diff --git a/src/Makefile.in b/src/Makefile.in
+index ac9a2a060..77beff8bc 100644
+--- a/src/Makefile.in
++++ b/src/Makefile.in
+@@ -25,6 +25,7 @@ SUBDIRS=util include lib \
+ 	plugins/kdcpolicy/test \
+ 	plugins/preauth/otp \
+ 	plugins/preauth/pkinit \
++	plugins/preauth/spake \
+ 	plugins/preauth/test \
+ 	plugins/tls/k5tls \
+ 	kdc kadmin slave clients appl tests \
+@@ -523,6 +524,7 @@ pyrunenv.vals: Makefile
+ 	done > $@
+ 	echo "tls_impl = '$(TLS_IMPL)'" >> $@
+ 	echo "have_sasl = '$(HAVE_SASL)'" >> $@
++	echo "have_spake_openssl = '$(HAVE_SPAKE_OPENSSL)'" >> $@
+ 	echo "sizeof_time_t = $(SIZEOF_TIME_T)" >> $@
+ 
+ runenv.py: pyrunenv.vals
+diff --git a/src/config/pre.in b/src/config/pre.in
+index 03f5c8890..6317d3564 100644
+--- a/src/config/pre.in
++++ b/src/config/pre.in
+@@ -441,9 +441,15 @@ TLS_IMPL	= @TLS_IMPL@
+ TLS_IMPL_CFLAGS = @TLS_IMPL_CFLAGS@
+ TLS_IMPL_LIBS	= @TLS_IMPL_LIBS@
+ 
++# SPAKE preauth back-end libraries
++SPAKE_OPENSSL_LIBS = @SPAKE_OPENSSL_LIBS@
++
+ # Whether we have the SASL header file for the LDAP KDB module
+ HAVE_SASL = @HAVE_SASL@
+ 
++# Whether we are building support for NIST SPAKE groups using OpenSSL
++HAVE_SPAKE_OPENSSL = @HAVE_SPAKE_OPENSSL@
++
+ # Whether we have libresolv 1.1.5 for URI discovery tests
+ HAVE_RESOLV_WRAPPER = @HAVE_RESOLV_WRAPPER@
+ 
+diff --git a/src/configure.in b/src/configure.in
+index 2b6d5baa7..08c63beca 100644
+--- a/src/configure.in
++++ b/src/configure.in
+@@ -321,6 +321,25 @@ AC_SUBST(TLS_IMPL)
+ AC_SUBST(TLS_IMPL_CFLAGS)
+ AC_SUBST(TLS_IMPL_LIBS)
+ 
++# The SPAKE preauth plugin currently supports edwards25519 natively,
++# and can support three NIST groups using OpenSSL.
++HAVE_SPAKE_OPENSSL=no
++AC_ARG_WITH([spake-openssl],
++AC_HELP_STRING([--with-spake-openssl],
++               [use OpenSSL for SPAKE preauth @<:@auto@:>@]),,[withval=auto])
++if test "$withval" = auto -o "$withval" = yes; then
++  AC_CHECK_LIB([crypto],[EC_POINT_new],[have_crypto=true],[have_crypto=false])
++  if test "$have_crypto" = true; then
++    AC_DEFINE(SPAKE_OPENSSL,1,[Define to use OpenSSL for SPAKE preauth])
++    SPAKE_OPENSSL_LIBS=-lcrypto
++    HAVE_SPAKE_OPENSSL=yes
++  elif test "$withval" = yes; then
++    AC_MSG_ERROR([OpenSSL libcrypto not found])
++  fi
++fi
++AC_SUBST(HAVE_SPAKE_OPENSSL)
++AC_SUBST(SPAKE_OPENSSL_LIBS)
++
+ AC_ARG_ENABLE([aesni],
+ AC_HELP_STRING([--disable-aesni],[Do not build with AES-NI support]), ,
+ enable_aesni=check)
+@@ -1440,6 +1459,7 @@ dnl	ccapi ccapi/lib ccapi/lib/unix ccapi/server ccapi/server/unix ccapi/test
+ 	plugins/kdb/test
+ 	plugins/kdcpolicy/test
+ 	plugins/preauth/otp
++	plugins/preauth/spake
+ 	plugins/preauth/test
+ 	plugins/authdata/greet_client
+ 	plugins/authdata/greet_server
+diff --git a/src/include/k5-int.h b/src/include/k5-int.h
+index 69b81a7f7..86b53c76b 100644
+--- a/src/include/k5-int.h
++++ b/src/include/k5-int.h
+@@ -286,6 +286,9 @@ typedef unsigned char   u_char;
+ #define KRB5_CONF_RESTRICT_ANONYMOUS_TO_TGT    "restrict_anonymous_to_tgt"
+ #define KRB5_CONF_SAFE_CHECKSUM_TYPE           "safe_checksum_type"
+ #define KRB5_CONF_SUPPORTED_ENCTYPES           "supported_enctypes"
++#define KRB5_CONF_SPAKE_PREAUTH_INDICATOR      "spake_preauth_indicator"
++#define KRB5_CONF_SPAKE_PREAUTH_KDC_CHALLENGE  "spake_preauth_kdc_challenge"
++#define KRB5_CONF_SPAKE_PREAUTH_GROUPS         "spake_preauth_groups"
+ #define KRB5_CONF_TICKET_LIFETIME              "ticket_lifetime"
+ #define KRB5_CONF_UDP_PREFERENCE_LIMIT         "udp_preference_limit"
+ #define KRB5_CONF_UNLOCKITER                   "unlockiter"
+diff --git a/src/include/krb5/krb5.hin b/src/include/krb5/krb5.hin
+index a650ecece..cea22dcac 100644
+--- a/src/include/krb5/krb5.hin
++++ b/src/include/krb5/krb5.hin
+@@ -1034,6 +1034,7 @@ krb5_c_keyed_checksum_types(krb5_context context, krb5_enctype enctype,
+ #define KRB5_KEYUSAGE_ENC_CHALLENGE_KDC 55
+ #define KRB5_KEYUSAGE_AS_REQ 56
+ #define KRB5_KEYUSAGE_CAMMAC 64
++#define KRB5_KEYUSAGE_SPAKE 65
+ 
+ /* Key usage values 512-1023 are reserved for uses internal to a Kerberos
+  * implementation. */
+@@ -1883,6 +1884,7 @@ krb5_verify_checksum(krb5_context context, krb5_cksumtype ctype,
+ #define KRB5_PADATA_PKINIT_KX           147 /**< RFC 6112 */
+ #define KRB5_ENCPADATA_REQ_ENC_PA_REP   149 /**< RFC 6806 */
+ #define KRB5_PADATA_AS_FRESHNESS        150 /**< RFC 8070 */
++#define KRB5_PADATA_SPAKE               151
+ 
+ #define KRB5_SAM_USE_SAD_AS_KEY         0x80000000
+ #define KRB5_SAM_SEND_ENCRYPTED_SAD     0x40000000
+diff --git a/src/kdc/kdc_preauth.c b/src/kdc/kdc_preauth.c
+index 62ff9a8a7..86b9e2991 100644
+--- a/src/kdc/kdc_preauth.c
++++ b/src/kdc/kdc_preauth.c
+@@ -131,6 +131,8 @@ get_plugin_vtables(krb5_context context,
+                            "preauth");
+     k5_plugin_register_dyn(context, PLUGIN_INTERFACE_KDCPREAUTH, "otp",
+                            "preauth");
++    k5_plugin_register_dyn(context, PLUGIN_INTERFACE_KDCPREAUTH, "spake",
++                           "preauth");
+     k5_plugin_register(context, PLUGIN_INTERFACE_KDCPREAUTH,
+                        "encrypted_challenge",
+                        kdcpreauth_encrypted_challenge_initvt);
+diff --git a/src/lib/krb5/krb/preauth2.c b/src/lib/krb5/krb/preauth2.c
+index 6b96fa135..451e0b7a8 100644
+--- a/src/lib/krb5/krb/preauth2.c
++++ b/src/lib/krb5/krb/preauth2.c
+@@ -132,6 +132,8 @@ k5_init_preauth_context(krb5_context context)
+     /* Auto-register built-in modules. */
+     k5_plugin_register_dyn(context, PLUGIN_INTERFACE_CLPREAUTH, "pkinit",
+                            "preauth");
++    k5_plugin_register_dyn(context, PLUGIN_INTERFACE_CLPREAUTH, "spake",
++                           "preauth");
+     k5_plugin_register(context, PLUGIN_INTERFACE_CLPREAUTH,
+                        "encrypted_challenge",
+                        clpreauth_encrypted_challenge_initvt);
+diff --git a/src/lib/krb5/os/trace.c b/src/lib/krb5/os/trace.c
+index 10b4f0c14..40a9e7b10 100644
+--- a/src/lib/krb5/os/trace.c
++++ b/src/lib/krb5/os/trace.c
+@@ -163,6 +163,7 @@ padata_type_string(krb5_preauthtype type)
+     case KRB5_PADATA_PKINIT_KX: return "PA-PKINIT-KX";
+     case KRB5_ENCPADATA_REQ_ENC_PA_REP: return "PA-REQ-ENC-PA-REP";
+     case KRB5_PADATA_AS_FRESHNESS: return "PA_AS_FRESHNESS";
++    case KRB5_PADATA_SPAKE: return "PA-SPAKE";
+     default: return NULL;
+     }
+ }
+diff --git a/src/plugins/preauth/spake/AUTHORS b/src/plugins/preauth/spake/AUTHORS
+new file mode 100644
+index 000000000..31d71c211
+--- /dev/null
++++ b/src/plugins/preauth/spake/AUTHORS
+@@ -0,0 +1,16 @@
++# This is the official list of fiat-crypto authors for copyright purposes.
++# This file is distinct from the CONTRIBUTORS files.
++# See the latter for an explanation.
++
++# Names should be added to this file as one of
++#     Organization's name
++#     Individual's name <submission email address>
++#     Individual's name <submission email address> <email2> <emailN>
++# See CONTRIBUTORS for the meaning of multiple email addresses.
++
++# Please keep the list sorted.
++
++Andres Erbsen <andreser@mit.edu>
++Google Inc.
++Jade Philipoom <jadep@mit.edu> <jade.philipoom@gmail.com>
++Massachusetts Institute of Technology
+diff --git a/src/plugins/preauth/spake/Makefile.in b/src/plugins/preauth/spake/Makefile.in
+new file mode 100644
+index 000000000..dd1b90730
+--- /dev/null
++++ b/src/plugins/preauth/spake/Makefile.in
+@@ -0,0 +1,39 @@
++mydir=plugins$(S)preauth$(S)spake
++BUILDTOP=$(REL)..$(S)..$(S)..
++MODULE_INSTALL_DIR = $(KRB5_PA_MODULE_DIR)
++
++# Like RUN_TEST, but use t_krb5.conf from this directory.
++RUN_TEST_LOCAL_CONF=$(RUN_SETUP) KRB5_CONFIG=$(srcdir)/t_krb5.conf LC_ALL=C \
++	$(VALGRIND)
++
++LIBBASE=spake
++LIBMAJOR=0
++LIBMINOR=0
++RELDIR=../plugins/preauth/spake
++SHLIB_EXPDEPS=$(KRB5_BASE_DEPLIBS)
++SHLIB_EXPLIBS=$(KRB5_BASE_LIBS) $(SPAKE_OPENSSL_LIBS)
++
++STLIBOBJS=util.o iana.o groups.o openssl.o edwards25519.o \
++	spake_client.o spake_kdc.o
++
++SRCS= \
++	$(srcdir)/util.c \
++	$(srcdir)/iana.c \
++	$(srcdir)/groups.c \
++	$(srcdir)/openssl.c \
++	$(srcdir)/edwards25519.c \
++	$(srcdir)/spake_client.c \
++	$(srcdir)/spake_kdc.c
++
++t_vectors: t_vectors.o $(STLIBOBJS) $(SHLIB_EXPDEPS)
++	$(CC_LINK) -o $@ t_vectors.o $(STLIBOBJS) $(SHLIB_EXPLIBS)
++
++all-unix: all-liblinks
++install-unix: install-libs
++clean-unix:: clean-liblinks clean-libs clean-libobjs
++
++check-unix: t_vectors
++	$(RUN_TEST_LOCAL_CONF) ./t_vectors
++
++@libnover_frag@
++@libobj_frag@
+diff --git a/src/plugins/preauth/spake/deps b/src/plugins/preauth/spake/deps
+new file mode 100644
+index 000000000..ce636af66
+--- /dev/null
++++ b/src/plugins/preauth/spake/deps
+@@ -0,0 +1,73 @@
++#
++# Generated makefile dependencies follow.
++#
++util.so util.po $(OUTPRE)util.$(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 groups.h iana.h \
++  trace.h util.c util.h
++iana.so iana.po $(OUTPRE)iana.$(OBJEXT): iana.c iana.h
++groups.so groups.po $(OUTPRE)groups.$(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 groups.c groups.h \
++  iana.h trace.h
++openssl.so openssl.po $(OUTPRE)openssl.$(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 groups.h iana.h \
++  openssl.c
++edwards25519.so edwards25519.po $(OUTPRE)edwards25519.$(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 \
++  edwards25519.c edwards25519_tables.h groups.h iana.h
++spake_client.so spake_client.po $(OUTPRE)spake_client.$(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-spake.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/clpreauth_plugin.h $(top_srcdir)/include/krb5/plugin.h \
++  $(top_srcdir)/include/port-sockets.h $(top_srcdir)/include/socket-utils.h \
++  groups.h iana.h spake_client.c trace.h util.h
++spake_kdc.so spake_kdc.po $(OUTPRE)spake_kdc.$(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-input.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-spake.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/kdcpreauth_plugin.h \
++  $(top_srcdir)/include/krb5/plugin.h $(top_srcdir)/include/port-sockets.h \
++  $(top_srcdir)/include/socket-utils.h groups.h iana.h \
++  spake_kdc.c trace.h util.h
+diff --git a/src/plugins/preauth/spake/edwards25519.c b/src/plugins/preauth/spake/edwards25519.c
+new file mode 100644
+index 000000000..fd228d9d4
+--- /dev/null
++++ b/src/plugins/preauth/spake/edwards25519.c
+@@ -0,0 +1,2651 @@
++/* -*- mode: c; c-basic-offset: 2; indent-tabs-mode: nil -*- */
++/* This file is adapted from the SPAKE edwards25519 code in BoringSSL. */
++/*
++ * The MIT License (MIT)
++ *
++ * Copyright (c) 2015-2016 the fiat-crypto authors (see the AUTHORS file).
++ *
++ * Permission is hereby granted, free of charge, to any person obtaining a copy
++ * of this software and associated documentation files (the "Software"), to
++ * deal in the Software without restriction, including without limitation the
++ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
++ * sell copies of the Software, and to permit persons to whom the Software is
++ * furnished to do so, subject to the following conditions:
++ *
++ * The above copyright notice and this permission notice shall be included in
++ * all copies or substantial portions of the Software.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
++ * IN THE SOFTWARE.
++ */
++/*
++ * Copyright (c) 2015-2016, Google Inc.
++ *
++ * Permission to use, copy, modify, and/or distribute this software for any
++ * purpose with or without fee is hereby granted, provided that the above
++ * copyright notice and this permission notice appear in all copies.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
++ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
++ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
++ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
++ */
++
++/*
++ * This code is adapted from the BoringSSL edwards25519 SPAKE2 implementation
++ * from third_party/fiat and crypto/spake25519.c, with the following
++ * adaptations:
++ *
++ * - The M and N points are the ones from draft-irtf-cfrg-spake2-05.  The
++ *   BoringSSL M and N points were determined similarly, but were not
++ *   restricted to members of the generator subgroup, so they use only one hash
++ *   iteration for both points.  The intent in BoringSSL had been to multiply w
++ *   by the cofactor so that wM and wN would be in the subgroup, but as that
++ *   step was accidentally omitted, a hack had to be introduced after the fact
++ *   to add multiples of the prime order to the scalar.  That hack is not
++ *   present in this code, and the SPAKE preauth spec does not multiply w by
++ *   the cofactor as it is unnecessary if M and N are chosen from the subgroup.
++ *
++ * - The SPAKE code is modified to fit the groups.h interface and the SPAKE
++ *   preauth spec.
++ *
++ * - The required declarations and code are all here in one file (except for
++ *   the generator point table, which is still in a separate header), so all of
++ *   the functions are declared static.
++ *
++ * - BORINGSSL_CURVE25519_64BIT is defined here using preprocessor conditionals
++ *   derived from the BoringSSL headers.
++ *
++ * - The field element bounds assertion checks are disabled by default, as they
++ *   slow the code down by roughly a factor of two.  The
++ *   OPENSSL_COMPILE_ASSERT() in fe_copy_lt() is changed to a regular assert
++ *   and is also conditionalized.  Do a build and "make check" with
++ *   EDWARDS25519_ASSERTS defined when updating this code.
++ *
++ * - The copyright comments at the top are formatted the way we do so in other
++ *   source files, for ease of extraction.
++ *
++ * - Declarations in for loops conflict with our compiler configuration in
++ *   older versions of gcc, so they are moved outside of the for loop.
++ *
++ * - The preprocessor symbol OPENSSL_SMALL is changed to CONFIG_SMALL.
++ *
++ * - OPENSSL_memset and OPENSSL_memmove are changed to memset and memmove, in
++ *   each case verifying that they are used with nonzero length arguments.
++ *
++ * - CRYPTO_memcmp is changed to k5_bcmp.
++ *
++ * - Functions used only by X25519 or Ed25519 interfaces but not SPAKE are
++ *   removed, taking care to check for unused functions in both the 64-bit and
++ *   32-bit preprocessor branches.  ge_p3_dbl() is unused here if CONFIG_SMALL
++ *   is defined, so it is placed inside #ifndef CONFIG_SMALL.
++ */
++
++// Some of this code is taken from the ref10 version of Ed25519 in SUPERCOP
++// 20141124 (http://bench.cr.yp.to/supercop.html). That code is released as
++// public domain but parts have been replaced with code generated by Fiat
++// (https://github.com/mit-plv/fiat-crypto), which is MIT licensed.
++
++#include "groups.h"
++#include "iana.h"
++
++#ifdef __GNUC__
++#pragma GCC diagnostic ignored "-Wdeclaration-after-statement"
++#endif
++
++/*
++ * These preprocessor conditionals are derived the BoringSSL
++ * include/openssl/base.h (OPENSSL_64_BIT) and crypto/internal.h
++ * (BORINGSSL_HAS_UINT128).
++ */
++#if defined(__x86_64) || defined(_M_AMD64) || defined(_M_X64) || defined(__aarch64__) || ((defined(__PPC64__) || defined(__powerpc64__)) && defined(_LITTLE_ENDIAN)) || defined(__mips__) && defined(__LP64__)
++#if !defined(_MSC_VER) || defined(__clang__)
++#define BORINGSSL_CURVE25519_64BIT
++typedef __int128_t int128_t;
++typedef __uint128_t uint128_t;
++#endif
++#endif
++
++#ifndef EDWARDS25519_ASSERTS
++#define assert_fe(f)
++#define assert_fe_loose(f)
++#define assert_fe_frozen(f)
++#endif
++
++/* From BoringSSL third-party/fiat/internal.h */
++
++#if defined(BORINGSSL_CURVE25519_64BIT)
++// fe means field element. Here the field is \Z/(2^255-19). An element t,
++// entries t[0]...t[4], represents the integer t[0]+2^51 t[1]+2^102 t[2]+2^153
++// t[3]+2^204 t[4].
++// fe limbs are bounded by 1.125*2^51.
++// Multiplication and carrying produce fe from fe_loose.
++typedef struct fe { uint64_t v[5]; } fe;
++
++// fe_loose limbs are bounded by 3.375*2^51.
++// Addition and subtraction produce fe_loose from (fe, fe).
++typedef struct fe_loose { uint64_t v[5]; } fe_loose;
++#else
++// fe means field element. Here the field is \Z/(2^255-19). An element t,
++// entries t[0]...t[9], represents the integer t[0]+2^26 t[1]+2^51 t[2]+2^77
++// t[3]+2^102 t[4]+...+2^230 t[9].
++// fe limbs are bounded by 1.125*2^26,1.125*2^25,1.125*2^26,1.125*2^25,etc.
++// Multiplication and carrying produce fe from fe_loose.
++typedef struct fe { uint32_t v[10]; } fe;
++
++// fe_loose limbs are bounded by 3.375*2^26,3.375*2^25,3.375*2^26,3.375*2^25,etc.
++// Addition and subtraction produce fe_loose from (fe, fe).
++typedef struct fe_loose { uint32_t v[10]; } fe_loose;
++#endif
++
++// ge means group element.
++//
++// Here the group is the set of pairs (x,y) of field elements (see fe.h)
++// satisfying -x^2 + y^2 = 1 + d x^2y^2
++// where d = -121665/121666.
++//
++// Representations:
++//   ge_p2 (projective): (X:Y:Z) satisfying x=X/Z, y=Y/Z
++//   ge_p3 (extended): (X:Y:Z:T) satisfying x=X/Z, y=Y/Z, XY=ZT
++//   ge_p1p1 (completed): ((X:Z),(Y:T)) satisfying x=X/Z, y=Y/T
++//   ge_precomp (Duif): (y+x,y-x,2dxy)
++
++typedef struct {
++  fe X;
++  fe Y;
++  fe Z;
++} ge_p2;
++
++typedef struct {
++  fe X;
++  fe Y;
++  fe Z;
++  fe T;
++} ge_p3;
++
++typedef struct {
++  fe_loose X;
++  fe_loose Y;
++  fe_loose Z;
++  fe_loose T;
++} ge_p1p1;
++
++typedef struct {
++  fe_loose yplusx;
++  fe_loose yminusx;
++  fe_loose xy2d;
++} ge_precomp;
++
++typedef struct {
++  fe_loose YplusX;
++  fe_loose YminusX;
++  fe_loose Z;
++  fe_loose T2d;
++} ge_cached;
++
++#include "edwards25519_tables.h"
++
++/* From BoringSSL third-party/fiat/curve25519.c */
++
++static uint64_t load_3(const uint8_t *in) {
++  uint64_t result;
++  result = (uint64_t)in[0];
++  result |= ((uint64_t)in[1]) << 8;
++  result |= ((uint64_t)in[2]) << 16;
++  return result;
++}
++
++static uint64_t load_4(const uint8_t *in) {
++  uint64_t result;
++  result = (uint64_t)in[0];
++  result |= ((uint64_t)in[1]) << 8;
++  result |= ((uint64_t)in[2]) << 16;
++  result |= ((uint64_t)in[3]) << 24;
++  return result;
++}
++
++#if defined(BORINGSSL_CURVE25519_64BIT)
++static uint64_t load_8(const uint8_t *in) {
++  uint64_t result;
++  result = (uint64_t)in[0];
++  result |= ((uint64_t)in[1]) << 8;
++  result |= ((uint64_t)in[2]) << 16;
++  result |= ((uint64_t)in[3]) << 24;
++  result |= ((uint64_t)in[4]) << 32;
++  result |= ((uint64_t)in[5]) << 40;
++  result |= ((uint64_t)in[6]) << 48;
++  result |= ((uint64_t)in[7]) << 56;
++  return result;
++}
++
++static uint8_t /*bool*/ addcarryx_u51(uint8_t /*bool*/ c, uint64_t a,
++                                      uint64_t b, uint64_t *low) {
++  // This function extracts 51 bits of result and 1 bit of carry (52 total), so
++  // a 64-bit intermediate is sufficient.
++  uint64_t x = a + b + c;
++  *low = x & ((UINT64_C(1) << 51) - 1);
++  return (x >> 51) & 1;
++}
++
++static uint8_t /*bool*/ subborrow_u51(uint8_t /*bool*/ c, uint64_t a,
++                                      uint64_t b, uint64_t *low) {
++  // This function extracts 51 bits of result and 1 bit of borrow (52 total), so
++  // a 64-bit intermediate is sufficient.
++  uint64_t x = a - b - c;
++  *low = x & ((UINT64_C(1) << 51) - 1);
++  return x >> 63;
++}
++
++static uint64_t cmovznz64(uint64_t t, uint64_t z, uint64_t nz) {
++  t = -!!t; // all set if nonzero, 0 if 0
++  return (t&nz) | ((~t)&z);
++}
++
++#else
++
++static uint8_t /*bool*/ addcarryx_u25(uint8_t /*bool*/ c, uint32_t a,
++                                      uint32_t b, uint32_t *low) {
++  // This function extracts 25 bits of result and 1 bit of carry (26 total), so
++  // a 32-bit intermediate is sufficient.
++  uint32_t x = a + b + c;
++  *low = x & ((1 << 25) - 1);
++  return (x >> 25) & 1;
++}
++
++static uint8_t /*bool*/ addcarryx_u26(uint8_t /*bool*/ c, uint32_t a,
++                                      uint32_t b, uint32_t *low) {
++  // This function extracts 26 bits of result and 1 bit of carry (27 total), so
++  // a 32-bit intermediate is sufficient.
++  uint32_t x = a + b + c;
++  *low = x & ((1 << 26) - 1);
++  return (x >> 26) & 1;
++}
++
++static uint8_t /*bool*/ subborrow_u25(uint8_t /*bool*/ c, uint32_t a,
++                                      uint32_t b, uint32_t *low) {
++  // This function extracts 25 bits of result and 1 bit of borrow (26 total), so
++  // a 32-bit intermediate is sufficient.
++  uint32_t x = a - b - c;
++  *low = x & ((1 << 25) - 1);
++  return x >> 31;
++}
++
++static uint8_t /*bool*/ subborrow_u26(uint8_t /*bool*/ c, uint32_t a,
++                                      uint32_t b, uint32_t *low) {
++  // This function extracts 26 bits of result and 1 bit of borrow (27 total), so
++  // a 32-bit intermediate is sufficient.
++  uint32_t x = a - b - c;
++  *low = x & ((1 << 26) - 1);
++  return x >> 31;
++}
++
++static uint32_t cmovznz32(uint32_t t, uint32_t z, uint32_t nz) {
++  t = -!!t; // all set if nonzero, 0 if 0
++  return (t&nz) | ((~t)&z);
++}
++
++#endif
++
++
++// Field operations.
++
++#if defined(BORINGSSL_CURVE25519_64BIT)
++
++#ifdef EDWARDS25519_ASSERTS
++#define assert_fe(f) do { \
++  unsigned _assert_fe_i; \
++  for (_assert_fe_i = 0; _assert_fe_i< 5; _assert_fe_i++) { \
++    assert(f[_assert_fe_i] < 1.125*(UINT64_C(1)<<51)); \
++  } \
++} while (0)
++
++#define assert_fe_loose(f) do { \
++  unsigned _assert_fe_i; \
++  for (_assert_fe_i = 0; _assert_fe_i< 5; _assert_fe_i++) { \
++    assert(f[_assert_fe_i] < 3.375*(UINT64_C(1)<<51)); \
++  } \
++} while (0)
++
++#define assert_fe_frozen(f) do { \
++  unsigned _assert_fe_i; \
++  for (_assert_fe_i = 0; _assert_fe_i< 5; _assert_fe_i++) { \
++    assert(f[_assert_fe_i] < (UINT64_C(1)<<51)); \
++  } \
++} while (0)
++#endif /* EDWARDS25519_ASSERTS */
++
++static void fe_frombytes_impl(uint64_t h[5], const uint8_t *s) {
++  // Ignores top bit of s.
++  uint64_t a0 = load_8(s);
++  uint64_t a1 = load_8(s+8);
++  uint64_t a2 = load_8(s+16);
++  uint64_t a3 = load_8(s+24);
++  // Use 51 bits, 64-51 = 13 left.
++  h[0] = a0 & ((UINT64_C(1) << 51) - 1);
++  // (64-51) + 38 = 13 + 38 = 51
++  h[1] = (a0 >> 51) | ((a1 & ((UINT64_C(1) << 38) - 1)) << 13);
++  // (64-38) + 25 = 26 + 25 = 51
++  h[2] = (a1 >> 38) | ((a2 & ((UINT64_C(1) << 25) - 1)) << 26);
++  // (64-25) + 12 = 39 + 12 = 51
++  h[3] = (a2 >> 25) | ((a3 & ((UINT64_C(1) << 12) - 1)) << 39);
++  // (64-12) = 52, ignore top bit
++  h[4] = (a3 >> 12) & ((UINT64_C(1) << 51) - 1);
++  assert_fe(h);
++}
++
++static void fe_frombytes(fe *h, const uint8_t *s) {
++  fe_frombytes_impl(h->v, s);
++}
++
++static void fe_freeze(uint64_t out[5], const uint64_t in1[5]) {
++  { const uint64_t x7 = in1[4];
++  { const uint64_t x8 = in1[3];
++  { const uint64_t x6 = in1[2];
++  { const uint64_t x4 = in1[1];
++  { const uint64_t x2 = in1[0];
++  { uint64_t x10; uint8_t/*bool*/ x11 = subborrow_u51(0x0, x2, 0x7ffffffffffed, &x10);
++  { uint64_t x13; uint8_t/*bool*/ x14 = subborrow_u51(x11, x4, 0x7ffffffffffff, &x13);
++  { uint64_t x16; uint8_t/*bool*/ x17 = subborrow_u51(x14, x6, 0x7ffffffffffff, &x16);
++  { uint64_t x19; uint8_t/*bool*/ x20 = subborrow_u51(x17, x8, 0x7ffffffffffff, &x19);
++  { uint64_t x22; uint8_t/*bool*/ x23 = subborrow_u51(x20, x7, 0x7ffffffffffff, &x22);
++  { uint64_t x24 = cmovznz64(x23, 0x0, 0xffffffffffffffffL);
++  { uint64_t x25 = (x24 & 0x7ffffffffffed);
++  { uint64_t x27; uint8_t/*bool*/ x28 = addcarryx_u51(0x0, x10, x25, &x27);
++  { uint64_t x29 = (x24 & 0x7ffffffffffff);
++  { uint64_t x31; uint8_t/*bool*/ x32 = addcarryx_u51(x28, x13, x29, &x31);
++  { uint64_t x33 = (x24 & 0x7ffffffffffff);
++  { uint64_t x35; uint8_t/*bool*/ x36 = addcarryx_u51(x32, x16, x33, &x35);
++  { uint64_t x37 = (x24 & 0x7ffffffffffff);
++  { uint64_t x39; uint8_t/*bool*/ x40 = addcarryx_u51(x36, x19, x37, &x39);
++  { uint64_t x41 = (x24 & 0x7ffffffffffff);
++  { uint64_t x43; addcarryx_u51(x40, x22, x41, &x43);
++  out[0] = x27;
++  out[1] = x31;
++  out[2] = x35;
++  out[3] = x39;
++  out[4] = x43;
++  }}}}}}}}}}}}}}}}}}}}}
++}
++
++static void fe_tobytes(uint8_t s[32], const fe *f) {
++  assert_fe(f->v);
++  uint64_t h[5];
++  fe_freeze(h, f->v);
++  assert_fe_frozen(h);
++
++  s[0] = h[0] >> 0;
++  s[1] = h[0] >> 8;
++  s[2] = h[0] >> 16;
++  s[3] = h[0] >> 24;
++  s[4] = h[0] >> 32;
++  s[5] = h[0] >> 40;
++  s[6] = (h[0] >> 48) | (h[1] << 3);
++  s[7] = h[1] >> 5;
++  s[8] = h[1] >> 13;
++  s[9] = h[1] >> 21;
++  s[10] = h[1] >> 29;
++  s[11] = h[1] >> 37;
++  s[12] = (h[1] >> 45) | (h[2] << 6);
++  s[13] = h[2] >> 2;
++  s[14] = h[2] >> 10;
++  s[15] = h[2] >> 18;
++  s[16] = h[2] >> 26;
++  s[17] = h[2] >> 34;
++  s[18] = h[2] >> 42;
++  s[19] = (h[2] >> 50) | (h[3] << 1);
++  s[20] = h[3] >> 7;
++  s[21] = h[3] >> 15;
++  s[22] = h[3] >> 23;
++  s[23] = h[3] >> 31;
++  s[24] = h[3] >> 39;
++  s[25] = (h[3] >> 47) | (h[4] << 4);
++  s[26] = h[4] >> 4;
++  s[27] = h[4] >> 12;
++  s[28] = h[4] >> 20;
++  s[29] = h[4] >> 28;
++  s[30] = h[4] >> 36;
++  s[31] = h[4] >> 44;
++}
++
++// h = 0
++static void fe_0(fe *h) {
++  memset(h, 0, sizeof(fe));
++}
++
++static void fe_loose_0(fe_loose *h) {
++  memset(h, 0, sizeof(fe_loose));
++}
++
++// h = 1
++static void fe_1(fe *h) {
++  memset(h, 0, sizeof(fe));
++  h->v[0] = 1;
++}
++
++static void fe_loose_1(fe_loose *h) {
++  memset(h, 0, sizeof(fe_loose));
++  h->v[0] = 1;
++}
++
++static void fe_add_impl(uint64_t out[5], const uint64_t in1[5], const uint64_t in2[5]) {
++  { const uint64_t x10 = in1[4];
++  { const uint64_t x11 = in1[3];
++  { const uint64_t x9 = in1[2];
++  { const uint64_t x7 = in1[1];
++  { const uint64_t x5 = in1[0];
++  { const uint64_t x18 = in2[4];
++  { const uint64_t x19 = in2[3];
++  { const uint64_t x17 = in2[2];
++  { const uint64_t x15 = in2[1];
++  { const uint64_t x13 = in2[0];
++  out[0] = (x5 + x13);
++  out[1] = (x7 + x15);
++  out[2] = (x9 + x17);
++  out[3] = (x11 + x19);
++  out[4] = (x10 + x18);
++  }}}}}}}}}}
++}
++
++// h = f + g
++// Can overlap h with f or g.
++static void fe_add(fe_loose *h, const fe *f, const fe *g) {
++  assert_fe(f->v);
++  assert_fe(g->v);
++  fe_add_impl(h->v, f->v, g->v);
++  assert_fe_loose(h->v);
++}
++
++static void fe_sub_impl(uint64_t out[5], const uint64_t in1[5], const uint64_t in2[5]) {
++  { const uint64_t x10 = in1[4];
++  { const uint64_t x11 = in1[3];
++  { const uint64_t x9 = in1[2];
++  { const uint64_t x7 = in1[1];
++  { const uint64_t x5 = in1[0];
++  { const uint64_t x18 = in2[4];
++  { const uint64_t x19 = in2[3];
++  { const uint64_t x17 = in2[2];
++  { const uint64_t x15 = in2[1];
++  { const uint64_t x13 = in2[0];
++  out[0] = ((0xfffffffffffda + x5) - x13);
++  out[1] = ((0xffffffffffffe + x7) - x15);
++  out[2] = ((0xffffffffffffe + x9) - x17);
++  out[3] = ((0xffffffffffffe + x11) - x19);
++  out[4] = ((0xffffffffffffe + x10) - x18);
++  }}}}}}}}}}
++}
++
++// h = f - g
++// Can overlap h with f or g.
++static void fe_sub(fe_loose *h, const fe *f, const fe *g) {
++  assert_fe(f->v);
++  assert_fe(g->v);
++  fe_sub_impl(h->v, f->v, g->v);
++  assert_fe_loose(h->v);
++}
++
++static void fe_carry_impl(uint64_t out[5], const uint64_t in1[5]) {
++  { const uint64_t x7 = in1[4];
++  { const uint64_t x8 = in1[3];
++  { const uint64_t x6 = in1[2];
++  { const uint64_t x4 = in1[1];
++  { const uint64_t x2 = in1[0];
++  { uint64_t x9 = (x2 >> 0x33);
++  { uint64_t x10 = (x2 & 0x7ffffffffffff);
++  { uint64_t x11 = (x9 + x4);
++  { uint64_t x12 = (x11 >> 0x33);
++  { uint64_t x13 = (x11 & 0x7ffffffffffff);
++  { uint64_t x14 = (x12 + x6);
++  { uint64_t x15 = (x14 >> 0x33);
++  { uint64_t x16 = (x14 & 0x7ffffffffffff);
++  { uint64_t x17 = (x15 + x8);
++  { uint64_t x18 = (x17 >> 0x33);
++  { uint64_t x19 = (x17 & 0x7ffffffffffff);
++  { uint64_t x20 = (x18 + x7);
++  { uint64_t x21 = (x20 >> 0x33);
++  { uint64_t x22 = (x20 & 0x7ffffffffffff);
++  { uint64_t x23 = (x10 + (0x13 * x21));
++  { uint64_t x24 = (x23 >> 0x33);
++  { uint64_t x25 = (x23 & 0x7ffffffffffff);
++  { uint64_t x26 = (x24 + x13);
++  { uint64_t x27 = (x26 >> 0x33);
++  { uint64_t x28 = (x26 & 0x7ffffffffffff);
++  out[0] = x25;
++  out[1] = x28;
++  out[2] = (x27 + x16);
++  out[3] = x19;
++  out[4] = x22;
++  }}}}}}}}}}}}}}}}}}}}}}}}}
++}
++
++static void fe_carry(fe *h, const fe_loose* f) {
++  assert_fe_loose(f->v);
++  fe_carry_impl(h->v, f->v);
++  assert_fe(h->v);
++}
++
++static void fe_mul_impl(uint64_t out[5], const uint64_t in1[5], const uint64_t in2[5]) {
++  assert_fe_loose(in1);
++  assert_fe_loose(in2);
++  { const uint64_t x10 = in1[4];
++  { const uint64_t x11 = in1[3];
++  { const uint64_t x9 = in1[2];
++  { const uint64_t x7 = in1[1];
++  { const uint64_t x5 = in1[0];
++  { const uint64_t x18 = in2[4];
++  { const uint64_t x19 = in2[3];
++  { const uint64_t x17 = in2[2];
++  { const uint64_t x15 = in2[1];
++  { const uint64_t x13 = in2[0];
++  { uint128_t x20 = ((uint128_t)x5 * x13);
++  { uint128_t x21 = (((uint128_t)x5 * x15) + ((uint128_t)x7 * x13));
++  { uint128_t x22 = ((((uint128_t)x5 * x17) + ((uint128_t)x9 * x13)) + ((uint128_t)x7 * x15));
++  { uint128_t x23 = (((((uint128_t)x5 * x19) + ((uint128_t)x11 * x13)) + ((uint128_t)x7 * x17)) + ((uint128_t)x9 * x15));
++  { uint128_t x24 = ((((((uint128_t)x5 * x18) + ((uint128_t)x10 * x13)) + ((uint128_t)x11 * x15)) + ((uint128_t)x7 * x19)) + ((uint128_t)x9 * x17));
++  { uint64_t x25 = (x10 * 0x13);
++  { uint64_t x26 = (x7 * 0x13);
++  { uint64_t x27 = (x9 * 0x13);
++  { uint64_t x28 = (x11 * 0x13);
++  { uint128_t x29 = ((((x20 + ((uint128_t)x25 * x15)) + ((uint128_t)x26 * x18)) + ((uint128_t)x27 * x19)) + ((uint128_t)x28 * x17));
++  { uint128_t x30 = (((x21 + ((uint128_t)x25 * x17)) + ((uint128_t)x27 * x18)) + ((uint128_t)x28 * x19));
++  { uint128_t x31 = ((x22 + ((uint128_t)x25 * x19)) + ((uint128_t)x28 * x18));
++  { uint128_t x32 = (x23 + ((uint128_t)x25 * x18));
++  { uint64_t x33 = (uint64_t) (x29 >> 0x33);
++  { uint64_t x34 = ((uint64_t)x29 & 0x7ffffffffffff);
++  { uint128_t x35 = (x33 + x30);
++  { uint64_t x36 = (uint64_t) (x35 >> 0x33);
++  { uint64_t x37 = ((uint64_t)x35 & 0x7ffffffffffff);
++  { uint128_t x38 = (x36 + x31);
++  { uint64_t x39 = (uint64_t) (x38 >> 0x33);
++  { uint64_t x40 = ((uint64_t)x38 & 0x7ffffffffffff);
++  { uint128_t x41 = (x39 + x32);
++  { uint64_t x42 = (uint64_t) (x41 >> 0x33);
++  { uint64_t x43 = ((uint64_t)x41 & 0x7ffffffffffff);
++  { uint128_t x44 = (x42 + x24);
++  { uint64_t x45 = (uint64_t) (x44 >> 0x33);
++  { uint64_t x46 = ((uint64_t)x44 & 0x7ffffffffffff);
++  { uint64_t x47 = (x34 + (0x13 * x45));
++  { uint64_t x48 = (x47 >> 0x33);
++  { uint64_t x49 = (x47 & 0x7ffffffffffff);
++  { uint64_t x50 = (x48 + x37);
++  { uint64_t x51 = (x50 >> 0x33);
++  { uint64_t x52 = (x50 & 0x7ffffffffffff);
++  out[0] = x49;
++  out[1] = x52;
++  out[2] = (x51 + x40);
++  out[3] = x43;
++  out[4] = x46;
++  }}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}
++  assert_fe(out);
++}
++
++static void fe_mul_ltt(fe_loose *h, const fe *f, const fe *g) {
++  fe_mul_impl(h->v, f->v, g->v);
++}
++
++static void fe_mul_llt(fe_loose *h, const fe_loose *f, const fe *g) {
++  fe_mul_impl(h->v, f->v, g->v);
++}
++
++static void fe_mul_ttt(fe *h, const fe *f, const fe *g) {
++  fe_mul_impl(h->v, f->v, g->v);
++}
++
++static void fe_mul_tlt(fe *h, const fe_loose *f, const fe *g) {
++  fe_mul_impl(h->v, f->v, g->v);
++}
++
++static void fe_mul_ttl(fe *h, const fe *f, const fe_loose *g) {
++  fe_mul_impl(h->v, f->v, g->v);
++}
++
++static void fe_mul_tll(fe *h, const fe_loose *f, const fe_loose *g) {
++  fe_mul_impl(h->v, f->v, g->v);
++}
++
++static void fe_sqr_impl(uint64_t out[5], const uint64_t in1[5]) {
++  assert_fe_loose(in1);
++  { const uint64_t x7 = in1[4];
++  { const uint64_t x8 = in1[3];
++  { const uint64_t x6 = in1[2];
++  { const uint64_t x4 = in1[1];
++  { const uint64_t x2 = in1[0];
++  { uint64_t x9 = (x2 * 0x2);
++  { uint64_t x10 = (x4 * 0x2);
++  { uint64_t x11 = ((x6 * 0x2) * 0x13);
++  { uint64_t x12 = (x7 * 0x13);
++  { uint64_t x13 = (x12 * 0x2);
++  { uint128_t x14 = ((((uint128_t)x2 * x2) + ((uint128_t)x13 * x4)) + ((uint128_t)x11 * x8));
++  { uint128_t x15 = ((((uint128_t)x9 * x4) + ((uint128_t)x13 * x6)) + ((uint128_t)x8 * (x8 * 0x13)));
++  { uint128_t x16 = ((((uint128_t)x9 * x6) + ((uint128_t)x4 * x4)) + ((uint128_t)x13 * x8));
++  { uint128_t x17 = ((((uint128_t)x9 * x8) + ((uint128_t)x10 * x6)) + ((uint128_t)x7 * x12));
++  { uint128_t x18 = ((((uint128_t)x9 * x7) + ((uint128_t)x10 * x8)) + ((uint128_t)x6 * x6));
++  { uint64_t x19 = (uint64_t) (x14 >> 0x33);
++  { uint64_t x20 = ((uint64_t)x14 & 0x7ffffffffffff);
++  { uint128_t x21 = (x19 + x15);
++  { uint64_t x22 = (uint64_t) (x21 >> 0x33);
++  { uint64_t x23 = ((uint64_t)x21 & 0x7ffffffffffff);
++  { uint128_t x24 = (x22 + x16);
++  { uint64_t x25 = (uint64_t) (x24 >> 0x33);
++  { uint64_t x26 = ((uint64_t)x24 & 0x7ffffffffffff);
++  { uint128_t x27 = (x25 + x17);
++  { uint64_t x28 = (uint64_t) (x27 >> 0x33);
++  { uint64_t x29 = ((uint64_t)x27 & 0x7ffffffffffff);
++  { uint128_t x30 = (x28 + x18);
++  { uint64_t x31 = (uint64_t) (x30 >> 0x33);
++  { uint64_t x32 = ((uint64_t)x30 & 0x7ffffffffffff);
++  { uint64_t x33 = (x20 + (0x13 * x31));
++  { uint64_t x34 = (x33 >> 0x33);
++  { uint64_t x35 = (x33 & 0x7ffffffffffff);
++  { uint64_t x36 = (x34 + x23);
++  { uint64_t x37 = (x36 >> 0x33);
++  { uint64_t x38 = (x36 & 0x7ffffffffffff);
++  out[0] = x35;
++  out[1] = x38;
++  out[2] = (x37 + x26);
++  out[3] = x29;
++  out[4] = x32;
++  }}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}
++  assert_fe(out);
++}
++
++static void fe_sq_tl(fe *h, const fe_loose *f) {
++  fe_sqr_impl(h->v, f->v);
++}
++
++static void fe_sq_tt(fe *h, const fe *f) {
++  fe_sqr_impl(h->v, f->v);
++}
++
++// Adapted from Fiat-synthesized |fe_sub_impl| with |out| = 0.
++static void fe_neg_impl(uint64_t out[5], const uint64_t in2[5]) {
++  { const uint64_t x10 = 0;
++  { const uint64_t x11 = 0;
++  { const uint64_t x9 = 0;
++  { const uint64_t x7 = 0;
++  { const uint64_t x5 = 0;
++  { const uint64_t x18 = in2[4];
++  { const uint64_t x19 = in2[3];
++  { const uint64_t x17 = in2[2];
++  { const uint64_t x15 = in2[1];
++  { const uint64_t x13 = in2[0];
++  out[0] = ((0xfffffffffffda + x5) - x13);
++  out[1] = ((0xffffffffffffe + x7) - x15);
++  out[2] = ((0xffffffffffffe + x9) - x17);
++  out[3] = ((0xffffffffffffe + x11) - x19);
++  out[4] = ((0xffffffffffffe + x10) - x18);
++  }}}}}}}}}}
++}
++
++// h = -f
++static void fe_neg(fe_loose *h, const fe *f) {
++  assert_fe(f->v);
++  fe_neg_impl(h->v, f->v);
++  assert_fe_loose(h->v);
++}
++
++// Replace (f,g) with (g,g) if b == 1;
++// replace (f,g) with (f,g) if b == 0.
++//
++// Preconditions: b in {0,1}.
++static void fe_cmov(fe_loose *f, const fe_loose *g, uint64_t b) {
++  unsigned i;
++  b = 0-b;
++  for (i = 0; i < 5; i++) {
++    uint64_t x = f->v[i] ^ g->v[i];
++    x &= b;
++    f->v[i] ^= x;
++  }
++}
++
++#else
++
++#ifdef EDWARDS25519_ASSERTS
++#define assert_fe(f) do { \
++  unsigned _assert_fe_i; \
++  for (_assert_fe_i = 0; _assert_fe_i< 10; _assert_fe_i++) { \
++    assert(f[_assert_fe_i] < 1.125*(1<<(26-(_assert_fe_i&1)))); \
++  } \
++} while (0)
++
++#define assert_fe_loose(f) do { \
++  unsigned _assert_fe_i; \
++  for (_assert_fe_i = 0; _assert_fe_i< 10; _assert_fe_i++) { \
++    assert(f[_assert_fe_i] < 3.375*(1<<(26-(_assert_fe_i&1)))); \
++  } \
++} while (0)
++
++#define assert_fe_frozen(f) do { \
++  unsigned _assert_fe_i; \
++  for (_assert_fe_i = 0; _assert_fe_i< 10; _assert_fe_i++) { \
++    assert(f[_assert_fe_i] < (1u<<(26-(_assert_fe_i&1)))); \
++  } \
++} while (0)
++#endif /* EDWARDS25519_ASSERTS */
++
++static void fe_frombytes_impl(uint32_t h[10], const uint8_t *s) {
++  // Ignores top bit of s.
++  uint32_t a0 = load_4(s);
++  uint32_t a1 = load_4(s+4);
++  uint32_t a2 = load_4(s+8);
++  uint32_t a3 = load_4(s+12);
++  uint32_t a4 = load_4(s+16);
++  uint32_t a5 = load_4(s+20);
++  uint32_t a6 = load_4(s+24);
++  uint32_t a7 = load_4(s+28);
++  h[0] = a0&((1<<26)-1);                    // 26 used, 32-26 left.   26
++  h[1] = (a0>>26) | ((a1&((1<<19)-1))<< 6); // (32-26) + 19 =  6+19 = 25
++  h[2] = (a1>>19) | ((a2&((1<<13)-1))<<13); // (32-19) + 13 = 13+13 = 26
++  h[3] = (a2>>13) | ((a3&((1<< 6)-1))<<19); // (32-13) +  6 = 19+ 6 = 25
++  h[4] = (a3>> 6);                          // (32- 6)              = 26
++  h[5] = a4&((1<<25)-1);                    //                        25
++  h[6] = (a4>>25) | ((a5&((1<<19)-1))<< 7); // (32-25) + 19 =  7+19 = 26
++  h[7] = (a5>>19) | ((a6&((1<<12)-1))<<13); // (32-19) + 12 = 13+12 = 25
++  h[8] = (a6>>12) | ((a7&((1<< 6)-1))<<20); // (32-12) +  6 = 20+ 6 = 26
++  h[9] = (a7>> 6)&((1<<25)-1); //                                     25
++  assert_fe(h);
++}
++
++static void fe_frombytes(fe *h, const uint8_t *s) {
++  fe_frombytes_impl(h->v, s);
++}
++
++static void fe_freeze(uint32_t out[10], const uint32_t in1[10]) {
++  { const uint32_t x17 = in1[9];
++  { const uint32_t x18 = in1[8];
++  { const uint32_t x16 = in1[7];
++  { const uint32_t x14 = in1[6];
++  { const uint32_t x12 = in1[5];
++  { const uint32_t x10 = in1[4];
++  { const uint32_t x8 = in1[3];
++  { const uint32_t x6 = in1[2];
++  { const uint32_t x4 = in1[1];
++  { const uint32_t x2 = in1[0];
++  { uint32_t x20; uint8_t/*bool*/ x21 = subborrow_u26(0x0, x2, 0x3ffffed, &x20);
++  { uint32_t x23; uint8_t/*bool*/ x24 = subborrow_u25(x21, x4, 0x1ffffff, &x23);
++  { uint32_t x26; uint8_t/*bool*/ x27 = subborrow_u26(x24, x6, 0x3ffffff, &x26);
++  { uint32_t x29; uint8_t/*bool*/ x30 = subborrow_u25(x27, x8, 0x1ffffff, &x29);
++  { uint32_t x32; uint8_t/*bool*/ x33 = subborrow_u26(x30, x10, 0x3ffffff, &x32);
++  { uint32_t x35; uint8_t/*bool*/ x36 = subborrow_u25(x33, x12, 0x1ffffff, &x35);
++  { uint32_t x38; uint8_t/*bool*/ x39 = subborrow_u26(x36, x14, 0x3ffffff, &x38);
++  { uint32_t x41; uint8_t/*bool*/ x42 = subborrow_u25(x39, x16, 0x1ffffff, &x41);
++  { uint32_t x44; uint8_t/*bool*/ x45 = subborrow_u26(x42, x18, 0x3ffffff, &x44);
++  { uint32_t x47; uint8_t/*bool*/ x48 = subborrow_u25(x45, x17, 0x1ffffff, &x47);
++  { uint32_t x49 = cmovznz32(x48, 0x0, 0xffffffff);
++  { uint32_t x50 = (x49 & 0x3ffffed);
++  { uint32_t x52; uint8_t/*bool*/ x53 = addcarryx_u26(0x0, x20, x50, &x52);
++  { uint32_t x54 = (x49 & 0x1ffffff);
++  { uint32_t x56; uint8_t/*bool*/ x57 = addcarryx_u25(x53, x23, x54, &x56);
++  { uint32_t x58 = (x49 & 0x3ffffff);
++  { uint32_t x60; uint8_t/*bool*/ x61 = addcarryx_u26(x57, x26, x58, &x60);
++  { uint32_t x62 = (x49 & 0x1ffffff);
++  { uint32_t x64; uint8_t/*bool*/ x65 = addcarryx_u25(x61, x29, x62, &x64);
++  { uint32_t x66 = (x49 & 0x3ffffff);
++  { uint32_t x68; uint8_t/*bool*/ x69 = addcarryx_u26(x65, x32, x66, &x68);
++  { uint32_t x70 = (x49 & 0x1ffffff);
++  { uint32_t x72; uint8_t/*bool*/ x73 = addcarryx_u25(x69, x35, x70, &x72);
++  { uint32_t x74 = (x49 & 0x3ffffff);
++  { uint32_t x76; uint8_t/*bool*/ x77 = addcarryx_u26(x73, x38, x74, &x76);
++  { uint32_t x78 = (x49 & 0x1ffffff);
++  { uint32_t x80; uint8_t/*bool*/ x81 = addcarryx_u25(x77, x41, x78, &x80);
++  { uint32_t x82 = (x49 & 0x3ffffff);
++  { uint32_t x84; uint8_t/*bool*/ x85 = addcarryx_u26(x81, x44, x82, &x84);
++  { uint32_t x86 = (x49 & 0x1ffffff);
++  { uint32_t x88; addcarryx_u25(x85, x47, x86, &x88);
++  out[0] = x52;
++  out[1] = x56;
++  out[2] = x60;
++  out[3] = x64;
++  out[4] = x68;
++  out[5] = x72;
++  out[6] = x76;
++  out[7] = x80;
++  out[8] = x84;
++  out[9] = x88;
++  }}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}
++}
++
++static void fe_tobytes(uint8_t s[32], const fe *f) {
++  assert_fe(f->v);
++  uint32_t h[10];
++  fe_freeze(h, f->v);
++  assert_fe_frozen(h);
++
++  s[0] = h[0] >> 0;
++  s[1] = h[0] >> 8;
++  s[2] = h[0] >> 16;
++  s[3] = (h[0] >> 24) | (h[1] << 2);
++  s[4] = h[1] >> 6;
++  s[5] = h[1] >> 14;
++  s[6] = (h[1] >> 22) | (h[2] << 3);
++  s[7] = h[2] >> 5;
++  s[8] = h[2] >> 13;
++  s[9] = (h[2] >> 21) | (h[3] << 5);
++  s[10] = h[3] >> 3;
++  s[11] = h[3] >> 11;
++  s[12] = (h[3] >> 19) | (h[4] << 6);
++  s[13] = h[4] >> 2;
++  s[14] = h[4] >> 10;
++  s[15] = h[4] >> 18;
++  s[16] = h[5] >> 0;
++  s[17] = h[5] >> 8;
++  s[18] = h[5] >> 16;
++  s[19] = (h[5] >> 24) | (h[6] << 1);
++  s[20] = h[6] >> 7;
++  s[21] = h[6] >> 15;
++  s[22] = (h[6] >> 23) | (h[7] << 3);
++  s[23] = h[7] >> 5;
++  s[24] = h[7] >> 13;
++  s[25] = (h[7] >> 21) | (h[8] << 4);
++  s[26] = h[8] >> 4;
++  s[27] = h[8] >> 12;
++  s[28] = (h[8] >> 20) | (h[9] << 6);
++  s[29] = h[9] >> 2;
++  s[30] = h[9] >> 10;
++  s[31] = h[9] >> 18;
++}
++
++// h = 0
++static void fe_0(fe *h) {
++  memset(h, 0, sizeof(fe));
++}
++
++static void fe_loose_0(fe_loose *h) {
++  memset(h, 0, sizeof(fe_loose));
++}
++
++// h = 1
++static void fe_1(fe *h) {
++  memset(h, 0, sizeof(fe));
++  h->v[0] = 1;
++}
++
++static void fe_loose_1(fe_loose *h) {
++  memset(h, 0, sizeof(fe_loose));
++  h->v[0] = 1;
++}
++
++static void fe_add_impl(uint32_t out[10], const uint32_t in1[10], const uint32_t in2[10]) {
++  { const uint32_t x20 = in1[9];
++  { const uint32_t x21 = in1[8];
++  { const uint32_t x19 = in1[7];
++  { const uint32_t x17 = in1[6];
++  { const uint32_t x15 = in1[5];
++  { const uint32_t x13 = in1[4];
++  { const uint32_t x11 = in1[3];
++  { const uint32_t x9 = in1[2];
++  { const uint32_t x7 = in1[1];
++  { const uint32_t x5 = in1[0];
++  { const uint32_t x38 = in2[9];
++  { const uint32_t x39 = in2[8];
++  { const uint32_t x37 = in2[7];
++  { const uint32_t x35 = in2[6];
++  { const uint32_t x33 = in2[5];
++  { const uint32_t x31 = in2[4];
++  { const uint32_t x29 = in2[3];
++  { const uint32_t x27 = in2[2];
++  { const uint32_t x25 = in2[1];
++  { const uint32_t x23 = in2[0];
++  out[0] = (x5 + x23);
++  out[1] = (x7 + x25);
++  out[2] = (x9 + x27);
++  out[3] = (x11 + x29);
++  out[4] = (x13 + x31);
++  out[5] = (x15 + x33);
++  out[6] = (x17 + x35);
++  out[7] = (x19 + x37);
++  out[8] = (x21 + x39);
++  out[9] = (x20 + x38);
++  }}}}}}}}}}}}}}}}}}}}
++}
++
++// h = f + g
++// Can overlap h with f or g.
++static void fe_add(fe_loose *h, const fe *f, const fe *g) {
++  assert_fe(f->v);
++  assert_fe(g->v);
++  fe_add_impl(h->v, f->v, g->v);
++  assert_fe_loose(h->v);
++}
++
++static void fe_sub_impl(uint32_t out[10], const uint32_t in1[10], const uint32_t in2[10]) {
++  { const uint32_t x20 = in1[9];
++  { const uint32_t x21 = in1[8];
++  { const uint32_t x19 = in1[7];
++  { const uint32_t x17 = in1[6];
++  { const uint32_t x15 = in1[5];
++  { const uint32_t x13 = in1[4];
++  { const uint32_t x11 = in1[3];
++  { const uint32_t x9 = in1[2];
++  { const uint32_t x7 = in1[1];
++  { const uint32_t x5 = in1[0];
++  { const uint32_t x38 = in2[9];
++  { const uint32_t x39 = in2[8];
++  { const uint32_t x37 = in2[7];
++  { const uint32_t x35 = in2[6];
++  { const uint32_t x33 = in2[5];
++  { const uint32_t x31 = in2[4];
++  { const uint32_t x29 = in2[3];
++  { const uint32_t x27 = in2[2];
++  { const uint32_t x25 = in2[1];
++  { const uint32_t x23 = in2[0];
++  out[0] = ((0x7ffffda + x5) - x23);
++  out[1] = ((0x3fffffe + x7) - x25);
++  out[2] = ((0x7fffffe + x9) - x27);
++  out[3] = ((0x3fffffe + x11) - x29);
++  out[4] = ((0x7fffffe + x13) - x31);
++  out[5] = ((0x3fffffe + x15) - x33);
++  out[6] = ((0x7fffffe + x17) - x35);
++  out[7] = ((0x3fffffe + x19) - x37);
++  out[8] = ((0x7fffffe + x21) - x39);
++  out[9] = ((0x3fffffe + x20) - x38);
++  }}}}}}}}}}}}}}}}}}}}
++}
++
++// h = f - g
++// Can overlap h with f or g.
++static void fe_sub(fe_loose *h, const fe *f, const fe *g) {
++  assert_fe(f->v);
++  assert_fe(g->v);
++  fe_sub_impl(h->v, f->v, g->v);
++  assert_fe_loose(h->v);
++}
++
++static void fe_carry_impl(uint32_t out[10], const uint32_t in1[10]) {
++  { const uint32_t x17 = in1[9];
++  { const uint32_t x18 = in1[8];
++  { const uint32_t x16 = in1[7];
++  { const uint32_t x14 = in1[6];
++  { const uint32_t x12 = in1[5];
++  { const uint32_t x10 = in1[4];
++  { const uint32_t x8 = in1[3];
++  { const uint32_t x6 = in1[2];
++  { const uint32_t x4 = in1[1];
++  { const uint32_t x2 = in1[0];
++  { uint32_t x19 = (x2 >> 0x1a);
++  { uint32_t x20 = (x2 & 0x3ffffff);
++  { uint32_t x21 = (x19 + x4);
++  { uint32_t x22 = (x21 >> 0x19);
++  { uint32_t x23 = (x21 & 0x1ffffff);
++  { uint32_t x24 = (x22 + x6);
++  { uint32_t x25 = (x24 >> 0x1a);
++  { uint32_t x26 = (x24 & 0x3ffffff);
++  { uint32_t x27 = (x25 + x8);
++  { uint32_t x28 = (x27 >> 0x19);
++  { uint32_t x29 = (x27 & 0x1ffffff);
++  { uint32_t x30 = (x28 + x10);
++  { uint32_t x31 = (x30 >> 0x1a);
++  { uint32_t x32 = (x30 & 0x3ffffff);
++  { uint32_t x33 = (x31 + x12);
++  { uint32_t x34 = (x33 >> 0x19);
++  { uint32_t x35 = (x33 & 0x1ffffff);
++  { uint32_t x36 = (x34 + x14);
++  { uint32_t x37 = (x36 >> 0x1a);
++  { uint32_t x38 = (x36 & 0x3ffffff);
++  { uint32_t x39 = (x37 + x16);
++  { uint32_t x40 = (x39 >> 0x19);
++  { uint32_t x41 = (x39 & 0x1ffffff);
++  { uint32_t x42 = (x40 + x18);
++  { uint32_t x43 = (x42 >> 0x1a);
++  { uint32_t x44 = (x42 & 0x3ffffff);
++  { uint32_t x45 = (x43 + x17);
++  { uint32_t x46 = (x45 >> 0x19);
++  { uint32_t x47 = (x45 & 0x1ffffff);
++  { uint32_t x48 = (x20 + (0x13 * x46));
++  { uint32_t x49 = (x48 >> 0x1a);
++  { uint32_t x50 = (x48 & 0x3ffffff);
++  { uint32_t x51 = (x49 + x23);
++  { uint32_t x52 = (x51 >> 0x19);
++  { uint32_t x53 = (x51 & 0x1ffffff);
++  out[0] = x50;
++  out[1] = x53;
++  out[2] = (x52 + x26);
++  out[3] = x29;
++  out[4] = x32;
++  out[5] = x35;
++  out[6] = x38;
++  out[7] = x41;
++  out[8] = x44;
++  out[9] = x47;
++  }}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}
++}
++
++static void fe_carry(fe *h, const fe_loose* f) {
++  assert_fe_loose(f->v);
++  fe_carry_impl(h->v, f->v);
++  assert_fe(h->v);
++}
++
++static void fe_mul_impl(uint32_t out[10], const uint32_t in1[10], const uint32_t in2[10]) {
++  assert_fe_loose(in1);
++  assert_fe_loose(in2);
++  { const uint32_t x20 = in1[9];
++  { const uint32_t x21 = in1[8];
++  { const uint32_t x19 = in1[7];
++  { const uint32_t x17 = in1[6];
++  { const uint32_t x15 = in1[5];
++  { const uint32_t x13 = in1[4];
++  { const uint32_t x11 = in1[3];
++  { const uint32_t x9 = in1[2];
++  { const uint32_t x7 = in1[1];
++  { const uint32_t x5 = in1[0];
++  { const uint32_t x38 = in2[9];
++  { const uint32_t x39 = in2[8];
++  { const uint32_t x37 = in2[7];
++  { const uint32_t x35 = in2[6];
++  { const uint32_t x33 = in2[5];
++  { const uint32_t x31 = in2[4];
++  { const uint32_t x29 = in2[3];
++  { const uint32_t x27 = in2[2];
++  { const uint32_t x25 = in2[1];
++  { const uint32_t x23 = in2[0];
++  { uint64_t x40 = ((uint64_t)x23 * x5);
++  { uint64_t x41 = (((uint64_t)x23 * x7) + ((uint64_t)x25 * x5));
++  { uint64_t x42 = ((((uint64_t)(0x2 * x25) * x7) + ((uint64_t)x23 * x9)) + ((uint64_t)x27 * x5));
++  { uint64_t x43 = (((((uint64_t)x25 * x9) + ((uint64_t)x27 * x7)) + ((uint64_t)x23 * x11)) + ((uint64_t)x29 * x5));
++  { uint64_t x44 = (((((uint64_t)x27 * x9) + (0x2 * (((uint64_t)x25 * x11) + ((uint64_t)x29 * x7)))) + ((uint64_t)x23 * x13)) + ((uint64_t)x31 * x5));
++  { uint64_t x45 = (((((((uint64_t)x27 * x11) + ((uint64_t)x29 * x9)) + ((uint64_t)x25 * x13)) + ((uint64_t)x31 * x7)) + ((uint64_t)x23 * x15)) + ((uint64_t)x33 * x5));
++  { uint64_t x46 = (((((0x2 * ((((uint64_t)x29 * x11) + ((uint64_t)x25 * x15)) + ((uint64_t)x33 * x7))) + ((uint64_t)x27 * x13)) + ((uint64_t)x31 * x9)) + ((uint64_t)x23 * x17)) + ((uint64_t)x35 * x5));
++  { uint64_t x47 = (((((((((uint64_t)x29 * x13) + ((uint64_t)x31 * x11)) + ((uint64_t)x27 * x15)) + ((uint64_t)x33 * x9)) + ((uint64_t)x25 * x17)) + ((uint64_t)x35 * x7)) + ((uint64_t)x23 * x19)) + ((uint64_t)x37 * x5));
++  { uint64_t x48 = (((((((uint64_t)x31 * x13) + (0x2 * (((((uint64_t)x29 * x15) + ((uint64_t)x33 * x11)) + ((uint64_t)x25 * x19)) + ((uint64_t)x37 * x7)))) + ((uint64_t)x27 * x17)) + ((uint64_t)x35 * x9)) + ((uint64_t)x23 * x21)) + ((uint64_t)x39 * x5));
++  { uint64_t x49 = (((((((((((uint64_t)x31 * x15) + ((uint64_t)x33 * x13)) + ((uint64_t)x29 * x17)) + ((uint64_t)x35 * x11)) + ((uint64_t)x27 * x19)) + ((uint64_t)x37 * x9)) + ((uint64_t)x25 * x21)) + ((uint64_t)x39 * x7)) + ((uint64_t)x23 * x20)) + ((uint64_t)x38 * x5));
++  { uint64_t x50 = (((((0x2 * ((((((uint64_t)x33 * x15) + ((uint64_t)x29 * x19)) + ((uint64_t)x37 * x11)) + ((uint64_t)x25 * x20)) + ((uint64_t)x38 * x7))) + ((uint64_t)x31 * x17)) + ((uint64_t)x35 * x13)) + ((uint64_t)x27 * x21)) + ((uint64_t)x39 * x9));
++  { uint64_t x51 = (((((((((uint64_t)x33 * x17) + ((uint64_t)x35 * x15)) + ((uint64_t)x31 * x19)) + ((uint64_t)x37 * x13)) + ((uint64_t)x29 * x21)) + ((uint64_t)x39 * x11)) + ((uint64_t)x27 * x20)) + ((uint64_t)x38 * x9));
++  { uint64_t x52 = (((((uint64_t)x35 * x17) + (0x2 * (((((uint64_t)x33 * x19) + ((uint64_t)x37 * x15)) + ((uint64_t)x29 * x20)) + ((uint64_t)x38 * x11)))) + ((uint64_t)x31 * x21)) + ((uint64_t)x39 * x13));
++  { uint64_t x53 = (((((((uint64_t)x35 * x19) + ((uint64_t)x37 * x17)) + ((uint64_t)x33 * x21)) + ((uint64_t)x39 * x15)) + ((uint64_t)x31 * x20)) + ((uint64_t)x38 * x13));
++  { uint64_t x54 = (((0x2 * ((((uint64_t)x37 * x19) + ((uint64_t)x33 * x20)) + ((uint64_t)x38 * x15))) + ((uint64_t)x35 * x21)) + ((uint64_t)x39 * x17));
++  { uint64_t x55 = (((((uint64_t)x37 * x21) + ((uint64_t)x39 * x19)) + ((uint64_t)x35 * x20)) + ((uint64_t)x38 * x17));
++  { uint64_t x56 = (((uint64_t)x39 * x21) + (0x2 * (((uint64_t)x37 * x20) + ((uint64_t)x38 * x19))));
++  { uint64_t x57 = (((uint64_t)x39 * x20) + ((uint64_t)x38 * x21));
++  { uint64_t x58 = ((uint64_t)(0x2 * x38) * x20);
++  { uint64_t x59 = (x48 + (x58 << 0x4));
++  { uint64_t x60 = (x59 + (x58 << 0x1));
++  { uint64_t x61 = (x60 + x58);
++  { uint64_t x62 = (x47 + (x57 << 0x4));
++  { uint64_t x63 = (x62 + (x57 << 0x1));
++  { uint64_t x64 = (x63 + x57);
++  { uint64_t x65 = (x46 + (x56 << 0x4));
++  { uint64_t x66 = (x65 + (x56 << 0x1));
++  { uint64_t x67 = (x66 + x56);
++  { uint64_t x68 = (x45 + (x55 << 0x4));
++  { uint64_t x69 = (x68 + (x55 << 0x1));
++  { uint64_t x70 = (x69 + x55);
++  { uint64_t x71 = (x44 + (x54 << 0x4));
++  { uint64_t x72 = (x71 + (x54 << 0x1));
++  { uint64_t x73 = (x72 + x54);
++  { uint64_t x74 = (x43 + (x53 << 0x4));
++  { uint64_t x75 = (x74 + (x53 << 0x1));
++  { uint64_t x76 = (x75 + x53);
++  { uint64_t x77 = (x42 + (x52 << 0x4));
++  { uint64_t x78 = (x77 + (x52 << 0x1));
++  { uint64_t x79 = (x78 + x52);
++  { uint64_t x80 = (x41 + (x51 << 0x4));
++  { uint64_t x81 = (x80 + (x51 << 0x1));
++  { uint64_t x82 = (x81 + x51);
++  { uint64_t x83 = (x40 + (x50 << 0x4));
++  { uint64_t x84 = (x83 + (x50 << 0x1));
++  { uint64_t x85 = (x84 + x50);
++  { uint64_t x86 = (x85 >> 0x1a);
++  { uint32_t x87 = ((uint32_t)x85 & 0x3ffffff);
++  { uint64_t x88 = (x86 + x82);
++  { uint64_t x89 = (x88 >> 0x19);
++  { uint32_t x90 = ((uint32_t)x88 & 0x1ffffff);
++  { uint64_t x91 = (x89 + x79);
++  { uint64_t x92 = (x91 >> 0x1a);
++  { uint32_t x93 = ((uint32_t)x91 & 0x3ffffff);
++  { uint64_t x94 = (x92 + x76);
++  { uint64_t x95 = (x94 >> 0x19);
++  { uint32_t x96 = ((uint32_t)x94 & 0x1ffffff);
++  { uint64_t x97 = (x95 + x73);
++  { uint64_t x98 = (x97 >> 0x1a);
++  { uint32_t x99 = ((uint32_t)x97 & 0x3ffffff);
++  { uint64_t x100 = (x98 + x70);
++  { uint64_t x101 = (x100 >> 0x19);
++  { uint32_t x102 = ((uint32_t)x100 & 0x1ffffff);
++  { uint64_t x103 = (x101 + x67);
++  { uint64_t x104 = (x103 >> 0x1a);
++  { uint32_t x105 = ((uint32_t)x103 & 0x3ffffff);
++  { uint64_t x106 = (x104 + x64);
++  { uint64_t x107 = (x106 >> 0x19);
++  { uint32_t x108 = ((uint32_t)x106 & 0x1ffffff);
++  { uint64_t x109 = (x107 + x61);
++  { uint64_t x110 = (x109 >> 0x1a);
++  { uint32_t x111 = ((uint32_t)x109 & 0x3ffffff);
++  { uint64_t x112 = (x110 + x49);
++  { uint64_t x113 = (x112 >> 0x19);
++  { uint32_t x114 = ((uint32_t)x112 & 0x1ffffff);
++  { uint64_t x115 = (x87 + (0x13 * x113));
++  { uint32_t x116 = (uint32_t) (x115 >> 0x1a);
++  { uint32_t x117 = ((uint32_t)x115 & 0x3ffffff);
++  { uint32_t x118 = (x116 + x90);
++  { uint32_t x119 = (x118 >> 0x19);
++  { uint32_t x120 = (x118 & 0x1ffffff);
++  out[0] = x117;
++  out[1] = x120;
++  out[2] = (x119 + x93);
++  out[3] = x96;
++  out[4] = x99;
++  out[5] = x102;
++  out[6] = x105;
++  out[7] = x108;
++  out[8] = x111;
++  out[9] = x114;
++  }}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}
++  assert_fe(out);
++}
++
++static void fe_mul_ltt(fe_loose *h, const fe *f, const fe *g) {
++  fe_mul_impl(h->v, f->v, g->v);
++}
++
++static void fe_mul_llt(fe_loose *h, const fe_loose *f, const fe *g) {
++  fe_mul_impl(h->v, f->v, g->v);
++}
++
++static void fe_mul_ttt(fe *h, const fe *f, const fe *g) {
++  fe_mul_impl(h->v, f->v, g->v);
++}
++
++static void fe_mul_tlt(fe *h, const fe_loose *f, const fe *g) {
++  fe_mul_impl(h->v, f->v, g->v);
++}
++
++static void fe_mul_ttl(fe *h, const fe *f, const fe_loose *g) {
++  fe_mul_impl(h->v, f->v, g->v);
++}
++
++static void fe_mul_tll(fe *h, const fe_loose *f, const fe_loose *g) {
++  fe_mul_impl(h->v, f->v, g->v);
++}
++
++static void fe_sqr_impl(uint32_t out[10], const uint32_t in1[10]) {
++  assert_fe_loose(in1);
++  { const uint32_t x17 = in1[9];
++  { const uint32_t x18 = in1[8];
++  { const uint32_t x16 = in1[7];
++  { const uint32_t x14 = in1[6];
++  { const uint32_t x12 = in1[5];
++  { const uint32_t x10 = in1[4];
++  { const uint32_t x8 = in1[3];
++  { const uint32_t x6 = in1[2];
++  { const uint32_t x4 = in1[1];
++  { const uint32_t x2 = in1[0];
++  { uint64_t x19 = ((uint64_t)x2 * x2);
++  { uint64_t x20 = ((uint64_t)(0x2 * x2) * x4);
++  { uint64_t x21 = (0x2 * (((uint64_t)x4 * x4) + ((uint64_t)x2 * x6)));
++  { uint64_t x22 = (0x2 * (((uint64_t)x4 * x6) + ((uint64_t)x2 * x8)));
++  { uint64_t x23 = ((((uint64_t)x6 * x6) + ((uint64_t)(0x4 * x4) * x8)) + ((uint64_t)(0x2 * x2) * x10));
++  { uint64_t x24 = (0x2 * ((((uint64_t)x6 * x8) + ((uint64_t)x4 * x10)) + ((uint64_t)x2 * x12)));
++  { uint64_t x25 = (0x2 * (((((uint64_t)x8 * x8) + ((uint64_t)x6 * x10)) + ((uint64_t)x2 * x14)) + ((uint64_t)(0x2 * x4) * x12)));
++  { uint64_t x26 = (0x2 * (((((uint64_t)x8 * x10) + ((uint64_t)x6 * x12)) + ((uint64_t)x4 * x14)) + ((uint64_t)x2 * x16)));
++  { uint64_t x27 = (((uint64_t)x10 * x10) + (0x2 * ((((uint64_t)x6 * x14) + ((uint64_t)x2 * x18)) + (0x2 * (((uint64_t)x4 * x16) + ((uint64_t)x8 * x12))))));
++  { uint64_t x28 = (0x2 * ((((((uint64_t)x10 * x12) + ((uint64_t)x8 * x14)) + ((uint64_t)x6 * x16)) + ((uint64_t)x4 * x18)) + ((uint64_t)x2 * x17)));
++  { uint64_t x29 = (0x2 * (((((uint64_t)x12 * x12) + ((uint64_t)x10 * x14)) + ((uint64_t)x6 * x18)) + (0x2 * (((uint64_t)x8 * x16) + ((uint64_t)x4 * x17)))));
++  { uint64_t x30 = (0x2 * (((((uint64_t)x12 * x14) + ((uint64_t)x10 * x16)) + ((uint64_t)x8 * x18)) + ((uint64_t)x6 * x17)));
++  { uint64_t x31 = (((uint64_t)x14 * x14) + (0x2 * (((uint64_t)x10 * x18) + (0x2 * (((uint64_t)x12 * x16) + ((uint64_t)x8 * x17))))));
++  { uint64_t x32 = (0x2 * ((((uint64_t)x14 * x16) + ((uint64_t)x12 * x18)) + ((uint64_t)x10 * x17)));
++  { uint64_t x33 = (0x2 * ((((uint64_t)x16 * x16) + ((uint64_t)x14 * x18)) + ((uint64_t)(0x2 * x12) * x17)));
++  { uint64_t x34 = (0x2 * (((uint64_t)x16 * x18) + ((uint64_t)x14 * x17)));
++  { uint64_t x35 = (((uint64_t)x18 * x18) + ((uint64_t)(0x4 * x16) * x17));
++  { uint64_t x36 = ((uint64_t)(0x2 * x18) * x17);
++  { uint64_t x37 = ((uint64_t)(0x2 * x17) * x17);
++  { uint64_t x38 = (x27 + (x37 << 0x4));
++  { uint64_t x39 = (x38 + (x37 << 0x1));
++  { uint64_t x40 = (x39 + x37);
++  { uint64_t x41 = (x26 + (x36 << 0x4));
++  { uint64_t x42 = (x41 + (x36 << 0x1));
++  { uint64_t x43 = (x42 + x36);
++  { uint64_t x44 = (x25 + (x35 << 0x4));
++  { uint64_t x45 = (x44 + (x35 << 0x1));
++  { uint64_t x46 = (x45 + x35);
++  { uint64_t x47 = (x24 + (x34 << 0x4));
++  { uint64_t x48 = (x47 + (x34 << 0x1));
++  { uint64_t x49 = (x48 + x34);
++  { uint64_t x50 = (x23 + (x33 << 0x4));
++  { uint64_t x51 = (x50 + (x33 << 0x1));
++  { uint64_t x52 = (x51 + x33);
++  { uint64_t x53 = (x22 + (x32 << 0x4));
++  { uint64_t x54 = (x53 + (x32 << 0x1));
++  { uint64_t x55 = (x54 + x32);
++  { uint64_t x56 = (x21 + (x31 << 0x4));
++  { uint64_t x57 = (x56 + (x31 << 0x1));
++  { uint64_t x58 = (x57 + x31);
++  { uint64_t x59 = (x20 + (x30 << 0x4));
++  { uint64_t x60 = (x59 + (x30 << 0x1));
++  { uint64_t x61 = (x60 + x30);
++  { uint64_t x62 = (x19 + (x29 << 0x4));
++  { uint64_t x63 = (x62 + (x29 << 0x1));
++  { uint64_t x64 = (x63 + x29);
++  { uint64_t x65 = (x64 >> 0x1a);
++  { uint32_t x66 = ((uint32_t)x64 & 0x3ffffff);
++  { uint64_t x67 = (x65 + x61);
++  { uint64_t x68 = (x67 >> 0x19);
++  { uint32_t x69 = ((uint32_t)x67 & 0x1ffffff);
++  { uint64_t x70 = (x68 + x58);
++  { uint64_t x71 = (x70 >> 0x1a);
++  { uint32_t x72 = ((uint32_t)x70 & 0x3ffffff);
++  { uint64_t x73 = (x71 + x55);
++  { uint64_t x74 = (x73 >> 0x19);
++  { uint32_t x75 = ((uint32_t)x73 & 0x1ffffff);
++  { uint64_t x76 = (x74 + x52);
++  { uint64_t x77 = (x76 >> 0x1a);
++  { uint32_t x78 = ((uint32_t)x76 & 0x3ffffff);
++  { uint64_t x79 = (x77 + x49);
++  { uint64_t x80 = (x79 >> 0x19);
++  { uint32_t x81 = ((uint32_t)x79 & 0x1ffffff);
++  { uint64_t x82 = (x80 + x46);
++  { uint64_t x83 = (x82 >> 0x1a);
++  { uint32_t x84 = ((uint32_t)x82 & 0x3ffffff);
++  { uint64_t x85 = (x83 + x43);
++  { uint64_t x86 = (x85 >> 0x19);
++  { uint32_t x87 = ((uint32_t)x85 & 0x1ffffff);
++  { uint64_t x88 = (x86 + x40);
++  { uint64_t x89 = (x88 >> 0x1a);
++  { uint32_t x90 = ((uint32_t)x88 & 0x3ffffff);
++  { uint64_t x91 = (x89 + x28);
++  { uint64_t x92 = (x91 >> 0x19);
++  { uint32_t x93 = ((uint32_t)x91 & 0x1ffffff);
++  { uint64_t x94 = (x66 + (0x13 * x92));
++  { uint32_t x95 = (uint32_t) (x94 >> 0x1a);
++  { uint32_t x96 = ((uint32_t)x94 & 0x3ffffff);
++  { uint32_t x97 = (x95 + x69);
++  { uint32_t x98 = (x97 >> 0x19);
++  { uint32_t x99 = (x97 & 0x1ffffff);
++  out[0] = x96;
++  out[1] = x99;
++  out[2] = (x98 + x72);
++  out[3] = x75;
++  out[4] = x78;
++  out[5] = x81;
++  out[6] = x84;
++  out[7] = x87;
++  out[8] = x90;
++  out[9] = x93;
++  }}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}
++  assert_fe(out);
++}
++
++static void fe_sq_tl(fe *h, const fe_loose *f) {
++  fe_sqr_impl(h->v, f->v);
++}
++
++static void fe_sq_tt(fe *h, const fe *f) {
++  fe_sqr_impl(h->v, f->v);
++}
++
++// Adapted from Fiat-synthesized |fe_sub_impl| with |out| = 0.
++static void fe_neg_impl(uint32_t out[10], const uint32_t in2[10]) {
++  { const uint32_t x20 = 0;
++  { const uint32_t x21 = 0;
++  { const uint32_t x19 = 0;
++  { const uint32_t x17 = 0;
++  { const uint32_t x15 = 0;
++  { const uint32_t x13 = 0;
++  { const uint32_t x11 = 0;
++  { const uint32_t x9 = 0;
++  { const uint32_t x7 = 0;
++  { const uint32_t x5 = 0;
++  { const uint32_t x38 = in2[9];
++  { const uint32_t x39 = in2[8];
++  { const uint32_t x37 = in2[7];
++  { const uint32_t x35 = in2[6];
++  { const uint32_t x33 = in2[5];
++  { const uint32_t x31 = in2[4];
++  { const uint32_t x29 = in2[3];
++  { const uint32_t x27 = in2[2];
++  { const uint32_t x25 = in2[1];
++  { const uint32_t x23 = in2[0];
++  out[0] = ((0x7ffffda + x5) - x23);
++  out[1] = ((0x3fffffe + x7) - x25);
++  out[2] = ((0x7fffffe + x9) - x27);
++  out[3] = ((0x3fffffe + x11) - x29);
++  out[4] = ((0x7fffffe + x13) - x31);
++  out[5] = ((0x3fffffe + x15) - x33);
++  out[6] = ((0x7fffffe + x17) - x35);
++  out[7] = ((0x3fffffe + x19) - x37);
++  out[8] = ((0x7fffffe + x21) - x39);
++  out[9] = ((0x3fffffe + x20) - x38);
++  }}}}}}}}}}}}}}}}}}}}
++}
++
++// h = -f
++static void fe_neg(fe_loose *h, const fe *f) {
++  assert_fe(f->v);
++  fe_neg_impl(h->v, f->v);
++  assert_fe_loose(h->v);
++}
++
++// Replace (f,g) with (g,g) if b == 1;
++// replace (f,g) with (f,g) if b == 0.
++//
++// Preconditions: b in {0,1}.
++static void fe_cmov(fe_loose *f, const fe_loose *g, unsigned b) {
++  b = 0-b;
++  unsigned i;
++  for (i = 0; i < 10; i++) {
++    uint32_t x = f->v[i] ^ g->v[i];
++    x &= b;
++    f->v[i] ^= x;
++  }
++}
++
++#endif  // BORINGSSL_CURVE25519_64BIT
++
++// h = f
++static void fe_copy(fe *h, const fe *f) {
++  memmove(h, f, sizeof(fe));
++}
++
++static void fe_copy_lt(fe_loose *h, const fe *f) {
++#ifdef EDWARDS25519_ASSERTS
++  assert(sizeof(fe_loose) == sizeof(fe));
++#endif
++  memmove(h, f, sizeof(fe));
++}
++#if !defined(CONFIG_SMALL)
++static void fe_copy_ll(fe_loose *h, const fe_loose *f) {
++  memmove(h, f, sizeof(fe_loose));
++}
++#endif // !defined(CONFIG_SMALL)
++
++static void fe_loose_invert(fe *out, const fe_loose *z) {
++  fe t0;
++  fe t1;
++  fe t2;
++  fe t3;
++  int i;
++
++  fe_sq_tl(&t0, z);
++  fe_sq_tt(&t1, &t0);
++  for (i = 1; i < 2; ++i) {
++    fe_sq_tt(&t1, &t1);
++  }
++  fe_mul_tlt(&t1, z, &t1);
++  fe_mul_ttt(&t0, &t0, &t1);
++  fe_sq_tt(&t2, &t0);
++  fe_mul_ttt(&t1, &t1, &t2);
++  fe_sq_tt(&t2, &t1);
++  for (i = 1; i < 5; ++i) {
++    fe_sq_tt(&t2, &t2);
++  }
++  fe_mul_ttt(&t1, &t2, &t1);
++  fe_sq_tt(&t2, &t1);
++  for (i = 1; i < 10; ++i) {
++    fe_sq_tt(&t2, &t2);
++  }
++  fe_mul_ttt(&t2, &t2, &t1);
++  fe_sq_tt(&t3, &t2);
++  for (i = 1; i < 20; ++i) {
++    fe_sq_tt(&t3, &t3);
++  }
++  fe_mul_ttt(&t2, &t3, &t2);
++  fe_sq_tt(&t2, &t2);
++  for (i = 1; i < 10; ++i) {
++    fe_sq_tt(&t2, &t2);
++  }
++  fe_mul_ttt(&t1, &t2, &t1);
++  fe_sq_tt(&t2, &t1);
++  for (i = 1; i < 50; ++i) {
++    fe_sq_tt(&t2, &t2);
++  }
++  fe_mul_ttt(&t2, &t2, &t1);
++  fe_sq_tt(&t3, &t2);
++  for (i = 1; i < 100; ++i) {
++    fe_sq_tt(&t3, &t3);
++  }
++  fe_mul_ttt(&t2, &t3, &t2);
++  fe_sq_tt(&t2, &t2);
++  for (i = 1; i < 50; ++i) {
++    fe_sq_tt(&t2, &t2);
++  }
++  fe_mul_ttt(&t1, &t2, &t1);
++  fe_sq_tt(&t1, &t1);
++  for (i = 1; i < 5; ++i) {
++    fe_sq_tt(&t1, &t1);
++  }
++  fe_mul_ttt(out, &t1, &t0);
++}
++
++static void fe_invert(fe *out, const fe *z) {
++  fe_loose l;
++  fe_copy_lt(&l, z);
++  fe_loose_invert(out, &l);
++}
++
++// return 0 if f == 0
++// return 1 if f != 0
++static int fe_isnonzero(const fe_loose *f) {
++  fe tight;
++  fe_carry(&tight, f);
++  uint8_t s[32];
++  fe_tobytes(s, &tight);
++
++  static const uint8_t zero[32] = {0};
++  return k5_bcmp(s, zero, sizeof(zero)) != 0;
++}
++
++// return 1 if f is in {1,3,5,...,q-2}
++// return 0 if f is in {0,2,4,...,q-1}
++static int fe_isnegative(const fe *f) {
++  uint8_t s[32];
++  fe_tobytes(s, f);
++  return s[0] & 1;
++}
++
++static void fe_sq2_tt(fe *h, const fe *f) {
++  // h = f^2
++  fe_sq_tt(h, f);
++
++  // h = h + h
++  fe_loose tmp;
++  fe_add(&tmp, h, h);
++  fe_carry(h, &tmp);
++}
++
++static void fe_pow22523(fe *out, const fe *z) {
++  fe t0;
++  fe t1;
++  fe t2;
++  int i;
++
++  fe_sq_tt(&t0, z);
++  fe_sq_tt(&t1, &t0);
++  for (i = 1; i < 2; ++i) {
++    fe_sq_tt(&t1, &t1);
++  }
++  fe_mul_ttt(&t1, z, &t1);
++  fe_mul_ttt(&t0, &t0, &t1);
++  fe_sq_tt(&t0, &t0);
++  fe_mul_ttt(&t0, &t1, &t0);
++  fe_sq_tt(&t1, &t0);
++  for (i = 1; i < 5; ++i) {
++    fe_sq_tt(&t1, &t1);
++  }
++  fe_mul_ttt(&t0, &t1, &t0);
++  fe_sq_tt(&t1, &t0);
++  for (i = 1; i < 10; ++i) {
++    fe_sq_tt(&t1, &t1);
++  }
++  fe_mul_ttt(&t1, &t1, &t0);
++  fe_sq_tt(&t2, &t1);
++  for (i = 1; i < 20; ++i) {
++    fe_sq_tt(&t2, &t2);
++  }
++  fe_mul_ttt(&t1, &t2, &t1);
++  fe_sq_tt(&t1, &t1);
++  for (i = 1; i < 10; ++i) {
++    fe_sq_tt(&t1, &t1);
++  }
++  fe_mul_ttt(&t0, &t1, &t0);
++  fe_sq_tt(&t1, &t0);
++  for (i = 1; i < 50; ++i) {
++    fe_sq_tt(&t1, &t1);
++  }
++  fe_mul_ttt(&t1, &t1, &t0);
++  fe_sq_tt(&t2, &t1);
++  for (i = 1; i < 100; ++i) {
++    fe_sq_tt(&t2, &t2);
++  }
++  fe_mul_ttt(&t1, &t2, &t1);
++  fe_sq_tt(&t1, &t1);
++  for (i = 1; i < 50; ++i) {
++    fe_sq_tt(&t1, &t1);
++  }
++  fe_mul_ttt(&t0, &t1, &t0);
++  fe_sq_tt(&t0, &t0);
++  for (i = 1; i < 2; ++i) {
++    fe_sq_tt(&t0, &t0);
++  }
++  fe_mul_ttt(out, &t0, z);
++}
++
++
++// Group operations.
++
++static void x25519_ge_tobytes(uint8_t s[32], const ge_p2 *h) {
++  fe recip;
++  fe x;
++  fe y;
++
++  fe_invert(&recip, &h->Z);
++  fe_mul_ttt(&x, &h->X, &recip);
++  fe_mul_ttt(&y, &h->Y, &recip);
++  fe_tobytes(s, &y);
++  s[31] ^= fe_isnegative(&x) << 7;
++}
++
++static int x25519_ge_frombytes_vartime(ge_p3 *h, const uint8_t *s) {
++  fe u;
++  fe_loose v;
++  fe v3;
++  fe vxx;
++  fe_loose check;
++
++  fe_frombytes(&h->Y, s);
++  fe_1(&h->Z);
++  fe_sq_tt(&v3, &h->Y);
++  fe_mul_ttt(&vxx, &v3, &d);
++  fe_sub(&v, &v3, &h->Z);  // u = y^2-1
++  fe_carry(&u, &v);
++  fe_add(&v, &vxx, &h->Z);  // v = dy^2+1
++
++  fe_sq_tl(&v3, &v);
++  fe_mul_ttl(&v3, &v3, &v);  // v3 = v^3
++  fe_sq_tt(&h->X, &v3);
++  fe_mul_ttl(&h->X, &h->X, &v);
++  fe_mul_ttt(&h->X, &h->X, &u);  // x = uv^7
++
++  fe_pow22523(&h->X, &h->X);  // x = (uv^7)^((q-5)/8)
++  fe_mul_ttt(&h->X, &h->X, &v3);
++  fe_mul_ttt(&h->X, &h->X, &u);  // x = uv^3(uv^7)^((q-5)/8)
++
++  fe_sq_tt(&vxx, &h->X);
++  fe_mul_ttl(&vxx, &vxx, &v);
++  fe_sub(&check, &vxx, &u);
++  if (fe_isnonzero(&check)) {
++    fe_add(&check, &vxx, &u);
++    if (fe_isnonzero(&check)) {
++      return -1;
++    }
++    fe_mul_ttt(&h->X, &h->X, &sqrtm1);
++  }
++
++  if (fe_isnegative(&h->X) != (s[31] >> 7)) {
++    fe_loose t;
++    fe_neg(&t, &h->X);
++    fe_carry(&h->X, &t);
++  }
++
++  fe_mul_ttt(&h->T, &h->X, &h->Y);
++  return 0;
++}
++
++static void ge_p2_0(ge_p2 *h) {
++  fe_0(&h->X);
++  fe_1(&h->Y);
++  fe_1(&h->Z);
++}
++
++static void ge_p3_0(ge_p3 *h) {
++  fe_0(&h->X);
++  fe_1(&h->Y);
++  fe_1(&h->Z);
++  fe_0(&h->T);
++}
++
++static void ge_cached_0(ge_cached *h) {
++  fe_loose_1(&h->YplusX);
++  fe_loose_1(&h->YminusX);
++  fe_loose_1(&h->Z);
++  fe_loose_0(&h->T2d);
++}
++
++static void ge_precomp_0(ge_precomp *h) {
++  fe_loose_1(&h->yplusx);
++  fe_loose_1(&h->yminusx);
++  fe_loose_0(&h->xy2d);
++}
++
++// r = p
++static void ge_p3_to_p2(ge_p2 *r, const ge_p3 *p) {
++  fe_copy(&r->X, &p->X);
++  fe_copy(&r->Y, &p->Y);
++  fe_copy(&r->Z, &p->Z);
++}
++
++// r = p
++static void x25519_ge_p3_to_cached(ge_cached *r, const ge_p3 *p) {
++  fe_add(&r->YplusX, &p->Y, &p->X);
++  fe_sub(&r->YminusX, &p->Y, &p->X);
++  fe_copy_lt(&r->Z, &p->Z);
++  fe_mul_ltt(&r->T2d, &p->T, &d2);
++}
++
++// r = p
++static void x25519_ge_p1p1_to_p2(ge_p2 *r, const ge_p1p1 *p) {
++  fe_mul_tll(&r->X, &p->X, &p->T);
++  fe_mul_tll(&r->Y, &p->Y, &p->Z);
++  fe_mul_tll(&r->Z, &p->Z, &p->T);
++}
++
++// r = p
++static void x25519_ge_p1p1_to_p3(ge_p3 *r, const ge_p1p1 *p) {
++  fe_mul_tll(&r->X, &p->X, &p->T);
++  fe_mul_tll(&r->Y, &p->Y, &p->Z);
++  fe_mul_tll(&r->Z, &p->Z, &p->T);
++  fe_mul_tll(&r->T, &p->X, &p->Y);
++}
++
++// r = p
++static void ge_p1p1_to_cached(ge_cached *r, const ge_p1p1 *p) {
++  ge_p3 t;
++  x25519_ge_p1p1_to_p3(&t, p);
++  x25519_ge_p3_to_cached(r, &t);
++}
++
++// r = 2 * p
++static void ge_p2_dbl(ge_p1p1 *r, const ge_p2 *p) {
++  fe trX, trZ, trT;
++  fe t0;
++
++  fe_sq_tt(&trX, &p->X);
++  fe_sq_tt(&trZ, &p->Y);
++  fe_sq2_tt(&trT, &p->Z);
++  fe_add(&r->Y, &p->X, &p->Y);
++  fe_sq_tl(&t0, &r->Y);
++
++  fe_add(&r->Y, &trZ, &trX);
++  fe_sub(&r->Z, &trZ, &trX);
++  fe_carry(&trZ, &r->Y);
++  fe_sub(&r->X, &t0, &trZ);
++  fe_carry(&trZ, &r->Z);
++  fe_sub(&r->T, &trT, &trZ);
++}
++
++#ifndef CONFIG_SMALL
++// r = 2 * p
++static void ge_p3_dbl(ge_p1p1 *r, const ge_p3 *p) {
++  ge_p2 q;
++  ge_p3_to_p2(&q, p);
++  ge_p2_dbl(r, &q);
++}
++#endif
++
++// r = p + q
++static void ge_madd(ge_p1p1 *r, const ge_p3 *p, const ge_precomp *q) {
++  fe trY, trZ, trT;
++
++  fe_add(&r->X, &p->Y, &p->X);
++  fe_sub(&r->Y, &p->Y, &p->X);
++  fe_mul_tll(&trZ, &r->X, &q->yplusx);
++  fe_mul_tll(&trY, &r->Y, &q->yminusx);
++  fe_mul_tlt(&trT, &q->xy2d, &p->T);
++  fe_add(&r->T, &p->Z, &p->Z);
++  fe_sub(&r->X, &trZ, &trY);
++  fe_add(&r->Y, &trZ, &trY);
++  fe_carry(&trZ, &r->T);
++  fe_add(&r->Z, &trZ, &trT);
++  fe_sub(&r->T, &trZ, &trT);
++}
++
++// r = p + q
++static void x25519_ge_add(ge_p1p1 *r, const ge_p3 *p, const ge_cached *q) {
++  fe trX, trY, trZ, trT;
++
++  fe_add(&r->X, &p->Y, &p->X);
++  fe_sub(&r->Y, &p->Y, &p->X);
++  fe_mul_tll(&trZ, &r->X, &q->YplusX);
++  fe_mul_tll(&trY, &r->Y, &q->YminusX);
++  fe_mul_tlt(&trT, &q->T2d, &p->T);
++  fe_mul_ttl(&trX, &p->Z, &q->Z);
++  fe_add(&r->T, &trX, &trX);
++  fe_sub(&r->X, &trZ, &trY);
++  fe_add(&r->Y, &trZ, &trY);
++  fe_carry(&trZ, &r->T);
++  fe_add(&r->Z, &trZ, &trT);
++  fe_sub(&r->T, &trZ, &trT);
++}
++
++// r = p - q
++static void x25519_ge_sub(ge_p1p1 *r, const ge_p3 *p, const ge_cached *q) {
++  fe trX, trY, trZ, trT;
++
++  fe_add(&r->X, &p->Y, &p->X);
++  fe_sub(&r->Y, &p->Y, &p->X);
++  fe_mul_tll(&trZ, &r->X, &q->YminusX);
++  fe_mul_tll(&trY, &r->Y, &q->YplusX);
++  fe_mul_tlt(&trT, &q->T2d, &p->T);
++  fe_mul_ttl(&trX, &p->Z, &q->Z);
++  fe_add(&r->T, &trX, &trX);
++  fe_sub(&r->X, &trZ, &trY);
++  fe_add(&r->Y, &trZ, &trY);
++  fe_carry(&trZ, &r->T);
++  fe_sub(&r->Z, &trZ, &trT);
++  fe_add(&r->T, &trZ, &trT);
++}
++
++static uint8_t equal(signed char b, signed char c) {
++  uint8_t ub = b;
++  uint8_t uc = c;
++  uint8_t x = ub ^ uc;  // 0: yes; 1..255: no
++  uint32_t y = x;       // 0: yes; 1..255: no
++  y -= 1;               // 4294967295: yes; 0..254: no
++  y >>= 31;             // 1: yes; 0: no
++  return y;
++}
++
++static void cmov(ge_precomp *t, const ge_precomp *u, uint8_t b) {
++  fe_cmov(&t->yplusx, &u->yplusx, b);
++  fe_cmov(&t->yminusx, &u->yminusx, b);
++  fe_cmov(&t->xy2d, &u->xy2d, b);
++}
++
++static void x25519_ge_scalarmult_small_precomp(
++    ge_p3 *h, const uint8_t a[32], const uint8_t precomp_table[15 * 2 * 32]) {
++  // precomp_table is first expanded into matching |ge_precomp|
++  // elements.
++  ge_precomp multiples[15];
++
++  unsigned i;
++  for (i = 0; i < 15; i++) {
++    const uint8_t *bytes = &precomp_table[i*(2 * 32)];
++    fe x, y;
++    fe_frombytes(&x, bytes);
++    fe_frombytes(&y, bytes + 32);
++
++    ge_precomp *out = &multiples[i];
++    fe_add(&out->yplusx, &y, &x);
++    fe_sub(&out->yminusx, &y, &x);
++    fe_mul_ltt(&out->xy2d, &x, &y);
++    fe_mul_llt(&out->xy2d, &out->xy2d, &d2);
++  }
++
++  // See the comment above |k25519SmallPrecomp| about the structure of the
++  // precomputed elements. This loop does 64 additions and 64 doublings to
++  // calculate the result.
++  ge_p3_0(h);
++
++  for (i = 63; i < 64; i--) {
++    unsigned j;
++    signed char index = 0;
++
++    for (j = 0; j < 4; j++) {
++      const uint8_t bit = 1 & (a[(8 * j) + (i / 8)] >> (i & 7));
++      index |= (bit << j);
++    }
++
++    ge_precomp e;
++    ge_precomp_0(&e);
++
++    for (j = 1; j < 16; j++) {
++      cmov(&e, &multiples[j-1], equal(index, j));
++    }
++
++    ge_cached cached;
++    ge_p1p1 r;
++    x25519_ge_p3_to_cached(&cached, h);
++    x25519_ge_add(&r, h, &cached);
++    x25519_ge_p1p1_to_p3(h, &r);
++
++    ge_madd(&r, h, &e);
++    x25519_ge_p1p1_to_p3(h, &r);
++  }
++}
++
++#if defined(CONFIG_SMALL)
++
++static void x25519_ge_scalarmult_base(ge_p3 *h, const uint8_t a[32]) {
++  x25519_ge_scalarmult_small_precomp(h, a, k25519SmallPrecomp);
++}
++
++#else
++
++static uint8_t negative(signed char b) {
++  uint32_t x = b;
++  x >>= 31;  // 1: yes; 0: no
++  return x;
++}
++
++static void table_select(ge_precomp *t, int pos, signed char b) {
++  ge_precomp minust;
++  uint8_t bnegative = negative(b);
++  uint8_t babs = b - ((uint8_t)((-bnegative) & b) << 1);
++
++  ge_precomp_0(t);
++  cmov(t, &k25519Precomp[pos][0], equal(babs, 1));
++  cmov(t, &k25519Precomp[pos][1], equal(babs, 2));
++  cmov(t, &k25519Precomp[pos][2], equal(babs, 3));
++  cmov(t, &k25519Precomp[pos][3], equal(babs, 4));
++  cmov(t, &k25519Precomp[pos][4], equal(babs, 5));
++  cmov(t, &k25519Precomp[pos][5], equal(babs, 6));
++  cmov(t, &k25519Precomp[pos][6], equal(babs, 7));
++  cmov(t, &k25519Precomp[pos][7], equal(babs, 8));
++  fe_copy_ll(&minust.yplusx, &t->yminusx);
++  fe_copy_ll(&minust.yminusx, &t->yplusx);
++
++  // NOTE: the input table is canonical, but types don't encode it
++  fe tmp;
++  fe_carry(&tmp, &t->xy2d);
++  fe_neg(&minust.xy2d, &tmp);
++
++  cmov(t, &minust, bnegative);
++}
++
++// h = a * B
++// where a = a[0]+256*a[1]+...+256^31 a[31]
++// B is the Ed25519 base point (x,4/5) with x positive.
++//
++// Preconditions:
++//   a[31] <= 127
++static void x25519_ge_scalarmult_base(ge_p3 *h, const uint8_t *a) {
++  signed char e[64];
++  signed char carry;
++  ge_p1p1 r;
++  ge_p2 s;
++  ge_precomp t;
++  int i;
++
++  for (i = 0; i < 32; ++i) {
++    e[2 * i + 0] = (a[i] >> 0) & 15;
++    e[2 * i + 1] = (a[i] >> 4) & 15;
++  }
++  // each e[i] is between 0 and 15
++  // e[63] is between 0 and 7
++
++  carry = 0;
++  for (i = 0; i < 63; ++i) {
++    e[i] += carry;
++    carry = e[i] + 8;
++    carry >>= 4;
++    e[i] -= carry << 4;
++  }
++  e[63] += carry;
++  // each e[i] is between -8 and 8
++
++  ge_p3_0(h);
++  for (i = 1; i < 64; i += 2) {
++    table_select(&t, i / 2, e[i]);
++    ge_madd(&r, h, &t);
++    x25519_ge_p1p1_to_p3(h, &r);
++  }
++
++  ge_p3_dbl(&r, h);
++  x25519_ge_p1p1_to_p2(&s, &r);
++  ge_p2_dbl(&r, &s);
++  x25519_ge_p1p1_to_p2(&s, &r);
++  ge_p2_dbl(&r, &s);
++  x25519_ge_p1p1_to_p2(&s, &r);
++  ge_p2_dbl(&r, &s);
++  x25519_ge_p1p1_to_p3(h, &r);
++
++  for (i = 0; i < 64; i += 2) {
++    table_select(&t, i / 2, e[i]);
++    ge_madd(&r, h, &t);
++    x25519_ge_p1p1_to_p3(h, &r);
++  }
++}
++
++#endif
++
++static void cmov_cached(ge_cached *t, ge_cached *u, uint8_t b) {
++  fe_cmov(&t->YplusX, &u->YplusX, b);
++  fe_cmov(&t->YminusX, &u->YminusX, b);
++  fe_cmov(&t->Z, &u->Z, b);
++  fe_cmov(&t->T2d, &u->T2d, b);
++}
++
++// r = scalar * A.
++// where a = a[0]+256*a[1]+...+256^31 a[31].
++static void x25519_ge_scalarmult(ge_p2 *r, const uint8_t *scalar,
++                                 const ge_p3 *A) {
++  ge_p2 Ai_p2[8];
++  ge_cached Ai[16];
++  ge_p1p1 t;
++
++  ge_cached_0(&Ai[0]);
++  x25519_ge_p3_to_cached(&Ai[1], A);
++  ge_p3_to_p2(&Ai_p2[1], A);
++
++  unsigned i;
++  for (i = 2; i < 16; i += 2) {
++    ge_p2_dbl(&t, &Ai_p2[i / 2]);
++    ge_p1p1_to_cached(&Ai[i], &t);
++    if (i < 8) {
++      x25519_ge_p1p1_to_p2(&Ai_p2[i], &t);
++    }
++    x25519_ge_add(&t, A, &Ai[i]);
++    ge_p1p1_to_cached(&Ai[i + 1], &t);
++    if (i < 7) {
++      x25519_ge_p1p1_to_p2(&Ai_p2[i + 1], &t);
++    }
++  }
++
++  ge_p2_0(r);
++  ge_p3 u;
++
++  for (i = 0; i < 256; i += 4) {
++    ge_p2_dbl(&t, r);
++    x25519_ge_p1p1_to_p2(r, &t);
++    ge_p2_dbl(&t, r);
++    x25519_ge_p1p1_to_p2(r, &t);
++    ge_p2_dbl(&t, r);
++    x25519_ge_p1p1_to_p2(r, &t);
++    ge_p2_dbl(&t, r);
++    x25519_ge_p1p1_to_p3(&u, &t);
++
++    uint8_t index = scalar[31 - i/8];
++    index >>= 4 - (i & 4);
++    index &= 0xf;
++
++    unsigned j;
++    ge_cached selected;
++    ge_cached_0(&selected);
++    for (j = 0; j < 16; j++) {
++      cmov_cached(&selected, &Ai[j], equal(j, index));
++    }
++
++    x25519_ge_add(&t, &u, &selected);
++    x25519_ge_p1p1_to_p2(r, &t);
++  }
++}
++
++// The set of scalars is \Z/l
++// where l = 2^252 + 27742317777372353535851937790883648493.
++
++// Input:
++//   s[0]+256*s[1]+...+256^63*s[63] = s
++//
++// Output:
++//   s[0]+256*s[1]+...+256^31*s[31] = s mod l
++//   where l = 2^252 + 27742317777372353535851937790883648493.
++//   Overwrites s in place.
++static void x25519_sc_reduce(uint8_t s[64]) {
++  int64_t s0 = 2097151 & load_3(s);
++  int64_t s1 = 2097151 & (load_4(s + 2) >> 5);
++  int64_t s2 = 2097151 & (load_3(s + 5) >> 2);
++  int64_t s3 = 2097151 & (load_4(s + 7) >> 7);
++  int64_t s4 = 2097151 & (load_4(s + 10) >> 4);
++  int64_t s5 = 2097151 & (load_3(s + 13) >> 1);
++  int64_t s6 = 2097151 & (load_4(s + 15) >> 6);
++  int64_t s7 = 2097151 & (load_3(s + 18) >> 3);
++  int64_t s8 = 2097151 & load_3(s + 21);
++  int64_t s9 = 2097151 & (load_4(s + 23) >> 5);
++  int64_t s10 = 2097151 & (load_3(s + 26) >> 2);
++  int64_t s11 = 2097151 & (load_4(s + 28) >> 7);
++  int64_t s12 = 2097151 & (load_4(s + 31) >> 4);
++  int64_t s13 = 2097151 & (load_3(s + 34) >> 1);
++  int64_t s14 = 2097151 & (load_4(s + 36) >> 6);
++  int64_t s15 = 2097151 & (load_3(s + 39) >> 3);
++  int64_t s16 = 2097151 & load_3(s + 42);
++  int64_t s17 = 2097151 & (load_4(s + 44) >> 5);
++  int64_t s18 = 2097151 & (load_3(s + 47) >> 2);
++  int64_t s19 = 2097151 & (load_4(s + 49) >> 7);
++  int64_t s20 = 2097151 & (load_4(s + 52) >> 4);
++  int64_t s21 = 2097151 & (load_3(s + 55) >> 1);
++  int64_t s22 = 2097151 & (load_4(s + 57) >> 6);
++  int64_t s23 = (load_4(s + 60) >> 3);
++  int64_t carry0;
++  int64_t carry1;
++  int64_t carry2;
++  int64_t carry3;
++  int64_t carry4;
++  int64_t carry5;
++  int64_t carry6;
++  int64_t carry7;
++  int64_t carry8;
++  int64_t carry9;
++  int64_t carry10;
++  int64_t carry11;
++  int64_t carry12;
++  int64_t carry13;
++  int64_t carry14;
++  int64_t carry15;
++  int64_t carry16;
++
++  s11 += s23 * 666643;
++  s12 += s23 * 470296;
++  s13 += s23 * 654183;
++  s14 -= s23 * 997805;
++  s15 += s23 * 136657;
++  s16 -= s23 * 683901;
++  s23 = 0;
++
++  s10 += s22 * 666643;
++  s11 += s22 * 470296;
++  s12 += s22 * 654183;
++  s13 -= s22 * 997805;
++  s14 += s22 * 136657;
++  s15 -= s22 * 683901;
++  s22 = 0;
++
++  s9 += s21 * 666643;
++  s10 += s21 * 470296;
++  s11 += s21 * 654183;
++  s12 -= s21 * 997805;
++  s13 += s21 * 136657;
++  s14 -= s21 * 683901;
++  s21 = 0;
++
++  s8 += s20 * 666643;
++  s9 += s20 * 470296;
++  s10 += s20 * 654183;
++  s11 -= s20 * 997805;
++  s12 += s20 * 136657;
++  s13 -= s20 * 683901;
++  s20 = 0;
++
++  s7 += s19 * 666643;
++  s8 += s19 * 470296;
++  s9 += s19 * 654183;
++  s10 -= s19 * 997805;
++  s11 += s19 * 136657;
++  s12 -= s19 * 683901;
++  s19 = 0;
++
++  s6 += s18 * 666643;
++  s7 += s18 * 470296;
++  s8 += s18 * 654183;
++  s9 -= s18 * 997805;
++  s10 += s18 * 136657;
++  s11 -= s18 * 683901;
++  s18 = 0;
++
++  carry6 = (s6 + (1 << 20)) >> 21;
++  s7 += carry6;
++  s6 -= carry6 << 21;
++  carry8 = (s8 + (1 << 20)) >> 21;
++  s9 += carry8;
++  s8 -= carry8 << 21;
++  carry10 = (s10 + (1 << 20)) >> 21;
++  s11 += carry10;
++  s10 -= carry10 << 21;
++  carry12 = (s12 + (1 << 20)) >> 21;
++  s13 += carry12;
++  s12 -= carry12 << 21;
++  carry14 = (s14 + (1 << 20)) >> 21;
++  s15 += carry14;
++  s14 -= carry14 << 21;
++  carry16 = (s16 + (1 << 20)) >> 21;
++  s17 += carry16;
++  s16 -= carry16 << 21;
++
++  carry7 = (s7 + (1 << 20)) >> 21;
++  s8 += carry7;
++  s7 -= carry7 << 21;
++  carry9 = (s9 + (1 << 20)) >> 21;
++  s10 += carry9;
++  s9 -= carry9 << 21;
++  carry11 = (s11 + (1 << 20)) >> 21;
++  s12 += carry11;
++  s11 -= carry11 << 21;
++  carry13 = (s13 + (1 << 20)) >> 21;
++  s14 += carry13;
++  s13 -= carry13 << 21;
++  carry15 = (s15 + (1 << 20)) >> 21;
++  s16 += carry15;
++  s15 -= carry15 << 21;
++
++  s5 += s17 * 666643;
++  s6 += s17 * 470296;
++  s7 += s17 * 654183;
++  s8 -= s17 * 997805;
++  s9 += s17 * 136657;
++  s10 -= s17 * 683901;
++  s17 = 0;
++
++  s4 += s16 * 666643;
++  s5 += s16 * 470296;
++  s6 += s16 * 654183;
++  s7 -= s16 * 997805;
++  s8 += s16 * 136657;
++  s9 -= s16 * 683901;
++  s16 = 0;
++
++  s3 += s15 * 666643;
++  s4 += s15 * 470296;
++  s5 += s15 * 654183;
++  s6 -= s15 * 997805;
++  s7 += s15 * 136657;
++  s8 -= s15 * 683901;
++  s15 = 0;
++
++  s2 += s14 * 666643;
++  s3 += s14 * 470296;
++  s4 += s14 * 654183;
++  s5 -= s14 * 997805;
++  s6 += s14 * 136657;
++  s7 -= s14 * 683901;
++  s14 = 0;
++
++  s1 += s13 * 666643;
++  s2 += s13 * 470296;
++  s3 += s13 * 654183;
++  s4 -= s13 * 997805;
++  s5 += s13 * 136657;
++  s6 -= s13 * 683901;
++  s13 = 0;
++
++  s0 += s12 * 666643;
++  s1 += s12 * 470296;
++  s2 += s12 * 654183;
++  s3 -= s12 * 997805;
++  s4 += s12 * 136657;
++  s5 -= s12 * 683901;
++  s12 = 0;
++
++  carry0 = (s0 + (1 << 20)) >> 21;
++  s1 += carry0;
++  s0 -= carry0 << 21;
++  carry2 = (s2 + (1 << 20)) >> 21;
++  s3 += carry2;
++  s2 -= carry2 << 21;
++  carry4 = (s4 + (1 << 20)) >> 21;
++  s5 += carry4;
++  s4 -= carry4 << 21;
++  carry6 = (s6 + (1 << 20)) >> 21;
++  s7 += carry6;
++  s6 -= carry6 << 21;
++  carry8 = (s8 + (1 << 20)) >> 21;
++  s9 += carry8;
++  s8 -= carry8 << 21;
++  carry10 = (s10 + (1 << 20)) >> 21;
++  s11 += carry10;
++  s10 -= carry10 << 21;
++
++  carry1 = (s1 + (1 << 20)) >> 21;
++  s2 += carry1;
++  s1 -= carry1 << 21;
++  carry3 = (s3 + (1 << 20)) >> 21;
++  s4 += carry3;
++  s3 -= carry3 << 21;
++  carry5 = (s5 + (1 << 20)) >> 21;
++  s6 += carry5;
++  s5 -= carry5 << 21;
++  carry7 = (s7 + (1 << 20)) >> 21;
++  s8 += carry7;
++  s7 -= carry7 << 21;
++  carry9 = (s9 + (1 << 20)) >> 21;
++  s10 += carry9;
++  s9 -= carry9 << 21;
++  carry11 = (s11 + (1 << 20)) >> 21;
++  s12 += carry11;
++  s11 -= carry11 << 21;
++
++  s0 += s12 * 666643;
++  s1 += s12 * 470296;
++  s2 += s12 * 654183;
++  s3 -= s12 * 997805;
++  s4 += s12 * 136657;
++  s5 -= s12 * 683901;
++  s12 = 0;
++
++  carry0 = s0 >> 21;
++  s1 += carry0;
++  s0 -= carry0 << 21;
++  carry1 = s1 >> 21;
++  s2 += carry1;
++  s1 -= carry1 << 21;
++  carry2 = s2 >> 21;
++  s3 += carry2;
++  s2 -= carry2 << 21;
++  carry3 = s3 >> 21;
++  s4 += carry3;
++  s3 -= carry3 << 21;
++  carry4 = s4 >> 21;
++  s5 += carry4;
++  s4 -= carry4 << 21;
++  carry5 = s5 >> 21;
++  s6 += carry5;
++  s5 -= carry5 << 21;
++  carry6 = s6 >> 21;
++  s7 += carry6;
++  s6 -= carry6 << 21;
++  carry7 = s7 >> 21;
++  s8 += carry7;
++  s7 -= carry7 << 21;
++  carry8 = s8 >> 21;
++  s9 += carry8;
++  s8 -= carry8 << 21;
++  carry9 = s9 >> 21;
++  s10 += carry9;
++  s9 -= carry9 << 21;
++  carry10 = s10 >> 21;
++  s11 += carry10;
++  s10 -= carry10 << 21;
++  carry11 = s11 >> 21;
++  s12 += carry11;
++  s11 -= carry11 << 21;
++
++  s0 += s12 * 666643;
++  s1 += s12 * 470296;
++  s2 += s12 * 654183;
++  s3 -= s12 * 997805;
++  s4 += s12 * 136657;
++  s5 -= s12 * 683901;
++  s12 = 0;
++
++  carry0 = s0 >> 21;
++  s1 += carry0;
++  s0 -= carry0 << 21;
++  carry1 = s1 >> 21;
++  s2 += carry1;
++  s1 -= carry1 << 21;
++  carry2 = s2 >> 21;
++  s3 += carry2;
++  s2 -= carry2 << 21;
++  carry3 = s3 >> 21;
++  s4 += carry3;
++  s3 -= carry3 << 21;
++  carry4 = s4 >> 21;
++  s5 += carry4;
++  s4 -= carry4 << 21;
++  carry5 = s5 >> 21;
++  s6 += carry5;
++  s5 -= carry5 << 21;
++  carry6 = s6 >> 21;
++  s7 += carry6;
++  s6 -= carry6 << 21;
++  carry7 = s7 >> 21;
++  s8 += carry7;
++  s7 -= carry7 << 21;
++  carry8 = s8 >> 21;
++  s9 += carry8;
++  s8 -= carry8 << 21;
++  carry9 = s9 >> 21;
++  s10 += carry9;
++  s9 -= carry9 << 21;
++  carry10 = s10 >> 21;
++  s11 += carry10;
++  s10 -= carry10 << 21;
++
++  s[0] = s0 >> 0;
++  s[1] = s0 >> 8;
++  s[2] = (s0 >> 16) | (s1 << 5);
++  s[3] = s1 >> 3;
++  s[4] = s1 >> 11;
++  s[5] = (s1 >> 19) | (s2 << 2);
++  s[6] = s2 >> 6;
++  s[7] = (s2 >> 14) | (s3 << 7);
++  s[8] = s3 >> 1;
++  s[9] = s3 >> 9;
++  s[10] = (s3 >> 17) | (s4 << 4);
++  s[11] = s4 >> 4;
++  s[12] = s4 >> 12;
++  s[13] = (s4 >> 20) | (s5 << 1);
++  s[14] = s5 >> 7;
++  s[15] = (s5 >> 15) | (s6 << 6);
++  s[16] = s6 >> 2;
++  s[17] = s6 >> 10;
++  s[18] = (s6 >> 18) | (s7 << 3);
++  s[19] = s7 >> 5;
++  s[20] = s7 >> 13;
++  s[21] = s8 >> 0;
++  s[22] = s8 >> 8;
++  s[23] = (s8 >> 16) | (s9 << 5);
++  s[24] = s9 >> 3;
++  s[25] = s9 >> 11;
++  s[26] = (s9 >> 19) | (s10 << 2);
++  s[27] = s10 >> 6;
++  s[28] = (s10 >> 14) | (s11 << 7);
++  s[29] = s11 >> 1;
++  s[30] = s11 >> 9;
++  s[31] = s11 >> 17;
++}
++
++/* Loosely from BoringSSL crypto/curve25519/spake25519.c */
++
++/*
++ * Here BoringSSL uses different points, not restricted to the generator
++ * subgroup, while we use the draft-irtf-cfrg-spake2-05 points.  The Python
++ * code is modified to add the subgroup restriction.
++ */
++
++// The following precomputation tables are for the following
++// points:
++//
++// N (found in 7 iterations):
++//   x: 10742253510813957597047979962966927467575235974254765187031601461055699024931
++//   y: 19796686047937480651099107989427797822652529149428697746066532921705571401683
++//   encoded: d3bfb518f44f3430f29d0c92af503865a1ed3281dc69b35dd868ba85f886c4ab
++//
++// M (found in 21 iterations):
++//   x: 8158688967149231307266666683326742915289288280191350817196911733632187385319
++//   y: 21622333750659878624441478467798461427617029906629724657331223068277098105040
++//   encoded: d048032c6ea0b6d697ddc2e86bda85a33adac920f1bf18e1b0c6d166a5cecdaf
++//
++// These points and their precomputation tables are generated with the
++// following Python code.
++
++/*
++import hashlib
++import ed25519 as E  # http://ed25519.cr.yp.to/python/ed25519.py
++
++SEED_N = 'edwards25519 point generation seed (N)'
++SEED_M = 'edwards25519 point generation seed (M)'
++
++def genpoint(seed):
++    v = hashlib.sha256(seed).digest()
++    it = 1
++    while True:
++        try:
++            x,y = E.decodepoint(v)
++            if E.scalarmult((x,y), E.l) != [0, 1]:
++                raise Exception('point has wrong order')
++        except Exception, e:
++            print e
++            it += 1
++            v = hashlib.sha256(v).digest()
++            continue
++        print "Found in %d iterations:" % it
++        print "  x = %d" % x
++        print "  y = %d" % y
++        print " Encoded (hex)"
++        print E.encodepoint((x,y)).encode('hex')
++        return (x,y)
++
++def gentable(P):
++    t = []
++    for i in range(1,16):
++        k = (i >> 3 & 1) * (1 << 192) + \
++            (i >> 2 & 1) * (1 << 128) + \
++            (i >> 1 & 1) * (1 <<  64) + \
++            (i      & 1)
++        t.append(E.scalarmult(P, k))
++    return ''.join(E.encodeint(x) + E.encodeint(y) for (x,y) in t)
++
++def printtable(table, name):
++    print "static const uint8_t %s[15 * 2 * 32] = {" % name,
++    for i in range(15 * 2 * 32):
++        if i % 12 == 0:
++            print "\n   ",
++        print " 0x%02x," % ord(table[i]),
++    print "\n};"
++
++if __name__ == "__main__":
++    print "Searching for N"
++    N = genpoint(SEED_N)
++    print "Generating precomputation table for N"
++    Ntable = gentable(N)
++    printtable(Ntable, "kSpakeNSmallPrecomp")
++
++    print "Searching for M"
++    M = genpoint(SEED_M)
++    print "Generating precomputation table for M"
++    Mtable = gentable(M)
++    printtable(Mtable, "kSpakeMSmallPrecomp")
++*/
++
++static const uint8_t kSpakeNSmallPrecomp[15 * 2 * 32] = {
++    0x23, 0xfc, 0x27, 0x6c, 0x55, 0xaf, 0xb3, 0x9c, 0xd8, 0x99, 0x3a, 0x0d,
++    0x7f, 0x08, 0xc9, 0xeb, 0x4d, 0x6e, 0x90, 0x99, 0x2f, 0x3c, 0x15, 0x2b,
++    0x89, 0x5a, 0x0f, 0xf2, 0x67, 0xe6, 0xbf, 0x17, 0xd3, 0xbf, 0xb5, 0x18,
++    0xf4, 0x4f, 0x34, 0x30, 0xf2, 0x9d, 0x0c, 0x92, 0xaf, 0x50, 0x38, 0x65,
++    0xa1, 0xed, 0x32, 0x81, 0xdc, 0x69, 0xb3, 0x5d, 0xd8, 0x68, 0xba, 0x85,
++    0xf8, 0x86, 0xc4, 0x2b, 0x53, 0x93, 0xb1, 0x99, 0x90, 0x30, 0xca, 0xb0,
++    0xbd, 0xea, 0x14, 0x4c, 0x6f, 0x2b, 0x81, 0x1e, 0x23, 0x45, 0xb2, 0x32,
++    0x2e, 0x2d, 0xe6, 0xb8, 0x5d, 0xc5, 0x15, 0x91, 0x63, 0x39, 0x18, 0x5b,
++    0x62, 0x63, 0x9b, 0xf4, 0x8b, 0xe0, 0x34, 0xa2, 0x95, 0x11, 0x92, 0x68,
++    0x54, 0xb7, 0xf3, 0x91, 0xca, 0x22, 0xad, 0x08, 0xd8, 0x9c, 0xa2, 0xf0,
++    0xdc, 0x9c, 0x2c, 0x84, 0x32, 0x26, 0xe0, 0x17, 0x89, 0x53, 0x6b, 0xfd,
++    0x76, 0x97, 0x25, 0xea, 0x99, 0x94, 0xf8, 0x29, 0x7c, 0xc4, 0x53, 0xc0,
++    0x98, 0x9a, 0x20, 0xdc, 0x70, 0x01, 0x50, 0xaa, 0x05, 0xa3, 0x40, 0x50,
++    0x66, 0x87, 0x30, 0x19, 0x12, 0xc3, 0xb8, 0x2d, 0x28, 0x8b, 0x7b, 0x48,
++    0xf7, 0x7b, 0xab, 0x45, 0x70, 0x2e, 0xbb, 0x85, 0xc1, 0x6c, 0xdd, 0x35,
++    0x00, 0x83, 0x20, 0x13, 0x82, 0x08, 0xaa, 0xa3, 0x03, 0x0f, 0xca, 0x27,
++    0x3e, 0x8b, 0x52, 0xc2, 0xd7, 0xb1, 0x8c, 0x22, 0xfe, 0x04, 0x4a, 0xf2,
++    0xe8, 0xac, 0xee, 0x2e, 0xd7, 0x77, 0x34, 0x49, 0xf2, 0xe9, 0xeb, 0x8c,
++    0xa6, 0xc8, 0xc6, 0xcd, 0x8a, 0x8f, 0x7c, 0x5d, 0x51, 0xc8, 0xfa, 0x6f,
++    0xb3, 0x93, 0xdb, 0x71, 0xef, 0x3e, 0x6e, 0xa7, 0x85, 0xc7, 0xd4, 0x3e,
++    0xa2, 0xe2, 0xc0, 0xaa, 0x17, 0xb3, 0xa4, 0x7c, 0xc2, 0x3f, 0x7c, 0x7a,
++    0xdd, 0x26, 0xde, 0x3e, 0xf1, 0x99, 0x06, 0xf7, 0x69, 0x1b, 0xc9, 0x20,
++    0x55, 0x4f, 0x86, 0x7a, 0x93, 0x89, 0x68, 0xe9, 0x2b, 0x2d, 0xbc, 0x08,
++    0x15, 0x5d, 0x2d, 0x0b, 0x4f, 0x1a, 0xb3, 0xd4, 0x8e, 0x77, 0x79, 0x2a,
++    0x25, 0xf9, 0xb6, 0x46, 0xfb, 0x87, 0x02, 0xa6, 0xe0, 0xd3, 0xba, 0x84,
++    0xea, 0x3e, 0x58, 0xa5, 0x7f, 0x8f, 0x8c, 0x39, 0x79, 0x28, 0xb5, 0xcf,
++    0xe4, 0xca, 0x63, 0xdc, 0xac, 0xed, 0x4b, 0x74, 0x1e, 0x94, 0x85, 0x8c,
++    0xe5, 0xf4, 0x76, 0x6f, 0x20, 0x67, 0x8b, 0xd8, 0xd6, 0x4b, 0xe7, 0x2d,
++    0xa0, 0xbd, 0xcc, 0x1f, 0xdf, 0x46, 0x9c, 0xa2, 0x49, 0x64, 0xdf, 0x24,
++    0x00, 0x11, 0x11, 0x45, 0x62, 0x5c, 0xd7, 0x8a, 0x00, 0x02, 0xf5, 0x9b,
++    0x4f, 0x53, 0x42, 0xc5, 0xd5, 0x55, 0x80, 0x73, 0x9a, 0x5b, 0x31, 0x5a,
++    0xbd, 0x3a, 0x43, 0xe9, 0x33, 0xe5, 0xaf, 0x1d, 0x92, 0x5e, 0x59, 0x37,
++    0xae, 0x57, 0xfa, 0x3b, 0xd2, 0x31, 0xae, 0xa6, 0xf9, 0xc9, 0xc1, 0x82,
++    0xa6, 0xa5, 0xed, 0x24, 0x53, 0x4b, 0x38, 0x22, 0xf2, 0x85, 0x8d, 0x13,
++    0xa6, 0x5e, 0xd6, 0x57, 0x17, 0xd3, 0x33, 0x38, 0x8d, 0x65, 0xd3, 0xcb,
++    0x1a, 0xa2, 0x3a, 0x2b, 0xbb, 0x61, 0x53, 0xd7, 0xff, 0xcd, 0x20, 0xb6,
++    0xbb, 0x8c, 0xab, 0x63, 0xef, 0xb8, 0x26, 0x7e, 0x81, 0x65, 0xaf, 0x90,
++    0xfc, 0xd2, 0xb6, 0x72, 0xdb, 0xe9, 0x23, 0x78, 0x12, 0x04, 0xc0, 0x03,
++    0x82, 0xa8, 0x7a, 0x0f, 0x48, 0x6f, 0x82, 0x7f, 0x81, 0xcd, 0xa7, 0x89,
++    0xdd, 0x86, 0xea, 0x5e, 0xa1, 0x50, 0x14, 0x34, 0x17, 0x64, 0x82, 0x0f,
++    0xc4, 0x40, 0x20, 0x1d, 0x8f, 0xfe, 0xfa, 0x99, 0xaf, 0x5b, 0xc1, 0x5d,
++    0xc8, 0x47, 0x07, 0x54, 0x4a, 0x22, 0x56, 0x57, 0xf1, 0x2c, 0x3b, 0x62,
++    0x7f, 0x12, 0x62, 0xaf, 0xfd, 0xf8, 0x04, 0x11, 0xa8, 0x51, 0xf0, 0x46,
++    0x5d, 0x79, 0x66, 0xff, 0x8a, 0x06, 0xef, 0x54, 0x64, 0x1b, 0x84, 0x3e,
++    0x41, 0xf3, 0xfe, 0x19, 0x51, 0xf7, 0x44, 0x9c, 0x16, 0xd3, 0x7a, 0x09,
++    0x59, 0xf5, 0x47, 0x45, 0xd0, 0x31, 0xef, 0x96, 0x2c, 0xc5, 0xc0, 0xd0,
++    0x56, 0xef, 0x3f, 0x07, 0x2b, 0xb7, 0x28, 0x49, 0xf5, 0xb1, 0x42, 0x18,
++    0xcf, 0x77, 0xd8, 0x2b, 0x71, 0x74, 0x80, 0xba, 0x34, 0x52, 0xce, 0x11,
++    0xfe, 0xc4, 0xb9, 0xeb, 0xf9, 0xc4, 0x5e, 0x1f, 0xd3, 0xde, 0x4b, 0x14,
++    0xe3, 0x6e, 0xe7, 0xd7, 0x83, 0x59, 0x98, 0xe8, 0x3d, 0x8e, 0xd6, 0x7d,
++    0xc0, 0x9a, 0x79, 0xb9, 0x83, 0xf1, 0xc1, 0x00, 0x5d, 0x16, 0x1b, 0x44,
++    0xe9, 0x02, 0xce, 0x99, 0x1e, 0x77, 0xef, 0xca, 0xbc, 0xf0, 0x6a, 0xb9,
++    0x65, 0x3f, 0x3c, 0xd9, 0xe1, 0x63, 0x0b, 0xbf, 0xaa, 0xa7, 0xe6, 0x6d,
++    0x6d, 0x3f, 0x44, 0x29, 0xa3, 0x8b, 0x6d, 0xc4, 0x81, 0xa9, 0xc3, 0x5a,
++    0x90, 0x55, 0x72, 0x61, 0x17, 0x22, 0x7f, 0x3e, 0x5f, 0xfc, 0xba, 0xb3,
++    0x7a, 0x99, 0x76, 0xe9, 0x20, 0xe5, 0xc5, 0xe8, 0x55, 0x56, 0x0f, 0x7a,
++    0x48, 0xe7, 0xbc, 0xe1, 0x13, 0xf4, 0x90, 0xef, 0x97, 0x6c, 0x02, 0x89,
++    0x4d, 0x22, 0x48, 0xda, 0xd3, 0x52, 0x45, 0x31, 0x26, 0xcc, 0xe8, 0x9e,
++    0x5d, 0xdd, 0x75, 0xe4, 0x1d, 0xbc, 0xb1, 0x08, 0x55, 0xaf, 0x54, 0x70,
++    0x0d, 0x0c, 0xf3, 0x50, 0xbc, 0x40, 0x83, 0xee, 0xdc, 0x6d, 0x8b, 0x40,
++    0x79, 0x62, 0x18, 0x37, 0xc4, 0x78, 0x02, 0x58, 0x7c, 0x78, 0xd3, 0x54,
++    0xed, 0x31, 0xbd, 0x7d, 0x48, 0xcf, 0xb6, 0x11, 0x27, 0x37, 0x9c, 0x86,
++    0xf7, 0x2e, 0x00, 0x7a, 0x48, 0x1b, 0xa6, 0x72, 0x70, 0x7b, 0x44, 0x45,
++    0xeb, 0x49, 0xbf, 0xbe, 0x09, 0x78, 0x66, 0x71, 0x12, 0x7f, 0x3d, 0x78,
++    0x51, 0x24, 0x82, 0xa2, 0xf0, 0x1e, 0x83, 0x81, 0x81, 0x45, 0x53, 0xfd,
++    0x5e, 0xf3, 0x03, 0x74, 0xbd, 0x23, 0x35, 0xf6, 0x10, 0xdd, 0x7c, 0x73,
++    0x46, 0x32, 0x09, 0x54, 0x99, 0x95, 0x91, 0x25, 0xb8, 0x32, 0x09, 0xd8,
++    0x2f, 0x97, 0x50, 0xa3, 0xf5, 0xd6, 0xb1, 0xed, 0x97, 0x51, 0x06, 0x42,
++    0x12, 0x0c, 0x69, 0x38, 0x09, 0xa0, 0xd8, 0x19, 0x70, 0xf7, 0x8f, 0x61,
++    0x0d, 0x56, 0x43, 0x66, 0x22, 0x8b, 0x0e, 0x0e, 0xf9, 0x81, 0x9f, 0xac,
++    0x6f, 0xbf, 0x7d, 0x04, 0x13, 0xf2, 0xe4, 0xeb, 0xfd, 0xbe, 0x4e, 0x56,
++    0xda, 0xe0, 0x22, 0x6d, 0x1b, 0x25, 0xc8, 0xa5, 0x9c, 0x05, 0x45, 0x52,
++    0x3c, 0x3a, 0xde, 0x6b, 0xac, 0x9b, 0xf8, 0x81, 0x97, 0x21, 0x46, 0xac,
++    0x7e, 0x89, 0xf8, 0x49, 0x58, 0xbb, 0x45, 0xac, 0xa2, 0xc4, 0x90, 0x1f,
++    0xb2, 0xb4, 0xf8, 0xe0, 0xcd, 0xa1, 0x9d, 0x1c, 0xf2, 0xf1, 0xdf, 0xfb,
++    0x88, 0x4e, 0xe5, 0x41, 0xd8, 0x6e, 0xac, 0x07, 0x87, 0x95, 0x35, 0xa6,
++    0x12, 0x08, 0x5d, 0x57, 0x5e, 0xaf, 0x71, 0x0f, 0x07, 0x4e, 0x81, 0x77,
++    0xf1, 0xef, 0xb5, 0x35, 0x5c, 0xfa, 0xf4, 0x4e, 0x42, 0xdc, 0x19, 0xfe,
++    0xe4, 0xd2, 0xb4, 0x27, 0xfb, 0x34, 0x1f, 0xb2, 0x6f, 0xf2, 0x95, 0xcc,
++    0xd4, 0x47, 0x63, 0xdc, 0x7e, 0x4f, 0x97, 0x2b, 0x7a, 0xe0, 0x80, 0x31,
++};
++
++static const uint8_t kSpakeMSmallPrecomp[15 * 2 * 32] = {
++    0xe7, 0x45, 0x7e, 0x47, 0x49, 0x69, 0xbd, 0x1b, 0x35, 0x1c, 0x2c, 0x98,
++    0x03, 0xf3, 0xb3, 0x37, 0xde, 0x39, 0xa5, 0xda, 0xc0, 0x2e, 0xa4, 0xac,
++    0x7d, 0x08, 0x26, 0xfc, 0x80, 0xa7, 0x09, 0x12, 0xd0, 0x48, 0x03, 0x2c,
++    0x6e, 0xa0, 0xb6, 0xd6, 0x97, 0xdd, 0xc2, 0xe8, 0x6b, 0xda, 0x85, 0xa3,
++    0x3a, 0xda, 0xc9, 0x20, 0xf1, 0xbf, 0x18, 0xe1, 0xb0, 0xc6, 0xd1, 0x66,
++    0xa5, 0xce, 0xcd, 0x2f, 0x80, 0xa8, 0x4e, 0xc3, 0x81, 0xae, 0x68, 0x3b,
++    0x0d, 0xdb, 0x56, 0x32, 0x2f, 0xa8, 0x97, 0xa0, 0x5c, 0x15, 0xc1, 0xcb,
++    0x6f, 0x7a, 0x5f, 0xc5, 0x32, 0xfb, 0x49, 0x17, 0x18, 0xfa, 0x85, 0x08,
++    0x85, 0xf1, 0xe3, 0x11, 0x8e, 0x3d, 0x70, 0x20, 0x38, 0x4e, 0x0c, 0x17,
++    0xa1, 0xa8, 0x20, 0xd2, 0xb1, 0x1d, 0x05, 0x8d, 0x0f, 0xc9, 0x96, 0x18,
++    0x9d, 0x8c, 0x89, 0x8f, 0x46, 0x6a, 0x6c, 0x6e, 0x72, 0x03, 0xb2, 0x75,
++    0x87, 0xd8, 0xa9, 0x60, 0x93, 0x2b, 0x8b, 0x66, 0xee, 0xaf, 0xce, 0x98,
++    0xcd, 0x6b, 0x7c, 0x6a, 0xbe, 0x19, 0xda, 0x66, 0x7c, 0xda, 0x53, 0xa0,
++    0xe3, 0x9a, 0x0e, 0x53, 0x3a, 0x7c, 0x73, 0x4a, 0x37, 0xa6, 0x53, 0x23,
++    0x67, 0x31, 0xce, 0x8a, 0xab, 0xee, 0x72, 0x76, 0xc2, 0xb5, 0x54, 0x42,
++    0xcf, 0x4b, 0xc7, 0x53, 0x24, 0x59, 0xaf, 0x76, 0x53, 0x10, 0x7e, 0x25,
++    0x94, 0x5c, 0x23, 0xa6, 0x5e, 0x05, 0xea, 0x14, 0xad, 0x2b, 0xce, 0x50,
++    0x77, 0xb3, 0x7a, 0x88, 0x4c, 0xf7, 0x74, 0x04, 0x35, 0xa4, 0x0c, 0x9e,
++    0xee, 0x6a, 0x4c, 0x3c, 0xc1, 0x6a, 0x35, 0x4d, 0x6d, 0x8f, 0x94, 0x95,
++    0xe4, 0x10, 0xca, 0x46, 0x4e, 0xfa, 0x38, 0x40, 0xeb, 0x1a, 0x1b, 0x5a,
++    0xff, 0x73, 0x4d, 0xe9, 0xf2, 0xbe, 0x89, 0xf5, 0xd1, 0x72, 0xd0, 0x1a,
++    0x7b, 0x82, 0x08, 0x19, 0xda, 0x54, 0x44, 0xa5, 0x3d, 0xd8, 0x10, 0x1c,
++    0xcf, 0x3b, 0xc7, 0x54, 0xd5, 0x11, 0xd7, 0x2a, 0x69, 0x3f, 0xa6, 0x58,
++    0x74, 0xfd, 0x90, 0xb2, 0xf4, 0xc2, 0x0e, 0xf3, 0x19, 0x8f, 0x51, 0x7c,
++    0x31, 0x12, 0x79, 0x61, 0x16, 0xb4, 0x2f, 0x2f, 0xd0, 0x88, 0x97, 0xf2,
++    0xc3, 0x8c, 0xa6, 0xa3, 0x29, 0xff, 0x7e, 0x12, 0x46, 0x2a, 0x9c, 0x09,
++    0x7c, 0x5f, 0x87, 0x07, 0x6b, 0xa1, 0x9a, 0x57, 0x55, 0x8e, 0xb0, 0x56,
++    0x5d, 0xc9, 0x4c, 0x5b, 0xae, 0xd3, 0xd0, 0x8e, 0xb8, 0xac, 0xba, 0xe8,
++    0x54, 0x45, 0x30, 0x14, 0xf6, 0x59, 0x20, 0xc4, 0x03, 0xb7, 0x7a, 0x5d,
++    0x6b, 0x5a, 0xcb, 0x28, 0x60, 0xf8, 0xef, 0x61, 0x60, 0x78, 0x6b, 0xf5,
++    0x21, 0x4b, 0x75, 0xc2, 0x77, 0xba, 0x0e, 0x38, 0x98, 0xe0, 0xfb, 0xb7,
++    0x5f, 0x75, 0x87, 0x04, 0x0c, 0xb4, 0x5c, 0x09, 0x04, 0x00, 0x38, 0x4e,
++    0x4f, 0x7b, 0x73, 0xe5, 0xdb, 0xdb, 0xf1, 0xf4, 0x5c, 0x64, 0x68, 0xfd,
++    0xb1, 0x86, 0xe8, 0x89, 0xbe, 0x9c, 0xd4, 0x96, 0x1d, 0xcb, 0xdc, 0x5c,
++    0xef, 0xd4, 0x33, 0x28, 0xb9, 0xb6, 0xaf, 0x3b, 0xcf, 0x8d, 0x30, 0xba,
++    0xe8, 0x08, 0xcf, 0x84, 0xba, 0x61, 0x10, 0x9b, 0x62, 0xf6, 0x18, 0x79,
++    0x66, 0x87, 0x82, 0x7c, 0xaa, 0x71, 0xac, 0xd0, 0xd0, 0x32, 0xb0, 0x54,
++    0x03, 0xa4, 0xad, 0x3f, 0x72, 0xca, 0x22, 0xff, 0x01, 0x87, 0x08, 0x36,
++    0x61, 0x22, 0xaa, 0x18, 0xab, 0x3a, 0xbc, 0xf2, 0x78, 0x05, 0xe1, 0x99,
++    0xa3, 0x59, 0x98, 0xcc, 0x21, 0xc6, 0x2b, 0x51, 0x6d, 0x43, 0x0a, 0x46,
++    0x50, 0xae, 0x11, 0x7e, 0xd5, 0x23, 0x56, 0xef, 0x83, 0xc8, 0xbf, 0x42,
++    0xf0, 0x45, 0x52, 0x1f, 0x34, 0xbc, 0x2f, 0xb0, 0xf0, 0xce, 0xf0, 0xec,
++    0xd0, 0x99, 0x59, 0x2e, 0x1f, 0xab, 0xa8, 0x1e, 0x4b, 0xce, 0x1b, 0x9a,
++    0x75, 0xc6, 0xc4, 0x71, 0x86, 0xf0, 0x8d, 0xec, 0xb0, 0x30, 0xb9, 0x62,
++    0xb3, 0xb7, 0xdd, 0x96, 0x29, 0xc8, 0xbf, 0xe9, 0xb0, 0x74, 0x78, 0x7b,
++    0xf7, 0xea, 0xa3, 0x14, 0x12, 0x56, 0xe0, 0xf3, 0x35, 0x7a, 0x26, 0x4a,
++    0x4c, 0xe6, 0xdf, 0x13, 0xb5, 0x52, 0xb0, 0x2a, 0x5f, 0x2e, 0xac, 0x34,
++    0xab, 0x5f, 0x1a, 0x01, 0xe4, 0x15, 0x1a, 0xd1, 0xbf, 0xc9, 0x95, 0x0a,
++    0xac, 0x1d, 0xe7, 0x53, 0x59, 0x8d, 0xc3, 0x21, 0x78, 0x5e, 0x12, 0x97,
++    0x8f, 0x4e, 0x1d, 0xf9, 0xe5, 0xe2, 0xc2, 0xc4, 0xba, 0xfb, 0x50, 0x96,
++    0x5b, 0x43, 0xe8, 0xf7, 0x0d, 0x1b, 0x64, 0x58, 0xbe, 0xd3, 0x95, 0x7f,
++    0x8e, 0xf1, 0x85, 0x35, 0xba, 0x25, 0x55, 0x2e, 0x02, 0x46, 0x5c, 0xad,
++    0x1f, 0xc5, 0x03, 0xcc, 0xd0, 0x43, 0x4c, 0xf2, 0x5e, 0x64, 0x0a, 0x89,
++    0xd9, 0xfd, 0x23, 0x7d, 0x4f, 0xbe, 0x2f, 0x0f, 0x1e, 0x12, 0x4a, 0xd9,
++    0xf8, 0x82, 0xde, 0x8f, 0x4f, 0x98, 0xb9, 0x90, 0xf6, 0xfa, 0xd1, 0x11,
++    0xa6, 0xdc, 0x7e, 0x32, 0x48, 0x6a, 0x8a, 0x14, 0x5e, 0x73, 0xb9, 0x6c,
++    0x0e, 0xc2, 0xf9, 0xcc, 0xf0, 0x32, 0xc8, 0xb5, 0x56, 0xaa, 0x5d, 0xd2,
++    0x07, 0xf1, 0x6f, 0x33, 0x6f, 0x05, 0x70, 0x49, 0x60, 0x49, 0x23, 0x23,
++    0x14, 0x0e, 0x4c, 0x58, 0x92, 0xad, 0xa9, 0x50, 0xb1, 0x59, 0x43, 0x96,
++    0x7b, 0xc1, 0x51, 0x45, 0xef, 0x0d, 0xef, 0xd1, 0xe4, 0xd0, 0xce, 0xdf,
++    0x6a, 0xbc, 0x1b, 0xbf, 0x7a, 0x87, 0x4e, 0x47, 0x17, 0x9c, 0x34, 0x38,
++    0xb0, 0x3c, 0xa1, 0x04, 0xfb, 0xe2, 0x66, 0xce, 0xb6, 0x82, 0xbb, 0xad,
++    0xc3, 0x8e, 0x12, 0x35, 0xbc, 0x17, 0xce, 0x01, 0x2d, 0xa3, 0xa6, 0xb9,
++    0xfa, 0x84, 0xc2, 0x2f, 0x5a, 0x4a, 0x8c, 0x4c, 0x11, 0x4e, 0xa8, 0x14,
++    0xcb, 0xb8, 0x99, 0xaa, 0x2e, 0x8c, 0xa0, 0xc9, 0x5f, 0x62, 0x2a, 0x84,
++    0x66, 0x60, 0x0a, 0x7e, 0xdc, 0x93, 0x17, 0x45, 0x19, 0xb3, 0x93, 0x4c,
++    0xdc, 0xd0, 0xd5, 0x5c, 0x25, 0xd2, 0xcd, 0x4e, 0x84, 0x4c, 0x73, 0xb3,
++    0x90, 0xa4, 0x22, 0x05, 0x2c, 0x7c, 0x39, 0x2b, 0x70, 0xd9, 0x61, 0x76,
++    0xb2, 0x03, 0x71, 0xe9, 0x0e, 0xf8, 0x57, 0x85, 0xad, 0xb1, 0x2f, 0x34,
++    0xa5, 0x66, 0xb0, 0x0f, 0x75, 0x94, 0x6e, 0x26, 0x79, 0x99, 0xb4, 0xe2,
++    0xe2, 0xa3, 0x58, 0xdd, 0xb4, 0xfb, 0x74, 0xf4, 0xa1, 0xca, 0xc3, 0x30,
++    0xe7, 0x86, 0xb2, 0xa2, 0x2c, 0x11, 0xc9, 0x58, 0xe3, 0xc1, 0xa6, 0x5f,
++    0x86, 0x6a, 0xe7, 0x75, 0xd5, 0xd8, 0x63, 0x95, 0x64, 0x59, 0xbc, 0xb8,
++    0xb7, 0xf5, 0x12, 0xe3, 0x03, 0xc6, 0x17, 0xea, 0x4e, 0xcb, 0xee, 0x4c,
++    0xae, 0x03, 0xd1, 0x33, 0xd0, 0x39, 0x36, 0x00, 0x0f, 0xf4, 0x9c, 0xbd,
++    0x35, 0x96, 0xfd, 0x0d, 0x26, 0xb7, 0x9e, 0xf4, 0x4b, 0x6f, 0x4b, 0xf1,
++    0xec, 0x11, 0x00, 0x16, 0x21, 0x1e, 0xd4, 0x43, 0x23, 0x8c, 0x4a, 0xfa,
++    0x9e, 0xd4, 0x2b, 0x36, 0x9a, 0x43, 0x1e, 0x58, 0x31, 0xe8, 0x1f, 0x83,
++    0x15, 0x20, 0x31, 0x68, 0xfe, 0x27, 0xd3, 0xd8, 0x9b, 0x43, 0x81, 0x8f,
++    0x57, 0x32, 0x14, 0xe6, 0x9e, 0xbf, 0xd1, 0xfb, 0xdf, 0xad, 0x7a, 0x52,
++};
++
++/* left_shift_3 sets |n| to |n|*8, where |n| is represented in little-endian
++ * order. */
++static void left_shift_3(uint8_t n[32]) {
++  uint8_t carry = 0;
++  unsigned i;
++
++  for (i = 0; i < 32; i++) {
++    const uint8_t next_carry = n[i] >> 5;
++    n[i] = (n[i] << 3) | carry;
++    carry = next_carry;
++  }
++}
++
++static krb5_error_code
++builtin_edwards25519_keygen(krb5_context context, groupdata *gdata,
++                            const uint8_t *wbytes, krb5_boolean use_m,
++                            uint8_t *priv_out, uint8_t *pub_out)
++{
++  uint8_t private[64];
++  krb5_data data = make_data(private, 32);
++  krb5_error_code ret;
++
++  /* Pick x or y uniformly from [0, p*h) divisible by h. */
++  ret = krb5_c_random_make_octets(context, &data);
++  if (ret)
++    return ret;
++  memset(private + 32, 0, 32);
++  x25519_sc_reduce(private);
++  left_shift_3(private);
++
++  /* Compute X=x*G or Y=y*G. */
++  ge_p3 P;
++  x25519_ge_scalarmult_base(&P, private);
++
++  /* Compute w mod p. */
++  uint8_t wreduced[64];
++  memcpy(wreduced, wbytes, 32);
++  memset(wreduced + 32, 0, 32);
++  x25519_sc_reduce(wreduced);
++
++  /* Compute the mask, w*M or w*N. */
++  ge_p3 mask;
++  x25519_ge_scalarmult_small_precomp(&mask, wreduced,
++                                     use_m ? kSpakeMSmallPrecomp :
++                                     kSpakeNSmallPrecomp);
++
++  /* Compute the masked point T=w*M+X or S=w*N+Y. */
++  ge_cached mask_cached;
++  x25519_ge_p3_to_cached(&mask_cached, &mask);
++  ge_p1p1 Pmasked;
++  x25519_ge_add(&Pmasked, &P, &mask_cached);
++
++  /* Encode T or S into pub_out. */
++  ge_p2 Pmasked_proj;
++  x25519_ge_p1p1_to_p2(&Pmasked_proj, &Pmasked);
++  x25519_ge_tobytes(pub_out, &Pmasked_proj);
++
++  /* Remember the private key in priv_out. */
++  memcpy(priv_out, private, 32);
++  return 0;
++}
++
++static krb5_error_code
++builtin_edwards25519_result(krb5_context context, groupdata *gdata,
++                            const uint8_t *wbytes, const uint8_t *ourpriv,
++                            const uint8_t *theirpub, krb5_boolean use_m,
++                            uint8_t *elem_out)
++{
++  /*
++   * Check if the point received from peer is on the curve.  This does not
++   * verify that it is in the generator subgroup, but since our private key is
++   * a multiple of the cofactor, the shared point will be in the generator
++   * subgroup even if a rogue peer sends a point which is not.
++   */
++  ge_p3 Qmasked;
++  if (x25519_ge_frombytes_vartime(&Qmasked, theirpub) != 0)
++    return EINVAL;
++
++  /* Compute w mod p. */
++  uint8_t wreduced[64];
++  memcpy(wreduced, wbytes, 32);
++  memset(wreduced + 32, 0, 32);
++  x25519_sc_reduce(wreduced);
++
++  /* Compute the peer's mask, w*M or w*N. */
++  ge_p3 peers_mask;
++  x25519_ge_scalarmult_small_precomp(&peers_mask, wreduced,
++                                     use_m ? kSpakeMSmallPrecomp :
++                                     kSpakeNSmallPrecomp);
++
++  ge_cached peers_mask_cached;
++  x25519_ge_p3_to_cached(&peers_mask_cached, &peers_mask);
++
++  /* Compute the peer's unmasked point, T-w*M or S-w*N. */
++  ge_p1p1 Qcompl;
++  ge_p3 Qunmasked;
++  x25519_ge_sub(&Qcompl, &Qmasked, &peers_mask_cached);
++  x25519_ge_p1p1_to_p3(&Qunmasked, &Qcompl);
++
++  /* Multiply by our private value to compute K=x*(S-w*N) or K=y*(T-w*M). */
++  ge_p2 K;
++  x25519_ge_scalarmult(&K, ourpriv, &Qunmasked);
++
++  /* Encode K into elem_out. */
++  x25519_ge_tobytes(elem_out, &K);
++  return 0;
++}
++
++static krb5_error_code
++builtin_sha256(krb5_context context, groupdata *gdata, const krb5_data *dlist,
++               size_t ndata, uint8_t *result_out)
++{
++  return k5_sha256(dlist, ndata, result_out);
++}
++
++groupdef builtin_edwards25519 = {
++  .reg = &spake_iana_edwards25519,
++  .keygen = builtin_edwards25519_keygen,
++  .result = builtin_edwards25519_result,
++  .hash = builtin_sha256
++};
+diff --git a/src/plugins/preauth/spake/edwards25519_tables.h b/src/plugins/preauth/spake/edwards25519_tables.h
+new file mode 100644
+index 000000000..c6c501373
+--- /dev/null
++++ b/src/plugins/preauth/spake/edwards25519_tables.h
+@@ -0,0 +1,7881 @@
++/* -*- mode: c; c-basic-offset: 2; indent-tabs-mode: nil -*- */
++/*
++ * The MIT License (MIT)
++ *
++ * Copyright (c) 2015-2016 the fiat-crypto authors (see the AUTHORS file).
++ *
++ * Permission is hereby granted, free of charge, to any person obtaining a copy
++ * of this software and associated documentation files (the "Software"), to deal
++ * in the Software without restriction, including without limitation the rights
++ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
++ * copies of the Software, and to permit persons to whom the Software is
++ * furnished to do so, subject to the following conditions:
++ *
++ * The above copyright notice and this permission notice shall be included in
++ * all copies or substantial portions of the Software.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
++ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
++ * SOFTWARE.
++ */
++
++/* From BoringSSL third-party/fiat/curve25519_tables.h */
++
++static const fe d = {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++    929955233495203, 466365720129213, 1662059464998953, 2033849074728123,
++    1442794654840575
++#else
++    56195235, 13857412, 51736253, 6949390, 114729, 24766616, 60832955, 30306712,
++    48412415, 21499315
++#endif
++}};
++
++static const fe sqrtm1 = {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++    1718705420411056, 234908883556509, 2233514472574048, 2117202627021982,
++    765476049583133
++#else
++    34513072, 25610706, 9377949, 3500415, 12389472, 33281959, 41962654,
++    31548777, 326685, 11406482
++#endif
++}};
++
++static const fe d2 = {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++    1859910466990425, 932731440258426, 1072319116312658, 1815898335770999,
++    633789495995903
++#else
++    45281625, 27714825, 36363642, 13898781, 229458, 15978800, 54557047,
++    27058993, 29715967, 9444199
++#endif
++}};
++
++#if defined(CONFIG_SMALL)
++
++// This block of code replaces the standard base-point table with a much smaller
++// one. The standard table is 30,720 bytes while this one is just 960.
++//
++// This table contains 15 pairs of group elements, (x, y), where each field
++// element is serialised with |fe_tobytes|. If |i| is the index of the group
++// element then consider i+1 as a four-bit number: (i₀, i₁, i₂, i₃) (where i₀
++// is the most significant bit). The value of the group element is then:
++// (i₀×2^192 + i₁×2^128 + i₂×2^64 + i₃)G, where G is the generator.
++static const uint8_t k25519SmallPrecomp[15 * 2 * 32] = {
++    0x1a, 0xd5, 0x25, 0x8f, 0x60, 0x2d, 0x56, 0xc9, 0xb2, 0xa7, 0x25, 0x95,
++    0x60, 0xc7, 0x2c, 0x69, 0x5c, 0xdc, 0xd6, 0xfd, 0x31, 0xe2, 0xa4, 0xc0,
++    0xfe, 0x53, 0x6e, 0xcd, 0xd3, 0x36, 0x69, 0x21, 0x58, 0x66, 0x66, 0x66,
++    0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66,
++    0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66,
++    0x66, 0x66, 0x66, 0x66, 0x02, 0xa2, 0xed, 0xf4, 0x8f, 0x6b, 0x0b, 0x3e,
++    0xeb, 0x35, 0x1a, 0xd5, 0x7e, 0xdb, 0x78, 0x00, 0x96, 0x8a, 0xa0, 0xb4,
++    0xcf, 0x60, 0x4b, 0xd4, 0xd5, 0xf9, 0x2d, 0xbf, 0x88, 0xbd, 0x22, 0x62,
++    0x13, 0x53, 0xe4, 0x82, 0x57, 0xfa, 0x1e, 0x8f, 0x06, 0x2b, 0x90, 0xba,
++    0x08, 0xb6, 0x10, 0x54, 0x4f, 0x7c, 0x1b, 0x26, 0xed, 0xda, 0x6b, 0xdd,
++    0x25, 0xd0, 0x4e, 0xea, 0x42, 0xbb, 0x25, 0x03, 0xa2, 0xfb, 0xcc, 0x61,
++    0x67, 0x06, 0x70, 0x1a, 0xc4, 0x78, 0x3a, 0xff, 0x32, 0x62, 0xdd, 0x2c,
++    0xab, 0x50, 0x19, 0x3b, 0xf2, 0x9b, 0x7d, 0xb8, 0xfd, 0x4f, 0x29, 0x9c,
++    0xa7, 0x91, 0xba, 0x0e, 0x46, 0x5e, 0x51, 0xfe, 0x1d, 0xbf, 0xe5, 0xe5,
++    0x9b, 0x95, 0x0d, 0x67, 0xf8, 0xd1, 0xb5, 0x5a, 0xa1, 0x93, 0x2c, 0xc3,
++    0xde, 0x0e, 0x97, 0x85, 0x2d, 0x7f, 0xea, 0xab, 0x3e, 0x47, 0x30, 0x18,
++    0x24, 0xe8, 0xb7, 0x60, 0xae, 0x47, 0x80, 0xfc, 0xe5, 0x23, 0xe7, 0xc2,
++    0xc9, 0x85, 0xe6, 0x98, 0xa0, 0x29, 0x4e, 0xe1, 0x84, 0x39, 0x2d, 0x95,
++    0x2c, 0xf3, 0x45, 0x3c, 0xff, 0xaf, 0x27, 0x4c, 0x6b, 0xa6, 0xf5, 0x4b,
++    0x11, 0xbd, 0xba, 0x5b, 0x9e, 0xc4, 0xa4, 0x51, 0x1e, 0xbe, 0xd0, 0x90,
++    0x3a, 0x9c, 0xc2, 0x26, 0xb6, 0x1e, 0xf1, 0x95, 0x7d, 0xc8, 0x6d, 0x52,
++    0xe6, 0x99, 0x2c, 0x5f, 0x9a, 0x96, 0x0c, 0x68, 0x29, 0xfd, 0xe2, 0xfb,
++    0xe6, 0xbc, 0xec, 0x31, 0x08, 0xec, 0xe6, 0xb0, 0x53, 0x60, 0xc3, 0x8c,
++    0xbe, 0xc1, 0xb3, 0x8a, 0x8f, 0xe4, 0x88, 0x2b, 0x55, 0xe5, 0x64, 0x6e,
++    0x9b, 0xd0, 0xaf, 0x7b, 0x64, 0x2a, 0x35, 0x25, 0x10, 0x52, 0xc5, 0x9e,
++    0x58, 0x11, 0x39, 0x36, 0x45, 0x51, 0xb8, 0x39, 0x93, 0xfc, 0x9d, 0x6a,
++    0xbe, 0x58, 0xcb, 0xa4, 0x0f, 0x51, 0x3c, 0x38, 0x05, 0xca, 0xab, 0x43,
++    0x63, 0x0e, 0xf3, 0x8b, 0x41, 0xa6, 0xf8, 0x9b, 0x53, 0x70, 0x80, 0x53,
++    0x86, 0x5e, 0x8f, 0xe3, 0xc3, 0x0d, 0x18, 0xc8, 0x4b, 0x34, 0x1f, 0xd8,
++    0x1d, 0xbc, 0xf2, 0x6d, 0x34, 0x3a, 0xbe, 0xdf, 0xd9, 0xf6, 0xf3, 0x89,
++    0xa1, 0xe1, 0x94, 0x9f, 0x5d, 0x4c, 0x5d, 0xe9, 0xa1, 0x49, 0x92, 0xef,
++    0x0e, 0x53, 0x81, 0x89, 0x58, 0x87, 0xa6, 0x37, 0xf1, 0xdd, 0x62, 0x60,
++    0x63, 0x5a, 0x9d, 0x1b, 0x8c, 0xc6, 0x7d, 0x52, 0xea, 0x70, 0x09, 0x6a,
++    0xe1, 0x32, 0xf3, 0x73, 0x21, 0x1f, 0x07, 0x7b, 0x7c, 0x9b, 0x49, 0xd8,
++    0xc0, 0xf3, 0x25, 0x72, 0x6f, 0x9d, 0xed, 0x31, 0x67, 0x36, 0x36, 0x54,
++    0x40, 0x92, 0x71, 0xe6, 0x11, 0x28, 0x11, 0xad, 0x93, 0x32, 0x85, 0x7b,
++    0x3e, 0xb7, 0x3b, 0x49, 0x13, 0x1c, 0x07, 0xb0, 0x2e, 0x93, 0xaa, 0xfd,
++    0xfd, 0x28, 0x47, 0x3d, 0x8d, 0xd2, 0xda, 0xc7, 0x44, 0xd6, 0x7a, 0xdb,
++    0x26, 0x7d, 0x1d, 0xb8, 0xe1, 0xde, 0x9d, 0x7a, 0x7d, 0x17, 0x7e, 0x1c,
++    0x37, 0x04, 0x8d, 0x2d, 0x7c, 0x5e, 0x18, 0x38, 0x1e, 0xaf, 0xc7, 0x1b,
++    0x33, 0x48, 0x31, 0x00, 0x59, 0xf6, 0xf2, 0xca, 0x0f, 0x27, 0x1b, 0x63,
++    0x12, 0x7e, 0x02, 0x1d, 0x49, 0xc0, 0x5d, 0x79, 0x87, 0xef, 0x5e, 0x7a,
++    0x2f, 0x1f, 0x66, 0x55, 0xd8, 0x09, 0xd9, 0x61, 0x38, 0x68, 0xb0, 0x07,
++    0xa3, 0xfc, 0xcc, 0x85, 0x10, 0x7f, 0x4c, 0x65, 0x65, 0xb3, 0xfa, 0xfa,
++    0xa5, 0x53, 0x6f, 0xdb, 0x74, 0x4c, 0x56, 0x46, 0x03, 0xe2, 0xd5, 0x7a,
++    0x29, 0x1c, 0xc6, 0x02, 0xbc, 0x59, 0xf2, 0x04, 0x75, 0x63, 0xc0, 0x84,
++    0x2f, 0x60, 0x1c, 0x67, 0x76, 0xfd, 0x63, 0x86, 0xf3, 0xfa, 0xbf, 0xdc,
++    0xd2, 0x2d, 0x90, 0x91, 0xbd, 0x33, 0xa9, 0xe5, 0x66, 0x0c, 0xda, 0x42,
++    0x27, 0xca, 0xf4, 0x66, 0xc2, 0xec, 0x92, 0x14, 0x57, 0x06, 0x63, 0xd0,
++    0x4d, 0x15, 0x06, 0xeb, 0x69, 0x58, 0x4f, 0x77, 0xc5, 0x8b, 0xc7, 0xf0,
++    0x8e, 0xed, 0x64, 0xa0, 0xb3, 0x3c, 0x66, 0x71, 0xc6, 0x2d, 0xda, 0x0a,
++    0x0d, 0xfe, 0x70, 0x27, 0x64, 0xf8, 0x27, 0xfa, 0xf6, 0x5f, 0x30, 0xa5,
++    0x0d, 0x6c, 0xda, 0xf2, 0x62, 0x5e, 0x78, 0x47, 0xd3, 0x66, 0x00, 0x1c,
++    0xfd, 0x56, 0x1f, 0x5d, 0x3f, 0x6f, 0xf4, 0x4c, 0xd8, 0xfd, 0x0e, 0x27,
++    0xc9, 0x5c, 0x2b, 0xbc, 0xc0, 0xa4, 0xe7, 0x23, 0x29, 0x02, 0x9f, 0x31,
++    0xd6, 0xe9, 0xd7, 0x96, 0xf4, 0xe0, 0x5e, 0x0b, 0x0e, 0x13, 0xee, 0x3c,
++    0x09, 0xed, 0xf2, 0x3d, 0x76, 0x91, 0xc3, 0xa4, 0x97, 0xae, 0xd4, 0x87,
++    0xd0, 0x5d, 0xf6, 0x18, 0x47, 0x1f, 0x1d, 0x67, 0xf2, 0xcf, 0x63, 0xa0,
++    0x91, 0x27, 0xf8, 0x93, 0x45, 0x75, 0x23, 0x3f, 0xd1, 0xf1, 0xad, 0x23,
++    0xdd, 0x64, 0x93, 0x96, 0x41, 0x70, 0x7f, 0xf7, 0xf5, 0xa9, 0x89, 0xa2,
++    0x34, 0xb0, 0x8d, 0x1b, 0xae, 0x19, 0x15, 0x49, 0x58, 0x23, 0x6d, 0x87,
++    0x15, 0x4f, 0x81, 0x76, 0xfb, 0x23, 0xb5, 0xea, 0xcf, 0xac, 0x54, 0x8d,
++    0x4e, 0x42, 0x2f, 0xeb, 0x0f, 0x63, 0xdb, 0x68, 0x37, 0xa8, 0xcf, 0x8b,
++    0xab, 0xf5, 0xa4, 0x6e, 0x96, 0x2a, 0xb2, 0xd6, 0xbe, 0x9e, 0xbd, 0x0d,
++    0xb4, 0x42, 0xa9, 0xcf, 0x01, 0x83, 0x8a, 0x17, 0x47, 0x76, 0xc4, 0xc6,
++    0x83, 0x04, 0x95, 0x0b, 0xfc, 0x11, 0xc9, 0x62, 0xb8, 0x0c, 0x76, 0x84,
++    0xd9, 0xb9, 0x37, 0xfa, 0xfc, 0x7c, 0xc2, 0x6d, 0x58, 0x3e, 0xb3, 0x04,
++    0xbb, 0x8c, 0x8f, 0x48, 0xbc, 0x91, 0x27, 0xcc, 0xf9, 0xb7, 0x22, 0x19,
++    0x83, 0x2e, 0x09, 0xb5, 0x72, 0xd9, 0x54, 0x1c, 0x4d, 0xa1, 0xea, 0x0b,
++    0xf1, 0xc6, 0x08, 0x72, 0x46, 0x87, 0x7a, 0x6e, 0x80, 0x56, 0x0a, 0x8a,
++    0xc0, 0xdd, 0x11, 0x6b, 0xd6, 0xdd, 0x47, 0xdf, 0x10, 0xd9, 0xd8, 0xea,
++    0x7c, 0xb0, 0x8f, 0x03, 0x00, 0x2e, 0xc1, 0x8f, 0x44, 0xa8, 0xd3, 0x30,
++    0x06, 0x89, 0xa2, 0xf9, 0x34, 0xad, 0xdc, 0x03, 0x85, 0xed, 0x51, 0xa7,
++    0x82, 0x9c, 0xe7, 0x5d, 0x52, 0x93, 0x0c, 0x32, 0x9a, 0x5b, 0xe1, 0xaa,
++    0xca, 0xb8, 0x02, 0x6d, 0x3a, 0xd4, 0xb1, 0x3a, 0xf0, 0x5f, 0xbe, 0xb5,
++    0x0d, 0x10, 0x6b, 0x38, 0x32, 0xac, 0x76, 0x80, 0xbd, 0xca, 0x94, 0x71,
++    0x7a, 0xf2, 0xc9, 0x35, 0x2a, 0xde, 0x9f, 0x42, 0x49, 0x18, 0x01, 0xab,
++    0xbc, 0xef, 0x7c, 0x64, 0x3f, 0x58, 0x3d, 0x92, 0x59, 0xdb, 0x13, 0xdb,
++    0x58, 0x6e, 0x0a, 0xe0, 0xb7, 0x91, 0x4a, 0x08, 0x20, 0xd6, 0x2e, 0x3c,
++    0x45, 0xc9, 0x8b, 0x17, 0x79, 0xe7, 0xc7, 0x90, 0x99, 0x3a, 0x18, 0x25,
++};
++
++#else
++
++// k25519Precomp[i][j] = (j+1)*256^i*B
++static const ge_precomp k25519Precomp[32][8] = {
++    {
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1288382639258501, 245678601348599, 269427782077623,
++                1462984067271730, 137412439391563
++#else
++                25967493, 19198397, 29566455, 3660896, 54414519, 4014786,
++                27544626, 21800161, 61029707, 2047604
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                62697248952638, 204681361388450, 631292143396476,
++                338455783676468, 1213667448819585
++#else
++                54563134, 934261, 64385954, 3049989, 66381436, 9406985,
++                12720692, 5043384, 19500929, 18085054
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                301289933810280, 1259582250014073, 1422107436869536,
++                796239922652654, 1953934009299142
++#else
++                58370664, 4489569, 9688441, 18769238, 10184608, 21191052,
++                29287918, 11864899, 42594502, 29115885
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1380971894829527, 790832306631236, 2067202295274102,
++                1995808275510000, 1566530869037010
++#else
++                54292951, 20578084, 45527620, 11784319, 41753206, 30803714,
++                55390960, 29739860, 66750418, 23343128
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                463307831301544, 432984605774163, 1610641361907204,
++                750899048855000, 1894842303421586
++#else
++                45405608, 6903824, 27185491, 6451973, 37531140, 24000426,
++                51492312, 11189267, 40279186, 28235350
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                748439484463711, 1033211726465151, 1396005112841647,
++                1611506220286469, 1972177495910992
++#else
++                26966623, 11152617, 32442495, 15396054, 14353839, 20802097,
++                63980037, 24013313, 51636816, 29387734
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1601611775252272, 1720807796594148, 1132070835939856,
++                1260455018889551, 2147779492816911
++#else
++                15636272, 23865875, 24204772, 25642034, 616976, 16869170,
++                27787599, 18782243, 28944399, 32004408
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                316559037616741, 2177824224946892, 1459442586438991,
++                1461528397712656, 751590696113597
++#else
++                16568933, 4717097, 55552716, 32452109, 15682895, 21747389,
++                16354576, 21778470, 7689661, 11199574
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1850748884277385, 1200145853858453, 1068094770532492,
++                672251375690438, 1586055907191707
++#else
++                30464137, 27578307, 55329429, 17883566, 23220364, 15915852,
++                7512774, 10017326, 49359771, 23634074
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                934282339813791, 1846903124198670, 1172395437954843,
++                1007037127761661, 1830588347719256
++#else
++                50071967, 13921891, 10945806, 27521001, 27105051, 17470053,
++                38182653, 15006022, 3284568, 27277892
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1694390458783935, 1735906047636159, 705069562067493,
++                648033061693059, 696214010414170
++#else
++                23599295, 25248385, 55915199, 25867015, 13236773, 10506355,
++                7464579, 9656445, 13059162, 10374397
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1121406372216585, 192876649532226, 190294192191717,
++                1994165897297032, 2245000007398739
++#else
++                7798537, 16710257, 3033922, 2874086, 28997861, 2835604,
++                32406664, 29715387, 66467155, 33453106
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                769950342298419, 132954430919746, 844085933195555,
++                974092374476333, 726076285546016
++#else
++                10861363, 11473154, 27284546, 1981175, 37044515, 12577860,
++                32867885, 14515107, 51670560, 10819379
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                425251763115706, 608463272472562, 442562545713235,
++                837766094556764, 374555092627893
++#else
++                4708026, 6336745, 20377586, 9066809, 55836755, 6594695,
++                41455196, 12483687, 54440373, 5581305
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1086255230780037, 274979815921559, 1960002765731872,
++                929474102396301, 1190409889297339
++#else
++                19563141, 16186464, 37722007, 4097518, 10237984, 29206317,
++                28542349, 13850243, 43430843, 17738489
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1388594989461809, 316767091099457, 394298842192982,
++                1230079486801005, 1440737038838979
++#else
++                51736881, 20691677, 32573249, 4720197, 40672342, 5875510,
++                47920237, 18329612, 57289923, 21468654
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                7380825640100, 146210432690483, 304903576448906,
++                1198869323871120, 997689833219095
++#else
++                58559652, 109982, 15149363, 2178705, 22900618, 4543417, 3044240,
++                17864545, 1762327, 14866737
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1181317918772081, 114573476638901, 262805072233344,
++                265712217171332, 294181933805782
++#else
++                48909169, 17603008, 56635573, 1707277, 49922944, 3916100,
++                38872452, 3959420, 27914454, 4383652
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                665000864555967, 2065379846933859, 370231110385876,
++                350988370788628, 1233371373142985
++#else
++                5153727, 9909285, 1723747, 30776558, 30523604, 5516873,
++                19480852, 5230134, 43156425, 18378665
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                2019367628972465, 676711900706637, 110710997811333,
++                1108646842542025, 517791959672113
++#else
++                36839857, 30090922, 7665485, 10083793, 28475525, 1649722,
++                20654025, 16520125, 30598449, 7715701
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                965130719900578, 247011430587952, 526356006571389,
++                91986625355052, 2157223321444601
++#else
++                28881826, 14381568, 9657904, 3680757, 46927229, 7843315,
++                35708204, 1370707, 29794553, 32145132
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                2068619540119183, 1966274918058806, 957728544705549,
++                729906502578991, 159834893065166
++#else
++                14499471, 30824833, 33917750, 29299779, 28494861, 14271267,
++                30290735, 10876454, 33954766, 2381725
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                2073601412052185, 31021124762708, 264500969797082,
++                248034690651703, 1030252227928288
++#else
++                59913433, 30899068, 52378708, 462250, 39384538, 3941371,
++                60872247, 3696004, 34808032, 15351954
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                551790716293402, 1989538725166328, 801169423371717,
++                2052451893578887, 678432056995012
++#else
++                27431194, 8222322, 16448760, 29646437, 48401861, 11938354,
++                34147463, 30583916, 29551812, 10109425
++#endif
++            }},
++        },
++    },
++    {
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1368953770187805, 790347636712921, 437508475667162,
++                2142576377050580, 1932081720066286
++#else
++                53451805, 20399000, 35825113, 11777097, 21447386, 6519384,
++                64730580, 31926875, 10092782, 28790261
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                953638594433374, 1092333936795051, 1419774766716690,
++                805677984380077, 859228993502513
++#else
++                27939166, 14210322, 4677035, 16277044, 44144402, 21156292,
++                34600109, 12005537, 49298737, 12803509
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1200766035879111, 20142053207432, 1465634435977050,
++                1645256912097844, 295121984874596
++#else
++                17228999, 17892808, 65875336, 300139, 65883994, 21839654,
++                30364212, 24516238, 18016356, 4397660
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1735718747031557, 1248237894295956, 1204753118328107,
++                976066523550493, 65943769534592
++#else
++                56150021, 25864224, 4776340, 18600194, 27850027, 17952220,
++                40489757, 14544524, 49631360, 982638
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1060098822528990, 1586825862073490, 212301317240126,
++                1975302711403555, 666724059764335
++#else
++                29253598, 15796703, 64244882, 23645547, 10057022, 3163536,
++                7332899, 29434304, 46061167, 9934962
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1091990273418756, 1572899409348578, 80968014455247,
++                306009358661350, 1520450739132526
++#else
++                5793284, 16271923, 42977250, 23438027, 29188559, 1206517,
++                52360934, 4559894, 36984942, 22656481
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1480517209436112, 1511153322193952, 1244343858991172,
++                304788150493241, 369136856496443
++#else
++                39464912, 22061425, 16282656, 22517939, 28414020, 18542168,
++                24191033, 4541697, 53770555, 5500567
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                2151330273626164, 762045184746182, 1688074332551515,
++                823046109005759, 907602769079491
++#else
++                12650548, 32057319, 9052870, 11355358, 49428827, 25154267,
++                49678271, 12264342, 10874051, 13524335
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                2047386910586836, 168470092900250, 1552838872594810,
++                340951180073789, 360819374702533
++#else
++                25556948, 30508442, 714650, 2510400, 23394682, 23139102,
++                33119037, 5080568, 44580805, 5376627
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1982622644432056, 2014393600336956, 128909208804214,
++                1617792623929191, 105294281913815
++#else
++                41020600, 29543379, 50095164, 30016803, 60382070, 1920896,
++                44787559, 24106988, 4535767, 1569007
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                980234343912898, 1712256739246056, 588935272190264,
++                204298813091998, 841798321043288
++#else
++                64853442, 14606629, 45416424, 25514613, 28430648, 8775819,
++                36614302, 3044289, 31848280, 12543772
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                197561292938973, 454817274782871, 1963754960082318,
++                2113372252160468, 971377527342673
++#else
++                45080285, 2943892, 35251351, 6777305, 13784462, 29262229,
++                39731668, 31491700, 7718481, 14474653
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                164699448829328, 3127451757672, 1199504971548753,
++                1766155447043652, 1899238924683527
++#else
++                2385296, 2454213, 44477544, 46602, 62670929, 17874016, 656964,
++                26317767, 24316167, 28300865
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                732262946680281, 1674412764227063, 2182456405662809,
++                1350894754474250, 558458873295247
++#else
++                13741529, 10911568, 33875447, 24950694, 46931033, 32521134,
++                33040650, 20129900, 46379407, 8321685
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                2103305098582922, 1960809151316468, 715134605001343,
++                1454892949167181, 40827143824949
++#else
++                21060490, 31341688, 15712756, 29218333, 1639039, 10656336,
++                23845965, 21679594, 57124405, 608371
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1239289043050212, 1744654158124578, 758702410031698,
++                1796762995074688, 1603056663766
++#else
++                53436132, 18466845, 56219170, 25997372, 61071954, 11305546,
++                1123968, 26773855, 27229398, 23887
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                2232056027107988, 987343914584615, 2115594492994461,
++                1819598072792159, 1119305654014850
++#else
++                43864724, 33260226, 55364135, 14712570, 37643165, 31524814,
++                12797023, 27114124, 65475458, 16678953
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                320153677847348, 939613871605645, 641883205761567,
++                1930009789398224, 329165806634126
++#else
++                37608244, 4770661, 51054477, 14001337, 7830047, 9564805,
++                65600720, 28759386, 49939598, 4904952
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                980930490474130, 1242488692177893, 1251446316964684,
++                1086618677993530, 1961430968465772
++#else
++                24059538, 14617003, 19037157, 18514524, 19766092, 18648003,
++                5169210, 16191880, 2128236, 29227599
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                276821765317453, 1536835591188030, 1305212741412361,
++                61473904210175, 2051377036983058
++#else
++                50127693, 4124965, 58568254, 22900634, 30336521, 19449185,
++                37302527, 916032, 60226322, 30567899
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                833449923882501, 1750270368490475, 1123347002068295,
++                185477424765687, 278090826653186
++#else
++                44477957, 12419371, 59974635, 26081060, 50629959, 16739174,
++                285431, 2763829, 15736322, 4143876
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                794524995833413, 1849907304548286, 53348672473145,
++                1272368559505217, 1147304168324779
++#else
++                2379333, 11839345, 62998462, 27565766, 11274297, 794957, 212801,
++                18959769, 23527083, 17096164
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1504846112759364, 1203096289004681, 562139421471418,
++                274333017451844, 1284344053775441
++#else
++                33431108, 22423954, 49269897, 17927531, 8909498, 8376530,
++                34483524, 4087880, 51919953, 19138217
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                483048732424432, 2116063063343382, 30120189902313,
++                292451576741007, 1156379271702225
++#else
++                1767664, 7197987, 53903638, 31531796, 54017513, 448825, 5799055,
++                4357868, 62334673, 17231393
++#endif
++            }},
++        },
++    },
++    {
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                928372153029038, 2147692869914564, 1455665844462196,
++                1986737809425946, 185207050258089
++#else
++                6721966, 13833823, 43585476, 32003117, 26354292, 21691111,
++                23365146, 29604700, 7390889, 2759800
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                137732961814206, 706670923917341, 1387038086865771,
++                1965643813686352, 1384777115696347
++#else
++                4409022, 2052381, 23373853, 10530217, 7676779, 20668478,
++                21302352, 29290375, 1244379, 20634787
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                481144981981577, 2053319313589856, 2065402289827512,
++                617954271490316, 1106602634668125
++#else
++                62687625, 7169618, 4982368, 30596842, 30256824, 30776892,
++                14086412, 9208236, 15886429, 16489664
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                696298019648792, 893299659040895, 1148636718636009,
++                26734077349617, 2203955659340681
++#else
++                1996056, 10375649, 14346367, 13311202, 60234729, 17116020,
++                53415665, 398368, 36502409, 32841498
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                657390353372855, 998499966885562, 991893336905797,
++                810470207106761, 343139804608786
++#else
++                41801399, 9795879, 64331450, 14878808, 33577029, 14780362,
++                13348553, 12076947, 36272402, 5113181
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                791736669492960, 934767652997115, 824656780392914,
++                1759463253018643, 361530362383518
++#else
++                49338080, 11797795, 31950843, 13929123, 41220562, 12288343,
++                36767763, 26218045, 13847710, 5387222
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                2022541353055597, 2094700262587466, 1551008075025686,
++                242785517418164, 695985404963562
++#else
++                48526701, 30138214, 17824842, 31213466, 22744342, 23111821,
++                8763060, 3617786, 47508202, 10370990
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1287487199965223, 2215311941380308, 1552928390931986,
++                1664859529680196, 1125004975265243
++#else
++                20246567, 19185054, 22358228, 33010720, 18507282, 23140436,
++                14554436, 24808340, 32232923, 16763880
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                677434665154918, 989582503122485, 1817429540898386,
++                1052904935475344, 1143826298169798
++#else
++                9648486, 10094563, 26416693, 14745928, 36734546, 27081810,
++                11094160, 15689506, 3140038, 17044340
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                367266328308408, 318431188922404, 695629353755355,
++                634085657580832, 24581612564426
++#else
++                50948792, 5472694, 31895588, 4744994, 8823515, 10365685,
++                39884064, 9448612, 38334410, 366294
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                773360688841258, 1815381330538070, 363773437667376,
++                539629987070205, 783280434248437
++#else
++                19153450, 11523972, 56012374, 27051289, 42461232, 5420646,
++                28344573, 8041113, 719605, 11671788
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                180820816194166, 168937968377394, 748416242794470,
++                1227281252254508, 1567587861004268
++#else
++                8678006, 2694440, 60300850, 2517371, 4964326, 11152271,
++                51675948, 18287915, 27000812, 23358879
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                478775558583645, 2062896624554807, 699391259285399,
++                358099408427873, 1277310261461761
++#else
++                51950941, 7134311, 8639287, 30739555, 59873175, 10421741,
++                564065, 5336097, 6750977, 19033406
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1984740906540026, 1079164179400229, 1056021349262661,
++                1659958556483663, 1088529069025527
++#else
++                11836410, 29574944, 26297893, 16080799, 23455045, 15735944,
++                1695823, 24735310, 8169719, 16220347
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                580736401511151, 1842931091388998, 1177201471228238,
++                2075460256527244, 1301133425678027
++#else
++                48993007, 8653646, 17578566, 27461813, 59083086, 17541668,
++                55964556, 30926767, 61118155, 19388398
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1515728832059182, 1575261009617579, 1510246567196186,
++                191078022609704, 116661716289141
++#else
++                43800366, 22586119, 15213227, 23473218, 36255258, 22504427,
++                27884328, 2847284, 2655861, 1738395
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1295295738269652, 1714742313707026, 545583042462581,
++                2034411676262552, 1513248090013606
++#else
++                39571412, 19301410, 41772562, 25551651, 57738101, 8129820,
++                21651608, 30315096, 48021414, 22549153
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                230710545179830, 30821514358353, 760704303452229,
++                390668103790604, 573437871383156
++#else
++                1533110, 3437855, 23735889, 459276, 29970501, 11335377,
++                26030092, 5821408, 10478196, 8544890
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1169380107545646, 263167233745614, 2022901299054448,
++                819900753251120, 2023898464874585
++#else
++                32173102, 17425121, 24896206, 3921497, 22579056, 30143578,
++                19270448, 12217473, 17789017, 30158437
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                2102254323485823, 1570832666216754, 34696906544624,
++                1993213739807337, 70638552271463
++#else
++                36555903, 31326030, 51530034, 23407230, 13243888, 517024,
++                15479401, 29701199, 30460519, 1052596
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                894132856735058, 548675863558441, 845349339503395,
++                1942269668326667, 1615682209874691
++#else
++                55493970, 13323617, 32618793, 8175907, 51878691, 12596686,
++                27491595, 28942073, 3179267, 24075541
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1287670217537834, 1222355136884920, 1846481788678694,
++                1150426571265110, 1613523400722047
++#else
++                31947050, 19187781, 62468280, 18214510, 51982886, 27514722,
++                52352086, 17142691, 19072639, 24043372
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                793388516527298, 1315457083650035, 1972286999342417,
++                1901825953052455, 338269477222410
++#else
++                11685058, 11822410, 3158003, 19601838, 33402193, 29389366,
++                5977895, 28339415, 473098, 5040608
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                550201530671806, 778605267108140, 2063911101902983,
++                115500557286349, 2041641272971022
++#else
++                46817982, 8198641, 39698732, 11602122, 1290375, 30754672,
++                28326861, 1721092, 47550222, 30422825
++#endif
++            }},
++        },
++    },
++    {
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                717255318455100, 519313764361315, 2080406977303708,
++                541981206705521, 774328150311600
++#else
++                7881532, 10687937, 7578723, 7738378, 48157852, 31000479,
++                21820785, 8076149, 39240368, 11538388
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                261715221532238, 1795354330069993, 1496878026850283,
++                499739720521052, 389031152673770
++#else
++                47173198, 3899860, 18283497, 26752864, 51380203, 22305220,
++                8754524, 7446702, 61432810, 5797015
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1997217696294013, 1717306351628065, 1684313917746180,
++                1644426076011410, 1857378133465451
++#else
++                55813245, 29760862, 51326753, 25589858, 12708868, 25098233,
++                2014098, 24503858, 64739691, 27677090
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1475434724792648, 76931896285979, 1116729029771667,
++                2002544139318042, 725547833803938
++#else
++                44636488, 21985690, 39426843, 1146374, 18956691, 16640559,
++                1192730, 29840233, 15123618, 10811505
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                2022306639183567, 726296063571875, 315345054448644,
++                1058733329149221, 1448201136060677
++#else
++                14352079, 30134717, 48166819, 10822654, 32750596, 4699007,
++                67038501, 15776355, 38222085, 21579878
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1710065158525665, 1895094923036397, 123988286168546,
++                1145519900776355, 1607510767693874
++#else
++                38867681, 25481956, 62129901, 28239114, 29416930, 1847569,
++                46454691, 17069576, 4714546, 23953777
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                561605375422540, 1071733543815037, 131496498800990,
++                1946868434569999, 828138133964203
++#else
++                15200332, 8368572, 19679101, 15970074, 35236190, 1959450,
++                24611599, 29010600, 55362987, 12340219
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1548495173745801, 442310529226540, 998072547000384,
++                553054358385281, 644824326376171
++#else
++                12876937, 23074376, 33134380, 6590940, 60801088, 14872439,
++                9613953, 8241152, 15370987, 9608631
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1445526537029440, 2225519789662536, 914628859347385,
++                1064754194555068, 1660295614401091
++#else
++                62965568, 21540023, 8446280, 33162829, 4407737, 13629032,
++                59383996, 15866073, 38898243, 24740332
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1199690223111956, 24028135822341, 66638289244341,
++                57626156285975, 565093967979607
++#else
++                26660628, 17876777, 8393733, 358047, 59707573, 992987, 43204631,
++                858696, 20571223, 8420556
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                876926774220824, 554618976488214, 1012056309841565,
++                839961821554611, 1414499340307677
++#else
++                14620696, 13067227, 51661590, 8264466, 14106269, 15080814,
++                33531827, 12516406, 45534429, 21077682
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                703047626104145, 1266841406201770, 165556500219173,
++                486991595001879, 1011325891650656
++#else
++                236881, 10476226, 57258, 18877408, 6472997, 2466984, 17258519,
++                7256740, 8791136, 15069930
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1622861044480487, 1156394801573634, 1869132565415504,
++                327103985777730, 2095342781472284
++#else
++                1276391, 24182514, 22949634, 17231625, 43615824, 27852245,
++                14711874, 4874229, 36445724, 31223040
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                334886927423922, 489511099221528, 129160865966726,
++                1720809113143481, 619700195649254
++#else
++                5855666, 4990204, 53397016, 7294283, 59304582, 1924646,
++                65685689, 25642053, 34039526, 9234252
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1646545795166119, 1758370782583567, 714746174550637,
++                1472693650165135, 898994790308209
++#else
++                20590503, 24535444, 31529743, 26201766, 64402029, 10650547,
++                31559055, 21944845, 18979185, 13396066
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                333403773039279, 295772542452938, 1693106465353610,
++                912330357530760, 471235657950362
++#else
++                24474287, 4968103, 22267082, 4407354, 24063882, 25229252,
++                48291976, 13594781, 33514650, 7021958
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1811196219982022, 1068969825533602, 289602974833439,
++                1988956043611592, 863562343398367
++#else
++                55541958, 26988926, 45743778, 15928891, 40950559, 4315420,
++                41160136, 29637754, 45628383, 12868081
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                906282429780072, 2108672665779781, 432396390473936,
++                150625823801893, 1708930497638539
++#else
++                38473832, 13504660, 19988037, 31421671, 21078224, 6443208,
++                45662757, 2244499, 54653067, 25465048
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                925664675702328, 21416848568684, 1831436641861340,
++                601157008940113, 371818055044496
++#else
++                36513336, 13793478, 61256044, 319135, 41385692, 27290532,
++                33086545, 8957937, 51875216, 5540520
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1479786007267725, 1738881859066675, 68646196476567,
++                2146507056100328, 1247662817535471
++#else
++                55478669, 22050529, 58989363, 25911358, 2620055, 1022908,
++                43398120, 31985447, 50980335, 18591624
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                52035296774456, 939969390708103, 312023458773250,
++                59873523517659, 1231345905848899
++#else
++                23152952, 775386, 27395463, 14006635, 57407746, 4649511,
++                1689819, 892185, 55595587, 18348483
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                643355106415761, 290186807495774, 2013561737429023,
++                319648069511546, 393736678496162
++#else
++                9770129, 9586738, 26496094, 4324120, 1556511, 30004408,
++                27453818, 4763127, 47929250, 5867133
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                129358342392716, 1932811617704777, 1176749390799681,
++                398040349861790, 1170779668090425
++#else
++                34343820, 1927589, 31726409, 28801137, 23962433, 17534932,
++                27846558, 5931263, 37359161, 17445976
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                2051980782668029, 121859921510665, 2048329875753063,
++                1235229850149665, 519062146124755
++#else
++                27461885, 30576896, 22380809, 1815854, 44075111, 30522493,
++                7283489, 18406359, 47582163, 7734628
++#endif
++            }},
++        },
++    },
++    {
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1608170971973096, 415809060360428, 1350468408164766,
++                2038620059057678, 1026904485989112
++#else
++                59098600, 23963614, 55988460, 6196037, 29344158, 20123547,
++                7585294, 30377806, 18549496, 15302069
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1837656083115103, 1510134048812070, 906263674192061,
++                1821064197805734, 565375124676301
++#else
++                34450527, 27383209, 59436070, 22502750, 6258877, 13504381,
++                10458790, 27135971, 58236621, 8424745
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                578027192365650, 2034800251375322, 2128954087207123,
++                478816193810521, 2196171989962750
++#else
++                24687186, 8613276, 36441818, 30320886, 1863891, 31723888,
++                19206233, 7134917, 55824382, 32725512
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1633188840273139, 852787172373708, 1548762607215796,
++                1266275218902681, 1107218203325133
++#else
++                11334899, 24336410, 8025292, 12707519, 17523892, 23078361,
++                10243737, 18868971, 62042829, 16498836
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                462189358480054, 1784816734159228, 1611334301651368,
++                1303938263943540, 707589560319424
++#else
++                8911542, 6887158, 57524604, 26595841, 11145640, 24010752,
++                17303924, 19430194, 6536640, 10543906
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1038829280972848, 38176604650029, 753193246598573,
++                1136076426528122, 595709990562434
++#else
++                38162480, 15479762, 49642029, 568875, 65611181, 11223453,
++                64439674, 16928857, 39873154, 8876770
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1408451820859834, 2194984964010833, 2198361797561729,
++                1061962440055713, 1645147963442934
++#else
++                41365946, 20987567, 51458897, 32707824, 34082177, 32758143,
++                33627041, 15824473, 66504438, 24514614
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                4701053362120, 1647641066302348, 1047553002242085,
++                1923635013395977, 206970314902065
++#else
++                10330056, 70051, 7957388, 24551765, 9764901, 15609756, 27698697,
++                28664395, 1657393, 3084098
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1750479161778571, 1362553355169293, 1891721260220598,
++                966109370862782, 1024913988299801
++#else
++                10477963, 26084172, 12119565, 20303627, 29016246, 28188843,
++                31280318, 14396151, 36875289, 15272408
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                212699049131723, 1117950018299775, 1873945661751056,
++                1403802921984058, 130896082652698
++#else
++                54820555, 3169462, 28813183, 16658753, 25116432, 27923966,
++                41934906, 20918293, 42094106, 1950503
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                636808533673210, 1262201711667560, 390951380330599,
++                1663420692697294, 561951321757406
++#else
++                40928506, 9489186, 11053416, 18808271, 36055143, 5825629,
++                58724558, 24786899, 15341278, 8373727
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                520731594438141, 1446301499955692, 273753264629267,
++                1565101517999256, 1019411827004672
++#else
++                28685821, 7759505, 52730348, 21551571, 35137043, 4079241,
++                298136, 23321830, 64230656, 15190419
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                926527492029409, 1191853477411379, 734233225181171,
++                184038887541270, 1790426146325343
++#else
++                34175969, 13806335, 52771379, 17760000, 43104243, 10940927,
++                8669718, 2742393, 41075551, 26679428
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1464651961852572, 1483737295721717, 1519450561335517,
++                1161429831763785, 405914998179977
++#else
++                65528476, 21825014, 41129205, 22109408, 49696989, 22641577,
++                9291593, 17306653, 54954121, 6048604
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                996126634382301, 796204125879525, 127517800546509,
++                344155944689303, 615279846169038
++#else
++                36803549, 14843443, 1539301, 11864366, 20201677, 1900163,
++                13934231, 5128323, 11213262, 9168384
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                738724080975276, 2188666632415296, 1961313708559162,
++                1506545807547587, 1151301638969740
++#else
++                40828332, 11007846, 19408960, 32613674, 48515898, 29225851,
++                62020803, 22449281, 20470156, 17155731
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                622917337413835, 1218989177089035, 1284857712846592,
++                970502061709359, 351025208117090
++#else
++                43972811, 9282191, 14855179, 18164354, 59746048, 19145871,
++                44324911, 14461607, 14042978, 5230683
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                2067814584765580, 1677855129927492, 2086109782475197,
++                235286517313238, 1416314046739645
++#else
++                29969548, 30812838, 50396996, 25001989, 9175485, 31085458,
++                21556950, 3506042, 61174973, 21104723
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                586844262630358, 307444381952195, 458399356043426,
++                602068024507062, 1028548203415243
++#else
++                63964118, 8744660, 19704003, 4581278, 46678178, 6830682,
++                45824694, 8971512, 38569675, 15326562
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                678489922928203, 2016657584724032, 90977383049628,
++                1026831907234582, 615271492942522
++#else
++                47644235, 10110287, 49846336, 30050539, 43608476, 1355668,
++                51585814, 15300987, 46594746, 9168259
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                301225714012278, 1094837270268560, 1202288391010439,
++                644352775178361, 1647055902137983
++#else
++                61755510, 4488612, 43305616, 16314346, 7780487, 17915493,
++                38160505, 9601604, 33087103, 24543045
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1210746697896478, 1416608304244708, 686487477217856,
++                1245131191434135, 1051238336855737
++#else
++                47665694, 18041531, 46311396, 21109108, 37284416, 10229460,
++                39664535, 18553900, 61111993, 15664671
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1135604073198207, 1683322080485474, 769147804376683,
++                2086688130589414, 900445683120379
++#else
++                23294591, 16921819, 44458082, 25083453, 27844203, 11461195,
++                13099750, 31094076, 18151675, 13417686
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1971518477615628, 401909519527336, 448627091057375,
++                1409486868273821, 1214789035034363
++#else
++                42385932, 29377914, 35958184, 5988918, 40250079, 6685064,
++                1661597, 21002991, 15271675, 18101767
++#endif
++            }},
++        },
++    },
++    {
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1364039144731711, 1897497433586190, 2203097701135459,
++                145461396811251, 1349844460790699
++#else
++                11433023, 20325767, 8239630, 28274915, 65123427, 32828713,
++                48410099, 2167543, 60187563, 20114249
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1045230323257973, 818206601145807, 630513189076103,
++                1672046528998132, 807204017562437
++#else
++                35672693, 15575145, 30436815, 12192228, 44645511, 9395378,
++                57191156, 24915434, 12215109, 12028277
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                439961968385997, 386362664488986, 1382706320807688,
++                309894000125359, 2207801346498567
++#else
++                14098381, 6555944, 23007258, 5757252, 51681032, 20603929,
++                30123439, 4617780, 50208775, 32898803
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1229004686397588, 920643968530863, 123975893911178,
++                681423993215777, 1400559197080973
++#else
++                63082644, 18313596, 11893167, 13718664, 52299402, 1847384,
++                51288865, 10154008, 23973261, 20869958
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                2003766096898049, 170074059235165, 1141124258967971,
++                1485419893480973, 1573762821028725
++#else
++                40577025, 29858441, 65199965, 2534300, 35238307, 17004076,
++                18341389, 22134481, 32013173, 23450893
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                729905708611432, 1270323270673202, 123353058984288,
++                426460209632942, 2195574535456672
++#else
++                41629544, 10876442, 55337778, 18929291, 54739296, 1838103,
++                21911214, 6354752, 4425632, 32716610
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1271140255321235, 2044363183174497, 52125387634689,
++                1445120246694705, 942541986339084
++#else
++                56675475, 18941465, 22229857, 30463385, 53917697, 776728,
++                49693489, 21533969, 4725004, 14044970
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1761608437466135, 583360847526804, 1586706389685493,
++                2157056599579261, 1170692369685772
++#else
++                19268631, 26250011, 1555348, 8692754, 45634805, 23643767,
++                6347389, 32142648, 47586572, 17444675
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                871476219910823, 1878769545097794, 2241832391238412,
++                548957640601001, 690047440233174
++#else
++                42244775, 12986007, 56209986, 27995847, 55796492, 33405905,
++                19541417, 8180106, 9282262, 10282508
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                297194732135507, 1366347803776820, 1301185512245601,
++                561849853336294, 1533554921345731
++#else
++                40903763, 4428546, 58447668, 20360168, 4098401, 19389175,
++                15522534, 8372215, 5542595, 22851749
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                999628998628371, 1132836708493400, 2084741674517453,
++                469343353015612, 678782988708035
++#else
++                56546323, 14895632, 26814552, 16880582, 49628109, 31065071,
++                64326972, 6993760, 49014979, 10114654
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                2189427607417022, 699801937082607, 412764402319267,
++                1478091893643349, 2244675696854460
++#else
++                47001790, 32625013, 31422703, 10427861, 59998115, 6150668,
++                38017109, 22025285, 25953724, 33448274
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1712292055966563, 204413590624874, 1405738637332841,
++                408981300829763, 861082219276721
++#else
++                62874467, 25515139, 57989738, 3045999, 2101609, 20947138,
++                19390019, 6094296, 63793585, 12831124
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                508561155940631, 966928475686665, 2236717801150132,
++                424543858577297, 2089272956986143
++#else
++                51110167, 7578151, 5310217, 14408357, 33560244, 33329692,
++                31575953, 6326196, 7381791, 31132593
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                221245220129925, 1156020201681217, 491145634799213,
++                542422431960839, 828100817819207
++#else
++                46206085, 3296810, 24736065, 17226043, 18374253, 7318640,
++                6295303, 8082724, 51746375, 12339663
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                153756971240384, 1299874139923977, 393099165260502,
++                1058234455773022, 996989038681183
++#else
++                27724736, 2291157, 6088201, 19369634, 1792726, 5857634,
++                13848414, 15768922, 25091167, 14856294
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                559086812798481, 573177704212711, 1629737083816402,
++                1399819713462595, 1646954378266038
++#else
++                48242193, 8331042, 24373479, 8541013, 66406866, 24284974,
++                12927299, 20858939, 44926390, 24541532
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1887963056288059, 228507035730124, 1468368348640282,
++                930557653420194, 613513962454686
++#else
++                55685435, 28132841, 11632844, 3405020, 30536730, 21880393,
++                39848098, 13866389, 30146206, 9142070
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1224529808187553, 1577022856702685, 2206946542980843,
++                625883007765001, 279930793512158
++#else
++                3924129, 18246916, 53291741, 23499471, 12291819, 32886066,
++                39406089, 9326383, 58871006, 4171293
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1076287717051609, 1114455570543035, 187297059715481,
++                250446884292121, 1885187512550540
++#else
++                51186905, 16037936, 6713787, 16606682, 45496729, 2790943,
++                26396185, 3731949, 345228, 28091483
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                902497362940219, 76749815795675, 1657927525633846,
++                1420238379745202, 1340321636548352
++#else
++                45781307, 13448258, 25284571, 1143661, 20614966, 24705045,
++                2031538, 21163201, 50855680, 19972348
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1129576631190784, 1281994010027327, 996844254743018,
++                257876363489249, 1150850742055018
++#else
++                31016192, 16832003, 26371391, 19103199, 62081514, 14854136,
++                17477601, 3842657, 28012650, 17149012
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                628740660038789, 1943038498527841, 467786347793886,
++                1093341428303375, 235413859513003
++#else
++                62033029, 9368965, 58546785, 28953529, 51858910, 6970559,
++                57918991, 16292056, 58241707, 3507939
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                237425418909360, 469614029179605, 1512389769174935,
++                1241726368345357, 441602891065214
++#else
++                29439664, 3537914, 23333589, 6997794, 49553303, 22536363,
++                51899661, 18503164, 57943934, 6580395
++#endif
++            }},
++        },
++    },
++    {
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1736417953058555, 726531315520508, 1833335034432527,
++                1629442561574747, 624418919286085
++#else
++                54923003, 25874643, 16438268, 10826160, 58412047, 27318820,
++                17860443, 24280586, 65013061, 9304566
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1960754663920689, 497040957888962, 1909832851283095,
++                1271432136996826, 2219780368020940
++#else
++                20714545, 29217521, 29088194, 7406487, 11426967, 28458727,
++                14792666, 18945815, 5289420, 33077305
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1537037379417136, 1358865369268262, 2130838645654099,
++                828733687040705, 1999987652890901
++#else
++                50443312, 22903641, 60948518, 20248671, 9192019, 31751970,
++                17271489, 12349094, 26939669, 29802138
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                629042105241814, 1098854999137608, 887281544569320,
++                1423102019874777, 7911258951561
++#else
++                54218966, 9373457, 31595848, 16374215, 21471720, 13221525,
++                39825369, 21205872, 63410057, 117886
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1811562332665373, 1501882019007673, 2213763501088999,
++                359573079719636, 36370565049116
++#else
++                22263325, 26994382, 3984569, 22379786, 51994855, 32987646,
++                28311252, 5358056, 43789084, 541963
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                218907117361280, 1209298913016966, 1944312619096112,
++                1130690631451061, 1342327389191701
++#else
++                16259200, 3261970, 2309254, 18019958, 50223152, 28972515,
++                24134069, 16848603, 53771797, 20002236
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1369976867854704, 1396479602419169, 1765656654398856,
++                2203659200586299, 998327836117241
++#else
++                9378160, 20414246, 44262881, 20809167, 28198280, 26310334,
++                64709179, 32837080, 690425, 14876244
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                2230701885562825, 1348173180338974, 2172856128624598,
++                1426538746123771, 444193481326151
++#else
++                24977353, 33240048, 58884894, 20089345, 28432342, 32378079,
++                54040059, 21257083, 44727879, 6618998
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                784210426627951, 918204562375674, 1284546780452985,
++                1324534636134684, 1872449409642708
++#else
++                65570671, 11685645, 12944378, 13682314, 42719353, 19141238,
++                8044828, 19737104, 32239828, 27901670
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                319638829540294, 596282656808406, 2037902696412608,
++                1557219121643918, 341938082688094
++#else
++                48505798, 4762989, 66182614, 8885303, 38696384, 30367116,
++                9781646, 23204373, 32779358, 5095274
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1901860206695915, 2004489122065736, 1625847061568236,
++                973529743399879, 2075287685312905
++#else
++                34100715, 28339925, 34843976, 29869215, 9460460, 24227009,
++                42507207, 14506723, 21639561, 30924196
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1371853944110545, 1042332820512553, 1949855697918254,
++                1791195775521505, 37487364849293
++#else
++                50707921, 20442216, 25239337, 15531969, 3987758, 29055114,
++                65819361, 26690896, 17874573, 558605
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                687200189577855, 1082536651125675, 644224940871546,
++                340923196057951, 343581346747396
++#else
++                53508735, 10240080, 9171883, 16131053, 46239610, 9599699,
++                33499487, 5080151, 2085892, 5119761
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                2082717129583892, 27829425539422, 145655066671970,
++                1690527209845512, 1865260509673478
++#else
++                44903700, 31034903, 50727262, 414690, 42089314, 2170429,
++                30634760, 25190818, 35108870, 27794547
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1059729620568824, 2163709103470266, 1440302280256872,
++                1769143160546397, 869830310425069
++#else
++                60263160, 15791201, 8550074, 32241778, 29928808, 21462176,
++                27534429, 26362287, 44757485, 12961481
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1609516219779025, 777277757338817, 2101121130363987,
++                550762194946473, 1905542338659364
++#else
++                42616785, 23983660, 10368193, 11582341, 43711571, 31309144,
++                16533929, 8206996, 36914212, 28394793
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                2024821921041576, 426948675450149, 595133284085473,
++                471860860885970, 600321679413000
++#else
++                55987368, 30172197, 2307365, 6362031, 66973409, 8868176,
++                50273234, 7031274, 7589640, 8945490
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                598474602406721, 1468128276358244, 1191923149557635,
++                1501376424093216, 1281662691293476
++#else
++                34956097, 8917966, 6661220, 21876816, 65916803, 17761038,
++                7251488, 22372252, 24099108, 19098262
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1721138489890707, 1264336102277790, 433064545421287,
++                1359988423149466, 1561871293409447
++#else
++                5019539, 25646962, 4244126, 18840076, 40175591, 6453164,
++                47990682, 20265406, 60876967, 23273695
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                719520245587143, 393380711632345, 132350400863381,
++                1543271270810729, 1819543295798660
++#else
++                10853575, 10721687, 26480089, 5861829, 44113045, 1972174,
++                65242217, 22996533, 63745412, 27113307
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                396397949784152, 1811354474471839, 1362679985304303,
++                2117033964846756, 498041172552279
++#else
++                50106456, 5906789, 221599, 26991285, 7828207, 20305514,
++                24362660, 31546264, 53242455, 7421391
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1812471844975748, 1856491995543149, 126579494584102,
++                1036244859282620, 1975108050082550
++#else
++                8139908, 27007935, 32257645, 27663886, 30375718, 1886181,
++                45933756, 15441251, 28826358, 29431403
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                650623932407995, 1137551288410575, 2125223403615539,
++                1725658013221271, 2134892965117796
++#else
++                6267067, 9695052, 7709135, 16950835, 34239795, 31668296,
++                14795159, 25714308, 13746020, 31812384
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                522584000310195, 1241762481390450, 1743702789495384,
++                2227404127826575, 1686746002148897
++#else
++                28584883, 7787108, 60375922, 18503702, 22846040, 25983196,
++                63926927, 33190907, 4771361, 25134474
++#endif
++            }},
++        },
++    },
++    {
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                427904865186312, 1703211129693455, 1585368107547509,
++                1436984488744336, 761188534613978
++#else
++                24949256, 6376279, 39642383, 25379823, 48462709, 23623825,
++                33543568, 21412737, 3569626, 11342593
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                318101947455002, 248138407995851, 1481904195303927,
++                309278454311197, 1258516760217879
++#else
++                26514970, 4740088, 27912651, 3697550, 19331575, 22082093,
++                6809885, 4608608, 7325975, 18753361
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1275068538599310, 513726919533379, 349926553492294,
++                688428871968420, 1702400196000666
++#else
++                55490446, 19000001, 42787651, 7655127, 65739590, 5214311,
++                39708324, 10258389, 49462170, 25367739
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1061864036265233, 961611260325381, 321859632700838,
++                1045600629959517, 1985130202504038
++#else
++                11431185, 15823007, 26570245, 14329124, 18029990, 4796082,
++                35662685, 15580663, 9280358, 29580745
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1558816436882417, 1962896332636523, 1337709822062152,
++                1501413830776938, 294436165831932
++#else
++                66948081, 23228174, 44253547, 29249434, 46247496, 19933429,
++                34297962, 22372809, 51563772, 4387440
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                818359826554971, 1862173000996177, 626821592884859,
++                573655738872376, 1749691246745455
++#else
++                46309467, 12194511, 3937617, 27748540, 39954043, 9340369,
++                42594872, 8548136, 20617071, 26072431
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1988022651432119, 1082111498586040, 1834020786104821,
++                1454826876423687, 692929915223122
++#else
++                66170039, 29623845, 58394552, 16124717, 24603125, 27329039,
++                53333511, 21678609, 24345682, 10325460
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                2146513703733331, 584788900394667, 464965657279958,
++                2183973639356127, 238371159456790
++#else
++                47253587, 31985546, 44906155, 8714033, 14007766, 6928528,
++                16318175, 32543743, 4766742, 3552007
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1129007025494441, 2197883144413266, 265142755578169,
++                971864464758890, 1983715884903702
++#else
++                45357481, 16823515, 1351762, 32751011, 63099193, 3950934,
++                3217514, 14481909, 10988822, 29559670
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1291366624493075, 381456718189114, 1711482489312444,
++                1815233647702022, 892279782992467
++#else
++                15564307, 19242862, 3101242, 5684148, 30446780, 25503076,
++                12677126, 27049089, 58813011, 13296004
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                444548969917454, 1452286453853356, 2113731441506810,
++                645188273895859, 810317625309512
++#else
++                57666574, 6624295, 36809900, 21640754, 62437882, 31497052,
++                31521203, 9614054, 37108040, 12074673
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                2242724082797924, 1373354730327868, 1006520110883049,
++                2147330369940688, 1151816104883620
++#else
++                4771172, 33419193, 14290748, 20464580, 27992297, 14998318,
++                65694928, 31997715, 29832612, 17163397
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1745720200383796, 1911723143175317, 2056329390702074,
++                355227174309849, 879232794371100
++#else
++                7064884, 26013258, 47946901, 28486894, 48217594, 30641695,
++                25825241, 5293297, 39986204, 13101589
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                163723479936298, 115424889803150, 1156016391581227,
++                1894942220753364, 1970549419986329
++#else
++                64810282, 2439669, 59642254, 1719964, 39841323, 17225986,
++                32512468, 28236839, 36752793, 29363474
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                681981452362484, 267208874112496, 1374683991933094,
++                638600984916117, 646178654558546
++#else
++                37102324, 10162315, 33928688, 3981722, 50626726, 20484387,
++                14413973, 9515896, 19568978, 9628812
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                13378654854251, 106237307029567, 1944412051589651,
++                1841976767925457, 230702819835573
++#else
++                33053803, 199357, 15894591, 1583059, 27380243, 28973997,
++                49269969, 27447592, 60817077, 3437739
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                260683893467075, 854060306077237, 913639551980112,
++                4704576840123, 280254810808712
++#else
++                48129987, 3884492, 19469877, 12726490, 15913552, 13614290,
++                44147131, 70103, 7463304, 4176122
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                715374893080287, 1173334812210491, 1806524662079626,
++                1894596008000979, 398905715033393
++#else
++                39984863, 10659916, 11482427, 17484051, 12771466, 26919315,
++                34389459, 28231680, 24216881, 5944158
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                500026409727661, 1596431288195371, 1420380351989370,
++                985211561521489, 392444930785633
++#else
++                8894125, 7450974, 64444715, 23788679, 39028346, 21165316,
++                19345745, 14680796, 11632993, 5847885
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                2096421546958141, 1922523000950363, 789831022876840,
++                427295144688779, 320923973161730
++#else
++                26942781, 31239115, 9129563, 28647825, 26024104, 11769399,
++                55590027, 6367193, 57381634, 4782139
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1927770723575450, 1485792977512719, 1850996108474547,
++                551696031508956, 2126047405475647
++#else
++                19916442, 28726022, 44198159, 22140040, 25606323, 27581991,
++                33253852, 8220911, 6358847, 31680575
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                2112099158080148, 742570803909715, 6484558077432,
++                1951119898618916, 93090382703416
++#else
++                801428, 31472730, 16569427, 11065167, 29875704, 96627, 7908388,
++                29073952, 53570360, 1387154
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                383905201636970, 859946997631870, 855623867637644,
++                1017125780577795, 794250831877809
++#else
++                19646058, 5720633, 55692158, 12814208, 11607948, 12749789,
++                14147075, 15156355, 45242033, 11835259
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                77571826285752, 999304298101753, 487841111777762,
++                1038031143212339, 339066367948762
++#else
++                19299512, 1155910, 28703737, 14890794, 2925026, 7269399,
++                26121523, 15467869, 40548314, 5052482
++#endif
++            }},
++        },
++    },
++    {
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                674994775520533, 266035846330789, 826951213393478,
++                1405007746162285, 1781791018620876
++#else
++                64091413, 10058205, 1980837, 3964243, 22160966, 12322533,
++                60677741, 20936246, 12228556, 26550755
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1001412661522686, 348196197067298, 1666614366723946,
++                888424995032760, 580747687801357
++#else
++                32944382, 14922211, 44263970, 5188527, 21913450, 24834489,
++                4001464, 13238564, 60994061, 8653814
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1939560076207777, 1409892634407635, 552574736069277,
++                383854338280405, 190706709864139
++#else
++                22865569, 28901697, 27603667, 21009037, 14348957, 8234005,
++                24808405, 5719875, 28483275, 2841751
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                2177087163428741, 1439255351721944, 1208070840382793,
++                2230616362004769, 1396886392021913
++#else
++                50687877, 32441126, 66781144, 21446575, 21886281, 18001658,
++                65220897, 33238773, 19932057, 20815229
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                676962063230039, 1880275537148808, 2046721011602706,
++                888463247083003, 1318301552024067
++#else
++                55452759, 10087520, 58243976, 28018288, 47830290, 30498519,
++                3999227, 13239134, 62331395, 19644223
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1466980508178206, 617045217998949, 652303580573628,
++                757303753529064, 207583137376902
++#else
++                1382174, 21859713, 17266789, 9194690, 53784508, 9720080,
++                20403944, 11284705, 53095046, 3093229
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1511056752906902, 105403126891277, 493434892772846,
++                1091943425335976, 1802717338077427
++#else
++                16650902, 22516500, 66044685, 1570628, 58779118, 7352752,
++                66806440, 16271224, 43059443, 26862581
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1853982405405128, 1878664056251147, 1528011020803992,
++                1019626468153565, 1128438412189035
++#else
++                45197768, 27626490, 62497547, 27994275, 35364760, 22769138,
++                24123613, 15193618, 45456747, 16815042
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1963939888391106, 293456433791664, 697897559513649,
++                985882796904380, 796244541237972
++#else
++                57172930, 29264984, 41829040, 4372841, 2087473, 10399484,
++                31870908, 14690798, 17361620, 11864968
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                416770998629779, 389655552427054, 1314476859406756,
++                1749382513022778, 1161905598739491
++#else
++                55801235, 6210371, 13206574, 5806320, 38091172, 19587231,
++                54777658, 26067830, 41530403, 17313742
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1428358296490651, 1027115282420478, 304840698058337,
++                441410174026628, 1819358356278573
++#else
++                14668443, 21284197, 26039038, 15305210, 25515617, 4542480,
++                10453892, 6577524, 9145645, 27110552
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                204943430200135, 1554861433819175, 216426658514651,
++                264149070665950, 2047097371738319
++#else
++                5974855, 3053895, 57675815, 23169240, 35243739, 3225008,
++                59136222, 3936127, 61456591, 30504127
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1934415182909034, 1393285083565062, 516409331772960,
++                1157690734993892, 121039666594268
++#else
++                30625386, 28825032, 41552902, 20761565, 46624288, 7695098,
++                17097188, 17250936, 39109084, 1803631
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                662035583584445, 286736105093098, 1131773000510616,
++                818494214211439, 472943792054479
++#else
++                63555773, 9865098, 61880298, 4272700, 61435032, 16864731,
++                14911343, 12196514, 45703375, 7047411
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                665784778135882, 1893179629898606, 808313193813106,
++                276797254706413, 1563426179676396
++#else
++                20093258, 9920966, 55970670, 28210574, 13161586, 12044805,
++                34252013, 4124600, 34765036, 23296865
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                945205108984232, 526277562959295, 1324180513733566,
++                1666970227868664, 153547609289173
++#else
++                46320040, 14084653, 53577151, 7842146, 19119038, 19731827,
++                4752376, 24839792, 45429205, 2288037
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                2031433403516252, 203996615228162, 170487168837083,
++                981513604791390, 843573964916831
++#else
++                40289628, 30270716, 29965058, 3039786, 52635099, 2540456,
++                29457502, 14625692, 42289247, 12570231
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1476570093962618, 838514669399805, 1857930577281364,
++                2017007352225784, 317085545220047
++#else
++                66045306, 22002608, 16920317, 12494842, 1278292, 27685323,
++                45948920, 30055751, 55134159, 4724942
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1461557121912842, 1600674043318359, 2157134900399597,
++                1670641601940616, 127765583803283
++#else
++                17960970, 21778898, 62967895, 23851901, 58232301, 32143814,
++                54201480, 24894499, 37532563, 1903855
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1293543509393474, 2143624609202546, 1058361566797508,
++                214097127393994, 946888515472729
++#else
++                23134274, 19275300, 56426866, 31942495, 20684484, 15770816,
++                54119114, 3190295, 26955097, 14109738
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                357067959932916, 1290876214345711, 521245575443703,
++                1494975468601005, 800942377643885
++#else
++                15308788, 5320727, 36995055, 19235554, 22902007, 7767164,
++                29425325, 22276870, 31960941, 11934971
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                566116659100033, 820247422481740, 994464017954148,
++                327157611686365, 92591318111744
++#else
++                39713153, 8435795, 4109644, 12222639, 42480996, 14818668,
++                20638173, 4875028, 10491392, 1379718
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                617256647603209, 1652107761099439, 1857213046645471,
++                1085597175214970, 817432759830522
++#else
++                53949449, 9197840, 3875503, 24618324, 65725151, 27674630,
++                33518458, 16176658, 21432314, 12180697
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                771808161440705, 1323510426395069, 680497615846440,
++                851580615547985, 1320806384849017
++#else
++                55321537, 11500837, 13787581, 19721842, 44678184, 10140204,
++                1465425, 12689540, 56807545, 19681548
++#endif
++            }},
++        },
++    },
++    {
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1219260086131915, 647169006596815, 79601124759706,
++                2161724213426748, 404861897060198
++#else
++                5414091, 18168391, 46101199, 9643569, 12834970, 1186149,
++                64485948, 32212200, 26128230, 6032912
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1327968293887866, 1335500852943256, 1401587164534264,
++                558137311952440, 1551360549268902
++#else
++                40771450, 19788269, 32496024, 19900513, 17847800, 20885276,
++                3604024, 8316894, 41233830, 23117073
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                417621685193956, 1429953819744454, 396157358457099,
++                1940470778873255, 214000046234152
++#else
++                3296484, 6223048, 24680646, 21307972, 44056843, 5903204,
++                58246567, 28915267, 12376616, 3188849
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1268047918491973, 2172375426948536, 1533916099229249,
++                1761293575457130, 1590622667026765
++#else
++                29190469, 18895386, 27549112, 32370916, 3520065, 22857131,
++                32049514, 26245319, 50999629, 23702124
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1627072914981959, 2211603081280073, 1912369601616504,
++                1191770436221309, 2187309757525860
++#else
++                52364359, 24245275, 735817, 32955454, 46701176, 28496527,
++                25246077, 17758763, 18640740, 32593455
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1149147819689533, 378692712667677, 828475842424202,
++                2218619146419342, 70688125792186
++#else
++                60180029, 17123636, 10361373, 5642961, 4910474, 12345252,
++                35470478, 33060001, 10530746, 1053335
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1299739417079761, 1438616663452759, 1536729078504412,
++                2053896748919838, 1008421032591246
++#else
++                37842897, 19367626, 53570647, 21437058, 47651804, 22899047,
++                35646494, 30605446, 24018830, 15026644
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                2040723824657366, 399555637875075, 632543375452995,
++                872649937008051, 1235394727030233
++#else
++                44516310, 30409154, 64819587, 5953842, 53668675, 9425630,
++                25310643, 13003497, 64794073, 18408815
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                2211311599327900, 2139787259888175, 938706616835350,
++                12609661139114, 2081897930719789
++#else
++                39688860, 32951110, 59064879, 31885314, 41016598, 13987818,
++                39811242, 187898, 43942445, 31022696
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1324994503390450, 336982330582631, 1183998925654177,
++                1091654665913274, 48727673971319
++#else
++                45364466, 19743956, 1844839, 5021428, 56674465, 17642958,
++                9716666, 16266922, 62038647, 726098
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1845522914617879, 1222198248335542, 150841072760134,
++                1927029069940982, 1189913404498011
++#else
++                29370903, 27500434, 7334070, 18212173, 9385286, 2247707,
++                53446902, 28714970, 30007387, 17731091
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1079559557592645, 2215338383666441, 1903569501302605,
++                49033973033940, 305703433934152
++#else
++                66172485, 16086690, 23751945, 33011114, 65941325, 28365395,
++                9137108, 730663, 9835848, 4555336
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                94653405416909, 1386121349852999, 1062130477891762,
++                36553947479274, 833669648948846
++#else
++                43732429, 1410445, 44855111, 20654817, 30867634, 15826977,
++                17693930, 544696, 55123566, 12422645
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1432015813136298, 440364795295369, 1395647062821501,
++                1976874522764578, 934452372723352
++#else
++                31117226, 21338698, 53606025, 6561946, 57231997, 20796761,
++                61990178, 29457725, 29120152, 13924425
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1296625309219774, 2068273464883862, 1858621048097805,
++                1492281814208508, 2235868981918946
++#else
++                49707966, 19321222, 19675798, 30819676, 56101901, 27695611,
++                57724924, 22236731, 7240930, 33317044
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1490330266465570, 1858795661361448, 1436241134969763,
++                294573218899647, 1208140011028933
++#else
++                35747106, 22207651, 52101416, 27698213, 44655523, 21401660,
++                1222335, 4389483, 3293637, 18002689
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1282462923712748, 741885683986255, 2027754642827561,
++                518989529541027, 1826610009555945
++#else
++                50424044, 19110186, 11038543, 11054958, 53307689, 30215898,
++                42789283, 7733546, 12796905, 27218610
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1525827120027511, 723686461809551, 1597702369236987,
++                244802101764964, 1502833890372311
++#else
++                58349431, 22736595, 41689999, 10783768, 36493307, 23807620,
++                38855524, 3647835, 3222231, 22393970
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                113622036244513, 1233740067745854, 674109952278496,
++                2114345180342965, 166764512856263
++#else
++                18606113, 1693100, 41660478, 18384159, 4112352, 10045021,
++                23603893, 31506198, 59558087, 2484984
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                2041668749310338, 2184405322203901, 1633400637611036,
++                2110682505536899, 2048144390084644
++#else
++                9255298, 30423235, 54952701, 32550175, 13098012, 24339566,
++                16377219, 31451620, 47306788, 30519729
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                503058759232932, 760293024620937, 2027152777219493,
++                666858468148475, 1539184379870952
++#else
++                44379556, 7496159, 61366665, 11329248, 19991973, 30206930,
++                35390715, 9936965, 37011176, 22935634
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1916168475367211, 915626432541343, 883217071712575,
++                363427871374304, 1976029821251593
++#else
++                21878571, 28553135, 4338335, 13643897, 64071999, 13160959,
++                19708896, 5415497, 59748361, 29445138
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                678039535434506, 570587290189340, 1605302676614120,
++                2147762562875701, 1706063797091704
++#else
++                27736842, 10103576, 12500508, 8502413, 63695848, 23920873,
++                10436917, 32004156, 43449720, 25422331
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1439489648586438, 2194580753290951, 832380563557396,
++                561521973970522, 584497280718389
++#else
++                19492550, 21450067, 37426887, 32701801, 63900692, 12403436,
++                30066266, 8367329, 13243957, 8709688
++#endif
++            }},
++        },
++    },
++    {
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                187989455492609, 681223515948275, 1933493571072456,
++                1872921007304880, 488162364135671
++#else
++                12015105, 2801261, 28198131, 10151021, 24818120, 28811299,
++                55914672, 27908697, 5150967, 7274186
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1413466089534451, 410844090765630, 1397263346404072,
++                408227143123410, 1594561803147811
++#else
++                2831347, 21062286, 1478974, 6122054, 23825128, 20820846,
++                31097298, 6083058, 31021603, 23760822
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                2102170800973153, 719462588665004, 1479649438510153,
++                1097529543970028, 1302363283777685
++#else
++                64578913, 31324785, 445612, 10720828, 53259337, 22048494,
++                43601132, 16354464, 15067285, 19406725
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                942065717847195, 1069313679352961, 2007341951411051,
++                70973416446291, 1419433790163706
++#else
++                7840923, 14037873, 33744001, 15934015, 66380651, 29911725,
++                21403987, 1057586, 47729402, 21151211
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1146565545556377, 1661971299445212, 406681704748893,
++                564452436406089, 1109109865829139
++#else
++                915865, 17085158, 15608284, 24765302, 42751837, 6060029,
++                49737545, 8410996, 59888403, 16527024
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                2214421081775077, 1165671861210569, 1890453018796184,
++                3556249878661, 442116172656317
++#else
++                32922597, 32997445, 20336073, 17369864, 10903704, 28169945,
++                16957573, 52992, 23834301, 6588044
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                753830546620811, 1666955059895019, 1530775289309243,
++                1119987029104146, 2164156153857580
++#else
++                32752011, 11232950, 3381995, 24839566, 22652987, 22810329,
++                17159698, 16689107, 46794284, 32248439
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                615171919212796, 1523849404854568, 854560460547503,
++                2067097370290715, 1765325848586042
++#else
++                62419196, 9166775, 41398568, 22707125, 11576751, 12733943,
++                7924251, 30802151, 1976122, 26305405
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1094538949313667, 1796592198908825, 870221004284388,
++                2025558921863561, 1699010892802384
++#else
++                21251203, 16309901, 64125849, 26771309, 30810596, 12967303,
++                156041, 30183180, 12331344, 25317235
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1951351290725195, 1916457206844795, 198025184438026,
++                1909076887557595, 1938542290318919
++#else
++                8651595, 29077400, 51023227, 28557437, 13002506, 2950805,
++                29054427, 28447462, 10008135, 28886531
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1014323197538413, 869150639940606, 1756009942696599,
++                1334952557375672, 1544945379082874
++#else
++                31486061, 15114593, 52847614, 12951353, 14369431, 26166587,
++                16347320, 19892343, 8684154, 23021480
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                764055910920305, 1603590757375439, 146805246592357,
++                1843313433854297, 954279890114939
++#else
++                19443825, 11385320, 24468943, 23895364, 43189605, 2187568,
++                40845657, 27467510, 31316347, 14219878
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                80113526615750, 764536758732259, 1055139345100233,
++                469252651759390, 617897512431515
++#else
++                38514374, 1193784, 32245219, 11392485, 31092169, 15722801,
++                27146014, 6992409, 29126555, 9207390
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                74497112547268, 740094153192149, 1745254631717581,
++                727713886503130, 1283034364416928
++#else
++                32382916, 1110093, 18477781, 11028262, 39697101, 26006320,
++                62128346, 10843781, 59151264, 19118701
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                525892105991110, 1723776830270342, 1476444848991936,
++                573789489857760, 133864092632978
++#else
++                2814918, 7836403, 27519878, 25686276, 46214848, 22000742,
++                45614304, 8550129, 28346258, 1994730
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                542611720192581, 1986812262899321, 1162535242465837,
++                481498966143464, 544600533583622
++#else
++                47530565, 8085544, 53108345, 29605809, 2785837, 17323125,
++                47591912, 7174893, 22628102, 8115180
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                64123227344372, 1239927720647794, 1360722983445904,
++                222610813654661, 62429487187991
++#else
++                36703732, 955510, 55975026, 18476362, 34661776, 20276352,
++                41457285, 3317159, 57165847, 930271
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1793193323953132, 91096687857833, 70945970938921,
++                2158587638946380, 1537042406482111
++#else
++                51805164, 26720662, 28856489, 1357446, 23421993, 1057177,
++                24091212, 32165462, 44343487, 22903716
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1895854577604609, 1394895708949416, 1728548428495944,
++                1140864900240149, 563645333603061
++#else
++                44357633, 28250434, 54201256, 20785565, 51297352, 25757378,
++                52269845, 17000211, 65241845, 8398969
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                141358280486863, 91435889572504, 1087208572552643,
++                1829599652522921, 1193307020643647
++#else
++                35139535, 2106402, 62372504, 1362500, 12813763, 16200670,
++                22981545, 27263159, 18009407, 17781660
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1611230858525381, 950720175540785, 499589887488610,
++                2001656988495019, 88977313255908
++#else
++                49887941, 24009210, 39324209, 14166834, 29815394, 7444469,
++                29551787, 29827013, 19288548, 1325865
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1189080501479658, 2184348804772597, 1040818725742319,
++                2018318290311834, 1712060030915354
++#else
++                15100138, 17718680, 43184885, 32549333, 40658671, 15509407,
++                12376730, 30075286, 33166106, 25511682
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                873966876953756, 1090638350350440, 1708559325189137,
++                672344594801910, 1320437969700239
++#else
++                20909212, 13023121, 57899112, 16251777, 61330449, 25459517,
++                12412150, 10018715, 2213263, 19676059
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1508590048271766, 1131769479776094, 101550868699323,
++                428297785557897, 561791648661744
++#else
++                32529814, 22479743, 30361438, 16864679, 57972923, 1513225,
++                22922121, 6382134, 61341936, 8371347
++#endif
++            }},
++        },
++    },
++    {
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                756417570499462, 237882279232602, 2136263418594016,
++                1701968045454886, 703713185137472
++#else
++                9923462, 11271500, 12616794, 3544722, 37110496, 31832805,
++                12891686, 25361300, 40665920, 10486143
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1781187809325462, 1697624151492346, 1381393690939988,
++                175194132284669, 1483054666415238
++#else
++                44511638, 26541766, 8587002, 25296571, 4084308, 20584370,
++                361725, 2610596, 43187334, 22099236
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                2175517777364616, 708781536456029, 955668231122942,
++                1967557500069555, 2021208005604118
++#else
++                5408392, 32417741, 62139741, 10561667, 24145918, 14240566,
++                31319731, 29318891, 19985174, 30118346
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1115135966606887, 224217372950782, 915967306279222,
++                593866251291540, 561747094208006
++#else
++                53114407, 16616820, 14549246, 3341099, 32155958, 13648976,
++                49531796, 8849296, 65030, 8370684
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1443163092879439, 391875531646162, 2180847134654632,
++                464538543018753, 1594098196837178
++#else
++                58787919, 21504805, 31204562, 5839400, 46481576, 32497154,
++                47665921, 6922163, 12743482, 23753914
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                850858855888869, 319436476624586, 327807784938441,
++                740785849558761, 17128415486016
++#else
++                64747493, 12678784, 28815050, 4759974, 43215817, 4884716,
++                23783145, 11038569, 18800704, 255233
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                2132756334090067, 536247820155645, 48907151276867,
++                608473197600695, 1261689545022784
++#else
++                61839187, 31780545, 13957885, 7990715, 23132995, 728773,
++                13393847, 9066957, 19258688, 18800639
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1525176236978354, 974205476721062, 293436255662638,
++                148269621098039, 137961998433963
++#else
++                64172210, 22726896, 56676774, 14516792, 63468078, 4372540,
++                35173943, 2209389, 65584811, 2055793
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1121075518299410, 2071745529082111, 1265567917414828,
++                1648196578317805, 496232102750820
++#else
++                580882, 16705327, 5468415, 30871414, 36182444, 18858431,
++                59905517, 24560042, 37087844, 7394434
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                122321229299801, 1022922077493685, 2001275453369484,
++                2017441881607947, 993205880778002
++#else
++                23838809, 1822728, 51370421, 15242726, 8318092, 29821328,
++                45436683, 30062226, 62287122, 14799920
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                654925550560074, 1168810995576858, 575655959430926,
++                905758704861388, 496774564663534
++#else
++                13345610, 9759151, 3371034, 17416641, 16353038, 8577942,
++                31129804, 13496856, 58052846, 7402517
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1954109525779738, 2117022646152485, 338102630417180,
++                1194140505732026, 107881734943492
++#else
++                2286874, 29118501, 47066405, 31546095, 53412636, 5038121,
++                11006906, 17794080, 8205060, 1607563
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1714785840001267, 2036500018681589, 1876380234251966,
++                2056717182974196, 1645855254384642
++#else
++                14414067, 25552300, 3331829, 30346215, 22249150, 27960244,
++                18364660, 30647474, 30019586, 24525154
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                106431476499341, 62482972120563, 1513446655109411,
++                807258751769522, 538491469114
++#else
++                39420813, 1585952, 56333811, 931068, 37988643, 22552112,
++                52698034, 12029092, 9944378, 8024
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                2002850762893643, 1243624520538135, 1486040410574605,
++                2184752338181213, 378495998083531
++#else
++                4368715, 29844802, 29874199, 18531449, 46878477, 22143727,
++                50994269, 32555346, 58966475, 5640029
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                922510868424903, 1089502620807680, 402544072617374,
++                1131446598479839, 1290278588136533
++#else
++                10299591, 13746483, 11661824, 16234854, 7630238, 5998374,
++                9809887, 16859868, 15219797, 19226649
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1867998812076769, 715425053580701, 39968586461416,
++                2173068014586163, 653822651801304
++#else
++                27425505, 27835351, 3055005, 10660664, 23458024, 595578,
++                51710259, 32381236, 48766680, 9742716
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                162892278589453, 182585796682149, 75093073137630,
++                497037941226502, 133871727117371
++#else
++                6744077, 2427284, 26042789, 2720740, 66260958, 1118973,
++                32324614, 7406442, 12420155, 1994844
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1914596576579670, 1608999621851578, 1987629837704609,
++                1519655314857977, 1819193753409464
++#else
++                14012502, 28529712, 48724410, 23975962, 40623521, 29617992,
++                54075385, 22644628, 24319928, 27108099
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1949315551096831, 1069003344994464, 1939165033499916,
++                1548227205730856, 1933767655861407
++#else
++                16412671, 29047065, 10772640, 15929391, 50040076, 28895810,
++                10555944, 23070383, 37006495, 28815383
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1730519386931635, 1393284965610134, 1597143735726030,
++                416032382447158, 1429665248828629
++#else
++                22397363, 25786748, 57815702, 20761563, 17166286, 23799296,
++                39775798, 6199365, 21880021, 21303672
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                360275475604565, 547835731063078, 215360904187529,
++                596646739879007, 332709650425085
++#else
++                62825557, 5368522, 35991846, 8163388, 36785801, 3209127,
++                16557151, 8890729, 8840445, 4957760
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                47602113726801, 1522314509708010, 437706261372925,
++                814035330438027, 335930650933545
++#else
++                51661137, 709326, 60189418, 22684253, 37330941, 6522331,
++                45388683, 12130071, 52312361, 5005756
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1291597595523886, 1058020588994081, 402837842324045,
++                1363323695882781, 2105763393033193
++#else
++                64994094, 19246303, 23019041, 15765735, 41839181, 6002751,
++                10183197, 20315106, 50713577, 31378319
++#endif
++            }},
++        },
++    },
++    {
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                109521982566564, 1715257748585139, 1112231216891516,
++                2046641005101484, 134249157157013
++#else
++                48083108, 1632004, 13466291, 25559332, 43468412, 16573536,
++                35094956, 30497327, 22208661, 2000468
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                2156991030936798, 2227544497153325, 1869050094431622,
++                754875860479115, 1754242344267058
++#else
++                3065054, 32141671, 41510189, 33192999, 49425798, 27851016,
++                58944651, 11248526, 63417650, 26140247
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1846089562873800, 98894784984326, 1412430299204844,
++                171351226625762, 1100604760929008
++#else
++                10379208, 27508878, 8877318, 1473647, 37817580, 21046851,
++                16690914, 2553332, 63976176, 16400288
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                84172382130492, 499710970700046, 425749630620778,
++                1762872794206857, 612842602127960
++#else
++                15716668, 1254266, 48636174, 7446273, 58659946, 6344163,
++                45011593, 26268851, 26894936, 9132066
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                868309334532756, 1703010512741873, 1952690008738057,
++                4325269926064, 2071083554962116
++#else
++                24158868, 12938817, 11085297, 25376834, 39045385, 29097348,
++                36532400, 64451, 60291780, 30861549
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                523094549451158, 401938899487815, 1407690589076010,
++                2022387426254453, 158660516411257
++#else
++                13488534, 7794716, 22236231, 5989356, 25426474, 20976224,
++                2350709, 30135921, 62420857, 2364225
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                612867287630009, 448212612103814, 571629077419196,
++                1466796750919376, 1728478129663858
++#else
++                16335033, 9132434, 25640582, 6678888, 1725628, 8517937,
++                55301840, 21856974, 15445874, 25756331
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1723848973783452, 2208822520534681, 1718748322776940,
++                1974268454121942, 1194212502258141
++#else
++                29004188, 25687351, 28661401, 32914020, 54314860, 25611345,
++                31863254, 29418892, 66830813, 17795152
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1254114807944608, 977770684047110, 2010756238954993,
++                1783628927194099, 1525962994408256
++#else
++                60986784, 18687766, 38493958, 14569918, 56250865, 29962602,
++                10343411, 26578142, 37280576, 22738620
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                232464058235826, 1948628555342434, 1835348780427694,
++                1031609499437291, 64472106918373
++#else
++                27081650, 3463984, 14099042, 29036828, 1616302, 27348828,
++                29542635, 15372179, 17293797, 960709
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                767338676040683, 754089548318405, 1523192045639075,
++                435746025122062, 512692508440385
++#else
++                20263915, 11434237, 61343429, 11236809, 13505955, 22697330,
++                50997518, 6493121, 47724353, 7639713
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1255955808701983, 1700487367990941, 1166401238800299,
++                1175121994891534, 1190934801395380
++#else
++                64278047, 18715199, 25403037, 25339236, 58791851, 17380732,
++                18006286, 17510682, 29994676, 17746311
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                349144008168292, 1337012557669162, 1475912332999108,
++                1321618454900458, 47611291904320
++#else
++                9769828, 5202651, 42951466, 19923039, 39057860, 21992807,
++                42495722, 19693649, 35924288, 709463
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                877519947135419, 2172838026132651, 272304391224129,
++                1655143327559984, 886229406429814
++#else
++                12286395, 13076066, 45333675, 32377809, 42105665, 4057651,
++                35090736, 24663557, 16102006, 13205847
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                375806028254706, 214463229793940, 572906353144089,
++                572168269875638, 697556386112979
++#else
++                13733362, 5599946, 10557076, 3195751, 61550873, 8536969,
++                41568694, 8525971, 10151379, 10394400
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1168827102357844, 823864273033637, 2071538752104697,
++                788062026895924, 599578340743362
++#else
++                4024660, 17416881, 22436261, 12276534, 58009849, 30868332,
++                19698228, 11743039, 33806530, 8934413
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1948116082078088, 2054898304487796, 2204939184983900,
++                210526805152138, 786593586607626
++#else
++                51229064, 29029191, 58528116, 30620370, 14634844, 32856154,
++                57659786, 3137093, 55571978, 11721157
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1915320147894736, 156481169009469, 655050471180417,
++                592917090415421, 2165897438660879
++#else
++                17555920, 28540494, 8268605, 2331751, 44370049, 9761012,
++                9319229, 8835153, 57903375, 32274386
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1726336468579724, 1119932070398949, 1929199510967666,
++                33918788322959, 1836837863503150
++#else
++                66647436, 25724417, 20614117, 16688288, 59594098, 28747312,
++                22300303, 505429, 6108462, 27371017
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                829996854845988, 217061778005138, 1686565909803640,
++                1346948817219846, 1723823550730181
++#else
++                62038564, 12367916, 36445330, 3234472, 32617080, 25131790,
++                29880582, 20071101, 40210373, 25686972
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                384301494966394, 687038900403062, 2211195391021739,
++                254684538421383, 1245698430589680
++#else
++                35133562, 5726538, 26934134, 10237677, 63935147, 32949378,
++                24199303, 3795095, 7592688, 18562353
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1247567493562688, 1978182094455847, 183871474792955,
++                806570235643435, 288461518067916
++#else
++                21594432, 18590204, 17466407, 29477210, 32537083, 2739898,
++                6407723, 12018833, 38852812, 4298411
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1449077384734201, 38285445457996, 2136537659177832,
++                2146493000841573, 725161151123125
++#else
++                46458361, 21592935, 39872588, 570497, 3767144, 31836892,
++                13891941, 31985238, 13717173, 10805743
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1201928866368855, 800415690605445, 1703146756828343,
++                997278587541744, 1858284414104014
++#else
++                52432215, 17910135, 15287173, 11927123, 24177847, 25378864,
++                66312432, 14860608, 40169934, 27690595
++#endif
++            }},
++        },
++    },
++    {
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                356468809648877, 782373916933152, 1718002439402870,
++                1392222252219254, 663171266061951
++#else
++                12962541, 5311799, 57048096, 11658279, 18855286, 25600231,
++                13286262, 20745728, 62727807, 9882021
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                759628738230460, 1012693474275852, 353780233086498,
++                246080061387552, 2030378857679162
++#else
++                18512060, 11319350, 46985740, 15090308, 18818594, 5271736,
++                44380960, 3666878, 43141434, 30255002
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                2040672435071076, 888593182036908, 1298443657189359,
++                1804780278521327, 354070726137060
++#else
++                60319844, 30408388, 16192428, 13241070, 15898607, 19348318,
++                57023983, 26893321, 64705764, 5276064
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1894938527423184, 1463213041477277, 474410505497651,
++                247294963033299, 877975941029128
++#else
++                30169808, 28236784, 26306205, 21803573, 27814963, 7069267,
++                7152851, 3684982, 1449224, 13082861
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                207937160991127, 12966911039119, 820997788283092,
++                1010440472205286, 1701372890140810
++#else
++                10342807, 3098505, 2119311, 193222, 25702612, 12233820,
++                23697382, 15056736, 46092426, 25352431
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                218882774543183, 533427444716285, 1233243976733245,
++                435054256891319, 1509568989549904
++#else
++                33958735, 3261607, 22745853, 7948688, 19370557, 18376767,
++                40936887, 6482813, 56808784, 22494330
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1888838535711826, 1052177758340622, 1213553803324135,
++                169182009127332, 463374268115872
++#else
++                32869458, 28145887, 25609742, 15678670, 56421095, 18083360,
++                26112420, 2521008, 44444576, 6904814
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                299137589460312, 1594371588983567, 868058494039073,
++                257771590636681, 1805012993142921
++#else
++                29506904, 4457497, 3377935, 23757988, 36598817, 12935079,
++                1561737, 3841096, 38105225, 26896789
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1806842755664364, 2098896946025095, 1356630998422878,
++                1458279806348064, 347755825962072
++#else
++                10340844, 26924055, 48452231, 31276001, 12621150, 20215377,
++                30878496, 21730062, 41524312, 5181965
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1402334161391744, 1560083671046299, 1008585416617747,
++                1147797150908892, 1420416683642459
++#else
++                25940096, 20896407, 17324187, 23247058, 58437395, 15029093,
++                24396252, 17103510, 64786011, 21165857
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                665506704253369, 273770475169863, 799236974202630,
++                848328990077558, 1811448782807931
++#else
++                45343161, 9916822, 65808455, 4079497, 66080518, 11909558,
++                1782390, 12641087, 20603771, 26992690
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1468412523962641, 771866649897997, 1931766110147832,
++                799561180078482, 524837559150077
++#else
++                48226577, 21881051, 24849421, 11501709, 13161720, 28785558,
++                1925522, 11914390, 4662781, 7820689
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                2223212657821850, 630416247363666, 2144451165500328,
++                816911130947791, 1024351058410032
++#else
++                12241050, 33128450, 8132690, 9393934, 32846760, 31954812,
++                29749455, 12172924, 16136752, 15264020
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1266603897524861, 156378408858100, 1275649024228779,
++                447738405888420, 253186462063095
++#else
++                56758909, 18873868, 58896884, 2330219, 49446315, 19008651,
++                10658212, 6671822, 19012087, 3772772
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                2022215964509735, 136144366993649, 1800716593296582,
++                1193970603800203, 871675847064218
++#else
++                3753511, 30133366, 10617073, 2028709, 14841030, 26832768,
++                28718731, 17791548, 20527770, 12988982
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1862751661970328, 851596246739884, 1519315554814041,
++                1542798466547449, 1417975335901520
++#else
++                52286360, 27757162, 63400876, 12689772, 66209881, 22639565,
++                42925817, 22989488, 3299664, 21129479
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1228168094547481, 334133883362894, 587567568420081,
++                433612590281181, 603390400373205
++#else
++                50331161, 18301130, 57466446, 4978982, 3308785, 8755439,
++                6943197, 6461331, 41525717, 8991217
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                121893973206505, 1843345804916664, 1703118377384911,
++                497810164760654, 101150811654673
++#else
++                49882601, 1816361, 65435576, 27467992, 31783887, 25378441,
++                34160718, 7417949, 36866577, 1507264
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                458346255946468, 290909935619344, 1452768413850679,
++                550922875254215, 1537286854336538
++#else
++                29692644, 6829891, 56610064, 4334895, 20945975, 21647936,
++                38221255, 8209390, 14606362, 22907359
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                584322311184395, 380661238802118, 114839394528060,
++                655082270500073, 2111856026034852
++#else
++                63627275, 8707080, 32188102, 5672294, 22096700, 1711240,
++                34088169, 9761486, 4170404, 31469107
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                996965581008991, 2148998626477022, 1012273164934654,
++                1073876063914522, 1688031788934939
++#else
++                55521375, 14855944, 62981086, 32022574, 40459774, 15084045,
++                22186522, 16002000, 52832027, 25153633
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                923487018849600, 2085106799623355, 528082801620136,
++                1606206360876188, 735907091712524
++#else
++                62297408, 13761028, 35404987, 31070512, 63796392, 7869046,
++                59995292, 23934339, 13240844, 10965870
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1697697887804317, 1335343703828273, 831288615207040,
++                949416685250051, 288760277392022
++#else
++                59366301, 25297669, 52340529, 19898171, 43876480, 12387165,
++                4498947, 14147411, 29514390, 4302863
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1419122478109648, 1325574567803701, 602393874111094,
++                2107893372601700, 1314159682671307
++#else
++                53695440, 21146572, 20757301, 19752600, 14785142, 8976368,
++                62047588, 31410058, 17846987, 19582505
++#endif
++            }},
++        },
++    },
++    {
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                2201150872731804, 2180241023425241, 97663456423163,
++                1633405770247824, 848945042443986
++#else
++                64864412, 32799703, 62511833, 32488122, 60861691, 1455298,
++                45461136, 24339642, 61886162, 12650266
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1173339555550611, 818605084277583, 47521504364289,
++                924108720564965, 735423405754506
++#else
++                57202067, 17484121, 21134159, 12198166, 40044289, 708125,
++                387813, 13770293, 47974538, 10958662
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                830104860549448, 1886653193241086, 1600929509383773,
++                1475051275443631, 286679780900937
++#else
++                22470984, 12369526, 23446014, 28113323, 45588061, 23855708,
++                55336367, 21979976, 42025033, 4271861
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1577111294832995, 1030899169768747, 144900916293530,
++                1964672592979567, 568390100955250
++#else
++                41939299, 23500789, 47199531, 15361594, 61124506, 2159191,
++                75375, 29275903, 34582642, 8469672
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                278388655910247, 487143369099838, 927762205508727,
++                181017540174210, 1616886700741287
++#else
++                15854951, 4148314, 58214974, 7259001, 11666551, 13824734,
++                36577666, 2697371, 24154791, 24093489
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1191033906638969, 940823957346562, 1606870843663445,
++                861684761499847, 658674867251089
++#else
++                15446137, 17747788, 29759746, 14019369, 30811221, 23944241,
++                35526855, 12840103, 24913809, 9815020
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1875032594195546, 1427106132796197, 724736390962158,
++                901860512044740, 635268497268760
++#else
++                62399578, 27940162, 35267365, 21265538, 52665326, 10799413,
++                58005188, 13438768, 18735128, 9466238
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                622869792298357, 1903919278950367, 1922588621661629,
++                1520574711600434, 1087100760174640
++#else
++                11933045, 9281483, 5081055, 28370608, 64480701, 28648802,
++                59381042, 22658328, 44380208, 16199063
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                25465949416618, 1693639527318811, 1526153382657203,
++                125943137857169, 145276964043999
++#else
++                14576810, 379472, 40322331, 25237195, 37682355, 22741457,
++                67006097, 1876698, 30801119, 2164795
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                214739857969358, 920212862967915, 1939901550972269,
++                1211862791775221, 85097515720120
++#else
++                15995086, 3199873, 13672555, 13712240, 47730029, 28906785,
++                54027253, 18058162, 53616056, 1268051
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                2006245852772938, 734762734836159, 254642929763427,
++                1406213292755966, 239303749517686
++#else
++                56818250, 29895392, 63822271, 10948817, 23037027, 3794475,
++                63638526, 20954210, 50053494, 3565903
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1619678837192149, 1919424032779215, 1357391272956794,
++                1525634040073113, 1310226789796241
++#else
++                29210069, 24135095, 61189071, 28601646, 10834810, 20226706,
++                50596761, 22733718, 39946641, 19523900
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1040763709762123, 1704449869235352, 605263070456329,
++                1998838089036355, 1312142911487502
++#else
++                53946955, 15508587, 16663704, 25398282, 38758921, 9019122,
++                37925443, 29785008, 2244110, 19552453
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1996723311435669, 1844342766567060, 985455700466044,
++                1165924681400960, 311508689870129
++#else
++                61955989, 29753495, 57802388, 27482848, 16243068, 14684434,
++                41435776, 17373631, 13491505, 4641841
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                43173156290518, 2202883069785309, 1137787467085917,
++                1733636061944606, 1394992037553852
++#else
++                10813398, 643330, 47920349, 32825515, 30292061, 16954354,
++                27548446, 25833190, 14476988, 20787001
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                670078326344559, 555655025059356, 471959386282438,
++                2141455487356409, 849015953823125
++#else
++                10292079, 9984945, 6481436, 8279905, 59857350, 7032742,
++                27282937, 31910173, 39196053, 12651323
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                2197214573372804, 794254097241315, 1030190060513737,
++                267632515541902, 2040478049202624
++#else
++                35923332, 32741048, 22271203, 11835308, 10201545, 15351028,
++                17099662, 3988035, 21721536, 30405492
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1812516004670529, 1609256702920783, 1706897079364493,
++                258549904773295, 996051247540686
++#else
++                10202177, 27008593, 35735631, 23979793, 34958221, 25434748,
++                54202543, 3852693, 13216206, 14842320
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1540374301420584, 1764656898914615, 1810104162020396,
++                923808779163088, 664390074196579
++#else
++                51293224, 22953365, 60569911, 26295436, 60124204, 26972653,
++                35608016, 13765823, 39674467, 9900183
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1323460699404750, 1262690757880991, 871777133477900,
++                1060078894988977, 1712236889662886
++#else
++                14465486, 19721101, 34974879, 18815558, 39665676, 12990491,
++                33046193, 15796406, 60056998, 25514317
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1696163952057966, 1391710137550823, 608793846867416,
++                1034391509472039, 1780770894075012
++#else
++                30924398, 25274812, 6359015, 20738097, 16508376, 9071735,
++                41620263, 15413634, 9524356, 26535554
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1367603834210841, 2131988646583224, 890353773628144,
++                1908908219165595, 270836895252891
++#else
++                12274201, 20378885, 32627640, 31769106, 6736624, 13267305,
++                5237659, 28444949, 15663515, 4035784
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                597536315471731, 40375058742586, 1942256403956049,
++                1185484645495932, 312666282024145
++#else
++                64157555, 8903984, 17349946, 601635, 50676049, 28941875,
++                53376124, 17665097, 44850385, 4659090
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1919411405316294, 1234508526402192, 1066863051997083,
++                1008444703737597, 1348810787701552
++#else
++                50192582, 28601458, 36715152, 18395610, 20774811, 15897498,
++                5736189, 15026997, 64930608, 20098846
++#endif
++            }},
++        },
++    },
++    {
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                2102881477513865, 1570274565945361, 1573617900503708,
++                18662635732583, 2232324307922098
++#else
++                58249865, 31335375, 28571665, 23398914, 66634396, 23448733,
++                63307367, 278094, 23440562, 33264224
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1853931367696942, 8107973870707, 350214504129299,
++                775206934582587, 1752317649166792
++#else
++                10226222, 27625730, 15139955, 120818, 52241171, 5218602,
++                32937275, 11551483, 50536904, 26111567
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1417148368003523, 721357181628282, 505725498207811,
++                373232277872983, 261634707184480
++#else
++                17932739, 21117156, 43069306, 10749059, 11316803, 7535897,
++                22503767, 5561594, 63462240, 3898660
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                2186733281493267, 2250694917008620, 1014829812957440,
++                479998161452389, 83566193876474
++#else
++                7749907, 32584865, 50769132, 33537967, 42090752, 15122142,
++                65535333, 7152529, 21831162, 1245233
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1268116367301224, 560157088142809, 802626839600444,
++                2210189936605713, 1129993785579988
++#else
++                26958440, 18896406, 4314585, 8346991, 61431100, 11960071,
++                34519569, 32934396, 36706772, 16838219
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                615183387352312, 917611676109240, 878893615973325,
++                978940963313282, 938686890583575
++#else
++                54942968, 9166946, 33491384, 13673479, 29787085, 13096535,
++                6280834, 14587357, 44770839, 13987524
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                522024729211672, 1045059315315808, 1892245413707790,
++                1907891107684253, 2059998109500714
++#else
++                42758936, 7778774, 21116000, 15572597, 62275598, 28196653,
++                62807965, 28429792, 59639082, 30696363
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1799679152208884, 912132775900387, 25967768040979,
++                432130448590461, 274568990261996
++#else
++                9681908, 26817309, 35157219, 13591837, 60225043, 386949,
++                31622781, 6439245, 52527852, 4091396
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                98698809797682, 2144627600856209, 1907959298569602,
++                811491302610148, 1262481774981493
++#else
++                58682418, 1470726, 38999185, 31957441, 3978626, 28430809,
++                47486180, 12092162, 29077877, 18812444
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1791451399743152, 1713538728337276, 118349997257490,
++                1882306388849954, 158235232210248
++#else
++                5269168, 26694706, 53878652, 25533716, 25932562, 1763552,
++                61502754, 28048550, 47091016, 2357888
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1217809823321928, 2173947284933160, 1986927836272325,
++                1388114931125539, 12686131160169
++#else
++                32264008, 18146780, 61721128, 32394338, 65017541, 29607531,
++                23104803, 20684524, 5727337, 189038
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1650875518872272, 1136263858253897, 1732115601395988,
++                734312880662190, 1252904681142109
++#else
++                14609104, 24599962, 61108297, 16931650, 52531476, 25810533,
++                40363694, 10942114, 41219933, 18669734
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                372986456113865, 525430915458171, 2116279931702135,
++                501422713587815, 1907002872974925
++#else
++                20513481, 5557931, 51504251, 7829530, 26413943, 31535028,
++                45729895, 7471780, 13913677, 28416557
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                803147181835288, 868941437997146, 316299302989663,
++                943495589630550, 571224287904572
++#else
++                41534488, 11967825, 29233242, 12948236, 60354399, 4713226,
++                58167894, 14059179, 12878652, 8511905
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                227742695588364, 1776969298667369, 628602552821802,
++                457210915378118, 2041906378111140
++#else
++                41452044, 3393630, 64153449, 26478905, 64858154, 9366907,
++                36885446, 6812973, 5568676, 30426776
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                815000523470260, 913085688728307, 1052060118271173,
++                1345536665214223, 541623413135555
++#else
++                11630004, 12144454, 2116339, 13606037, 27378885, 15676917,
++                49700111, 20050058, 52713667, 8070817
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1580216071604333, 1877997504342444, 857147161260913,
++                703522726778478, 2182763974211603
++#else
++                27117677, 23547054, 35826092, 27984343, 1127281, 12772488,
++                37262958, 10483305, 55556115, 32525717
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1870080310923419, 71988220958492, 1783225432016732,
++                615915287105016, 1035570475990230
++#else
++                10637467, 27866368, 5674780, 1072708, 40765276, 26572129,
++                65424888, 9177852, 39615702, 15431202
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                730987750830150, 857613889540280, 1083813157271766,
++                1002817255970169, 1719228484436074
++#else
++                20525126, 10892566, 54366392, 12779442, 37615830, 16150074,
++                38868345, 14943141, 52052074, 25618500
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                377616581647602, 1581980403078513, 804044118130621,
++                2034382823044191, 643844048472185
++#else
++                37084402, 5626925, 66557297, 23573344, 753597, 11981191,
++                25244767, 30314666, 63752313, 9594023
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                176957326463017, 1573744060478586, 528642225008045,
++                1816109618372371, 1515140189765006
++#else
++                43356201, 2636869, 61944954, 23450613, 585133, 7877383,
++                11345683, 27062142, 13352334, 22577348
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1888911448245718, 1387110895611080, 1924503794066429,
++                1731539523700949, 2230378382645454
++#else
++                65177046, 28146973, 3304648, 20669563, 17015805, 28677341,
++                37325013, 25801949, 53893326, 33235227
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                443392177002051, 233793396845137, 2199506622312416,
++                1011858706515937, 974676837063129
++#else
++                20239939, 6607058, 6203985, 3483793, 48721888, 32775202,
++                46385121, 15077869, 44358105, 14523816
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1846351103143623, 1949984838808427, 671247021915253,
++                1946756846184401, 1929296930380217
++#else
++                27406023, 27512775, 27423595, 29057038, 4996213, 10002360,
++                38266833, 29008937, 36936121, 28748764
++#endif
++            }},
++        },
++    },
++    {
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                849646212452002, 1410198775302919, 73767886183695,
++                1641663456615812, 762256272452411
++#else
++                11374242, 12660715, 17861383, 21013599, 10935567, 1099227,
++                53222788, 24462691, 39381819, 11358503
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                692017667358279, 723305578826727, 1638042139863265,
++                748219305990306, 334589200523901
++#else
++                54378055, 10311866, 1510375, 10778093, 64989409, 24408729,
++                32676002, 11149336, 40985213, 4985767
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                22893968530686, 2235758574399251, 1661465835630252,
++                925707319443452, 1203475116966621
++#else
++                48012542, 341146, 60911379, 33315398, 15756972, 24757770,
++                66125820, 13794113, 47694557, 17933176
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                801299035785166, 1733292596726131, 1664508947088596,
++                467749120991922, 1647498584535623
++#else
++                6490062, 11940286, 25495923, 25828072, 8668372, 24803116,
++                3367602, 6970005, 65417799, 24549641
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                903105258014366, 427141894933047, 561187017169777,
++                1884330244401954, 1914145708422219
++#else
++                1656478, 13457317, 15370807, 6364910, 13605745, 8362338,
++                47934242, 28078708, 50312267, 28522993
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1344191060517578, 1960935031767890, 1518838929955259,
++                1781502350597190, 1564784025565682
++#else
++                44835530, 20030007, 67044178, 29220208, 48503227, 22632463,
++                46537798, 26546453, 67009010, 23317098
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                673723351748086, 1979969272514923, 1175287312495508,
++                1187589090978666, 1881897672213940
++#else
++                17747446, 10039260, 19368299, 29503841, 46478228, 17513145,
++                31992682, 17696456, 37848500, 28042460
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1917185587363432, 1098342571752737, 5935801044414,
++                2000527662351839, 1538640296181569
++#else
++                31932008, 28568291, 47496481, 16366579, 22023614, 88450,
++                11371999, 29810185, 4882241, 22927527
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                2495540013192, 678856913479236, 224998292422872,
++                219635787698590, 1972465269000940
++#else
++                29796488, 37186, 19818052, 10115756, 55279832, 3352735,
++                18551198, 3272828, 61917932, 29392022
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                271413961212179, 1353052061471651, 344711291283483,
++                2014925838520662, 2006221033113941
++#else
++                12501267, 4044383, 58495907, 20162046, 34678811, 5136598,
++                47878486, 30024734, 330069, 29895023
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                194583029968109, 514316781467765, 829677956235672,
++                1676415686873082, 810104584395840
++#else
++                6384877, 2899513, 17807477, 7663917, 64749976, 12363164,
++                25366522, 24980540, 66837568, 12071498
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1980510813313589, 1948645276483975, 152063780665900,
++                129968026417582, 256984195613935
++#else
++                58743349, 29511910, 25133447, 29037077, 60897836, 2265926,
++                34339246, 1936674, 61949167, 3829362
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1860190562533102, 1936576191345085, 461100292705964,
++                1811043097042830, 957486749306835
++#else
++                28425966, 27718999, 66531773, 28857233, 52891308, 6870929,
++                7921550, 26986645, 26333139, 14267664
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                796664815624365, 1543160838872951, 1500897791837765,
++                1667315977988401, 599303877030711
++#else
++                56041645, 11871230, 27385719, 22994888, 62522949, 22365119,
++                10004785, 24844944, 45347639, 8930323
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1151480509533204, 2136010406720455, 738796060240027,
++                319298003765044, 1150614464349587
++#else
++                45911060, 17158396, 25654215, 31829035, 12282011, 11008919,
++                1541940, 4757911, 40617363, 17145491
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1731069268103150, 735642447616087, 1364750481334268,
++                417232839982871, 927108269127661
++#else
++                13537262, 25794942, 46504023, 10961926, 61186044, 20336366,
++                53952279, 6217253, 51165165, 13814989
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1017222050227968, 1987716148359, 2234319589635701,
++                621282683093392, 2132553131763026
++#else
++                49686272, 15157789, 18705543, 29619, 24409717, 33293956,
++                27361680, 9257833, 65152338, 31777517
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1567828528453324, 1017807205202360, 565295260895298,
++                829541698429100, 307243822276582
++#else
++                42063564, 23362465, 15366584, 15166509, 54003778, 8423555,
++                37937324, 12361134, 48422886, 4578289
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                249079270936248, 1501514259790706, 947909724204848,
++                944551802437487, 552658763982480
++#else
++                24579768, 3711570, 1342322, 22374306, 40103728, 14124955,
++                44564335, 14074918, 21964432, 8235257
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                2089966982947227, 1854140343916181, 2151980759220007,
++                2139781292261749, 158070445864917
++#else
++                60580251, 31142934, 9442965, 27628844, 12025639, 32067012,
++                64127349, 31885225, 13006805, 2355433
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1338766321464554, 1906702607371284, 1519569445519894,
++                115384726262267, 1393058953390992
++#else
++                50803946, 19949172, 60476436, 28412082, 16974358, 22643349,
++                27202043, 1719366, 1141648, 20758196
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1364621558265400, 1512388234908357, 1926731583198686,
++                2041482526432505, 920401122333774
++#else
++                54244920, 20334445, 58790597, 22536340, 60298718, 28710537,
++                13475065, 30420460, 32674894, 13715045
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1884844597333588, 601480070269079, 620203503079537,
++                1079527400117915, 1202076693132015
++#else
++                11423316, 28086373, 32344215, 8962751, 24989809, 9241752,
++                53843611, 16086211, 38367983, 17912338
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                840922919763324, 727955812569642, 1303406629750194,
++                522898432152867, 294161410441865
++#else
++                65699196, 12530727, 60740138, 10847386, 19531186, 19422272,
++                55399715, 7791793, 39862921, 4383346
++#endif
++            }},
++        },
++    },
++    {
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                353760790835310, 1598361541848743, 1122905698202299,
++                1922533590158905, 419107700666580
++#else
++                38137966, 5271446, 65842855, 23817442, 54653627, 16732598,
++                62246457, 28647982, 27193556, 6245191
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                359856369838236, 180914355488683, 861726472646627,
++                218807937262986, 575626773232501
++#else
++                51914908, 5362277, 65324971, 2695833, 4960227, 12840725,
++                23061898, 3260492, 22510453, 8577507
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                755467689082474, 909202735047934, 730078068932500,
++                936309075711518, 2007798262842972
++#else
++                54476394, 11257345, 34415870, 13548176, 66387860, 10879010,
++                31168030, 13952092, 37537372, 29918525
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1609384177904073, 362745185608627, 1335318541768201,
++                800965770436248, 547877979267412
++#else
++                3877321, 23981693, 32416691, 5405324, 56104457, 19897796,
++                3759768, 11935320, 5611860, 8164018
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                984339177776787, 815727786505884, 1645154585713747,
++                1659074964378553, 1686601651984156
++#else
++                50833043, 14667796, 15906460, 12155291, 44997715, 24514713,
++                32003001, 24722143, 5773084, 25132323
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1697863093781930, 599794399429786, 1104556219769607,
++                830560774794755, 12812858601017
++#else
++                43320746, 25300131, 1950874, 8937633, 18686727, 16459170,
++                66203139, 12376319, 31632953, 190926
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1168737550514982, 897832437380552, 463140296333799,
++                302564600022547, 2008360505135501
++#else
++                42515238, 17415546, 58684872, 13378745, 14162407, 6901328,
++                58820115, 4508563, 41767309, 29926903
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1856930662813910, 678090852002597, 1920179140755167,
++                1259527833759868, 55540971895511
++#else
++                8884438, 27670423, 6023973, 10104341, 60227295, 28612898,
++                18722940, 18768427, 65436375, 827624
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1158643631044921, 476554103621892, 178447851439725,
++                1305025542653569, 103433927680625
++#else
++                34388281, 17265135, 34605316, 7101209, 13354605, 2659080,
++                65308289, 19446395, 42230385, 1541285
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                2176793111709008, 1576725716350391, 2009350167273523,
++                2012390194631546, 2125297410909580
++#else
++                2901328, 32436745, 3880375, 23495044, 49487923, 29941650,
++                45306746, 29986950, 20456844, 31669399
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                825403285195098, 2144208587560784, 1925552004644643,
++                1915177840006985, 1015952128947864
++#else
++                27019610, 12299467, 53450576, 31951197, 54247203, 28692960,
++                47568713, 28538373, 29439640, 15138866
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1807108316634472, 1534392066433717, 347342975407218,
++                1153820745616376, 7375003497471
++#else
++                21536104, 26928012, 34661045, 22864223, 44700786, 5175813,
++                61688824, 17193268, 7779327, 109896
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                983061001799725, 431211889901241, 2201903782961093,
++                817393911064341, 2214616493042167
++#else
++                30279725, 14648750, 59063993, 6425557, 13639621, 32810923,
++                28698389, 12180118, 23177719, 33000357
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                228567918409756, 865093958780220, 358083886450556,
++                159617889659320, 1360637926292598
++#else
++                26572828, 3405927, 35407164, 12890904, 47843196, 5335865,
++                60615096, 2378491, 4439158, 20275085
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                234147501399755, 2229469128637390, 2175289352258889,
++                1397401514549353, 1885288963089922
++#else
++                44392139, 3489069, 57883598, 33221678, 18875721, 32414337,
++                14819433, 20822905, 49391106, 28092994
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1111762412951562, 252849572507389, 1048714233823341,
++                146111095601446, 1237505378776770
++#else
++                62052362, 16566550, 15953661, 3767752, 56672365, 15627059,
++                66287910, 2177224, 8550082, 18440267
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1113790697840279, 1051167139966244, 1045930658550944,
++                2011366241542643, 1686166824620755
++#else
++                48635543, 16596774, 66727204, 15663610, 22860960, 15585581,
++                39264755, 29971692, 43848403, 25125843
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1054097349305049, 1872495070333352, 182121071220717,
++                1064378906787311, 100273572924182
++#else
++                34628313, 15707274, 58902952, 27902350, 29464557, 2713815,
++                44383727, 15860481, 45206294, 1494192
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1306410853171605, 1627717417672447, 50983221088417,
++                1109249951172250, 870201789081392
++#else
++                47546773, 19467038, 41524991, 24254879, 13127841, 759709,
++                21923482, 16529112, 8742704, 12967017
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                104233794644221, 1548919791188248, 2224541913267306,
++                2054909377116478, 1043803389015153
++#else
++                38643965, 1553204, 32536856, 23080703, 42417258, 33148257,
++                58194238, 30620535, 37205105, 15553882
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                216762189468802, 707284285441622, 190678557969733,
++                973969342604308, 1403009538434867
++#else
++                21877890, 3230008, 9881174, 10539357, 62311749, 2841331,
++                11543572, 14513274, 19375923, 20906471
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1279024291038477, 344776835218310, 273722096017199,
++                1834200436811442, 634517197663804
++#else
++                8832269, 19058947, 13253510, 5137575, 5037871, 4078777,
++                24880818, 27331716, 2862652, 9455043
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                343805853118335, 1302216857414201, 566872543223541,
++                2051138939539004, 321428858384280
++#else
++                29306751, 5123106, 20245049, 19404543, 9592565, 8447059,
++                65031740, 30564351, 15511448, 4789663
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                470067171324852, 1618629234173951, 2000092177515639,
++                7307679772789, 1117521120249968
++#else
++                46429108, 7004546, 8824831, 24119455, 63063159, 29803695,
++                61354101, 108892, 23513200, 16652362
++#endif
++            }},
++        },
++    },
++    {
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                278151578291475, 1810282338562947, 1771599529530998,
++                1383659409671631, 685373414471841
++#else
++                33852691, 4144781, 62632835, 26975308, 10770038, 26398890,
++                60458447, 20618131, 48789665, 10212859
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                577009397403102, 1791440261786291, 2177643735971638,
++                174546149911960, 1412505077782326
++#else
++                2756062, 8598110, 7383731, 26694540, 22312758, 32449420,
++                21179800, 2600940, 57120566, 21047965
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                893719721537457, 1201282458018197, 1522349501711173,
++                58011597740583, 1130406465887139
++#else
++                42463153, 13317461, 36659605, 17900503, 21365573, 22684775,
++                11344423, 864440, 64609187, 16844368
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                412607348255453, 1280455764199780, 2233277987330768,
++                14180080401665, 331584698417165
++#else
++                40676061, 6148328, 49924452, 19080277, 18782928, 33278435,
++                44547329, 211299, 2719757, 4940997
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                262483770854550, 990511055108216, 526885552771698,
++                571664396646158, 354086190278723
++#else
++                65784982, 3911312, 60160120, 14759764, 37081714, 7851206,
++                21690126, 8518463, 26699843, 5276295
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1820352417585487, 24495617171480, 1547899057533253,
++                10041836186225, 480457105094042
++#else
++                53958991, 27125364, 9396248, 365013, 24703301, 23065493,
++                1321585, 149635, 51656090, 7159368
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                2023310314989233, 637905337525881, 2106474638900687,
++                557820711084072, 1687858215057826
++#else
++                9987761, 30149673, 17507961, 9505530, 9731535, 31388918,
++                22356008, 8312176, 22477218, 25151047
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1144168702609745, 604444390410187, 1544541121756138,
++                1925315550126027, 626401428894002
++#else
++                18155857, 17049442, 19744715, 9006923, 15154154, 23015456,
++                24256459, 28689437, 44560690, 9334108
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1922168257351784, 2018674099908659, 1776454117494445,
++                956539191509034, 36031129147635
++#else
++                2986088, 28642539, 10776627, 30080588, 10620589, 26471229,
++                45695018, 14253544, 44521715, 536905
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                544644538748041, 1039872944430374, 876750409130610,
++                710657711326551, 1216952687484972
++#else
++                4377737, 8115836, 24567078, 15495314, 11625074, 13064599,
++                7390551, 10589625, 10838060, 18134008
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                58242421545916, 2035812695641843, 2118491866122923,
++                1191684463816273, 46921517454099
++#else
++                47766460, 867879, 9277171, 30335973, 52677291, 31567988,
++                19295825, 17757482, 6378259, 699185
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                272268252444639, 1374166457774292, 2230115177009552,
++                1053149803909880, 1354288411641016
++#else
++                7895007, 4057113, 60027092, 20476675, 49222032, 33231305,
++                66392824, 15693154, 62063800, 20180469
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1857910905368338, 1754729879288912, 885945464109877,
++                1516096106802166, 1602902393369811
++#else
++                59371282, 27685029, 52542544, 26147512, 11385653, 13201616,
++                31730678, 22591592, 63190227, 23885106
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1193437069800958, 901107149704790, 999672920611411,
++                477584824802207, 364239578697845
++#else
++                10188286, 17783598, 59772502, 13427542, 22223443, 14896287,
++                30743455, 7116568, 45322357, 5427592
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                886299989548838, 1538292895758047, 1590564179491896,
++                1944527126709657, 837344427345298
++#else
++                696102, 13206899, 27047647, 22922350, 15285304, 23701253,
++                10798489, 28975712, 19236242, 12477404
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                754558365378305, 1712186480903618, 1703656826337531,
++                750310918489786, 518996040250900
++#else
++                55879425, 11243795, 50054594, 25513566, 66320635, 25386464,
++                63211194, 11180503, 43939348, 7733643
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1309847803895382, 1462151862813074, 211370866671570,
++                1544595152703681, 1027691798954090
++#else
++                17800790, 19518253, 40108434, 21787760, 23887826, 3149671,
++                23466177, 23016261, 10322026, 15313801
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                803217563745370, 1884799722343599, 1357706345069218,
++                2244955901722095, 730869460037413
++#else
++                26246234, 11968874, 32263343, 28085704, 6830754, 20231401,
++                51314159, 33452449, 42659621, 10890803
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                689299471295966, 1831210565161071, 1375187341585438,
++                1106284977546171, 1893781834054269
++#else
++                35743198, 10271362, 54448239, 27287163, 16690206, 20491888,
++                52126651, 16484930, 25180797, 28219548
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                696351368613042, 1494385251239250, 738037133616932,
++                636385507851544, 927483222611406
++#else
++                66522290, 10376443, 34522450, 22268075, 19801892, 10997610,
++                2276632, 9482883, 316878, 13820577
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1949114198209333, 1104419699537997, 783495707664463,
++                1747473107602770, 2002634765788641
++#else
++                57226037, 29044064, 64993357, 16457135, 56008783, 11674995,
++                30756178, 26039378, 30696929, 29841583
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1607325776830197, 530883941415333, 1451089452727895,
++                1581691157083423, 496100432831154
++#else
++                32988917, 23951020, 12499365, 7910787, 56491607, 21622917,
++                59766047, 23569034, 34759346, 7392472
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1068900648804224, 2006891997072550, 1134049269345549,
++                1638760646180091, 2055396084625778
++#else
++                58253184, 15927860, 9866406, 29905021, 64711949, 16898650,
++                36699387, 24419436, 25112946, 30627788
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                2222475519314561, 1870703901472013, 1884051508440561,
++                1344072275216753, 1318025677799069
++#else
++                64604801, 33117465, 25621773, 27875660, 15085041, 28074555,
++                42223985, 20028237, 5537437, 19640113
++#endif
++            }},
++        },
++    },
++    {
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                155711679280656, 681100400509288, 389811735211209,
++                2135723811340709, 408733211204125
++#else
++                55883280, 2320284, 57524584, 10149186, 33664201, 5808647,
++                52232613, 31824764, 31234589, 6090599
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                7813206966729, 194444201427550, 2071405409526507,
++                1065605076176312, 1645486789731291
++#else
++                57475529, 116425, 26083934, 2897444, 60744427, 30866345, 609720,
++                15878753, 60138459, 24519663
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                16625790644959, 1647648827778410, 1579910185572704,
++                436452271048548, 121070048451050
++#else
++                39351007, 247743, 51914090, 24551880, 23288160, 23542496,
++                43239268, 6503645, 20650474, 1804084
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1037263028552531, 568385780377829, 297953104144430,
++                1558584511931211, 2238221839292471
++#else
++                39519059, 15456423, 8972517, 8469608, 15640622, 4439847,
++                3121995, 23224719, 27842615, 33352104
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                190565267697443, 672855706028058, 338796554369226,
++                337687268493904, 853246848691734
++#else
++                51801891, 2839643, 22530074, 10026331, 4602058, 5048462,
++                28248656, 5031932, 55733782, 12714368
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1763863028400139, 766498079432444, 1321118624818005,
++                69494294452268, 858786744165651
++#else
++                20807691, 26283607, 29286140, 11421711, 39232341, 19686201,
++                45881388, 1035545, 47375635, 12796919
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1292056768563024, 1456632109855638, 1100631247050184,
++                1386133165675321, 1232898350193752
++#else
++                12076880, 19253146, 58323862, 21705509, 42096072, 16400683,
++                49517369, 20654993, 3480664, 18371617
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                366253102478259, 525676242508811, 1449610995265438,
++                1183300845322183, 185960306491545
++#else
++                34747315, 5457596, 28548107, 7833186, 7303070, 21600887,
++                42745799, 17632556, 33734809, 2771024
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                28315355815982, 460422265558930, 1799675876678724,
++                1969256312504498, 1051823843138725
++#else
++                45719598, 421931, 26597266, 6860826, 22486084, 26817260,
++                49971378, 29344205, 42556581, 15673396
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                156914999361983, 1606148405719949, 1665208410108430,
++                317643278692271, 1383783705665320
++#else
++                46924223, 2338215, 19788685, 23933476, 63107598, 24813538,
++                46837679, 4733253, 3727144, 20619984
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                54684536365732, 2210010038536222, 1194984798155308,
++                535239027773705, 1516355079301361
++#else
++                6120100, 814863, 55314462, 32931715, 6812204, 17806661, 2019593,
++                7975683, 31123697, 22595451
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1484387703771650, 198537510937949, 2186282186359116,
++                617687444857508, 647477376402122
++#else
++                30069250, 22119100, 30434653, 2958439, 18399564, 32578143,
++                12296868, 9204260, 50676426, 9648164
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                2147715541830533, 500032538445817, 646380016884826,
++                352227855331122, 1488268620408052
++#else
++                32705413, 32003455, 30705657, 7451065, 55303258, 9631812,
++                3305266, 5248604, 41100532, 22176930
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                159386186465542, 1877626593362941, 618737197060512,
++                1026674284330807, 1158121760792685
++#else
++                17219846, 2375039, 35537917, 27978816, 47649184, 9219902,
++                294711, 15298639, 2662509, 17257359
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1744544377739822, 1964054180355661, 1685781755873170,
++                2169740670377448, 1286112621104591
++#else
++                65935918, 25995736, 62742093, 29266687, 45762450, 25120105,
++                32087528, 32331655, 32247247, 19164571
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                81977249784993, 1667943117713086, 1668983819634866,
++                1605016835177615, 1353960708075544
++#else
++                14312609, 1221556, 17395390, 24854289, 62163122, 24869796,
++                38911119, 23916614, 51081240, 20175586
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1602253788689063, 439542044889886, 2220348297664483,
++                657877410752869, 157451572512238
++#else
++                65680039, 23875441, 57873182, 6549686, 59725795, 33085767,
++                23046501, 9803137, 17597934, 2346211
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1029287186166717, 65860128430192, 525298368814832,
++                1491902500801986, 1461064796385400
++#else
++                18510781, 15337574, 26171504, 981392, 44867312, 7827555,
++                43617730, 22231079, 3059832, 21771562
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                408216988729246, 2121095722306989, 913562102267595,
++                1879708920318308, 241061448436731
++#else
++                10141598, 6082907, 17829293, 31606789, 9830091, 13613136,
++                41552228, 28009845, 33606651, 3592095
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1185483484383269, 1356339572588553, 584932367316448,
++                102132779946470, 1792922621116791
++#else
++                33114149, 17665080, 40583177, 20211034, 33076704, 8716171,
++                1151462, 1521897, 66126199, 26716628
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1966196870701923, 2230044620318636, 1425982460745905,
++                261167817826569, 46517743394330
++#else
++                34169699, 29298616, 23947180, 33230254, 34035889, 21248794,
++                50471177, 3891703, 26353178, 693168
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                107077591595359, 884959942172345, 27306869797400,
++                2224911448949390, 964352058245223
++#else
++                30374239, 1595580, 50224825, 13186930, 4600344, 406904, 9585294,
++                33153764, 31375463, 14369965
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1730194207717538, 431790042319772, 1831515233279467,
++                1372080552768581, 1074513929381760
++#else
++                52738210, 25781902, 1510300, 6434173, 48324075, 27291703,
++                32732229, 20445593, 17901440, 16011505
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1450880638731607, 1019861580989005, 1229729455116861,
++                1174945729836143, 826083146840706
++#else
++                18171223, 21619806, 54608461, 15197121, 56070717, 18324396,
++                47936623, 17508055, 8764034, 12309598
++#endif
++            }},
++        },
++    },
++    {
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1899935429242705, 1602068751520477, 940583196550370,
++                82431069053859, 1540863155745696
++#else
++                5975889, 28311244, 47649501, 23872684, 55567586, 14015781,
++                43443107, 1228318, 17544096, 22960650
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                2136688454840028, 2099509000964294, 1690800495246475,
++                1217643678575476, 828720645084218
++#else
++                5811932, 31839139, 3442886, 31285122, 48741515, 25194890,
++                49064820, 18144304, 61543482, 12348899
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                765548025667841, 462473984016099, 998061409979798,
++                546353034089527, 2212508972466858
++#else
++                35709185, 11407554, 25755363, 6891399, 63851926, 14872273,
++                42259511, 8141294, 56476330, 32968952
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                46575283771160, 892570971573071, 1281983193144090,
++                1491520128287375, 75847005908304
++#else
++                54433560, 694025, 62032719, 13300343, 14015258, 19103038,
++                57410191, 22225381, 30944592, 1130208
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1801436127943107, 1734436817907890, 1268728090345068,
++                167003097070711, 2233597765834956
++#else
++                8247747, 26843490, 40546482, 25845122, 52706924, 18905521,
++                4652151, 2488540, 23550156, 33283200
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1997562060465113, 1048700225534011, 7615603985628,
++                1855310849546841, 2242557647635213
++#else
++                17294297, 29765994, 7026747, 15626851, 22990044, 113481,
++                2267737, 27646286, 66700045, 33416712
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1161017320376250, 492624580169043, 2169815802355237,
++                976496781732542, 1770879511019629
++#else
++                16091066, 17300506, 18599251, 7340678, 2137637, 32332775,
++                63744702, 14550935, 3260525, 26388161
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1357044908364776, 729130645262438, 1762469072918979,
++                1365633616878458, 181282906404941
++#else
++                62198760, 20221544, 18550886, 10864893, 50649539, 26262835,
++                44079994, 20349526, 54360141, 2701325
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1080413443139865, 1155205815510486, 1848782073549786,
++                622566975152580, 124965574467971
++#else
++                58534169, 16099414, 4629974, 17213908, 46322650, 27548999,
++                57090500, 9276970, 11329923, 1862132
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1184526762066993, 247622751762817, 692129017206356,
++                820018689412496, 2188697339828085
++#else
++                14763057, 17650824, 36190593, 3689866, 3511892, 10313526,
++                45157776, 12219230, 58070901, 32614131
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                2020536369003019, 202261491735136, 1053169669150884,
++                2056531979272544, 778165514694311
++#else
++                8894987, 30108338, 6150752, 3013931, 301220, 15693451, 35127648,
++                30644714, 51670695, 11595569
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                237404399610207, 1308324858405118, 1229680749538400,
++                720131409105291, 1958958863624906
++#else
++                15214943, 3537601, 40870142, 19495559, 4418656, 18323671,
++                13947275, 10730794, 53619402, 29190761
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                515583508038846, 17656978857189, 1717918437373989,
++                1568052070792483, 46975803123923
++#else
++                64570558, 7682792, 32759013, 263109, 37124133, 25598979,
++                44776739, 23365796, 977107, 699994
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                281527309158085, 36970532401524, 866906920877543,
++                2222282602952734, 1289598729589882
++#else
++                54642373, 4195083, 57897332, 550903, 51543527, 12917919,
++                19118110, 33114591, 36574330, 19216518
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1278207464902042, 494742455008756, 1262082121427081,
++                1577236621659884, 1888786707293291
++#else
++                31788442, 19046775, 4799988, 7372237, 8808585, 18806489,
++                9408236, 23502657, 12493931, 28145115
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                353042527954210, 1830056151907359, 1111731275799225,
++                174960955838824, 404312815582675
++#else
++                41428258, 5260743, 47873055, 27269961, 63412921, 16566086,
++                27218280, 2607121, 29375955, 6024730
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                2064251142068628, 1666421603389706, 1419271365315441,
++                468767774902855, 191535130366583
++#else
++                842132, 30759739, 62345482, 24831616, 26332017, 21148791,
++                11831879, 6985184, 57168503, 2854095
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1716987058588002, 1859366439773457, 1767194234188234,
++                64476199777924, 1117233614485261
++#else
++                62261602, 25585100, 2516241, 27706719, 9695690, 26333246,
++                16512644, 960770, 12121869, 16648078
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                984292135520292, 135138246951259, 2220652137473167,
++                1722843421165029, 190482558012909
++#else
++                51890212, 14667095, 53772635, 2013716, 30598287, 33090295,
++                35603941, 25672367, 20237805, 2838411
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                298845952651262, 1166086588952562, 1179896526238434,
++                1347812759398693, 1412945390096208
++#else
++                47820798, 4453151, 15298546, 17376044, 22115042, 17581828,
++                12544293, 20083975, 1068880, 21054527
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1143239552672925, 906436640714209, 2177000572812152,
++                2075299936108548, 325186347798433
++#else
++                57549981, 17035596, 33238497, 13506958, 30505848, 32439836,
++                58621956, 30924378, 12521377, 4845654
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                721024854374772, 684487861263316, 1373438744094159,
++                2193186935276995, 1387043709851261
++#else
++                38910324, 10744107, 64150484, 10199663, 7759311, 20465832,
++                3409347, 32681032, 60626557, 20668561
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                418098668140962, 715065997721283, 1471916138376055,
++                2168570337288357, 937812682637044
++#else
++                43547042, 6230155, 46726851, 10655313, 43068279, 21933259,
++                10477733, 32314216, 63995636, 13974497
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1043584187226485, 2143395746619356, 2209558562919611,
++                482427979307092, 847556718384018
++#else
++                12966261, 15550616, 35069916, 31939085, 21025979, 32924988,
++                5642324, 7188737, 18895762, 12629579
++#endif
++            }},
++        },
++    },
++    {
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1248731221520759, 1465200936117687, 540803492710140,
++                52978634680892, 261434490176109
++#else
++                14741879, 18607545, 22177207, 21833195, 1279740, 8058600,
++                11758140, 789443, 32195181, 3895677
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1057329623869501, 620334067429122, 461700859268034,
++                2012481616501857, 297268569108938
++#else
++                10758205, 15755439, 62598914, 9243697, 62229442, 6879878,
++                64904289, 29988312, 58126794, 4429646
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1055352180870759, 1553151421852298, 1510903185371259,
++                1470458349428097, 1226259419062731
++#else
++                64654951, 15725972, 46672522, 23143759, 61304955, 22514211,
++                59972993, 21911536, 18047435, 18272689
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1492988790301668, 790326625573331, 1190107028409745,
++                1389394752159193, 1620408196604194
++#else
++                41935844, 22247266, 29759955, 11776784, 44846481, 17733976,
++                10993113, 20703595, 49488162, 24145963
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                47000654413729, 1004754424173864, 1868044813557703,
++                173236934059409, 588771199737015
++#else
++                21987233, 700364, 42603816, 14972007, 59334599, 27836036,
++                32155025, 2581431, 37149879, 8773374
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                30498470091663, 1082245510489825, 576771653181956,
++                806509986132686, 1317634017056939
++#else
++                41540495, 454462, 53896929, 16126714, 25240068, 8594567,
++                20656846, 12017935, 59234475, 19634276
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                420308055751555, 1493354863316002, 165206721528088,
++                1884845694919786, 2065456951573059
++#else
++                6028163, 6263078, 36097058, 22252721, 66289944, 2461771,
++                35267690, 28086389, 65387075, 30777706
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1115636332012334, 1854340990964155, 83792697369514,
++                1972177451994021, 457455116057587
++#else
++                54829870, 16624276, 987579, 27631834, 32908202, 1248608,
++                7719845, 29387734, 28408819, 6816612
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1698968457310898, 1435137169051090, 1083661677032510,
++                938363267483709, 340103887207182
++#else
++                56750770, 25316602, 19549650, 21385210, 22082622, 16147817,
++                20613181, 13982702, 56769294, 5067942
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1995325341336574, 911500251774648, 164010755403692,
++                855378419194762, 1573601397528842
++#else
++                36602878, 29732664, 12074680, 13582412, 47230892, 2443950,
++                47389578, 12746131, 5331210, 23448488
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                241719380661528, 310028521317150, 1215881323380194,
++                1408214976493624, 2141142156467363
++#else
++                30528792, 3601899, 65151774, 4619784, 39747042, 18118043,
++                24180792, 20984038, 27679907, 31905504
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1315157046163473, 727368447885818, 1363466668108618,
++                1668921439990361, 1398483384337907
++#else
++                9402385, 19597367, 32834042, 10838634, 40528714, 20317236,
++                26653273, 24868867, 22611443, 20839026
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                75029678299646, 1015388206460473, 1849729037055212,
++                1939814616452984, 444404230394954
++#else
++                22190590, 1118029, 22736441, 15130463, 36648172, 27563110,
++                19189624, 28905490, 4854858, 6622139
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                2053597130993710, 2024431685856332, 2233550957004860,
++                2012407275509545, 872546993104440
++#else
++                58798126, 30600981, 58846284, 30166382, 56707132, 33282502,
++                13424425, 29987205, 26404408, 13001963
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1217269667678610, 599909351968693, 1390077048548598,
++                1471879360694802, 739586172317596
++#else
++                35867026, 18138731, 64114613, 8939345, 11562230, 20713762,
++                41044498, 21932711, 51703708, 11020692
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1718318639380794, 1560510726633958, 904462881159922,
++                1418028351780052, 94404349451937
++#else
++                1866042, 25604943, 59210214, 23253421, 12483314, 13477547,
++                3175636, 21130269, 28761761, 1406734
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                2132502667405250, 214379346175414, 1502748313768060,
++                1960071701057800, 1353971822643138
++#else
++                66660290, 31776765, 13018550, 3194501, 57528444, 22392694,
++                24760584, 29207344, 25577410, 20175752
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                319394212043702, 2127459436033571, 717646691535162,
++                663366796076914, 318459064945314
++#else
++                42818486, 4759344, 66418211, 31701615, 2066746, 10693769,
++                37513074, 9884935, 57739938, 4745409
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                405989424923593, 1960452633787083, 667349034401665,
++                1492674260767112, 1451061489880787
++#else
++                57967561, 6049713, 47577803, 29213020, 35848065, 9944275,
++                51646856, 22242579, 10931923, 21622501
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                947085906234007, 323284730494107, 1485778563977200,
++                728576821512394, 901584347702286
++#else
++                50547351, 14112679, 59096219, 4817317, 59068400, 22139825,
++                44255434, 10856640, 46638094, 13434653
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1575783124125742, 2126210792434375, 1569430791264065,
++                1402582372904727, 1891780248341114
++#else
++                22759470, 23480998, 50342599, 31683009, 13637441, 23386341,
++                1765143, 20900106, 28445306, 28189722
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                838432205560695, 1997703511451664, 1018791879907867,
++                1662001808174331, 78328132957753
++#else
++                29875063, 12493613, 2795536, 29768102, 1710619, 15181182,
++                56913147, 24765756, 9074233, 1167180
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                739152638255629, 2074935399403557, 505483666745895,
++                1611883356514088, 628654635394878
++#else
++                40903181, 11014232, 57266213, 30918946, 40200743, 7532293,
++                48391976, 24018933, 3843902, 9367684
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1822054032121349, 643057948186973, 7306757352712,
++                577249257962099, 284735863382083
++#else
++                56139269, 27150720, 9591133, 9582310, 11349256, 108879,
++                16235123, 8601684, 66969667, 4242894
++#endif
++            }},
++        },
++    },
++    {
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1366558556363930, 1448606567552086, 1478881020944768,
++                165803179355898, 1115718458123498
++#else
++                22092954, 20363309, 65066070, 21585919, 32186752, 22037044,
++                60534522, 2470659, 39691498, 16625500
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                204146226972102, 1630511199034723, 2215235214174763,
++                174665910283542, 956127674017216
++#else
++                56051142, 3042015, 13770083, 24296510, 584235, 33009577,
++                59338006, 2602724, 39757248, 14247412
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1562934578796716, 1070893489712745, 11324610642270,
++                958989751581897, 2172552325473805
++#else
++                6314156, 23289540, 34336361, 15957556, 56951134, 168749,
++                58490057, 14290060, 27108877, 32373552
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1770564423056027, 735523631664565, 1326060113795289,
++                1509650369341127, 65892421582684
++#else
++                58522267, 26383465, 13241781, 10960156, 34117849, 19759835,
++                33547975, 22495543, 39960412, 981873
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                623682558650637, 1337866509471512, 990313350206649,
++                1314236615762469, 1164772974270275
++#else
++                22833421, 9293594, 34459416, 19935764, 57971897, 14756818,
++                44180005, 19583651, 56629059, 17356469
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                223256821462517, 723690150104139, 1000261663630601,
++                933280913953265, 254872671543046
++#else
++                59340277, 3326785, 38997067, 10783823, 19178761, 14905060,
++                22680049, 13906969, 51175174, 3797898
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1969087237026041, 624795725447124, 1335555107635969,
++                2069986355593023, 1712100149341902
++#else
++                21721337, 29341686, 54902740, 9310181, 63226625, 19901321,
++                23740223, 30845200, 20491982, 25512280
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1236103475266979, 1837885883267218, 1026072585230455,
++                1025865513954973, 1801964901432134
++#else
++                9209251, 18419377, 53852306, 27386633, 66377847, 15289672,
++                25947805, 15286587, 30997318, 26851369
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1115241013365517, 1712251818829143, 2148864332502771,
++                2096001471438138, 2235017246626125
++#else
++                7392013, 16618386, 23946583, 25514540, 53843699, 32020573,
++                52911418, 31232855, 17649997, 33304352
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1299268198601632, 2047148477845621, 2165648650132450,
++                1612539282026145, 514197911628890
++#else
++                57807776, 19360604, 30609525, 30504889, 41933794, 32270679,
++                51867297, 24028707, 64875610, 7662145
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                118352772338543, 1067608711804704, 1434796676193498,
++                1683240170548391, 230866769907437
++#else
++                49550191, 1763593, 33994528, 15908609, 37067994, 21380136,
++                7335079, 25082233, 63934189, 3440182
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1850689576796636, 1601590730430274, 1139674615958142,
++                1954384401440257, 76039205311
++#else
++                47219164, 27577423, 42997570, 23865561, 10799742, 16982475,
++                40449, 29122597, 4862399, 1133
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1723387471374172, 997301467038410, 533927635123657,
++                20928644693965, 1756575222802513
++#else
++                34252636, 25680474, 61686474, 14860949, 50789833, 7956141,
++                7258061, 311861, 36513873, 26175010
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                2146711623855116, 503278928021499, 625853062251406,
++                1109121378393107, 1033853809911861
++#else
++                63335436, 31988495, 28985339, 7499440, 24445838, 9325937,
++                29727763, 16527196, 18278453, 15405622
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                571005965509422, 2005213373292546, 1016697270349626,
++                56607856974274, 914438579435146
++#else
++                62726958, 8508651, 47210498, 29880007, 61124410, 15149969,
++                53795266, 843522, 45233802, 13626196
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1346698876211176, 2076651707527589, 1084761571110205,
++                265334478828406, 1068954492309671
++#else
++                2281448, 20067377, 56193445, 30944521, 1879357, 16164207,
++                56324982, 3953791, 13340839, 15928663
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1769967932677654, 1695893319756416, 1151863389675920,
++                1781042784397689, 400287774418285
++#else
++                31727126, 26374577, 48671360, 25270779, 2875792, 17164102,
++                41838969, 26539605, 43656557, 5964752
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1851867764003121, 403841933237558, 820549523771987,
++                761292590207581, 1743735048551143
++#else
++                4100401, 27594980, 49929526, 6017713, 48403027, 12227140,
++                40424029, 11344143, 2538215, 25983677
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                410915148140008, 2107072311871739, 1004367461876503,
++                99684895396761, 1180818713503224
++#else
++                57675240, 6123112, 11159803, 31397824, 30016279, 14966241,
++                46633881, 1485420, 66479608, 17595569
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                285945406881439, 648174397347453, 1098403762631981,
++                1366547441102991, 1505876883139217
++#else
++                40304287, 4260918, 11851389, 9658551, 35091757, 16367491,
++                46903439, 20363143, 11659921, 22439314
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                672095903120153, 1675918957959872, 636236529315028,
++                1569297300327696, 2164144194785875
++#else
++                26180377, 10015009, 36264640, 24973138, 5418196, 9480663,
++                2231568, 23384352, 33100371, 32248261
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1902708175321798, 1035343530915438, 1178560808893263,
++                301095684058146, 1280977479761118
++#else
++                15121094, 28352561, 56718958, 15427820, 39598927, 17561924,
++                21670946, 4486675, 61177054, 19088051
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1615357281742403, 404257611616381, 2160201349780978,
++                1160947379188955, 1578038619549541
++#else
++                16166467, 24070699, 56004733, 6023907, 35182066, 32189508,
++                2340059, 17299464, 56373093, 23514607
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                2013087639791217, 822734930507457, 1785668418619014,
++                1668650702946164, 389450875221715
++#else
++                28042865, 29997343, 54982337, 12259705, 63391366, 26608532,
++                6766452, 24864833, 18036435, 5803270
++#endif
++            }},
++        },
++    },
++    {
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                453918449698368, 106406819929001, 2072540975937135,
++                308588860670238, 1304394580755385
++#else
++                66291264, 6763911, 11803561, 1585585, 10958447, 30883267,
++                23855390, 4598332, 60949433, 19436993
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1295082798350326, 2091844511495996, 1851348972587817,
++                3375039684596, 789440738712837
++#else
++                36077558, 19298237, 17332028, 31170912, 31312681, 27587249,
++                696308, 50292, 47013125, 11763583
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                2083069137186154, 848523102004566, 993982213589257,
++                1405313299916317, 1532824818698468
++#else
++                66514282, 31040148, 34874710, 12643979, 12650761, 14811489,
++                665117, 20940800, 47335652, 22840869
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1495961298852430, 1397203457344779, 1774950217066942,
++                139302743555696, 66603584342787
++#else
++                30464590, 22291560, 62981387, 20819953, 19835326, 26448819,
++                42712688, 2075772, 50088707, 992470
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1782411379088302, 1096724939964781, 27593390721418,
++                542241850291353, 1540337798439873
++#else
++                18357166, 26559999, 7766381, 16342475, 37783946, 411173,
++                14578841, 8080033, 55534529, 22952821
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                693543956581437, 171507720360750, 1557908942697227,
++                1074697073443438, 1104093109037196
++#else
++                19598397, 10334610, 12555054, 2555664, 18821899, 23214652,
++                21873262, 16014234, 26224780, 16452269
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                345288228393419, 1099643569747172, 134881908403743,
++                1740551994106740, 248212179299770
++#else
++                36884939, 5145195, 5944548, 16385966, 3976735, 2009897,
++                55731060, 25936245, 46575034, 3698649
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                231429562203065, 1526290236421172, 2021375064026423,
++                1520954495658041, 806337791525116
++#else
++                14187449, 3448569, 56472628, 22743496, 44444983, 30120835,
++                7268409, 22663988, 27394300, 12015369
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1079623667189886, 872403650198613, 766894200588288,
++                2163700860774109, 2023464507911816
++#else
++                19695742, 16087646, 28032085, 12999827, 6817792, 11427614,
++                20244189, 32241655, 53849736, 30151970
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                854645372543796, 1936406001954827, 151460662541253,
++                825325739271555, 1554306377287556
++#else
++                30860084, 12735208, 65220619, 28854697, 50133957, 2256939,
++                58942851, 12298311, 58558340, 23160969
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1497138821904622, 1044820250515590, 1742593886423484,
++                1237204112746837, 849047450816987
++#else
++                61389038, 22309106, 65198214, 15569034, 26642876, 25966672,
++                61319509, 18435777, 62132699, 12651792
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                667962773375330, 1897271816877105, 1399712621683474,
++                1143302161683099, 2081798441209593
++#else
++                64260450, 9953420, 11531313, 28271553, 26895122, 20857343,
++                53990043, 17036529, 9768697, 31021214
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                127147851567005, 1936114012888110, 1704424366552046,
++                856674880716312, 716603621335359
++#else
++                42389405, 1894650, 66821166, 28850346, 15348718, 25397902,
++                32767512, 12765450, 4940095, 10678226
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1072409664800960, 2146937497077528, 1508780108920651,
++                935767602384853, 1112800433544068
++#else
++                18860224, 15980149, 48121624, 31991861, 40875851, 22482575,
++                59264981, 13944023, 42736516, 16582018
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                333549023751292, 280219272863308, 2104176666454852,
++                1036466864875785, 536135186520207
++#else
++                51604604, 4970267, 37215820, 4175592, 46115652, 31354675,
++                55404809, 15444559, 56105103, 7989036
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                373666279883137, 146457241530109, 304116267127857,
++                416088749147715, 1258577131183391
++#else
++                31490433, 5568061, 64696061, 2182382, 34772017, 4531685,
++                35030595, 6200205, 47422751, 18754260
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1186115062588401, 2251609796968486, 1098944457878953,
++                1153112761201374, 1791625503417267
++#else
++                49800177, 17674491, 35586086, 33551600, 34221481, 16375548,
++                8680158, 17182719, 28550067, 26697300
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1870078460219737, 2129630962183380, 852283639691142,
++                292865602592851, 401904317342226
++#else
++                38981977, 27866340, 16837844, 31733974, 60258182, 12700015,
++                37068883, 4364037, 1155602, 5988841
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1361070124828035, 815664541425524, 1026798897364671,
++                1951790935390647, 555874891834790
++#else
++                21890435, 20281525, 54484852, 12154348, 59276991, 15300495,
++                23148983, 29083951, 24618406, 8283181
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1546301003424277, 459094500062839, 1097668518375311,
++                1780297770129643, 720763293687608
++#else
++                33972757, 23041680, 9975415, 6841041, 35549071, 16356535,
++                3070187, 26528504, 1466168, 10740210
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1212405311403990, 1536693382542438, 61028431067459,
++                1863929423417129, 1223219538638038
++#else
++                65599446, 18066246, 53605478, 22898515, 32799043, 909394,
++                53169961, 27774712, 34944214, 18227391
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1294303766540260, 1183557465955093, 882271357233093,
++                63854569425375, 2213283684565087
++#else
++                3960804, 19286629, 39082773, 17636380, 47704005, 13146867,
++                15567327, 951507, 63848543, 32980496
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                339050984211414, 601386726509773, 413735232134068,
++                966191255137228, 1839475899458159
++#else
++                24740822, 5052253, 37014733, 8961360, 25877428, 6165135,
++                42740684, 14397371, 59728495, 27410326
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                235605972169408, 2174055643032978, 1538335001838863,
++                1281866796917192, 1815940222628465
++#else
++                38220480, 3510802, 39005586, 32395953, 55870735, 22922977,
++                51667400, 19101303, 65483377, 27059617
++#endif
++            }},
++        },
++    },
++    {
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1632352921721536, 1833328609514701, 2092779091951987,
++                1923956201873226, 2210068022482919
++#else
++                793280, 24323954, 8836301, 27318725, 39747955, 31184838,
++                33152842, 28669181, 57202663, 32932579
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                35271216625062, 1712350667021807, 983664255668860,
++                98571260373038, 1232645608559836
++#else
++                5666214, 525582, 20782575, 25516013, 42570364, 14657739,
++                16099374, 1468826, 60937436, 18367850
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1998172393429622, 1798947921427073, 784387737563581,
++                1589352214827263, 1589861734168180
++#else
++                62249590, 29775088, 64191105, 26806412, 7778749, 11688288,
++                36704511, 23683193, 65549940, 23690785
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1733739258725305, 31715717059538, 201969945218860,
++                992093044556990, 1194308773174556
++#else
++                10896313, 25834728, 824274, 472601, 47648556, 3009586, 25248958,
++                14783338, 36527388, 17796587
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                846415389605137, 746163495539180, 829658752826080,
++                592067705956946, 957242537821393
++#else
++                10566929, 12612572, 35164652, 11118702, 54475488, 12362878,
++                21752402, 8822496, 24003793, 14264025
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1758148849754419, 619249044817679, 168089007997045,
++                1371497636330523, 1867101418880350
++#else
++                27713843, 26198459, 56100623, 9227529, 27050101, 2504721,
++                23886875, 20436907, 13958494, 27821979
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                326633984209635, 261759506071016, 1700682323676193,
++                1577907266349064, 1217647663383016
++#else
++                43627235, 4867225, 39861736, 3900520, 29838369, 25342141,
++                35219464, 23512650, 7340520, 18144364
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1714182387328607, 1477856482074168, 574895689942184,
++                2159118410227270, 1555532449716575
++#else
++                4646495, 25543308, 44342840, 22021777, 23184552, 8566613,
++                31366726, 32173371, 52042079, 23179239
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                853828206885131, 998498946036955, 1835887550391235,
++                207627336608048, 258363815956050
++#else
++                49838347, 12723031, 50115803, 14878793, 21619651, 27356856,
++                27584816, 3093888, 58265170, 3849920
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                141141474651677, 1236728744905256, 643101419899887,
++                1646615130509173, 1208239602291765
++#else
++                58043933, 2103171, 25561640, 18428694, 61869039, 9582957,
++                32477045, 24536477, 5002293, 18004173
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1501663228068911, 1354879465566912, 1444432675498247,
++                897812463852601, 855062598754348
++#else
++                55051311, 22376525, 21115584, 20189277, 8808711, 21523724,
++                16489529, 13378448, 41263148, 12741425
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                714380763546606, 1032824444965790, 1774073483745338,
++                1063840874947367, 1738680636537158
++#else
++                61162478, 10645102, 36197278, 15390283, 63821882, 26435754,
++                24306471, 15852464, 28834118, 25908360
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1640635546696252, 633168953192112, 2212651044092396,
++                30590958583852, 368515260889378
++#else
++                49773116, 24447374, 42577584, 9434952, 58636780, 32971069,
++                54018092, 455840, 20461858, 5491305
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1171650314802029, 1567085444565577, 1453660792008405,
++                757914533009261, 1619511342778196
++#else
++                13669229, 17458950, 54626889, 23351392, 52539093, 21661233,
++                42112877, 11293806, 38520660, 24132599
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                420958967093237, 971103481109486, 2169549185607107,
++                1301191633558497, 1661514101014240
++#else
++                28497909, 6272777, 34085870, 14470569, 8906179, 32328802,
++                18504673, 19389266, 29867744, 24758489
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                907123651818302, 1332556122804146, 1824055253424487,
++                1367614217442959, 1982558335973172
++#else
++                50901822, 13517195, 39309234, 19856633, 24009063, 27180541,
++                60741263, 20379039, 22853428, 29542421
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1121533090144639, 1021251337022187, 110469995947421,
++                1511059774758394, 2110035908131662
++#else
++                24191359, 16712145, 53177067, 15217830, 14542237, 1646131,
++                18603514, 22516545, 12876622, 31441985
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                303213233384524, 2061932261128138, 352862124777736,
++                40828818670255, 249879468482660
++#else
++                17902668, 4518229, 66697162, 30725184, 26878216, 5258055,
++                54248111, 608396, 16031844, 3723494
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                856559257852200, 508517664949010, 1378193767894916,
++                1723459126947129, 1962275756614521
++#else
++                38476072, 12763727, 46662418, 7577503, 33001348, 20536687,
++                17558841, 25681542, 23896953, 29240187
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1445691340537320, 40614383122127, 402104303144865,
++                485134269878232, 1659439323587426
++#else
++                47103464, 21542479, 31520463, 605201, 2543521, 5991821,
++                64163800, 7229063, 57189218, 24727572
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                20057458979482, 1183363722525800, 2140003847237215,
++                2053873950687614, 2112017736174909
++#else
++                28816026, 298879, 38943848, 17633493, 19000927, 31888542,
++                54428030, 30605106, 49057085, 31471516
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                2228654250927986, 1483591363415267, 1368661293910956,
++                1076511285177291, 526650682059608
++#else
++                16000882, 33209536, 3493091, 22107234, 37604268, 20394642,
++                12577739, 16041268, 47393624, 7847706
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                709481497028540, 531682216165724, 316963769431931,
++                1814315888453765, 258560242424104
++#else
++                10151868, 10572098, 27312476, 7922682, 14825339, 4723128,
++                34252933, 27035413, 57088296, 3852847
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1053447823660455, 1955135194248683, 1010900954918985,
++                1182614026976701, 1240051576966610
++#else
++                55678375, 15697595, 45987307, 29133784, 5386313, 15063598,
++                16514493, 17622322, 29330898, 18478208
++#endif
++            }},
++        },
++    },
++    {
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1957943897155497, 1788667368028035, 137692910029106,
++                1039519607062, 826404763313028
++#else
++                41609129, 29175637, 51885955, 26653220, 16615730, 2051784,
++                3303702, 15490, 39560068, 12314390
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1848942433095597, 1582009882530495, 1849292741020143,
++                1068498323302788, 2001402229799484
++#else
++                15683501, 27551389, 18109119, 23573784, 15337967, 27556609,
++                50391428, 15921865, 16103996, 29823217
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1528282417624269, 2142492439828191, 2179662545816034,
++                362568973150328, 1591374675250271
++#else
++                43939021, 22773182, 13588191, 31925625, 63310306, 32479502,
++                47835256, 5402698, 37293151, 23713330
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                160026679434388, 232341189218716, 2149181472355545,
++                598041771119831, 183859001910173
++#else
++                23190676, 2384583, 34394524, 3462153, 37205209, 32025299,
++                55842007, 8911516, 41903005, 2739712
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                2013278155187349, 662660471354454, 793981225706267,
++                411706605985744, 804490933124791
++#else
++                21374101, 30000182, 33584214, 9874410, 15377179, 11831242,
++                33578960, 6134906, 4931255, 11987849
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                2051892037280204, 488391251096321, 2230187337030708,
++                930221970662692, 679002758255210
++#else
++                67101132, 30575573, 50885377, 7277596, 105524, 33232381,
++                35628324, 13861387, 37032554, 10117929
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1530723630438670, 875873929577927, 341560134269988,
++                449903119530753, 1055551308214179
++#else
++                37607694, 22809559, 40945095, 13051538, 41483300, 5089642,
++                60783361, 6704078, 12890019, 15728940
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1461835919309432, 1955256480136428, 180866187813063,
++                1551979252664528, 557743861963950
++#else
++                45136504, 21783052, 66157804, 29135591, 14704839, 2695116,
++                903376, 23126293, 12885166, 8311031
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                359179641731115, 1324915145732949, 902828372691474,
++                294254275669987, 1887036027752957
++#else
++                49592363, 5352193, 10384213, 19742774, 7506450, 13453191,
++                26423267, 4384730, 1888765, 28119028
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                2043271609454323, 2038225437857464, 1317528426475850,
++                1398989128982787, 2027639881006861
++#else
++                41291507, 30447119, 53614264, 30371925, 30896458, 19632703,
++                34857219, 20846562, 47644429, 30214188
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                2072902725256516, 312132452743412, 309930885642209,
++                996244312618453, 1590501300352303
++#else
++                43500868, 30888657, 66582772, 4651135, 5765089, 4618330,
++                6092245, 14845197, 17151279, 23700316
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1397254305160710, 695734355138021, 2233992044438756,
++                1776180593969996, 1085588199351115
++#else
++                42278406, 20820711, 51942885, 10367249, 37577956, 33289075,
++                22825804, 26467153, 50242379, 16176524
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                440567051331029, 254894786356681, 493869224930222,
++                1556322069683366, 1567456540319218
++#else
++                43525589, 6564960, 20063689, 3798228, 62368686, 7359224,
++                2006182, 23191006, 38362610, 23356922
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1950722461391320, 1907845598854797, 1822757481635527,
++                2121567704750244, 73811931471221
++#else
++                56482264, 29068029, 53788301, 28429114, 3432135, 27161203,
++                23632036, 31613822, 32808309, 1099883
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                387139307395758, 2058036430315676, 1220915649965325,
++                1794832055328951, 1230009312169328
++#else
++                15030958, 5768825, 39657628, 30667132, 60681485, 18193060,
++                51830967, 26745081, 2051440, 18328567
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1765973779329517, 659344059446977, 19821901606666,
++                1301928341311214, 1116266004075885
++#else
++                63746541, 26315059, 7517889, 9824992, 23555850, 295369, 5148398,
++                19400244, 44422509, 16633659
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1127572801181483, 1224743760571696, 1276219889847274,
++                1529738721702581, 1589819666871853
++#else
++                4577067, 16802144, 13249840, 18250104, 19958762, 19017158,
++                18559669, 22794883, 8402477, 23690159
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                2181229378964934, 2190885205260020, 1511536077659137,
++                1246504208580490, 668883326494241
++#else
++                38702534, 32502850, 40318708, 32646733, 49896449, 22523642,
++                9453450, 18574360, 17983009, 9967138
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                437866655573314, 669026411194768, 81896997980338,
++                523874406393178, 245052060935236
++#else
++                41346370, 6524721, 26585488, 9969270, 24709298, 1220360,
++                65430874, 7806336, 17507396, 3651560
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1975438052228868, 1071801519999806, 594652299224319,
++                1877697652668809, 1489635366987285
++#else
++                56688388, 29436320, 14584638, 15971087, 51340543, 8861009,
++                26556809, 27979875, 48555541, 22197296
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                958592545673770, 233048016518599, 851568750216589,
++                567703851596087, 1740300006094761
++#else
++                2839082, 14284142, 4029895, 3472686, 14402957, 12689363,
++                40466743, 8459446, 61503401, 25932490
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                2014540178270324, 192672779514432, 213877182641530,
++                2194819933853411, 1716422829364835
++#else
++                62269556, 30018987, 9744960, 2871048, 25113978, 3187018,
++                41998051, 32705365, 17258083, 25576693
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1540769606609725, 2148289943846077, 1597804156127445,
++                1230603716683868, 815423458809453
++#else
++                18164541, 22959256, 49953981, 32012014, 19237077, 23809137,
++                23357532, 18337424, 26908269, 12150756
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1738560251245018, 1779576754536888, 1783765347671392,
++                1880170990446751, 1088225159617541
++#else
++                36843994, 25906566, 5112248, 26517760, 65609056, 26580174,
++                43167, 28016731, 34806789, 16215818
++#endif
++            }},
++        },
++    },
++    {
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                659303913929492, 1956447718227573, 1830568515922666,
++                841069049744408, 1669607124206368
++#else
++                60209940, 9824393, 54804085, 29153342, 35711722, 27277596,
++                32574488, 12532905, 59605792, 24879084
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1143465490433355, 1532194726196059, 1093276745494697,
++                481041706116088, 2121405433561163
++#else
++                39765323, 17038963, 39957339, 22831480, 946345, 16291093,
++                254968, 7168080, 21676107, 31611404
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1686424298744462, 1451806974487153, 266296068846582,
++                1834686947542675, 1720762336132256
++#else
++                21260942, 25129680, 50276977, 21633609, 43430902, 3968120,
++                63456915, 27338965, 63552672, 25641356
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                889217026388959, 1043290623284660, 856125087551909,
++                1669272323124636, 1603340330827879
++#else
++                16544735, 13250366, 50304436, 15546241, 62525861, 12757257,
++                64646556, 24874095, 48201831, 23891632
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1206396181488998, 333158148435054, 1402633492821422,
++                1120091191722026, 1945474114550509
++#else
++                64693606, 17976703, 18312302, 4964443, 51836334, 20900867,
++                26820650, 16690659, 25459437, 28989823
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                766720088232571, 1512222781191002, 1189719893490790,
++                2091302129467914, 2141418006894941
++#else
++                41964155, 11425019, 28423002, 22533875, 60963942, 17728207,
++                9142794, 31162830, 60676445, 31909614
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                419663647306612, 1998875112167987, 1426599870253707,
++                1154928355379510, 486538532138187
++#else
++                44004212, 6253475, 16964147, 29785560, 41994891, 21257994,
++                39651638, 17209773, 6335691, 7249989
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                938160078005954, 1421776319053174, 1941643234741774,
++                180002183320818, 1414380336750546
++#else
++                36775618, 13979674, 7503222, 21186118, 55152142, 28932738,
++                36836594, 2682241, 25993170, 21075909
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                398001940109652, 1577721237663248, 1012748649830402,
++                1540516006905144, 1011684812884559
++#else
++                4364628, 5930691, 32304656, 23509878, 59054082, 15091130,
++                22857016, 22955477, 31820367, 15075278
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1653276489969630, 6081825167624, 1921777941170836,
++                1604139841794531, 861211053640641
++#else
++                31879134, 24635739, 17258760, 90626, 59067028, 28636722,
++                24162787, 23903546, 49138625, 12833044
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                996661541407379, 1455877387952927, 744312806857277,
++                139213896196746, 1000282908547789
++#else
++                19073683, 14851414, 42705695, 21694263, 7625277, 11091125,
++                47489674, 2074448, 57694925, 14905376
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1450817495603008, 1476865707053229, 1030490562252053,
++                620966950353376, 1744760161539058
++#else
++                24483648, 21618865, 64589997, 22007013, 65555733, 15355505,
++                41826784, 9253128, 27628530, 25998952
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                559728410002599, 37056661641185, 2038622963352006,
++                1637244893271723, 1026565352238948
++#else
++                17597607, 8340603, 19355617, 552187, 26198470, 30377849,
++                4593323, 24396850, 52997988, 15297015
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                962165956135846, 1116599660248791, 182090178006815,
++                1455605467021751, 196053588803284
++#else
++                510886, 14337390, 35323607, 16638631, 6328095, 2713355,
++                46891447, 21690211, 8683220, 2921426
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                796863823080135, 1897365583584155, 420466939481601,
++                2165972651724672, 932177357788289
++#else
++                18606791, 11874196, 27155355, 28272950, 43077121, 6265445,
++                41930624, 32275507, 4674689, 13890525
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                877047233620632, 1375632631944375, 643773611882121,
++                660022738847877, 19353932331831
++#else
++                13609624, 13069022, 39736503, 20498523, 24360585, 9592974,
++                14977157, 9835105, 4389687, 288396
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                2216943882299338, 394841323190322, 2222656898319671,
++                558186553950529, 1077236877025190
++#else
++                9922506, 33035038, 13613106, 5883594, 48350519, 33120168,
++                54804801, 8317627, 23388070, 16052080
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                801118384953213, 1914330175515892, 574541023311511,
++                1471123787903705, 1526158900256288
++#else
++                12719997, 11937594, 35138804, 28525742, 26900119, 8561328,
++                46953177, 21921452, 52354592, 22741539
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                949617889087234, 2207116611267331, 912920039141287,
++                501158539198789, 62362560771472
++#else
++                15961858, 14150409, 26716931, 32888600, 44314535, 13603568,
++                11829573, 7467844, 38286736, 929274
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1474518386765335, 1760793622169197, 1157399790472736,
++                1622864308058898, 165428294422792
++#else
++                11038231, 21972036, 39798381, 26237869, 56610336, 17246600,
++                43629330, 24182562, 45715720, 2465073
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1961673048027128, 102619413083113, 1051982726768458,
++                1603657989805485, 1941613251499678
++#else
++                20017144, 29231206, 27915241, 1529148, 12396362, 15675764,
++                13817261, 23896366, 2463390, 28932292
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1401939116319266, 335306339903072, 72046196085786,
++                862423201496006, 850518754531384
++#else
++                50749986, 20890520, 55043680, 4996453, 65852442, 1073571,
++                9583558, 12851107, 4003896, 12673717
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1234706593321979, 1083343891215917, 898273974314935,
++                1640859118399498, 157578398571149
++#else
++                65377275, 18398561, 63845933, 16143081, 19294135, 13385325,
++                14741514, 24450706, 7903885, 2348101
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1143483057726416, 1992614991758919, 674268662140796,
++                1773370048077526, 674318359920189
++#else
++                24536016, 17039225, 12715591, 29692277, 1511292, 10047386,
++                63266518, 26425272, 38731325, 10048126
++#endif
++            }},
++        },
++    },
++    {
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1835401379538542, 173900035308392, 818247630716732,
++                1762100412152786, 1021506399448291
++#else
++                54486638, 27349611, 30718824, 2591312, 56491836, 12192839,
++                18873298, 26257342, 34811107, 15221631
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1506632088156630, 2127481795522179, 513812919490255,
++                140643715928370, 442476620300318
++#else
++                40630742, 22450567, 11546243, 31701949, 9180879, 7656409,
++                45764914, 2095754, 29769758, 6593415
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                2056683376856736, 219094741662735, 2193541883188309,
++                1841182310235800, 556477468664293
++#else
++                35114656, 30646970, 4176911, 3264766, 12538965, 32686321,
++                26312344, 27435754, 30958053, 8292160
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1315019427910827, 1049075855992603, 2066573052986543,
++                266904467185534, 2040482348591520
++#else
++                31429803, 19595316, 29173531, 15632448, 12174511, 30794338,
++                32808830, 3977186, 26143136, 30405556
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                94096246544434, 922482381166992, 24517828745563,
++                2139430508542503, 2097139044231004
++#else
++                22648882, 1402143, 44308880, 13746058, 7936347, 365344,
++                58440231, 31879998, 63350620, 31249806
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                537697207950515, 1399352016347350, 1563663552106345,
++                2148749520888918, 549922092988516
++#else
++                51616947, 8012312, 64594134, 20851969, 43143017, 23300402,
++                65496150, 32018862, 50444388, 8194477
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1747985413252434, 680511052635695, 1809559829982725,
++                594274250930054, 201673170745982
++#else
++                27338066, 26047012, 59694639, 10140404, 48082437, 26964542,
++                27277190, 8855376, 28572286, 3005164
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                323583936109569, 1973572998577657, 1192219029966558,
++                79354804385273, 1374043025560347
++#else
++                26287105, 4821776, 25476601, 29408529, 63344350, 17765447,
++                49100281, 1182478, 41014043, 20474836
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                213277331329947, 416202017849623, 1950535221091783,
++                1313441578103244, 2171386783823658
++#else
++                59937691, 3178079, 23970071, 6201893, 49913287, 29065239,
++                45232588, 19571804, 32208682, 32356184
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                189088804229831, 993969372859110, 895870121536987,
++                1547301535298256, 1477373024911350
++#else
++                50451143, 2817642, 56822502, 14811297, 6024667, 13349505,
++                39793360, 23056589, 39436278, 22014573
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1620578418245010, 541035331188469, 2235785724453865,
++                2154865809088198, 1974627268751826
++#else
++                15941010, 24148500, 45741813, 8062054, 31876073, 33315803,
++                51830470, 32110002, 15397330, 29424239
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1346805451740245, 1350981335690626, 942744349501813,
++                2155094562545502, 1012483751693409
++#else
++                8934485, 20068965, 43822466, 20131190, 34662773, 14047985,
++                31170398, 32113411, 39603297, 15087183
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                2107080134091762, 1132567062788208, 1824935377687210,
++                769194804343737, 1857941799971888
++#else
++                48751602, 31397940, 24524912, 16876564, 15520426, 27193656,
++                51606457, 11461895, 16788528, 27685490
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1074666112436467, 249279386739593, 1174337926625354,
++                1559013532006480, 1472287775519121
++#else
++                65161459, 16013772, 21750665, 3714552, 49707082, 17498998,
++                63338576, 23231111, 31322513, 21938797
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1872620123779532, 1892932666768992, 1921559078394978,
++                1270573311796160, 1438913646755037
++#else
++                21426636, 27904214, 53460576, 28206894, 38296674, 28633461,
++                48833472, 18933017, 13040861, 21441484
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                837390187648199, 1012253300223599, 989780015893987,
++                1351393287739814, 328627746545550
++#else
++                11293895, 12478086, 39972463, 15083749, 37801443, 14748871,
++                14555558, 20137329, 1613710, 4896935
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1028328827183114, 1711043289969857, 1350832470374933,
++                1923164689604327, 1495656368846911
++#else
++                41213962, 15323293, 58619073, 25496531, 25967125, 20128972,
++                2825959, 28657387, 43137087, 22287016
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1900828492104143, 430212361082163, 687437570852799,
++                832514536673512, 1685641495940794
++#else
++                51184079, 28324551, 49665331, 6410663, 3622847, 10243618,
++                20615400, 12405433, 43355834, 25118015
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                842632847936398, 605670026766216, 290836444839585,
++                163210774892356, 2213815011799645
++#else
++                60017550, 12556207, 46917512, 9025186, 50036385, 4333800,
++                4378436, 2432030, 23097949, 32988414
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1176336383453996, 1725477294339771, 12700622672454,
++                678015708818208, 162724078519879
++#else
++                4565804, 17528778, 20084411, 25711615, 1724998, 189254,
++                24767264, 10103221, 48596551, 2424777
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1448049969043497, 1789411762943521, 385587766217753,
++                90201620913498, 832999441066823
++#else
++                366633, 21577626, 8173089, 26664313, 30788633, 5745705,
++                59940186, 1344108, 63466311, 12412658
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                516086333293313, 2240508292484616, 1351669528166508,
++                1223255565316488, 750235824427138
++#else
++                43107073, 7690285, 14929416, 33386175, 34898028, 20141445,
++                24162696, 18227928, 63967362, 11179384
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1263624896582495, 1102602401673328, 526302183714372,
++                2152015839128799, 1483839308490010
++#else
++                18289503, 18829478, 8056944, 16430056, 45379140, 7842513,
++                61107423, 32067534, 48424218, 22110928
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                442991718646863, 1599275157036458, 1925389027579192,
++                899514691371390, 350263251085160
++#else
++                476239, 6601091, 60956074, 23831056, 17503544, 28690532,
++                27672958, 13403813, 11052904, 5219329
++#endif
++            }},
++        },
++    },
++    {
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1689713572022143, 593854559254373, 978095044791970,
++                1985127338729499, 1676069120347625
++#else
++                20678527, 25178694, 34436965, 8849122, 62099106, 14574751,
++                31186971, 29580702, 9014761, 24975376
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1557207018622683, 340631692799603, 1477725909476187,
++                614735951619419, 2033237123746766
++#else
++                53464795, 23204192, 51146355, 5075807, 65594203, 22019831,
++                34006363, 9160279, 8473550, 30297594
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                968764929340557, 1225534776710944, 662967304013036,
++                1155521416178595, 791142883466590
++#else
++                24900749, 14435722, 17209120, 18261891, 44516588, 9878982,
++                59419555, 17218610, 42540382, 11788947
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1487081286167458, 993039441814934, 1792378982844640,
++                698652444999874, 2153908693179754
++#else
++                63990690, 22159237, 53306774, 14797440, 9652448, 26708528,
++                47071426, 10410732, 42540394, 32095740
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1123181311102823, 685575944875442, 507605465509927,
++                1412590462117473, 568017325228626
++#else
++                51449703, 16736705, 44641714, 10215877, 58011687, 7563910,
++                11871841, 21049238, 48595538, 8464117
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                560258797465417, 2193971151466401, 1824086900849026,
++                579056363542056, 1690063960036441
++#else
++                43708233, 8348506, 52522913, 32692717, 63158658, 27181012,
++                14325288, 8628612, 33313881, 25183915
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1918407319222416, 353767553059963, 1930426334528099,
++                1564816146005724, 1861342381708096
++#else
++                46921872, 28586496, 22367355, 5271547, 66011747, 28765593,
++                42303196, 23317577, 58168128, 27736162
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                2131325168777276, 1176636658428908, 1756922641512981,
++                1390243617176012, 1966325177038383
++#else
++                60160060, 31759219, 34483180, 17533252, 32635413, 26180187,
++                15989196, 20716244, 28358191, 29300528
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                2063958120364491, 2140267332393533, 699896251574968,
++                273268351312140, 375580724713232
++#else
++                43547083, 30755372, 34757181, 31892468, 57961144, 10429266,
++                50471180, 4072015, 61757200, 5596588
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                2024297515263178, 416959329722687, 1079014235017302,
++                171612225573183, 1031677520051053
++#else
++                38872266, 30164383, 12312895, 6213178, 3117142, 16078565,
++                29266239, 2557221, 1768301, 15373193
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                2033900009388450, 1744902869870788, 2190580087917640,
++                1949474984254121, 231049754293748
++#else
++                59865506, 30307471, 62515396, 26001078, 66980936, 32642186,
++                66017961, 29049440, 42448372, 3442909
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                343868674606581, 550155864008088, 1450580864229630,
++                481603765195050, 896972360018042
++#else
++                36898293, 5124042, 14181784, 8197961, 18964734, 21615339,
++                22597930, 7176455, 48523386, 13365929
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                2151139328380127, 314745882084928, 59756825775204,
++                1676664391494651, 2048348075599360
++#else
++                59231455, 32054473, 8324672, 4690079, 6261860, 890446, 24538107,
++                24984246, 57419264, 30522764
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1528930066340597, 1605003907059576, 1055061081337675,
++                1458319101947665, 1234195845213142
++#else
++                25008885, 22782833, 62803832, 23916421, 16265035, 15721635,
++                683793, 21730648, 15723478, 18390951
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                830430507734812, 1780282976102377, 1425386760709037,
++                362399353095425, 2168861579799910
++#else
++                57448220, 12374378, 40101865, 26528283, 59384749, 21239917,
++                11879681, 5400171, 519526, 32318556
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1155762232730333, 980662895504006, 2053766700883521,
++                490966214077606, 510405877041357
++#else
++                22258397, 17222199, 59239046, 14613015, 44588609, 30603508,
++                46754982, 7315966, 16648397, 7605640
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1683750316716132, 652278688286128, 1221798761193539,
++                1897360681476669, 319658166027343
++#else
++                59027556, 25089834, 58885552, 9719709, 19259459, 18206220,
++                23994941, 28272877, 57640015, 4763277
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                618808732869972, 72755186759744, 2060379135624181,
++                1730731526741822, 48862757828238
++#else
++                45409620, 9220968, 51378240, 1084136, 41632757, 30702041,
++                31088446, 25789909, 55752334, 728111
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1463171970593505, 1143040711767452, 614590986558883,
++                1409210575145591, 1882816996436803
++#else
++                26047201, 21802961, 60208540, 17032633, 24092067, 9158119,
++                62835319, 20998873, 37743427, 28056159
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                2230133264691131, 563950955091024, 2042915975426398,
++                827314356293472, 672028980152815
++#else
++                17510331, 33231575, 5854288, 8403524, 17133918, 30441820,
++                38997856, 12327944, 10750447, 10014012
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                264204366029760, 1654686424479449, 2185050199932931,
++                2207056159091748, 506015669043634
++#else
++                56796096, 3936951, 9156313, 24656749, 16498691, 32559785,
++                39627812, 32887699, 3424690, 7540221
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1784446333136569, 1973746527984364, 334856327359575,
++                1156769775884610, 1023950124675478
++#else
++                30322361, 26590322, 11361004, 29411115, 7433303, 4989748,
++                60037442, 17237212, 57864598, 15258045
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                2065270940578383, 31477096270353, 306421879113491,
++                181958643936686, 1907105536686083
++#else
++                13054543, 30774935, 19155473, 469045, 54626067, 4566041,
++                5631406, 2711395, 1062915, 28418087
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1496516440779464, 1748485652986458, 872778352227340,
++                818358834654919, 97932669284220
++#else
++                47868616, 22299832, 37599834, 26054466, 61273100, 13005410,
++                61042375, 12194496, 32960380, 1459310
++#endif
++            }},
++        },
++    },
++    {
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                471636015770351, 672455402793577, 1804995246884103,
++                1842309243470804, 1501862504981682
++#else
++                19852015, 7027924, 23669353, 10020366, 8586503, 26896525,
++                394196, 27452547, 18638002, 22379495
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1013216974933691, 538921919682598, 1915776722521558,
++                1742822441583877, 1886550687916656
++#else
++                31395515, 15098109, 26581030, 8030562, 50580950, 28547297,
++                9012485, 25970078, 60465776, 28111795
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                2094270000643336, 303971879192276, 40801275554748,
++                649448917027930, 1818544418535447
++#else
++                57916680, 31207054, 65111764, 4529533, 25766844, 607986,
++                67095642, 9677542, 34813975, 27098423
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                2241737709499165, 549397817447461, 838180519319392,
++                1725686958520781, 1705639080897747
++#else
++                64664349, 33404494, 29348901, 8186665, 1873760, 12489863,
++                36174285, 25714739, 59256019, 25416002
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1216074541925116, 50120933933509, 1565829004133810,
++                721728156134580, 349206064666188
++#else
++                51872508, 18120922, 7766469, 746860, 26346930, 23332670,
++                39775412, 10754587, 57677388, 5203575
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                948617110470858, 346222547451945, 1126511960599975,
++                1759386906004538, 493053284802266
++#else
++                31834314, 14135496, 66338857, 5159117, 20917671, 16786336,
++                59640890, 26216907, 31809242, 7347066
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1454933046815146, 874696014266362, 1467170975468588,
++                1432316382418897, 2111710746366763
++#else
++                57502122, 21680191, 20414458, 13033986, 13716524, 21862551,
++                19797969, 21343177, 15192875, 31466942
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                2105387117364450, 1996463405126433, 1303008614294500,
++                851908115948209, 1353742049788635
++#else
++                54445282, 31372712, 1168161, 29749623, 26747876, 19416341,
++                10609329, 12694420, 33473243, 20172328
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                750300956351719, 1487736556065813, 15158817002104,
++                1511998221598392, 971739901354129
++#else
++                33184999, 11180355, 15832085, 22169002, 65475192, 225883,
++                15089336, 22530529, 60973201, 14480052
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1874648163531693, 2124487685930551, 1810030029384882,
++                918400043048335, 586348627300650
++#else
++                31308717, 27934434, 31030839, 31657333, 15674546, 26971549,
++                5496207, 13685227, 27595050, 8737275
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1235084464747900, 1166111146432082, 1745394857881591,
++                1405516473883040, 4463504151617
++#else
++                46790012, 18404192, 10933842, 17376410, 8335351, 26008410,
++                36100512, 20943827, 26498113, 66511
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1663810156463827, 327797390285791, 1341846161759410,
++                1964121122800605, 1747470312055380
++#else
++                22644435, 24792703, 50437087, 4884561, 64003250, 19995065,
++                30540765, 29267685, 53781076, 26039336
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                660005247548233, 2071860029952887, 1358748199950107,
++                911703252219107, 1014379923023831
++#else
++                39091017, 9834844, 18617207, 30873120, 63706907, 20246925,
++                8205539, 13585437, 49981399, 15115438
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                2206641276178231, 1690587809721504, 1600173622825126,
++                2156096097634421, 1106822408548216
++#else
++                23711543, 32881517, 31206560, 25191721, 6164646, 23844445,
++                33572981, 32128335, 8236920, 16492939
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1344788193552206, 1949552134239140, 1735915881729557,
++                675891104100469, 1834220014427292
++#else
++                43198286, 20038905, 40809380, 29050590, 25005589, 25867162,
++                19574901, 10071562, 6708380, 27332008
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1920949492387964, 158885288387530, 70308263664033,
++                626038464897817, 1468081726101009
++#else
++                2101372, 28624378, 19702730, 2367575, 51681697, 1047674,
++                5301017, 9328700, 29955601, 21876122
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                622221042073383, 1210146474039168, 1742246422343683,
++                1403839361379025, 417189490895736
++#else
++                3096359, 9271816, 45488000, 18032587, 52260867, 25961494,
++                41216721, 20918836, 57191288, 6216607
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                22727256592983, 168471543384997, 1324340989803650,
++                1839310709638189, 504999476432775
++#else
++                34493015, 338662, 41913253, 2510421, 37895298, 19734218,
++                24822829, 27407865, 40341383, 7525078
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1313240518756327, 1721896294296942, 52263574587266,
++                2065069734239232, 804910473424630
++#else
++                44042215, 19568808, 16133486, 25658254, 63719298, 778787,
++                66198528, 30771936, 47722230, 11994100
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1337466662091884, 1287645354669772, 2018019646776184,
++                652181229374245, 898011753211715
++#else
++                21691500, 19929806, 66467532, 19187410, 3285880, 30070836,
++                42044197, 9718257, 59631427, 13381417
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1969792547910734, 779969968247557, 2011350094423418,
++                1823964252907487, 1058949448296945
++#else
++                18445390, 29352196, 14979845, 11622458, 65381754, 29971451,
++                23111647, 27179185, 28535281, 15779576
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                207343737062002, 1118176942430253, 758894594548164,
++                806764629546266, 1157700123092949
++#else
++                30098034, 3089662, 57874477, 16662134, 45801924, 11308410,
++                53040410, 12021729, 9955285, 17251076
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1273565321399022, 1638509681964574, 759235866488935,
++                666015124346707, 897983460943405
++#else
++                9734894, 18977602, 59635230, 24415696, 2060391, 11313496,
++                48682835, 9924398, 20194861, 13380996
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1717263794012298, 1059601762860786, 1837819172257618,
++                1054130665797229, 680893204263559
++#else
++                40730762, 25589224, 44941042, 15789296, 49053522, 27385639,
++                65123949, 15707770, 26342023, 10146099
++#endif
++            }},
++        },
++    },
++    {
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                2237039662793603, 2249022333361206, 2058613546633703,
++                149454094845279, 2215176649164582
++#else
++                41091971, 33334488, 21339190, 33513044, 19745255, 30675732,
++                37471583, 2227039, 21612326, 33008704
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                79472182719605, 1851130257050174, 1825744808933107,
++                821667333481068, 781795293511946
++#else
++                54031477, 1184227, 23562814, 27583990, 46757619, 27205717,
++                25764460, 12243797, 46252298, 11649657
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                755822026485370, 152464789723500, 1178207602290608,
++                410307889503239, 156581253571278
++#else
++                57077370, 11262625, 27384172, 2271902, 26947504, 17556661,
++                39943, 6114064, 33514190, 2333242
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1418185496130297, 484520167728613, 1646737281442950,
++                1401487684670265, 1349185550126961
++#else
++                45675257, 21132610, 8119781, 7219913, 45278342, 24538297,
++                60429113, 20883793, 24350577, 20104431
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1495380034400429, 325049476417173, 46346894893933,
++                1553408840354856, 828980101835683
++#else
++                62992557, 22282898, 43222677, 4843614, 37020525, 690622,
++                35572776, 23147595, 8317859, 12352766
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1280337889310282, 2070832742866672, 1640940617225222,
++                2098284908289951, 450929509534434
++#else
++                18200138, 19078521, 34021104, 30857812, 43406342, 24451920,
++                43556767, 31266881, 20712162, 6719373
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                407703353998781, 126572141483652, 286039827513621,
++                1999255076709338, 2030511179441770
++#else
++                26656189, 6075253, 59250308, 1886071, 38764821, 4262325,
++                11117530, 29791222, 26224234, 30256974
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1254958221100483, 1153235960999843, 942907704968834,
++                637105404087392, 1149293270147267
++#else
++                49939907, 18700334, 63713187, 17184554, 47154818, 14050419,
++                21728352, 9493610, 18620611, 17125804
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                894249020470196, 400291701616810, 406878712230981,
++                1599128793487393, 1145868722604026
++#else
++                53785524, 13325348, 11432106, 5964811, 18609221, 6062965,
++                61839393, 23828875, 36407290, 17074774
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1497955250203334, 110116344653260, 1128535642171976,
++                1900106496009660, 129792717460909
++#else
++                43248326, 22321272, 26961356, 1640861, 34695752, 16816491,
++                12248508, 28313793, 13735341, 1934062
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                452487513298665, 1352120549024569, 1173495883910956,
++                1999111705922009, 367328130454226
++#else
++                25089769, 6742589, 17081145, 20148166, 21909292, 17486451,
++                51972569, 29789085, 45830866, 5473615
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1717539401269642, 1475188995688487, 891921989653942,
++                836824441505699, 1885988485608364
++#else
++                31883658, 25593331, 1083431, 21982029, 22828470, 13290673,
++                59983779, 12469655, 29111212, 28103418
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1241784121422547, 187337051947583, 1118481812236193,
++                428747751936362, 30358898927325
++#else
++                24244947, 18504025, 40845887, 2791539, 52111265, 16666677,
++                24367466, 6388839, 56813277, 452382
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                2022432361201842, 1088816090685051, 1977843398539868,
++                1854834215890724, 564238862029357
++#else
++                41468082, 30136590, 5217915, 16224624, 19987036, 29472163,
++                42872612, 27639183, 15766061, 8407814
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                938868489100585, 1100285072929025, 1017806255688848,
++                1957262154788833, 152787950560442
++#else
++                46701865, 13990230, 15495425, 16395525, 5377168, 15166495,
++                58191841, 29165478, 59040954, 2276717
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                867319417678923, 620471962942542, 226032203305716,
++                342001443957629, 1761675818237336
++#else
++                30157899, 12924066, 49396814, 9245752, 19895028, 3368142,
++                43281277, 5096218, 22740376, 26251015
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1295072362439987, 931227904689414, 1355731432641687,
++                922235735834035, 892227229410209
++#else
++                2041139, 19298082, 7783686, 13876377, 41161879, 20201972,
++                24051123, 13742383, 51471265, 13295221
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1680989767906154, 535362787031440, 2136691276706570,
++                1942228485381244, 1267350086882274
++#else
++                33338218, 25048699, 12532112, 7977527, 9106186, 31839181,
++                49388668, 28941459, 62657506, 18884987
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                366018233770527, 432660629755596, 126409707644535,
++                1973842949591662, 645627343442376
++#else
++                47063583, 5454096, 52762316, 6447145, 28862071, 1883651,
++                64639598, 29412551, 7770568, 9620597
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                535509430575217, 546885533737322, 1524675609547799,
++                2138095752851703, 1260738089896827
++#else
++                23208049, 7979712, 33071466, 8149229, 1758231, 22719437,
++                30945527, 31860109, 33606523, 18786461
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1159906385590467, 2198530004321610, 714559485023225,
++                81880727882151, 1484020820037082
++#else
++                1439939, 17283952, 66028874, 32760649, 4625401, 10647766,
++                62065063, 1220117, 30494170, 22113633
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1377485731340769, 2046328105512000, 1802058637158797,
++                62146136768173, 1356993908853901
++#else
++                62071265, 20526136, 64138304, 30492664, 15640973, 26852766,
++                40369837, 926049, 65424525, 20220784
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                2013612215646735, 1830770575920375, 536135310219832,
++                609272325580394, 270684344495013
++#else
++                13908495, 30005160, 30919927, 27280607, 45587000, 7989038,
++                9021034, 9078865, 3353509, 4033511
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1237542585982777, 2228682050256790, 1385281931622824,
++                593183794882890, 493654978552689
++#else
++                37445433, 18440821, 32259990, 33209950, 24295848, 20642309,
++                23161162, 8839127, 27485041, 7356032
++#endif
++            }},
++        },
++    },
++    {
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                47341488007760, 1891414891220257, 983894663308928,
++                176161768286818, 1126261115179708
++#else
++                9661008, 705443, 11980065, 28184278, 65480320, 14661172,
++                60762722, 2625014, 28431036, 16782598
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1694030170963455, 502038567066200, 1691160065225467,
++                949628319562187, 275110186693066
++#else
++                43269631, 25243016, 41163352, 7480957, 49427195, 25200248,
++                44562891, 14150564, 15970762, 4099461
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1124515748676336, 1661673816593408, 1499640319059718,
++                1584929449166988, 558148594103306
++#else
++                29262576, 16756590, 26350592, 24760869, 8529670, 22346382,
++                13617292, 23617289, 11465738, 8317062
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1784525599998356, 1619698033617383, 2097300287550715,
++                258265458103756, 1905684794832758
++#else
++                41615764, 26591503, 32500199, 24135381, 44070139, 31252209,
++                14898636, 3848455, 20969334, 28396916
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1288941072872766, 931787902039402, 190731008859042,
++                2006859954667190, 1005931482221702
++#else
++                46724414, 19206718, 48772458, 13884721, 34069410, 2842113,
++                45498038, 29904543, 11177094, 14989547
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1465551264822703, 152905080555927, 680334307368453,
++                173227184634745, 666407097159852
++#else
++                42612143, 21838415, 16959895, 2278463, 12066309, 10137771,
++                13515641, 2581286, 38621356, 9930239
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                2111017076203943, 1378760485794347, 1248583954016456,
++                1352289194864422, 1895180776543896
++#else
++                49357223, 31456605, 16544299, 20545132, 51194056, 18605350,
++                18345766, 20150679, 16291480, 28240394
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                171348223915638, 662766099800389, 462338943760497,
++                466917763340314, 656911292869115
++#else
++                33879670, 2553287, 32678213, 9875984, 8534129, 6889387,
++                57432090, 6957616, 4368891, 9788741
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                488623681976577, 866497561541722, 1708105560937768,
++                1673781214218839, 1506146329818807
++#else
++                16660737, 7281060, 56278106, 12911819, 20108584, 25452756,
++                45386327, 24941283, 16250551, 22443329
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                160425464456957, 950394373239689, 430497123340934,
++                711676555398832, 320964687779005
++#else
++                47343357, 2390525, 50557833, 14161979, 1905286, 6414907,
++                4689584, 10604807, 36918461, 4782746
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                988979367990485, 1359729327576302, 1301834257246029,
++                294141160829308, 29348272277475
++#else
++                65754325, 14736940, 59741422, 20261545, 7710541, 19398842,
++                57127292, 4383044, 22546403, 437323
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1434382743317910, 100082049942065, 221102347892623,
++                186982837860588, 1305765053501834
++#else
++                31665558, 21373968, 50922033, 1491338, 48740239, 3294681,
++                27343084, 2786261, 36475274, 19457415
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                2205916462268190, 499863829790820, 961960554686616,
++                158062762756985, 1841471168298305
++#else
++                52641566, 32870716, 33734756, 7448551, 19294360, 14334329,
++                47418233, 2355318, 47824193, 27440058
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1191737341426592, 1847042034978363, 1382213545049056,
++                1039952395710448, 788812858896859
++#else
++                15121312, 17758270, 6377019, 27523071, 56310752, 20596586,
++                18952176, 15496498, 37728731, 11754227
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1346965964571152, 1291881610839830, 2142916164336056,
++                786821641205979, 1571709146321039
++#else
++                64471568, 20071356, 8488726, 19250536, 12728760, 31931939,
++                7141595, 11724556, 22761615, 23420291
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                787164375951248, 202869205373189, 1356590421032140,
++                1431233331032510, 786341368775957
++#else
++                16918416, 11729663, 49025285, 3022986, 36093132, 20214772,
++                38367678, 21327038, 32851221, 11717399
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                492448143532951, 304105152670757, 1761767168301056,
++                233782684697790, 1981295323106089
++#else
++                11166615, 7338049, 60386341, 4531519, 37640192, 26252376,
++                31474878, 3483633, 65915689, 29523600
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                665807507761866, 1343384868355425, 895831046139653,
++                439338948736892, 1986828765695105
++#else
++                66923210, 9921304, 31456609, 20017994, 55095045, 13348922,
++                33142652, 6546660, 47123585, 29606055
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                756096210874553, 1721699973539149, 258765301727885,
++                1390588532210645, 1212530909934781
++#else
++                34648249, 11266711, 55911757, 25655328, 31703693, 3855903,
++                58571733, 20721383, 36336829, 18068118
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                852891097972275, 1816988871354562, 1543772755726524,
++                1174710635522444, 202129090724628
++#else
++                49102387, 12709067, 3991746, 27075244, 45617340, 23004006,
++                35973516, 17504552, 10928916, 3011958
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1205281565824323, 22430498399418, 992947814485516,
++                1392458699738672, 688441466734558
++#else
++                60151107, 17960094, 31696058, 334240, 29576716, 14796075,
++                36277808, 20749251, 18008030, 10258577
++#endif
++            }},
++        },
++        {
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1050627428414972, 1955849529137135, 2171162376368357,
++                91745868298214, 447733118757826
++#else
++                44660220, 15655568, 7018479, 29144429, 36794597, 32352840,
++                65255398, 1367119, 25127874, 6671743
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1287181461435438, 622722465530711, 880952150571872,
++                741035693459198, 311565274989772
++#else
++                29701166, 19180498, 56230743, 9279287, 67091296, 13127209,
++                21382910, 11042292, 25838796, 4642684
++#endif
++            }},
++            {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++                1003649078149734, 545233927396469, 1849786171789880,
++                1318943684880434, 280345687170552
++#else
++                46678630, 14955536, 42982517, 8124618, 61739576, 27563961,
++                30468146, 19653792, 18423288, 4177476
++#endif
++            }},
++        },
++    },
++};
++
++#endif  // CONFIG_SMALL
++
++// Bi[i] = (2*i+1)*B
++static const ge_precomp Bi[8] = {
++    {
++        {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++            1288382639258501, 245678601348599, 269427782077623,
++            1462984067271730, 137412439391563
++#else
++            25967493, 19198397, 29566455, 3660896, 54414519, 4014786, 27544626,
++            21800161, 61029707, 2047604
++#endif
++        }},
++        {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++            62697248952638, 204681361388450, 631292143396476, 338455783676468,
++            1213667448819585
++#else
++            54563134, 934261, 64385954, 3049989, 66381436, 9406985, 12720692,
++            5043384, 19500929, 18085054
++#endif
++        }},
++        {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++            301289933810280, 1259582250014073, 1422107436869536,
++            796239922652654, 1953934009299142
++#else
++            58370664, 4489569, 9688441, 18769238, 10184608, 21191052, 29287918,
++            11864899, 42594502, 29115885
++#endif
++        }},
++    },
++    {
++        {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++            1601611775252272, 1720807796594148, 1132070835939856,
++            1260455018889551, 2147779492816911
++#else
++            15636272, 23865875, 24204772, 25642034, 616976, 16869170, 27787599,
++            18782243, 28944399, 32004408
++#endif
++        }},
++        {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++            316559037616741, 2177824224946892, 1459442586438991,
++            1461528397712656, 751590696113597
++#else
++            16568933, 4717097, 55552716, 32452109, 15682895, 21747389, 16354576,
++            21778470, 7689661, 11199574
++#endif
++        }},
++        {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++            1850748884277385, 1200145853858453, 1068094770532492,
++            672251375690438, 1586055907191707
++#else
++            30464137, 27578307, 55329429, 17883566, 23220364, 15915852, 7512774,
++            10017326, 49359771, 23634074
++#endif
++        }},
++    },
++    {
++        {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++            769950342298419, 132954430919746, 844085933195555, 974092374476333,
++            726076285546016
++#else
++            10861363, 11473154, 27284546, 1981175, 37044515, 12577860, 32867885,
++            14515107, 51670560, 10819379
++#endif
++        }},
++        {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++            425251763115706, 608463272472562, 442562545713235, 837766094556764,
++            374555092627893
++#else
++            4708026, 6336745, 20377586, 9066809, 55836755, 6594695, 41455196,
++            12483687, 54440373, 5581305
++#endif
++        }},
++        {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++            1086255230780037, 274979815921559, 1960002765731872,
++            929474102396301, 1190409889297339
++#else
++            19563141, 16186464, 37722007, 4097518, 10237984, 29206317, 28542349,
++            13850243, 43430843, 17738489
++#endif
++        }},
++    },
++    {
++        {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++            665000864555967, 2065379846933859, 370231110385876, 350988370788628,
++            1233371373142985
++#else
++            5153727, 9909285, 1723747, 30776558, 30523604, 5516873, 19480852,
++            5230134, 43156425, 18378665
++#endif
++        }},
++        {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++            2019367628972465, 676711900706637, 110710997811333,
++            1108646842542025, 517791959672113
++#else
++            36839857, 30090922, 7665485, 10083793, 28475525, 1649722, 20654025,
++            16520125, 30598449, 7715701
++#endif
++        }},
++        {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++            965130719900578, 247011430587952, 526356006571389, 91986625355052,
++            2157223321444601
++#else
++            28881826, 14381568, 9657904, 3680757, 46927229, 7843315, 35708204,
++            1370707, 29794553, 32145132
++#endif
++        }},
++    },
++    {
++        {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++            1802695059465007, 1664899123557221, 593559490740857,
++            2160434469266659, 927570450755031
++#else
++            44589871, 26862249, 14201701, 24808930, 43598457, 8844725, 18474211,
++            32192982, 54046167, 13821876
++#endif
++        }},
++        {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++            1725674970513508, 1933645953859181, 1542344539275782,
++            1767788773573747, 1297447965928905
++#else
++            60653668, 25714560, 3374701, 28813570, 40010246, 22982724, 31655027,
++            26342105, 18853321, 19333481
++#endif
++        }},
++        {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++            1381809363726107, 1430341051343062, 2061843536018959,
++            1551778050872521, 2036394857967624
++#else
++            4566811, 20590564, 38133974, 21313742, 59506191, 30723862, 58594505,
++            23123294, 2207752, 30344648
++#endif
++        }},
++    },
++    {
++        {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++            1970894096313054, 528066325833207, 1619374932191227,
++            2207306624415883, 1169170329061080
++#else
++            41954014, 29368610, 29681143, 7868801, 60254203, 24130566, 54671499,
++            32891431, 35997400, 17421995
++#endif
++        }},
++        {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++            2070390218572616, 1458919061857835, 624171843017421,
++            1055332792707765, 433987520732508
++#else
++            25576264, 30851218, 7349803, 21739588, 16472781, 9300885, 3844789,
++            15725684, 171356, 6466918
++#endif
++        }},
++        {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++            893653801273833, 1168026499324677, 1242553501121234,
++            1306366254304474, 1086752658510815
++#else
++            23103977, 13316479, 9739013, 17404951, 817874, 18515490, 8965338,
++            19466374, 36393951, 16193876
++#endif
++        }},
++    },
++    {
++        {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++            213454002618221, 939771523987438, 1159882208056014, 317388369627517,
++            621213314200687
++#else
++            33587053, 3180712, 64714734, 14003686, 50205390, 17283591, 17238397,
++            4729455, 49034351, 9256799
++#endif
++        }},
++        {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++            1971678598905747, 338026507889165, 762398079972271, 655096486107477,
++            42299032696322
++#else
++            41926547, 29380300, 32336397, 5036987, 45872047, 11360616, 22616405,
++            9761698, 47281666, 630304
++#endif
++        }},
++        {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++            177130678690680, 1754759263300204, 1864311296286618,
++            1180675631479880, 1292726903152791
++#else
++            53388152, 2639452, 42871404, 26147950, 9494426, 27780403, 60554312,
++            17593437, 64659607, 19263131
++#endif
++        }},
++    },
++    {
++        {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++            1913163449625248, 460779200291993, 2193883288642314,
++            1008900146920800, 1721983679009502
++#else
++            63957664, 28508356, 9282713, 6866145, 35201802, 32691408, 48168288,
++            15033783, 25105118, 25659556
++#endif
++        }},
++        {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++            1070401523076875, 1272492007800961, 1910153608563310,
++            2075579521696771, 1191169788841221
++#else
++            42782475, 15950225, 35307649, 18961608, 55446126, 28463506, 1573891,
++            30928545, 2198789, 17749813
++#endif
++        }},
++        {{
++#if defined(BORINGSSL_CURVE25519_64BIT)
++            692896803108118, 500174642072499, 2068223309439677,
++            1162190621851337, 1426986007309901
++#else
++            64009494, 10324966, 64867251, 7453182, 61661885, 30818928, 53296841,
++            17317989, 34647629, 21263748
++#endif
++        }},
++    },
++};
+diff --git a/src/plugins/preauth/spake/groups.c b/src/plugins/preauth/spake/groups.c
+new file mode 100644
+index 000000000..a195cc195
+--- /dev/null
++++ b/src/plugins/preauth/spake/groups.c
+@@ -0,0 +1,442 @@
++/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
++/* plugins/preauth/spake/groups.c - SPAKE group interfaces */
++/*
++ * Copyright (C) 2015 by the Massachusetts Institute of Technology.
++ * 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 SPAKE2 algorithm works as follows:
++ *
++ * 1. The parties agree on a group, a base element G, and constant elements M
++ *    and N.  In this mechanism, these parameters are determined by the
++ *    registered group number.
++ * 2. Both parties derive a scalar value w from the initial key.
++ * 3. The first party (the KDC, in this mechanism) chooses a random secret
++ *    scalar x and sends T=xG+wM.
++ * 4. The second party (the client, in this mechanism) chooses a random
++ *    secret scalar y and sends S=yG+wN.
++ * 5. The first party computes K=x(S-wN).
++ * 6. The second party computes the same value as K=y(T-wM).
++ * 7. Both parties derive a key from a random oracle whose input incorporates
++ *    the party identities, w, T, S, and K.
++ *
++ * We implement the algorithm using a vtable for each group, where the primary
++ * vtable methods are "keygen" (corresponding to step 3 or 4) and "result"
++ * (corresponding to step 5 or 6).  We use the term "private scalar" to refer
++ * to x or y, and "public element" to refer to S or T.
++ */
++
++#include "iana.h"
++#include "trace.h"
++#include "groups.h"
++
++#define DEFAULT_GROUPS_CLIENT "edwards25519"
++#define DEFAULT_GROUPS_KDC ""
++
++typedef struct groupent_st {
++    const groupdef *gdef;
++    groupdata *gdata;
++} groupent;
++
++struct groupstate_st {
++    krb5_boolean is_kdc;
++
++    /* Permitted and groups, from configuration */
++    int32_t *permitted;
++    size_t npermitted;
++
++    /* Optimistic challenge group, from configuration */
++    int32_t challenge_group;
++
++    /* Lazily-initialized list of gdata objects. */
++    groupent *data;
++    size_t ndata;
++};
++
++extern groupdef builtin_edwards25519;
++#ifdef SPAKE_OPENSSL
++extern groupdef ossl_P256;
++extern groupdef ossl_P384;
++extern groupdef ossl_P521;
++#endif
++
++static const groupdef *groupdefs[] = {
++    &builtin_edwards25519,
++#ifdef SPAKE_OPENSSL
++    &ossl_P256,
++    &ossl_P384,
++    &ossl_P521,
++#endif
++    NULL
++};
++
++/* Find a groupdef structure by group number.  Return NULL on failure. */
++static const groupdef *
++find_gdef(int32_t group)
++{
++    size_t i;
++
++    for (i = 0; groupdefs[i] != NULL; i++) {
++        if (groupdefs[i]->reg->id == group)
++            return groupdefs[i];
++    }
++
++    return NULL;
++}
++
++/* Find a group number by name.  Return 0 on failure. */
++static int32_t
++find_gnum(const char *name)
++{
++    size_t i;
++
++    for (i = 0; groupdefs[i] != NULL; i++) {
++        if (strcasecmp(name, groupdefs[i]->reg->name) == 0)
++            return groupdefs[i]->reg->id;
++    }
++    return 0;
++}
++
++static krb5_boolean
++in_grouplist(const int32_t *list, size_t count, int32_t group)
++{
++    size_t i;
++
++    for (i = 0; i < count; i++) {
++        if (list[i] == group)
++            return TRUE;
++    }
++
++    return FALSE;
++}
++
++/* Retrieve a group data object for group within gstate, lazily initializing it
++ * if necessary. */
++static krb5_error_code
++get_gdata(krb5_context context, groupstate *gstate, const groupdef *gdef,
++          groupdata **gdata_out)
++{
++    krb5_error_code ret;
++    groupent *ent, *newptr;
++
++    *gdata_out = NULL;
++
++    /* Look for an existing entry. */
++    for (ent = gstate->data; ent < gstate->data + gstate->ndata; ent++) {
++        if (ent->gdef == gdef) {
++            *gdata_out = ent->gdata;
++            return 0;
++        }
++    }
++
++    /* Make a new entry. */
++    newptr = realloc(gstate->data, (gstate->ndata + 1) * sizeof(groupent));
++    if (newptr == NULL)
++        return ENOMEM;
++    gstate->data = newptr;
++    ent = &gstate->data[gstate->ndata];
++    ent->gdef = gdef;
++    ent->gdata = NULL;
++    if (gdef->init != NULL) {
++        ret = gdef->init(context, gdef, &ent->gdata);
++        if (ret)
++            return ret;
++    }
++    gstate->ndata++;
++    *gdata_out = ent->gdata;
++    return 0;
++}
++
++/* Destructively parse str into a list of group numbers. */
++static krb5_error_code
++parse_groups(krb5_context context, char *str, int32_t **list_out,
++             size_t *count_out)
++{
++    const char *const delim = " \t\r\n,";
++    char *token, *save = NULL;
++    int32_t group, *newptr, *list = NULL;
++    size_t count = 0;
++
++    *list_out = NULL;
++    *count_out = 0;
++
++    /* Walk through the words in profstr. */
++    for (token = strtok_r(str, delim, &save); token != NULL;
++         token = strtok_r(NULL, delim, &save)) {
++        group = find_gnum(token);
++        if (!group) {
++            TRACE_SPAKE_UNKNOWN_GROUP(context, token);
++            continue;
++        }
++        if (in_grouplist(list, count, group))
++            continue;
++        newptr = realloc(list, (count + 1) * sizeof(*list));
++        if (newptr == NULL) {
++            free(list);
++            return ENOMEM;
++        }
++        list = newptr;
++        list[count++] = group;
++    }
++
++    *list_out = list;
++    *count_out = count;
++    return 0;
++}
++
++krb5_error_code
++group_init_state(krb5_context context, krb5_boolean is_kdc,
++                 groupstate **gstate_out)
++{
++    krb5_error_code ret;
++    groupstate *gstate;
++    const char *defgroups;
++    char *profstr1 = NULL, *profstr2 = NULL;
++    int32_t *permitted = NULL, challenge_group = 0;
++    size_t npermitted;
++
++    *gstate_out = NULL;
++
++    defgroups = is_kdc ? DEFAULT_GROUPS_KDC : DEFAULT_GROUPS_CLIENT;
++    ret = profile_get_string(context->profile, KRB5_CONF_LIBDEFAULTS,
++                             KRB5_CONF_SPAKE_PREAUTH_GROUPS, NULL, defgroups,
++                             &profstr1);
++    if (ret)
++        goto cleanup;
++    ret = parse_groups(context, profstr1, &permitted, &npermitted);
++    if (ret)
++        goto cleanup;
++    if (npermitted == 0) {
++        ret = KRB5_PLUGIN_OP_NOTSUPP;
++        k5_setmsg(context, ret, _("No SPAKE preauth groups configured"));
++        goto cleanup;
++    }
++
++    if (is_kdc) {
++        /*
++         * Check for a configured optimistic challenge group.  If one is set,
++         * the KDC will send a challenge in the PREAUTH_REQUIRED method data,
++         * before receiving the list of supported groups.
++         */
++        ret = profile_get_string(context->profile, KRB5_CONF_KDCDEFAULTS,
++                                 KRB5_CONF_SPAKE_PREAUTH_KDC_CHALLENGE, NULL,
++                                 NULL, &profstr2);
++        if (ret)
++            goto cleanup;
++        if (profstr2 != NULL) {
++            challenge_group = find_gnum(profstr2);
++            if (!in_grouplist(permitted, npermitted, challenge_group)) {
++                ret = KRB5_PLUGIN_OP_NOTSUPP;
++                k5_setmsg(context, ret,
++                          _("SPAKE challenge group not a permitted group: %s"),
++                          profstr2);
++                goto cleanup;
++            }
++        }
++    }
++
++    gstate = k5alloc(sizeof(*gstate), &ret);
++    if (gstate == NULL)
++        goto cleanup;
++    gstate->is_kdc = is_kdc;
++    gstate->permitted = permitted;
++    gstate->npermitted = npermitted;
++    gstate->challenge_group = challenge_group;
++    permitted = NULL;
++    gstate->data = NULL;
++    gstate->ndata = 0;
++    *gstate_out = gstate;
++
++cleanup:
++    profile_release_string(profstr1);
++    profile_release_string(profstr2);
++    free(permitted);
++    return ret;
++}
++
++
++void
++group_free_state(groupstate *gstate)
++{
++    groupent *ent;
++
++    for (ent = gstate->data; ent < gstate->data + gstate->ndata; ent++) {
++        if (ent->gdata != NULL && ent->gdef->fini != NULL)
++            ent->gdef->fini(ent->gdata);
++    }
++
++    free(gstate->permitted);
++    free(gstate->data);
++    free(gstate);
++}
++
++krb5_boolean
++group_is_permitted(groupstate *gstate, int32_t group)
++{
++    return in_grouplist(gstate->permitted, gstate->npermitted, group);
++}
++
++void
++group_get_permitted(groupstate *gstate, int32_t **list_out, int32_t *count_out)
++{
++    *list_out = gstate->permitted;
++    *count_out = gstate->npermitted;
++}
++
++krb5_int32
++group_optimistic_challenge(groupstate *gstate)
++{
++    assert(gstate->is_kdc);
++    return gstate->challenge_group;
++}
++
++krb5_error_code
++group_mult_len(int32_t group, size_t *len_out)
++{
++    const groupdef *gdef;
++
++    *len_out = 0;
++    gdef = find_gdef(group);
++    if (gdef == NULL)
++        return EINVAL;
++    *len_out = gdef->reg->mult_len;
++    return 0;
++}
++
++krb5_error_code
++group_keygen(krb5_context context, groupstate *gstate, int32_t group,
++             const krb5_data *wbytes, krb5_data *priv_out, krb5_data *pub_out)
++{
++    krb5_error_code ret;
++    const groupdef *gdef;
++    groupdata *gdata;
++    uint8_t *priv = NULL, *pub = NULL;
++
++    *priv_out = empty_data();
++    *pub_out = empty_data();
++    gdef = find_gdef(group);
++    if (gdef == NULL || wbytes->length != gdef->reg->mult_len)
++        return EINVAL;
++    ret = get_gdata(context, gstate, gdef, &gdata);
++    if (ret)
++        return ret;
++
++    priv = k5alloc(gdef->reg->mult_len, &ret);
++    if (priv == NULL)
++        goto cleanup;
++    pub = k5alloc(gdef->reg->elem_len, &ret);
++    if (pub == NULL)
++        goto cleanup;
++
++    ret = gdef->keygen(context, gdata, (uint8_t *)wbytes->data, gstate->is_kdc,
++                       priv, pub);
++    if (ret)
++        goto cleanup;
++
++    *priv_out = make_data(priv, gdef->reg->mult_len);
++    *pub_out = make_data(pub, gdef->reg->elem_len);
++    priv = pub = NULL;
++    TRACE_SPAKE_KEYGEN(context, pub_out);
++
++cleanup:
++    zapfree(priv, gdef->reg->mult_len);
++    free(pub);
++    return ret;
++}
++
++krb5_error_code
++group_result(krb5_context context, groupstate *gstate, int32_t group,
++             const krb5_data *wbytes, const krb5_data *ourpriv,
++             const krb5_data *theirpub, krb5_data *spakeresult_out)
++{
++    krb5_error_code ret;
++    const groupdef *gdef;
++    groupdata *gdata;
++    uint8_t *spakeresult = NULL;
++
++    *spakeresult_out = empty_data();
++    gdef = find_gdef(group);
++    if (gdef == NULL || wbytes->length != gdef->reg->mult_len)
++        return EINVAL;
++    if (ourpriv->length != gdef->reg->mult_len ||
++        theirpub->length != gdef->reg->elem_len)
++        return EINVAL;
++    ret = get_gdata(context, gstate, gdef, &gdata);
++    if (ret)
++        return ret;
++
++    spakeresult = k5alloc(gdef->reg->elem_len, &ret);
++    if (spakeresult == NULL)
++        goto cleanup;
++
++    /* Invert is_kdc here to use the other party's constant. */
++    ret = gdef->result(context, gdata, (uint8_t *)wbytes->data,
++                       (uint8_t *)ourpriv->data, (uint8_t *)theirpub->data,
++                       !gstate->is_kdc, spakeresult);
++    if (ret)
++        goto cleanup;
++
++    *spakeresult_out = make_data(spakeresult, gdef->reg->elem_len);
++    spakeresult = NULL;
++    TRACE_SPAKE_RESULT(context, spakeresult_out);
++
++cleanup:
++    zapfree(spakeresult, gdef->reg->elem_len);
++    return ret;
++}
++
++krb5_error_code
++group_hash_len(int32_t group, size_t *len_out)
++{
++    const groupdef *gdef;
++
++    *len_out = 0;
++    gdef = find_gdef(group);
++    if (gdef == NULL)
++        return EINVAL;
++    *len_out = gdef->reg->hash_len;
++    return 0;
++}
++
++krb5_error_code
++group_hash(krb5_context context, groupstate *gstate, int32_t group,
++           const krb5_data *dlist, size_t ndata, uint8_t *result_out)
++{
++    krb5_error_code ret;
++    const groupdef *gdef;
++    groupdata *gdata;
++
++    gdef = find_gdef(group);
++    if (gdef == NULL)
++        return EINVAL;
++    ret = get_gdata(context, gstate, gdef, &gdata);
++    if (ret)
++        return ret;
++    return gdef->hash(context, gdata, dlist, ndata, result_out);
++}
+diff --git a/src/plugins/preauth/spake/groups.h b/src/plugins/preauth/spake/groups.h
+new file mode 100644
+index 000000000..3add69494
+--- /dev/null
++++ b/src/plugins/preauth/spake/groups.h
+@@ -0,0 +1,148 @@
++/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
++/* plugins/preauth/spake/groups.h - SPAKE group interfaces */
++/*
++ * Copyright (C) 2015 by the Massachusetts Institute of Technology.
++ * 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.
++ */
++
++#ifndef GROUPS_H
++#define GROUPS_H
++
++#include "k5-int.h"
++#include "iana.h"
++
++typedef struct groupstate_st groupstate;
++typedef struct groupdata_st groupdata;
++typedef struct groupdef_st groupdef;
++
++struct groupdef_st {
++    const spake_iana *reg;
++
++    /*
++     * Optional: create a per-group data object to allow more efficient keygen
++     * and result computations.  Saving a reference to gdef is okay; its
++     * lifetime will always be longer than the resulting object.
++     */
++    krb5_error_code (*init)(krb5_context context, const groupdef *gdef,
++                            groupdata **gdata_out);
++
++    /* Optional: release a group data object. */
++    void (*fini)(groupdata *gdata);
++
++    /*
++     * Mandatory: generate a random private scalar (x or y) and a public
++     * element (T or S), using wbytes for the w value.  If use_m is true, use
++     * the M element (generating T); otherwise use the N element (generating
++     * S).  wbytes and priv_out have length reg->mult_len; pub_out has length
++     * reg->elem_len.  priv_out and pub_out are caller-allocated.
++     */
++    krb5_error_code (*keygen)(krb5_context context, groupdata *gdata,
++                              const uint8_t *wbytes, krb5_boolean use_m,
++                              uint8_t *priv_out, uint8_t *pub_out);
++
++    /*
++     * Mandatory: compute K given a private scalar (x or y) and the other
++     * party's public element (S or T), using wbytes for the w value.  If use_m
++     * is true, use the M element (computing K from y and T); otherwise use the
++     * N element (computing K from x and S).  wbytes and ourpriv have length
++     * reg->mult_len; theirpub and elem_out have length reg->elem_len.
++     * elem_out is caller-allocated.
++     */
++    krb5_error_code (*result)(krb5_context context, groupdata *gdata,
++                              const uint8_t *wbytes, const uint8_t *ourpriv,
++                              const uint8_t *theirpub, krb5_boolean use_m,
++                              uint8_t *elem_out);
++
++    /*
++     * Mandatory: compute the group's specified hash function over datas (with
++     * ndata elements), placing the result in result_out.  result_out is
++     * caller-allocated with length reg->hash_len.
++     */
++    krb5_error_code (*hash)(krb5_context context, groupdata *gdata,
++                            const krb5_data *datas, size_t ndata,
++                            uint8_t *result_out);
++};
++
++/* Initialize an object which holds group configuration and pre-computation
++ * state for each group.  is_kdc is true for KDCs, false for clients. */
++krb5_error_code group_init_state(krb5_context context, krb5_boolean is_kdc,
++                                 groupstate **out);
++
++/* Release resources held by gstate. */
++void group_free_state(groupstate *gstate);
++
++/* Return true if group is permitted by configuration. */
++krb5_boolean group_is_permitted(groupstate *gstate, int32_t group);
++
++/* Set *list_out and *count_out to the list of groups permitted by
++ * configuration. */
++void group_get_permitted(groupstate *gstate, int32_t **list_out,
++                         int32_t *count_out);
++
++/* Return the KDC optimistic challenge group if one is configured.  Valid for
++ * KDC groupstate objects only. */
++krb5_int32 group_optimistic_challenge(groupstate *gstate);
++
++/* Set *len_out to the multiplier length for group. */
++krb5_error_code group_mult_len(int32_t group, size_t *len_out);
++
++/*
++ * Generate a SPAKE private scalar (x or y) and public element (T or S), given
++ * an input multiplier wbytes.  Use constant M if gstate is a KDC groupstate
++ * object, N if it is a client object.  Allocate storage and place the results
++ * in *priv_out and *pub_out.
++ */
++krb5_error_code group_keygen(krb5_context context, groupstate *gstate,
++                             int32_t group, const krb5_data *wbytes,
++                             krb5_data *priv_out, krb5_data *pub_out);
++
++/*
++ * Compute the SPAKE result K from our private scalar (x or y) and their public
++ * key (S or T), deriving the input scalar w from ikey.  Use the other party's
++ * constant, N if gstate is a KDC groupstate object or M if it is a client
++ * object.  Allocate storage and place the result in *spakeresult_out.
++ */
++krb5_error_code group_result(krb5_context context, groupstate *gstate,
++                             int32_t group, const krb5_data *wbytes,
++                             const krb5_data *ourpriv,
++                             const krb5_data *theirpub,
++                             krb5_data *spakeresult_out);
++
++/* Set *result_out to the hash output length for group. */
++krb5_error_code group_hash_len(int32_t group, size_t *result_out);
++
++/*
++ * Compute the group's specified hash function over dlist (with ndata
++ * elements).  result_out is caller-allocated with enough bytes for the hash
++ * output as given by group_hash_len().
++ */
++krb5_error_code group_hash(krb5_context context, groupstate *gstate,
++                           int32_t group, const krb5_data *dlist, size_t ndata,
++                           uint8_t *result_out);
++
++#endif /* GROUPS_H */
+diff --git a/src/plugins/preauth/spake/iana.c b/src/plugins/preauth/spake/iana.c
+new file mode 100644
+index 000000000..e7901dedf
+--- /dev/null
++++ b/src/plugins/preauth/spake/iana.c
+@@ -0,0 +1,108 @@
++/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
++/* plugins/preauth/spake/iana.c - SPAKE IANA registry contents */
++/*
++ * Copyright (C) 2015 by the Massachusetts Institute of Technology.
++ * 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.
++ */
++
++#include "iana.h"
++
++static uint8_t edwards25519_M[] = {
++    0xD0, 0x48, 0x03, 0x2C, 0x6E, 0xA0, 0xB6, 0xD6, 0x97, 0xDD, 0xC2, 0xE8,
++    0x6B, 0xDA, 0x85, 0xA3, 0x3A, 0xDA, 0xC9, 0x20, 0xF1, 0xBF, 0x18, 0xE1,
++    0xB0, 0xC6, 0xD1, 0x66, 0xA5, 0xCE, 0xCD, 0xAF
++};
++
++static uint8_t edwards25519_N[] = {
++    0xD3, 0xBF, 0xB5, 0x18, 0xF4, 0x4F, 0x34, 0x30, 0xF2, 0x9D, 0x0C, 0x92,
++    0xAF, 0x50, 0x38, 0x65, 0xA1, 0xED, 0x32, 0x81, 0xDC, 0x69, 0xB3, 0x5D,
++    0xD8, 0x68, 0xBA, 0x85, 0xF8, 0x86, 0xC4, 0xAB
++};
++
++static uint8_t P256_M[] = {
++    0x02, 0x88, 0x6E, 0x2F, 0x97, 0xAC, 0xE4, 0x6E, 0x55, 0xBA, 0x9D, 0xD7,
++    0x24, 0x25, 0x79, 0xF2, 0x99, 0x3B, 0x64, 0xE1, 0x6E, 0xF3, 0xDC, 0xAB,
++    0x95, 0xAF, 0xD4, 0x97, 0x33, 0x3D, 0x8F, 0xA1, 0x2F
++};
++
++static uint8_t P256_N[] = {
++    0x03, 0xD8, 0xBB, 0xD6, 0xC6, 0x39, 0xC6, 0x29, 0x37, 0xB0, 0x4D, 0x99,
++    0x7F, 0x38, 0xC3, 0x77, 0x07, 0x19, 0xC6, 0x29, 0xD7, 0x01, 0x4D, 0x49,
++    0xA2, 0x4B, 0x4F, 0x98, 0xBA, 0xA1, 0x29, 0x2B, 0x49
++};
++
++static uint8_t P384_M[] = {
++    0x03, 0x0F, 0xF0, 0x89, 0x5A, 0xE5, 0xEB, 0xF6, 0x18, 0x70, 0x80, 0xA8,
++    0x2D, 0x82, 0xB4, 0x2E, 0x27, 0x65, 0xE3, 0xB2, 0xF8, 0x74, 0x9C, 0x7E,
++    0x05, 0xEB, 0xA3, 0x66, 0x43, 0x4B, 0x36, 0x3D, 0x3D, 0xC3, 0x6F, 0x15,
++    0x31, 0x47, 0x39, 0x07, 0x4D, 0x2E, 0xB8, 0x61, 0x3F, 0xCE, 0xEC, 0x28,
++    0x53
++};
++
++static uint8_t P384_N[] = {
++    0x02, 0xC7, 0x2C, 0xF2, 0xE3, 0x90, 0x85, 0x3A, 0x1C, 0x1C, 0x4A, 0xD8,
++    0x16, 0xA6, 0x2F, 0xD1, 0x58, 0x24, 0xF5, 0x60, 0x78, 0x91, 0x8F, 0x43,
++    0xF9, 0x22, 0xCA, 0x21, 0x51, 0x8F, 0x9C, 0x54, 0x3B, 0xB2, 0x52, 0xC5,
++    0x49, 0x02, 0x14, 0xCF, 0x9A, 0xA3, 0xF0, 0xBA, 0xAB, 0x4B, 0x66, 0x5C,
++    0x10
++};
++
++static uint8_t P521_M[] = {
++    0x02, 0x00, 0x3F, 0x06, 0xF3, 0x81, 0x31, 0xB2, 0xBA, 0x26, 0x00, 0x79,
++    0x1E, 0x82, 0x48, 0x8E, 0x8D, 0x20, 0xAB, 0x88, 0x9A, 0xF7, 0x53, 0xA4,
++    0x18, 0x06, 0xC5, 0xDB, 0x18, 0xD3, 0x7D, 0x85, 0x60, 0x8C, 0xFA, 0xE0,
++    0x6B, 0x82, 0xE4, 0xA7, 0x2C, 0xD7, 0x44, 0xC7, 0x19, 0x19, 0x35, 0x62,
++    0xA6, 0x53, 0xEA, 0x1F, 0x11, 0x9E, 0xEF, 0x93, 0x56, 0x90, 0x7E, 0xDC,
++    0x9B, 0x56, 0x97, 0x99, 0x62, 0xD7, 0xAA
++};
++
++static uint8_t P521_N[] = {
++    0x02, 0x00, 0xC7, 0x92, 0x4B, 0x9E, 0xC0, 0x17, 0xF3, 0x09, 0x45, 0x62,
++    0x89, 0x43, 0x36, 0xA5, 0x3C, 0x50, 0x16, 0x7B, 0xA8, 0xC5, 0x96, 0x38,
++    0x76, 0x88, 0x05, 0x42, 0xBC, 0x66, 0x9E, 0x49, 0x4B, 0x25, 0x32, 0xD7,
++    0x6C, 0x5B, 0x53, 0xDF, 0xB3, 0x49, 0xFD, 0xF6, 0x91, 0x54, 0xB9, 0xE0,
++    0x04, 0x8C, 0x58, 0xA4, 0x2E, 0x8E, 0xD0, 0x4C, 0xEF, 0x05, 0x2A, 0x3B,
++    0xC3, 0x49, 0xD9, 0x55, 0x75, 0xCD, 0x25
++};
++
++const spake_iana spake_iana_edwards25519 = {
++    SPAKE_GROUP_EDWARDS25519, "edwards25519", 32, 32,
++    edwards25519_M, edwards25519_N, 32
++};
++
++const spake_iana spake_iana_p256 = {
++    SPAKE_GROUP_P256, "P-256", 32, 33, P256_M, P256_N, 32
++};
++
++const spake_iana spake_iana_p384 = {
++    SPAKE_GROUP_P384, "P-384", 48, 49, P384_M, P384_N, 48
++};
++
++const spake_iana spake_iana_p521 = {
++    SPAKE_GROUP_P521, "P-521", 66, 67, P521_M, P521_N, 64
++};
+diff --git a/src/plugins/preauth/spake/iana.h b/src/plugins/preauth/spake/iana.h
+new file mode 100644
+index 000000000..1d99c4dd6
+--- /dev/null
++++ b/src/plugins/preauth/spake/iana.h
+@@ -0,0 +1,65 @@
++/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
++/* plugins/preauth/spake/iana.h - SPAKE IANA registry contents */
++/*
++ * Copyright (C) 2015 by the Massachusetts Institute of Technology.
++ * 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.
++ */
++
++#ifndef IANA_H
++#define IANA_H
++
++#include <stdint.h>
++#include <stddef.h>
++
++typedef enum {
++    SPAKE_SF_NONE = 1,
++} spake_sf_type;
++
++typedef enum {
++    SPAKE_GROUP_EDWARDS25519 = 1,
++    SPAKE_GROUP_P256 = 2,
++    SPAKE_GROUP_P384 = 3,
++    SPAKE_GROUP_P521 = 4,
++} spake_group;
++
++typedef struct {
++    int32_t id;
++    const char *name;
++    size_t mult_len;
++    size_t elem_len;
++    const uint8_t *m;
++    const uint8_t *n;
++    size_t hash_len;
++} spake_iana;
++
++extern const spake_iana spake_iana_edwards25519;
++extern const spake_iana spake_iana_p256;
++extern const spake_iana spake_iana_p384;
++extern const spake_iana spake_iana_p521;
++
++#endif /* IANA_H */
+diff --git a/src/plugins/preauth/spake/openssl.c b/src/plugins/preauth/spake/openssl.c
+new file mode 100644
+index 000000000..b821a9158
+--- /dev/null
++++ b/src/plugins/preauth/spake/openssl.c
+@@ -0,0 +1,315 @@
++/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
++/* plugins/preauth/spake/openssl.c - SPAKE implementations using OpenSSL */
++/*
++ * Copyright (C) 2015 by the Massachusetts Institute of Technology.
++ * 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.
++ */
++
++#include "k5-int.h"
++
++#include "groups.h"
++#include "iana.h"
++
++#ifdef SPAKE_OPENSSL
++#include <openssl/bn.h>
++#include <openssl/ec.h>
++#include <openssl/obj_mac.h>
++#include <openssl/evp.h>
++
++/* OpenSSL 1.1 standardizes constructor and destructor names, renaming
++ * EVP_MD_CTX_create and EVP_MD_CTX_destroy. */
++#if OPENSSL_VERSION_NUMBER < 0x10100000L
++#define EVP_MD_CTX_new EVP_MD_CTX_create
++#define EVP_MD_CTX_free EVP_MD_CTX_destroy
++#endif
++
++struct groupdata_st {
++    const groupdef *gdef;
++    EC_GROUP *group;
++    BIGNUM *order;
++    BN_CTX *ctx;
++    EC_POINT *M;
++    EC_POINT *N;
++    const EVP_MD *md;
++};
++
++static void
++ossl_fini(groupdata *gd)
++{
++    if (gd == NULL)
++        return;
++
++    EC_GROUP_free(gd->group);
++    EC_POINT_free(gd->M);
++    EC_POINT_free(gd->N);
++    BN_CTX_free(gd->ctx);
++    BN_free(gd->order);
++}
++
++static krb5_error_code
++ossl_init(krb5_context context, const groupdef *gdef, groupdata **gdata_out)
++{
++    const spake_iana *reg = gdef->reg;
++    const EVP_MD *md;
++    groupdata *gd;
++    int nid;
++
++    switch (reg->id) {
++    case SPAKE_GROUP_P256:
++        nid = NID_X9_62_prime256v1;
++        md = EVP_sha256();
++        break;
++    case SPAKE_GROUP_P384:
++        nid = NID_secp384r1;
++        md = EVP_sha384();
++        break;
++    case SPAKE_GROUP_P521:
++        nid = NID_secp521r1;
++        md = EVP_sha512();
++        break;
++    default:
++        return EINVAL;
++    };
++
++    gd = calloc(1, sizeof(*gd));
++    if (gd == NULL)
++        return ENOMEM;
++    gd->gdef = gdef;
++
++    gd->group = EC_GROUP_new_by_curve_name(nid);
++    if (gd->group == NULL)
++        goto error;
++
++    gd->ctx = BN_CTX_new();
++    if (gd->ctx == NULL)
++        goto error;
++
++    gd->order = BN_new();
++    if (gd->order == NULL)
++        goto error;
++    if (!EC_GROUP_get_order(gd->group, gd->order, gd->ctx))
++        goto error;
++
++    gd->M = EC_POINT_new(gd->group);
++    if (gd->M == NULL)
++        goto error;
++    if (!EC_POINT_oct2point(gd->group, gd->M, reg->m, reg->elem_len, gd->ctx))
++        goto error;
++
++    gd->N = EC_POINT_new(gd->group);
++    if (gd->N == NULL)
++        goto error;
++    if (!EC_POINT_oct2point(gd->group, gd->N, reg->n, reg->elem_len, gd->ctx))
++        goto error;
++
++    gd->md = md;
++
++    *gdata_out = gd;
++    return 0;
++
++error:
++    ossl_fini(gd);
++    return ENOMEM;
++}
++
++/* Convert pseudo-random bytes into a scalar value in constant time.
++ * Return NULL on failure. */
++static BIGNUM *
++unmarshal_w(const groupdata *gdata, const uint8_t *wbytes)
++{
++    const spake_iana *reg = gdata->gdef->reg;
++    BIGNUM *w = NULL;
++
++    w = BN_new();
++    if (w == NULL)
++        return NULL;
++
++    BN_set_flags(w, BN_FLG_CONSTTIME);
++
++    if (BN_bin2bn(wbytes, reg->mult_len, w) &&
++        BN_div(NULL, w, w, gdata->order, gdata->ctx))
++        return w;
++
++    BN_free(w);
++    return NULL;
++}
++
++static krb5_error_code
++ossl_keygen(krb5_context context, groupdata *gdata, const uint8_t *wbytes,
++            krb5_boolean use_m, uint8_t *priv_out, uint8_t *pub_out)
++{
++    const spake_iana *reg = gdata->gdef->reg;
++    const EC_POINT *constant = use_m ? gdata->M : gdata->N;
++    krb5_boolean success = FALSE;
++    EC_POINT *pub = NULL;
++    BIGNUM *priv = NULL, *w = NULL;
++    size_t len;
++
++    w = unmarshal_w(gdata, wbytes);
++    if (w == NULL)
++        goto cleanup;
++
++    pub = EC_POINT_new(gdata->group);
++    if (pub == NULL)
++        goto cleanup;
++
++    priv = BN_new();
++    if (priv == NULL)
++        goto cleanup;
++
++    if (!BN_rand_range(priv, gdata->order))
++        goto cleanup;
++
++    /* Compute priv*G + w*constant; EC_POINT_mul() does this in one call. */
++    if (!EC_POINT_mul(gdata->group, pub, priv, constant, w, gdata->ctx))
++        goto cleanup;
++
++    /* Marshal priv into priv_out. */
++    memset(priv_out, 0, reg->mult_len);
++    BN_bn2bin(priv, &priv_out[reg->mult_len - BN_num_bytes(priv)]);
++
++    /* Marshal pub into pub_out. */
++    len = EC_POINT_point2oct(gdata->group, pub, POINT_CONVERSION_COMPRESSED,
++                             pub_out, reg->elem_len, gdata->ctx);
++    if (len != reg->elem_len)
++        goto cleanup;
++
++    success = TRUE;
++
++cleanup:
++    EC_POINT_free(pub);
++    BN_clear_free(priv);
++    BN_clear_free(w);
++    return success ? 0 : ENOMEM;
++}
++
++static krb5_error_code
++ossl_result(krb5_context context, groupdata *gdata, const uint8_t *wbytes,
++            const uint8_t *ourpriv, const uint8_t *theirpub,
++            krb5_boolean use_m, uint8_t *elem_out)
++{
++    const spake_iana *reg = gdata->gdef->reg;
++    const EC_POINT *constant = use_m ? gdata->M : gdata->N;
++    krb5_boolean success = FALSE, invalid = FALSE;
++    EC_POINT *result = NULL, *pub = NULL;
++    BIGNUM *priv = NULL, *w = NULL;
++    size_t len;
++
++    w = unmarshal_w(gdata, wbytes);
++    if (w == NULL)
++        goto cleanup;
++
++    priv = BN_bin2bn(ourpriv, reg->mult_len, NULL);
++    if (priv == NULL)
++        goto cleanup;
++
++    pub = EC_POINT_new(gdata->group);
++    if (pub == NULL)
++        goto cleanup;
++    if (!EC_POINT_oct2point(gdata->group, pub, theirpub, reg->elem_len,
++                            gdata->ctx)) {
++        invalid = TRUE;
++        goto cleanup;
++    }
++
++    /* Compute result = priv*(pub - w*constant), using result to hold the
++     * intermediate steps. */
++    result = EC_POINT_new(gdata->group);
++    if (result == NULL)
++        goto cleanup;
++    if (!EC_POINT_mul(gdata->group, result, NULL, constant, w, gdata->ctx))
++        goto cleanup;
++    if (!EC_POINT_invert(gdata->group, result, gdata->ctx))
++        goto cleanup;
++    if (!EC_POINT_add(gdata->group, result, pub, result, gdata->ctx))
++        goto cleanup;
++    if (!EC_POINT_mul(gdata->group, result, NULL, result, priv, gdata->ctx))
++        goto cleanup;
++
++    /* Marshal result into elem_out. */
++    len = EC_POINT_point2oct(gdata->group, result, POINT_CONVERSION_COMPRESSED,
++                             elem_out, reg->elem_len, gdata->ctx);
++    if (len != reg->elem_len)
++        goto cleanup;
++
++    success = TRUE;
++
++cleanup:
++    BN_clear_free(priv);
++    BN_clear_free(w);
++    EC_POINT_free(pub);
++    EC_POINT_clear_free(result);
++    return invalid ? EINVAL : (success ? 0 : ENOMEM);
++}
++
++static krb5_error_code
++ossl_hash(krb5_context context, groupdata *gdata, const krb5_data *dlist,
++          size_t ndata, uint8_t *result_out)
++{
++    EVP_MD_CTX *ctx;
++    size_t i;
++    int ok;
++
++    ctx = EVP_MD_CTX_new();
++    if (ctx == NULL)
++        return ENOMEM;
++    ok = EVP_DigestInit_ex(ctx, gdata->md, NULL);
++    for (i = 0; i < ndata; i++)
++        ok = ok && EVP_DigestUpdate(ctx, dlist[i].data, dlist[i].length);
++    ok = ok && EVP_DigestFinal_ex(ctx, result_out, NULL);
++    EVP_MD_CTX_free(ctx);
++    return ok ? 0 : ENOMEM;
++}
++
++groupdef ossl_P256 = {
++    .reg = &spake_iana_p256,
++    .init = ossl_init,
++    .fini = ossl_fini,
++    .keygen = ossl_keygen,
++    .result = ossl_result,
++    .hash = ossl_hash,
++};
++
++groupdef ossl_P384 = {
++    .reg = &spake_iana_p384,
++    .init = ossl_init,
++    .fini = ossl_fini,
++    .keygen = ossl_keygen,
++    .result = ossl_result,
++    .hash = ossl_hash,
++};
++
++groupdef ossl_P521 = {
++    .reg = &spake_iana_p521,
++    .init = ossl_init,
++    .fini = ossl_fini,
++    .keygen = ossl_keygen,
++    .result = ossl_result,
++    .hash = ossl_hash,
++};
++#endif /* SPAKE_OPENSSL */
+diff --git a/src/plugins/preauth/spake/spake.exports b/src/plugins/preauth/spake/spake.exports
+new file mode 100644
+index 000000000..81d100228
+--- /dev/null
++++ b/src/plugins/preauth/spake/spake.exports
+@@ -0,0 +1,2 @@
++clpreauth_spake_initvt
++kdcpreauth_spake_initvt
+diff --git a/src/plugins/preauth/spake/spake_client.c b/src/plugins/preauth/spake/spake_client.c
+new file mode 100644
+index 000000000..d72bd64aa
+--- /dev/null
++++ b/src/plugins/preauth/spake/spake_client.c
+@@ -0,0 +1,363 @@
++/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
++/* plugins/preauth/spake/spake_client.c - SPAKE clpreauth module */
++/*
++ * Copyright (C) 2015 by the Massachusetts Institute of Technology.
++ * 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.
++ */
++
++#include "k5-int.h"
++#include "k5-spake.h"
++#include "trace.h"
++#include "util.h"
++#include "iana.h"
++#include "groups.h"
++#include <krb5/clpreauth_plugin.h>
++
++typedef struct reqstate_st {
++    krb5_keyblock *initial_key;
++    krb5_data *support;
++    krb5_data thash;
++    krb5_data spakeresult;
++} reqstate;
++
++static krb5_error_code
++spake_init(krb5_context context, krb5_clpreauth_moddata *moddata_out)
++{
++    krb5_error_code ret;
++    groupstate *gstate;
++
++    ret = group_init_state(context, FALSE, &gstate);
++    if (ret)
++        return ret;
++    *moddata_out = (krb5_clpreauth_moddata)gstate;
++    return 0;
++}
++
++static void
++spake_fini(krb5_context context, krb5_clpreauth_moddata moddata)
++{
++    group_free_state((groupstate *)moddata);
++}
++
++static void
++spake_request_init(krb5_context context, krb5_clpreauth_moddata moddata,
++                   krb5_clpreauth_modreq *modreq_out)
++{
++    *modreq_out = calloc(1, sizeof(reqstate));
++}
++
++static void
++spake_request_fini(krb5_context context, krb5_clpreauth_moddata moddata,
++                   krb5_clpreauth_modreq modreq)
++{
++    reqstate *st = (reqstate *)modreq;
++
++    krb5_free_keyblock(context, st->initial_key);
++    krb5_free_data(context, st->support);
++    krb5_free_data_contents(context, &st->thash);
++    zapfree(st->spakeresult.data, st->spakeresult.length);
++    free(st);
++}
++
++static krb5_error_code
++spake_prep_questions(krb5_context context, krb5_clpreauth_moddata moddata,
++                     krb5_clpreauth_modreq modreq,
++                     krb5_get_init_creds_opt *opt, krb5_clpreauth_callbacks cb,
++                     krb5_clpreauth_rock rock, krb5_kdc_req *req,
++                     krb5_data *enc_req, krb5_data *enc_prev_req,
++                     krb5_pa_data *pa_data)
++{
++    reqstate *st = (reqstate *)modreq;
++
++    if (st == NULL)
++        return ENOMEM;
++    if (st->initial_key == NULL && pa_data->length > 0)
++        cb->need_as_key(context, rock);
++
++    /* When second-factor is implemented, we should ask questions based on the
++     * factors in the challenge. */
++
++    return 0;
++}
++
++/*
++ * Output a PA-SPAKE support message indicating which groups we support.  This
++ * may be done for optimistic preauth, in response to an empty message, or in
++ * response to a challenge using a group we do not support.  Save the support
++ * message in st->support.
++ */
++static krb5_error_code
++send_support(krb5_context context, groupstate *gstate, reqstate *st,
++             krb5_pa_data ***pa_out)
++{
++    krb5_error_code ret;
++    krb5_data *support;
++    krb5_pa_spake msg;
++
++    msg.choice = SPAKE_MSGTYPE_SUPPORT;
++    group_get_permitted(gstate, &msg.u.support.groups, &msg.u.support.ngroups);
++    ret = encode_krb5_pa_spake(&msg, &support);
++    if (ret)
++        return ret;
++
++    /* Save the support message for later use in the transcript hash. */
++    ret = krb5_copy_data(context, support, &st->support);
++    if (ret) {
++        krb5_free_data(context, support);
++        return ret;
++    }
++
++    TRACE_SPAKE_SEND_SUPPORT(context);
++    return convert_to_padata(support, pa_out);
++}
++
++/* Return true if SF-NONE is present in factors. */
++static krb5_boolean
++contains_sf_none(krb5_spake_factor **factors)
++{
++    int i;
++
++    for (i = 0; factors != NULL && factors[i] != NULL; i++) {
++        if (factors[i]->type == SPAKE_SF_NONE)
++            return TRUE;
++    }
++    return FALSE;
++}
++
++static krb5_error_code
++process_challenge(krb5_context context, groupstate *gstate, reqstate *st,
++                  krb5_spake_challenge *ch, const krb5_data *der_msg,
++                  krb5_clpreauth_callbacks cb, krb5_clpreauth_rock rock,
++                  krb5_prompter_fct prompter, void *prompter_data,
++                  const krb5_data *der_req, krb5_pa_data ***pa_out)
++{
++    krb5_error_code ret;
++    krb5_keyblock *k0 = NULL, *k1 = NULL;
++    krb5_spake_factor factor;
++    krb5_pa_spake msg;
++    krb5_data *der_factor = NULL, *response;
++    krb5_data clpriv = empty_data(), clpub = empty_data();
++    krb5_data wbytes = empty_data();
++    krb5_enc_data enc_factor;
++
++    enc_factor.ciphertext = empty_data();
++
++    /* Not expected if we already computed the SPAKE result. */
++    if (st->spakeresult.length != 0)
++        return KRB5KDC_ERR_PREAUTH_FAILED;
++
++    if (!group_is_permitted(gstate, ch->group)) {
++        TRACE_SPAKE_REJECT_CHALLENGE(context, ch->group);
++        /* No point in sending a second support message. */
++        if (st->support != NULL)
++            return KRB5KDC_ERR_PREAUTH_FAILED;
++        return send_support(context, gstate, st, pa_out);
++    }
++
++    /* Initialize and update the transcript with the concatenation of the
++     * support message (if we sent one) and the received challenge. */
++    ret = update_thash(context, gstate, ch->group, &st->thash, st->support,
++                       der_msg);
++    if (ret)
++        return ret;
++
++    TRACE_SPAKE_RECEIVE_CHALLENGE(context, ch->group, &ch->pubkey);
++
++    /* When second factor support is implemented, we should check for a
++     * supported factor type instead of just checking for SF-NONE. */
++    if (!contains_sf_none(ch->factors))
++        return KRB5KDC_ERR_PREAUTH_FAILED;
++
++    ret = derive_wbytes(context, ch->group, st->initial_key, &wbytes);
++    if (ret)
++        goto cleanup;
++    ret = group_keygen(context, gstate, ch->group, &wbytes, &clpriv, &clpub);
++    if (ret)
++        goto cleanup;
++    ret = group_result(context, gstate, ch->group, &wbytes, &clpriv,
++                       &ch->pubkey, &st->spakeresult);
++    if (ret)
++        goto cleanup;
++
++    ret = update_thash(context, gstate, ch->group, &st->thash, &clpub, NULL);
++    if (ret)
++        goto cleanup;
++    TRACE_SPAKE_CLIENT_THASH(context, &st->thash);
++
++    /* Replace the reply key with K'[0]. */
++    ret = derive_key(context, gstate, ch->group, st->initial_key, &wbytes,
++                     &st->spakeresult, &st->thash, der_req, 0, &k0);
++    if (ret)
++        goto cleanup;
++    ret = cb->set_as_key(context, rock, k0);
++    if (ret)
++        goto cleanup;
++
++    /* Encrypt a SPAKESecondFactor message with K'[1]. */
++    ret = derive_key(context, gstate, ch->group, st->initial_key, &wbytes,
++                     &st->spakeresult, &st->thash, der_req, 1, &k1);
++    if (ret)
++        goto cleanup;
++    /* When second factor support is implemented, we should construct an
++     * appropriate factor here instead of hardcoding SF-NONE. */
++    factor.type = SPAKE_SF_NONE;
++    factor.data = NULL;
++    ret = encode_krb5_spake_factor(&factor, &der_factor);
++    if (ret)
++        goto cleanup;
++    ret = krb5_encrypt_helper(context, k1, KRB5_KEYUSAGE_SPAKE, der_factor,
++                              &enc_factor);
++    if (ret)
++        goto cleanup;
++
++    /* Encode and output a response message. */
++    msg.choice = SPAKE_MSGTYPE_RESPONSE;
++    msg.u.response.pubkey = clpub;
++    msg.u.response.factor = enc_factor;
++    ret = encode_krb5_pa_spake(&msg, &response);
++    if (ret)
++        goto cleanup;
++    TRACE_SPAKE_SEND_RESPONSE(context);
++    ret = convert_to_padata(response, pa_out);
++
++cleanup:
++    krb5_free_keyblock(context, k0);
++    krb5_free_keyblock(context, k1);
++    krb5_free_data_contents(context, &enc_factor.ciphertext);
++    krb5_free_data_contents(context, &clpub);
++    zapfree(clpriv.data, clpriv.length);
++    zapfree(wbytes.data, wbytes.length);
++    if (der_factor != NULL) {
++        zapfree(der_factor->data, der_factor->length);
++        free(der_factor);
++    }
++    return ret;
++}
++
++static krb5_error_code
++process_encdata(krb5_context context, reqstate *st, krb5_enc_data *enc,
++                krb5_clpreauth_callbacks cb, krb5_clpreauth_rock rock,
++                krb5_prompter_fct prompter, void *prompter_data,
++                const krb5_data *der_prev_req, const krb5_data *der_req,
++                krb5_pa_data ***pa_out)
++{
++    /* Not expected if we haven't sent a response yet. */
++    if (st->spakeresult.length == 0)
++        return KRB5KDC_ERR_PREAUTH_FAILED;
++
++    /*
++     * When second factor support is implemented, we should process encdata
++     * messages according to the factor type.  We should make sure to re-derive
++     * K'[0] and replace the reply key again, in case the request has changed.
++     * We should use der_prev_req to derive K'[n] to decrypt factor from the
++     * KDC.  We should use der_req to derive K'[n+1] for the next message to
++     * send to the KDC.
++     */
++    return KRB5_PLUGIN_OP_NOTSUPP;
++}
++
++static krb5_error_code
++spake_process(krb5_context context, krb5_clpreauth_moddata moddata,
++              krb5_clpreauth_modreq modreq, krb5_get_init_creds_opt *opt,
++              krb5_clpreauth_callbacks cb, krb5_clpreauth_rock rock,
++              krb5_kdc_req *req, krb5_data *der_req, krb5_data *der_prev_req,
++              krb5_pa_data *pa_in, krb5_prompter_fct prompter,
++              void *prompter_data, krb5_pa_data ***pa_out)
++{
++    krb5_error_code ret;
++    groupstate *gstate = (groupstate *)moddata;
++    reqstate *st = (reqstate *)modreq;
++    krb5_pa_spake *msg;
++    krb5_data in_data;
++    krb5_keyblock *as_key;
++
++    if (st == NULL)
++        return ENOMEM;
++
++    if (pa_in->length == 0) {
++        /* Not expected if we already sent a support message. */
++        if (st->support != NULL)
++            return KRB5KDC_ERR_PREAUTH_FAILED;
++        return send_support(context, gstate, st, pa_out);
++    }
++
++    /* We need the initial reply key to process any non-trivial message. */
++    if (st->initial_key == NULL) {
++        ret = cb->get_as_key(context, rock, &as_key);
++        if (ret)
++            return ret;
++        ret = krb5_copy_keyblock(context, as_key, &st->initial_key);
++        if (ret)
++            return ret;
++    }
++
++    in_data = make_data(pa_in->contents, pa_in->length);
++    ret = decode_krb5_pa_spake(&in_data, &msg);
++    if (ret)
++        return ret;
++
++    if (msg->choice == SPAKE_MSGTYPE_CHALLENGE) {
++        ret = process_challenge(context, gstate, st, &msg->u.challenge,
++                                &in_data, cb, rock, prompter, prompter_data,
++                                der_req, pa_out);
++    } else if (msg->choice == SPAKE_MSGTYPE_ENCDATA) {
++        ret = process_encdata(context, st, &msg->u.encdata, cb, rock, prompter,
++                              prompter_data, der_prev_req, der_req, pa_out);
++    } else {
++        /* Unexpected message type */
++        ret = KRB5KDC_ERR_PREAUTH_FAILED;
++    }
++
++    k5_free_pa_spake(context, msg);
++    return ret;
++}
++
++krb5_error_code
++clpreauth_spake_initvt(krb5_context context, int maj_ver, int min_ver,
++                       krb5_plugin_vtable vtable);
++
++krb5_error_code
++clpreauth_spake_initvt(krb5_context context, int maj_ver, int min_ver,
++                       krb5_plugin_vtable vtable)
++{
++    krb5_clpreauth_vtable vt;
++    static krb5_preauthtype pa_types[] = { KRB5_PADATA_SPAKE, 0 };
++
++    if (maj_ver != 1)
++        return KRB5_PLUGIN_VER_NOTSUPP;
++    vt = (krb5_clpreauth_vtable)vtable;
++    vt->name = "spake";
++    vt->pa_type_list = pa_types;
++    vt->init = spake_init;
++    vt->fini = spake_fini;
++    vt->request_init = spake_request_init;
++    vt->request_fini = spake_request_fini;
++    vt->process = spake_process;
++    vt->prep_questions = spake_prep_questions;
++    return 0;
++}
+diff --git a/src/plugins/preauth/spake/spake_kdc.c b/src/plugins/preauth/spake/spake_kdc.c
+new file mode 100644
+index 000000000..c1723ebaf
+--- /dev/null
++++ b/src/plugins/preauth/spake/spake_kdc.c
+@@ -0,0 +1,590 @@
++/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
++/* plugins/preauth/spake/spake_kdc.c - SPAKE kdcpreauth module */
++/*
++ * Copyright (C) 2015 by the Massachusetts Institute of Technology.
++ * 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.
++ */
++
++#include "k5-int.h"
++#include "k5-input.h"
++#include "k5-spake.h"
++
++#include "groups.h"
++#include "trace.h"
++#include "iana.h"
++#include "util.h"
++
++#include <krb5/kdcpreauth_plugin.h>
++
++/*
++ * The SPAKE kdcpreauth module uses a secure cookie containing the following
++ * concatenated fields (all integer fields are big-endian):
++ *
++ *     version (16-bit unsigned integer)
++ *     stage (16-bit unsigned integer)
++ *     group (32-bit signed integer)
++ *     SPAKE value (32-bit unsigned length, followed by data)
++ *     Transcript hash (32-bit unsigned length, followed by data)
++ *     Zero or more instances of:
++ *         second-factor number (32-bit signed integer)
++ *         second-factor data (32-bit unsigned length, followed by data)
++ *
++ * The only currently supported version is 1.  stage is 0 if the cookie was
++ * sent with a challenge message.  stage is n>0 if the cookie was sent with an
++ * encdata message encrypted in K'[2n].  group indicates the group number used
++ * in the SPAKE challenge.  The SPAKE value is the KDC private key for a
++ * stage-0 cookie, represented in the scalar marshalling form of the group; for
++ * other cookies, the SPAKE value is the SPAKE result K, represented in the
++ * group element marshalling form.  The transcript hash is the intermediate
++ * hash after updating with the support and challenge messages for a stage-0
++ * cookie, or the final hash for other cookies.  For a stage 0 cookie, there
++ * may be any number of second-factor records, including none (no record is
++ * generated for SF-NONE); for other cookies, there must be exactly one
++ * second-factor record corresponding to the factor type chosen by the client.
++ */
++
++/* From a k5input structure representing the remainder of a secure cookie
++ * plaintext, parse a four-byte length and data. */
++static void
++parse_data(struct k5input *in, krb5_data *out)
++{
++    out->length = k5_input_get_uint32_be(in);
++    out->data = (char *)k5_input_get_bytes(in, out->length);
++}
++
++/* Parse a received cookie into its components.  The pointers stored in the
++ * krb5_data outputs are aliases into cookie and should not be freed. */
++static krb5_error_code
++parse_cookie(const krb5_data *cookie, int *stage_out, int32_t *group_out,
++             krb5_data *spake_out, krb5_data *thash_out,
++             krb5_data *factors_out)
++{
++    struct k5input in;
++    int version, stage;
++    int32_t group;
++    krb5_data thash, spake, factors;
++
++    *spake_out = *thash_out = *factors_out = empty_data();
++    k5_input_init(&in, cookie->data, cookie->length);
++
++    /* Parse and check the version, and read the other integer fields. */
++    version = k5_input_get_uint16_be(&in);
++    if (version != 1)
++        return KRB5KDC_ERR_PREAUTH_FAILED;
++    stage = k5_input_get_uint16_be(&in);
++    group = k5_input_get_uint32_be(&in);
++
++    /* Parse the data fields.  The factor data is anything remaining after the
++     * transcript hash. */
++    parse_data(&in, &spake);
++    parse_data(&in, &thash);
++    if (in.status)
++        return in.status;
++    factors = make_data((char *)in.ptr, in.len);
++
++    *stage_out = stage;
++    *group_out = group;
++    *spake_out = spake;
++    *thash_out = thash;
++    *factors_out = factors;
++    return 0;
++}
++
++/* Marshal data into buf as a four-byte length followed by the contents. */
++static void
++marshal_data(struct k5buf *buf, const krb5_data *data)
++{
++    uint8_t lenbuf[4];
++
++    store_32_be(data->length, lenbuf);
++    k5_buf_add_len(buf, lenbuf, 4);
++    k5_buf_add_len(buf, data->data, data->length);
++}
++
++/* Marshal components into a cookie. */
++static krb5_error_code
++make_cookie(int stage, int32_t group, const krb5_data *spake,
++            const krb5_data *thash, krb5_data *cookie_out)
++{
++    struct k5buf buf;
++    uint8_t intbuf[4];
++
++    *cookie_out = empty_data();
++    k5_buf_init_dynamic_zap(&buf);
++
++    /* Marshal the version, stage, and group. */
++    store_16_be(1, intbuf);
++    k5_buf_add_len(&buf, intbuf, 2);
++    store_16_be(stage, intbuf);
++    k5_buf_add_len(&buf, intbuf, 2);
++    store_32_be(group, intbuf);
++    k5_buf_add_len(&buf, intbuf, 4);
++
++    /* Marshal the data fields. */
++    marshal_data(&buf, spake);
++    marshal_data(&buf, thash);
++
++    /* When second factor support is implemented, we should add factor data
++     * here. */
++
++    if (buf.data == NULL)
++        return ENOMEM;
++    *cookie_out = make_data(buf.data, buf.len);
++    return 0;
++}
++
++/* Add authentication indicators if any are configured for SPAKE. */
++static krb5_error_code
++add_indicators(krb5_context context, const krb5_data *realm,
++               krb5_kdcpreauth_callbacks cb, krb5_kdcpreauth_rock rock)
++{
++    krb5_error_code ret;
++    const char *keys[4];
++    char *realmstr, **indicators, **ind;
++
++    realmstr = k5memdup0(realm->data, realm->length, &ret);
++    if (realmstr == NULL)
++        return ret;
++    keys[0] = KRB5_CONF_REALMS;
++    keys[1] = realmstr;
++    keys[2] = KRB5_CONF_SPAKE_PREAUTH_INDICATOR;
++    keys[3] = NULL;
++    ret = profile_get_values(context->profile, keys, &indicators);
++    free(realmstr);
++    if (ret == PROF_NO_RELATION)
++        return 0;
++    if (ret)
++        return ret;
++
++    for (ind = indicators; *ind != NULL && !ret; ind++)
++        ret = cb->add_auth_indicator(context, rock, *ind);
++
++    profile_free_list(indicators);
++    return ret;
++}
++
++/* Initialize a SPAKE module data object. */
++static krb5_error_code
++spake_init(krb5_context context, krb5_kdcpreauth_moddata *moddata_out,
++           const char **realmnames)
++{
++    krb5_error_code ret;
++    groupstate *gstate;
++
++    ret = group_init_state(context, TRUE, &gstate);
++    if (ret)
++        return ret;
++    *moddata_out = (krb5_kdcpreauth_moddata)gstate;
++    return 0;
++}
++
++/* Release a SPAKE module data object. */
++static void
++spake_fini(krb5_context context, krb5_kdcpreauth_moddata moddata)
++{
++    group_free_state((groupstate *)moddata);
++}
++
++/*
++ * Generate a SPAKE challenge message for the specified group.  Use cb and rock
++ * to retrieve the initial reply key and to set a stage-0 cookie.  Invoke
++ * either erespond or vrespond with the result.
++ */
++static void
++send_challenge(krb5_context context, groupstate *gstate, int32_t group,
++               krb5_kdcpreauth_callbacks cb, krb5_kdcpreauth_rock rock,
++               const krb5_data *support,
++               krb5_kdcpreauth_edata_respond_fn erespond,
++               krb5_kdcpreauth_verify_respond_fn vrespond, void *arg)
++{
++    krb5_error_code ret;
++    const krb5_keyblock *ikey;
++    krb5_pa_data **padata = NULL, *pa;
++    krb5_data kdcpriv = empty_data(), kdcpub = empty_data(), *der_msg = NULL;
++    krb5_data thash = empty_data(), cookie = empty_data();
++    krb5_data wbytes = empty_data();
++    krb5_spake_factor f, *flist[2];
++    krb5_pa_spake msg;
++
++    ikey = cb->client_keyblock(context, rock);
++    if (ikey == NULL) {
++        ret = KRB5KDC_ERR_ETYPE_NOSUPP;
++        goto cleanup;
++    }
++
++    ret = derive_wbytes(context, group, ikey, &wbytes);
++    if (ret)
++        goto cleanup;
++    ret = group_keygen(context, gstate, group, &wbytes, &kdcpriv, &kdcpub);
++    if (ret)
++        goto cleanup;
++
++    /* Encode the challenge.  When second factor support is implemented, we
++     * should construct a factor list instead of hardcoding SF-NONE. */
++    f.type = SPAKE_SF_NONE;
++    f.data = NULL;
++    flist[0] = &f;
++    flist[1] = NULL;
++    msg.choice = SPAKE_MSGTYPE_CHALLENGE;
++    msg.u.challenge.group = group;
++    msg.u.challenge.pubkey = kdcpub;
++    msg.u.challenge.factors = flist;
++    ret = encode_krb5_pa_spake(&msg, &der_msg);
++    if (ret)
++        goto cleanup;
++
++    /* Initialize and update the transcript hash with the support message (if
++     * we received one) and challenge message. */
++    ret = update_thash(context, gstate, group, &thash, support, der_msg);
++    if (ret)
++        goto cleanup;
++
++    /* Save the group, transcript hash, and private key in a stage-0 cookie.
++     * When second factor support is implemented, also save factor state. */
++    ret = make_cookie(0, group, &kdcpriv, &thash, &cookie);
++    if (ret)
++        goto cleanup;
++    ret = cb->set_cookie(context, rock, KRB5_PADATA_SPAKE, &cookie);
++    if (ret)
++        goto cleanup;
++
++    ret = convert_to_padata(der_msg, &padata);
++    der_msg = NULL;
++    TRACE_SPAKE_SEND_CHALLENGE(context, group);
++
++cleanup:
++    zapfree(wbytes.data, wbytes.length);
++    zapfree(kdcpriv.data, kdcpriv.length);
++    zapfree(cookie.data, cookie.length);
++    krb5_free_data_contents(context, &kdcpub);
++    krb5_free_data_contents(context, &thash);
++    krb5_free_data(context, der_msg);
++
++    if (erespond != NULL) {
++        assert(vrespond == NULL);
++        /* Grab the first pa-data element from the list, if we made one. */
++        pa = (padata == NULL) ? NULL : padata[0];
++        free(padata);
++        (*erespond)(arg, ret, pa);
++    } else {
++        assert(vrespond != NULL);
++        if (!ret)
++            ret = KRB5KDC_ERR_MORE_PREAUTH_DATA_REQUIRED;
++        (*vrespond)(arg, ret, NULL, padata, NULL);
++    }
++}
++
++/* Generate the METHOD-DATA entry indicating support for SPAKE.  Include an
++ * optimistic challenge if configured to do so. */
++static void
++spake_edata(krb5_context context, krb5_kdc_req *req,
++            krb5_kdcpreauth_callbacks cb, krb5_kdcpreauth_rock rock,
++            krb5_kdcpreauth_moddata moddata, krb5_preauthtype pa_type,
++            krb5_kdcpreauth_edata_respond_fn respond, void *arg)
++{
++    const krb5_keyblock *ikey;
++    groupstate *gstate = (groupstate *)moddata;
++    krb5_data empty = empty_data();
++    int32_t group;
++
++    /* SPAKE requires a client key, which cannot be a single-DES key. */
++    ikey = cb->client_keyblock(context, rock);
++    if (ikey == NULL) {
++        (*respond)(arg, KRB5KDC_ERR_ETYPE_NOSUPP, NULL);
++        return;
++    }
++
++    group = group_optimistic_challenge(gstate);
++    if (group) {
++        send_challenge(context, gstate, group, cb, rock, &empty, respond, NULL,
++                       arg);
++    } else {
++        /* No optimistic challenge configured; send an empty pa-data value. */
++        (*respond)(arg, 0, NULL);
++    }
++}
++
++/* Choose a group from the client's support message and generate a
++ * challenge. */
++static void
++verify_support(krb5_context context, groupstate *gstate,
++               krb5_spake_support *support, const krb5_data *der_msg,
++               krb5_kdcpreauth_callbacks cb, krb5_kdcpreauth_rock rock,
++               krb5_kdcpreauth_verify_respond_fn respond, void *arg)
++{
++    krb5_error_code ret;
++    int32_t i, group;
++
++    for (i = 0; i < support->ngroups; i++) {
++        if (group_is_permitted(gstate, support->groups[i]))
++            break;
++    }
++    if (i == support->ngroups) {
++        TRACE_SPAKE_REJECT_SUPPORT(context);
++        ret = KRB5KDC_ERR_PREAUTH_FAILED;
++        goto error;
++    }
++    group = support->groups[i];
++    TRACE_SPAKE_RECEIVE_SUPPORT(context, group);
++
++    send_challenge(context, gstate, group, cb, rock, der_msg, NULL, respond,
++                   arg);
++    return;
++
++error:
++    (*respond)(arg, ret, NULL, NULL, NULL);
++}
++
++/*
++ * From the client's response message, compute the SPAKE result and decrypt the
++ * factor reply.  On success, either mark the reply as pre-authenticated and
++ * set a reply key in the pre-request module data, or generate an additional
++ * factor challenge and ask for another round of pre-authentication.
++ */
++static void
++verify_response(krb5_context context, groupstate *gstate,
++                krb5_spake_response *resp, const krb5_data *realm,
++                krb5_kdcpreauth_callbacks cb, krb5_kdcpreauth_rock rock,
++                krb5_enc_tkt_part *enc_tkt_reply,
++                krb5_kdcpreauth_verify_respond_fn respond, void *arg)
++{
++    krb5_error_code ret;
++    const krb5_keyblock *ikey;
++    krb5_keyblock *k1 = NULL, *reply_key = NULL;
++    krb5_data cookie, thash_in, kdcpriv, factors, *der_req;
++    krb5_data thash = empty_data(), der_factor = empty_data();
++    krb5_data wbytes = empty_data(), spakeresult = empty_data();
++    krb5_spake_factor *factor = NULL;
++    int stage;
++    int32_t group;
++
++    ikey = cb->client_keyblock(context, rock);
++    if (ikey == NULL) {
++        ret = KRB5KDC_ERR_ETYPE_NOSUPP;
++        goto cleanup;
++    }
++
++    /* Fetch the stage-0 cookie and parse it.  (All of the krb5_data results
++     * are aliases into memory owned by rock). */
++    if (!cb->get_cookie(context, rock, KRB5_PADATA_SPAKE, &cookie)) {
++        ret = KRB5KDC_ERR_PREAUTH_FAILED;
++        goto cleanup;
++    }
++    ret = parse_cookie(&cookie, &stage, &group, &kdcpriv, &thash_in, &factors);
++    if (ret)
++        goto cleanup;
++    if (stage != 0) {
++        /* The received cookie wasn't sent with a challenge. */
++        ret = KRB5KDC_ERR_PREAUTH_FAILED;
++        goto cleanup;
++    }
++    TRACE_SPAKE_RECEIVE_RESPONSE(context, &resp->pubkey);
++
++    /* Update the transcript hash with the client public key. */
++    ret = krb5int_copy_data_contents(context, &thash_in, &thash);
++    if (ret)
++        goto cleanup;
++    ret = update_thash(context, gstate, group, &thash, &resp->pubkey, NULL);
++    if (ret)
++        goto cleanup;
++    TRACE_SPAKE_KDC_THASH(context, &thash);
++
++    ret = derive_wbytes(context, group, ikey, &wbytes);
++    if (ret)
++        goto cleanup;
++    ret = group_result(context, gstate, group, &wbytes, &kdcpriv,
++                       &resp->pubkey, &spakeresult);
++    if (ret)
++        goto cleanup;
++
++    /* Decrypt the response factor field using K'[1].  If the decryption
++     * integrity check fails, the client probably used the wrong password. */
++    der_req = cb->request_body(context, rock);
++    ret = derive_key(context, gstate, group, ikey, &wbytes, &spakeresult,
++                     &thash, der_req, 1, &k1);
++    if (ret)
++        goto cleanup;
++    ret = alloc_data(&der_factor, resp->factor.ciphertext.length);
++    if (ret)
++        goto cleanup;
++    ret = krb5_c_decrypt(context, k1, KRB5_KEYUSAGE_SPAKE, NULL, &resp->factor,
++                         &der_factor);
++    if (ret == KRB5KRB_AP_ERR_BAD_INTEGRITY)
++        ret = KRB5KDC_ERR_PREAUTH_FAILED;
++    if (ret)
++        goto cleanup;
++    ret = decode_krb5_spake_factor(&der_factor, &factor);
++    if (ret)
++        goto cleanup;
++
++    /*
++     * When second factor support is implemented, we should verify the factor
++     * data here, and possibly generate an encdata message for another hop.
++     * This function may need to be split at this point to allow for
++     * asynchronous verification of the second-factor value.  We might also
++     * need to collect authentication indicators from the second-factor module;
++     * alternatively the module could have access to cb and rock so that it can
++     * add indicators itself.
++     */
++    if (factor->type != SPAKE_SF_NONE) {
++        ret = KRB5KDC_ERR_PREAUTH_FAILED;
++        goto cleanup;
++    }
++
++    ret = add_indicators(context, realm, cb, rock);
++    if (ret)
++        goto cleanup;
++
++    enc_tkt_reply->flags |= TKT_FLG_PRE_AUTH;
++
++    ret = derive_key(context, gstate, group, ikey, &wbytes, &spakeresult,
++                     &thash, der_req, 0, &reply_key);
++
++cleanup:
++    zapfree(wbytes.data, wbytes.length);
++    zapfree(der_factor.data, der_factor.length);
++    zapfree(spakeresult.data, spakeresult.length);
++    krb5_free_data_contents(context, &thash);
++    krb5_free_keyblock(context, k1);
++    k5_free_spake_factor(context, factor);
++    (*respond)(arg, ret, (krb5_kdcpreauth_modreq)reply_key, NULL, NULL);
++}
++
++/*
++ * Decrypt and validate an additional second-factor reply.  On success, either
++ * mark the reply as pre-authenticated and set a reply key in the pre-request
++ * module data, or generate an additional factor challenge and ask for another
++ * round of pre-authentication.
++ */
++static void
++verify_encdata(krb5_context context, krb5_enc_data *enc,
++               krb5_kdcpreauth_callbacks cb, krb5_kdcpreauth_rock rock,
++               krb5_enc_tkt_part *enc_tkt_reply,
++               krb5_kdcpreauth_verify_respond_fn respond, void *arg)
++{
++    /*
++     * When second factor support is implemented, we should process encdata
++     * message according to the factor type recorded in the cookie.  If the
++     * second factor exchange finishes successfully, we should set
++     * TKT_FLG_PRE_AUTH, set the reply key to K'[0], and add any auth
++     * indicators from configuration (with a call to add_indicators()) or the
++     * second factor module (unless the module has access to cb and rock and
++     * can add indicators itself).
++     */
++    (*respond)(arg, KRB5KDC_ERR_PREAUTH_FAILED, NULL, NULL, NULL);
++}
++
++/*
++ * Respond to a client padata message, either by generating a SPAKE challenge,
++ * generating an additional second-factor challenge, or marking the reply as
++ * pre-authenticated and setting an additional reply key in the pre-request
++ * module data.
++ */
++static void
++spake_verify(krb5_context context, krb5_data *req_pkt, krb5_kdc_req *request,
++             krb5_enc_tkt_part *enc_tkt_reply, krb5_pa_data *data,
++             krb5_kdcpreauth_callbacks cb, krb5_kdcpreauth_rock rock,
++             krb5_kdcpreauth_moddata moddata,
++             krb5_kdcpreauth_verify_respond_fn respond, void *arg)
++{
++    krb5_error_code ret;
++    krb5_pa_spake *pa_spake = NULL;
++    krb5_data in_data = make_data(data->contents, data->length);
++    groupstate *gstate = (groupstate *)moddata;
++
++    ret = decode_krb5_pa_spake(&in_data, &pa_spake);
++    if (ret) {
++        (*respond)(arg, ret, NULL, NULL, NULL);
++    } else if (pa_spake->choice == SPAKE_MSGTYPE_SUPPORT) {
++        verify_support(context, gstate, &pa_spake->u.support, &in_data, cb,
++                       rock, respond, arg);
++    } else if (pa_spake->choice == SPAKE_MSGTYPE_RESPONSE) {
++        verify_response(context, gstate, &pa_spake->u.response,
++                        &request->server->realm, cb, rock, enc_tkt_reply,
++                        respond, arg);
++    } else if (pa_spake->choice == SPAKE_MSGTYPE_ENCDATA) {
++        verify_encdata(context, &pa_spake->u.encdata, cb, rock, enc_tkt_reply,
++                       respond, arg);
++    } else {
++        ret = KRB5KDC_ERR_PREAUTH_FAILED;
++        k5_setmsg(context, ret, _("Unknown SPAKE request type"));
++        (*respond)(arg, ret, NULL, NULL, NULL);
++    }
++
++    k5_free_pa_spake(context, pa_spake);
++}
++
++/* If a key was set in the per-request module data, replace the reply key.  Do
++ * not generate any pa-data to include with the KDC reply. */
++static krb5_error_code
++spake_return(krb5_context context, krb5_pa_data *padata, krb5_data *req_pkt,
++             krb5_kdc_req *request, krb5_kdc_rep *reply,
++             krb5_keyblock *encrypting_key, krb5_pa_data **send_pa_out,
++             krb5_kdcpreauth_callbacks cb, krb5_kdcpreauth_rock rock,
++             krb5_kdcpreauth_moddata moddata, krb5_kdcpreauth_modreq modreq)
++{
++    krb5_keyblock *reply_key = (krb5_keyblock *)modreq;
++
++    if (reply_key == NULL)
++        return 0;
++    krb5_free_keyblock_contents(context, encrypting_key);
++    return krb5_copy_keyblock_contents(context, reply_key, encrypting_key);
++}
++
++/* Release a per-request module data object. */
++static void
++spake_free_modreq(krb5_context context, krb5_kdcpreauth_moddata moddata,
++                  krb5_kdcpreauth_modreq modreq)
++{
++    krb5_free_keyblock(context, (krb5_keyblock *)modreq);
++}
++
++krb5_error_code
++kdcpreauth_spake_initvt(krb5_context context, int maj_ver, int min_ver,
++                        krb5_plugin_vtable vtable);
++
++krb5_error_code
++kdcpreauth_spake_initvt(krb5_context context, int maj_ver, int min_ver,
++                        krb5_plugin_vtable vtable)
++{
++    krb5_kdcpreauth_vtable vt;
++    static krb5_preauthtype pa_types[] = { KRB5_PADATA_SPAKE, 0 };
++
++    if (maj_ver != 1)
++        return KRB5_PLUGIN_VER_NOTSUPP;
++    vt = (krb5_kdcpreauth_vtable)vtable;
++    vt->name = "spake";
++    vt->pa_type_list = pa_types;
++    vt->init = spake_init;
++    vt->fini = spake_fini;
++    vt->edata = spake_edata;
++    vt->verify = spake_verify;
++    vt->return_padata = spake_return;
++    vt->free_modreq = spake_free_modreq;
++    return 0;
++}
+diff --git a/src/plugins/preauth/spake/t_krb5.conf b/src/plugins/preauth/spake/t_krb5.conf
+new file mode 100644
+index 000000000..65fdaec63
+--- /dev/null
++++ b/src/plugins/preauth/spake/t_krb5.conf
+@@ -0,0 +1,2 @@
++[libdefaults]
++	spake_preauth_groups = edwards25519
+diff --git a/src/plugins/preauth/spake/t_vectors.c b/src/plugins/preauth/spake/t_vectors.c
+new file mode 100644
+index 000000000..2279202d3
+--- /dev/null
++++ b/src/plugins/preauth/spake/t_vectors.c
+@@ -0,0 +1,476 @@
++/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
++/* plugins/preauth/spake/t_vectors.c - SPAKE test vector verification */
++/*
++ * Copyright (C) 2015 by the Massachusetts Institute of Technology.
++ * 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.
++ */
++
++#include "k5-int.h"
++#include "k5-hex.h"
++#include "groups.h"
++#include "iana.h"
++#include "util.h"
++#include <ctype.h>
++
++struct test {
++    krb5_enctype enctype;
++    int32_t group;
++    const char *ikey;
++    const char *w;
++    const char *x;
++    const char *y;
++    const char *T;
++    const char *S;
++    const char *K;
++    const char *support;
++    const char *challenge;
++    const char *thash;
++    const char *body;
++    const char *K0;
++    const char *K1;
++    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",
++      "7C86659D29CF2B2EA93BFE79C3CEFB8850E82215B3EA6FCD896561D48048F49C",
++      "C8A62E7B626F44CAD807B2D695450697E020D230A738C5CD5691CC781DCE8754",
++      "18FE7C1512708C7FD06DB270361F04593775BC634CEAF45347E5C11C38AAE017",
++      "7DB465F1C08C64983A19F560BCE966FE5306C4B447F70A5BCA14612A92DA1D63",
++      "38F8D4568090148EBC9FD17C241B4CC2769505A7CA6F3F7104417B72B5B5CF54",
++      "03E75EDD2CD7E7677642DD68736E91700953AC55DC650E3C2A1B3B4ACDB800F8",
++      /* support, challenge, thash, body */
++      "A0093007A0053003020101",
++      "A1363034A003020101A12204207DB465F1C08C64983A19F560BCE966FE5306C4"
++      "B447F70A5BCA14612A92DA1D63A20930073005A003020101",
++      "F4B208458017DE6EF7F6A307D47D87DB6C2AF1D291B726860F68BC08BFEF440A",
++      "3075A00703050000000000A1143012A003020101A10B30091B07726165627572"
++      "6EA2101B0E415448454E412E4D49542E454455A3233021A003020102A11A3018"
++      "1B066B72627467741B0E415448454E412E4D49542E454455A511180F31393730"
++      "303130313030303030305AA703020100A8053003020117",
++      /* K'[0], K'[1], K'[2], K'[3] */
++      "770B720C82384CBB693E85411EEDECBA",
++      "621DEEC88E2865837C4D3462BB50A1D5",
++      "1CC8F6333B9FA3B42662FD9914FBD5BB",
++      "EDB4032B7FC3806D5211A534DCBC390C",
++    },
++
++    { ENCTYPE_AES128_CTS_HMAC_SHA1_96, SPAKE_GROUP_EDWARDS25519,
++      /* initial key, w, x, y, T, S, K */
++      "FCA822951813FB252154C883F5EE1CF4",
++      "0D591B197B667E083C2F5F98AC891D3C9F99E710E464E62F1FB7C9B67936F3EB",
++      "50BE049A5A570FA1459FB9F666E6FD80602E4E87790A0E567F12438A2C96C138",
++      "B877AFE8612B406D96BE85BD9F19D423E95BE96C0E1E0B5824127195C3ED5917",
++      "9E9311D985C1355E022D7C3C694AD8D6F7AD6D647B68A90B0FE46992818002DA",
++      "FBE08F7F96CD5D4139E7C9ECCB95E79B8ACE41E270A60198C007DF18525B628E",
++      "C2F7F99997C585E6B686CEB62DB42F17CC70932DEF3BB4CF009E36F22EA5473D",
++      /* support, challenge, thash, body */
++      "A0093007A0053003020101",
++      "A1363034A003020101A12204209E9311D985C1355E022D7C3C694AD8D6F7AD6D"
++      "647B68A90B0FE46992818002DAA20930073005A003020101",
++      "951285F107C87F0169B9C918A1F51F60CB1A75B9F8BB799A99F53D03ADD94B5F",
++      "3075A00703050000000000A1143012A003020101A10B30091B07726165627572"
++      "6EA2101B0E415448454E412E4D49542E454455A3233021A003020102A11A3018"
++      "1B066B72627467741B0E415448454E412E4D49542E454455A511180F31393730"
++      "303130313030303030305AA703020100A8053003020111",
++      /* K'[0], K'[1], K'[2], K'[3] */
++      "548022D58A7C47EAE8C49DCCF6BAA407",
++      "B2C9BA0E13FC8AB3A9D96B51B601CF4A",
++      "69F0EE5FDB6C237E7FCD38D9F87DF1BD",
++      "78F91E2240B5EE528A5CC8D7CBEBFBA5",
++    },
++    { ENCTYPE_AES256_CTS_HMAC_SHA1_96, SPAKE_GROUP_EDWARDS25519,
++      /* initial key, w, x, y, T, S, K */
++      "01B897121D933AB44B47EB5494DB15E50EB74530DBDAE9B634D65020FF5D88C1",
++      "E902341590A1B4BB4D606A1C643CCCB3F2108F1B6AA97B381012B9400C9E3F4E",
++      "88C6C0A4F0241EF217C9788F02C32D00B72E4310748CD8FB5F94717607E6417D",
++      "88B859DF58EF5C69BACDFE681C582754EAAB09A74DC29CFF50B328613C232F55",
++      "6F301AACAE1220E91BE42868C163C5009AEEA1E9D9E28AFCFC339CDA5E7105B5",
++      "9E2CC32908FC46273279EC75354B4AEAFA70C3D99A4D507175ED70D80B255DDA",
++      "CF57F58F6E60169D2ECC8F20BB923A8E4C16E5BC95B9E64B5DC870DA7026321B",
++      /* support, challenge, thash, body */
++      "A0093007A0053003020101",
++      "A1363034A003020101A12204206F301AACAE1220E91BE42868C163C5009AEEA1"
++      "E9D9E28AFCFC339CDA5E7105B5A20930073005A003020101",
++      "1C605649D4658B58CBE79A5FAF227ACC16C355C58B7DADE022F90C158FE5ED8E",
++      "3075A00703050000000000A1143012A003020101A10B30091B07726165627572"
++      "6EA2101B0E415448454E412E4D49542E454455A3233021A003020102A11A3018"
++      "1B066B72627467741B0E415448454E412E4D49542E454455A511180F31393730"
++      "303130313030303030305AA703020100A8053003020112",
++      /* K'[0], K'[1], K'[2], K'[3] */
++      "A9BFA71C95C575756F922871524B65288B3F695573CCC0633E87449568210C23",
++      "1865A9EE1EF0640EC28AC007391CAC624C42639C714767A974E99AA10003015F",
++      "E57781513FEFDB978E374E156B0DA0C1A08148F5EB26B8E157AC3C077E28BF49",
++      "008E6487293C3CC9FABBBCDD8B392D6DCB88222317FD7FE52D12FBC44FA047F1",
++    },
++
++#ifdef SPAKE_OPENSSL
++    { ENCTYPE_AES256_CTS_HMAC_SHA1_96, SPAKE_GROUP_P256,
++      /* initial key, w, x, y, T, S, K */
++      "01B897121D933AB44B47EB5494DB15E50EB74530DBDAE9B634D65020FF5D88C1",
++      "EB2984AF18703F94DD5288B8596CD36988D0D4E83BFB2B44DE14D0E95E2090BD",
++      "935DDD725129FB7C6288E1A5CC45782198A6416D1775336D71EACD0549A3E80E",
++      "E07405EB215663ABC1F254B8ADC0DA7A16FEBAA011AF923D79FDEF7C42930B33",
++      "024F62078CEB53840D02612195494D0D0D88DE21FEEB81187C71CBF3D01E71788D",
++      "021D07DC31266FC7CFD904CE2632111A169B7EC730E5F74A7E79700F86638E13C8",
++      "0268489D7A9983F2FDE69C6E6A1307E9D252259264F5F2DFC32F58CCA19671E79B",
++      /* support, challenge, thash, body */
++      "A0093007A0053003020102",
++      "A1373035A003020102A1230421024F62078CEB53840D02612195494D0D0D88DE"
++      "21FEEB81187C71CBF3D01E71788DA20930073005A003020101",
++      "20AD3C1A9A90FC037D1963A1C4BFB15AB4484D7B6CF07B12D24984F14652DE60",
++      "3075A00703050000000000A1143012A003020101A10B30091B07726165627572"
++      "6EA2101B0E415448454E412E4D49542E454455A3233021A003020102A11A3018"
++      "1B066B72627467741B0E415448454E412E4D49542E454455A511180F31393730"
++      "303130313030303030305AA703020100A8053003020112",
++      /* K'[0], K'[1], K'[2], K'[3] */
++      "7D3B906F7BE49932DB22CD3463F032D06C9C078BE4B1D076D201FC6E61EF531E",
++      "17D74E36F8993841FBB7FEB12FA4F011243D3AE4D2ACE55B39379294BBC4DB2C",
++      "D192C9044081A2AA6A97A6C69E2724E8E5671C2C9CE073DD439CDBAF96D7DAB0",
++      "41E5BAD6B67F12C53CE0E2720DD6A9887F877BF9463C2D5209C74C36F8D776B7",
++    },
++
++    { ENCTYPE_AES256_CTS_HMAC_SHA1_96, SPAKE_GROUP_P384,
++      /* initial key, w, x, y, T, S, K */
++      "01B897121D933AB44B47EB5494DB15E50EB74530DBDAE9B634D65020FF5D88C1",
++      "0304CFC55151C6BBE889653DB96DBFE0BA4ACAFC024C1E8840CB3A486F6D80C1"
++      "6E1B8974016AA4B7FA43042A9B3825B1",
++      "F323CA74D344749096FD35D0ADF20806E521460637176E84D977E9933C49D76F"
++      "CFC6E62585940927468FF53D864A7A50",
++      "5B7C709ACB175A5AFB82860DEABCA8D0B341FACDFF0AC0F1A425799AA905D750"
++      "7E1EA9C573581A81467437419466E472",
++      "02A1524603EF14F184696F854229D3397507A66C63F841BA748451056BE07879"
++      "AC298912387B1C5CDFF6381C264701BE57",
++      "020D5ADFDB92BC377041CF5837412574C5D13E0F4739208A4F0C859A0A302BC6"
++      "A533440A245B9D97A0D34AF5016A20053D",
++      "0264AA8C61DA9600DFB0BEB5E46550D63740E4EF29E73F1A30D543EB43C25499"
++      "037AD16538586552761B093CF0E37C703A",
++      /* support, challenge, thash, body */
++      "A0093007A0053003020103",
++      "A1473045A003020103A133043102A1524603EF14F184696F854229D3397507A6"
++      "6C63F841BA748451056BE07879AC298912387B1C5CDFF6381C264701BE57A209"
++      "30073005A003020101",
++      "5AC0D99EF9E5A73998797FE64F074673E3952DEC4C7D1AACCE8B75F64D2B0276"
++      "A901CB8539B4E8ED69E4DB0CE805B47B",
++      "3075A00703050000000000A1143012A003020101A10B30091B07726165627572"
++      "6EA2101B0E415448454E412E4D49542E454455A3233021A003020102A11A3018"
++      "1B066B72627467741B0E415448454E412E4D49542E454455A511180F31393730"
++      "303130313030303030305AA703020100A8053003020112",
++      /* K'[0], K'[1], K'[2], K'[3] */
++      "B917D37C16DD1D8567FBE379F64E1EE36CA3FD127AA4E60F97E4AFA3D9E56D91",
++      "93D40079DAB229B9C79366829F4E7E7282E6A4B943AC7BAC69922D516673F49A",
++      "BFC4F16F12F683E71589F9A888E232875EF293AC9793DB6C919567CD7B94BCD4",
++      "3630E2B5B99938E7506733141E8EC344166F6407E5FC2EF107C156E764D1BC20",
++    },
++
++    { ENCTYPE_AES256_CTS_HMAC_SHA1_96, SPAKE_GROUP_P521,
++      /* initial key, w, x, y, T, S, K */
++      "01B897121D933AB44B47EB5494DB15E50EB74530DBDAE9B634D65020FF5D88C1",
++      "DE3A095A2B2386EFF3EB15B735398DA1CAF95BC8425665D82370AFF58B0471F3"
++      "4A57BCCDDF1EBF0A2965B58A93EE5B45E85D1A5435D1C8C83662999722D54283"
++      "1F9A",
++      "017C38701A14B490B6081DFC83524562BE7FBB42E0B20426465E3E37952D30BC"
++      "AB0ED857010255D44936A1515607964A870C7C879B741D878F9F9CDF5A865306"
++      "F3F5",
++      "003E2E2950656FA231E959ACDD984D125E7FA59CEC98126CBC8F3888447911EB"
++      "CD49428A1C22D5FDB76A19FBEB1D9EDFA3DA6CF55B158B53031D05D51433ADE9"
++      "B2B4",
++      "02017D3DE19A3EC53D0174905665EF37947D142535102CD9809C0DFBD0DFE007"
++      "353D54CF406CE2A59950F2BB540DF6FBE75F8BBBEF811C9BA06CC275ADBD9675"
++      "6696EC",
++      "02004D142D87477841F6BA053C8F651F3395AD264B7405CA5911FB9A55ABD454"
++      "FEF658A5F9ED97D1EFAC68764E9092FA15B9E0050880D78E95FD03ABF5931791"
++      "6822B5",
++      "03007C303F62F09282CC849490805BD4457A6793A832CBEB55DF427DB6A31E99"
++      "B055D5DC99756D24D47B70AD8B6015B0FB8742A718462ED423B90FA3FE631AC1"
++      "3FA916",
++      /* support, challenge, thash, body */
++      "A0093007A0053003020104",
++      "A1593057A003020104A145044302017D3DE19A3EC53D0174905665EF37947D14"
++      "2535102CD9809C0DFBD0DFE007353D54CF406CE2A59950F2BB540DF6FBE75F8B"
++      "BBEF811C9BA06CC275ADBD96756696ECA20930073005A003020101",
++      "8D6A89AE4D80CC4E47B6F4E48EA3E57919CC69598D0D3DC7C8BD49B6F1DB1409"
++      "CA0312944CD964E213ABA98537041102237CFF5B331E5347A0673869B412302E",
++      "3075A00703050000000000A1143012A003020101A10B30091B07726165627572"
++      "6EA2101B0E415448454E412E4D49542E454455A3233021A003020102A11A3018"
++      "1B066B72627467741B0E415448454E412E4D49542E454455A511180F31393730"
++      "303130313030303030305AA703020100A8053003020112",
++      /* K'[0], K'[1], K'[2], K'[3] */
++      "1EB3D10BEE8FAB483ADCD3EB38F3EBF1F4FEB8DB96ECC035F563CF2E1115D276",
++      "482B92781CE57F49176E4C94153CC622FE247A7DBE931D1478315F856F085890",
++      "A2C215126DD3DF280AAB5A27E1E0FB7E594192CBFF8D6D8E1B6F1818D9BB8FAC",
++      "CC06603DE984324013A01F888DE6D43B410A4DA2DEA53509F30E433C352FB668",
++    },
++#endif /* SPAKE_OPENSSL */
++
++    /* Successful optimistic challenge (no support message in transcript) */
++    { ENCTYPE_AES256_CTS_HMAC_SHA1_96, SPAKE_GROUP_EDWARDS25519,
++      /* initial key, w, x, y, T, S, K */
++      "01B897121D933AB44B47EB5494DB15E50EB74530DBDAE9B634D65020FF5D88C1",
++      "E902341590A1B4BB4D606A1C643CCCB3F2108F1B6AA97B381012B9400C9E3F4E",
++      "70937207344CAFBC53C8A55070E399C584CBAFCE00B836980DD4E7E74FAD2A64",
++      "785D6801A2490DF028903AC6449B105F2FF0DB895B252953CDC2076649526103",
++      "83523B35F1565006CBFC4F159885467C2FB9BC6FE23D36CB1DA43D199F1A3118",
++      "2A8F70F46CEE9030700037B77F22CEC7970DCC238E3E066D9D726BAF183992C6",
++      "D3C5E4266AA6D1B2873A97CE8AF91C7E4D7A7AC456ACCED7908D34C561AD8FA6",
++      /* support, challenge, thash, body */
++      NULL,
++      "A1363034A003020101A122042083523B35F1565006CBFC4F159885467C2FB9BC"
++      "6FE23D36CB1DA43D199F1A3118A20930073005A003020101",
++      "26F07F9F8965307434D11EA855461D41E0CBABCC0A1BAB48ECEE0C6C1A4292B7",
++      "3075A00703050000000000A1143012A003020101A10B30091B07726165627572"
++      "6EA2101B0E415448454E412E4D49542E454455A3233021A003020102A11A3018"
++      "1B066B72627467741B0E415448454E412E4D49542E454455A511180F31393730"
++      "303130313030303030305AA703020100A8053003020112",
++      /* K'[0], K'[1], K'[2], K'[3] */
++      "4569EC08B5DE5C3CC19D941725913ACE8D74524B521A341DC746ACD5C3784D92",
++      "0D96CE1A4AC0F2E280A0CFC31742B06461D83D04AE45433DB2D80478DD882A4C",
++      "58018C19315A1BA5D5BB9813B58029F0AEC18A6F9CA59E0847DE1C60BC25945C",
++      "ED7E9BFFD68C54D86FB19CD3C03F317F88A71AD9A5E94C28581D93FC4EC72B6A",
++    },
++
++#ifdef SPAKE_OPENSSL
++    /* Rejected optimistic challenge (no support message in transcript),
++     * falling back from edwards25519 to P-521 */
++    { ENCTYPE_AES256_CTS_HMAC_SHA1_96, SPAKE_GROUP_P521,
++      /* initial key, w, x, y, T, S, K */
++      "01B897121D933AB44B47EB5494DB15E50EB74530DBDAE9B634D65020FF5D88C1",
++      "DE3A095A2B2386EFF3EB15B735398DA1CAF95BC8425665D82370AFF58B0471F3"
++      "4A57BCCDDF1EBF0A2965B58A93EE5B45E85D1A5435D1C8C83662999722D54283"
++      "1F9A",
++      "01687B59051BF40048D7C31D5A973D792FA12284B7A447E7F5938B5885CA0BB2"
++      "C3F0BD30291A55FEA08E143E2E04BDD7D19B753C7C99032F06CAB0D9C2AA8F83"
++      "7EF7",
++      "01DED675EBF74FE30C9A53710F577E9CF84F09F6048FE245A4600004884CC167"
++      "733F9A9E43108FB83BABE8754CD37CBD7025E28BC9FF870F084C7244F536285E"
++      "25B4",
++      "02014CB2E5B592ECE5990F0EF30D308C061DE1598BC4272B4A6599BED466FD15"
++      "21693642ABCF4DBE36CE1A2D13967DE45F6C4F8D0FA8E14428BF03FB96EF5F1E"
++      "D3E645",
++      "02016C64995E804416F748FD5FA3AA678CBC7CBB596A4F523132DC8AF7CE84E5"
++      "41F484A2C74808C6B21DCF7775BAEFA6753398425BECC7B838B210AC5DAA0CB0"
++      "B710E2",
++      "0200997F4848AE2E7A98C23D14AC662030743AB37FCCC2A45F1C721114F40BCC"
++      "80FE6EC6ABA49868F8AEA1AA994D50E81B86D3E4D3C1130C8695B68907C673D9"
++      "E5886A",
++      /* support, challenge, thash, body */
++      "A0093007A0053003020104",
++      "A1593057A003020104A145044302014CB2E5B592ECE5990F0EF30D308C061DE1"
++      "598BC4272B4A6599BED466FD1521693642ABCF4DBE36CE1A2D13967DE45F6C4F"
++      "8D0FA8E14428BF03FB96EF5F1ED3E645A20930073005A003020101",
++      "D0EFED5E3E2C39C26034756D92A66FEC3082AD793D0197F3F89AD36026F146A3"
++      "996E548AA3FC49E2E82F8CAC5D132C505AA475B39E7BE79CDED22C26C41AA777",
++      "3075A00703050000000000A1143012A003020101A10B30091B07726165627572"
++      "6EA2101B0E415448454E412E4D49542E454455A3233021A003020102A11A3018"
++      "1B066B72627467741B0E415448454E412E4D49542E454455A511180F31393730"
++      "303130313030303030305AA703020100A8053003020112",
++      /* K'[0], K'[1], K'[2], K'[3] */
++      "631FCC8596E7F40E59045950D72AA0B7BAC2810A07B767050E983841CF3A2D4C",
++      "881464920117074DBC67155A8F3341D1121EF65F78EA0380BFA81A134C1C47B1",
++      "377B72AC3AF2CAAD582D73AE4682FD56B531EE56706200DD6C38C42B8219837A",
++      "35AD8E4D580ED3F0D15AD928329773C081BD19F9A56363F3A5F77C7E66108C26",
++    },
++#endif /* SPAKE_OPENSSL */
++};
++
++static krb5_context ctx;
++
++static void
++check(krb5_error_code code)
++{
++    const char *errmsg;
++
++    if (code) {
++        errmsg = krb5_get_error_message(ctx, code);
++        assert(errmsg != NULL);
++        abort();
++    }
++}
++
++static void
++check_key_equal(const krb5_keyblock *kb1, const krb5_keyblock *kb2)
++{
++    assert(kb1->enctype == kb2->enctype);
++    assert(kb1->length == kb2->length);
++    assert(memcmp(kb1->contents, kb2->contents, kb1->length) == 0);
++}
++
++static krb5_data *
++decode_data(const char *s)
++{
++    uint8_t *bytes;
++    size_t len;
++    krb5_data *d;
++
++    if (k5_hex_decode(s, &bytes, &len) != 0)
++        abort();
++    d = malloc(sizeof(*d));
++    assert(d != NULL);
++    *d = make_data(bytes, len);
++    return d;
++}
++
++static krb5_keyblock *
++decode_keyblock(krb5_enctype enctype, const char *s)
++{
++    uint8_t *bytes;
++    size_t len;
++    krb5_keyblock *kb;
++
++    if (k5_hex_decode(s, &bytes, &len) != 0)
++        abort();
++    kb = malloc(sizeof(*kb));
++    kb->magic = KV5M_KEYBLOCK;
++    kb->enctype = enctype;
++    kb->length = len;
++    kb->contents = bytes;
++    return kb;
++}
++
++static void
++run_test(const struct test *t)
++{
++    groupstate *gstate;
++    krb5_keyblock *ikey, *K0, *K1, *K2, *K3, *kb;
++    krb5_data *w, *x, *y, *T, *S, *K, *support, *challenge, *thash;
++    krb5_data *body, wbytes, result, hash, empty = empty_data();
++
++    /* Decode hex strings into keyblocks and byte strings. */
++    ikey = decode_keyblock(t->enctype, t->ikey);
++    w = decode_data(t->w);
++    x = decode_data(t->x);
++    y = decode_data(t->y);
++    T = decode_data(t->T);
++    S = decode_data(t->S);
++    K = decode_data(t->K);
++    support = (t->support != NULL) ? decode_data(t->support) : NULL;
++    challenge = decode_data(t->challenge);
++    thash = decode_data(t->thash);
++    body = decode_data(t->body);
++    K0 = decode_keyblock(t->enctype, t->K0);
++    K1 = decode_keyblock(t->enctype, t->K1);
++    K2 = decode_keyblock(t->enctype, t->K2);
++    K3 = decode_keyblock(t->enctype, t->K3);
++
++    check(derive_wbytes(ctx, t->group, ikey, &wbytes));
++    assert(data_eq(*w, wbytes));
++
++    /* Verify KDC-side result computation. */
++    check(group_init_state(ctx, TRUE, &gstate));
++    check(group_result(ctx, gstate, t->group, &wbytes, x, S, &result));
++    assert(data_eq(*K, result));
++    krb5_free_data_contents(ctx, &result);
++    group_free_state(gstate);
++
++    /* Verify client-side result computation. */
++    check(group_init_state(ctx, FALSE, &gstate));
++    check(group_result(ctx, gstate, t->group, &wbytes, y, T, &result));
++    assert(data_eq(*K, result));
++    krb5_free_data_contents(ctx, &result);
++
++    /* Verify transcript hash. */
++    hash = empty_data();
++    check(update_thash(ctx, gstate, t->group, &hash, support, challenge));
++    check(update_thash(ctx, gstate, t->group, &hash, S, &empty));
++    assert(data_eq(*thash, hash));
++    krb5_free_data_contents(ctx, &hash);
++
++    /* Verify derived keys. */
++    check(derive_key(ctx, gstate, t->group, ikey, &wbytes, K, thash, body, 0,
++                     &kb));
++    check_key_equal(K0, kb);
++    krb5_free_keyblock(ctx, kb);
++    check(derive_key(ctx, gstate, t->group, ikey, &wbytes, K, thash, body, 1,
++                     &kb));
++    check_key_equal(K1, kb);
++    krb5_free_keyblock(ctx, kb);
++    check(derive_key(ctx, gstate, t->group, ikey, &wbytes, K, thash, body, 2,
++                     &kb));
++    check_key_equal(K2, kb);
++    krb5_free_keyblock(ctx, kb);
++    check(derive_key(ctx, gstate, t->group, ikey, &wbytes, K, thash, body, 3,
++                     &kb));
++    check_key_equal(K3, kb);
++    krb5_free_keyblock(ctx, kb);
++
++    group_free_state(gstate);
++    krb5_free_data_contents(ctx, &wbytes);
++    krb5_free_keyblock(ctx, ikey);
++    krb5_free_data(ctx, w);
++    krb5_free_data(ctx, x);
++    krb5_free_data(ctx, y);
++    krb5_free_data(ctx, T);
++    krb5_free_data(ctx, S);
++    krb5_free_data(ctx, K);
++    krb5_free_data(ctx, support);
++    krb5_free_data(ctx, challenge);
++    krb5_free_data(ctx, thash);
++    krb5_free_data(ctx, body);
++    krb5_free_keyblock(ctx, K0);
++    krb5_free_keyblock(ctx, K1);
++    krb5_free_keyblock(ctx, K2);
++    krb5_free_keyblock(ctx, K3);
++}
++
++int
++main()
++{
++    size_t i;
++
++    check(krb5_init_context(&ctx));
++    for (i = 0; i < sizeof(tests) / sizeof(*tests); i++)
++        run_test(&tests[i]);
++    krb5_free_context(ctx);
++    return 0;
++}
+diff --git a/src/plugins/preauth/spake/trace.h b/src/plugins/preauth/spake/trace.h
+new file mode 100644
+index 000000000..9dd964260
+--- /dev/null
++++ b/src/plugins/preauth/spake/trace.h
+@@ -0,0 +1,74 @@
++/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
++/* plugins/preauth/spake/internal.h - SPAKE internal function declarations */
++/*
++ * Copyright (C) 2015 by the Massachusetts Institute of Technology.
++ * 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.
++ */
++
++#ifndef TRACE_H
++#define TRACE_H
++
++#include "k5-int.h"
++
++/*
++ * Possible improvements at the cost of more code:
++ * - Groups could be displayed by name instead of number
++ * - We could display the group list when tracing support messages
++ */
++
++#define TRACE_SPAKE_CLIENT_THASH(c, thash)                      \
++    TRACE(c, "SPAKE final transcript hash: {hexdata}", thash)
++#define TRACE_SPAKE_DERIVE_KEY(c, n, kb)                        \
++    TRACE(c, "SPAKE derived K'[{int}] = {keyblock}", n, kb)
++#define TRACE_SPAKE_KDC_THASH(c, thash)                         \
++    TRACE(c, "SPAKE final transcript hash: {hexdata}", thash)
++#define TRACE_SPAKE_KEYGEN(c, pubkey)                                   \
++    TRACE(c, "SPAKE key generated with pubkey {hexdata}", pubkey)
++#define TRACE_SPAKE_RECEIVE_CHALLENGE(c, group, pubkey)                 \
++    TRACE(c, "SPAKE challenge received with group {int}, pubkey {hexdata}", \
++          group, pubkey)
++#define TRACE_SPAKE_RECEIVE_RESPONSE(c, pubkey)                         \
++    TRACE(c, "SPAKE response received with pubkey {hexdata}", pubkey)
++#define TRACE_SPAKE_RECEIVE_SUPPORT(c, group)                           \
++    TRACE(c, "SPAKE support message received, selected group {int}", group)
++#define TRACE_SPAKE_REJECT_CHALLENGE(c, group)                          \
++    TRACE(c, "SPAKE challenge with group {int} rejected", (int)group)
++#define TRACE_SPAKE_REJECT_SUPPORT(c)           \
++    TRACE(c, "SPAKE support message rejected")
++#define TRACE_SPAKE_RESULT(c, result)                           \
++    TRACE(c, "SPAKE algorithm result: {hexdata}", result)
++#define TRACE_SPAKE_SEND_CHALLENGE(c, group)                    \
++    TRACE(c, "Sending SPAKE challenge with group {int}", group)
++#define TRACE_SPAKE_SEND_RESPONSE(c)            \
++    TRACE(c, "Sending SPAKE response")
++#define TRACE_SPAKE_SEND_SUPPORT(c)             \
++    TRACE(c, "Sending SPAKE support message")
++#define TRACE_SPAKE_UNKNOWN_GROUP(c, name)                      \
++    TRACE(c, "Unrecognized SPAKE group name: {string}", name)
++
++#endif /* TRACE_H */
+diff --git a/src/plugins/preauth/spake/util.c b/src/plugins/preauth/spake/util.c
+new file mode 100644
+index 000000000..cbdbbd7ac
+--- /dev/null
++++ b/src/plugins/preauth/spake/util.c
+@@ -0,0 +1,211 @@
++/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
++/* plugins/preauth/spake/util.c - Utility functions for SPAKE preauth module */
++/*
++ * Copyright (C) 2015 by the Massachusetts Institute of Technology.
++ * 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.
++ */
++
++#include "k5-int.h"
++#include "trace.h"
++#include "util.h"
++#include "groups.h"
++
++/* Use data to construct a single-element pa-data list of type
++ * KRB5_PADATA_SPAKE.  Claim data's memory on success or failure. */
++krb5_error_code
++convert_to_padata(krb5_data *data, krb5_pa_data ***pa_out)
++{
++    krb5_pa_data *pa = NULL, **list = NULL;
++
++    list = calloc(2, sizeof(*list));
++    if (list == NULL)
++        goto fail;
++    pa = calloc(1, sizeof(*pa));
++    if (pa == NULL)
++        goto fail;
++    pa->magic = KV5M_PA_DATA;
++    pa->pa_type = KRB5_PADATA_SPAKE;
++    pa->length = data->length;
++    pa->contents = (uint8_t *)data->data;
++    list[0] = pa;
++    list[1] = NULL;
++    *pa_out = list;
++    free(data);
++    return 0;
++
++fail:
++    free(list);
++    free(pa);
++    free(data->data);
++    free(data);
++    return ENOMEM;
++}
++
++/*
++ * Update the transcript hash thash with its current value and the
++ * concatenation of data1 and data2, using the hash function for group.  Either
++ * data1 or data2 may be NULL to omit it.  Allocate thash if it is empty.
++ */
++krb5_error_code
++update_thash(krb5_context context, groupstate *gstate, int32_t group,
++             krb5_data *thash, const krb5_data *data1, const krb5_data *data2)
++{
++    krb5_error_code ret;
++    size_t hashlen;
++    krb5_data dlist[3];
++
++    if (thash->length == 0) {
++        /* Initialize the transcript hash to all zeros. */
++        ret = group_hash_len(group, &hashlen);
++        if (ret)
++            return ret;
++        ret = alloc_data(thash, hashlen);
++        if (ret)
++            return ret;
++    }
++
++    /* Set up the data array and hash it with the group's hash function. */
++    dlist[0] = *thash;
++    dlist[1] = (data1 != NULL) ? *data1 : empty_data();
++    dlist[2] = (data2 != NULL) ? *data2 : empty_data();
++    return group_hash(context, gstate, group, dlist, 3,
++                      (uint8_t *)thash->data);
++}
++
++/* Derive a byte vector for the SPAKE w multiplier input from ikey.  Place
++ * result in allocated storage in *wbytes_out. */
++krb5_error_code
++derive_wbytes(krb5_context context, int32_t group, const krb5_keyblock *ikey,
++              krb5_data *wbytes_out)
++{
++    krb5_error_code ret;
++    const char prefix[] = "SPAKEsecret";
++    size_t mult_len, prefix_len = sizeof(prefix) - 1;
++    krb5_data prf_input = empty_data(), wbytes = empty_data();
++
++    *wbytes_out = empty_data();
++
++    /* Allocate space for a multiplier. */
++    ret = group_mult_len(group, &mult_len);
++    if (ret)
++        goto cleanup;
++    ret = alloc_data(&wbytes, mult_len);
++    if (ret)
++        goto cleanup;
++
++    /* Compose the PRF input string. */
++    ret = alloc_data(&prf_input, prefix_len + 4);
++    if (ret)
++        goto cleanup;
++    memcpy(prf_input.data, prefix, prefix_len);
++    store_32_be(group, prf_input.data + prefix_len);
++
++    /* Derive the SPAKE input from the initial reply key with PRF+. */
++    ret = krb5_c_prfplus(context, ikey, &prf_input, &wbytes);
++    if (ret)
++        goto cleanup;
++
++    *wbytes_out = wbytes;
++    wbytes = empty_data();
++
++cleanup:
++    free(prf_input.data);
++    zapfree(wbytes.data, wbytes.length);
++    return ret;
++}
++
++/*
++ * Derive K'[n] from the group number, the initial key enctype, the initial
++ * multiplier, the SPAKE result, the transcript hash, and the encoded
++ * KDC-REQ-BODY.  Place the result in allocated storage in *out.
++ */
++krb5_error_code
++derive_key(krb5_context context, groupstate *gstate, int32_t group,
++           const krb5_keyblock *ikey, const krb5_data *wbytes,
++           const krb5_data *spakeresult, const krb5_data *thash,
++           const krb5_data *der_req, uint32_t n, krb5_keyblock **out)
++{
++    krb5_error_code ret;
++    krb5_data dlist[9], seed = empty_data(), d;
++    uint8_t groupnbuf[4], etypenbuf[4], nbuf[4], bcount;
++    size_t hashlen, seedlen, keylen, nblocks, i;
++    size_t ndata = sizeof(dlist) / sizeof(*dlist);
++    krb5_keyblock *hkey = NULL;
++
++    *out = NULL;
++
++    store_32_be(group, groupnbuf);
++    store_32_be(n, nbuf);
++    store_32_be(ikey->enctype, etypenbuf);
++    dlist[0] = string2data("SPAKEkey");
++    dlist[1] = make_data(groupnbuf, sizeof(groupnbuf));
++    dlist[2] = make_data(etypenbuf, sizeof(etypenbuf));
++    dlist[3] = *wbytes;
++    dlist[4] = *spakeresult;
++    dlist[5] = *thash;
++    dlist[6] = *der_req;
++    dlist[7] = make_data(nbuf, sizeof(nbuf));
++    dlist[8] = make_data(&bcount, 1);
++
++    /* Count the number of hash blocks required (should be 1 for all current
++     * scenarios) and allocate space. */
++    ret = group_hash_len(group, &hashlen);
++    if (ret)
++        goto cleanup;
++    ret = krb5_c_keylengths(context, ikey->enctype, &seedlen, &keylen);
++    if (ret)
++        goto cleanup;
++    nblocks = (seedlen + hashlen - 1) / hashlen;
++    ret = alloc_data(&seed, nblocks * hashlen);
++    if (ret)
++        goto cleanup;
++
++    /* Compute and concatenate hash blocks to fill the seed buffer. */
++    for (i = 0; i < nblocks; i++) {
++        bcount = i + 1;
++        ret = group_hash(context, gstate, group, dlist, ndata,
++                         (uint8_t *)seed.data + i * hashlen);
++        if (ret)
++            goto cleanup;
++    }
++
++    ret = krb5_init_keyblock(context, ikey->enctype, keylen, &hkey);
++    if (ret)
++        goto cleanup;
++    d = make_data(seed.data, seedlen);
++    ret = krb5_c_random_to_key(context, ikey->enctype, &d, hkey);
++    if (ret)
++        goto cleanup;
++
++    ret = krb5_c_fx_cf2_simple(context, ikey, "SPAKE", hkey, "keyderiv", out);
++
++cleanup:
++    zapfree(seed.data, seed.length);
++    krb5_free_keyblock(context, hkey);
++    return ret;
++}
+diff --git a/src/plugins/preauth/spake/util.h b/src/plugins/preauth/spake/util.h
+new file mode 100644
+index 000000000..3ab2bead1
+--- /dev/null
++++ b/src/plugins/preauth/spake/util.h
+@@ -0,0 +1,56 @@
++/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
++/* plugins/preauth/spake/internal.h - SPAKE internal function declarations */
++/*
++ * Copyright (C) 2015 by the Massachusetts Institute of Technology.
++ * 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.
++ */
++
++#ifndef UTIL_H
++#define UTIL_H
++
++#include "k5-int.h"
++#include "groups.h"
++
++krb5_error_code convert_to_padata(krb5_data *data, krb5_pa_data ***pa_out);
++
++krb5_error_code update_thash(krb5_context context, groupstate *gstate,
++                             int32_t group, krb5_data *thash,
++                             const krb5_data *data1, const krb5_data *data2);
++
++krb5_error_code derive_wbytes(krb5_context context, int32_t group,
++                              const krb5_keyblock *ikey,
++                              krb5_data *wbytes_out);
++
++krb5_error_code derive_key(krb5_context context, groupstate *gstate,
++                           int32_t group, const krb5_keyblock *ikey,
++                           const krb5_data *wbytes,
++                           const krb5_data *spakeresult,
++                           const krb5_data *thash, const krb5_data *der_req,
++                           uint32_t n, krb5_keyblock **out);
++
++#endif /* UTIL_H */
+diff --git a/src/tests/Makefile.in b/src/tests/Makefile.in
+index 67d3e8200..aed23e570 100644
+--- a/src/tests/Makefile.in
++++ b/src/tests/Makefile.in
+@@ -130,6 +130,7 @@ check-pytests: unlockiter
+ 	$(RUNPYTEST) $(srcdir)/t_changepw.py $(PYTESTFLAGS)
+ 	$(RUNPYTEST) $(srcdir)/t_pkinit.py $(PYTESTFLAGS)
+ 	$(RUNPYTEST) $(srcdir)/t_otp.py $(PYTESTFLAGS)
++	$(RUNPYTEST) $(srcdir)/t_spake.py $(PYTESTFLAGS)
+ 	$(RUNPYTEST) $(srcdir)/t_localauth.py $(PYTESTFLAGS)
+ 	$(RUNPYTEST) $(srcdir)/t_kadm5_hook.py $(PYTESTFLAGS)
+ 	$(RUNPYTEST) $(srcdir)/t_kadm5_auth.py $(PYTESTFLAGS)
+diff --git a/src/tests/t_spake.py b/src/tests/t_spake.py
+new file mode 100644
+index 000000000..a81a238b4
+--- /dev/null
++++ b/src/tests/t_spake.py
+@@ -0,0 +1,151 @@
++#!/usr/bin/python
++from k5test import *
++
++# The name and number of each supported SPAKE group.
++builtin_groups = ((1, 'edwards25519'),)
++openssl_groups = ((2, 'P-256'), (3, 'P-384'), (4, 'P-521'))
++if runenv.have_spake_openssl == 'yes':
++    groups = builtin_groups + openssl_groups
++else:
++    groups = builtin_groups
++
++for gnum, gname in groups:
++    output('*** Testing group %s\n' % gname)
++    conf = {'libdefaults': {'spake_preauth_groups': gname}}
++    for realm in multipass_realms(create_user=False, create_host=False,
++                                  krb5_conf=conf):
++        realm.run([kadminl, 'addprinc', '+preauth', '-pw', 'pw', 'user'])
++
++        # Test a basic SPAKE preauth scenario with no optimizations.
++        msgs = ('Sending unauthenticated request',
++                '/Additional pre-authentication required',
++                'Selected etype info:',
++                'Sending SPAKE support message',
++                'for next request: PA-FX-COOKIE (133), PA-SPAKE (151)',
++                '/More preauthentication data is required',
++                'Continuing preauth mech PA-SPAKE (151)',
++                'SPAKE challenge received with group ' + str(gnum),
++                'Sending SPAKE response',
++                'for next request: PA-FX-COOKIE (133), PA-SPAKE (151)',
++                'AS key determined by preauth:',
++                'Decrypted AS reply')
++        realm.kinit('user', 'pw', expected_trace=msgs)
++
++        # Test an unsuccessful authentication.  (The client will try
++        # again with encrypted timestamp, which isn't really desired,
++        # but check for that as long as it is expected.)
++        msgs = ('/Additional pre-authentication required',
++                'Selected etype info:',
++                'Sending SPAKE support message',
++                'for next request: PA-FX-COOKIE (133), PA-SPAKE (151)',
++                '/More preauthentication data is required',
++                'Continuing preauth mech PA-SPAKE (151)',
++                'SPAKE challenge received with group ' + str(gnum),
++                'Sending SPAKE response',
++                '/Preauthentication failed',
++                'Encrypted timestamp ',
++                'for next request: PA-FX-COOKIE (133), PA-ENC-TIMESTAMP (2)',
++                '/Preauthentication failed')
++        realm.kinit('user', 'wrongpw', expected_code=1, expected_trace=msgs)
++
++conf = {'libdefaults': {'spake_preauth_groups': 'edwards25519'}}
++kdcconf = {'realms': {'$realm': {'spake_preauth_indicator': 'indspake'}}}
++realm = K5Realm(create_user=False, krb5_conf=conf, kdc_conf=kdcconf)
++realm.run([kadminl, 'addprinc', '+preauth', '-pw', 'pw', 'user'])
++
++# Test with FAST.
++msgs = ('Using FAST due to armor ccache negotiation',
++        'FAST armor key:',
++        'Sending unauthenticated request',
++        '/Additional pre-authentication required',
++        'Decoding FAST response',
++        'Selected etype info:',
++        'Sending SPAKE support message',
++        'for next request: PA-FX-COOKIE (133), PA-SPAKE (151)',
++        '/More preauthentication data is required',
++        'Continuing preauth mech PA-SPAKE (151)',
++        'SPAKE challenge received with group 1',
++        'Sending SPAKE response',
++        'for next request: PA-FX-COOKIE (133), PA-SPAKE (151)',
++        'AS key determined by preauth:',
++        'FAST reply key:')
++realm.kinit(realm.host_princ, flags=['-k'])
++realm.kinit('user', 'pw', flags=['-T', realm.ccache], expected_trace=msgs)
++
++# Test optimistic client preauth (151 is PA-SPAKE).
++msgs = ('Attempting optimistic preauth',
++        'Processing preauth types: PA-SPAKE (151)',
++        'Sending SPAKE support message',
++        'for next request: PA-SPAKE (151)',
++        '/More preauthentication data is required',
++        'Selected etype info:',
++        'SPAKE challenge received with group 1',
++        'Sending SPAKE response',
++        'for next request: PA-FX-COOKIE (133), PA-SPAKE (151)',
++        'AS key determined by preauth:',
++        'Decrypted AS reply')
++realm.run(['./icred', '-o', '151', 'user', 'pw'], expected_trace=msgs)
++
++# Test KDC optimistic challenge (accepted by client).
++oconf = {'kdcdefaults': {'spake_preauth_kdc_challenge': 'edwards25519'}}
++oenv = realm.special_env('ochal', True, krb5_conf=oconf)
++realm.stop_kdc()
++realm.start_kdc(env=oenv)
++msgs = ('Sending unauthenticated request',
++        '/Additional pre-authentication required',
++        'Selected etype info:',
++        'SPAKE challenge received with group 1',
++        'Sending SPAKE response',
++        'for next request: PA-FX-COOKIE (133), PA-SPAKE (151)',
++        'AS key determined by preauth:',
++        'Decrypted AS reply')
++realm.kinit('user', 'pw', expected_trace=msgs)
++
++if runenv.have_spake_openssl != 'yes':
++    skip_rest('SPAKE fallback tests', 'SPAKE not built using OpenSSL')
++
++# Test optimistic client preauth falling back to encrypted timestamp
++# because the KDC doesn't support any of the client groups.
++p256conf={'libdefaults': {'spake_preauth_groups': 'P-256'}}
++p256env = realm.special_env('p256', False, krb5_conf=p256conf)
++msgs = ('Attempting optimistic preauth',
++        'Processing preauth types: PA-SPAKE (151)',
++        'Sending SPAKE support message',
++        'for next request: PA-SPAKE (151)',
++        '/Preauthentication failed',
++        'Selected etype info:',
++        'SPAKE challenge with group 1 rejected',
++        'spake (151) (real) returned: -1765328360/Preauthentication failed',
++        'Encrypted timestamp ',
++        'for next request: PA-FX-COOKIE (133), PA-ENC-TIMESTAMP (2)',
++        'AS key determined by preauth:',
++        'Decrypted AS reply')
++realm.run(['./icred', '-o', '151', 'user', 'pw'], env=p256env,
++          expected_trace=msgs)
++
++# Test KDC optimistic challenge (rejected by client).
++rconf = {'libdefaults': {'spake_preauth_groups': 'P-384,edwards25519'},
++         'kdcdefaults': {'spake_preauth_kdc_challenge': 'P-384'}}
++renv = realm.special_env('ochal', True, krb5_conf=rconf)
++realm.stop_kdc()
++realm.start_kdc(env=renv)
++msgs = ('Sending unauthenticated request',
++        '/Additional pre-authentication required',
++        'Selected etype info:',
++        'SPAKE challenge with group 3 rejected',
++        'Sending SPAKE support message',
++        'for next request: PA-FX-COOKIE (133), PA-SPAKE (151)',
++        '/More preauthentication data is required',
++        'Continuing preauth mech PA-SPAKE (151)',
++        'SPAKE challenge received with group 1',
++        'Sending SPAKE response',
++        'for next request: PA-FX-COOKIE (133), PA-SPAKE (151)',
++        'AS key determined by preauth:',
++        'Decrypted AS reply')
++realm.kinit('user', 'pw', expected_trace=msgs)
++
++# Check that the auth indicator for SPAKE is properly included by the KDC.
++realm.run([kvno, realm.host_princ])
++realm.run(['./adata', realm.host_princ], expected_msg='+97: [indspake]')
++
++success('SPAKE pre-authentication tests')
diff --git a/SOURCES/Add-doc-index-entries-for-SPAKE-constants.patch b/SOURCES/Add-doc-index-entries-for-SPAKE-constants.patch
new file mode 100644
index 0000000..7ac2afe
--- /dev/null
+++ b/SOURCES/Add-doc-index-entries-for-SPAKE-constants.patch
@@ -0,0 +1,31 @@
+From c891e4bc54c8083a1af8d28aa9b12ab1177ebb9a Mon Sep 17 00:00:00 2001
+From: Greg Hudson <ghudson@mit.edu>
+Date: Tue, 27 Mar 2018 00:49:43 -0400
+Subject: [PATCH] Add doc index entries for SPAKE constants
+
+ticket: 8647
+(cherry picked from commit c010c9031753f356bb380e8a1324cc34721f8221)
+---
+ doc/appdev/refs/macros/index.rst | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/doc/appdev/refs/macros/index.rst b/doc/appdev/refs/macros/index.rst
+index dba818b26..47c6d4413 100644
+--- a/doc/appdev/refs/macros/index.rst
++++ b/doc/appdev/refs/macros/index.rst
+@@ -190,6 +190,7 @@ Public
+    KRB5_KEYUSAGE_PA_SAM_CHALLENGE_CKSUM.rst
+    KRB5_KEYUSAGE_PA_SAM_CHALLENGE_TRACKID.rst
+    KRB5_KEYUSAGE_PA_SAM_RESPONSE.rst
++   KRB5_KEYUSAGE_SPAKE.rst
+    KRB5_KEYUSAGE_TGS_REP_ENCPART_SESSKEY.rst
+    KRB5_KEYUSAGE_TGS_REP_ENCPART_SUBKEY.rst
+    KRB5_KEYUSAGE_TGS_REQ_AD_SESSKEY.rst
+@@ -274,6 +275,7 @@ Public
+    KRB5_PADATA_SAM_RESPONSE.rst
+    KRB5_PADATA_SAM_RESPONSE_2.rst
+    KRB5_PADATA_SESAME.rst
++   KRB5_PADATA_SPAKE.rst
+    KRB5_PADATA_SVR_REFERRAL_INFO.rst
+    KRB5_PADATA_TGS_REQ.rst
+    KRB5_PADATA_USE_SPECIFIED_KVNO.rst
diff --git a/SOURCES/Add-flag-to-disable-encrypted-timestamp-on-client.patch b/SOURCES/Add-flag-to-disable-encrypted-timestamp-on-client.patch
new file mode 100644
index 0000000..adc4f41
--- /dev/null
+++ b/SOURCES/Add-flag-to-disable-encrypted-timestamp-on-client.patch
@@ -0,0 +1,204 @@
+From f44ef4893050e673f495444c27a19525813f75a8 Mon Sep 17 00:00:00 2001
+From: Greg Hudson <ghudson@mit.edu>
+Date: Mon, 11 Jun 2018 13:53:27 -0400
+Subject: [PATCH] Add flag to disable encrypted timestamp on client
+
+ticket: 8655
+(cherry picked from commit 4ad376134b8d456392edbac7a7d351e6c7a7f0e7)
+---
+ doc/admin/conf_files/krb5_conf.rst | 10 ++++++++++
+ doc/admin/spake.rst                |  8 ++++++++
+ src/include/k5-int.h               |  1 +
+ src/include/k5-trace.h             |  2 ++
+ src/lib/krb5/krb/get_in_tkt.c      | 23 +++++++++++++++++++++++
+ src/lib/krb5/krb/init_creds_ctx.h  |  1 +
+ src/lib/krb5/krb/preauth_encts.c   | 14 +++++++++++++-
+ src/tests/t_referral.py            | 13 +++++++++++++
+ 8 files changed, 71 insertions(+), 1 deletion(-)
+
+diff --git a/doc/admin/conf_files/krb5_conf.rst b/doc/admin/conf_files/krb5_conf.rst
+index ce545492d..eb5c29e5d 100644
+--- a/doc/admin/conf_files/krb5_conf.rst
++++ b/doc/admin/conf_files/krb5_conf.rst
+@@ -475,6 +475,16 @@ following tags may be specified in the realm's subsection:
+     (for example, when converting ``rcmd.hostname`` to
+     ``host/hostname.domain``).
+ 
++**disable_encrypted_timestamp**
++    If this flag is true, the client will not perform encrypted
++    timestamp preauthentication if requested by the KDC.  Setting this
++    flag can help to prevent dictionary attacks by active attackers,
++    if the realm's KDCs support SPAKE preauthentication or if initial
++    authentication always uses another mechanism or always uses FAST.
++    This flag persists across client referrals during initial
++    authentication.  This flag does not prevent the KDC from offering
++    encrypted timestamp.  New in release 1.17.
++
+ **http_anchors**
+     When KDCs and kpasswd servers are accessed through HTTPS proxies, this tag
+     can be used to specify the location of the CA certificate which should be
+diff --git a/doc/admin/spake.rst b/doc/admin/spake.rst
+index b65c694aa..4f6eeaf53 100644
+--- a/doc/admin/spake.rst
++++ b/doc/admin/spake.rst
+@@ -30,6 +30,14 @@ principal entries, as you would for any preauthentication mechanism::
+ Clients which do not implement SPAKE preauthentication will fall back
+ to encrypted timestamp.
+ 
++An active attacker can force a fallback to encrypted timestamp by
++modifying the initial KDC response, defeating the protection against
++dictionary attacks.  To prevent this fallback on clients which do
++implement SPAKE preauthentication, set the
++**disable_encrypted_timestamp** variable to ``true`` in the
++:ref:`realms` subsection for realms whose KDCs offer SPAKE
++preauthentication.
++
+ By default, SPAKE preauthentication requires an extra network round
+ trip to the KDC during initial authentication.  If most of the clients
+ in a realm support SPAKE, this extra round trip can be eliminated
+diff --git a/src/include/k5-int.h b/src/include/k5-int.h
+index 86b53c76b..e4a9a1412 100644
+--- a/src/include/k5-int.h
++++ b/src/include/k5-int.h
+@@ -204,6 +204,7 @@ typedef unsigned char   u_char;
+ #define KRB5_CONF_DES_CRC_SESSION_SUPPORTED    "des_crc_session_supported"
+ #define KRB5_CONF_DICT_FILE                    "dict_file"
+ #define KRB5_CONF_DISABLE                      "disable"
++#define KRB5_CONF_DISABLE_ENCRYPTED_TIMESTAMP  "disable_encrypted_timestamp"
+ #define KRB5_CONF_DISABLE_LAST_SUCCESS         "disable_last_success"
+ #define KRB5_CONF_DISABLE_LOCKOUT              "disable_lockout"
+ #define KRB5_CONF_DNS_CANONICALIZE_HOSTNAME    "dns_canonicalize_hostname"
+diff --git a/src/include/k5-trace.h b/src/include/k5-trace.h
+index 5f7eb9517..0854974dc 100644
+--- a/src/include/k5-trace.h
++++ b/src/include/k5-trace.h
+@@ -299,6 +299,8 @@ void krb5int_trace(krb5_context context, const char *fmt, ...);
+ #define TRACE_PREAUTH_ENC_TS(c, sec, usec, plain, enc)                  \
+     TRACE(c, "Encrypted timestamp (for {long}.{int}): plain {hexdata}, " \
+           "encrypted {hexdata}", (long) sec, (int) usec, plain, enc)
++#define TRACE_PREAUTH_ENC_TS_DISABLED(c)                                \
++    TRACE(c, "Ignoring encrypted timestamp because it is disabled")
+ #define TRACE_PREAUTH_ETYPE_INFO(c, etype, salt, s2kparams)          \
+     TRACE(c, "Selected etype info: etype {etype}, salt \"{data}\", " \
+           "params \"{data}\"", etype, salt, s2kparams)
+diff --git a/src/lib/krb5/krb/get_in_tkt.c b/src/lib/krb5/krb/get_in_tkt.c
+index c026bbc6d..79dede2c6 100644
+--- a/src/lib/krb5/krb/get_in_tkt.c
++++ b/src/lib/krb5/krb/get_in_tkt.c
+@@ -801,6 +801,24 @@ read_allowed_preauth_type(krb5_context context, krb5_init_creds_context ctx)
+     free(tmp);
+ }
+ 
++/* Return true if encrypted timestamp is disabled for realm. */
++static krb5_boolean
++encts_disabled(profile_t profile, const krb5_data *realm)
++{
++    krb5_error_code ret;
++    char *realmstr;
++    int bval;
++
++    realmstr = k5memdup0(realm->data, realm->length, &ret);
++    if (realmstr == NULL)
++        return FALSE;
++    ret = profile_get_boolean(profile, KRB5_CONF_REALMS, realmstr,
++                              KRB5_CONF_DISABLE_ENCRYPTED_TIMESTAMP, FALSE,
++                              &bval);
++    free(realmstr);
++    return (ret == 0) ? bval : FALSE;
++}
++
+ /**
+  * Throw away any pre-authentication realm state and begin with a
+  * unauthenticated or optimistically authenticated request.  If fast_upgrade is
+@@ -842,6 +860,11 @@ restart_init_creds_loop(krb5_context context, krb5_init_creds_context ctx,
+             goto cleanup;
+     }
+ 
++    /* Never set encts_disabled back to false, so it can't be circumvented with
++     * client realm referrals. */
++    if (encts_disabled(context->profile, &ctx->request->client->realm))
++        ctx->encts_disabled = TRUE;
++
+     krb5_free_principal(context, ctx->request->server);
+     ctx->request->server = NULL;
+ 
+diff --git a/src/lib/krb5/krb/init_creds_ctx.h b/src/lib/krb5/krb/init_creds_ctx.h
+index 7ba61e17c..7a6219b1c 100644
+--- a/src/lib/krb5/krb/init_creds_ctx.h
++++ b/src/lib/krb5/krb/init_creds_ctx.h
+@@ -61,6 +61,7 @@ struct _krb5_init_creds_context {
+     krb5_boolean info_pa_permitted;
+     krb5_boolean restarted;
+     krb5_boolean fallback_disabled;
++    krb5_boolean encts_disabled;
+     struct krb5_responder_context_st rctx;
+     krb5_preauthtype selected_preauth_type;
+     krb5_preauthtype allowed_preauth_type;
+diff --git a/src/lib/krb5/krb/preauth_encts.c b/src/lib/krb5/krb/preauth_encts.c
+index 45bf9da92..345701984 100644
+--- a/src/lib/krb5/krb/preauth_encts.c
++++ b/src/lib/krb5/krb/preauth_encts.c
+@@ -28,6 +28,7 @@
+ #include <k5-int.h>
+ #include <krb5/clpreauth_plugin.h>
+ #include "int-proto.h"
++#include "init_creds_ctx.h"
+ 
+ static krb5_error_code
+ encts_prep_questions(krb5_context context, krb5_clpreauth_moddata moddata,
+@@ -38,7 +39,10 @@ encts_prep_questions(krb5_context context, krb5_clpreauth_moddata moddata,
+                      krb5_data *encoded_previous_request,
+                      krb5_pa_data *pa_data)
+ {
+-    cb->need_as_key(context, rock);
++    krb5_init_creds_context ctx = (krb5_init_creds_context)rock;
++
++    if (!ctx->encts_disabled)
++        cb->need_as_key(context, rock);
+     return 0;
+ }
+ 
+@@ -51,6 +55,7 @@ encts_process(krb5_context context, krb5_clpreauth_moddata moddata,
+               krb5_prompter_fct prompter, void *prompter_data,
+               krb5_pa_data ***out_padata)
+ {
++    krb5_init_creds_context ctx = (krb5_init_creds_context)rock;
+     krb5_error_code ret;
+     krb5_pa_enc_ts pa_enc;
+     krb5_data *ts = NULL, *enc_ts = NULL;
+@@ -60,6 +65,13 @@ encts_process(krb5_context context, krb5_clpreauth_moddata moddata,
+ 
+     enc_data.ciphertext = empty_data();
+ 
++    if (ctx->encts_disabled) {
++        TRACE_PREAUTH_ENC_TS_DISABLED(context);
++        k5_setmsg(context, KRB5_PREAUTH_FAILED,
++                  _("Encrypted timestamp is disabled"));
++        return KRB5_PREAUTH_FAILED;
++    }
++
+     ret = cb->get_as_key(context, rock, &as_key);
+     if (ret)
+         goto cleanup;
+diff --git a/src/tests/t_referral.py b/src/tests/t_referral.py
+index 98fdf2925..e12fdc2e9 100755
+--- a/src/tests/t_referral.py
++++ b/src/tests/t_referral.py
+@@ -126,4 +126,17 @@ r1.klist('user@KRBTEST2.COM', 'krbtgt/KRBTEST2.COM')
+ r1.kinit('abc@XYZ', 'pw', ['-E'])
+ r1.klist('abc\@XYZ@KRBTEST2.COM', 'krbtgt/KRBTEST2.COM')
+ 
++# Test that disable_encrypted_timestamp persists across client
++# referrals.  (This test relies on SPAKE not being enabled by default
++# on the KDC.)
++r2.run([kadminl, 'modprinc', '+preauth', 'user'])
++msgs = ('Encrypted timestamp (for ')
++r1.kinit('user', password('user'), ['-C'], expected_trace=msgs)
++dconf = {'realms': {'$realm': {'disable_encrypted_timestamp': 'true'}}}
++denv = r1.special_env('disable_encts', False, krb5_conf=dconf)
++msgs = ('Ignoring encrypted timestamp because it is disabled',
++        '/Encrypted timestamp is disabled')
++r1.kinit('user', None, ['-C'], env=denv, expected_code=1, expected_trace=msgs,
++         expected_msg='Encrypted timestamp is disabled')
++
+ success('KDC host referral tests')
diff --git a/SOURCES/Add-k5_buf_add_vfmt-to-k5buf-interface.patch b/SOURCES/Add-k5_buf_add_vfmt-to-k5buf-interface.patch
new file mode 100644
index 0000000..1a333a7
--- /dev/null
+++ b/SOURCES/Add-k5_buf_add_vfmt-to-k5buf-interface.patch
@@ -0,0 +1,119 @@
+From 74e1079df0cc6e8932e487455177a69f782b863a Mon Sep 17 00:00:00 2001
+From: Greg Hudson <ghudson@mit.edu>
+Date: Thu, 4 Jan 2018 14:35:12 -0500
+Subject: [PATCH] Add k5_buf_add_vfmt to k5buf interface
+
+(cherry picked from commit f05766469efc2a055085c0bcf9d40c4cdf47fe36)
+---
+ src/include/k5-buf.h                          |  8 ++++++
+ src/util/support/k5buf.c                      | 26 +++++++++++--------
+ src/util/support/libkrb5support-fixed.exports |  1 +
+ 3 files changed, 24 insertions(+), 11 deletions(-)
+
+diff --git a/src/include/k5-buf.h b/src/include/k5-buf.h
+index f3207bd09..1223916a6 100644
+--- a/src/include/k5-buf.h
++++ b/src/include/k5-buf.h
+@@ -76,6 +76,14 @@ void k5_buf_add_fmt(struct k5buf *buf, const char *fmt, ...)
+ #endif
+     ;
+ 
++/* Add sprintf-style formatted data to BUF, with a va_list.  The value of ap is
++ * undefined after the call. */
++void k5_buf_add_vfmt(struct k5buf *buf, const char *fmt, va_list ap)
++#if !defined(__cplusplus) && (__GNUC__ > 2)
++    __attribute__((__format__(__printf__, 2, 0)))
++#endif
++    ;
++
+ /* Extend the length of buf by len and return a pointer to the reserved space,
+  * to be filled in by the caller.  Return NULL on error. */
+ void *k5_buf_get_space(struct k5buf *buf, size_t len);
+diff --git a/src/util/support/k5buf.c b/src/util/support/k5buf.c
+index f619f6a48..35978f238 100644
+--- a/src/util/support/k5buf.c
++++ b/src/util/support/k5buf.c
+@@ -141,9 +141,9 @@ k5_buf_add_len(struct k5buf *buf, const void *data, size_t len)
+ }
+ 
+ void
+-k5_buf_add_fmt(struct k5buf *buf, const char *fmt, ...)
++k5_buf_add_vfmt(struct k5buf *buf, const char *fmt, va_list ap)
+ {
+-    va_list ap;
++    va_list apcopy;
+     int r;
+     size_t remaining;
+     char *tmp;
+@@ -154,9 +154,7 @@ k5_buf_add_fmt(struct k5buf *buf, const char *fmt, ...)
+ 
+     if (buf->buftype == K5BUF_FIXED) {
+         /* Format the data directly into the fixed buffer. */
+-        va_start(ap, fmt);
+         r = vsnprintf(endptr(buf), remaining, fmt, ap);
+-        va_end(ap);
+         if (SNPRINTF_OVERFLOW(r, remaining))
+             set_error(buf);
+         else
+@@ -166,9 +164,9 @@ k5_buf_add_fmt(struct k5buf *buf, const char *fmt, ...)
+ 
+     /* Optimistically format the data directly into the dynamic buffer. */
+     assert(buf->buftype == K5BUF_DYNAMIC);
+-    va_start(ap, fmt);
+-    r = vsnprintf(endptr(buf), remaining, fmt, ap);
+-    va_end(ap);
++    va_copy(apcopy, ap);
++    r = vsnprintf(endptr(buf), remaining, fmt, apcopy);
++    va_end(apcopy);
+     if (!SNPRINTF_OVERFLOW(r, remaining)) {
+         buf->len += (unsigned int) r;
+         return;
+@@ -179,9 +177,7 @@ k5_buf_add_fmt(struct k5buf *buf, const char *fmt, ...)
+         if (!ensure_space(buf, r))
+             return;
+         remaining = buf->space - buf->len;
+-        va_start(ap, fmt);
+         r = vsnprintf(endptr(buf), remaining, fmt, ap);
+-        va_end(ap);
+         if (SNPRINTF_OVERFLOW(r, remaining))  /* Shouldn't ever happen. */
+             k5_buf_free(buf);
+         else
+@@ -191,9 +187,7 @@ k5_buf_add_fmt(struct k5buf *buf, const char *fmt, ...)
+ 
+     /* It's a pre-C99 snprintf implementation, or something else went wrong.
+      * Fall back to asprintf. */
+-    va_start(ap, fmt);
+     r = vasprintf(&tmp, fmt, ap);
+-    va_end(ap);
+     if (r < 0) {
+         k5_buf_free(buf);
+         return;
+@@ -206,6 +200,16 @@ k5_buf_add_fmt(struct k5buf *buf, const char *fmt, ...)
+     free(tmp);
+ }
+ 
++void
++k5_buf_add_fmt(struct k5buf *buf, const char *fmt, ...)
++{
++    va_list ap;
++
++    va_start(ap, fmt);
++    k5_buf_add_vfmt(buf, fmt, ap);
++    va_end(ap);
++}
++
+ void *
+ k5_buf_get_space(struct k5buf *buf, size_t len)
+ {
+diff --git a/src/util/support/libkrb5support-fixed.exports b/src/util/support/libkrb5support-fixed.exports
+index 30c946e7e..cb9bf0826 100644
+--- a/src/util/support/libkrb5support-fixed.exports
++++ b/src/util/support/libkrb5support-fixed.exports
+@@ -6,6 +6,7 @@ k5_buf_init_dynamic
+ k5_buf_add
+ k5_buf_add_len
+ k5_buf_add_fmt
++k5_buf_add_vfmt
+ k5_buf_get_space
+ k5_buf_truncate
+ k5_buf_status
diff --git a/SOURCES/Add-k5_dir_filenames-to-libkrb5support.patch b/SOURCES/Add-k5_dir_filenames-to-libkrb5support.patch
new file mode 100644
index 0000000..d420f15
--- /dev/null
+++ b/SOURCES/Add-k5_dir_filenames-to-libkrb5support.patch
@@ -0,0 +1,222 @@
+From 9010a0dbf59771cb0a9c1e6fd5a18a92a1200ca7 Mon Sep 17 00:00:00 2001
+From: Greg Hudson <ghudson@mit.edu>
+Date: Tue, 5 Jun 2018 14:01:05 -0400
+Subject: [PATCH] Add k5_dir_filenames() to libkrb5support
+
+Add a support function to get a list of filenames from a directory in
+sorted order.
+
+(cherry picked from commit 27534121eb39089ff4335d8b465027e9ba783682)
+---
+ src/include/k5-platform.h                     |   7 +
+ src/util/support/Makefile.in                  |   3 +
+ src/util/support/dir_filenames.c              | 135 ++++++++++++++++++
+ src/util/support/libkrb5support-fixed.exports |   2 +
+ 4 files changed, 147 insertions(+)
+ create mode 100644 src/util/support/dir_filenames.c
+
+diff --git a/src/include/k5-platform.h b/src/include/k5-platform.h
+index 07ef6a4ca..763408a09 100644
+--- a/src/include/k5-platform.h
++++ b/src/include/k5-platform.h
+@@ -44,6 +44,8 @@
+  * + constant time memory comparison
+  * + path manipulation
+  * + _, N_, dgettext, bindtextdomain (for localization)
++ * + getopt_long
++ * + fetching filenames from a directory
+  */
+ 
+ #ifndef K5_PLATFORM_H
+@@ -1148,4 +1150,9 @@ extern int k5_getopt_long(int nargc, char **nargv, char *options,
+ #define getopt_long k5_getopt_long
+ #endif /* HAVE_GETOPT_LONG */
+ 
++/* Set *fnames_out to a null-terminated list of filenames within dirname,
++ * sorted according to strcmp().  Return 0 on success, or ENOENT/ENOMEM. */
++int k5_dir_filenames(const char *dirname, char ***fnames_out);
++void k5_free_filenames(char **fnames);
++
+ #endif /* K5_PLATFORM_H */
+diff --git a/src/util/support/Makefile.in b/src/util/support/Makefile.in
+index caaf15822..4715e0391 100644
+--- a/src/util/support/Makefile.in
++++ b/src/util/support/Makefile.in
+@@ -85,6 +85,7 @@ STLIBOBJS= \
+ 	hex.o \
+ 	bcmp.o \
+ 	strerror_r.o \
++	dir_filenames.o \
+ 	$(GETTIMEOFDAY_ST_OBJ) \
+ 	$(IPC_ST_OBJ) \
+ 	$(STRLCPY_ST_OBJ) \
+@@ -111,6 +112,7 @@ LIBOBJS= \
+ 	$(OUTPRE)hex.$(OBJEXT) \
+ 	$(OUTPRE)bcmp.$(OBJEXT) \
+ 	$(OUTPRE)strerror_r.$(OBJEXT) \
++	$(OUTPRE)dir_filenames.$(OBJEXT) \
+ 	$(GETTIMEOFDAY_OBJ) \
+ 	$(IPC_OBJ) \
+ 	$(STRLCPY_OBJ) \
+@@ -147,6 +149,7 @@ SRCS=\
+ 	$(srcdir)/hex.c \
+ 	$(srcdir)/bcmp.c \
+ 	$(srcdir)/strerror_r.c \
++	$(srcdir)/dir_filenames.c \
+ 	$(srcdir)/t_utf8.c \
+ 	$(srcdir)/t_utf16.c \
+ 	$(srcdir)/getopt.c \
+diff --git a/src/util/support/dir_filenames.c b/src/util/support/dir_filenames.c
+new file mode 100644
+index 000000000..9312b0238
+--- /dev/null
++++ b/src/util/support/dir_filenames.c
+@@ -0,0 +1,135 @@
++/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
++/* util/support/dir_filenames.c - fetch filenames in a directory */
++/*
++ * Copyright (C) 2018 by the Massachusetts Institute of Technology.
++ * 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.
++ */
++
++#include "k5-platform.h"
++
++void
++k5_free_filenames(char **fnames)
++{
++    char **fn;
++
++    for (fn = fnames; fn != NULL && *fn != NULL; fn++)
++        free(*fn);
++    free(fnames);
++}
++
++/* Resize the filename list and add a name. */
++static int
++add_filename(char ***fnames, int *n_fnames, const char *name)
++{
++    char **newlist;
++
++    newlist = realloc(*fnames, (*n_fnames + 2) * sizeof(*newlist));
++    if (newlist == NULL)
++        return ENOMEM;
++    *fnames = newlist;
++    newlist[*n_fnames] = strdup(name);
++    if (newlist[*n_fnames] == NULL)
++        return ENOMEM;
++    (*n_fnames)++;
++    newlist[*n_fnames] = NULL;
++    return 0;
++}
++
++static int
++compare_with_strcmp(const void *a, const void *b)
++{
++    return strcmp(*(char **)a, *(char **)b);
++}
++
++#ifdef _WIN32
++
++int
++k5_dir_filenames(const char *dirname, char ***fnames_out)
++{
++    char *wildcard;
++    WIN32_FIND_DATA ffd;
++    HANDLE handle;
++    char **fnames = NULL;
++    int n_fnames = 0;
++
++    *fnames_out = NULL;
++
++    if (asprintf(&wildcard, "%s\\*", dirname) < 0)
++        return ENOMEM;
++    handle = FindFirstFile(wildcard, &ffd);
++    free(wildcard);
++    if (handle == INVALID_HANDLE_VALUE)
++        return ENOENT;
++
++    do {
++        if (add_filename(&fnames, &n_fnames, &ffd.cFileName) != 0) {
++            k5_free_filenames(fnames);
++            FindClose(handle);
++            return ENOMEM;
++        }
++    } while (FindNextFile(handle, &ffd) != 0);
++
++    FindClose(handle);
++    qsort(fnames, n_fnames, sizeof(*fnames), compare_with_strcmp);
++    *fnames_out = fnames;
++    return 0;
++}
++
++#else /* _WIN32 */
++
++#include <dirent.h>
++
++int
++k5_dir_filenames(const char *dirname, char ***fnames_out)
++{
++    DIR *dir;
++    struct dirent *ent;
++    char **fnames = NULL;
++    int n_fnames = 0;
++
++    *fnames_out = NULL;
++
++    dir = opendir(dirname);
++    if (dir == NULL)
++        return ENOENT;
++
++    while ((ent = readdir(dir)) != NULL) {
++        if (add_filename(&fnames, &n_fnames, ent->d_name) != 0) {
++            k5_free_filenames(fnames);
++            closedir(dir);
++            return ENOMEM;
++        }
++    }
++
++    closedir(dir);
++    qsort(fnames, n_fnames, sizeof(*fnames), compare_with_strcmp);
++    *fnames_out = fnames;
++    return 0;
++}
++
++#endif /* not _WIN32 */
+diff --git a/src/util/support/libkrb5support-fixed.exports b/src/util/support/libkrb5support-fixed.exports
+index a5e2ade04..16ed5a6c1 100644
+--- a/src/util/support/libkrb5support-fixed.exports
++++ b/src/util/support/libkrb5support-fixed.exports
+@@ -58,6 +58,8 @@ k5_path_split
+ k5_strerror_r
+ k5_utf8_to_utf16le
+ k5_utf16le_to_utf8
++k5_dir_filenames
++k5_free_filenames
+ krb5int_key_register
+ krb5int_key_delete
+ krb5int_getspecific
diff --git a/SOURCES/Add-k5test-mark-function.patch b/SOURCES/Add-k5test-mark-function.patch
new file mode 100644
index 0000000..0b2b9fa
--- /dev/null
+++ b/SOURCES/Add-k5test-mark-function.patch
@@ -0,0 +1,60 @@
+From 68b61c6d6402c0ad57509705137c92ae814ace27 Mon Sep 17 00:00:00 2001
+From: Greg Hudson <ghudson@mit.edu>
+Date: Wed, 18 Apr 2018 19:21:40 -0400
+Subject: [PATCH] Add k5test mark() function
+
+Make it easier to locate a failing command in long Python test scripts
+by allowing the script to output marks, and displaying the most recent
+mark with command failures.
+
+(cherry picked from commit 4e813204ac3dace93297f47d64dfc0aaecc370f8)
+---
+ src/util/k5test.py | 14 ++++++++++++++
+ 1 file changed, 14 insertions(+)
+
+diff --git a/src/util/k5test.py b/src/util/k5test.py
+index 4d30baf40..bc32877a7 100644
+--- a/src/util/k5test.py
++++ b/src/util/k5test.py
+@@ -141,6 +141,11 @@ Scripts may use the following functions and variables:
+   added newline) in testlog, and write it to stdout if running
+   verbosely.
+ 
++* mark(message): Place a divider message in the test output, to make
++  it easier to determine what part of the test script a command
++  invocation belongs to.  The last mark message will also be displayed
++  if a command invocation fails.  Do not include a newline in message.
++
+ * which(progname): Return the location of progname in the executable
+   path, or None if it is not found.
+ 
+@@ -376,6 +381,8 @@ def fail(msg):
+     """Print a message and exit with failure."""
+     global _current_pass
+     print "*** Failure:", msg
++    if _last_mark:
++        print "*** Last mark: %s" % _last_mark
+     if _last_cmd:
+         print "*** Last command (#%d): %s" % (_cmd_index - 1, _last_cmd)
+     if _last_cmd_output:
+@@ -392,6 +399,12 @@ def success(msg):
+     _success = True
+ 
+ 
++def mark(msg):
++    global _last_mark
++    output('\n====== %s ======\n' % msg)
++    _last_mark = msg
++
++
+ def skipped(whatmsg, whymsg):
+     output('*** Skipping: %s: %s\n' % (whatmsg, whymsg), force_verbose=True)
+     f = open(os.path.join(buildtop, 'skiptests'), 'a')
+@@ -1275,6 +1288,7 @@ atexit.register(_onexit)
+ signal.signal(signal.SIGINT, _onsigint)
+ _outfile = open('testlog', 'w')
+ _cmd_index = 1
++_last_mark = None
+ _last_cmd = None
+ _last_cmd_output = None
+ buildtop = _find_buildtop()
diff --git a/SOURCES/Add-libkrb5support-hex-functions-and-tests.patch b/SOURCES/Add-libkrb5support-hex-functions-and-tests.patch
new file mode 100644
index 0000000..d7caab2
--- /dev/null
+++ b/SOURCES/Add-libkrb5support-hex-functions-and-tests.patch
@@ -0,0 +1,484 @@
+From 507b1aff60fdadc91ca7c56d39711049aeeb1e58 Mon Sep 17 00:00:00 2001
+From: Greg Hudson <ghudson@mit.edu>
+Date: Mon, 19 Feb 2018 00:51:44 -0500
+Subject: [PATCH] Add libkrb5support hex functions and tests
+
+(cherry picked from commit 720dea558da0062d3cea4385327161e62cf09a5e)
+[rharwood@redhat.com Remove .gitignore]
+---
+ src/include/k5-hex.h                          |  53 ++++++
+ src/util/support/Makefile.in                  |  15 +-
+ src/util/support/deps                         |   6 +
+ src/util/support/hex.c                        | 116 ++++++++++++
+ src/util/support/libkrb5support-fixed.exports |   2 +
+ src/util/support/t_hex.c                      | 169 ++++++++++++++++++
+ 6 files changed, 358 insertions(+), 3 deletions(-)
+ create mode 100644 src/include/k5-hex.h
+ create mode 100644 src/util/support/hex.c
+ create mode 100644 src/util/support/t_hex.c
+
+diff --git a/src/include/k5-hex.h b/src/include/k5-hex.h
+new file mode 100644
+index 000000000..75bd2cb19
+--- /dev/null
++++ b/src/include/k5-hex.h
+@@ -0,0 +1,53 @@
++/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
++/* include/k5-hex.h - libkrb5support hex encoding/decoding declarations */
++/*
++ * Copyright (C) 2018 by the Massachusetts Institute of Technology.
++ * 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.
++ */
++
++#ifndef K5_HEX_H
++#define K5_HEX_H
++
++#include "k5-platform.h"
++
++/*
++ * Encode len bytes in hex, placing the result in allocated storage in
++ * *hex_out.  Use uppercase hex digits if uppercase is non-zero.  Return 0 on
++ * success, ENOMEM on error.
++ */
++int k5_hex_encode(const void *bytes, size_t len, int uppercase,
++                  char **hex_out);
++
++/*
++ * Decode hex bytes, placing the result in allocated storage in *bytes_out and
++ * *len_out.  Null-terminate the result (primarily for decoding passwords in
++ * libkdb_ldap).  Return 0 on success, ENOMEM or EINVAL on error.
++ */
++int k5_hex_decode(const char *hex, uint8_t **bytes_out, size_t *len_out);
++
++#endif /* K5_HEX_H */
+diff --git a/src/util/support/Makefile.in b/src/util/support/Makefile.in
+index 58ac2e333..caaf15822 100644
+--- a/src/util/support/Makefile.in
++++ b/src/util/support/Makefile.in
+@@ -82,6 +82,7 @@ STLIBOBJS= \
+ 	path.o \
+ 	base64.o \
+ 	json.o \
++	hex.o \
+ 	bcmp.o \
+ 	strerror_r.o \
+ 	$(GETTIMEOFDAY_ST_OBJ) \
+@@ -107,6 +108,7 @@ LIBOBJS= \
+ 	$(OUTPRE)path.$(OBJEXT) \
+ 	$(OUTPRE)base64.$(OBJEXT) \
+ 	$(OUTPRE)json.$(OBJEXT) \
++	$(OUTPRE)hex.$(OBJEXT) \
+ 	$(OUTPRE)bcmp.$(OBJEXT) \
+ 	$(OUTPRE)strerror_r.$(OBJEXT) \
+ 	$(GETTIMEOFDAY_OBJ) \
+@@ -137,10 +139,12 @@ SRCS=\
+ 	$(srcdir)/t_unal.c \
+ 	$(srcdir)/t_path.c \
+ 	$(srcdir)/t_json.c \
++	$(srcdir)/t_hex.c \
+ 	$(srcdir)/zap.c \
+ 	$(srcdir)/path.c \
+ 	$(srcdir)/base64.c \
+ 	$(srcdir)/json.c \
++	$(srcdir)/hex.c \
+ 	$(srcdir)/bcmp.c \
+ 	$(srcdir)/strerror_r.c \
+ 	$(srcdir)/t_utf8.c \
+@@ -216,6 +220,9 @@ T_JSON_OBJS= t_json.o json.o base64.o k5buf.o $(PRINTF_ST_OBJ)
+ t_json: $(T_JSON_OBJS)
+ 	$(CC_LINK) -o $@ $(T_JSON_OBJS)
+ 
++t_hex: t_hex.o hex.o
++	$(CC_LINK) -o $@ t_hex.o hex.o
++
+ t_unal: t_unal.o
+ 	$(CC_LINK) -o t_unal t_unal.o
+ 
+@@ -227,7 +234,8 @@ T_UTF16_OBJS= t_utf16.o utf8_conv.o utf8.o k5buf.o $(PRINTF_ST_OBJ)
+ t_utf16: $(T_UTF16_OBJS)
+ 	$(CC_LINK) -o $@ $(T_UTF16_OBJS)
+ 
+-TEST_PROGS= t_k5buf t_path t_path_win t_base64 t_json t_unal t_utf8 t_utf16
++TEST_PROGS= t_k5buf t_path t_path_win t_base64 t_json t_hex t_unal t_utf8 \
++	t_utf16
+ 
+ check-unix: $(TEST_PROGS)
+ 	./t_k5buf
+@@ -235,6 +243,7 @@ check-unix: $(TEST_PROGS)
+ 	./t_path_win
+ 	./t_base64
+ 	./t_json
++	./t_hex
+ 	./t_unal
+ 	./t_utf8
+ 	./t_utf16
+@@ -242,8 +251,8 @@ check-unix: $(TEST_PROGS)
+ clean:
+ 	$(RM) t_k5buf.o t_k5buf t_unal.o t_unal path_win.o path_win
+ 	$(RM) t_path_win.o t_path_win t_path.o t_path t_base64.o t_base64
+-	$(RM) t_json.o t_json libkrb5support.exports t_utf8.o t_utf8
+-	$(RM) t_utf16.o t_utf16
++	$(RM) t_json.o t_json t_hex.o t_hex libkrb5support.exports
++	$(RM) t_utf8.o t_utf8 t_utf16.o t_utf16
+ 
+ @lib_frag@
+ @libobj_frag@
+diff --git a/src/util/support/deps b/src/util/support/deps
+index 34d8a884b..80e9a1c58 100644
+--- a/src/util/support/deps
++++ b/src/util/support/deps
+@@ -63,6 +63,9 @@ t_path.so t_path.po $(OUTPRE)t_path.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \
+   t_path.c
+ t_json.so t_json.po $(OUTPRE)t_json.$(OBJEXT): $(top_srcdir)/include/k5-json.h \
+   t_json.c
++t_hex.so t_hex.po $(OUTPRE)t_hex.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \
++  $(top_srcdir)/include/k5-hex.h $(top_srcdir)/include/k5-platform.h \
++  $(top_srcdir)/include/k5-thread.h t_hex.c
+ zap.so zap.po $(OUTPRE)zap.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \
+   $(top_srcdir)/include/k5-platform.h $(top_srcdir)/include/k5-thread.h \
+   zap.c
+@@ -76,6 +79,9 @@ json.so json.po $(OUTPRE)json.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \
+   $(top_srcdir)/include/k5-base64.h $(top_srcdir)/include/k5-buf.h \
+   $(top_srcdir)/include/k5-json.h $(top_srcdir)/include/k5-platform.h \
+   $(top_srcdir)/include/k5-thread.h json.c
++hex.so hex.po $(OUTPRE)hex.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \
++  $(top_srcdir)/include/k5-hex.h $(top_srcdir)/include/k5-platform.h \
++  $(top_srcdir)/include/k5-thread.h hex.c
+ bcmp.so bcmp.po $(OUTPRE)bcmp.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \
+   $(top_srcdir)/include/k5-platform.h $(top_srcdir)/include/k5-thread.h \
+   bcmp.c
+diff --git a/src/util/support/hex.c b/src/util/support/hex.c
+new file mode 100644
+index 000000000..4407ff9ff
+--- /dev/null
++++ b/src/util/support/hex.c
+@@ -0,0 +1,116 @@
++/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
++/* util/support/hex.c - hex encoding/decoding implementation */
++/*
++ * Copyright (C) 2018 by the Massachusetts Institute of Technology.
++ * 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.
++ */
++
++#include <k5-platform.h>
++#include <k5-hex.h>
++#include <ctype.h>
++
++static inline char
++hex_digit(uint8_t bval, int uppercase)
++{
++    assert(bval >= 0 && bval <= 0xF);
++    if (bval < 10)
++        return '0' + bval;
++    else if (uppercase)
++        return 'A' + (bval - 10);
++    else
++        return 'a' + (bval - 10);
++}
++
++int
++k5_hex_encode(const void *bytes, size_t len, int uppercase, char **hex_out)
++{
++    size_t i;
++    const uint8_t *p = bytes;
++    char *hex;
++
++    *hex_out = NULL;
++
++    hex = malloc(len * 2 + 1);
++    if (hex == NULL)
++        return ENOMEM;
++
++    for (i = 0; i < len; i++) {
++        hex[i * 2] = hex_digit(p[i] >> 4, uppercase);
++        hex[i * 2 + 1] = hex_digit(p[i] & 0xF, uppercase);
++    }
++    hex[len * 2] = '\0';
++
++    *hex_out = hex;
++    return 0;
++}
++
++/* Decode a hex digit.  Return 0-15 on success, -1 on invalid input. */
++static inline int
++decode_hexchar(unsigned char c)
++{
++    if (isdigit(c))
++        return c - '0';
++    if (c >= 'A' && c <= 'F')
++        return c - 'A' + 10;
++    if (c >= 'a' && c <= 'f')
++        return c - 'a' + 10;
++    return -1;
++}
++
++int
++k5_hex_decode(const char *hex, uint8_t **bytes_out, size_t *len_out)
++{
++    size_t hexlen, i;
++    int h1, h2;
++    uint8_t *bytes;
++
++    *bytes_out = NULL;
++    *len_out = 0;
++
++    hexlen = strlen(hex);
++    if (hexlen % 2 != 0)
++        return EINVAL;
++    bytes = malloc(hexlen / 2 + 1);
++    if (bytes == NULL)
++        return ENOMEM;
++
++    for (i = 0; i < hexlen / 2; i++) {
++        h1 = decode_hexchar(hex[i * 2]);
++        h2 = decode_hexchar(hex[i * 2 + 1]);
++        if (h1 == -1 || h2 == -1) {
++            free(bytes);
++            return EINVAL;
++        }
++        bytes[i] = h1 * 16 + h2;
++    }
++    bytes[i] = 0;
++
++    *bytes_out = bytes;
++    *len_out = hexlen / 2;
++    return 0;
++}
+diff --git a/src/util/support/libkrb5support-fixed.exports b/src/util/support/libkrb5support-fixed.exports
+index fd74a1897..30c946e7e 100644
+--- a/src/util/support/libkrb5support-fixed.exports
++++ b/src/util/support/libkrb5support-fixed.exports
+@@ -16,6 +16,8 @@ k5_get_error
+ k5_free_error
+ k5_clear_error
+ k5_set_error_info_callout_fn
++k5_hex_decode
++k5_hex_encode
+ k5_json_array_add
+ k5_json_array_create
+ k5_json_array_fmt
+diff --git a/src/util/support/t_hex.c b/src/util/support/t_hex.c
+new file mode 100644
+index 000000000..a586a1bc8
+--- /dev/null
++++ b/src/util/support/t_hex.c
+@@ -0,0 +1,169 @@
++/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
++/* util/support/t_hex.c - Test hex encoding and decoding */
++/*
++ * Copyright (C) 2018 by the Massachusetts Institute of Technology.
++ * 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.
++ */
++
++#include <k5-platform.h>
++#include <k5-hex.h>
++
++struct {
++    const char *hex;
++    const char *binary;
++    size_t binary_len;
++    int uppercase;
++} tests[] = {
++    /* Invalid hex strings */
++    { "1" },
++    { "123" },
++    { "0/" },
++    { "/0" },
++    { "0:" },
++    { ":0" },
++    { "0@" },
++    { "@0" },
++    { "0G" },
++    { "G0" },
++    { "0`" },
++    { "`0" },
++    { "0g" },
++    { "g0" },
++    { " 00 " },
++    { "0\x01" },
++
++    { "", "", 0 },
++    { "00", "\x00", 1 },
++    { "01", "\x01", 1 },
++    { "10", "\x10", 1 },
++    { "01ff", "\x01\xFF", 2 },
++    { "A0B0C0", "\xA0\xB0\xC0", 3, 1 },
++    { "1a2b3c4d5e6f", "\x1A\x2B\x3C\x4D\x5E\x6F", 6 },
++    { "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
++      "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
++      "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF", 32 },
++
++    /* All byte values, lowercase */
++    { "0001020304050607", "\x00\x01\x02\x03\x04\x05\x06\x07", 8 },
++    { "08090a0b0c0d0e0f", "\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F", 8 },
++    { "1011121314151617", "\x10\x11\x12\x13\x14\x15\x16\x17", 8 },
++    { "18191a1b1c1d1e1f", "\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F", 8 },
++    { "2021222324252627", "\x20\x21\x22\x23\x24\x25\x26\x27", 8 },
++    { "28292a2b2c2d2e2f", "\x28\x29\x2A\x2B\x2C\x2D\x2E\x2F", 8 },
++    { "3031323334353637", "\x30\x31\x32\x33\x34\x35\x36\x37", 8 },
++    { "38393a3b3c3d3e3f", "\x38\x39\x3A\x3B\x3C\x3D\x3E\x3F", 8 },
++    { "4041424344454647", "\x40\x41\x42\x43\x44\x45\x46\x47", 8 },
++    { "48494a4b4c4d4e4f", "\x48\x49\x4A\x4B\x4C\x4D\x4E\x4F", 8 },
++    { "5051525354555657", "\x50\x51\x52\x53\x54\x55\x56\x57", 8 },
++    { "58595a5b5c5d5e5f", "\x58\x59\x5A\x5B\x5C\x5D\x5E\x5F", 8 },
++    { "6061626364656667", "\x60\x61\x62\x63\x64\x65\x66\x67", 8 },
++    { "68696a6b6c6d6e6f", "\x68\x69\x6A\x6B\x6C\x6D\x6E\x6F", 8 },
++    { "7071727374757677", "\x70\x71\x72\x73\x74\x75\x76\x77", 8 },
++    { "78797a7b7c7d7e7f", "\x78\x79\x7A\x7B\x7C\x7D\x7E\x7F", 8 },
++    { "8081828384858687", "\x80\x81\x82\x83\x84\x85\x86\x87", 8 },
++    { "88898a8b8c8d8e8f", "\x88\x89\x8A\x8B\x8C\x8D\x8E\x8F", 8 },
++    { "9091929394959697", "\x90\x91\x92\x93\x94\x95\x96\x97", 8 },
++    { "98999a9b9c9d9e9f", "\x98\x99\x9A\x9B\x9C\x9D\x9E\x9F", 8 },
++    { "a0a1a2a3a4a5a6a7", "\xA0\xA1\xA2\xA3\xA4\xA5\xA6\xA7", 8 },
++    { "a8a9aaabacadaeaf", "\xA8\xA9\xAA\xAB\xAC\xAD\xAE\xAF", 8 },
++    { "b0b1b2b3b4b5b6b7", "\xB0\xB1\xB2\xB3\xB4\xB5\xB6\xB7", 8 },
++    { "b8b9babbbcbdbebf", "\xB8\xB9\xBA\xBB\xBC\xBD\xBE\xBF", 8 },
++    { "c0c1c2c3c4c5c6c7", "\xC0\xC1\xC2\xC3\xC4\xC5\xC6\xC7", 8 },
++    { "c8c9cacbcccdcecf", "\xC8\xC9\xCA\xCB\xCC\xCD\xCE\xCF", 8 },
++    { "d0d1d2d3d4d5d6d7", "\xD0\xD1\xD2\xD3\xD4\xD5\xD6\xD7", 8 },
++    { "d8d9dadbdcdddedf", "\xD8\xD9\xDA\xDB\xDC\xDD\xDE\xDF", 8 },
++    { "e0e1e2e3e4e5e6e7", "\xE0\xE1\xE2\xE3\xE4\xE5\xE6\xE7", 8 },
++    { "e8e9eaebecedeeef", "\xE8\xE9\xEA\xEB\xEC\xED\xEE\xEF", 8 },
++    { "f0f1f2f3f4f5f6f7", "\xF0\xF1\xF2\xF3\xF4\xF5\xF6\xF7", 8 },
++    { "f8f9fafbfcfdfeff", "\xF8\xF9\xFA\xFB\xFC\xFD\xFE\xFF", 8 },
++
++    /* All byte values, uppercase */
++    { "0001020304050607", "\x00\x01\x02\x03\x04\x05\x06\x07", 8, 1 },
++    { "08090A0B0C0D0E0F", "\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F", 8, 1 },
++    { "1011121314151617", "\x10\x11\x12\x13\x14\x15\x16\x17", 8, 1 },
++    { "18191A1B1C1D1E1F", "\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F", 8, 1 },
++    { "2021222324252627", "\x20\x21\x22\x23\x24\x25\x26\x27", 8, 1 },
++    { "28292A2B2C2D2E2F", "\x28\x29\x2A\x2B\x2C\x2D\x2E\x2F", 8, 1 },
++    { "3031323334353637", "\x30\x31\x32\x33\x34\x35\x36\x37", 8, 1 },
++    { "38393A3B3C3D3E3F", "\x38\x39\x3A\x3B\x3C\x3D\x3E\x3F", 8, 1 },
++    { "4041424344454647", "\x40\x41\x42\x43\x44\x45\x46\x47", 8, 1 },
++    { "48494A4B4C4D4E4F", "\x48\x49\x4A\x4B\x4C\x4D\x4E\x4F", 8, 1 },
++    { "5051525354555657", "\x50\x51\x52\x53\x54\x55\x56\x57", 8, 1 },
++    { "58595A5B5C5D5E5F", "\x58\x59\x5A\x5B\x5C\x5D\x5E\x5F", 8, 1 },
++    { "6061626364656667", "\x60\x61\x62\x63\x64\x65\x66\x67", 8, 1 },
++    { "68696A6B6C6D6E6F", "\x68\x69\x6A\x6B\x6C\x6D\x6E\x6F", 8, 1 },
++    { "7071727374757677", "\x70\x71\x72\x73\x74\x75\x76\x77", 8, 1 },
++    { "78797A7B7C7D7E7F", "\x78\x79\x7A\x7B\x7C\x7D\x7E\x7F", 8, 1 },
++    { "8081828384858687", "\x80\x81\x82\x83\x84\x85\x86\x87", 8, 1 },
++    { "88898A8B8C8D8E8F", "\x88\x89\x8A\x8B\x8C\x8D\x8E\x8F", 8, 1 },
++    { "9091929394959697", "\x90\x91\x92\x93\x94\x95\x96\x97", 8, 1 },
++    { "98999A9B9C9D9E9F", "\x98\x99\x9A\x9B\x9C\x9D\x9E\x9F", 8, 1 },
++    { "A0A1A2A3A4A5A6A7", "\xA0\xA1\xA2\xA3\xA4\xA5\xA6\xA7", 8, 1 },
++    { "A8A9AAABACADAEAF", "\xA8\xA9\xAA\xAB\xAC\xAD\xAE\xAF", 8, 1 },
++    { "B0B1B2B3B4B5B6B7", "\xB0\xB1\xB2\xB3\xB4\xB5\xB6\xB7", 8, 1 },
++    { "B8B9BABBBCBDBEBF", "\xB8\xB9\xBA\xBB\xBC\xBD\xBE\xBF", 8, 1 },
++    { "C0C1C2C3C4C5C6C7", "\xC0\xC1\xC2\xC3\xC4\xC5\xC6\xC7", 8, 1 },
++    { "C8C9CACBCCCDCECF", "\xC8\xC9\xCA\xCB\xCC\xCD\xCE\xCF", 8, 1 },
++    { "D0D1D2D3D4D5D6D7", "\xD0\xD1\xD2\xD3\xD4\xD5\xD6\xD7", 8, 1 },
++    { "D8D9DADBDCDDDEDF", "\xD8\xD9\xDA\xDB\xDC\xDD\xDE\xDF", 8, 1 },
++    { "E0E1E2E3E4E5E6E7", "\xE0\xE1\xE2\xE3\xE4\xE5\xE6\xE7", 8, 1 },
++    { "E8E9EAEBECEDEEEF", "\xE8\xE9\xEA\xEB\xEC\xED\xEE\xEF", 8, 1 },
++    { "F0F1F2F3F4F5F6F7", "\xF0\xF1\xF2\xF3\xF4\xF5\xF6\xF7", 8, 1 },
++    { "F8F9FAFBFCFDFEFF", "\xF8\xF9\xFA\xFB\xFC\xFD\xFE\xFF", 8, 1 },
++};
++
++int main()
++{
++    size_t i;
++    char *hex;
++    int ret;
++    uint8_t *bytes;
++    size_t len;
++
++    for (i = 0; i < sizeof(tests) / sizeof(*tests); i++) {
++        if (tests[i].binary == NULL) {
++            ret = k5_hex_decode(tests[i].hex, &bytes, &len);
++            assert(ret == EINVAL && bytes == NULL && len == 0);
++            continue;
++        }
++
++        ret = k5_hex_decode(tests[i].hex, &bytes, &len);
++        assert(ret == 0);
++        assert(len == tests[i].binary_len);
++        assert(memcmp(bytes, tests[i].binary, len) == 0);
++        assert(bytes[len] == 0);
++        free(bytes);
++
++        ret = k5_hex_encode((uint8_t *)tests[i].binary, tests[i].binary_len,
++                            tests[i].uppercase, &hex);
++        assert(ret == 0);
++        assert(strcmp(tests[i].hex, hex) == 0);
++        free(hex);
++    }
++    return 0;
++}
diff --git a/SOURCES/Add-vector-support-to-k5_sha256.patch b/SOURCES/Add-vector-support-to-k5_sha256.patch
new file mode 100644
index 0000000..f9a3233
--- /dev/null
+++ b/SOURCES/Add-vector-support-to-k5_sha256.patch
@@ -0,0 +1,106 @@
+From f8b14b92cc4c82578f8fc56dd1fddebe88120769 Mon Sep 17 00:00:00 2001
+From: Greg Hudson <ghudson@mit.edu>
+Date: Sat, 3 Feb 2018 20:53:42 -0500
+Subject: [PATCH] Add vector support to k5_sha256()
+
+Add a length argument so that multiple krb5_data values can be passed
+to k5_sha256(), for efficient computation of SHA-256 hashes over
+concatenations of data values.
+
+(cherry picked from commit 4f3373e8c55b3e9bdfb5b065e07214c5816c85fa)
+---
+ src/include/k5-int.h                 | 4 ++--
+ src/lib/crypto/builtin/sha2/sha256.c | 6 ++++--
+ src/lib/crypto/crypto_tests/t_sha2.c | 2 +-
+ src/lib/crypto/openssl/sha256.c      | 6 ++++--
+ src/lib/krb5/rcache/rc_conv.c        | 2 +-
+ 5 files changed, 12 insertions(+), 8 deletions(-)
+
+diff --git a/src/include/k5-int.h b/src/include/k5-int.h
+index 9378ae047..1c1d9783b 100644
+--- a/src/include/k5-int.h
++++ b/src/include/k5-int.h
+@@ -635,9 +635,9 @@ krb5int_arcfour_gsscrypt(const krb5_keyblock *keyblock, krb5_keyusage usage,
+ 
+ #define K5_SHA256_HASHLEN (256 / 8)
+ 
+-/* Write the SHA-256 hash of in to out. */
++/* Write the SHA-256 hash of in (containing n elements) to out. */
+ krb5_error_code
+-k5_sha256(const krb5_data *in, uint8_t out[K5_SHA256_HASHLEN]);
++k5_sha256(const krb5_data *in, size_t n, uint8_t out[K5_SHA256_HASHLEN]);
+ 
+ /*
+  * Attempt to zero memory in a way that compilers won't optimize out.
+diff --git a/src/lib/crypto/builtin/sha2/sha256.c b/src/lib/crypto/builtin/sha2/sha256.c
+index 2b5cbe480..9a940b3f8 100644
+--- a/src/lib/crypto/builtin/sha2/sha256.c
++++ b/src/lib/crypto/builtin/sha2/sha256.c
+@@ -257,12 +257,14 @@ k5_sha256_final(void *res, SHA256_CTX *m)
+ }
+ 
+ krb5_error_code
+-k5_sha256(const krb5_data *in, uint8_t out[K5_SHA256_HASHLEN])
++k5_sha256(const krb5_data *in, size_t n, uint8_t out[K5_SHA256_HASHLEN])
+ {
+     SHA256_CTX ctx;
++    size_t i;
+ 
+     k5_sha256_init(&ctx);
+-    k5_sha256_update(&ctx, in->data, in->length);
++    for (i = 0; i < n; i++)
++        k5_sha256_update(&ctx, in[i].data, in[i].length);
+     k5_sha256_final(out, &ctx);
+     return 0;
+ }
+diff --git a/src/lib/crypto/crypto_tests/t_sha2.c b/src/lib/crypto/crypto_tests/t_sha2.c
+index 12f32869b..e6fa58498 100644
+--- a/src/lib/crypto/crypto_tests/t_sha2.c
++++ b/src/lib/crypto/crypto_tests/t_sha2.c
+@@ -125,7 +125,7 @@ hash_test(const struct krb5_hash_provider *hash, struct test *tests)
+ 
+ 	    if (hash == &krb5int_hash_sha256) {
+ 		/* Try again using k5_sha256(). */
+-		if (k5_sha256(&iov.data, (uint8_t *)hval.data) != 0)
++		if (k5_sha256(&iov.data, 1, (uint8_t *)hval.data) != 0)
+ 		    abort();
+ 		if (memcmp(hval.data, t->hash, hval.length) != 0)
+ 		    abort();
+diff --git a/src/lib/crypto/openssl/sha256.c b/src/lib/crypto/openssl/sha256.c
+index fa095d472..0edd8b7ba 100644
+--- a/src/lib/crypto/openssl/sha256.c
++++ b/src/lib/crypto/openssl/sha256.c
+@@ -34,16 +34,18 @@
+ #include <openssl/evp.h>
+ 
+ krb5_error_code
+-k5_sha256(const krb5_data *in, uint8_t out[K5_SHA256_HASHLEN])
++k5_sha256(const krb5_data *in, size_t n, uint8_t out[K5_SHA256_HASHLEN])
+ {
+     EVP_MD_CTX *ctx;
++    size_t i;
+     int ok;
+ 
+     ctx = EVP_MD_CTX_new();
+     if (ctx == NULL)
+         return ENOMEM;
+     ok = EVP_DigestInit_ex(ctx, EVP_sha256(), NULL);
+-    ok = ok && EVP_DigestUpdate(ctx, in->data, in->length);
++    for (i = 0; i < n; i++)
++        ok = ok && EVP_DigestUpdate(ctx, in[i].data, in[i].length);
+     ok = ok && EVP_DigestFinal_ex(ctx, out, NULL);
+     EVP_MD_CTX_free(ctx);
+     return ok ? 0 : ENOMEM;
+diff --git a/src/lib/krb5/rcache/rc_conv.c b/src/lib/krb5/rcache/rc_conv.c
+index 0e021f5d8..f2fe528ac 100644
+--- a/src/lib/krb5/rcache/rc_conv.c
++++ b/src/lib/krb5/rcache/rc_conv.c
+@@ -58,7 +58,7 @@ krb5_rc_hash_message(krb5_context context, const krb5_data *message,
+     *out = NULL;
+ 
+     /* Calculate the binary checksum. */
+-    retval = k5_sha256(message, cksum);
++    retval = k5_sha256(message, 1, cksum);
+     if (retval)
+         return retval;
+ 
diff --git a/SOURCES/Be-more-careful-asking-for-AS-key-in-SPAKE-client.patch b/SOURCES/Be-more-careful-asking-for-AS-key-in-SPAKE-client.patch
new file mode 100644
index 0000000..692f4ad
--- /dev/null
+++ b/SOURCES/Be-more-careful-asking-for-AS-key-in-SPAKE-client.patch
@@ -0,0 +1,229 @@
+From 2b9e79d58b28196dba5f7d3ff2f32ca577444ddc Mon Sep 17 00:00:00 2001
+From: Greg Hudson <ghudson@mit.edu>
+Date: Sat, 31 Mar 2018 10:43:49 -0400
+Subject: [PATCH] Be more careful asking for AS key in SPAKE client
+
+Asking for the AS key too early can result in password prompts in
+situations where SPAKE won't proceed, such as when the KDC offers only
+second factor types not supported by the client.
+
+In spake_prep_questions(), decode the received message and make sure
+it's a challenge with a supported group and second factor type
+(SF-NONE at the moment).  Save the decoded message and use it in
+spake_process().  Do not retrieve the AS key at the beginning of
+spake_process(); instead do so in process_challenge() after checking
+the challenge group and factor types.
+
+Move contains_sf_none() earlier in the file so that it can be used by
+spake_prep_questions() without a prototype.
+
+ticket: 8659
+(cherry picked from commit f240f1b0d324312be8aa59ead7cfbe0c329ed064)
+---
+ src/plugins/preauth/spake/spake_client.c | 111 ++++++++++++++---------
+ 1 file changed, 66 insertions(+), 45 deletions(-)
+
+diff --git a/src/plugins/preauth/spake/spake_client.c b/src/plugins/preauth/spake/spake_client.c
+index d72bd64aa..47a6ba26c 100644
+--- a/src/plugins/preauth/spake/spake_client.c
++++ b/src/plugins/preauth/spake/spake_client.c
+@@ -39,12 +39,26 @@
+ #include <krb5/clpreauth_plugin.h>
+ 
+ typedef struct reqstate_st {
++    krb5_pa_spake *msg;         /* set in prep_questions, used in process */
+     krb5_keyblock *initial_key;
+     krb5_data *support;
+     krb5_data thash;
+     krb5_data spakeresult;
+ } reqstate;
+ 
++/* Return true if SF-NONE is present in factors. */
++static krb5_boolean
++contains_sf_none(krb5_spake_factor **factors)
++{
++    int i;
++
++    for (i = 0; factors != NULL && factors[i] != NULL; i++) {
++        if (factors[i]->type == SPAKE_SF_NONE)
++            return TRUE;
++    }
++    return FALSE;
++}
++
+ static krb5_error_code
+ spake_init(krb5_context context, krb5_clpreauth_moddata *moddata_out)
+ {
+@@ -77,6 +91,7 @@ spake_request_fini(krb5_context context, krb5_clpreauth_moddata moddata,
+ {
+     reqstate *st = (reqstate *)modreq;
+ 
++    k5_free_pa_spake(context, st->msg);
+     krb5_free_keyblock(context, st->initial_key);
+     krb5_free_data(context, st->support);
+     krb5_free_data_contents(context, &st->thash);
+@@ -92,16 +107,42 @@ spake_prep_questions(krb5_context context, krb5_clpreauth_moddata moddata,
+                      krb5_data *enc_req, krb5_data *enc_prev_req,
+                      krb5_pa_data *pa_data)
+ {
++    krb5_error_code ret;
++    groupstate *gstate = (groupstate *)moddata;
+     reqstate *st = (reqstate *)modreq;
++    krb5_data in_data;
++    krb5_spake_challenge *ch;
+ 
+     if (st == NULL)
+         return ENOMEM;
+-    if (st->initial_key == NULL && pa_data->length > 0)
++
++    /* We don't need to ask any questions to send a support message. */
++    if (pa_data->length == 0)
++        return 0;
++
++    /* Decode the incoming message, replacing any previous one in the request
++     * state.  If we can't decode it, we have no questions to ask. */
++    k5_free_pa_spake(context, st->msg);
++    st->msg = NULL;
++    in_data = make_data(pa_data->contents, pa_data->length);
++    ret = decode_krb5_pa_spake(&in_data, &st->msg);
++    if (ret)
++        return (ret == ENOMEM) ? ENOMEM : 0;
++
++    if (st->msg->choice == SPAKE_MSGTYPE_CHALLENGE) {
++        ch = &st->msg->u.challenge;
++        if (!group_is_permitted(gstate, ch->group))
++            return 0;
++        /* When second factor support is implemented, we should ask questions
++         * based on the factors in the challenge. */
++        if (!contains_sf_none(ch->factors))
++            return 0;
++        /* We will need the AS key to respond to the challenge. */
+         cb->need_as_key(context, rock);
+-
+-    /* When second-factor is implemented, we should ask questions based on the
+-     * factors in the challenge. */
+-
++    } else if (st->msg->choice == SPAKE_MSGTYPE_ENCDATA) {
++        /* When second factor support is implemented, we should decrypt the
++         * encdata message and ask questions based on the factor data. */
++    }
+     return 0;
+ }
+ 
+@@ -136,19 +177,6 @@ send_support(krb5_context context, groupstate *gstate, reqstate *st,
+     return convert_to_padata(support, pa_out);
+ }
+ 
+-/* Return true if SF-NONE is present in factors. */
+-static krb5_boolean
+-contains_sf_none(krb5_spake_factor **factors)
+-{
+-    int i;
+-
+-    for (i = 0; factors != NULL && factors[i] != NULL; i++) {
+-        if (factors[i]->type == SPAKE_SF_NONE)
+-            return TRUE;
+-    }
+-    return FALSE;
+-}
+-
+ static krb5_error_code
+ process_challenge(krb5_context context, groupstate *gstate, reqstate *st,
+                   krb5_spake_challenge *ch, const krb5_data *der_msg,
+@@ -157,7 +185,7 @@ process_challenge(krb5_context context, groupstate *gstate, reqstate *st,
+                   const krb5_data *der_req, krb5_pa_data ***pa_out)
+ {
+     krb5_error_code ret;
+-    krb5_keyblock *k0 = NULL, *k1 = NULL;
++    krb5_keyblock *k0 = NULL, *k1 = NULL, *as_key;
+     krb5_spake_factor factor;
+     krb5_pa_spake msg;
+     krb5_data *der_factor = NULL, *response;
+@@ -167,8 +195,8 @@ process_challenge(krb5_context context, groupstate *gstate, reqstate *st,
+ 
+     enc_factor.ciphertext = empty_data();
+ 
+-    /* Not expected if we already computed the SPAKE result. */
+-    if (st->spakeresult.length != 0)
++    /* Not expected if we processed a challenge and didn't reject it. */
++    if (st->initial_key != NULL)
+         return KRB5KDC_ERR_PREAUTH_FAILED;
+ 
+     if (!group_is_permitted(gstate, ch->group)) {
+@@ -193,6 +221,12 @@ process_challenge(krb5_context context, groupstate *gstate, reqstate *st,
+     if (!contains_sf_none(ch->factors))
+         return KRB5KDC_ERR_PREAUTH_FAILED;
+ 
++    ret = cb->get_as_key(context, rock, &as_key);
++    if (ret)
++        goto cleanup;
++    ret = krb5_copy_keyblock(context, as_key, &st->initial_key);
++    if (ret)
++        goto cleanup;
+     ret = derive_wbytes(context, ch->group, st->initial_key, &wbytes);
+     if (ret)
+         goto cleanup;
+@@ -267,7 +301,7 @@ process_encdata(krb5_context context, reqstate *st, krb5_enc_data *enc,
+                 krb5_pa_data ***pa_out)
+ {
+     /* Not expected if we haven't sent a response yet. */
+-    if (st->spakeresult.length == 0)
++    if (st->initial_key == NULL || st->spakeresult.length == 0)
+         return KRB5KDC_ERR_PREAUTH_FAILED;
+ 
+     /*
+@@ -292,9 +326,7 @@ spake_process(krb5_context context, krb5_clpreauth_moddata moddata,
+     krb5_error_code ret;
+     groupstate *gstate = (groupstate *)moddata;
+     reqstate *st = (reqstate *)modreq;
+-    krb5_pa_spake *msg;
+     krb5_data in_data;
+-    krb5_keyblock *as_key;
+ 
+     if (st == NULL)
+         return ENOMEM;
+@@ -306,34 +338,23 @@ spake_process(krb5_context context, krb5_clpreauth_moddata moddata,
+         return send_support(context, gstate, st, pa_out);
+     }
+ 
+-    /* We need the initial reply key to process any non-trivial message. */
+-    if (st->initial_key == NULL) {
+-        ret = cb->get_as_key(context, rock, &as_key);
+-        if (ret)
+-            return ret;
+-        ret = krb5_copy_keyblock(context, as_key, &st->initial_key);
+-        if (ret)
+-            return ret;
+-    }
+-
+-    in_data = make_data(pa_in->contents, pa_in->length);
+-    ret = decode_krb5_pa_spake(&in_data, &msg);
+-    if (ret)
+-        return ret;
+-
+-    if (msg->choice == SPAKE_MSGTYPE_CHALLENGE) {
+-        ret = process_challenge(context, gstate, st, &msg->u.challenge,
++    if (st->msg == NULL) {
++        /* The message failed to decode in spake_prep_questions(). */
++        ret = KRB5KDC_ERR_PREAUTH_FAILED;
++    } else if (st->msg->choice == SPAKE_MSGTYPE_CHALLENGE) {
++        in_data = make_data(pa_in->contents, pa_in->length);
++        ret = process_challenge(context, gstate, st, &st->msg->u.challenge,
+                                 &in_data, cb, rock, prompter, prompter_data,
+                                 der_req, pa_out);
+-    } else if (msg->choice == SPAKE_MSGTYPE_ENCDATA) {
+-        ret = process_encdata(context, st, &msg->u.encdata, cb, rock, prompter,
+-                              prompter_data, der_prev_req, der_req, pa_out);
++    } else if (st->msg->choice == SPAKE_MSGTYPE_ENCDATA) {
++        ret = process_encdata(context, st, &st->msg->u.encdata, cb, rock,
++                              prompter, prompter_data, der_prev_req, der_req,
++                              pa_out);
+     } else {
+         /* Unexpected message type */
+         ret = KRB5KDC_ERR_PREAUTH_FAILED;
+     }
+ 
+-    k5_free_pa_spake(context, msg);
+     return ret;
+ }
+ 
diff --git a/SOURCES/Become-FIPS-aware.patch b/SOURCES/Become-FIPS-aware.patch
new file mode 100644
index 0000000..e87f8a3
--- /dev/null
+++ b/SOURCES/Become-FIPS-aware.patch
@@ -0,0 +1,156 @@
+From ce06474e3b12430480374f923c25bae9581fb146 Mon Sep 17 00:00:00 2001
+From: Robbie Harwood <rharwood@redhat.com>
+Date: Fri, 9 Nov 2018 15:12:21 -0500
+Subject: [PATCH] Become FIPS-aware
+
+A lot of the FIPS error conditions from OpenSSL are incredibly
+mysterious (at best, things return NULL unexpectedly; at worst,
+internal assertions are tripped; most of the time, you just get
+ENOMEM).  In order to cope with this, we need to have some level of
+awareness of what we can and can't safely call.
+
+This will slow down some calls slightly (FIPS_mode() takes multiple
+locks), but not for any crypto we care about - AES is fine, for
+instance.
+---
+ src/lib/crypto/openssl/enc_provider/camellia.c  |  6 ++++++
+ src/lib/crypto/openssl/enc_provider/des.c       |  9 +++++++++
+ src/lib/crypto/openssl/enc_provider/rc4.c       | 13 ++++++++++++-
+ src/lib/crypto/openssl/hash_provider/hash_evp.c |  4 ++++
+ src/lib/crypto/openssl/hmac.c                   |  6 +++++-
+ 5 files changed, 36 insertions(+), 2 deletions(-)
+
+diff --git a/src/lib/crypto/openssl/enc_provider/camellia.c b/src/lib/crypto/openssl/enc_provider/camellia.c
+index 2da691329..f79679a0b 100644
+--- a/src/lib/crypto/openssl/enc_provider/camellia.c
++++ b/src/lib/crypto/openssl/enc_provider/camellia.c
+@@ -304,6 +304,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 (FIPS_mode())
++        return KRB5_CRYPTO_INTERNAL;
++
+     if (output->length < CAMELLIA_BLOCK_SIZE)
+         return KRB5_BAD_MSIZE;
+ 
+@@ -331,6 +334,9 @@ static krb5_error_code
+ krb5int_camellia_init_state (const krb5_keyblock *key, krb5_keyusage usage,
+                              krb5_data *state)
+ {
++    if (FIPS_mode())
++        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/des.c b/src/lib/crypto/openssl/enc_provider/des.c
+index a662db512..7d17d287e 100644
+--- a/src/lib/crypto/openssl/enc_provider/des.c
++++ b/src/lib/crypto/openssl/enc_provider/des.c
+@@ -85,6 +85,9 @@ k5_des_encrypt(krb5_key key, const krb5_data *ivec, krb5_crypto_iov *data,
+     EVP_CIPHER_CTX *ctx;
+     krb5_boolean empty;
+ 
++    if (FIPS_mode())
++        return KRB5_CRYPTO_INTERNAL;
++
+     ret = validate(key, ivec, data, num_data, &empty);
+     if (ret != 0 || empty)
+         return ret;
+@@ -133,6 +136,9 @@ k5_des_decrypt(krb5_key key, const krb5_data *ivec, krb5_crypto_iov *data,
+     EVP_CIPHER_CTX *ctx;
+     krb5_boolean empty;
+ 
++    if (FIPS_mode())
++        return KRB5_CRYPTO_INTERNAL;
++
+     ret = validate(key, ivec, data, num_data, &empty);
+     if (ret != 0 || empty)
+         return ret;
+@@ -182,6 +188,9 @@ k5_des_cbc_mac(krb5_key key, const krb5_crypto_iov *data, size_t num_data,
+     DES_key_schedule sched;
+     krb5_boolean empty;
+ 
++    if (FIPS_mode())
++        return KRB5_CRYPTO_INTERNAL;
++
+     ret = validate(key, ivec, data, num_data, &empty);
+     if (ret != 0)
+         return ret;
+diff --git a/src/lib/crypto/openssl/enc_provider/rc4.c b/src/lib/crypto/openssl/enc_provider/rc4.c
+index 7f3c086ed..a3f2a7442 100644
+--- a/src/lib/crypto/openssl/enc_provider/rc4.c
++++ b/src/lib/crypto/openssl/enc_provider/rc4.c
+@@ -66,6 +66,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 (FIPS_mode())
++        return KRB5_CRYPTO_INTERNAL;
++
+     arcstate = (state != NULL) ? (struct arcfour_state *) state->data : NULL;
+     if (arcstate != NULL) {
+         ctx = arcstate->ctx;
+@@ -113,7 +116,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 = (struct arcfour_state *) state->data;
++    struct arcfour_state *arcstate;
++
++    if (FIPS_mode())
++        return;
++
++    arcstate = (struct arcfour_state *) state->data;
+ 
+     EVP_CIPHER_CTX_free(arcstate->ctx);
+     free(arcstate);
+@@ -125,6 +133,9 @@ k5_arcfour_init_state(const krb5_keyblock *key,
+ {
+     struct arcfour_state *arcstate;
+ 
++    if (FIPS_mode())
++        return KRB5_CRYPTO_INTERNAL;
++
+     /* Create a state structure with an uninitialized context. */
+     arcstate = calloc(1, sizeof(*arcstate));
+     if (arcstate == NULL)
+diff --git a/src/lib/crypto/openssl/hash_provider/hash_evp.c b/src/lib/crypto/openssl/hash_provider/hash_evp.c
+index 957ed8d9c..8c1fd7f59 100644
+--- a/src/lib/crypto/openssl/hash_provider/hash_evp.c
++++ b/src/lib/crypto/openssl/hash_provider/hash_evp.c
+@@ -64,12 +64,16 @@ 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)
+ {
++    if (FIPS_mode())
++        return KRB5_CRYPTO_INTERNAL;
+     return hash_evp(EVP_md4(), data, num_data, output);
+ }
+ 
+ static krb5_error_code
+ hash_md5(const krb5_crypto_iov *data, size_t num_data, krb5_data *output)
+ {
++    if (FIPS_mode())
++        return KRB5_CRYPTO_INTERNAL;
+     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 b2db6ec02..d94d9ac94 100644
+--- a/src/lib/crypto/openssl/hmac.c
++++ b/src/lib/crypto/openssl/hmac.c
+@@ -103,7 +103,11 @@ map_digest(const struct krb5_hash_provider *hash)
+         return EVP_sha256();
+     else if (!strncmp(hash->hash_name, "SHA-384",7))
+         return EVP_sha384();
+-    else if (!strncmp(hash->hash_name, "MD5", 3))
++
++    if (FIPS_mode())
++        return NULL;
++
++    if (!strncmp(hash->hash_name, "MD5", 3))
+         return EVP_md5();
+     else if (!strncmp(hash->hash_name, "MD4", 3))
+         return EVP_md4();
diff --git a/SOURCES/Convert-Python-tests-to-Python-3.patch b/SOURCES/Convert-Python-tests-to-Python-3.patch
new file mode 100644
index 0000000..5f5dc23
--- /dev/null
+++ b/SOURCES/Convert-Python-tests-to-Python-3.patch
@@ -0,0 +1,536 @@
+From 2bc365f12282cdd83a191478b97f4ea0d9aa60dd Mon Sep 17 00:00:00 2001
+From: Greg Hudson <ghudson@mit.edu>
+Date: Mon, 19 Feb 2018 21:10:09 -0500
+Subject: [PATCH] Convert Python tests to Python 3
+
+Look for python3 in configure.in and verify that we got it.  Convert
+test code to conform to Python 3.
+
+ticket: 8710 (new)
+(cherry picked from commit e23d24beacb73581bbf4351250f3955e6fd44361)
+[rharwood@redhat.com: Context skew due to not having LMDB in tests]
+---
+ src/Makefile.in                  |  1 +
+ src/configure.in                 |  6 ++--
+ src/kadmin/dbutil/t_tdumputil.py |  4 +--
+ src/tests/jsonwalker.py          | 16 +++++------
+ src/tests/t_cve-2012-1014.py     |  2 +-
+ src/tests/t_cve-2012-1015.py     |  2 +-
+ src/tests/t_hostrealm.py         |  4 ++-
+ src/tests/t_kdb.py               | 11 ++++---
+ src/tests/t_keytab.py            | 34 +++++++++++-----------
+ src/tests/t_mkey.py              |  6 ++--
+ src/tests/t_otp.py               |  7 +++--
+ src/tests/t_tabdump.py           |  4 +--
+ src/util/Makefile.in             |  1 +
+ src/util/k5test.py               | 49 +++++++++++++++++---------------
+ src/util/princflags.py           | 25 ++++++++--------
+ 15 files changed, 88 insertions(+), 84 deletions(-)
+
+diff --git a/src/Makefile.in b/src/Makefile.in
+index 77beff8bc..79b8d5f98 100644
+--- a/src/Makefile.in
++++ b/src/Makefile.in
+@@ -533,6 +533,7 @@ runenv.py: pyrunenv.vals
+ 
+ clean-unix::
+ 	$(RM) runenv.py runenv.pyc pyrunenv.vals
++	$(RM) -r __pycache__
+ 
+ COV_BUILD=	cov-build
+ COV_ANALYZE=	cov-analyze
+diff --git a/src/configure.in b/src/configure.in
+index 3f45784b5..00cb297b8 100644
+--- a/src/configure.in
++++ b/src/configure.in
+@@ -1098,15 +1098,13 @@ fi
+ AC_SUBST(HAVE_RUNTEST)
+ 
+ # For Python tests.
+-AC_CHECK_PROG(PYTHON,python2,python2)
++AC_CHECK_PROG(PYTHON,python3,python3)
+ if text x"$PYTHON" = x; then
+ 	AC_CHECK_PROG(PYTHON,python,python)
+ fi
+ HAVE_PYTHON=no
+ if test x"$PYTHON" != x; then
+-	# k5test.py requires python 2.4 (for the subprocess module).
+-	# Some code needs python 2.5 (for syntax like conditional expressions).
+-	wantver="(sys.hexversion >= 0x2050000 and sys.hexversion < 0x3000000)"
++	wantver="(sys.hexversion >= 0x3000000)"
+ 	if "$PYTHON" -c "import sys; sys.exit(not $wantver and 1 or 0)"; then
+ 		HAVE_PYTHON=yes
+ 	fi
+diff --git a/src/kadmin/dbutil/t_tdumputil.py b/src/kadmin/dbutil/t_tdumputil.py
+index 52e356533..47b2aa7a3 100755
+--- a/src/kadmin/dbutil/t_tdumputil.py
++++ b/src/kadmin/dbutil/t_tdumputil.py
+@@ -6,8 +6,8 @@ realm = K5Realm(create_kdb=False)
+ def compare(s, expected, msg):
+     if s == expected:
+         return
+-    print 'expected:', repr(expected)
+-    print 'got:', repr(s)
++    print('expected:', repr(expected))
++    print('got:', repr(s))
+     fail(msg)
+ 
+ out = realm.run(['./t_tdumputil', '2', 'field1', 'field2',
+diff --git a/src/tests/jsonwalker.py b/src/tests/jsonwalker.py
+index 942ca2db7..7a0675e08 100644
+--- a/src/tests/jsonwalker.py
++++ b/src/tests/jsonwalker.py
+@@ -2,8 +2,8 @@ import sys
+ try:
+     import cjson
+ except ImportError:
+-    print "Warning: skipping audit log verification because the cjson module" \
+-          " is unavailable"
++    print("Warning: skipping audit log verification because the cjson module" \
++          " is unavailable")
+     sys.exit(0)
+ from collections import defaultdict
+ from optparse import OptionParser
+@@ -22,10 +22,10 @@ class Parser(object):
+         result = self.parse(logs)
+         if len(result) != len(self.defaults):
+             diff = set(self.defaults.keys()).difference(result.keys())
+-            print 'Test failed.'
+-            print 'The following attributes were not set:'
++            print('Test failed.')
++            print('The following attributes were not set:')
+             for it in diff:
+-                print it
++                print(it)
+             sys.exit(1)
+ 
+     def flatten(self, defaults):
+@@ -42,7 +42,7 @@ class Parser(object):
+         result = dict()
+         for path,value in self._walk(defaults):
+             if path in result:
+-                print 'Warning: attribute path %s already exists' % path
++                print('Warning: attribute path %s already exists' % path)
+             result[path] = value
+ 
+         return result
+@@ -60,7 +60,7 @@ class Parser(object):
+                         if v is not None:
+                             dv = self.DEFAULTS[type(v)]
+                         else:
+-                            print 'Warning: attribute %s is set to None' % a
++                            print('Warning: attribute %s is set to None' % a)
+                             continue
+                     # by now we have default value
+                     if v != dv:
+@@ -96,7 +96,7 @@ if __name__ == '__main__':
+                 content.append(cjson.decode(l.rstrip()))
+         f.close()
+     else:
+-        print 'Input file in jason format is required'
++        print('Input file in jason format is required')
+         exit()
+ 
+     defaults = None
+diff --git a/src/tests/t_cve-2012-1014.py b/src/tests/t_cve-2012-1014.py
+index dcff95f6e..8447e0ee7 100755
+--- a/src/tests/t_cve-2012-1014.py
++++ b/src/tests/t_cve-2012-1014.py
+@@ -20,7 +20,7 @@ x2 = base64.b16decode('A44F304DA007030500FEDCBA90A10E30' +
+                       '01')
+ 
+ for x in range(11, 128):
+-    s.sendto(''.join([x1, chr(x), x2]), a)
++    s.sendto(x1 + bytes([x]) + x2, a)
+ 
+ # Make sure kinit still works.
+ 
+diff --git a/src/tests/t_cve-2012-1015.py b/src/tests/t_cve-2012-1015.py
+index 28b1e619b..ae5678cac 100755
+--- a/src/tests/t_cve-2012-1015.py
++++ b/src/tests/t_cve-2012-1015.py
+@@ -27,7 +27,7 @@ x1 = base64.b16decode('6A81A030819DA103020105A20302010A' +
+ x2 = base64.b16decode('A8083006020106020112')
+ 
+ for x in range(0, 128):
+-    s.sendto(''.join([x1, chr(x), x2]), a)
++    s.sendto(x1 + bytes([x]) + x2, a)
+ 
+ # Make sure kinit still works.
+ 
+diff --git a/src/tests/t_hostrealm.py b/src/tests/t_hostrealm.py
+index 256ba2a38..beea6f3bc 100755
+--- a/src/tests/t_hostrealm.py
++++ b/src/tests/t_hostrealm.py
+@@ -119,7 +119,9 @@ testd(realm, 'KRBTEST.COM', 'default_realm profile', env=notest2)
+ # see the first.  Remove the profile default_realm setting to expose
+ # this behavior.
+ remove_default = {'libdefaults': {'default_realm': None}}
+-nodefault_conf = dict(disable_conf.items() + remove_default.items())
++# Python 3.5+: nodefault_conf = {**disable_conf, **remove_default}
++nodefault_conf = dict(list(disable_conf.items()) +
++                      list(remove_default.items()))
+ nodefault = realm.special_env('nodefault', False, krb5_conf=nodefault_conf)
+ testd(realm, 'one', 'default_realm test1', env=nodefault)
+ 
+diff --git a/src/tests/t_kdb.py b/src/tests/t_kdb.py
+index 983cd93c8..42237f7a1 100755
+--- a/src/tests/t_kdb.py
++++ b/src/tests/t_kdb.py
+@@ -1,6 +1,5 @@
+ from k5test import *
+ import time
+-from itertools import imap
+ 
+ # Run kdbtest against the BDB module.
+ realm = K5Realm(create_kdb=False)
+@@ -51,7 +50,7 @@ else:
+ def slap_add(ldif):
+     proc = subprocess.Popen([slapadd, '-b', 'cn=config', '-F', slapd_conf],
+                             stdin=subprocess.PIPE, stdout=subprocess.PIPE,
+-                            stderr=subprocess.STDOUT)
++                            stderr=subprocess.STDOUT, universal_newlines=True)
+     (out, dummy) = proc.communicate(ldif)
+     output(out)
+     return proc.wait()
+@@ -98,7 +97,7 @@ if slap_add('include: file://%s\n' % schema) != 0:
+ ldap_homes = ['/etc/ldap', '/etc/openldap', '/usr/local/etc/openldap',
+               '/usr/local/etc/ldap']
+ local_schema_path = '/schema/core.ldif'
+-core_schema = next((i for i in imap(lambda x:x+local_schema_path, ldap_homes)
++core_schema = next((i for i in map(lambda x:x+local_schema_path, ldap_homes)
+                     if os.path.isfile(i)), None)
+ if core_schema:
+     if slap_add('include: file://%s\n' % core_schema) != 0:
+@@ -114,7 +113,7 @@ atexit.register(kill_slapd)
+ 
+ out = open(slapd_out, 'w')
+ subprocess.call([slapd, '-h', ldap_uri, '-F', slapd_conf], stdout=out,
+-                stderr=out)
++                stderr=out, universal_newlines=True)
+ out.close()
+ pidf = open(slapd_pidfile, 'r')
+ slapd_pid = int(pidf.read())
+@@ -158,7 +157,7 @@ def ldap_search(args):
+     proc = subprocess.Popen([ldapsearch, '-H', ldap_uri, '-b', top_dn,
+                              '-D', admin_dn, '-w', admin_pw, args],
+                             stdin=subprocess.PIPE, stdout=subprocess.PIPE,
+-                            stderr=subprocess.STDOUT)
++                            stderr=subprocess.STDOUT, universal_newlines=True)
+     (out, dummy) = proc.communicate()
+     return out
+ 
+@@ -166,7 +165,7 @@ def ldap_modify(ldif, args=[]):
+     proc = subprocess.Popen([ldapmodify, '-H', ldap_uri, '-D', admin_dn,
+                              '-x', '-w', admin_pw] + args,
+                             stdin=subprocess.PIPE, stdout=subprocess.PIPE,
+-                            stderr=subprocess.STDOUT)
++                            stderr=subprocess.STDOUT, universal_newlines=True)
+     (out, dummy) = proc.communicate(ldif)
+     output(out)
+ 
+diff --git a/src/tests/t_keytab.py b/src/tests/t_keytab.py
+index 228c36334..8a17ae2eb 100755
+--- a/src/tests/t_keytab.py
++++ b/src/tests/t_keytab.py
+@@ -90,36 +90,36 @@ test_key_rotate(realm, princ, 2)
+ 
+ # Test that klist -k can read a keytab entry without a 32-bit kvno and
+ # reports the 8-bit key version.
+-record = '\x00\x01'             # principal component count
+-record += '\x00\x0bKRBTEST.COM' # realm
+-record += '\x00\x04user'        # principal component
+-record += '\x00\x00\x00\x01'    # name type (NT-PRINCIPAL)
+-record += '\x54\xf7\x4d\x35'    # timestamp
+-record += '\x02'                # key version
+-record += '\x00\x12'            # enctype
+-record += '\x00\x20'            # key length
+-record += '\x00' * 32           # key bytes
+-f = open(realm.keytab, 'w')
+-f.write('\x05\x02\x00\x00\x00' + chr(len(record)))
++record = b'\x00\x01'             # principal component count
++record += b'\x00\x0bKRBTEST.COM' # realm
++record += b'\x00\x04user'        # principal component
++record += b'\x00\x00\x00\x01'    # name type (NT-PRINCIPAL)
++record += b'\x54\xf7\x4d\x35'    # timestamp
++record += b'\x02'                # key version
++record += b'\x00\x12'            # enctype
++record += b'\x00\x20'            # key length
++record += b'\x00' * 32           # key bytes
++f = open(realm.keytab, 'wb')
++f.write(b'\x05\x02\x00\x00\x00' + bytes([len(record)]))
+ f.write(record)
+ f.close()
+ msg = '   2 %s' % realm.user_princ
+ out = realm.run([klist, '-k'], expected_msg=msg)
+ 
+ # Make sure zero-fill isn't treated as a 32-bit kvno.
+-f = open(realm.keytab, 'w')
+-f.write('\x05\x02\x00\x00\x00' + chr(len(record) + 4))
++f = open(realm.keytab, 'wb')
++f.write(b'\x05\x02\x00\x00\x00' + bytes([len(record) + 4]))
+ f.write(record)
+-f.write('\x00\x00\x00\x00')
++f.write(b'\x00\x00\x00\x00')
+ f.close()
+ msg = '   2 %s' % realm.user_princ
+ out = realm.run([klist, '-k'], expected_msg=msg)
+ 
+ # Make sure a hand-crafted 32-bit kvno is recognized.
+-f = open(realm.keytab, 'w')
+-f.write('\x05\x02\x00\x00\x00' + chr(len(record) + 4))
++f = open(realm.keytab, 'wb')
++f.write(b'\x05\x02\x00\x00\x00' + bytes([len(record) + 4]))
+ f.write(record)
+-f.write('\x00\x00\x00\x03')
++f.write(b'\x00\x00\x00\x03')
+ f.close()
+ msg = '   3 %s' % realm.user_princ
+ out = realm.run([klist, '-k'], expected_msg=msg)
+diff --git a/src/tests/t_mkey.py b/src/tests/t_mkey.py
+index 48a533059..cbc830235 100755
+--- a/src/tests/t_mkey.py
++++ b/src/tests/t_mkey.py
+@@ -296,10 +296,10 @@ realm.stop()
+ # 2. list_mkeys displays the same list as for a post-1.7 KDB.
+ dumpfile = os.path.join(srctop, 'tests', 'dumpfiles', 'dump.16')
+ os.remove(stash_file)
+-f = open(stash_file, 'w')
++f = open(stash_file, 'wb')
+ f.write(struct.pack('=HL24s', 16, 24,
+-                    '\xF8\x3E\xFB\xBA\x6D\x80\xD9\x54\xE5\x5D\xF2\xE0'
+-                    '\x94\xAD\x6D\x86\xB5\x16\x37\xEC\x7C\x8A\xBC\x86'))
++                    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())
+diff --git a/src/tests/t_otp.py b/src/tests/t_otp.py
+index 0fd35d576..617a8ecf5 100755
+--- a/src/tests/t_otp.py
++++ b/src/tests/t_otp.py
+@@ -29,8 +29,8 @@
+ #
+ 
+ from k5test import *
+-from Queue import Empty
+-import StringIO
++from queue import Empty
++from io import StringIO
+ import struct
+ 
+ try:
+@@ -120,7 +120,8 @@ class UnixRadiusDaemon(RadiusDaemon):
+         sock.listen(1)
+         return (sock, addr)
+ 
+-    def recvRequest(self, (sock, addr)):
++    def recvRequest(self, sock_and_addr):
++        sock, addr = sock_and_addr
+         conn = sock.accept()[0]
+         sock.close()
+         os.remove(addr)
+diff --git a/src/tests/t_tabdump.py b/src/tests/t_tabdump.py
+index 2a86136dd..49531bf49 100755
+--- a/src/tests/t_tabdump.py
++++ b/src/tests/t_tabdump.py
+@@ -1,10 +1,10 @@
+ from k5test import *
+ 
+ import csv
+-import StringIO
++from io import StringIO
+ 
+ def tab_csv(s):
+-    io = StringIO.StringIO(s)
++    io = StringIO(s)
+     return list(csv.DictReader(io, dialect=csv.excel_tab))
+ 
+ 
+diff --git a/src/util/Makefile.in b/src/util/Makefile.in
+index 2611581c1..19a6bd312 100644
+--- a/src/util/Makefile.in
++++ b/src/util/Makefile.in
+@@ -26,3 +26,4 @@ install:
+ 
+ clean-unix::
+ 	$(RM) *.pyc
++	$(RM) -r __pycache__
+diff --git a/src/util/k5test.py b/src/util/k5test.py
+index bc32877a7..81fac3063 100644
+--- a/src/util/k5test.py
++++ b/src/util/k5test.py
+@@ -380,16 +380,16 @@ import imp
+ def fail(msg):
+     """Print a message and exit with failure."""
+     global _current_pass
+-    print "*** Failure:", msg
++    print("*** Failure:", msg)
+     if _last_mark:
+-        print "*** Last mark: %s" % _last_mark
++        print("*** Last mark: %s" % _last_mark)
+     if _last_cmd:
+-        print "*** Last command (#%d): %s" % (_cmd_index - 1, _last_cmd)
++        print("*** Last command (#%d): %s" % (_cmd_index - 1, _last_cmd))
+     if _last_cmd_output:
+-        print "*** Output of last command:"
++        print("*** Output of last command:")
+         sys.stdout.write(_last_cmd_output)
+     if _current_pass:
+-        print "*** Failed in test pass:", _current_pass
++        print("*** Failed in test pass:", _current_pass)
+     sys.exit(1)
+ 
+ 
+@@ -465,15 +465,16 @@ def _onexit():
+         if not verbose:
+             testlogfile = os.path.join(os.getcwd(), 'testlog')
+             utildir = os.path.join(srctop, 'util')
+-            print 'For details, see: %s' % testlogfile
+-            print 'Or re-run this test script with the -v flag:'
+-            print '    cd %s' % os.getcwd()
+-            print '    PYTHONPATH=%s %s %s -v' % \
+-                (utildir, sys.executable, sys.argv[0])
+-            print
+-        print 'Use --debug=NUM to run a command under a debugger.  Use'
+-        print '--stop-after=NUM to stop after a daemon is started in order to'
+-        print 'attach to it with a debugger.  Use --help to see other options.'
++            print('For details, see: %s' % testlogfile)
++            print('Or re-run this test script with the -v flag:')
++            print('    cd %s' % os.getcwd())
++            print('    PYTHONPATH=%s %s %s -v' %
++                  (utildir, sys.executable, sys.argv[0]))
++            print()
++        print('Use --debug=NUM to run a command under a debugger.  Use')
++        print('--stop-after=NUM to stop after a daemon is started in order to')
++        print('attach to it with a debugger.  Use --help to see other')
++        print('options.')
+ 
+ 
+ def _onsigint(signum, frame):
+@@ -523,8 +524,8 @@ def _get_hostname():
+     hostname = socket.gethostname()
+     try:
+         ai = socket.getaddrinfo(hostname, None, 0, 0, 0, socket.AI_CANONNAME)
+-    except socket.gaierror, (error, errstr):
+-        fail('Local hostname "%s" does not resolve: %s.' % (hostname, errstr))
++    except socket.gaierror as e:
++        fail('Local hostname "%s" does not resolve: %s.' % (hostname, e[1]))
+     (family, socktype, proto, canonname, sockaddr) = ai[0]
+     try:
+         name = socket.getnameinfo(sockaddr, socket.NI_NAMEREQD)
+@@ -594,7 +595,7 @@ def _match_cmdnum(cmdnum, ind):
+ def _build_env():
+     global buildtop, runenv
+     env = os.environ.copy()
+-    for (k, v) in runenv.env.iteritems():
++    for (k, v) in runenv.env.items():
+         if v.find('./') == 0:
+             env[k] = os.path.join(buildtop, v)
+         else:
+@@ -704,7 +705,8 @@ def _run_cmd(args, env, input=None, expected_code=0, expected_msg=None,
+ 
+     # Run the command and log the result, folding stderr into stdout.
+     proc = subprocess.Popen(args, stdin=infile, stdout=subprocess.PIPE,
+-                            stderr=subprocess.STDOUT, env=env)
++                            stderr=subprocess.STDOUT, env=env,
++                            universal_newlines=True)
+     (outdata, dummy_errdata) = proc.communicate(input)
+     _last_cmd_output = outdata
+     code = proc.returncode
+@@ -734,10 +736,10 @@ def _debug_cmd(args, env, input):
+            (_cmd_index, _shell_equiv(args)), True)
+     if input:
+         print
+-        print '*** Enter the following input when appropriate:'
+-        print 
+-        print input
+-        print
++        print('*** Enter the following input when appropriate:')
++        print()
++        print(input)
++        print()
+     code = subprocess.call(args, env=env)
+     output('*** [%d] Completed in debugger with return code %d\n' %
+            (_cmd_index, code))
+@@ -765,7 +767,8 @@ def _start_daemon(args, env, sentinel):
+ 
+     # Start the daemon and look for the sentinel in stdout or stderr.
+     proc = subprocess.Popen(args, stdin=null_input, stdout=subprocess.PIPE,
+-                            stderr=subprocess.STDOUT, env=env)
++                            stderr=subprocess.STDOUT, env=env,
++                            universal_newlines=True)
+     _last_cmd_output = ''
+     while True:
+         line = proc.stdout.readline()
+diff --git a/src/util/princflags.py b/src/util/princflags.py
+index f568dd2f1..f645e86e4 100644
+--- a/src/util/princflags.py
++++ b/src/util/princflags.py
+@@ -1,5 +1,4 @@
+ import re
+-import string
+ 
+ # Module for translating KDB principal flags between string and
+ # integer forms.
+@@ -81,7 +80,7 @@ _prefixlen = len(_prefix)
+ _flagnames = {}
+ 
+ # Translation table to map hyphens to underscores
+-_squash = string.maketrans('-', '_')
++_squash = str.maketrans('-', '_')
+ 
+ # Combined input-to-flag lookup table, to be filled in by
+ # _setup_tables()
+@@ -176,7 +175,7 @@ def flagnum2str(n):
+ # Return a list of flag names from a flag word.
+ def flags2namelist(flags):
+     a = []
+-    for n in xrange(32):
++    for n in range(32):
+         if flags & (1 << n):
+             a.append(flagnum2str(n))
+     return a
+@@ -225,21 +224,21 @@ def speclist2mask(s):
+ 
+ # Print C table of input flag specifiers for lib/kadm5/str_conv.c.
+ def _print_ftbl():
+-    print 'static const struct flag_table_row ftbl[] = {'
+-    a = sorted(pflags.items(), key=lambda (k, v): (v.flag, -v.invert, k))
++    print('static const struct flag_table_row ftbl[] = {')
++    a = sorted(pflags.items(), key=lambda k, v: (v.flag, -v.invert, k))
+     for k, v in a:
+         s1 = '    {"%s",' % k
+         s2 = '%-31s KRB5_KDB_%s,' % (s1, v.flagname())
+-        print '%-63s %d},' % (s2, 1 if v.invert else 0)
++        print('%-63s %d},' % (s2, 1 if v.invert else 0))
+ 
+-    print '};'
+-    print '#define NFTBL (sizeof(ftbl) / sizeof(ftbl[0]))'
++    print('};')
++    print('#define NFTBL (sizeof(ftbl) / sizeof(ftbl[0]))')
+ 
+ 
+ # Print C table of output flag names for lib/kadm5/str_conv.c.
+ def _print_outflags():
+-    print 'static const char *outflags[] = {'
+-    for i in xrange(32):
++    print('static const char *outflags[] = {')
++    for i in range(32):
+         flag = 1 << i
+         if flag > max(_flagnames.keys()):
+             break
+@@ -247,10 +246,10 @@ def _print_outflags():
+             s = '    "%s",' % _flagnames[flag]
+         except KeyError:
+             s = '    NULL,'
+-        print '%-32s/* 0x%08x */' % (s, flag)
++        print('%-32s/* 0x%08x */' % (s, flag))
+ 
+-    print '};'
+-    print '#define NOUTFLAGS (sizeof(outflags) / sizeof(outflags[0]))'
++    print('};')
++    print('#define NOUTFLAGS (sizeof(outflags) / sizeof(outflags[0]))')
+ 
+ 
+ # Print out C tables to insert into lib/kadm5/str_conv.c.
diff --git a/SOURCES/Eliminate-preprocessor-disabled-dead-code.patch b/SOURCES/Eliminate-preprocessor-disabled-dead-code.patch
new file mode 100644
index 0000000..9c55c67
--- /dev/null
+++ b/SOURCES/Eliminate-preprocessor-disabled-dead-code.patch
@@ -0,0 +1,2950 @@
+From 904a5789da342857a50de5874fe6aae1f96cbc5c Mon Sep 17 00:00:00 2001
+From: Robbie Harwood <rharwood@redhat.com>
+Date: Mon, 16 Jul 2018 15:35:15 -0400
+Subject: [PATCH] Eliminate preprocessor-disabled dead code
+
+It's been policy for a while now not to create "dead hunks" like
+these.  A great deal of this code simply doesn't work because it
+hasn't been kept up-to-date, and may never have worked.  Eliminate
+these dead hunks along with the complexity to support them.
+
+(cherry picked from commit 2bc951d3c88b460a16249115cbd51d69c3c57e22)
+[rharwood@redhat.com: context skew]
+---
+ src/ccapi/common/win/OldCC/ccutils.c          |  6 --
+ src/ccapi/common/win/OldCC/ccutils.h          |  3 -
+ src/ccapi/common/win/OldCC/opts.cxx           | 39 ----------
+ src/ccapi/common/win/OldCC/secure.hxx         |  6 --
+ src/ccapi/common/win/OldCC/util.h             |  3 -
+ src/ccapi/lib/win/OldCC/client.cxx            | 39 ----------
+ src/ccapi/lib/win/ccapi_os_ipc.cxx            | 15 ----
+ src/ccapi/lib/win/ccs_reply_proc.c            |  8 +-
+ src/ccapi/lib/win/dllmain.cxx                 | 12 +--
+ src/ccapi/server/win/ccs_os_server.cpp        | 23 +-----
+ src/ccapi/server/win/ccs_request_proc.c       | 12 +--
+ src/ccapi/server/win/ccs_win_pipe.c           |  4 +-
+ src/ccapi/test/pingtest.c                     |  6 --
+ src/clients/ksu/authorization.c               | 17 -----
+ src/config/win-post.in                        |  8 --
+ src/include/gssrpc/auth.h                     | 15 ----
+ src/include/gssrpc/rename.h                   | 26 +------
+ src/include/gssrpc/rpc.h                      | 25 -------
+ src/include/gssrpc/types.hin                  |  7 --
+ src/include/k5-platform.h                     | 28 +------
+ src/kadmin/dbutil/kdb5_util.c                 | 38 ----------
+ src/kadmin/server/ipropd_svc.c                | 29 -------
+ src/kdc/kdc_log.c                             |  8 --
+ src/kdc/kdc_preauth.c                         | 13 ----
+ src/lib/apputils/net-server.c                 | 27 -------
+ src/lib/crypto/builtin/des/destest.c          |  4 -
+ src/lib/crypto/builtin/des/t_verify.c         | 24 ------
+ src/lib/crypto/builtin/pbkdf2.c               | 38 +---------
+ src/lib/crypto/builtin/sha1/t_shs.c           | 15 ----
+ src/lib/crypto/crypto_tests/t_cksums.c        |  4 -
+ src/lib/crypto/crypto_tests/t_crc.c           | 45 +----------
+ src/lib/crypto/crypto_tests/t_cts.c           | 27 -------
+ src/lib/crypto/crypto_tests/t_decrypt.c       |  4 -
+ src/lib/crypto/crypto_tests/t_derive.c        |  4 -
+ src/lib/crypto/crypto_tests/t_hmac.c          | 11 ---
+ src/lib/crypto/crypto_tests/t_str2key.c       |  4 -
+ src/lib/crypto/crypto_tests/vectors.c         |  5 --
+ src/lib/crypto/krb/nfold.c                    | 10 ---
+ src/lib/gssapi/generic/util_set.c             | 15 ----
+ src/lib/gssapi/krb5/accept_sec_context.c      | 11 ---
+ src/lib/gssapi/krb5/gssapi_krb5.c             | 28 -------
+ src/lib/gssapi/krb5/naming_exts.c             | 10 ---
+ src/lib/gssapi/mechglue/g_initialize.c        | 25 -------
+ src/lib/gssapi/mechglue/g_inq_cred.c          |  5 --
+ src/lib/gssapi/mechglue/mglueP.h              |  5 --
+ src/lib/kadm5/clnt/client_init.c              | 48 +-----------
+ src/lib/kadm5/srv/server_init.c               | 11 ---
+ src/lib/kadm5/unit-test/setkey-test.c         |  9 ---
+ src/lib/krb5/asn.1/ldap_key_seq.c             |  3 -
+ src/lib/krb5/ccache/ccapi/stdcc.c             | 58 --------------
+ src/lib/krb5/ccache/ccapi/winccld.h           | 36 ---------
+ src/lib/krb5/keytab/t_keytab.c                | 13 ----
+ src/lib/krb5/krb/gc_via_tkt.c                 | 11 ---
+ src/lib/krb5/krb/init_ctx.c                   |  7 --
+ src/lib/krb5/krb/rd_req_dec.c                 | 31 +-------
+ src/lib/krb5/krb/t_ser.c                      | 75 +------------------
+ src/lib/krb5/krb/unparse.c                    |  7 --
+ src/lib/krb5/os/localaddr.c                   | 22 ------
+ src/lib/krb5/rcache/rc_io.c                   |  4 -
+ src/lib/rpc/auth_gssapi.c                     |  8 --
+ src/lib/rpc/svc_auth.c                        |  3 -
+ src/lib/rpc/svc_auth_gssapi.c                 |  4 -
+ src/lib/win_glue.c                            |  9 ---
+ src/plugins/kdb/db2/lockout.c                 |  4 -
+ src/plugins/kdb/ldap/libkdb_ldap/ldap_realm.c |  3 -
+ src/plugins/preauth/pkinit/pkinit_clnt.c      | 18 -----
+ src/plugins/preauth/pkinit/pkinit_matching.c  | 11 ---
+ src/plugins/preauth/pkinit/pkinit_srv.c       | 18 -----
+ src/tests/asn.1/krb5_decode_leak.c            | 12 ---
+ src/tests/dejagnu/config/default.exp          | 20 -----
+ src/tests/shlib/t_loader.c                    | 12 ---
+ src/tests/threads/t_rcache.c                  |  6 --
+ src/util/profile/prof_file.c                  | 43 -----------
+ src/util/support/fake-addrinfo.c              |  6 --
+ src/util/support/utf8.c                       | 22 ------
+ src/windows/include/loadfuncs-krb5.h          | 23 ------
+ src/windows/kfwlogon/kfwlogon.c               | 11 ---
+ src/windows/leash/Leash.cpp                   |  4 -
+ src/windows/leash/Makefile.in                 |  3 -
+ src/windows/leash/VSroutines.c                | 64 ----------------
+ src/windows/leashdll/lsh_pwd.c                | 11 ---
+ src/windows/leashdll/lshfunc.c                | 32 +-------
+ src/windows/leashdll/lshutil.cpp              | 11 ---
+ src/windows/lib/cacheapi.h                    | 15 ----
+ 84 files changed, 23 insertions(+), 1396 deletions(-)
+ delete mode 100644 src/windows/leash/VSroutines.c
+
+diff --git a/src/ccapi/common/win/OldCC/ccutils.c b/src/ccapi/common/win/OldCC/ccutils.c
+index 13f72cbe0..403c67ebe 100644
+--- a/src/ccapi/common/win/OldCC/ccutils.c
++++ b/src/ccapi/common/win/OldCC/ccutils.c
+@@ -101,9 +101,6 @@ HANDLE createThreadEvent(char* uuid, char* suffix) {
+         event_name = allocEventName(uuid, suffix);
+         if (!event_name) status = cci_check_error(ccErrNoMem);
+         }
+-#if 0
+-    cci_debug_printf("%s event_name:%s", __FUNCTION__, event_name);
+-#endif
+     if (!status) {
+         hEvent = CreateEvent(psa, FALSE, FALSE, event_name);
+         if (!hEvent)     status = cci_check_error(GetLastError());
+@@ -125,9 +122,6 @@ HANDLE openThreadEvent(char* uuid, char* suffix) {
+ 
+     event_name = allocEventName(uuid, suffix);
+     if (!event_name) status = cci_check_error(ccErrNoMem);
+-#if 0
+-    cci_debug_printf("%s event_name:%s", __FUNCTION__, event_name);
+-#endif
+     if (!status) {
+         hEvent = OpenEvent(EVENT_MODIFY_STATE, FALSE, event_name);
+         if (!hEvent) status = cci_check_error(GetLastError());
+diff --git a/src/ccapi/common/win/OldCC/ccutils.h b/src/ccapi/common/win/OldCC/ccutils.h
+index f91c77702..9da3d87fd 100644
+--- a/src/ccapi/common/win/OldCC/ccutils.h
++++ b/src/ccapi/common/win/OldCC/ccutils.h
+@@ -29,9 +29,6 @@
+ #ifdef __cplusplus
+ extern "C" {
+ #endif
+-#if 0
+-}
+-#endif
+ 
+ #define REPLY_SUFFIX    (char*)"reply"
+ #define LISTEN_SUFFIX   (char*)"listen"
+diff --git a/src/ccapi/common/win/OldCC/opts.cxx b/src/ccapi/common/win/OldCC/opts.cxx
+index bd5f503ea..c9776638b 100644
+--- a/src/ccapi/common/win/OldCC/opts.cxx
++++ b/src/ccapi/common/win/OldCC/opts.cxx
+@@ -29,45 +29,6 @@
+ #include <stdlib.h>
+ #include <opts.hxx>
+ 
+-#if 0
+-const struct Opts*
+-GetOpts(
+-    )
+-{
+-    bool done = false;
+-    struct Opts* o;
+-    if (!(o = new Opts))
+-        goto cleanup;
+-    if (!(o->pszString = new char[lstrlenA(opts.pszString) + 1]))
+-        goto cleanup;
+-    if (!(o->pszEndpoint = new char[lstrlenA(opts.pszEndpoint) + 1]))
+-        goto cleanup;
+-    strcpy(o->pszString, opts.pszString);
+-    strcpy(o->pszEndpoint, opts.pszEndpoint);
+-    done = true;
+- cleanup:
+-    if (!done) {
+-        FreeOpts(o);
+-        o = 0;
+-    }
+-    return o;
+-}
+-
+-void
+-FreeOpts(
+-    struct Opts* o
+-    )
+-{
+-    if (o) {
+-        if (o->pszString)
+-            delete [] o->pszString;
+-        if (o->pszEndpoint)
+-            delete [] o->pszEndpoint;
+-        delete o;
+-    }
+-}
+-#endif
+-
+ bool
+ ParseOpts::IsValidOpt(
+     char ch
+diff --git a/src/ccapi/common/win/OldCC/secure.hxx b/src/ccapi/common/win/OldCC/secure.hxx
+index 3714c6f84..1b2e7532d 100644
+--- a/src/ccapi/common/win/OldCC/secure.hxx
++++ b/src/ccapi/common/win/OldCC/secure.hxx
+@@ -38,12 +38,6 @@ public:
+     static void Start(SecureClient*& s);
+     static void Stop(SecureClient*& s);
+ 
+-#if 0
+-    static DWORD CheckImpersonation();
+-    static bool IsImp();
+-    static DWORD DuplicateImpAsPrimary(HANDLE& hPrimary);
+-#endif
+-
+     SecureClient();
+     ~SecureClient();
+     DWORD Error();
+diff --git a/src/ccapi/common/win/OldCC/util.h b/src/ccapi/common/win/OldCC/util.h
+index 082f6080b..45e069a71 100644
+--- a/src/ccapi/common/win/OldCC/util.h
++++ b/src/ccapi/common/win/OldCC/util.h
+@@ -29,9 +29,6 @@
+ #ifdef __cplusplus
+ extern "C" {
+ #endif
+-#if 0
+-}
+-#endif
+ 
+ BOOL isNT();
+ 
+diff --git a/src/ccapi/lib/win/OldCC/client.cxx b/src/ccapi/lib/win/OldCC/client.cxx
+index 4b2d718cc..0f95dfceb 100644
+--- a/src/ccapi/lib/win/OldCC/client.cxx
++++ b/src/ccapi/lib/win/OldCC/client.cxx
+@@ -118,9 +118,6 @@ DWORD find_server(Init::InitInfo& info, LPSTR endpoint) {
+     char*               szDir       = 0;
+     BOOL                bRes        = FALSE;
+     char*               cmdline     = NULL;
+-#if 0
+-    HANDLE hToken = 0;
+-#endif
+ 
+     psa = isNT() ? &sa : 0;
+ 
+@@ -156,38 +153,6 @@ DWORD find_server(Init::InitInfo& info, LPSTR endpoint) {
+             }
+ 
+         if (!status) {
+-
+-#if 0
+-            if (SecureClient::IsImp()) {
+-                cci_debug_printf(STARTUP "Token is impersonation token"));
+-                SecureClient::DuplicateImpAsPrimary(hToken);
+-                } 
+-            else {
+-                cci_debug_printf(STARTUP "Token is NOT impersonation token"));
+-                }
+-#endif
+-
+-#if 0
+-            if (hToken)
+-                bRes = CreateProcessAsUser(hToken,
+-                                       szExe, // app name
+-                                       NULL, // cmd line
+-                                       psa, // SA
+-                                       psa, // SA
+-                                       FALSE, 
+-                                       CREATE_NEW_PROCESS_GROUP | 
+-                                       //CREATE_NEW_CONSOLE |
+-                                       NORMAL_PRIORITY_CLASS |
+-                                       // CREATE_NO_WINDOW |
+-                                       DETACHED_PROCESS |
+-                                       0
+-                                       ,
+-                                       NULL, // environment
+-                                       szDir, // current dir
+-                                       &si,
+-                                       &pi);
+-            else
+-#endif
+                 alloc_cmdline_2_args(szExe, endpoint, "-D", &cmdline);
+                 bRes = CreateProcess(  szExe,       // app name
+                                        NULL, //cmdline,     // cmd line is <server endpoint -[DC]>
+@@ -223,10 +188,6 @@ DWORD find_server(Init::InitInfo& info, LPSTR endpoint) {
+             cci_debug_printf("  unexpected error while looking for server: 0D%d / 0U%u / 0X%X", status, status, status);
+             } 
+ 
+-#if 0
+-    if (hToken)
+-        CloseHandle(hToken);
+-#endif
+     if (szDir)                      free_alloc_p(&szDir);
+     if (szExe)                      free_alloc_p(&szExe);
+     if (hEvent)                     CloseHandle(hEvent);
+diff --git a/src/ccapi/lib/win/ccapi_os_ipc.cxx b/src/ccapi/lib/win/ccapi_os_ipc.cxx
+index 35589a54f..1b1f874e9 100644
+--- a/src/ccapi/lib/win/ccapi_os_ipc.cxx
++++ b/src/ccapi/lib/win/ccapi_os_ipc.cxx
+@@ -132,9 +132,6 @@ extern "C" cc_int32 cci_os_ipc_thread_init (void) {
+         cci_check_error(err);
+         }
+ 
+-#if 0
+-    cci_debug_printf("%s UUID:<%s>", __FUNCTION__, tspdata_getUUID(ptspdata));
+-#endif
+     // Initialize old CCAPI if necessary:
+     if (!err) if (!Init::  Initialized()) err = Init::  Initialize( );
+     if (!err) if (!Client::Initialized()) err = Client::Initialize(0);
+@@ -243,10 +240,6 @@ extern "C" cc_int32 cci_os_ipc_msg( cc_int32        in_launch_server,
+             if (!GetTspData(GetTlsIndex(), &ptspdata)) {return ccErrBadParam;}
+             uuid    = tspdata_getUUID(ptspdata);
+             lenUUID = 1 + strlen(uuid);     /* 1+ includes terminating \0. */
+-#if 0
+-            cci_debug_printf("%s calling remote ccs_rpc_request tsp*:0x%X", __FUNCTION__, ptspdata);
+-            cci_debug_printf("  rpcmsg:%d; UUID[%d]:<%s> SST:%ld", in_msg, lenUUID, uuid, sst);
+-#endif
+             /* copy ptr into handle; ptr may be 4 or 8 bytes, depending on platform; handle is always 8 */
+             memcpy(tspdata_handle, &ptspdata, sizeof(ptspdata));
+             ccs_rpc_request(                    /* make call with user message: */
+@@ -282,11 +275,6 @@ extern "C" cc_int32 cci_os_ipc_msg( cc_int32        in_launch_server,
+     if (!err && server_died) {
+         err = cci_check_error (ccErrServerUnavailable);
+         }
+-#if 0    
+-    if (err == BOOTSTRAP_UNKNOWN_SERVICE && !in_launch_server) {
+-        err = ccNoError;  /* If the server is not running just return an empty stream. */
+-        }
+-#endif
+ 
+     if (!err) {
+         *out_reply_stream = tspdata_getStream(ptspdata);
+@@ -365,9 +353,6 @@ cc_int32 ccapi_connect(const struct tspdata* tsp) {
+     ReleaseMutex(hCCAPIv2Mutex);       
+ 
+     if (!status) {
+-#if 0
+-        cci_debug_printf("%s Waiting for replyEvent.", __FUNCTION__);
+-#endif
+         status = WaitForSingleObject(replyEvent, INFINITE);//(SECONDS_TO_WAIT)*1000);
+         status = cci_check_error(RpcMgmtIsServerListening(CLIENT_REQUEST_RPC_HANDLE));
+         cci_debug_printf("  Server %sFOUND!", (status) ? "NOT " : "");
+diff --git a/src/ccapi/lib/win/ccs_reply_proc.c b/src/ccapi/lib/win/ccs_reply_proc.c
+index bf8c7f4f4..b4dbc0d19 100644
+--- a/src/ccapi/lib/win/ccs_reply_proc.c
++++ b/src/ccapi/lib/win/ccs_reply_proc.c
+@@ -47,9 +47,7 @@ void ccs_rpc_request_reply(
+     struct tspdata* tsp;
+     k5_ipc_stream    stream;
+     long            status  = 0;
+-#if 0
+-    cci_debug_printf("%s! msg#:%d SST:%ld uuid:%s", __FUNCTION__, rpcmsg, srvStartTime, uuid);
+-#endif
++
+     memcpy(&tsp, tspHandle, sizeof(tsp));
+     if (!status) {
+         status = krb5int_ipc_stream_new (&stream);  /* Create a stream for the request data */
+@@ -77,9 +75,7 @@ void ccs_rpc_connect_reply(
+ 
+     HANDLE  hEvent  = openThreadEvent(uuid, REPLY_SUFFIX);
+     DWORD*  p       = (DWORD*)(tspHandle);
+-#if 0
+-    cci_debug_printf("%s! msg#:%d SST:%ld uuid:%s", __FUNCTION__, rpcmsg, srvStartTime, uuid);
+-#endif
++
+     SetEvent(hEvent);
+     CloseHandle(hEvent);
+     }
+diff --git a/src/ccapi/lib/win/dllmain.cxx b/src/ccapi/lib/win/dllmain.cxx
+index 82cacad9c..aa5d00a65 100644
+--- a/src/ccapi/lib/win/dllmain.cxx
++++ b/src/ccapi/lib/win/dllmain.cxx
+@@ -163,17 +163,7 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL,     // DLL module handle
+             // using multiple DLLs that use this DLL.
+             //
+             WaitForSingleObject( hCCAPIv2Mutex, INFINITE );
+-#if 0
+-            bool process_teardown_workaround = false;
+-            if (lpvReserved) {
+-                Init::InitInfo info;
+-                status = Init::Info(info);
+-                if (status) break;
+-                if (!info.isNT) process_teardown_workaround = true;
+-            }
+-            if (process_teardown_workaround)
+-                break;
+-#endif
++
+             // return value is ignored, so we set status for debugging purposes
+             status = Client::Cleanup();
+             status = Init::Cleanup();
+diff --git a/src/ccapi/server/win/ccs_os_server.cpp b/src/ccapi/server/win/ccs_os_server.cpp
+index f84239491..7c5012039 100644
+--- a/src/ccapi/server/win/ccs_os_server.cpp
++++ b/src/ccapi/server/win/ccs_os_server.cpp
+@@ -245,10 +245,7 @@ cc_int32 ccs_os_server_listen_loop (int argc, const char *argv[]) {
+ 
+             if (worklist_remove(&rpcmsg, &pipe, &buf, &serverStartTime)) {
+                 uuid = ccs_win_pipe_getUuid(pipe);
+-#if 0
+-                cci_debug_printf("%s: processing WorkItem msg:%ld pipeUUID:<%s> pipeHandle:0x%X SST:%ld",
+-                    __FUNCTION__, rpcmsg, uuid, ccs_win_pipe_getHandle(pipe), serverStartTime);
+-#endif
++
+                 if (serverStartTime <= getMySST()) {
+                     switch (rpcmsg) {
+                         case CCMSG_CONNECT: {
+@@ -472,13 +469,6 @@ void    receiveLoop(void* rpcargs) {
+     }   // End receiveLoop
+ 
+ 
+-#if 0
+-
+-    return status;
+-}
+-#endif
+-
+-
+ 
+ /* ------------------------------------------------------------------------ */
+ /* The connection listener thread waits forever for a call to the CCAPI_CLIENT_<UUID>
+@@ -647,17 +637,6 @@ RPC_STATUS send_connection_reply(ccs_pipe_t in_pipe) {
+     return (status);
+     }
+ 
+-#if 0
+-DWORD alloc_name(LPSTR* pname, LPSTR postfix) {
+-    DWORD len = strlen(sessID) + 1 + strlen(postfix) + 1;
+-
+-    *pname = (LPSTR)malloc(len);
+-    if (!*pname) return GetLastError();
+-    _snprintf(*pname, len, "%s.%s", sessID, postfix);
+-    return 0;
+-    }
+-#endif
+-
+ RPC_STATUS GetPeerName( RPC_BINDING_HANDLE hClient,
+                         LPTSTR pszClientName,
+                         int iMaxLen) {
+diff --git a/src/ccapi/server/win/ccs_request_proc.c b/src/ccapi/server/win/ccs_request_proc.c
+index 461c441ed..c0328ea7e 100644
+--- a/src/ccapi/server/win/ccs_request_proc.c
++++ b/src/ccapi/server/win/ccs_request_proc.c
+@@ -45,9 +45,7 @@ void ccs_rpc_request(
+     k5_ipc_stream   stream;
+     UINT64*         p       = (UINT64*)(tspHandle);
+     WIN_PIPE*       pipe    = NULL;
+-#if 0
+-    cci_debug_printf("%s rpcmsg:%d; UUID:<%s> SST:<%s>", __FUNCTION__, rpcmsg, pszUUID, serverStartTime);
+-#endif
++
+     status = (rpcmsg != CCMSG_REQUEST) && (rpcmsg != CCMSG_PING);
+ 
+     if (!status) {
+@@ -72,9 +70,7 @@ void ccs_rpc_connect(
+ 
+     UINT64*     p       = (UINT64*)(tspHandle);
+     WIN_PIPE*   pipe    = ccs_win_pipe_new(pszUUID, *p);
+-#if 0
+-    cci_debug_printf("%s; rpcmsg:%d; UUID: <%s>", __FUNCTION__, rpcmsg, pszUUID);
+-#endif
++
+     worklist_add(   rpcmsg,
+                     pipe,
+                     NULL,               /* No payload with connect request */
+@@ -89,9 +85,7 @@ CC_UINT32 ccs_authenticate(const CC_CHAR* name) {
+     PDWORD      pvalue  = 0;
+     CC_UINT32   result  = 0;
+     DWORD       status  = 0;
+-#if 0
+-    cci_debug_printf("%s ( %s )", __FUNCTION__, name);
+-#endif
++
+     hMap = OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, (LPSTR)name);
+     status  = !hMap;
+ 
+diff --git a/src/ccapi/server/win/ccs_win_pipe.c b/src/ccapi/server/win/ccs_win_pipe.c
+index d23e4448e..99c667017 100644
+--- a/src/ccapi/server/win/ccs_win_pipe.c
++++ b/src/ccapi/server/win/ccs_win_pipe.c
+@@ -61,9 +61,7 @@ struct ccs_win_pipe_t* ccs_win_pipe_new (const char* uuid, const UINT64 h) {
+         out_pipe->uuid          = uuidCopy;
+         out_pipe->clientHandle  = h;
+         }
+-#if 0
+-    cci_debug_printf("0x%X = %s(%s, 0x%X)", out_pipe, __FUNCTION__, uuid, h);
+-#endif
++
+     return out_pipe;
+     }
+ 
+diff --git a/src/ccapi/test/pingtest.c b/src/ccapi/test/pingtest.c
+index d44839f71..0ffc15e7a 100644
+--- a/src/ccapi/test/pingtest.c
++++ b/src/ccapi/test/pingtest.c
+@@ -74,12 +74,6 @@ int main(   int argc, char *argv[]) {
+ 
+     if ((dwTlsIndex = TlsAlloc()) == TLS_OUT_OF_INDEXES) return FALSE;
+ 
+-//    send_test("krbcc.229026.0.ep");
+-
+-#if 0
+-    err = cc_initialize(&context, ccapi_version_7, NULL, NULL);
+-#endif
+-
+     if (!err) {
+         err = cci_os_ipc_thread_init();
+         }
+diff --git a/src/clients/ksu/authorization.c b/src/clients/ksu/authorization.c
+index 90aafbd75..891921870 100644
+--- a/src/clients/ksu/authorization.c
++++ b/src/clients/ksu/authorization.c
+@@ -123,23 +123,6 @@ krb5_error_code krb5_authorization(context, principal, luser,
+                 "In krb5_authorization: if auth files exist -> can access\n");
+     }
+ 
+-#if 0
+-    if (cmd){
+-        if(k5users_flag){
+-            return 0; /* if  kusers does not exist -> done */
+-        }else{
+-            if(retval = k5users_lookup(users_fp,princname,
+-                                       cmd,&retbool,out_fcmd)){
+-                auth_cleanup(users_fp, login_fp, princname);
+-                return retval;
+-            }else{
+-                *ok =retbool;
+-                return retval;
+-            }
+-        }
+-    }
+-#endif
+-
+     /* if either file exists,
+        first see if the principal is in the login in file,
+        if it's not there check the k5users file */
+diff --git a/src/config/win-post.in b/src/config/win-post.in
+index 6535c1ba5..3f43bda77 100644
+--- a/src/config/win-post.in
++++ b/src/config/win-post.in
+@@ -121,14 +121,6 @@ clean-windows-files:
+ !else
+ 	@if exist $(OUTPRE3)$(DIRNUL) deltree /y $(OUTPRE3)
+ !endif
+-!if 0
+-	$(RM) .\$(OUTPRE)*.obj .\$(OUTPRE)*.res
+-	$(RM) .\$(OUTPRE)*.exe .\$(OUTPRE)*.dll
+-	$(RM) .\$(OUTPRE)*.lib .\$(OUTPRE)*.pdb
+-	$(RM) .\$(OUTPRE)*.exp .\$(OUTPRE)*.map
+-	$(RM) .\$(OUTPRE)*.idb .\$(OUTPRE)*.ilk
+-	$(RM) .\$(OUTPRE)*.manifest
+-!endif
+ 
+ # Dependencies
+ !if exist($(srcdir)/deps)
+diff --git a/src/include/gssrpc/auth.h b/src/include/gssrpc/auth.h
+index 0f653fcc7..8576c5142 100644
+--- a/src/include/gssrpc/auth.h
++++ b/src/include/gssrpc/auth.h
+@@ -75,12 +75,6 @@ enum auth_stat {
+ };
+ 
+ union des_block {
+-#if 0 /* XXX nothing uses this, anyway */
+-	struct {
+-		uint32_t high;
+-		uint32_t low;
+-	} key;
+-#endif
+ 	char c[8];
+ };
+ typedef union des_block des_block;
+@@ -207,15 +201,6 @@ extern bool_t xdr_opaque_auth(XDR *, struct opaque_auth *);
+ #define AUTH_GSSAPI	300001		/* GSS-API style */
+ #define RPCSEC_GSS	6		/* RPCSEC_GSS */
+ 
+-#if 0
+-/*
+- * BACKWARDS COMPATIBILIY!  OpenV*Secure 1.0 had AUTH_GSSAPI == 4.  We
+- * need to accept this value until 1.0 is dead.
+- */
+-/* This conflicts with AUTH_KERB (Solaris). */
+-#define AUTH_GSSAPI_COMPAT		4
+-#endif
+-
+ GSSRPC__END_DECLS
+ 
+ #endif /* !defined(GSSRPC_AUTH_H) */
+diff --git a/src/include/gssrpc/rename.h b/src/include/gssrpc/rename.h
+index 669a0580c..df37e95b7 100644
+--- a/src/include/gssrpc/rename.h
++++ b/src/include/gssrpc/rename.h
+@@ -50,10 +50,7 @@
+  * External names in the RPC API not beginning with "_" get renamed
+  * with the prefix "gssrpc_" via #define, e.g., "foo" -> "gssrpc_foo".
+  * External names in the RPC API beginning with "_" get textually
+- * rewritten, with "#if 0"-disabled #defines mapping them back to
+- * their original forms, e.g., "_foo" is rewrittten to "gssrpc__foo"
+- * in the original files, with an unused "#define gssrpc__foo _foo"
+- * here.
++ * rewritten.
+  */
+ 
+ #ifndef GSSRPC_RENAME_H
+@@ -72,10 +69,6 @@
+ #define authdes_create		gssrpc_authdes_create
+ #define xdr_opaque_auth		gssrpc_xdr_opaque_auth
+ 
+-#if 0
+-#define gssrpc__null_auth	_null_auth
+-#endif
+-
+ /* auth_gss.c */
+ 
+ #define auth_debug_gss		gssrpc_auth_debug_gss
+@@ -181,10 +174,6 @@
+ #define callrpc			gssrpc_callrpc
+ #define getrpcport		gssrpc_getrpcport
+ 
+-#if 0
+-#define gssrpc__rpc_getdtablesize	_rpc_getdtablesize
+-#endif
+-
+ /* rpc_msg.h */
+ 
+ #define xdr_callmsg		gssrpc_xdr_callmsg
+@@ -193,10 +182,6 @@
+ #define xdr_accepted_reply	gssrpc_xdr_accepted_reply
+ #define xdr_rejected_reply	gssrpc_xdr_rejected_reply
+ 
+-#if 0
+-#define gssrpc__seterr_reply	_seterr_reply
+-#endif
+-
+ /* svc.h */
+ 
+ #define svc_register		gssrpc_svc_register
+@@ -244,15 +229,6 @@
+ #define svcauth_gss_set_svc_name	gssrpc_svcauth_gss_set_svc_name
+ #define svcauth_gss_get_principal	gssrpc_svcauth_gss_get_principal
+ 
+-#if 0
+-#define gssrpc__authenticate	_authenticate
+-#define gssrpc__svcauth_none	_svcauth_none
+-#define gssrpc__svcauth_unix	_svcauth_unix
+-#define gssrpc__svcauth_short	_svcauth_short
+-#define gssrpc__svcauth_gssapi	_svcauth_gssapi
+-#define gssrpc__svcauth_gss	_svcauth_gss
+-#endif
+-
+ /* svc_auth_gss.c */
+ 
+ #define svc_debug_gss		gssrpc_svc_debug_gss
+diff --git a/src/include/gssrpc/rpc.h b/src/include/gssrpc/rpc.h
+index 2d94a7fe9..78727c49d 100644
+--- a/src/include/gssrpc/rpc.h
++++ b/src/include/gssrpc/rpc.h
+@@ -55,36 +55,11 @@
+ #include <gssrpc/rpc_msg.h>	/* protocol for rpc messages */
+ #include <gssrpc/auth_unix.h>	/* protocol for unix style cred */
+ #include <gssrpc/auth_gss.h>	/* RPCSEC_GSS */
+-/*
+- *  Uncomment-out the next line if you are building the rpc library with
+- *  DES Authentication (see the README file in the secure_rpc/ directory).
+- */
+-#if 0
+-#include <gssrpc/auth_des.h>	protocol for des style cred
+-#endif
+ 
+ /* Server side only remote procedure callee */
+ #include <gssrpc/svc_auth.h>	/* service side authenticator */
+ #include <gssrpc/svc.h>		/* service manager and multiplexer */
+ 
+-/*
+- * Punt the rpc/netdb.h everywhere because it just makes things much more
+- * difficult.  We don't use the *rpcent functions anyway.
+- */
+-#if 0
+-/*
+- * COMMENT OUT THE NEXT INCLUDE IF RUNNING ON SUN OS OR ON A VERSION
+- * OF UNIX BASED ON NFSSRC.  These systems will already have the structures
+- * defined by <rpc/netdb.h> included in <netdb.h>.
+- */
+-/* routines for parsing /etc/rpc */
+-#if 0 /* netdb.h already included in rpc/types.h */
+-#include <netdb.h>
+-#endif
+-
+-#include <gssrpc/netdb.h>	/* structures and routines to parse /etc/rpc */
+-#endif
+-
+ /*
+  * get the local host's IP address without consulting
+  * name service library functions
+diff --git a/src/include/gssrpc/types.hin b/src/include/gssrpc/types.hin
+index 022ab4fa9..4c4120c6f 100644
+--- a/src/include/gssrpc/types.hin
++++ b/src/include/gssrpc/types.hin
+@@ -116,13 +116,6 @@ typedef int32_t		rpc_inline_t;
+ #define mem_alloc(bsize)	malloc(bsize)
+ #define mem_free(ptr, bsize)	free(ptr)
+ 
+-#if 0
+-#include <netdb.h> /* XXX This should not have to be here.
+-		    * I got sick of seeing the warnings for MAXHOSTNAMELEN
+-		    * and the two values were different. -- shanzer
+-		    */
+-#endif
+-
+ #ifndef INADDR_LOOPBACK
+ #define       INADDR_LOOPBACK         (uint32_t)0x7F000001
+ #endif
+diff --git a/src/include/k5-platform.h b/src/include/k5-platform.h
+index 763408a09..3368c7193 100644
+--- a/src/include/k5-platform.h
++++ b/src/include/k5-platform.h
+@@ -526,15 +526,11 @@ typedef struct { int error; unsigned char did_run; } k5_init_t;
+ # endif
+ #elif TARGET_OS_MAC
+ # include <architecture/byte_order.h>
+-# if 0 /* This causes compiler warnings.  */
+-#  define SWAP16                OSSwapInt16
+-# else
+-#  define SWAP16                k5_swap16
++# define SWAP16                k5_swap16
+ static inline unsigned int k5_swap16 (unsigned int x) {
+     x &= 0xffff;
+     return (x >> 8) | ((x & 0xff) << 8);
+ }
+-# endif
+ # define SWAP32                 OSSwapInt32
+ # define SWAP64                 OSSwapInt64
+ #elif defined(HAVE_SYS_BSWAP_H)
+@@ -848,25 +844,6 @@ k5_ntohll (uint64_t val)
+    business.  Probably most callers won't check the return status
+    anyways.  */
+ 
+-#if 0
+-static inline void
+-set_cloexec_fd(int fd)
+-{
+-#if defined(F_SETFD)
+-# ifdef FD_CLOEXEC
+-    (void)fcntl(fd, F_SETFD, FD_CLOEXEC);
+-# else
+-    (void)fcntl(fd, F_SETFD, 1);
+-# endif
+-#endif
+-}
+-
+-static inline void
+-set_cloexec_file(FILE *f)
+-{
+-    return set_cloexec_fd(fileno(f));
+-}
+-#else
+ /* Macros make the Sun compiler happier, and all variants of this do a
+    single evaluation of the argument, and fcntl and fileno should
+    produce reasonable error messages on type mismatches, on any system
+@@ -881,9 +858,6 @@ set_cloexec_file(FILE *f)
+ # define set_cloexec_fd(FD)     ((void)(FD))
+ #endif
+ #define set_cloexec_file(F)     set_cloexec_fd(fileno(F))
+-#endif
+-
+-
+ 
+ /* Since the original ANSI C spec left it undefined whether or
+    how you could copy around a va_list, C 99 added va_copy.
+diff --git a/src/kadmin/dbutil/kdb5_util.c b/src/kadmin/dbutil/kdb5_util.c
+index 000b5595c..4ff1cdf38 100644
+--- a/src/kadmin/dbutil/kdb5_util.c
++++ b/src/kadmin/dbutil/kdb5_util.c
+@@ -358,44 +358,6 @@ int main(argc, argv)
+     return exit_status;
+ }
+ 
+-#if 0
+-/*
+- * This function is no longer used in kdb5_util (and it would no
+- * longer work, anyway).
+- */
+-void set_dbname(argc, argv)
+-    int argc;
+-    char *argv[];
+-{
+-    krb5_error_code retval;
+-
+-    if (argc < 3) {
+-        com_err(argv[0], 0, _("Too few arguments"));
+-        com_err(progname, 0, _("Usage: %s dbpathname realmname"), argv[0]);
+-        exit_status++;
+-        return;
+-    }
+-    if (dbactive) {
+-        if ((retval = krb5_db_fini(util_context)) && retval!= KRB5_KDB_DBNOTINITED) {
+-            com_err(progname, retval, _("while closing previous database"));
+-            exit_status++;
+-            return;
+-        }
+-        if (valid_master_key) {
+-            krb5_free_keyblock_contents(util_context, &master_keyblock);
+-            master_keyblock.contents = NULL;
+-            valid_master_key = 0;
+-        }
+-        krb5_free_principal(util_context, master_princ);
+-        free(mkey_fullname);
+-        dbactive = FALSE;
+-    }
+-
+-    (void) set_dbname_help(progname, argv[1]);
+-    return;
+-}
+-#endif
+-
+ /*
+  * open_db_and_mkey: Opens the KDC and policy database, and sets the
+  * global master_* variables.  Sets dbactive to TRUE if the databases
+diff --git a/src/kadmin/server/ipropd_svc.c b/src/kadmin/server/ipropd_svc.c
+index e6e190136..3228687c7 100644
+--- a/src/kadmin/server/ipropd_svc.c
++++ b/src/kadmin/server/ipropd_svc.c
+@@ -621,32 +621,3 @@ krb5_iprop_prog_1(struct svc_req *rqstp,
+     }
+ 
+ }
+-
+-#if 0
+-/*
+- * Get the host base service name for the kiprop principal. Returns
+- * KADM5_OK on success. Caller must free the storage allocated for
+- * host_service_name.
+- */
+-kadm5_ret_t
+-kiprop_get_adm_host_srv_name(krb5_context context,
+-			     const char *realm,
+-			     char **host_service_name)
+-{
+-    kadm5_ret_t ret;
+-    char *name;
+-    char *host;
+-
+-    if (ret = kadm5_get_master(context, realm, &host))
+-	return (ret);
+-
+-    if (asprintf(&name, "%s@%s", KIPROP_SVC_NAME, host) < 0) {
+-	free(host);
+-	return (ENOMEM);
+-    }
+-    free(host);
+-    *host_service_name = name;
+-
+-    return (KADM5_OK);
+-}
+-#endif
+diff --git a/src/kdc/kdc_log.c b/src/kdc/kdc_log.c
+index 7e8733980..4eec50373 100644
+--- a/src/kdc/kdc_log.c
++++ b/src/kdc/kdc_log.c
+@@ -94,14 +94,6 @@ log_as_req(krb5_context context,
+     krb5_db_audit_as_req(context, request,
+                          local_addr->address, remote_addr->address,
+                          client, server, authtime, errcode);
+-#if 0
+-    /* Sun (OpenSolaris) version would probably something like this.
+-       The client and server names passed can be null, unlike in the
+-       logging routines used above.  Note that a struct in_addr is
+-       used, but the real address could be an IPv6 address.  */
+-    audit_krb5kdc_as_req(some in_addr *, (in_port_t)remote_addr->port, 0,
+-                         cname, sname, errcode);
+-#endif
+ }
+ 
+ /*
+diff --git a/src/kdc/kdc_preauth.c b/src/kdc/kdc_preauth.c
+index 86b9e2991..811c16368 100644
+--- a/src/kdc/kdc_preauth.c
++++ b/src/kdc/kdc_preauth.c
+@@ -712,19 +712,6 @@ const char *missing_required_preauth(krb5_db_entry *client,
+                                      krb5_db_entry *server,
+                                      krb5_enc_tkt_part *enc_tkt_reply)
+ {
+-#if 0
+-    /*
+-     * If this is the pwchange service, and the pre-auth bit is set,
+-     * allow it even if the HW preauth would normally be required.
+-     *
+-     * Sandia national labs wanted this for some strange reason... we
+-     * leave it disabled normally.
+-     */
+-    if (isflagset(server->attributes, KRB5_KDB_PWCHANGE_SERVICE) &&
+-        isflagset(enc_tkt_reply->flags, TKT_FLG_PRE_AUTH))
+-        return 0;
+-#endif
+-
+ #ifdef DEBUG
+     krb5_klog_syslog (
+         LOG_DEBUG,
+diff --git a/src/lib/apputils/net-server.c b/src/lib/apputils/net-server.c
+index a40da927e..54ee4c5c5 100644
+--- a/src/lib/apputils/net-server.c
++++ b/src/lib/apputils/net-server.c
+@@ -1060,17 +1060,6 @@ process_packet(verto_ctx *ctx, verto_ev *ev)
+         return;
+     }
+ 
+-#if 0
+-    if (state->daddr_len > 0) {
+-        char addrbuf[100];
+-        if (getnameinfo(ss2sa(&state->daddr), state->daddr_len,
+-                        addrbuf, sizeof(addrbuf),
+-                        0, 0, NI_NUMERICHOST))
+-            strlcpy(addrbuf, "?", sizeof(addrbuf));
+-        com_err(conn->prog, 0, _("pktinfo says local addr is %s"), addrbuf);
+-    }
+-#endif
+-
+     if (state->daddr_len == 0 && conn->type == CONN_UDP) {
+         /*
+          * An address couldn't be obtained, so the PKTINFO option probably
+@@ -1116,11 +1105,6 @@ kill_lru_tcp_or_rpc_connection(void *handle, verto_ev *newev)
+             continue;
+         if (c->type != CONN_TCP && c->type != CONN_RPC)
+             continue;
+-#if 0
+-        krb5_klog_syslog(LOG_INFO, "fd %d started at %ld",
+-                         verto_get_fd(oldest_ev),
+-                         c->start_time);
+-#endif
+         if (oldest_c == NULL
+             || oldest_c->start_time > c->start_time) {
+             oldest_ev = ev;
+@@ -1186,10 +1170,6 @@ accept_tcp_connection(verto_ctx *ctx, verto_ev *ev)
+             strlcpy(p, tmpbuf, end - p);
+         }
+     }
+-#if 0
+-    krb5_klog_syslog(LOG_INFO, "accepted TCP connection on socket %d from %s",
+-                     s, newconn->addrbuf);
+-#endif
+ 
+     newconn->addr_s = addr_s;
+     newconn->addrlen = addrlen;
+@@ -1481,9 +1461,6 @@ accept_rpc_connection(verto_ctx *ctx, verto_ev *ev)
+         newconn = verto_get_private(newev);
+ 
+         set_cloexec_fd(s);
+-#if 0
+-        setnbio(s), setnolinger(s), setkeepalive(s);
+-#endif
+ 
+         if (getpeername(s, addr, &addrlen) ||
+             getnameinfo(addr, addrlen,
+@@ -1503,10 +1480,6 @@ accept_rpc_connection(verto_ctx *ctx, verto_ev *ev)
+                 strlcpy(p, tmpbuf, end - p);
+             }
+         }
+-#if 0
+-        krb5_klog_syslog(LOG_INFO, _("accepted RPC connection on socket %d "
+-                                     "from %s"), s, newconn->addrbuf);
+-#endif
+ 
+         newconn->addr_s = addr_s;
+         newconn->addrlen = addrlen;
+diff --git a/src/lib/crypto/builtin/des/destest.c b/src/lib/crypto/builtin/des/destest.c
+index dd2f68ec4..0d92b365b 100644
+--- a/src/lib/crypto/builtin/des/destest.c
++++ b/src/lib/crypto/builtin/des/destest.c
+@@ -67,9 +67,6 @@ main(argc, argv)
+     char *argv[];
+ {
+     char block1[17], block2[17], block3[17];
+-#if 0
+-    mit_des_cblock key, input, output, output2;
+-#else
+     /* Force tests of unaligned accesses.  */
+     union { unsigned char c[8*4+3]; long l; } u;
+     unsigned char *ioblocks = u.c;
+@@ -77,7 +74,6 @@ main(argc, argv)
+     unsigned char *output = ioblocks+10;
+     unsigned char *output2 = ioblocks+19;
+     unsigned char *key = ioblocks+27;
+-#endif
+     mit_des_key_schedule sched;
+     int num = 0;
+     int retval;
+diff --git a/src/lib/crypto/builtin/des/t_verify.c b/src/lib/crypto/builtin/des/t_verify.c
+index 1f3239fed..f4332f5c0 100644
+--- a/src/lib/crypto/builtin/des/t_verify.c
++++ b/src/lib/crypto/builtin/des/t_verify.c
+@@ -334,30 +334,6 @@ main(argc,argv)
+     exit(0);
+ }
+ 
+-#if 0
+-void
+-flip(array)
+-    char *array;
+-{
+-    register int old,new,i,j;
+-    /* flips the bit order within each byte from 0 lsb to 0 msb */
+-    for (i = 0; i<=7; i++) {
+-        old = *array;
+-        new = 0;
+-        for (j = 0; j<=7; j++) {
+-            if (old & 01)
+-                new = new | 01;
+-            if (j < 7) {
+-                old = old >> 1;
+-                new = new << 1;
+-            }
+-        }
+-        *array = new;
+-        array++;
+-    }
+-}
+-#endif
+-
+ static void
+ do_encrypt(in,out)
+     unsigned char *in;
+diff --git a/src/lib/crypto/builtin/pbkdf2.c b/src/lib/crypto/builtin/pbkdf2.c
+index d36b32e7e..8905f2671 100644
+--- a/src/lib/crypto/builtin/pbkdf2.c
++++ b/src/lib/crypto/builtin/pbkdf2.c
+@@ -102,11 +102,6 @@ F(char *output, char *u_tmp1, char *u_tmp2,
+     krb5_data out;
+     krb5_error_code err;
+ 
+-#if 0
+-    printf("F(i=%d, count=%lu, pass=%d:%s)\n", i, count,
+-           pass->length, pass->data);
+-#endif
+-
+     /* Compute U_1.  */
+     store_32_be(i, ibytes);
+ 
+@@ -114,45 +109,25 @@ F(char *output, char *u_tmp1, char *u_tmp2,
+     memcpy(u_tmp2 + salt->length, ibytes, 4);
+     sdata = make_data(u_tmp2, salt->length + 4);
+ 
+-#if 0
+-    printd("initial salt", &sdata);
+-#endif
+-
+     out = make_data(u_tmp1, hlen);
+ 
+-#if 0
+-    printf("F: computing hmac #1 (U_1) with %s\n", pdata.contents);
+-#endif
+     err = hmac(hash, pass, &sdata, &out);
+     if (err)
+         return err;
+-#if 0
+-    printd("F: prf return value", &out);
+-#endif
++
+     memcpy(output, u_tmp1, hlen);
+ 
+     /* Compute U_2, .. U_c.  */
+     sdata.length = hlen;
+     for (j = 2; j <= count; j++) {
+-#if 0
+-        printf("F: computing hmac #%d (U_%d)\n", j, j);
+-#endif
+         memcpy(u_tmp2, u_tmp1, hlen);
+         err = hmac(hash, pass, &sdata, &out);
+         if (err)
+             return err;
+-#if 0
+-        printd("F: prf return value", &out);
+-#endif
++
+         /* And xor them together.  */
+         for (k = 0; k < hlen; k++)
+             output[k] ^= u_tmp1[k];
+-#if 0
+-        printf("F: xor result:\n");
+-        for (k = 0; k < hlen; k++)
+-            printf(" %02x", 0xff & output[k]);
+-        printf("\n");
+-#endif
+     }
+     return 0;
+ }
+@@ -185,9 +160,6 @@ pbkdf2(const struct krb5_hash_provider *hash, krb5_keyblock *pass,
+ 
+     /* Step 3.  */
+     for (i = 1; i <= l; i++) {
+-#if 0
+-        int j;
+-#endif
+         krb5_error_code err;
+         char *out;
+ 
+@@ -205,12 +177,6 @@ pbkdf2(const struct krb5_hash_provider *hash, krb5_keyblock *pass,
+             memcpy(output->data + (i-1) * hlen, utmp3,
+                    output->length - (i-1) * hlen);
+ 
+-#if 0
+-        printf("after F(%d), @%p:\n", i, output->data);
+-        for (j = (i-1) * hlen; j < i * hlen; j++)
+-            printf(" %02x", 0xff & output->data[j]);
+-        printf ("\n");
+-#endif
+     }
+     free(utmp1);
+     free(utmp2);
+diff --git a/src/lib/crypto/builtin/sha1/t_shs.c b/src/lib/crypto/builtin/sha1/t_shs.c
+index 08157b662..c1d18f557 100644
+--- a/src/lib/crypto/builtin/sha1/t_shs.c
++++ b/src/lib/crypto/builtin/sha1/t_shs.c
+@@ -59,10 +59,6 @@ main()
+ {
+     SHS_INFO shsInfo;
+     unsigned int i;
+-#if 0
+-    time_t secondCount;
+-    SHS_BYTE data[ 200 ];
+-#endif
+ 
+     /* Make sure we've got the endianness set right.  If the machine is
+        big-endian (up to 64 bits) the following value will be signed,
+@@ -120,17 +116,6 @@ main()
+     puts( "passed, result= 3232AFFA48628A26653B5AAA44541FD90D690603" );
+ #endif /* NEW_SHS */
+ 
+-#if 0
+-    printf( "\nTesting speed for 100MB data... " );
+-    shsInit( &shsInfo );
+-    secondCount = time( NULL );
+-    for( i = 0; i < 500000U; i++ )
+-        shsUpdate( &shsInfo, data, 200 );
+-    secondCount = time( NULL ) - secondCount;
+-    printf( "done.  Time = %ld seconds, %ld kbytes/second.\n", \
+-            secondCount, 100500L / secondCount );
+-#endif
+-
+     puts( "\nAll SHS tests passed" );
+     exit( 0 );
+ }
+diff --git a/src/lib/crypto/crypto_tests/t_cksums.c b/src/lib/crypto/crypto_tests/t_cksums.c
+index 4b5406e67..5afc90ed8 100644
+--- a/src/lib/crypto/crypto_tests/t_cksums.c
++++ b/src/lib/crypto/crypto_tests/t_cksums.c
+@@ -175,15 +175,11 @@ printhex(const char *head, void *data, size_t len)
+ 
+     printf("%s", head);
+     for (i = 0; i < len; i++) {
+-#if 0                           /* For convenience when updating test cases. */
+-        printf("\\x%02X", ((unsigned char*)data)[i]);
+-#else
+         printf("%02X", ((unsigned char*)data)[i]);
+         if (i % 16 == 15 && i + 1 < len)
+             printf("\n%*s", (int)strlen(head), "");
+         else if (i + 1 < len)
+             printf(" ");
+-#endif
+     }
+     printf("\n");
+ }
+diff --git a/src/lib/crypto/crypto_tests/t_crc.c b/src/lib/crypto/crypto_tests/t_crc.c
+index 1a35cfba5..8cd1d36cb 100644
+--- a/src/lib/crypto/crypto_tests/t_crc.c
++++ b/src/lib/crypto/crypto_tests/t_crc.c
+@@ -107,41 +107,9 @@ struct crc_trial trials[] = {
+ 
+ #define NTRIALS (sizeof(trials) / sizeof(trials[0]))
+ 
+-#if 0
+-static void
+-timetest(unsigned int nblk, unsigned int blksiz)
+-{
+-    char *block;
+-    unsigned int i;
+-    struct tms before, after;
+-    unsigned long cksum;
+ 
+-    block = malloc(blksiz * nblk);
+-    if (block == NULL)
+-        exit(1);
+-    for (i = 0; i < blksiz * nblk; i++)
+-        block[i] = i % 256;
+-    times(&before);
+-    for (i = 0; i < nblk; i++) {
+-        cksum = 0;
+-        mit_crc32(block + i * blksiz, blksiz, &cksum);
+-    }
+-
+-    times(&after);
+-    printf("shift-8 implementation, %d blocks of %d bytes:\n",
+-           nblk, blksiz);
+-    printf("\tu=%ld s=%ld cu=%ld cs=%ld\n",
+-           (long)(after.tms_utime - before.tms_utime),
+-           (long)(after.tms_stime - before.tms_stime),
+-           (long)(after.tms_cutime - before.tms_cutime),
+-           (long)(after.tms_cstime - before.tms_cstime));
+-
+-    free(block);
+-}
+-#endif
+-
+-static void
+-verify(void)
++int
++main(void)
+ {
+     unsigned int i;
+     struct crc_trial trial;
+@@ -176,14 +144,5 @@ verify(void)
+                (trial.sum == cksum) ? "OK" : "***BAD***",
+                typestr, trial.data, cksum);
+     }
+-}
+-
+-int
+-main(void)
+-{
+-#if 0
+-    timetest(64*1024, 1024);
+-#endif
+-    verify();
+     exit(0);
+ }
+diff --git a/src/lib/crypto/crypto_tests/t_cts.c b/src/lib/crypto/crypto_tests/t_cts.c
+index 2b022b4ac..fe505169f 100644
+--- a/src/lib/crypto/crypto_tests/t_cts.c
++++ b/src/lib/crypto/crypto_tests/t_cts.c
+@@ -44,37 +44,10 @@
+ 
+ const char *whoami;
+ 
+-#if 0
+-static void printhex (size_t len, const char *p)
+-{
+-    while (len--)
+-        printf ("%02x", 0xff & *p++);
+-}
+-
+-static void printstringhex (const char *p) { printhex (strlen (p), p); }
+-
+-static void printdata (krb5_data *d) { printhex (d->length, d->data); }
+-
+-static void printkey (krb5_keyblock *k) { printhex (k->length, k->contents); }
+-#endif
+-
+-
+ #define JURISIC "Juri\305\241i\304\207" /* hi Miro */
+ #define ESZETT "\303\237"
+ #define GCLEF  "\360\235\204\236" /* outside BMP, woo hoo!  */
+ 
+-#if 0
+-static void
+-check_error (int r, int line) {
+-    if (r != 0) {
+-        fprintf (stderr, "%s:%d: %s\n", __FILE__, line,
+-                 error_message (r));
+-        exit (1);
+-    }
+-}
+-#define CHECK check_error(r, __LINE__)
+-#endif
+-
+ static void printd (const char *descr, krb5_data *d) {
+     unsigned int i, j;
+     const int r = 16;
+diff --git a/src/lib/crypto/crypto_tests/t_decrypt.c b/src/lib/crypto/crypto_tests/t_decrypt.c
+index 1dbc4dd1b..4ae0256cc 100644
+--- a/src/lib/crypto/crypto_tests/t_decrypt.c
++++ b/src/lib/crypto/crypto_tests/t_decrypt.c
+@@ -658,15 +658,11 @@ printhex(const char *head, void *data, size_t len)
+ 
+     printf("%s", head);
+     for (i = 0; i < len; i++) {
+-#if 0                           /* For convenience when updating test cases. */
+-        printf("\\x%02X", ((unsigned char*)data)[i]);
+-#else
+         printf("%02X", ((unsigned char*)data)[i]);
+         if (i % 16 == 15 && i + 1 < len)
+             printf("\n%*s", (int)strlen(head), "");
+         else if (i + 1 < len)
+             printf(" ");
+-#endif
+     }
+     printf("\n");
+ }
+diff --git a/src/lib/crypto/crypto_tests/t_derive.c b/src/lib/crypto/crypto_tests/t_derive.c
+index 381ae4393..afbf7477f 100644
+--- a/src/lib/crypto/crypto_tests/t_derive.c
++++ b/src/lib/crypto/crypto_tests/t_derive.c
+@@ -273,15 +273,11 @@ printhex(const char *head, void *data, size_t len)
+ 
+     printf("%s", head);
+     for (i = 0; i < len; i++) {
+-#if 0                           /* For convenience when updating test cases. */
+-        printf("\\x%02X", ((unsigned char*)data)[i]);
+-#else
+         printf("%02X", ((unsigned char*)data)[i]);
+         if (i % 16 == 15 && i + 1 < len)
+             printf("\n%*s", (int)strlen(head), "");
+         else if (i + 1 < len)
+             printf(" ");
+-#endif
+     }
+     printf("\n");
+ }
+diff --git a/src/lib/crypto/crypto_tests/t_hmac.c b/src/lib/crypto/crypto_tests/t_hmac.c
+index 93d54828f..da359cb49 100644
+--- a/src/lib/crypto/crypto_tests/t_hmac.c
++++ b/src/lib/crypto/crypto_tests/t_hmac.c
+@@ -46,17 +46,6 @@ static void keyToData (krb5_keyblock *k, krb5_data *d) {
+     d->data = (char *) k->contents;
+ }
+ 
+-#if 0
+-static void check_error (int r, int line) {
+-    if (r != 0) {
+-        fprintf (stderr, "%s:%d: %s\n", __FILE__, line,
+-                 error_message (r));
+-        exit (1);
+-    }
+-}
+-#define CHECK check_error(r, __LINE__)
+-#endif
+-
+ static void printd (const char *descr, krb5_data *d) {
+     unsigned int i, j;
+     const int r = 16;
+diff --git a/src/lib/crypto/crypto_tests/t_str2key.c b/src/lib/crypto/crypto_tests/t_str2key.c
+index 7a7813874..27896e61e 100644
+--- a/src/lib/crypto/crypto_tests/t_str2key.c
++++ b/src/lib/crypto/crypto_tests/t_str2key.c
+@@ -719,15 +719,11 @@ printhex(const char *head, void *data, size_t len)
+ 
+     printf("%s", head);
+     for (i = 0; i < len; i++) {
+-#if 0                           /* For convenience when updating test cases. */
+-        printf("\\x%02X", ((unsigned char*)data)[i]);
+-#else
+         printf("%02X", ((unsigned char*)data)[i]);
+         if (i % 16 == 15 && i + 1 < len)
+             printf("\n%*s", (int)strlen(head), "");
+         else if (i + 1 < len)
+             printf(" ");
+-#endif
+     }
+     printf("\n");
+ }
+diff --git a/src/lib/crypto/crypto_tests/vectors.c b/src/lib/crypto/crypto_tests/vectors.c
+index 482d2de20..c1a765732 100644
+--- a/src/lib/crypto/crypto_tests/vectors.c
++++ b/src/lib/crypto/crypto_tests/vectors.c
+@@ -448,11 +448,6 @@ int main (int argc, char **argv)
+ {
+     whoami = argv[0];
+     test_nfold ();
+-#if 0
+-    test_mit_des_s2k ();
+-    test_des3_s2k ();
+-    test_dr_dk ();
+-#endif
+     test_pbkdf2();
+     return 0;
+ }
+diff --git a/src/lib/crypto/krb/nfold.c b/src/lib/crypto/krb/nfold.c
+index ea02fddcf..75bceaecd 100644
+--- a/src/lib/crypto/krb/nfold.c
++++ b/src/lib/crypto/krb/nfold.c
+@@ -98,19 +98,9 @@ krb5int_nfold(unsigned int inbits, const unsigned char *in, unsigned int outbits
+         byte += out[i%outbits];
+         out[i%outbits] = byte&0xff;
+ 
+-#if 0
+-        printf("msbit[%d] = %d\tbyte = %02x\tsum = %03x\n", i, msbit,
+-               (((in[((inbits-1)-(msbit>>3))%inbits]<<8)|
+-                 (in[((inbits)-(msbit>>3))%inbits]))
+-                >>((msbit&7)+1))&0xff, byte);
+-#endif
+-
+         /* keep around the carry bit, if any */
+         byte >>= 8;
+ 
+-#if 0
+-        printf("carry=%d\n", byte);
+-#endif
+     }
+ 
+     /* if there's a carry bit left over, add it back in */
+diff --git a/src/lib/gssapi/generic/util_set.c b/src/lib/gssapi/generic/util_set.c
+index 8866f525f..432a9ee0d 100644
+--- a/src/lib/gssapi/generic/util_set.c
++++ b/src/lib/gssapi/generic/util_set.c
+@@ -40,21 +40,6 @@ int g_set_init(g_set_elt *s)
+     return(0);
+ }
+ 
+-#if 0
+-int g_set_destroy(g_set_elt *s)
+-{
+-    g_set next;
+-
+-    while (*s) {
+-        next = (*s)->next;
+-        free(*s);
+-        *s = next;
+-    }
+-
+-    return(0);
+-}
+-#endif
+-
+ int g_set_entry_add(g_set_elt *s, void *key, void *value)
+ {
+     g_set_elt first;
+diff --git a/src/lib/gssapi/krb5/accept_sec_context.c b/src/lib/gssapi/krb5/accept_sec_context.c
+index 06967aa27..5baa6cecf 100644
+--- a/src/lib/gssapi/krb5/accept_sec_context.c
++++ b/src/lib/gssapi/krb5/accept_sec_context.c
+@@ -654,17 +654,6 @@ kg_accept_krb5(minor_status, context_handle,
+ 
+     krb5_auth_con_getauthenticator(context, auth_context, &authdat);
+ 
+-#if 0
+-    /* make sure the necessary parts of the authdat are present */
+-
+-    if ((authdat->authenticator->subkey == NULL) ||
+-        (authdat->ticket->enc_part2 == NULL)) {
+-        code = KG_NO_SUBKEY;
+-        major_status = GSS_S_FAILURE;
+-        goto fail;
+-    }
+-#endif
+-
+     if (authdat->checksum == NULL) {
+         /*
+          * Some SMB client implementations use handcrafted GSSAPI code that
+diff --git a/src/lib/gssapi/krb5/gssapi_krb5.c b/src/lib/gssapi/krb5/gssapi_krb5.c
+index 43930dd61..1eaf2bffb 100644
+--- a/src/lib/gssapi/krb5/gssapi_krb5.c
++++ b/src/lib/gssapi/krb5/gssapi_krb5.c
+@@ -465,28 +465,12 @@ krb5_gss_inquire_cred_by_oid(OM_uint32 *minor_status,
+     return GSS_S_UNAVAILABLE;
+ }
+ 
+-/*
+- * gss_set_sec_context_option() methods
+- * (Disabled until we have something to populate the array.)
+- */
+-#if 0
+-static struct {
+-    gss_OID_desc oid;
+-    OM_uint32 (*func)(OM_uint32 *, gss_ctx_id_t *, const gss_OID, const gss_buffer_t);
+-} krb5_gss_set_sec_context_option_ops[] = {
+-};
+-#endif
+-
+ OM_uint32 KRB5_CALLCONV
+ krb5_gss_set_sec_context_option (OM_uint32 *minor_status,
+                                  gss_ctx_id_t *context_handle,
+                                  const gss_OID desired_object,
+                                  const gss_buffer_t value)
+ {
+-#if 0
+-    size_t i;
+-#endif
+-
+     if (minor_status == NULL)
+         return GSS_S_CALL_INACCESSIBLE_WRITE;
+ 
+@@ -498,18 +482,6 @@ krb5_gss_set_sec_context_option (OM_uint32 *minor_status,
+     if (desired_object == GSS_C_NO_OID)
+         return GSS_S_CALL_INACCESSIBLE_READ;
+ 
+-#if 0
+-    for (i = 0; i < sizeof(krb5_gss_set_sec_context_option_ops)/
+-             sizeof(krb5_gss_set_sec_context_option_ops[0]); i++) {
+-        if (g_OID_prefix_equal(desired_object, &krb5_gss_set_sec_context_option_ops[i].oid)) {
+-            return (*krb5_gss_set_sec_context_option_ops[i].func)(minor_status,
+-                                                                  context_handle,
+-                                                                  desired_object,
+-                                                                  value);
+-        }
+-    }
+-#endif
+-
+     *minor_status = EINVAL;
+ 
+     return GSS_S_UNAVAILABLE;
+diff --git a/src/lib/gssapi/krb5/naming_exts.c b/src/lib/gssapi/krb5/naming_exts.c
+index 5f00efe34..41752d90b 100644
+--- a/src/lib/gssapi/krb5/naming_exts.c
++++ b/src/lib/gssapi/krb5/naming_exts.c
+@@ -664,13 +664,3 @@ cleanup:
+ 
+     return kg_map_name_error(minor_status, code);
+ }
+-
+-#if 0
+-OM_uint32
+-krb5_gss_display_name_ext(OM_uint32 *minor_status,
+-                          gss_name_t name,
+-                          gss_OID display_as_name_type,
+-                          gss_buffer_t display_name)
+-{
+-}
+-#endif
+diff --git a/src/lib/gssapi/mechglue/g_initialize.c b/src/lib/gssapi/mechglue/g_initialize.c
+index 9197666e1..0ad11c0b0 100644
+--- a/src/lib/gssapi/mechglue/g_initialize.c
++++ b/src/lib/gssapi/mechglue/g_initialize.c
+@@ -391,9 +391,6 @@ build_mechSet(void)
+ 		g_mechSet.count = count;
+ 	}
+ 
+-#if 0
+-	g_mechSetTime = fileInfo.st_mtime;
+-#endif
+ 	k5_mutex_unlock(&g_mechSetLock);
+ 	k5_mutex_unlock(&g_mechListLock);
+ 
+@@ -916,10 +913,6 @@ loadInterMech(gss_mech_info minfo)
+ 
+ 	if (krb5int_open_plugin(minfo->uLibName, &dl, &errinfo) != 0 ||
+ 	    errinfo.code != 0) {
+-#if 0
+-		(void) syslog(LOG_INFO, "libgss dlopen(%s): %s\n",
+-				aMech->uLibName, dlerror());
+-#endif
+ 		return;
+ 	}
+ 
+@@ -959,12 +952,6 @@ loadInterMech(gss_mech_info minfo)
+ 	dl = NULL;
+ 
+ cleanup:
+-#if 0
+-	if (aMech->mech == NULL) {
+-		(void) syslog(LOG_INFO, "unable to initialize mechanism"
+-				" library [%s]\n", aMech->uLibName);
+-	}
+-#endif
+ 	if (dl != NULL)
+ 		krb5int_close_plugin(dl);
+ 	k5_clear_error(&errinfo);
+@@ -1161,10 +1148,6 @@ gssint_get_mechanism(gss_const_OID oid)
+ 
+ 	if (krb5int_open_plugin(aMech->uLibName, &dl, &errinfo) != 0 ||
+ 	    errinfo.code != 0) {
+-#if 0
+-		(void) syslog(LOG_INFO, "libgss dlopen(%s): %s\n",
+-				aMech->uLibName, dlerror());
+-#endif
+ 		k5_mutex_unlock(&g_mechListLock);
+ 		return ((gss_mechanism)NULL);
+ 	}
+@@ -1180,10 +1163,6 @@ gssint_get_mechanism(gss_const_OID oid)
+ 	}
+ 	if (aMech->mech == NULL) {
+ 		(void) krb5int_close_plugin(dl);
+-#if 0
+-		(void) syslog(LOG_INFO, "unable to initialize mechanism"
+-				" library [%s]\n", aMech->uLibName);
+-#endif
+ 		k5_mutex_unlock(&g_mechListLock);
+ 		return ((gss_mechanism)NULL);
+ 	}
+@@ -1503,10 +1482,6 @@ addConfigEntry(const char *oidStr, const char *oid, const char *sharedLib,
+ 	oidBuf.length = strlen(oid);
+ 	if (generic_gss_str_to_oid(&minor, &oidBuf, &mechOid)
+ 		!= GSS_S_COMPLETE) {
+-#if 0
+-		(void) syslog(LOG_INFO, "invalid mechanism oid"
+-				" [%s] in configuration file", oid);
+-#endif
+ 		return;
+ 	}
+ 
+diff --git a/src/lib/gssapi/mechglue/g_inq_cred.c b/src/lib/gssapi/mechglue/g_inq_cred.c
+index 911196264..cbe045ab9 100644
+--- a/src/lib/gssapi/mechglue/g_inq_cred.c
++++ b/src/lib/gssapi/mechglue/g_inq_cred.c
+@@ -198,11 +198,6 @@ gss_inquire_cred_by_mech(minor_status, cred_handle, mech_type, name,
+     union_cred = (gss_union_cred_t) cred_handle;
+     mech_cred = gssint_get_mechanism_cred(union_cred, selected_mech);
+ 
+-#if 0
+-    if (mech_cred == NULL)
+-	return (GSS_S_DEFECTIVE_CREDENTIAL);
+-#endif
+-
+     public_mech = gssint_get_public_oid(selected_mech);
+     status = mech->gss_inquire_cred_by_mech(minor_status,
+ 					    mech_cred, public_mech,
+diff --git a/src/lib/gssapi/mechglue/mglueP.h b/src/lib/gssapi/mechglue/mglueP.h
+index 2b5145e07..2b00987e6 100644
+--- a/src/lib/gssapi/mechglue/mglueP.h
++++ b/src/lib/gssapi/mechglue/mglueP.h
+@@ -730,11 +730,6 @@ typedef struct gss_mech_config {
+ /********************************************************/
+ /* Internal mechglue routines */
+ 
+-#if 0
+-int gssint_mechglue_init(void);
+-void gssint_mechglue_fini(void);
+-#endif
+-
+ OM_uint32 gssint_select_mech_type(OM_uint32 *minor, gss_const_OID in_oid,
+ 				  gss_OID *selected_oid);
+ gss_OID gssint_get_public_oid(gss_const_OID internal_oid);
+diff --git a/src/lib/kadm5/clnt/client_init.c b/src/lib/kadm5/clnt/client_init.c
+index 4350a9eb0..6f10db018 100644
+--- a/src/lib/kadm5/clnt/client_init.c
++++ b/src/lib/kadm5/clnt/client_init.c
+@@ -161,7 +161,6 @@ init_any(krb5_context context, char *client_name, enum init_type init_type,
+     generic_ret r = { 0, 0 };
+ 
+     initialize_ovk_error_table();
+-/*      initialize_adb_error_table(); */
+     initialize_ovku_error_table();
+ 
+     if (! server_handle) {
+@@ -612,53 +611,8 @@ setup_gss(kadm5_server_handle_t handle, kadm5_config_params *params_in,
+     gssstat = gss_acquire_cred(&minor_stat, gss_client, 0,
+                                GSS_C_NULL_OID_SET, GSS_C_INITIATE,
+                                &handle->cred, NULL, NULL);
+-    if (gssstat != GSS_S_COMPLETE) {
+-#if 0 /* for debugging only */
+-        {
+-            OM_uint32 maj_status, min_status, message_context = 0;
+-            gss_buffer_desc status_string;
+-            do {
+-                maj_status = gss_display_status(&min_status,
+-                                                gssstat,
+-                                                GSS_C_GSS_CODE,
+-                                                GSS_C_NO_OID,
+-                                                &message_context,
+-                                                &status_string);
+-                if (maj_status == GSS_S_COMPLETE) {
+-                    fprintf(stderr, "MAJ: %.*s\n",
+-                            (int) status_string.length,
+-                            (char *)status_string.value);
+-                    gss_release_buffer(&min_status, &status_string);
+-                } else {
+-                    fprintf(stderr,
+-                            "MAJ? gss_display_status returns 0x%lx?!\n",
+-                            (unsigned long) maj_status);
+-                    message_context = 0;
+-                }
+-            } while (message_context != 0);
+-            do {
+-                maj_status = gss_display_status(&min_status,
+-                                                minor_stat,
+-                                                GSS_C_MECH_CODE,
+-                                                GSS_C_NO_OID,
+-                                                &message_context,
+-                                                &status_string);
+-                if (maj_status == GSS_S_COMPLETE) {
+-                    fprintf(stderr, "MIN: %.*s\n",
+-                            (int) status_string.length,
+-                            (char *)status_string.value);
+-                    gss_release_buffer(&min_status, &status_string);
+-                } else {
+-                    fprintf(stderr,
+-                            "MIN? gss_display_status returns 0x%lx?!\n",
+-                            (unsigned long) maj_status);
+-                    message_context = 0;
+-                }
+-            } while (message_context != 0);
+-        }
+-#endif
++    if (gssstat != GSS_S_COMPLETE)
+         goto error;
+-    }
+ 
+     /*
+      * Do actual creation of RPC auth handle.  Implements auth flavor
+diff --git a/src/lib/kadm5/srv/server_init.c b/src/lib/kadm5/srv/server_init.c
+index b3ae4ff5c..87a732292 100644
+--- a/src/lib/kadm5/srv/server_init.c
++++ b/src/lib/kadm5/srv/server_init.c
+@@ -186,7 +186,6 @@ kadm5_ret_t kadm5_init(krb5_context context, char *client_name, char *pass,
+     handle->context = context;
+ 
+     initialize_ovk_error_table();
+-/*     initialize_adb_error_table(); */
+     initialize_ovku_error_table();
+ 
+     handle->magic_number = KADM5_SERVER_HANDLE_MAGIC;
+@@ -207,16 +206,6 @@ kadm5_ret_t kadm5_init(krb5_context context, char *client_name, char *pass,
+      */
+     memset(&params_local, 0, sizeof(params_local));
+ 
+-#if 0 /* Now that we look at krb5.conf as well as kdc.conf, we can
+-         expect to see admin_server being set sometimes.  */
+-#define ILLEGAL_PARAMS (KADM5_CONFIG_ADMIN_SERVER)
+-    if (params_in && (params_in->mask & ILLEGAL_PARAMS)) {
+-        free_db_args(handle);
+-        free(handle);
+-        return KADM5_BAD_SERVER_PARAMS;
+-    }
+-#endif
+-
+     ret = kadm5_get_config_params(handle->context, 1, params_in,
+                                   &handle->params);
+     if (ret) {
+diff --git a/src/lib/kadm5/unit-test/setkey-test.c b/src/lib/kadm5/unit-test/setkey-test.c
+index 0431653bf..fa2392f81 100644
+--- a/src/lib/kadm5/unit-test/setkey-test.c
++++ b/src/lib/kadm5/unit-test/setkey-test.c
+@@ -35,15 +35,6 @@ krb5_keyblock *tests[] = {
+     test1, test2, test3, NULL
+ };
+ 
+-#if 0
+-int keyblocks_equal(krb5_keyblock *kb1, krb5_keyblock *kb2)
+-{
+-    return (kb1->enctype == kb2->enctype &&
+-            kb1->length == kb2->length &&
+-            memcmp(kb1->contents, kb2->contents, kb1->length) == 0);
+-}
+-#endif
+-
+ krb5_data tgtname = {
+     0,
+     KRB5_TGS_NAME_SIZE,
+diff --git a/src/lib/krb5/asn.1/ldap_key_seq.c b/src/lib/krb5/asn.1/ldap_key_seq.c
+index 74569d9e2..f0be2d6d9 100644
+--- a/src/lib/krb5/asn.1/ldap_key_seq.c
++++ b/src/lib/krb5/asn.1/ldap_key_seq.c
+@@ -96,9 +96,6 @@ no_salt(void *p)
+ DEFOPTIONALTYPE(key_data_salt_if_present, is_salt_present, no_salt, krbsalt);
+ DEFCTAGGEDTYPE(key_data_0, 0, key_data_salt_if_present);
+ DEFCTAGGEDTYPE(key_data_1, 1, encryptionkey);
+-#if 0 /* We don't support this field currently.  */
+-DEFCTAGGEDTYPE(key_data_2, 2, s2kparams),
+-#endif
+ static const struct atype_info *key_data_fields[] = {
+     &k5_atype_key_data_0, &k5_atype_key_data_1
+ };
+diff --git a/src/lib/krb5/ccache/ccapi/stdcc.c b/src/lib/krb5/ccache/ccapi/stdcc.c
+index 0256a0a5d..db69eebb4 100644
+--- a/src/lib/krb5/ccache/ccapi/stdcc.c
++++ b/src/lib/krb5/ccache/ccapi/stdcc.c
+@@ -1300,14 +1300,6 @@ krb5_error_code KRB5_CALLCONV  krb5_stdcc_initialize
+         return cc_err_xlate(err);
+     }
+ 
+-#if 0
+-    /*
+-     * Some implementations don't set the principal name
+-     * correctly, so we force set it to the correct value.
+-     */
+-    err = cc_set_principal(gCntrlBlock, ccapi_data->NamedCache,
+-                           CC_CRED_V5, cName);
+-#endif
+     krb5_free_unparsed_name(context, cName);
+     cache_changed();
+ 
+@@ -1432,54 +1424,6 @@ krb5_error_code KRB5_CALLCONV krb5_stdcc_next_cred
+  *
+  * - try to find a matching credential in the cache
+  */
+-#if 0
+-krb5_error_code KRB5_CALLCONV krb5_stdcc_retrieve
+-(krb5_context context,
+- krb5_ccache id,
+- krb5_flags whichfields,
+- krb5_creds *mcreds,
+- krb5_creds *creds )
+-{
+-    krb5_error_code retval;
+-    krb5_cc_cursor curs = NULL;
+-    krb5_creds *fetchcreds;
+-
+-    if ((retval = stdcc_setup(context, NULL)))
+-        return retval;
+-
+-    fetchcreds = (krb5_creds *)malloc(sizeof(krb5_creds));
+-    if (fetchcreds == NULL) return KRB5_CC_NOMEM;
+-
+-    /* we're going to use the iterators */
+-    krb5_stdcc_start_seq_get(context, id, &curs);
+-
+-    while (!krb5_stdcc_next_cred(context, id, &curs, fetchcreds)) {
+-        /*
+-         * look at each credential for a match
+-         * use this match routine since it takes the
+-         * whichfields and the API doesn't
+-         */
+-        if (stdccCredsMatch(context, fetchcreds,
+-                            mcreds, whichfields)) {
+-            /* we found it, copy and exit */
+-            *creds = *fetchcreds;
+-            krb5_stdcc_end_seq_get(context, id, &curs);
+-            return 0;
+-        }
+-        /* free copy allocated by next_cred */
+-        krb5_free_cred_contents(context, fetchcreds);
+-    }
+-
+-    /* no luck, end get and exit */
+-    krb5_stdcc_end_seq_get(context, id, &curs);
+-
+-    /* we're not using this anymore so we should get rid of it! */
+-    free(fetchcreds);
+-
+-    return KRB5_CC_NOTFOUND;
+-}
+-#else
+-
+ krb5_error_code KRB5_CALLCONV
+ krb5_stdcc_retrieve(context, id, whichfields, mcreds, creds)
+     krb5_context context;
+@@ -1492,8 +1436,6 @@ krb5_stdcc_retrieve(context, id, whichfields, mcreds, creds)
+                                        creds);
+ }
+ 
+-#endif
+-
+ /*
+  *  end seq
+  *
+diff --git a/src/lib/krb5/ccache/ccapi/winccld.h b/src/lib/krb5/ccache/ccapi/winccld.h
+index 85017abbd..df34e3346 100644
+--- a/src/lib/krb5/ccache/ccapi/winccld.h
++++ b/src/lib/krb5/ccache/ccapi/winccld.h
+@@ -85,24 +85,10 @@ DECL_FUNC_PTR(cc_create);
+ DECL_FUNC_PTR(cc_open);
+ DECL_FUNC_PTR(cc_close);
+ DECL_FUNC_PTR(cc_destroy);
+-#if 0 /* Not used */
+-#ifdef CC_API_VER2
+-DECL_FUNC_PTR(cc_seq_fetch_NCs_begin);
+-DECL_FUNC_PTR(cc_seq_fetch_NCs_next);
+-DECL_FUNC_PTR(cc_seq_fetch_NCs_end);
+-#else
+-DECL_FUNC_PTR(cc_seq_fetch_NCs);
+-#endif
+-DECL_FUNC_PTR(cc_get_NC_info);
+-DECL_FUNC_PTR(cc_free_NC_info);
+-#endif
+ DECL_FUNC_PTR(cc_get_name);
+ DECL_FUNC_PTR(cc_set_principal);
+ DECL_FUNC_PTR(cc_get_principal);
+ DECL_FUNC_PTR(cc_get_cred_version);
+-#if 0 /* Not used */
+-DECL_FUNC_PTR(cc_lock_request);
+-#endif
+ DECL_FUNC_PTR(cc_store);
+ DECL_FUNC_PTR(cc_remove_cred);
+ #ifdef CC_API_VER2
+@@ -127,18 +113,10 @@ FUNC_INFO krbcc_fi[] = {
+     MAKE_FUNC_INFO(cc_open),
+     MAKE_FUNC_INFO(cc_close),
+     MAKE_FUNC_INFO(cc_destroy),
+-#if 0 /* Not used */
+-    MAKE_FUNC_INFO(cc_seq_fetch_NCs),
+-    MAKE_FUNC_INFO(cc_get_NC_info),
+-    MAKE_FUNC_INFO(cc_free_NC_info),
+-#endif
+     MAKE_FUNC_INFO(cc_get_name),
+     MAKE_FUNC_INFO(cc_set_principal),
+     MAKE_FUNC_INFO(cc_get_principal),
+     MAKE_FUNC_INFO(cc_get_cred_version),
+-#if 0 /* Not used */
+-    MAKE_FUNC_INFO(cc_lock_request),
+-#endif
+     MAKE_FUNC_INFO(cc_store),
+     MAKE_FUNC_INFO(cc_remove_cred),
+ #ifdef CC_API_VER2
+@@ -166,24 +144,10 @@ FUNC_INFO krbcc_fi[] = {
+ #define cc_open pcc_open
+ #define cc_close pcc_close
+ #define cc_destroy pcc_destroy
+-#if 0 /* Not used */
+-#ifdef CC_API_VER2
+-#define cc_seq_fetch_NCs_begin pcc_seq_fetch_NCs_begin
+-#define cc_seq_fetch_NCs_next pcc_seq_fetch_NCs_next
+-#define cc_seq_fetch_NCs_end pcc_seq_fetch_NCs_end
+-#else
+-#define cc_seq_fetch_NCs pcc_seq_fetch_NCs
+-#endif
+-#define cc_get_NC_info pcc_get_NC_info
+-#define cc_free_NC_info pcc_free_NC_info
+-#endif /* End of Not used */
+ #define cc_get_name pcc_get_name
+ #define cc_set_principal pcc_set_principal
+ #define cc_get_principal pcc_get_principal
+ #define cc_get_cred_version pcc_get_cred_version
+-#if 0 /* Not used */
+-#define cc_lock_request pcc_lock_request
+-#endif
+ #define cc_store pcc_store
+ #define cc_remove_cred pcc_remove_cred
+ #ifdef CC_API_VER2
+diff --git a/src/lib/krb5/keytab/t_keytab.c b/src/lib/krb5/keytab/t_keytab.c
+index 80a94eafe..c845596d6 100644
+--- a/src/lib/krb5/keytab/t_keytab.c
++++ b/src/lib/krb5/keytab/t_keytab.c
+@@ -441,16 +441,3 @@ main(void)
+     return 0;
+ 
+ }
+-
+-
+-#if 0
+-/* remove and add are functions, so that they can return NOWRITE
+-   if not a writable keytab */
+-krb5_error_code KRB5_CALLCONV krb5_kt_remove_entry
+-(krb5_context,
+- krb5_keytab,
+- krb5_keytab_entry * );
+-
+-
+-
+-#endif
+diff --git a/src/lib/krb5/krb/gc_via_tkt.c b/src/lib/krb5/krb/gc_via_tkt.c
+index 5b9bb9573..e7a3b01f8 100644
+--- a/src/lib/krb5/krb/gc_via_tkt.c
++++ b/src/lib/krb5/krb/gc_via_tkt.c
+@@ -131,17 +131,6 @@ check_reply_server(krb5_context context, krb5_flags kdcoptions,
+         /* Canonicalization not requested, and not a TGS referral. */
+         return KRB5_KDCREP_MODIFIED;
+     }
+-#if 0
+-    /*
+-     * Is this check needed?  find_nxt_kdc() in gc_frm_kdc.c already
+-     * effectively checks this.
+-     */
+-    if (krb5_realm_compare(context, in_cred->client, in_cred->server) &&
+-        data_eq(*in_cred->server->data[1], *in_cred->client->realm)) {
+-        /* Attempted to rewrite local TGS. */
+-        return KRB5_KDCREP_MODIFIED;
+-    }
+-#endif
+     return 0;
+ }
+ 
+diff --git a/src/lib/krb5/krb/init_ctx.c b/src/lib/krb5/krb/init_ctx.c
+index 4246c5dd2..c90b2af87 100644
+--- a/src/lib/krb5/krb/init_ctx.c
++++ b/src/lib/krb5/krb/init_ctx.c
+@@ -232,13 +232,6 @@ krb5_init_context_profile(profile_t profile, krb5_flags flags,
+     get_integer(ctx, KRB5_CONF_CLOCKSKEW, DEFAULT_CLOCKSKEW, &tmp);
+     ctx->clockskew = tmp;
+ 
+-#if 0
+-    /* Default ticket lifetime is currently not supported */
+-    profile_get_integer(ctx->profile, KRB5_CONF_LIBDEFAULTS, "tkt_lifetime",
+-                        0, 10 * 60 * 60, &tmp);
+-    ctx->tkt_lifetime = tmp;
+-#endif
+-
+     /* DCE 1.1 and below only support CKSUMTYPE_RSA_MD4 (2)  */
+     /* DCE add kdc_req_checksum_type = 2 to krb5.conf */
+     get_integer(ctx, KRB5_CONF_KDC_REQ_CHECKSUM_TYPE, CKSUMTYPE_RSA_MD5,
+diff --git a/src/lib/krb5/krb/rd_req_dec.c b/src/lib/krb5/krb/rd_req_dec.c
+index 6defbdbf0..4cd429a11 100644
+--- a/src/lib/krb5/krb/rd_req_dec.c
++++ b/src/lib/krb5/krb/rd_req_dec.c
+@@ -441,30 +441,6 @@ decrypt_ticket(krb5_context context, const krb5_ap_req *req,
+ #endif /* LEAN_CLIENT */
+ }
+ 
+-#if 0
+-#include <syslog.h>
+-static void
+-debug_log_authz_data(const char *which, krb5_authdata **a)
+-{
+-    if (a) {
+-        syslog(LOG_ERR|LOG_DAEMON, "%s authz data:", which);
+-        while (*a) {
+-            syslog(LOG_ERR|LOG_DAEMON, "  ad_type:%d length:%d '%.*s'",
+-                   (*a)->ad_type, (*a)->length, (*a)->length,
+-                   (char *) (*a)->contents);
+-            a++;
+-        }
+-        syslog(LOG_ERR|LOG_DAEMON, "  [end]");
+-    } else
+-        syslog(LOG_ERR|LOG_DAEMON, "no %s authz data", which);
+-}
+-#else
+-static void
+-debug_log_authz_data(const char *which, krb5_authdata **a)
+-{
+-}
+-#endif
+-
+ static krb5_error_code
+ rd_req_decoded_opt(krb5_context context, krb5_auth_context *auth_context,
+                    const krb5_ap_req *req, krb5_const_principal server,
+@@ -759,8 +735,6 @@ rd_req_decoded_opt(krb5_context context, krb5_auth_context *auth_context,
+                                     &((*auth_context)->key))))
+         goto cleanup;
+ 
+-    debug_log_authz_data("ticket", req->ticket->enc_part2->authorization_data);
+-
+     /*
+      * If not AP_OPTS_MUTUAL_REQUIRED then and sequence numbers are used
+      * then the default sequence number is the one's complement of the
+@@ -855,10 +829,9 @@ decrypt_authenticator(krb5_context context, const krb5_ap_req *request,
+         free(scratch.data);}
+ 
+     /*  now decode the decrypted stuff */
+-    if (!(retval = decode_krb5_authenticator(&scratch, &local_auth))) {
++    if (!(retval = decode_krb5_authenticator(&scratch, &local_auth)))
+         *authpp = local_auth;
+-        debug_log_authz_data("authenticator", local_auth->authorization_data);
+-    }
++
+     clean_scratch();
+     return retval;
+ }
+diff --git a/src/lib/krb5/krb/t_ser.c b/src/lib/krb5/krb/t_ser.c
+index 9cdf5e641..1d6cceaa2 100644
+--- a/src/lib/krb5/krb/t_ser.c
++++ b/src/lib/krb5/krb/t_ser.c
+@@ -151,10 +151,6 @@ ser_data(int verbose, char *msg, krb5_pointer ctx, krb5_magic dtype)
+                     krb5_encrypt_block *eblock;
+ 
+                     eblock = (krb5_encrypt_block *) nctx;
+-#if 0
+-                    if (eblock->priv && eblock->priv_size)
+-                        free(eblock->priv);
+-#endif
+                     if (eblock->key)
+                         krb5_free_keyblock(ser_ctx, eblock->key);
+                     free(eblock);
+@@ -450,60 +446,6 @@ ser_rcache_test(krb5_context kcontext, int verbose)
+     return(kret);
+ }
+ 
+-#if 0
+-/*
+- * Serialize krb5_encrypt_block.
+- */
+-static krb5_error_code
+-ser_eblock_test(kcontext, verbose)
+-    krb5_context        kcontext;
+-    int                 verbose;
+-{
+-    krb5_error_code     kret;
+-    krb5_encrypt_block  eblock;
+-    krb5_keyblock       ukeyblock;
+-    krb5_octet          keydata[8];
+-
+-    memset(&eblock, 0, sizeof(krb5_encrypt_block));
+-    eblock.magic = KV5M_ENCRYPT_BLOCK;
+-    krb5_use_enctype(kcontext, &eblock, DEFAULT_KDC_ENCTYPE);
+-    if (!(kret = ser_data(verbose, "> NULL eblock",
+-                          (krb5_pointer) &eblock, KV5M_ENCRYPT_BLOCK))) {
+-#if 0
+-        eblock.priv = (krb5_pointer) stuff;
+-        eblock.priv_size = 8;
+-#endif
+-        if (!(kret = ser_data(verbose, "> eblock with private data",
+-                              (krb5_pointer) &eblock,
+-                              KV5M_ENCRYPT_BLOCK))) {
+-            memset(&ukeyblock, 0, sizeof(ukeyblock));
+-            memset(keydata, 0, sizeof(keydata));
+-            ukeyblock.enctype = ENCTYPE_DES_CBC_MD5;
+-            ukeyblock.length = sizeof(keydata);
+-            ukeyblock.contents = keydata;
+-            keydata[0] = 0xde;
+-            keydata[1] = 0xad;
+-            keydata[2] = 0xbe;
+-            keydata[3] = 0xef;
+-            keydata[4] = 0xfe;
+-            keydata[5] = 0xed;
+-            keydata[6] = 0xf0;
+-            keydata[7] = 0xd;
+-            eblock.key = &ukeyblock;
+-            if (!(kret = ser_data(verbose, "> eblock with private key",
+-                                  (krb5_pointer) &eblock,
+-                                  KV5M_ENCRYPT_BLOCK))) {
+-                if (verbose)
+-                    printf("* eblock test succeeded\n");
+-            }
+-        }
+-    }
+-    if (kret)
+-        printf("* eblock test failed\n");
+-    return(kret);
+-}
+-#endif
+-
+ /*
+  * Serialize krb5_principal
+  */
+@@ -584,7 +526,7 @@ main(int argc, char **argv)
+     do_ptest = 1;
+     do_rtest = 1;
+     do_stest = 1;
+-    while ((option = getopt(argc, argv, "acekprsxvACEKPRSX")) != -1) {
++    while ((option = getopt(argc, argv, "acekprsxvACKPRSX")) != -1) {
+         switch (option) {
+         case 'a':
+             do_atest = 0;
+@@ -619,11 +561,6 @@ main(int argc, char **argv)
+         case 'C':
+             do_ctest = 1;
+             break;
+-#if 0
+-        case 'E':
+-            do_etest = 1;
+-            break;
+-#endif
+         case 'K':
+             do_ktest = 1;
+             break;
+@@ -641,7 +578,7 @@ main(int argc, char **argv)
+             break;
+         default:
+             fprintf(stderr,
+-                    "%s: usage is %s [-acekprsxvACEKPRSX]\n",
++                    "%s: usage is %s [-acekprsxvACKPRSX]\n",
+                     argv[0], argv[0]);
+             exit(1);
+             break;
+@@ -682,14 +619,6 @@ main(int argc, char **argv)
+         if (kret)
+             goto fail;
+     }
+-#if 0 /* code to be tested is currently disabled */
+-    if (do_etest) {
+-        ch_err = 'e';
+-        kret = ser_eblock_test(kcontext, verbose);
+-        if (kret)
+-            goto fail;
+-    }
+-#endif
+     if (do_ptest) {
+         ch_err = 'p';
+         kret = ser_princ_test(kcontext, verbose);
+diff --git a/src/lib/krb5/krb/unparse.c b/src/lib/krb5/krb/unparse.c
+index 5bb64d00a..d94aa3cfa 100644
+--- a/src/lib/krb5/krb/unparse.c
++++ b/src/lib/krb5/krb/unparse.c
+@@ -122,13 +122,6 @@ copy_component_quoting(char *dest, const krb5_data *src, int flags)
+             *q++ = '\\';
+             *q++ = 'b';
+             break;
+-#if 0
+-            /* Heimdal escapes spaces in principal names upon unparsing */
+-        case ' ':
+-            *q++ = '\\';
+-            *q++ = ' ';
+-            break;
+-#endif
+         case '\0':
+             *q++ = '\\';
+             *q++ = '0';
+diff --git a/src/lib/krb5/os/localaddr.c b/src/lib/krb5/os/localaddr.c
+index 58443f6e3..92d765f4b 100644
+--- a/src/lib/krb5/os/localaddr.c
++++ b/src/lib/krb5/os/localaddr.c
+@@ -392,20 +392,6 @@ get_linux_ipv6_addrs ()
+                 a6.s6_addr[i] = addrbyte[i];
+             if (scope != 0)
+                 continue;
+-#if 0 /* These symbol names are as used by ifconfig, but none of the
+-         system header files export them.  Dig up the kernel versions
+-         someday and see if they're exported.  */
+-            switch (scope) {
+-            case 0:
+-            default:
+-                break;
+-            case IPV6_ADDR_LINKLOCAL:
+-            case IPV6_ADDR_SITELOCAL:
+-            case IPV6_ADDR_COMPATv4:
+-            case IPV6_ADDR_LOOPBACK:
+-                continue;
+-            }
+-#endif
+             nw = calloc (1, sizeof (struct linux_ipv6_addr_list));
+             if (nw == 0)
+                 continue;
+@@ -1331,14 +1317,6 @@ krb5_os_localaddr(krb5_context context, krb5_address ***addr)
+     return get_localaddrs(context, addr, 1);
+ }
+ 
+-#if 0 /* not actually used anywhere currently */
+-krb5_error_code
+-krb5int_local_addresses(krb5_context context, krb5_address ***addr)
+-{
+-    return get_localaddrs(context, addr, 0);
+-}
+-#endif
+-
+ static krb5_error_code
+ get_localaddrs (krb5_context context, krb5_address ***addr, int use_profile)
+ {
+diff --git a/src/lib/krb5/rcache/rc_io.c b/src/lib/krb5/rcache/rc_io.c
+index b9859fe9f..35fa14a1f 100644
+--- a/src/lib/krb5/rcache/rc_io.c
++++ b/src/lib/krb5/rcache/rc_io.c
+@@ -117,10 +117,6 @@ krb5_rc_io_mkstemp(krb5_context context, krb5_rc_iostuff *d, char *dir)
+     return 0;
+ }
+ 
+-#if 0
+-static krb5_error_code rc_map_errno (int) __attribute__((cold));
+-#endif
+-
+ static krb5_error_code
+ rc_map_errno (krb5_context context, int e, const char *fn,
+               const char *operation)
+diff --git a/src/lib/rpc/auth_gssapi.c b/src/lib/rpc/auth_gssapi.c
+index ace0be925..568ec6d87 100644
+--- a/src/lib/rpc/auth_gssapi.c
++++ b/src/lib/rpc/auth_gssapi.c
+@@ -744,14 +744,6 @@ skip_call:
+      }
+ 
+      free(AUTH_PRIVATE(auth)->client_handle.value);
+-
+-#if 0
+-     PRINTF(("gssapi_destroy: calling GSSAPI_EXIT\n"));
+-     AUTH_PRIVATE(auth)->established = FALSE;
+-     callstat = clnt_call(AUTH_PRIVATE(auth)->clnt, AUTH_GSSAPI_EXIT,
+-			  xdr_void, NULL, xdr_void, NULL, timeout);
+-#endif
+-
+      free(auth->ah_private);
+      free(auth);
+      PRINTF(("gssapi_destroy: done\n"));
+diff --git a/src/lib/rpc/svc_auth.c b/src/lib/rpc/svc_auth.c
+index 5fedef7d7..e0f80af0b 100644
+--- a/src/lib/rpc/svc_auth.c
++++ b/src/lib/rpc/svc_auth.c
+@@ -59,9 +59,6 @@ static struct svcauthsw_type {
+ } svcauthsw[] = {
+      {AUTH_GSSAPI, gssrpc__svcauth_gssapi},	/* AUTH_GSSAPI */
+      {AUTH_NONE, gssrpc__svcauth_none},		/* AUTH_NONE */
+-#if 0
+-     {AUTH_GSSAPI_COMPAT, gssrpc__svcauth_gssapi}, /* AUTH_GSSAPI_COMPAT */
+-#endif
+      {AUTH_UNIX, gssrpc__svcauth_unix},		/* AUTH_UNIX */
+      {AUTH_SHORT, gssrpc__svcauth_short},	/* AUTH_SHORT */
+      {RPCSEC_GSS, gssrpc__svcauth_gss}		/* RPCSEC_GSS */
+diff --git a/src/lib/rpc/svc_auth_gssapi.c b/src/lib/rpc/svc_auth_gssapi.c
+index f3b3e35b8..384bdc336 100644
+--- a/src/lib/rpc/svc_auth_gssapi.c
++++ b/src/lib/rpc/svc_auth_gssapi.c
+@@ -869,10 +869,6 @@ done:
+      L_PRINTF(2, ("destroy_client: client %d destroyed\n", client_data->key));
+ 
+      free(client_data);
+-
+-#if 0 /*ifdef PURIFY*/
+-     purify_watch_n(client_data, sizeof(*client_data), "rw");
+-#endif
+ }
+ 
+ static void dump_db(char *msg)
+diff --git a/src/lib/win_glue.c b/src/lib/win_glue.c
+index 3d6dd7206..e149a1226 100644
+--- a/src/lib/win_glue.c
++++ b/src/lib/win_glue.c
+@@ -111,10 +111,6 @@ void GetCallingAppVerInfo( char *AppTitle, char *AppVer, char *AppIni,
+ 		 * hey , I bet we don't have a version resource, let's
+ 		 * punt
+ 		 */
+-#if 0
+-		/* let's see what we have? (1813 means no resource) */
+-		size = GetLastError(); 		/*  WIN32 only */
+-#endif
+ 		*VSflag = FALSE;
+ 		return;
+ 	}
+@@ -291,11 +287,6 @@ krb5_error_code krb5_vercheck()
+ 		return retval;
+ #endif
+ #ifdef VERSERV
+-#if 0
+-	/* Check library ? */
+-	if (CallVersionServer(APP_TITLE, APP_VER, APP_INI, NULL))
+-		return KRB5_LIB_EXPIRED;
+-#endif
+ 	{
+ #ifdef APP_TITLE
+ 		if (CallVersionServer(APP_TITLE, APP_VER, APP_INI, NULL))
+diff --git a/src/plugins/kdb/db2/lockout.c b/src/plugins/kdb/db2/lockout.c
+index 3a4f41821..30fb554db 100644
+--- a/src/plugins/kdb/db2/lockout.c
++++ b/src/plugins/kdb/db2/lockout.c
+@@ -157,10 +157,6 @@ krb5_db2_lockout_audit(krb5_context context,
+     case KRB5KDC_ERR_PREAUTH_FAILED:
+     case KRB5KRB_AP_ERR_BAD_INTEGRITY:
+         break;
+-#if 0
+-    case KRB5KDC_ERR_CLIENT_REVOKED:
+-        break;
+-#endif
+     default:
+         return 0;
+     }
+diff --git a/src/plugins/kdb/ldap/libkdb_ldap/ldap_realm.c b/src/plugins/kdb/ldap/libkdb_ldap/ldap_realm.c
+index 28dffe0c2..f6d00be9f 100644
+--- a/src/plugins/kdb/ldap/libkdb_ldap/ldap_realm.c
++++ b/src/plugins/kdb/ldap/libkdb_ldap/ldap_realm.c
+@@ -777,9 +777,6 @@ krb5_ldap_read_realm_params(krb5_context context, char *lrealm,
+     ent = ldap_first_entry (ld, result);
+     if (ent == NULL) {
+         ldap_get_option (ld, LDAP_OPT_ERROR_NUMBER, (void *) &st);
+-#if 0
+-        st = translate_ldap_error(st, OP_SEARCH);
+-#endif
+         goto cleanup;
+     }
+ 
+diff --git a/src/plugins/preauth/pkinit/pkinit_clnt.c b/src/plugins/preauth/pkinit/pkinit_clnt.c
+index 77e9e5308..238101762 100644
+--- a/src/plugins/preauth/pkinit/pkinit_clnt.c
++++ b/src/plugins/preauth/pkinit/pkinit_clnt.c
+@@ -507,24 +507,6 @@ verify_kdc_san(krb5_context context,
+         for (hostptr = certhosts; *hostptr != NULL; hostptr++)
+             TRACE_PKINIT_CLIENT_SAN_KDCCERT_DNSNAME(context, *hostptr);
+     }
+-#if 0
+-    retval = call_san_checking_plugins(context, plgctx, reqctx, idctx,
+-                                       princs, hosts, &plugin_decision,
+-                                       need_eku_checking);
+-    pkiDebug("%s: call_san_checking_plugins() returned retval %d\n",
+-             __FUNCTION__);
+-    if (retval) {
+-        retval = KRB5KDC_ERR_KDC_NAME_MISMATCH;
+-        goto out;
+-    }
+-    pkiDebug("%s: call_san_checking_plugins() returned decision %d and "
+-             "need_eku_checking %d\n",
+-             __FUNCTION__, plugin_decision, *need_eku_checking);
+-    if (plugin_decision != NO_DECISION) {
+-        retval = plugin_decision;
+-        goto out;
+-    }
+-#endif
+ 
+     pkiDebug("%s: Checking pkinit sans\n", __FUNCTION__);
+     for (i = 0; princs != NULL && princs[i] != NULL; i++) {
+diff --git a/src/plugins/preauth/pkinit/pkinit_matching.c b/src/plugins/preauth/pkinit/pkinit_matching.c
+index c2a4c084d..afcce3f8b 100644
+--- a/src/plugins/preauth/pkinit/pkinit_matching.c
++++ b/src/plugins/preauth/pkinit/pkinit_matching.c
+@@ -572,17 +572,6 @@ check_all_certs(krb5_context context,
+      */
+     for (i = 0, md = matchdata[i]; md != NULL; md = matchdata[++i]) {
+         pkiDebug("%s: subject: '%s'\n", __FUNCTION__, md->subject_dn);
+-#if 0
+-        pkiDebug("%s: issuer:  '%s'\n", __FUNCTION__, md->subject_dn);
+-        for (j = 0; md->sans != NULL && md->sans[j] != NULL; j++) {
+-            char *san_string;
+-            krb5_unparse_name(context, md->sans[j], &san_string);
+-            pkiDebug("%s: PKINIT san: '%s'\n", __FUNCTION__, san_string);
+-            krb5_free_unparsed_name(context, san_string);
+-        }
+-        for (j = 0; md->upns != NULL && md->upns[j] != NULL; j++)
+-            pkiDebug("%s: UPN san: '%s'\n", __FUNCTION__, md->upns[j]);
+-#endif
+         certs_checked++;
+         for (rc = rs->crs; rc != NULL; rc = rc->next) {
+             comp_match = component_match(context, rc, md);
+diff --git a/src/plugins/preauth/pkinit/pkinit_srv.c b/src/plugins/preauth/pkinit/pkinit_srv.c
+index 76ad5bf19..27e6ef4d2 100644
+--- a/src/plugins/preauth/pkinit/pkinit_srv.c
++++ b/src/plugins/preauth/pkinit/pkinit_srv.c
+@@ -204,24 +204,6 @@ verify_client_san(krb5_context context,
+         goto out;
+     }
+ 
+-    /* XXX Verify this is consistent with client side XXX */
+-#if 0
+-    retval = call_san_checking_plugins(context, plgctx, reqctx, princs,
+-                                       upns, NULL, &plugin_decision, &ignore);
+-    pkiDebug("%s: call_san_checking_plugins() returned retval %d\n",
+-             __FUNCTION__);
+-    if (retval) {
+-        retval = KRB5KDC_ERR_CLIENT_NAME_MISMATCH;
+-        goto cleanup;
+-    }
+-    pkiDebug("%s: call_san_checking_plugins() returned decision %d\n",
+-             __FUNCTION__, plugin_decision);
+-    if (plugin_decision != NO_DECISION) {
+-        retval = plugin_decision;
+-        goto out;
+-    }
+-#endif
+-
+ #ifdef DEBUG_SAN_INFO
+     krb5_unparse_name(context, client, &client_string);
+ #endif
+diff --git a/src/tests/asn.1/krb5_decode_leak.c b/src/tests/asn.1/krb5_decode_leak.c
+index 22601c7bf..77fd3ee40 100644
+--- a/src/tests/asn.1/krb5_decode_leak.c
++++ b/src/tests/asn.1/krb5_decode_leak.c
+@@ -633,18 +633,6 @@ main(int argc, char **argv)
+                   krb5_free_ad_kdcissued);
+         ktest_empty_ad_kdcissued(&kdci);
+     }
+-#if 0
+-    /****************************************************************/
+-    /* encode_krb5_ad_signedpath_data */
+-    {
+-        krb5_ad_signedpath_data spd, *tmp;
+-        ktest_make_sample_ad_signedpath_data(&spd);
+-        leak_test(spd, encode_krb5_ad_signedpath_data,
+-                  decode_krb5_ad_signedpath_data,
+-                  NULL);
+-        ktest_empty_ad_signedpath_data(&spd);
+-    }
+-#endif
+     /****************************************************************/
+     /* encode_krb5_ad_signedpath */
+     {
+diff --git a/src/tests/dejagnu/config/default.exp b/src/tests/dejagnu/config/default.exp
+index 2d1686c56..daf3c7d3b 100644
+--- a/src/tests/dejagnu/config/default.exp
++++ b/src/tests/dejagnu/config/default.exp
+@@ -32,26 +32,6 @@ set tgt_support_desmd5 0
+ # request a des-cbc-md4 session key.  Since only des-cbc-crc is in the
+ # KDC's permitted_enctypes list, the TGT will be unusable.
+ 
+-# KLUDGE for tracking down leaking ptys
+-if 0 {
+-    rename spawn oldspawn
+-    rename wait oldwait
+-    proc spawn { args } {
+-	upvar 1 spawn_id spawn_id
+-	verbose "spawn: args=$args"
+-	set pid [eval oldspawn $args]
+-	verbose "spawn: pid=$pid spawn_id=$spawn_id"
+-	return $pid
+-    }
+-    proc wait { args } {
+-	upvar 1 spawn_id spawn_id
+-	verbose "wait: args=$args"
+-	set ret [eval oldwait $args]
+-	verbose "wait: $ret"
+-	return $ret
+-    }
+-}
+-
+ if { [string length $VALGRIND] } {
+     rename spawn valgrind_aux_spawn
+     proc spawn { args } {
+diff --git a/src/tests/shlib/t_loader.c b/src/tests/shlib/t_loader.c
+index 869be800a..29481a7be 100644
+--- a/src/tests/shlib/t_loader.c
++++ b/src/tests/shlib/t_loader.c
+@@ -186,18 +186,6 @@ int main()
+ 
+     (void) setvbuf(stdout, 0, _IONBF, 0);
+ 
+-#if 0
+-    /* Simplest test: Load, then unload out of order.  */
+-    celib = do_open("com_err", "3.0", 0);
+-    k5lib = do_open("krb5", "3.2", 0);
+-    gsslib = do_open("gssapi_krb5", "2.2", 0);
+-    celib2 = do_open("com_err", "3.0", 0);
+-    do_close(celib);
+-    do_close(k5lib);
+-    do_close(celib2);
+-    do_close(gsslib);
+-#endif
+-
+     celib = do_open("com_err", "3.0", 0);
+     k5lib = do_open("krb5", "3.2", 0);
+     gsslib = do_open("gssapi_krb5", "2.2", 0);
+diff --git a/src/tests/threads/t_rcache.c b/src/tests/threads/t_rcache.c
+index d6187f061..9d9b1acd3 100644
+--- a/src/tests/threads/t_rcache.c
++++ b/src/tests/threads/t_rcache.c
+@@ -106,7 +106,6 @@ static void try_one (struct tinfo *t)
+ static void *run_a_loop (void *x)
+ {
+     struct tinfo t = { 0 };
+-/*    int chr = "ABCDEFGHIJKLMNOPQRSTUVWXYZ_"[(*(int*)x) % 27]; */
+ 
+     t.now = time(0);
+     t.idx = *(int *)x;
+@@ -117,12 +116,7 @@ static void *run_a_loop (void *x)
+         t.now = time(0);
+         try_one(&t);
+         t.total++;
+-#if 0
+-        printf("%c", chr);
+-        fflush(stdout);
+-#endif
+     }
+-/*    printf("thread %u total %u\n", (unsigned) ((int *)x-ip), t.total);*/
+     *(int*)x = t.total;
+     return 0;
+ }
+diff --git a/src/util/profile/prof_file.c b/src/util/profile/prof_file.c
+index 0f5462aea..64b32dbf1 100644
+--- a/src/util/profile/prof_file.c
++++ b/src/util/profile/prof_file.c
+@@ -79,39 +79,6 @@ void profile_library_finalizer(void)
+ 
+ static void profile_free_file_data(prf_data_t);
+ 
+-#if 0
+-
+-#define scan_shared_trees_locked()                              \
+-    {                                                           \
+-        prf_data_t d;                                           \
+-        k5_mutex_assert_locked(&g_shared_trees_mutex);          \
+-        for (d = g_shared_trees; d; d = d->next) {              \
+-            assert(d->magic == PROF_MAGIC_FILE_DATA);           \
+-            assert((d->flags & PROFILE_FILE_SHARED) != 0);      \
+-            assert(d->filespec[0] != 0);                        \
+-            assert(d->fslen <= 1000); /* XXX */                 \
+-            assert(d->filespec[d->fslen] == 0);                 \
+-            assert(d->fslen = strlen(d->filespec));             \
+-            assert(d->root != NULL);                            \
+-        }                                                       \
+-    }
+-
+-#define scan_shared_trees_unlocked()                    \
+-    {                                                   \
+-        int r;                                          \
+-        r = k5_mutex_lock(&g_shared_trees_mutex);       \
+-        assert (r == 0);                                \
+-        scan_shared_trees_locked();                     \
+-        k5_mutex_unlock(&g_shared_trees_mutex);         \
+-    }
+-
+-#else
+-
+-#define scan_shared_trees_locked()      { ; }
+-#define scan_shared_trees_unlocked()    { ; }
+-
+-#endif
+-
+ static int rw_access(const_profile_filespec_t filespec)
+ {
+ #ifdef HAVE_ACCESS
+@@ -209,8 +176,6 @@ errcode_t profile_open_file(const_profile_filespec_t filespec,
+     if (retval)
+         return retval;
+ 
+-    scan_shared_trees_unlocked();
+-
+     prf = malloc(sizeof(struct _prf_file_t));
+     if (!prf)
+         return ENOMEM;
+@@ -244,7 +209,6 @@ errcode_t profile_open_file(const_profile_filespec_t filespec,
+     }
+ 
+     k5_mutex_lock(&g_shared_trees_mutex);
+-    scan_shared_trees_locked();
+     for (data = g_shared_trees; data; data = data->next) {
+         if (!strcmp(data->filespec, expanded_filename)
+             /* Check that current uid has read access.  */
+@@ -264,7 +228,6 @@ errcode_t profile_open_file(const_profile_filespec_t filespec,
+         }
+         prf->data = data;
+         *ret_prof = prf;
+-        scan_shared_trees_unlocked();
+         return 0;
+     }
+     k5_mutex_unlock(&g_shared_trees_mutex);
+@@ -291,11 +254,9 @@ errcode_t profile_open_file(const_profile_filespec_t filespec,
+     }
+ 
+     k5_mutex_lock(&g_shared_trees_mutex);
+-    scan_shared_trees_locked();
+     data->flags |= PROFILE_FILE_SHARED;
+     data->next = g_shared_trees;
+     g_shared_trees = data;
+-    scan_shared_trees_locked();
+     k5_mutex_unlock(&g_shared_trees_mutex);
+ 
+     *ret_prof = prf;
+@@ -537,11 +498,9 @@ void profile_dereference_data(prf_data_t data)
+ }
+ void profile_dereference_data_locked(prf_data_t data)
+ {
+-    scan_shared_trees_locked();
+     data->refcount--;
+     if (data->refcount == 0)
+         profile_free_file_data(data);
+-    scan_shared_trees_locked();
+ }
+ 
+ void profile_lock_global()
+@@ -562,7 +521,6 @@ void profile_free_file(prf_file_t prf)
+ /* Call with mutex locked!  */
+ static void profile_free_file_data(prf_data_t data)
+ {
+-    scan_shared_trees_locked();
+     if (data->flags & PROFILE_FILE_SHARED) {
+         /* Remove from linked list.  */
+         if (g_shared_trees == data)
+@@ -586,7 +544,6 @@ static void profile_free_file_data(prf_data_t data)
+     data->magic = 0;
+     k5_mutex_destroy(&data->lock);
+     free(data);
+-    scan_shared_trees_locked();
+ }
+ 
+ errcode_t profile_close_file(prf_file_t prf)
+diff --git a/src/util/support/fake-addrinfo.c b/src/util/support/fake-addrinfo.c
+index 3ee162e0d..0fb35cf15 100644
+--- a/src/util/support/fake-addrinfo.c
++++ b/src/util/support/fake-addrinfo.c
+@@ -888,16 +888,10 @@ fake_getaddrinfo (const char *name, const char *serv,
+        If it's not set, don't accept such names.  */
+     if (flags & AI_NUMERICHOST) {
+         struct in_addr addr4;
+-#if 0
+-        ret = inet_aton (name, &addr4);
+-        if (ret)
+-            return EAI_NONAME;
+-#else
+         addr4.s_addr = inet_addr (name);
+         if (addr4.s_addr == 0xffffffff || addr4.s_addr == -1)
+             /* 255.255.255.255 or parse error, both bad */
+             return EAI_NONAME;
+-#endif
+         ret = fai_add_entry (&res, &addr4, port, &template);
+     } else {
+         ret = fai_add_hosts_by_name (name, &template, port, flags,
+diff --git a/src/util/support/utf8.c b/src/util/support/utf8.c
+index 34e2b6adb..ea8818116 100644
+--- a/src/util/support/utf8.c
++++ b/src/util/support/utf8.c
+@@ -404,28 +404,6 @@ int krb5int_utf8_isalnum(const char * p)
+ 
+     return KRB5_ALNUM(c);
+ }
+-
+-#if 0
+-int krb5int_utf8_islower(const char * p)
+-{
+-    unsigned c = * (const unsigned char *) p;
+-
+-    if (!KRB5_ASCII(c))
+-        return 0;
+-
+-    return KRB5_LOWER(c);
+-}
+-
+-int krb5int_utf8_isupper(const char * p)
+-{
+-    unsigned c = * (const unsigned char *) p;
+-
+-    if (!KRB5_ASCII(c))
+-        return 0;
+-
+-    return KRB5_UPPER(c);
+-}
+-#endif
+ #endif
+ 
+ 
+diff --git a/src/windows/include/loadfuncs-krb5.h b/src/windows/include/loadfuncs-krb5.h
+index a90678878..39a3504f6 100644
+--- a/src/windows/include/loadfuncs-krb5.h
++++ b/src/windows/include/loadfuncs-krb5.h
+@@ -106,29 +106,6 @@ TYPEDEF_FUNC(
+     krb5_free_ap_rep,
+     (krb5_context, krb5_ap_rep * )
+     );
+-
+-/* Removed around the time of krb5_rc_* change... */
+-#if 0
+-TYPEDEF_FUNC(
+-    void,
+-    KRB5_CALLCONV,
+-    krb5_free_safe,
+-    (krb5_context, krb5_safe * )
+-    );
+-TYPEDEF_FUNC(
+-    void,
+-    KRB5_CALLCONV,
+-    krb5_free_priv,
+-    (krb5_context, krb5_priv * )
+-    );
+-TYPEDEF_FUNC(
+-    void,
+-    KRB5_CALLCONV,
+-    krb5_free_priv_enc_part,
+-    (krb5_context, krb5_priv_enc_part * )
+-    );
+-#endif
+-
+ TYPEDEF_FUNC(
+     void,
+     KRB5_CALLCONV,
+diff --git a/src/windows/kfwlogon/kfwlogon.c b/src/windows/kfwlogon/kfwlogon.c
+index d851c4685..c388fffcd 100644
+--- a/src/windows/kfwlogon/kfwlogon.c
++++ b/src/windows/kfwlogon/kfwlogon.c
+@@ -434,9 +434,6 @@ static BOOL
+ GetSecurityLogonSessionData(HANDLE hToken, PSECURITY_LOGON_SESSION_DATA * ppSessionData)
+ {
+     NTSTATUS Status = 0;
+-#if 0
+-    HANDLE  TokenHandle;
+-#endif
+     TOKEN_STATISTICS Stats;
+     DWORD   ReqLen;
+     BOOL    Success;
+@@ -445,16 +442,8 @@ GetSecurityLogonSessionData(HANDLE hToken, PSECURITY_LOGON_SESSION_DATA * ppSess
+         return FALSE;
+     *ppSessionData = NULL;
+ 
+-#if 0
+-    Success = OpenProcessToken( HANDLE GetCurrentProcess(), TOKEN_QUERY, &TokenHandle );
+-    if ( !Success )
+-        return FALSE;
+-#endif
+ 
+     Success = GetTokenInformation( hToken, TokenStatistics, &Stats, sizeof(TOKEN_STATISTICS), &ReqLen );
+-#if 0
+-    CloseHandle( TokenHandle );
+-#endif
+     if ( !Success )
+         return FALSE;
+ 
+diff --git a/src/windows/leash/Leash.cpp b/src/windows/leash/Leash.cpp
+index f4e749350..cafcda7ce 100644
+--- a/src/windows/leash/Leash.cpp
++++ b/src/windows/leash/Leash.cpp
+@@ -46,8 +46,6 @@
+ static char THIS_FILE[] = __FILE__;
+ #endif
+ 
+-extern "C" int VScheckVersion(HWND hWnd, HANDLE hThisInstance);
+-
+ TicketInfoWrapper ticketinfo;
+ 
+ HWND CLeashApp::m_hProgram = 0;
+@@ -479,8 +477,6 @@ BOOL CLeashApp::InitInstance()
+         }
+     }
+ 
+-    VScheckVersion(m_pMainWnd->m_hWnd, AfxGetInstanceHandle());
+-
+     // The one and only window has been initialized, so show and update it.
+     m_pMainWnd->SetWindowText("MIT Kerberos");
+     m_pMainWnd->UpdateWindow();
+diff --git a/src/windows/leash/Makefile.in b/src/windows/leash/Makefile.in
+index 1b124e90f..57f93a418 100644
+--- a/src/windows/leash/Makefile.in
++++ b/src/windows/leash/Makefile.in
+@@ -61,9 +61,6 @@ OBJS=   \
+ 	$(OUTPRE)MainFrm.obj \
+ 	$(OUTPRE)out2con.obj \
+ 	$(OUTPRE)StdAfx.obj \
+-	$(OUTPRE)AfsProperties.obj \
+-	$(OUTPRE)VSroutines.obj \
+-	$(OUTPRE)KrbMiscConfigOpt.obj \
+ 	$(OUTPRE)KrbListTickets.obj
+ 
+ RESFILE = $(OUTPRE)Leash.res
+diff --git a/src/windows/leash/VSroutines.c b/src/windows/leash/VSroutines.c
+deleted file mode 100644
+index 63f0b4ae1..000000000
+--- a/src/windows/leash/VSroutines.c
++++ /dev/null
+@@ -1,64 +0,0 @@
+-#include <windows.h>
+-#include <winver.h>
+-
+-#if 0
+-//#ifdef USE_VS
+-#include <vs.h>
+-
+-#define ININAME	"leash.ini"
+-
+-int VScheckVersion(HWND hWnd, HANDLE hThisInstance)
+-{
+-    VS_Request		vrequest;
+-    VS_Status		status;
+-    BOOL		ok_to_continue;
+-    HCURSOR		hcursor;
+-    char		szFilename[255];
+-    char		szVerQ[90];
+-    char		*cp;
+-    LPSTR		lpAppVersion;
+-    LPSTR		lpAppName;
+-    LONG FAR		*lpLangInfo;
+-    DWORD		hVersionInfoID;
+-    DWORD		size;
+-    GLOBALHANDLE	hVersionInfo;
+-    LPSTR		lpVersionInfo;
+-    int			dumint;
+-    int			retval;
+-
+-    GetModuleFileName(hThisInstance, (LPSTR)szFilename, 255);
+-    size = GetFileVersionInfoSize((LPSTR) szFilename, &hVersionInfoID);
+-    hVersionInfo = GlobalAlloc(GHND, size);
+-    lpVersionInfo = GlobalLock(hVersionInfo);
+-    retval = GetFileVersionInfo(szFilename, hVersionInfoID, size,
+-                                lpVersionInfo);
+-    retval = VerQueryValue(lpVersionInfo, "\\VarFileInfo\\Translation",
+-                           (LPSTR FAR *)&lpLangInfo, &dumint);
+-    wsprintf(szVerQ, "\\StringFileInfo\\%04x%04x\\",
+-             LOWORD(*lpLangInfo), HIWORD(*lpLangInfo));
+-    cp = szVerQ + lstrlen(szVerQ);
+-    lstrcpy(cp, "ProductName");
+-    retval = VerQueryValue(lpVersionInfo, szVerQ, &lpAppName, &dumint);
+-    lstrcpy(cp, "ProductVersion");
+-
+-    retval = VerQueryValue(lpVersionInfo, szVerQ, &lpAppVersion, &dumint);
+-    hcursor = SetCursor(LoadCursor((HINSTANCE)NULL, IDC_WAIT));
+-    vrequest = VSFormRequest(lpAppName, lpAppVersion, ININAME, NULL, hWnd,
+-                             V_CHECK_AND_LOG);
+-    if ((ok_to_continue = (ReqStatus(vrequest) != V_E_CANCEL))
+-        && v_complain((status = VSProcessRequest(vrequest)), ININAME))
+-        WinVSReportRequest(vrequest, hWnd, "Version Server Status Report");
+-    if (ok_to_continue && status == V_REQUIRED)
+-        ok_to_continue = FALSE;
+-    VSDestroyRequest(vrequest);
+-    SetCursor(hcursor);
+-    GlobalUnlock(hVersionInfo);
+-    GlobalFree(hVersionInfo);
+-    return(ok_to_continue);
+-}
+-#else
+-int VScheckVersion(HWND hWnd, HANDLE hThisInstance)
+-{
+-    return(1);
+-}
+-#endif
+diff --git a/src/windows/leashdll/lsh_pwd.c b/src/windows/leashdll/lsh_pwd.c
+index ac85625a0..7cbe3d7e4 100644
+--- a/src/windows/leashdll/lsh_pwd.c
++++ b/src/windows/leashdll/lsh_pwd.c
+@@ -1426,11 +1426,6 @@ AuthenticateProc(
+         CSetDlgItemText(hDialog, IDC_EDIT_PRINCIPAL, principal);
+         CSetDlgItemText(hDialog, IDC_EDIT_PASSWORD, "");
+ 
+-#if 0  /* 20030619 - mjv wishes to return to the default character */
+-        /* echo spaces */
+-	CSendDlgItemMessage(hDialog, IDC_EDIT_PASSWORD, EM_SETPASSWORDCHAR, 32, 0);
+-#endif
+-
+ 	/* Set Lifetime Slider
+ 	*   min value = 5
+ 	*   max value = 1440
+@@ -1817,12 +1812,6 @@ NewPasswordProc(
+         if (hEditCtrl)
+             pAutoComplete = Leash_pec_create(hEditCtrl);
+ 
+-#if 0  /* 20030619 - mjv wishes to return to the default character */
+-	/* echo spaces */
+-	CSendDlgItemMessage(hDialog, IDC_EDIT_PASSWORD, EM_SETPASSWORDCHAR, 32, 0);
+-	CSendDlgItemMessage(hDialog, IDC_EDIT_PASSWORD2, EM_SETPASSWORDCHAR, 32, 0);
+-	CSendDlgItemMessage(hDialog, IDC_EDIT_PASSWORD3, EM_SETPASSWORDCHAR, 32, 0);
+-#endif
+         /* setup text of stuff. */
+ 
+         if (Position.x > 0 && Position.y > 0 &&
+diff --git a/src/windows/leashdll/lshfunc.c b/src/windows/leashdll/lshfunc.c
+index 8dafb7bed..47337de5d 100644
+--- a/src/windows/leashdll/lshfunc.c
++++ b/src/windows/leashdll/lshfunc.c
+@@ -279,19 +279,11 @@ Leash_changepwd_v5(
+     if ( !pkrb5_init_context )
+         goto cleanup;
+ 
+-   if (rc = pkrb5_init_context(&context)) {
+-#if 0
+-       com_err(argv[0], ret, "initializing kerberos library");
+-#endif
++   if (rc = pkrb5_init_context(&context))
+        goto cleanup;
+-   }
+ 
+-   if (rc = pkrb5_parse_name(context, principal, &princ)) {
+-#if 0
+-       com_err(argv[0], ret, "parsing client name");
+-#endif
++   if (rc = pkrb5_parse_name(context, principal, &princ))
+        goto cleanup;
+-   }
+ 
+    pkrb5_get_init_creds_opt_init(&opts);
+    pkrb5_get_init_creds_opt_set_tkt_life(&opts, 5*60);
+@@ -305,29 +297,13 @@ Leash_changepwd_v5(
+ 
+ 
+    if (rc = pkrb5_get_init_creds_password(context, &creds, princ, password,
+-                                          0, 0, 0, "kadmin/changepw", &opts)) {
+-       if (rc == KRB5KRB_AP_ERR_BAD_INTEGRITY) {
+-#if 0
+-           com_err(argv[0], 0,
+-                   "Password incorrect while getting initial ticket");
+-#endif
+-       }
+-       else {
+-#if 0
+-           com_err(argv[0], ret, "getting initial ticket");
+-#endif
+-       }
++                                          0, 0, 0, "kadmin/changepw", &opts))
+        goto cleanup;
+-   }
+ 
+    if (rc = pkrb5_change_password(context, &creds, newpassword,
+                                   &result_code, &result_code_string,
+-                                  &result_string)) {
+-#if 0
+-       com_err(argv[0], ret, "changing password");
+-#endif
++                                  &result_string))
+        goto cleanup;
+-   }
+ 
+    if (result_code) {
+        int len = result_code_string.length +
+diff --git a/src/windows/leashdll/lshutil.cpp b/src/windows/leashdll/lshutil.cpp
+index 37c0723f3..a90e7e92e 100644
+--- a/src/windows/leashdll/lshutil.cpp
++++ b/src/windows/leashdll/lshutil.cpp
+@@ -531,17 +531,6 @@ protected:
+             IAutoCompleteDropDown* pacdd = NULL;
+             hRes = pac->QueryInterface(IID_IAutoCompleteDropDown, (LPVOID*)&pacdd);
+             pac->Release();
+-
+-        // @TODO: auto-suggest; other advanced options?
+-#if 0
+-            IAutoComplete2 *pac2;
+-
+-            if (SUCCEEDED(pac->QueryInterface(IID_IAutoComplete2,
+-                                              (LPVOID*)&pac2))) {
+-                pac2->SetOptions(ACO_AUTOSUGGEST);
+-                pac2->Release();
+-            }
+-#endif
+             m_acdd = pacdd;
+         }
+     }
+diff --git a/src/windows/lib/cacheapi.h b/src/windows/lib/cacheapi.h
+index c485080c1..b30857810 100644
+--- a/src/windows/lib/cacheapi.h
++++ b/src/windows/lib/cacheapi.h
+@@ -102,21 +102,6 @@ typedef struct opaque_dll_control_block_type* apiCB;
+ typedef struct opaque_ccache_pointer_type* ccache_p;
+ typedef struct opaque_credential_iterator_type* ccache_cit;
+ 
+-#if 0
+-enum _cc_data_type {
+-    type_ticket = 0,                /* 0 for ticket, second_ticket */
+-    /* Ted's draft spec says these are to be
+-       "as defined in the Kerberos V5 protocol"
+-       all I can find are typdefs,
+-       can't find an enumerated type or #define
+-    */
+-    type_address,           /* =  <"as defined in the Kerberos V5 protocol"> */
+-    type_authdata,          /* = <"as defined in the Kerberos V5 protocol"> */
+-    type_encryption,        /* = <"as defined in the Kerberos V5 protocol"> */
+-    cc_data_type_max        /* for validation */
+-};
+-#endif
+-
+ typedef struct _cc_data
+ {
+     cc_uint32       type;		// should be one of _cc_data_type
diff --git a/SOURCES/Exit-with-status-0-from-kadmind.patch b/SOURCES/Exit-with-status-0-from-kadmind.patch
new file mode 100644
index 0000000..5fbdff8
--- /dev/null
+++ b/SOURCES/Exit-with-status-0-from-kadmind.patch
@@ -0,0 +1,31 @@
+From 3bfe632c7011c335362d78356232507d9ee26f73 Mon Sep 17 00:00:00 2001
+From: Robbie Harwood <rharwood@redhat.com>
+Date: Wed, 14 Mar 2018 14:31:22 -0400
+Subject: [PATCH] Exit with status 0 from kadmind
+
+Typically, 0 denotes successful exit.  In particular, init systems
+will complain if another different value is returned.  This presents a
+problem for automated installation jobs which want to restart kadmind.
+
+`service kadmin stop` typically sends SIGTERM, which is caught by
+verto and passed to our handler.  Besides cleanup, we then call
+verto_break(), which causes the verto_run() event loop to return.  The
+weird return code has been present since the addition of the kadmin
+code, which used a similar event model for signals.
+
+(cherry picked from commit f970ad412aca36f8a7d3addb1cd4026ed22e5592)
+---
+ src/kadmin/server/ovsec_kadmd.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/src/kadmin/server/ovsec_kadmd.c b/src/kadmin/server/ovsec_kadmd.c
+index aac4d4ffd..0a28b2384 100644
+--- a/src/kadmin/server/ovsec_kadmd.c
++++ b/src/kadmin/server/ovsec_kadmd.c
+@@ -559,5 +559,5 @@ main(int argc, char *argv[])
+ 
+     krb5_klog_close(context);
+     krb5_free_context(context);
+-    exit(2);
++    exit(0);
+ }
diff --git a/SOURCES/Explicitly-look-for-python2-in-configure.in.patch b/SOURCES/Explicitly-look-for-python2-in-configure.in.patch
new file mode 100644
index 0000000..cb6620f
--- /dev/null
+++ b/SOURCES/Explicitly-look-for-python2-in-configure.in.patch
@@ -0,0 +1,816 @@
+From 1d0c0db7755076834519fd02c271a78bbf26bb19 Mon Sep 17 00:00:00 2001
+From: Greg Hudson <ghudson@mit.edu>
+Date: Tue, 3 Jul 2018 01:20:50 -0400
+Subject: [PATCH] Explicitly look for python2 in configure.in
+
+The executable "python" has traditionally been Python 2, but is
+becoming more ambiguous as operating systems transition towards Python
+3.  Look for "python2" in the path in preference to "python", and
+check that what we found isn't Python 3.
+
+Remove the "#!/usr/bin/python" headers at the start of Python test
+scripts since we run them explicitly under python, not as executables.
+Execute paste-kdcproxy.py via sys.executable in t_proxy.py so that it
+doesn't need a #!/usr/bin/python header.
+
+ticket: 8709 (new)
+(cherry picked from commit 2bd410ecdb366083fe9b4e5f6ac4b741b624230b)
+---
+ src/appl/gss-sample/t_gss_sample.py     | 2 --
+ src/appl/user_user/t_user2user.py       | 1 -
+ src/configure.in                        | 9 ++++++---
+ src/kadmin/dbutil/t_tdumputil.py        | 2 --
+ src/kdc/t_bigreply.py                   | 1 -
+ src/kdc/t_emptytgt.py                   | 1 -
+ src/kdc/t_workers.py                    | 1 -
+ src/lib/kdb/t_stringattr.py             | 1 -
+ src/lib/krad/t_daemon.py                | 2 --
+ src/lib/krb5/ccache/t_cccol.py          | 1 -
+ src/lib/krb5/krb/t_expire_warn.py       | 2 --
+ src/lib/krb5/krb/t_in_ccache_patypes.py | 2 --
+ src/lib/krb5/krb/t_vfy_increds.py       | 2 --
+ src/lib/krb5/os/t_discover_uri.py       | 1 -
+ src/tests/gssapi/t_authind.py           | 1 -
+ src/tests/gssapi/t_ccselect.py          | 2 --
+ src/tests/gssapi/t_client_keytab.py     | 1 -
+ src/tests/gssapi/t_enctypes.py          | 1 -
+ src/tests/gssapi/t_export_cred.py       | 1 -
+ src/tests/gssapi/t_gssapi.py            | 1 -
+ src/tests/gssapi/t_s4u.py               | 1 -
+ src/tests/jsonwalker.py                 | 2 --
+ src/tests/t_audit.py                    | 1 -
+ src/tests/t_authdata.py                 | 1 -
+ src/tests/t_bogus_kdc_req.py            | 2 --
+ src/tests/t_ccache.py                   | 2 --
+ src/tests/t_certauth.py                 | 1 -
+ src/tests/t_changepw.py                 | 1 -
+ src/tests/t_crossrealm.py               | 2 --
+ src/tests/t_cve-2012-1014.py            | 2 --
+ src/tests/t_cve-2012-1015.py            | 2 --
+ src/tests/t_cve-2013-1416.py            | 2 --
+ src/tests/t_cve-2013-1417.py            | 2 --
+ src/tests/t_dump.py                     | 1 -
+ src/tests/t_errmsg.py                   | 1 -
+ src/tests/t_etype_info.py               | 1 -
+ src/tests/t_general.py                  | 1 -
+ src/tests/t_hooks.py                    | 1 -
+ src/tests/t_hostrealm.py                | 1 -
+ src/tests/t_iprop.py                    | 2 --
+ src/tests/t_kadm5_auth.py               | 1 -
+ src/tests/t_kadm5_hook.py               | 1 -
+ src/tests/t_kadmin_acl.py               | 1 -
+ src/tests/t_kadmin_parsing.py           | 1 -
+ src/tests/t_kdb.py                      | 1 -
+ src/tests/t_kdb_locking.py              | 2 --
+ src/tests/t_kdc_log.py                  | 2 --
+ src/tests/t_kdcpolicy.py                | 1 -
+ src/tests/t_keydata.py                  | 1 -
+ src/tests/t_keyrollover.py              | 1 -
+ src/tests/t_keytab.py                   | 1 -
+ src/tests/t_kprop.py                    | 1 -
+ src/tests/t_localauth.py                | 1 -
+ src/tests/t_mkey.py                     | 1 -
+ src/tests/t_otp.py                      | 2 --
+ src/tests/t_pkinit.py                   | 1 -
+ src/tests/t_policy.py                   | 1 -
+ src/tests/t_preauth.py                  | 1 -
+ src/tests/t_princflags.py               | 1 -
+ src/tests/t_proxy.py                    | 4 ++--
+ src/tests/t_pwqual.py                   | 1 -
+ src/tests/t_rdreq.py                    | 1 -
+ src/tests/t_referral.py                 | 1 -
+ src/tests/t_renew.py                    | 1 -
+ src/tests/t_renprinc.py                 | 2 --
+ src/tests/t_salt.py                     | 1 -
+ src/tests/t_sesskeynego.py              | 1 -
+ src/tests/t_skew.py                     | 1 -
+ src/tests/t_sn2princ.py                 | 1 -
+ src/tests/t_spake.py                    | 1 -
+ src/tests/t_stringattr.py               | 2 --
+ src/tests/t_tabdump.py                  | 1 -
+ src/tests/t_unlockiter.py               | 1 -
+ src/tests/t_y2038.py                    | 1 -
+ src/util/paste-kdcproxy.py              | 1 -
+ 75 files changed, 8 insertions(+), 99 deletions(-)
+
+diff --git a/src/appl/gss-sample/t_gss_sample.py b/src/appl/gss-sample/t_gss_sample.py
+index 0299e4590..2f537823a 100755
+--- a/src/appl/gss-sample/t_gss_sample.py
++++ b/src/appl/gss-sample/t_gss_sample.py
+@@ -1,5 +1,3 @@
+-#!/usr/bin/python
+-
+ # Copyright (C) 2010 by the Massachusetts Institute of Technology.
+ # All rights reserved.
+ #
+diff --git a/src/appl/user_user/t_user2user.py b/src/appl/user_user/t_user2user.py
+index 2a7d03f8d..2c054f181 100755
+--- a/src/appl/user_user/t_user2user.py
++++ b/src/appl/user_user/t_user2user.py
+@@ -1,4 +1,3 @@
+-#!/usr/bin/python
+ from k5test import *
+ 
+ # If uuserver is not compiled under -DDEBUG, then set to 0
+diff --git a/src/configure.in b/src/configure.in
+index 08c63beca..3f45784b5 100644
+--- a/src/configure.in
++++ b/src/configure.in
+@@ -1098,13 +1098,16 @@ fi
+ AC_SUBST(HAVE_RUNTEST)
+ 
+ # For Python tests.
+-AC_CHECK_PROG(PYTHON,python,python)
++AC_CHECK_PROG(PYTHON,python2,python2)
++if text x"$PYTHON" = x; then
++	AC_CHECK_PROG(PYTHON,python,python)
++fi
+ HAVE_PYTHON=no
+ if test x"$PYTHON" != x; then
+ 	# k5test.py requires python 2.4 (for the subprocess module).
+ 	# Some code needs python 2.5 (for syntax like conditional expressions).
+-	vercheck="import sys;sys.exit((sys.hexversion < 0x2050000) and 1 or 0)"
+-	if python -c "$vercheck"; then
++	wantver="(sys.hexversion >= 0x2050000 and sys.hexversion < 0x3000000)"
++	if "$PYTHON" -c "import sys; sys.exit(not $wantver and 1 or 0)"; then
+ 		HAVE_PYTHON=yes
+ 	fi
+ fi
+diff --git a/src/kadmin/dbutil/t_tdumputil.py b/src/kadmin/dbutil/t_tdumputil.py
+index 5d7ac38d2..52e356533 100755
+--- a/src/kadmin/dbutil/t_tdumputil.py
++++ b/src/kadmin/dbutil/t_tdumputil.py
+@@ -1,5 +1,3 @@
+-#!/usr/bin/python
+-
+ from k5test import *
+ from subprocess import *
+ 
+diff --git a/src/kdc/t_bigreply.py b/src/kdc/t_bigreply.py
+index 6bc9a8fe0..b6300154f 100644
+--- a/src/kdc/t_bigreply.py
++++ b/src/kdc/t_bigreply.py
+@@ -1,4 +1,3 @@
+-#!/usr/bin/python
+ from k5test import *
+ 
+ # Set the maximum UDP reply size very low, so that all replies go
+diff --git a/src/kdc/t_emptytgt.py b/src/kdc/t_emptytgt.py
+index 2d0432e33..c601c010c 100755
+--- a/src/kdc/t_emptytgt.py
++++ b/src/kdc/t_emptytgt.py
+@@ -1,4 +1,3 @@
+-#!/usr/bin/python
+ from k5test import *
+ 
+ realm = K5Realm(create_host=False)
+diff --git a/src/kdc/t_workers.py b/src/kdc/t_workers.py
+index 6dd4f6805..8de3f34d9 100755
+--- a/src/kdc/t_workers.py
++++ b/src/kdc/t_workers.py
+@@ -1,4 +1,3 @@
+-#!/usr/bin/python
+ from k5test import *
+ 
+ realm = K5Realm(start_kdc=False, create_host=False)
+diff --git a/src/lib/kdb/t_stringattr.py b/src/lib/kdb/t_stringattr.py
+index 085e179e4..93e2b0c01 100755
+--- a/src/lib/kdb/t_stringattr.py
++++ b/src/lib/kdb/t_stringattr.py
+@@ -1,4 +1,3 @@
+-#!/usr/bin/python
+ from k5test import *
+ 
+ realm = K5Realm(create_kdb=False)
+diff --git a/src/lib/krad/t_daemon.py b/src/lib/krad/t_daemon.py
+index dcda0050b..7d7a5d0c8 100755
+--- a/src/lib/krad/t_daemon.py
++++ b/src/lib/krad/t_daemon.py
+@@ -1,5 +1,3 @@
+-#!/usr/bin/python
+-#
+ # Copyright 2013 Red Hat, Inc.  All rights reserved.
+ #
+ # Redistribution and use in source and binary forms, with or without
+diff --git a/src/lib/krb5/ccache/t_cccol.py b/src/lib/krb5/ccache/t_cccol.py
+index f7f178564..1467512e2 100755
+--- a/src/lib/krb5/ccache/t_cccol.py
++++ b/src/lib/krb5/ccache/t_cccol.py
+@@ -1,4 +1,3 @@
+-#!/usr/bin/python
+ from k5test import *
+ 
+ realm = K5Realm(create_kdb=False)
+diff --git a/src/lib/krb5/krb/t_expire_warn.py b/src/lib/krb5/krb/t_expire_warn.py
+index aed39e399..781f2728a 100755
+--- a/src/lib/krb5/krb/t_expire_warn.py
++++ b/src/lib/krb5/krb/t_expire_warn.py
+@@ -1,5 +1,3 @@
+-#!/usr/bin/python
+-
+ # Copyright (C) 2010 by the Massachusetts Institute of Technology.
+ # All rights reserved.
+ #
+diff --git a/src/lib/krb5/krb/t_in_ccache_patypes.py b/src/lib/krb5/krb/t_in_ccache_patypes.py
+index c04234064..b2812688c 100755
+--- a/src/lib/krb5/krb/t_in_ccache_patypes.py
++++ b/src/lib/krb5/krb/t_in_ccache_patypes.py
+@@ -1,5 +1,3 @@
+-#!/usr/bin/python
+-
+ # Copyright (C) 2010,2012 by the Massachusetts Institute of Technology.
+ # All rights reserved.
+ #
+diff --git a/src/lib/krb5/krb/t_vfy_increds.py b/src/lib/krb5/krb/t_vfy_increds.py
+index c820cc690..b899308a8 100755
+--- a/src/lib/krb5/krb/t_vfy_increds.py
++++ b/src/lib/krb5/krb/t_vfy_increds.py
+@@ -1,5 +1,3 @@
+-#!/usr/bin/python
+-
+ # Copyright (C) 2011 by the Massachusetts Institute of Technology.
+ # All rights reserved.
+ #
+diff --git a/src/lib/krb5/os/t_discover_uri.py b/src/lib/krb5/os/t_discover_uri.py
+index 278f98371..87bac1792 100644
+--- a/src/lib/krb5/os/t_discover_uri.py
++++ b/src/lib/krb5/os/t_discover_uri.py
+@@ -1,4 +1,3 @@
+-#!/usr/bin/python
+ from k5test import *
+ 
+ entries = ('URI _kerberos.TEST krb5srv::kkdcp:https://kdc1 1 1\n',
+diff --git a/src/tests/gssapi/t_authind.py b/src/tests/gssapi/t_authind.py
+index 84793beb6..af1741a23 100644
+--- a/src/tests/gssapi/t_authind.py
++++ b/src/tests/gssapi/t_authind.py
+@@ -1,4 +1,3 @@
+-#!/usr/bin/python
+ from k5test import *
+ 
+ # Test authentication indicators.  Load the test preauth module so we
+diff --git a/src/tests/gssapi/t_ccselect.py b/src/tests/gssapi/t_ccselect.py
+index 3503f9269..cd62da231 100755
+--- a/src/tests/gssapi/t_ccselect.py
++++ b/src/tests/gssapi/t_ccselect.py
+@@ -1,5 +1,3 @@
+-#!/usr/bin/python
+-
+ # Copyright (C) 2011 by the Massachusetts Institute of Technology.
+ # All rights reserved.
+ 
+diff --git a/src/tests/gssapi/t_client_keytab.py b/src/tests/gssapi/t_client_keytab.py
+index 2da87f45b..e474a27c7 100755
+--- a/src/tests/gssapi/t_client_keytab.py
++++ b/src/tests/gssapi/t_client_keytab.py
+@@ -1,4 +1,3 @@
+-#!/usr/bin/python
+ from k5test import *
+ 
+ # Set up a basic realm and a client keytab containing two user principals.
+diff --git a/src/tests/gssapi/t_enctypes.py b/src/tests/gssapi/t_enctypes.py
+index f513db2b5..ee43ff028 100755
+--- a/src/tests/gssapi/t_enctypes.py
++++ b/src/tests/gssapi/t_enctypes.py
+@@ -1,4 +1,3 @@
+-#!/usr/bin/python
+ from k5test import *
+ 
+ # Define some convenience abbreviations for enctypes we will see in
+diff --git a/src/tests/gssapi/t_export_cred.py b/src/tests/gssapi/t_export_cred.py
+index b98962788..89167bcc5 100755
+--- a/src/tests/gssapi/t_export_cred.py
++++ b/src/tests/gssapi/t_export_cred.py
+@@ -1,4 +1,3 @@
+-#!/usr/bin/python
+ from k5test import *
+ 
+ # Test gss_export_cred and gss_import_cred for initiator creds,
+diff --git a/src/tests/gssapi/t_gssapi.py b/src/tests/gssapi/t_gssapi.py
+index 6da5fceff..a7dda20fb 100755
+--- a/src/tests/gssapi/t_gssapi.py
++++ b/src/tests/gssapi/t_gssapi.py
+@@ -1,4 +1,3 @@
+-#!/usr/bin/python
+ from k5test import *
+ 
+ # Test krb5 negotiation under SPNEGO for all enctype configurations.  Also
+diff --git a/src/tests/gssapi/t_s4u.py b/src/tests/gssapi/t_s4u.py
+index e4cd68469..fc9d9e8a4 100755
+--- a/src/tests/gssapi/t_s4u.py
++++ b/src/tests/gssapi/t_s4u.py
+@@ -1,4 +1,3 @@
+-#!/usr/bin/python
+ from k5test import *
+ 
+ realm = K5Realm(create_host=False, get_creds=False)
+diff --git a/src/tests/jsonwalker.py b/src/tests/jsonwalker.py
+index 265c69c70..942ca2db7 100644
+--- a/src/tests/jsonwalker.py
++++ b/src/tests/jsonwalker.py
+@@ -1,5 +1,3 @@
+-#!/usr/bin/python
+-
+ import sys
+ try:
+     import cjson
+diff --git a/src/tests/t_audit.py b/src/tests/t_audit.py
+index 00e96bfea..0f880edb2 100755
+--- a/src/tests/t_audit.py
++++ b/src/tests/t_audit.py
+@@ -1,4 +1,3 @@
+-#!/usr/bin/python
+ from k5test import *
+ 
+ conf = {'plugins': {'audit': {
+diff --git a/src/tests/t_authdata.py b/src/tests/t_authdata.py
+index 8a577b4b1..5cff80348 100644
+--- a/src/tests/t_authdata.py
++++ b/src/tests/t_authdata.py
+@@ -1,4 +1,3 @@
+-#!/usr/bin/python
+ from k5test import *
+ 
+ # Load the sample KDC authdata module.
+diff --git a/src/tests/t_bogus_kdc_req.py b/src/tests/t_bogus_kdc_req.py
+index b6208ca68..a101c0e10 100755
+--- a/src/tests/t_bogus_kdc_req.py
++++ b/src/tests/t_bogus_kdc_req.py
+@@ -1,5 +1,3 @@
+-#!/usr/bin/python
+-
+ import base64
+ import socket
+ from k5test import *
+diff --git a/src/tests/t_ccache.py b/src/tests/t_ccache.py
+index 61d549b7b..a913eb025 100755
+--- a/src/tests/t_ccache.py
++++ b/src/tests/t_ccache.py
+@@ -1,5 +1,3 @@
+-#!/usr/bin/python
+-
+ # Copyright (C) 2011 by the Massachusetts Institute of Technology.
+ # All rights reserved.
+ 
+diff --git a/src/tests/t_certauth.py b/src/tests/t_certauth.py
+index e64a57b0d..9c7094525 100644
+--- a/src/tests/t_certauth.py
++++ b/src/tests/t_certauth.py
+@@ -1,4 +1,3 @@
+-#!/usr/bin/python
+ from k5test import *
+ 
+ # Skip this test if pkinit wasn't built.
+diff --git a/src/tests/t_changepw.py b/src/tests/t_changepw.py
+index 37fe4fce1..211cda6c3 100755
+--- a/src/tests/t_changepw.py
++++ b/src/tests/t_changepw.py
+@@ -1,4 +1,3 @@
+-#!/usr/bin/python
+ from k5test import *
+ 
+ # This file is intended to cover any password-changing mechanism.  For
+diff --git a/src/tests/t_crossrealm.py b/src/tests/t_crossrealm.py
+index 4d595dca6..09028bfa7 100755
+--- a/src/tests/t_crossrealm.py
++++ b/src/tests/t_crossrealm.py
+@@ -1,5 +1,3 @@
+-#!/usr/bin/python
+-
+ # Copyright (C) 2011 by the Massachusetts Institute of Technology.
+ # All rights reserved.
+ #
+diff --git a/src/tests/t_cve-2012-1014.py b/src/tests/t_cve-2012-1014.py
+index e02162d6c..dcff95f6e 100755
+--- a/src/tests/t_cve-2012-1014.py
++++ b/src/tests/t_cve-2012-1014.py
+@@ -1,5 +1,3 @@
+-#!/usr/bin/python
+-
+ import base64
+ import socket
+ from k5test import *
+diff --git a/src/tests/t_cve-2012-1015.py b/src/tests/t_cve-2012-1015.py
+index e00c4dc90..28b1e619b 100755
+--- a/src/tests/t_cve-2012-1015.py
++++ b/src/tests/t_cve-2012-1015.py
+@@ -1,5 +1,3 @@
+-#!/usr/bin/python
+-
+ import base64
+ import socket
+ from k5test import *
+diff --git a/src/tests/t_cve-2013-1416.py b/src/tests/t_cve-2013-1416.py
+index 94fb6d5ef..8c4391a86 100755
+--- a/src/tests/t_cve-2013-1416.py
++++ b/src/tests/t_cve-2013-1416.py
+@@ -1,5 +1,3 @@
+-#!/usr/bin/python
+-
+ from k5test import *
+ 
+ realm = K5Realm()
+diff --git a/src/tests/t_cve-2013-1417.py b/src/tests/t_cve-2013-1417.py
+index c26930a30..ce47d21ca 100755
+--- a/src/tests/t_cve-2013-1417.py
++++ b/src/tests/t_cve-2013-1417.py
+@@ -1,5 +1,3 @@
+-#!/usr/bin/python
+-
+ from k5test import *
+ 
+ realm = K5Realm(realm='TEST')
+diff --git a/src/tests/t_dump.py b/src/tests/t_dump.py
+index 8a9462bd8..2cfeada6c 100755
+--- a/src/tests/t_dump.py
++++ b/src/tests/t_dump.py
+@@ -1,4 +1,3 @@
+-#!/usr/bin/python
+ from k5test import *
+ from filecmp import cmp
+ 
+diff --git a/src/tests/t_errmsg.py b/src/tests/t_errmsg.py
+index c9ae6637f..4aacf4e0a 100755
+--- a/src/tests/t_errmsg.py
++++ b/src/tests/t_errmsg.py
+@@ -1,4 +1,3 @@
+-#!/usr/bin/python
+ from k5test import *
+ 
+ realm = K5Realm(create_kdb=False)
+diff --git a/src/tests/t_etype_info.py b/src/tests/t_etype_info.py
+index b2eb0f7af..b12fb53c8 100644
+--- a/src/tests/t_etype_info.py
++++ b/src/tests/t_etype_info.py
+@@ -1,4 +1,3 @@
+-#!/usr/bin/python
+ from k5test import *
+ 
+ supported_enctypes = 'aes128-cts des3-cbc-sha1 rc4-hmac des-cbc-crc:afs3'
+diff --git a/src/tests/t_general.py b/src/tests/t_general.py
+index 91ad0cb8a..96ba8a4b0 100755
+--- a/src/tests/t_general.py
++++ b/src/tests/t_general.py
+@@ -1,4 +1,3 @@
+-#!/usr/bin/python
+ from k5test import *
+ 
+ for realm in multipass_realms(create_host=False):
+diff --git a/src/tests/t_hooks.py b/src/tests/t_hooks.py
+index 58dff3ae7..4fd3822e8 100755
+--- a/src/tests/t_hooks.py
++++ b/src/tests/t_hooks.py
+@@ -1,4 +1,3 @@
+-#!/usr/bin/python
+ from k5test import *
+ 
+ # Test that KDC send and recv hooks work correctly.
+diff --git a/src/tests/t_hostrealm.py b/src/tests/t_hostrealm.py
+index 224c067ef..256ba2a38 100755
+--- a/src/tests/t_hostrealm.py
++++ b/src/tests/t_hostrealm.py
+@@ -1,4 +1,3 @@
+-#!/usr/bin/python
+ from k5test import *
+ 
+ plugin = os.path.join(buildtop, "plugins", "hostrealm", "test",
+diff --git a/src/tests/t_iprop.py b/src/tests/t_iprop.py
+index 8e23cd5de..9cbeb3e68 100755
+--- a/src/tests/t_iprop.py
++++ b/src/tests/t_iprop.py
+@@ -1,5 +1,3 @@
+-#!/usr/bin/python
+-
+ import os
+ import re
+ 
+diff --git a/src/tests/t_kadm5_auth.py b/src/tests/t_kadm5_auth.py
+index ba4ab8ef1..6e0f42b08 100644
+--- a/src/tests/t_kadm5_auth.py
++++ b/src/tests/t_kadm5_auth.py
+@@ -1,4 +1,3 @@
+-#!/usr/bin/python
+ from k5test import *
+ 
+ # Create a realm with the welcomer and bouncer kadm5_auth test modules
+diff --git a/src/tests/t_kadm5_hook.py b/src/tests/t_kadm5_hook.py
+index c1c8c9419..32fab781d 100755
+--- a/src/tests/t_kadm5_hook.py
++++ b/src/tests/t_kadm5_hook.py
+@@ -1,4 +1,3 @@
+-#!/usr/bin/python
+ from k5test import *
+ 
+ plugin = os.path.join(buildtop, "plugins", "kadm5_hook", "test",
+diff --git a/src/tests/t_kadmin_acl.py b/src/tests/t_kadmin_acl.py
+index 42bdf423c..01a3eda29 100755
+--- a/src/tests/t_kadmin_acl.py
++++ b/src/tests/t_kadmin_acl.py
+@@ -1,4 +1,3 @@
+-#!/usr/bin/python
+ from k5test import *
+ import os
+ 
+diff --git a/src/tests/t_kadmin_parsing.py b/src/tests/t_kadmin_parsing.py
+index 8de387c64..bebb01488 100644
+--- a/src/tests/t_kadmin_parsing.py
++++ b/src/tests/t_kadmin_parsing.py
+@@ -1,4 +1,3 @@
+-#!/usr/bin/python
+ from k5test import *
+ 
+ # This file contains tests for kadmin command parsing.  Principal
+diff --git a/src/tests/t_kdb.py b/src/tests/t_kdb.py
+index 6e563b103..983cd93c8 100755
+--- a/src/tests/t_kdb.py
++++ b/src/tests/t_kdb.py
+@@ -1,4 +1,3 @@
+-#!/usr/bin/python
+ from k5test import *
+ import time
+ from itertools import imap
+diff --git a/src/tests/t_kdb_locking.py b/src/tests/t_kdb_locking.py
+index aac0a220f..b5afd6d23 100755
+--- a/src/tests/t_kdb_locking.py
++++ b/src/tests/t_kdb_locking.py
+@@ -1,5 +1,3 @@
+-#!/usr/bin/python
+-
+ # This is a regression test for
+ # https://bugzilla.redhat.com/show_bug.cgi?id=586032 .
+ #
+diff --git a/src/tests/t_kdc_log.py b/src/tests/t_kdc_log.py
+index 8ddb7691b..1b14828de 100755
+--- a/src/tests/t_kdc_log.py
++++ b/src/tests/t_kdc_log.py
+@@ -1,5 +1,3 @@
+-#!/usr/bin/python
+-
+ from k5test import *
+ 
+ # Make a TGS request with an expired ticket.
+diff --git a/src/tests/t_kdcpolicy.py b/src/tests/t_kdcpolicy.py
+index 5b198bb43..a44adfdb5 100644
+--- a/src/tests/t_kdcpolicy.py
++++ b/src/tests/t_kdcpolicy.py
+@@ -1,4 +1,3 @@
+-#!/usr/bin/python
+ from k5test import *
+ from datetime import datetime
+ import re
+diff --git a/src/tests/t_keydata.py b/src/tests/t_keydata.py
+index 5c04a8523..b37233b21 100755
+--- a/src/tests/t_keydata.py
++++ b/src/tests/t_keydata.py
+@@ -1,4 +1,3 @@
+-#!/usr/bin/python
+ from k5test import *
+ 
+ realm = K5Realm(create_user=False, create_host=False)
+diff --git a/src/tests/t_keyrollover.py b/src/tests/t_keyrollover.py
+index bfd38914b..7c8d828f0 100755
+--- a/src/tests/t_keyrollover.py
++++ b/src/tests/t_keyrollover.py
+@@ -1,4 +1,3 @@
+-#!/usr/bin/python
+ from k5test import *
+ 
+ rollover_krb5_conf = {'libdefaults': {'allow_weak_crypto': 'true'}}
+diff --git a/src/tests/t_keytab.py b/src/tests/t_keytab.py
+index a48740ba5..228c36334 100755
+--- a/src/tests/t_keytab.py
++++ b/src/tests/t_keytab.py
+@@ -1,4 +1,3 @@
+-#!/usr/bin/python
+ from k5test import *
+ 
+ for realm in multipass_realms(create_user=False):
+diff --git a/src/tests/t_kprop.py b/src/tests/t_kprop.py
+index 39169675d..f352ec8d7 100755
+--- a/src/tests/t_kprop.py
++++ b/src/tests/t_kprop.py
+@@ -1,4 +1,3 @@
+-#!/usr/bin/python
+ from k5test import *
+ 
+ conf_slave = {'dbmodules': {'db': {'database_name': '$testdir/db.slave'}}}
+diff --git a/src/tests/t_localauth.py b/src/tests/t_localauth.py
+index aa625d038..ebc9cdfde 100755
+--- a/src/tests/t_localauth.py
++++ b/src/tests/t_localauth.py
+@@ -1,4 +1,3 @@
+-#!/usr/bin/python
+ from k5test import *
+ 
+ # Unfortunately, we can't reliably test the k5login module.  We can control
+diff --git a/src/tests/t_mkey.py b/src/tests/t_mkey.py
+index 615cd91ca..48a533059 100755
+--- a/src/tests/t_mkey.py
++++ b/src/tests/t_mkey.py
+@@ -1,4 +1,3 @@
+-#!/usr/bin/python
+ from k5test import *
+ import random
+ import re
+diff --git a/src/tests/t_otp.py b/src/tests/t_otp.py
+index 9b18ff94b..0fd35d576 100755
+--- a/src/tests/t_otp.py
++++ b/src/tests/t_otp.py
+@@ -1,5 +1,3 @@
+-#!/usr/bin/python
+-#
+ # Author: Nathaniel McCallum <npmccallum@redhat.com>
+ #
+ # Copyright (c) 2013 Red Hat, Inc.
+diff --git a/src/tests/t_pkinit.py b/src/tests/t_pkinit.py
+index 0e964c689..850db4fdd 100755
+--- a/src/tests/t_pkinit.py
++++ b/src/tests/t_pkinit.py
+@@ -1,4 +1,3 @@
+-#!/usr/bin/python
+ from k5test import *
+ 
+ # Skip this test if pkinit wasn't built.
+diff --git a/src/tests/t_policy.py b/src/tests/t_policy.py
+index 26c4e466e..eb3865d7c 100755
+--- a/src/tests/t_policy.py
++++ b/src/tests/t_policy.py
+@@ -1,4 +1,3 @@
+-#!/usr/bin/python
+ from k5test import *
+ import re
+ 
+diff --git a/src/tests/t_preauth.py b/src/tests/t_preauth.py
+index 32e35b08b..f597c3d08 100644
+--- a/src/tests/t_preauth.py
++++ b/src/tests/t_preauth.py
+@@ -1,4 +1,3 @@
+-#!/usr/bin/python
+ from k5test import *
+ 
+ # Test that the kdcpreauth client_keyblock() callback matches the key
+diff --git a/src/tests/t_princflags.py b/src/tests/t_princflags.py
+index 6378ef94f..aa3660217 100755
+--- a/src/tests/t_princflags.py
++++ b/src/tests/t_princflags.py
+@@ -1,4 +1,3 @@
+-#!/usr/bin/python
+ from k5test import *
+ from princflags import *
+ import re
+diff --git a/src/tests/t_proxy.py b/src/tests/t_proxy.py
+index 4e86fce8f..ff1929bef 100755
+--- a/src/tests/t_proxy.py
++++ b/src/tests/t_proxy.py
+@@ -1,4 +1,3 @@
+-#!/usr/bin/python
+ from k5test import *
+ 
+ # Skip this test if we're missing proxy functionality or parts of the proxy.
+@@ -62,7 +61,8 @@ def start_proxy(realm, keycertpem):
+     conf.write('kpasswd = kpasswd://localhost:%d\n' % (realm.portbase + 2))
+     conf.close()
+     realm.env['KDCPROXY_CONFIG'] = proxy_conf_path
+-    cmd = [proxy_exec_path, str(realm.server_port()), keycertpem]
++    cmd = [sys.executable, proxy_exec_path, str(realm.server_port()),
++           keycertpem]
+     return realm.start_server(cmd, sentinel='proxy server ready')
+ 
+ # Fail: untrusted issuer and hostname doesn't match.
+diff --git a/src/tests/t_pwqual.py b/src/tests/t_pwqual.py
+index 011110bd1..171805697 100755
+--- a/src/tests/t_pwqual.py
++++ b/src/tests/t_pwqual.py
+@@ -1,4 +1,3 @@
+-#!/usr/bin/python
+ from k5test import *
+ 
+ plugin = os.path.join(buildtop, "plugins", "pwqual", "test", "pwqual_test.so")
+diff --git a/src/tests/t_rdreq.py b/src/tests/t_rdreq.py
+index f67c34866..00cd5cbb4 100755
+--- a/src/tests/t_rdreq.py
++++ b/src/tests/t_rdreq.py
+@@ -1,4 +1,3 @@
+-#!/usr/bin/python
+ from k5test import *
+ 
+ conf = {'realms': {'$realm': {'supported_enctypes': 'aes256-cts aes128-cts'}}}
+diff --git a/src/tests/t_referral.py b/src/tests/t_referral.py
+index e12fdc2e9..2f29d5712 100755
+--- a/src/tests/t_referral.py
++++ b/src/tests/t_referral.py
+@@ -1,4 +1,3 @@
+-#!/usr/bin/python
+ from k5test import *
+ 
+ # Create a pair of realms, where KRBTEST1.COM can authenticate to
+diff --git a/src/tests/t_renew.py b/src/tests/t_renew.py
+index 034190c80..67b4182fd 100755
+--- a/src/tests/t_renew.py
++++ b/src/tests/t_renew.py
+@@ -1,4 +1,3 @@
+-#!/usr/bin/python
+ from k5test import *
+ from datetime import datetime
+ import re
+diff --git a/src/tests/t_renprinc.py b/src/tests/t_renprinc.py
+index cc780839a..46cbed441 100755
+--- a/src/tests/t_renprinc.py
++++ b/src/tests/t_renprinc.py
+@@ -1,5 +1,3 @@
+-#!/usr/bin/python
+-
+ # Copyright (C) 2011 by the Massachusetts Institute of Technology.
+ # All rights reserved.
+ 
+diff --git a/src/tests/t_salt.py b/src/tests/t_salt.py
+index ddb1905ed..278911a22 100755
+--- a/src/tests/t_salt.py
++++ b/src/tests/t_salt.py
+@@ -1,4 +1,3 @@
+-#!/usr/bin/python
+ from k5test import *
+ import re
+ 
+diff --git a/src/tests/t_sesskeynego.py b/src/tests/t_sesskeynego.py
+index 732c306ea..448092387 100755
+--- a/src/tests/t_sesskeynego.py
++++ b/src/tests/t_sesskeynego.py
+@@ -1,4 +1,3 @@
+-#!/usr/bin/python
+ from k5test import *
+ import re
+ 
+diff --git a/src/tests/t_skew.py b/src/tests/t_skew.py
+index f2ae06695..36d5a95c5 100755
+--- a/src/tests/t_skew.py
++++ b/src/tests/t_skew.py
+@@ -1,4 +1,3 @@
+-#!/usr/bin/python
+ from k5test import *
+ 
+ # Create a realm with the KDC one hour in the past.
+diff --git a/src/tests/t_sn2princ.py b/src/tests/t_sn2princ.py
+index 19a0d2fa7..e2c85e665 100755
+--- a/src/tests/t_sn2princ.py
++++ b/src/tests/t_sn2princ.py
+@@ -1,4 +1,3 @@
+-#!/usr/bin/python
+ from k5test import *
+ 
+ offline = (len(args) > 0 and args[0] != "no")
+diff --git a/src/tests/t_spake.py b/src/tests/t_spake.py
+index 5b47e62d3..65af46d18 100644
+--- a/src/tests/t_spake.py
++++ b/src/tests/t_spake.py
+@@ -1,4 +1,3 @@
+-#!/usr/bin/python
+ from k5test import *
+ 
+ # The name and number of each supported SPAKE group.
+diff --git a/src/tests/t_stringattr.py b/src/tests/t_stringattr.py
+index 5672a0f20..c2dc348e9 100755
+--- a/src/tests/t_stringattr.py
++++ b/src/tests/t_stringattr.py
+@@ -1,5 +1,3 @@
+-#!/usr/bin/python
+-
+ # Copyright (C) 2011 by the Massachusetts Institute of Technology.
+ # All rights reserved.
+ 
+diff --git a/src/tests/t_tabdump.py b/src/tests/t_tabdump.py
+index 066e48418..2a86136dd 100755
+--- a/src/tests/t_tabdump.py
++++ b/src/tests/t_tabdump.py
+@@ -1,4 +1,3 @@
+-#!/usr/bin/python
+ from k5test import *
+ 
+ import csv
+diff --git a/src/tests/t_unlockiter.py b/src/tests/t_unlockiter.py
+index 2a438e99a..603cf721d 100755
+--- a/src/tests/t_unlockiter.py
++++ b/src/tests/t_unlockiter.py
+@@ -1,4 +1,3 @@
+-#!/usr/bin/python
+ from k5test import *
+ 
+ # Default KDB iteration is locked.  Expect write lock failure unless
+diff --git a/src/tests/t_y2038.py b/src/tests/t_y2038.py
+index 02e946df4..42a4ff7ed 100644
+--- a/src/tests/t_y2038.py
++++ b/src/tests/t_y2038.py
+@@ -1,4 +1,3 @@
+-#!/usr/bin/python
+ from k5test import *
+ 
+ # These tests will become much less important after the y2038 boundary
+diff --git a/src/util/paste-kdcproxy.py b/src/util/paste-kdcproxy.py
+index 1e56b8954..30467fd74 100755
+--- a/src/util/paste-kdcproxy.py
++++ b/src/util/paste-kdcproxy.py
+@@ -1,4 +1,3 @@
+-#!/usr/bin/python
+ import kdcproxy
+ from paste import httpserver
+ import os
diff --git a/SOURCES/Fix-SPAKE-memory-leak.patch b/SOURCES/Fix-SPAKE-memory-leak.patch
new file mode 100644
index 0000000..e1cacca
--- /dev/null
+++ b/SOURCES/Fix-SPAKE-memory-leak.patch
@@ -0,0 +1,41 @@
+From 390c515e13dffc8c00b44623cba47e27c2f20cf7 Mon Sep 17 00:00:00 2001
+From: Greg Hudson <ghudson@mit.edu>
+Date: Tue, 27 Mar 2018 10:36:05 -0400
+Subject: [PATCH] Fix SPAKE memory leak
+
+In the NIST group implementations, ossl_fini() needs to free the
+groupdata container as well as its fields.  Also in
+spake_kdc.c:parse_data(), initialize the magic field of the resulting
+data object to avoid a harmless uninitialized memory copy.
+
+ticket: 8647
+(cherry picked from commit 70b88b8018658e052d6eabf06f8fdad17fbe993c)
+---
+ src/plugins/preauth/spake/openssl.c   | 1 +
+ src/plugins/preauth/spake/spake_kdc.c | 1 +
+ 2 files changed, 2 insertions(+)
+
+diff --git a/src/plugins/preauth/spake/openssl.c b/src/plugins/preauth/spake/openssl.c
+index b821a9158..f2e4b53ec 100644
+--- a/src/plugins/preauth/spake/openssl.c
++++ b/src/plugins/preauth/spake/openssl.c
+@@ -69,6 +69,7 @@ ossl_fini(groupdata *gd)
+     EC_POINT_free(gd->N);
+     BN_CTX_free(gd->ctx);
+     BN_free(gd->order);
++    free(gd);
+ }
+ 
+ static krb5_error_code
+diff --git a/src/plugins/preauth/spake/spake_kdc.c b/src/plugins/preauth/spake/spake_kdc.c
+index c1723ebaf..59e88409e 100644
+--- a/src/plugins/preauth/spake/spake_kdc.c
++++ b/src/plugins/preauth/spake/spake_kdc.c
+@@ -75,6 +75,7 @@ parse_data(struct k5input *in, krb5_data *out)
+ {
+     out->length = k5_input_get_uint32_be(in);
+     out->data = (char *)k5_input_get_bytes(in, out->length);
++    out->magic = KV5M_DATA;
+ }
+ 
+ /* Parse a received cookie into its components.  The pointers stored in the
diff --git a/SOURCES/Fix-hex-conversion-of-PKINIT-certid-strings.patch b/SOURCES/Fix-hex-conversion-of-PKINIT-certid-strings.patch
new file mode 100644
index 0000000..57d561b
--- /dev/null
+++ b/SOURCES/Fix-hex-conversion-of-PKINIT-certid-strings.patch
@@ -0,0 +1,92 @@
+From 8b898badbe8051270c6da96f5c15f3bc8b6d974e Mon Sep 17 00:00:00 2001
+From: Sumit Bose <sbose@redhat.com>
+Date: Fri, 26 Jan 2018 11:47:50 -0500
+Subject: [PATCH] Fix hex conversion of PKINIT certid strings
+
+When parsing a PKCS11 token specification, correctly convert from hex
+to binary instead of using OpenSSL bignum functions (which would strip
+leading zeros).
+
+[ghudson@mit.edu: made hex_string_to_bin() a bit less verbose; wrote
+commit message]
+
+ticket: 8636
+(cherry picked from commit 63e8b8142fd7b3931a7bf2d6448978ca536bafc0)
+---
+ .../preauth/pkinit/pkinit_crypto_openssl.c    | 55 +++++++++++++++----
+ 1 file changed, 44 insertions(+), 11 deletions(-)
+
+diff --git a/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c b/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c
+index 2064eb7bd..eb2953fe1 100644
+--- a/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c
++++ b/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c
+@@ -4616,6 +4616,43 @@ reassemble_pkcs11_name(pkinit_identity_opts *idopts)
+     return ret;
+ }
+ 
++static int
++hex_string_to_bin(const char *str, int *bin_len_out, CK_BYTE **bin_out)
++{
++    size_t str_len, i;
++    CK_BYTE *bin;
++    char *endptr, tmp[3] = { '\0', '\0', '\0' };
++    long val;
++
++    *bin_len_out = 0;
++    *bin_out = NULL;
++
++    str_len = strlen(str);
++    if (str_len % 2 != 0)
++        return EINVAL;
++    bin = malloc(str_len / 2);
++    if (bin == NULL)
++        return ENOMEM;
++
++    errno = 0;
++    for (i = 0; i < str_len / 2; i++) {
++        tmp[0] = str[i * 2];
++        tmp[1] = str[i * 2 + 1];
++
++        val = strtol(tmp, &endptr, 16);
++        if (val < 0 || val > 255 || errno != 0 || endptr != &tmp[2]) {
++            free(bin);
++            return EINVAL;
++        }
++
++        bin[i] = (CK_BYTE)val;
++    }
++
++    *bin_len_out = str_len / 2;
++    *bin_out = bin;
++    return 0;
++}
++
+ static krb5_error_code
+ pkinit_get_certs_pkcs11(krb5_context context,
+                         pkinit_plg_crypto_context plg_cryptoctx,
+@@ -4658,18 +4695,14 @@ pkinit_get_certs_pkcs11(krb5_context context,
+     }
+     /* Convert the ascii cert_id string into a binary blob */
+     if (idopts->cert_id_string != NULL) {
+-        BIGNUM *bn = NULL;
+-        BN_hex2bn(&bn, idopts->cert_id_string);
+-        if (bn == NULL)
+-            return ENOMEM;
+-        id_cryptoctx->cert_id_len = BN_num_bytes(bn);
+-        id_cryptoctx->cert_id = malloc((size_t) id_cryptoctx->cert_id_len);
+-        if (id_cryptoctx->cert_id == NULL) {
+-            BN_free(bn);
+-            return ENOMEM;
++        r = hex_string_to_bin(idopts->cert_id_string,
++                              &id_cryptoctx->cert_id_len,
++                              &id_cryptoctx->cert_id);
++        if (r != 0) {
++            pkiDebug("Failed to convert certid string [%s]\n",
++                     idopts->cert_id_string);
++            return r;
+         }
+-        BN_bn2bin(bn, id_cryptoctx->cert_id);
+-        BN_free(bn);
+     }
+     id_cryptoctx->slotid = idopts->slotid;
+     id_cryptoctx->pkcs11_method = 1;
diff --git a/SOURCES/Fix-k5test-prompts-for-Python-3.patch b/SOURCES/Fix-k5test-prompts-for-Python-3.patch
new file mode 100644
index 0000000..4adb451
--- /dev/null
+++ b/SOURCES/Fix-k5test-prompts-for-Python-3.patch
@@ -0,0 +1,35 @@
+From 43cf653d21d931b792b36c7e6e4cfab3a6236bef Mon Sep 17 00:00:00 2001
+From: Greg Hudson <ghudson@mit.edu>
+Date: Wed, 25 Jul 2018 11:50:02 -0400
+Subject: [PATCH] Fix k5test prompts for Python 3
+
+With Python 3, sys.stdout.write() of a partial line followed by
+sys.stdin.readline() does not display the partial line.  Add explicit
+flushes to make prompts visible in k5test.py.
+
+ticket: 8710
+(cherry picked from commit 297535b72177dcced036b78107e9d0e37781c7a3)
+---
+ src/util/k5test.py | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/src/util/k5test.py b/src/util/k5test.py
+index 81fac3063..e4f99b211 100644
+--- a/src/util/k5test.py
++++ b/src/util/k5test.py
+@@ -457,6 +457,7 @@ def _onexit():
+     if _debug or _stop_before or _stop_after or _shell_before or _shell_after:
+         # Wait before killing daemons in case one is being debugged.
+         sys.stdout.write('*** Press return to kill daemons and exit script: ')
++        sys.stdout.flush()
+         sys.stdin.readline()
+     for proc in _daemons:
+         os.kill(proc.pid, signal.SIGTERM)
+@@ -658,6 +659,7 @@ def _valgrind(args):
+ def _stop_or_shell(stop, shell, env, ind):
+     if (_match_cmdnum(stop, ind)):
+         sys.stdout.write('*** [%d] Waiting for return: ' % ind)
++        sys.stdout.flush()
+         sys.stdin.readline()
+     if (_match_cmdnum(shell, ind)):
+         output('*** [%d] Spawning shell\n' % ind, True)
diff --git a/SOURCES/Fix-read-overflow-in-KDC-sort_pa_data.patch b/SOURCES/Fix-read-overflow-in-KDC-sort_pa_data.patch
new file mode 100644
index 0000000..4f46827
--- /dev/null
+++ b/SOURCES/Fix-read-overflow-in-KDC-sort_pa_data.patch
@@ -0,0 +1,48 @@
+From 59a28991e15496e6f9cf867c32dc18e7e1062f59 Mon Sep 17 00:00:00 2001
+From: Greg Hudson <ghudson@mit.edu>
+Date: Thu, 15 Mar 2018 20:27:30 -0400
+Subject: [PATCH] Fix read overflow in KDC sort_pa_data()
+
+sort_pa_data() could read past the end of pa_order if all preauth
+systems in the table have the PA_REPLACES_KEY flag, causing a
+dereference of preauth_systems[-1].  This situation became possible
+after commit fea1a488924faa3938ef723feaa1ff12d22a91ff with the
+elimination of static_preauth_systems; before that there were always
+table entries which did not have PA_REPLACES_KEY set.
+
+Fix this bug by removing the loop to count n_key_replacers, and
+instead get the count from the prior loop by stopping once we move all
+of the key-replacing modules to the front.
+
+(cherry picked from commit b38e318cea18fd65647189eed64aef83bf1cb772)
+---
+ src/kdc/kdc_preauth.c | 9 +++++----
+ 1 file changed, 5 insertions(+), 4 deletions(-)
+
+diff --git a/src/kdc/kdc_preauth.c b/src/kdc/kdc_preauth.c
+index 80b130222..62ff9a8a7 100644
+--- a/src/kdc/kdc_preauth.c
++++ b/src/kdc/kdc_preauth.c
+@@ -663,17 +663,18 @@ sort_pa_order(krb5_context context, krb5_kdc_req *request, int *pa_order)
+                 break;
+             }
+         }
++        /* If we didn't find one, we have moved all of the key-replacing
++         * modules, and i is the count of those modules. */
++        if (j == n_repliers)
++            break;
+     }
++    n_key_replacers = i;
+ 
+     if (request->padata != NULL) {
+         /* Now reorder the subset of modules which replace the key,
+          * bubbling those which handle pa_data types provided by the
+          * client ahead of the others.
+          */
+-        for (i = 0; preauth_systems[pa_order[i]].flags & PA_REPLACES_KEY; i++) {
+-            continue;
+-        }
+-        n_key_replacers = i;
+         for (i = 0; i < n_key_replacers; i++) {
+             if (pa_list_includes(request->padata,
+                                  preauth_systems[pa_order[i]].type))
diff --git a/SOURCES/Fix-securid_sam2-preauth-for-non-default-salt.patch b/SOURCES/Fix-securid_sam2-preauth-for-non-default-salt.patch
new file mode 100644
index 0000000..610bf4e
--- /dev/null
+++ b/SOURCES/Fix-securid_sam2-preauth-for-non-default-salt.patch
@@ -0,0 +1,43 @@
+From e405f42b532e377e7e3d654313a07f8c11f48f9a Mon Sep 17 00:00:00 2001
+From: Greg Hudson <ghudson@mit.edu>
+Date: Wed, 3 Jan 2018 12:06:08 -0500
+Subject: [PATCH] Fix securid_sam2 preauth for non-default salt
+
+When looking up the client long-term key, look for any salt type, not
+just the default salt type.
+
+ticket: 8629
+(cherry picked from commit a2339099ad13c84de0843fd04d0ba612fc194a1e)
+---
+ src/plugins/preauth/securid_sam2/grail.c    | 3 +--
+ src/plugins/preauth/securid_sam2/securid2.c | 3 +--
+ 2 files changed, 2 insertions(+), 4 deletions(-)
+
+diff --git a/src/plugins/preauth/securid_sam2/grail.c b/src/plugins/preauth/securid_sam2/grail.c
+index 18d48f924..48b61b0d1 100644
+--- a/src/plugins/preauth/securid_sam2/grail.c
++++ b/src/plugins/preauth/securid_sam2/grail.c
+@@ -213,8 +213,7 @@ verify_grail_data(krb5_context context, krb5_db_entry *client,
+         return KRB5KDC_ERR_PREAUTH_FAILED;
+ 
+     ret = krb5_dbe_find_enctype(context, client,
+-                                sr2->sam_enc_nonce_or_sad.enctype,
+-                                KRB5_KDB_SALTTYPE_NORMAL,
++                                sr2->sam_enc_nonce_or_sad.enctype, -1,
+                                 sr2->sam_enc_nonce_or_sad.kvno,
+                                 &client_key_data);
+     if (ret)
+diff --git a/src/plugins/preauth/securid_sam2/securid2.c b/src/plugins/preauth/securid_sam2/securid2.c
+index ca99ce3ef..363e17a10 100644
+--- a/src/plugins/preauth/securid_sam2/securid2.c
++++ b/src/plugins/preauth/securid_sam2/securid2.c
+@@ -313,8 +313,7 @@ verify_securid_data_2(krb5_context context, krb5_db_entry *client,
+     }
+ 
+     retval = krb5_dbe_find_enctype(context, client,
+-                                   sr2->sam_enc_nonce_or_sad.enctype,
+-                                   KRB5_KDB_SALTTYPE_NORMAL,
++                                   sr2->sam_enc_nonce_or_sad.enctype, -1,
+                                    sr2->sam_enc_nonce_or_sad.kvno,
+                                    &client_key_data);
+     if (retval) {
diff --git a/SOURCES/Fix-segfault-in-finish_dispatch.patch b/SOURCES/Fix-segfault-in-finish_dispatch.patch
new file mode 100644
index 0000000..ff28848
--- /dev/null
+++ b/SOURCES/Fix-segfault-in-finish_dispatch.patch
@@ -0,0 +1,133 @@
+From 617d153bb32d0bd7db33ccec21043d1113651f3a Mon Sep 17 00:00:00 2001
+From: Robbie Harwood <rharwood@redhat.com>
+Date: Wed, 18 Apr 2018 14:13:28 -0400
+Subject: [PATCH] Fix segfault in finish_dispatch()
+
+dispatch() doesn't necessarily initialize state->active_realm which
+led to an explicit NULL dereference in finish_dispatch().
+
+Additionally, fix make_too_big_error() so that it won't subsequently
+dereference state->active_realm.
+
+tags: pullup
+target_version: 1.16-next
+target_version: 1.15-next
+---
+ src/kdc/dispatch.c | 79 ++++++++++++++++++++++++----------------------
+ 1 file changed, 42 insertions(+), 37 deletions(-)
+
+diff --git a/src/kdc/dispatch.c b/src/kdc/dispatch.c
+index 3ed5176a8..fb3686c98 100644
+--- a/src/kdc/dispatch.c
++++ b/src/kdc/dispatch.c
+@@ -35,9 +35,6 @@
+ 
+ static krb5_int32 last_usec = 0, last_os_random = 0;
+ 
+-static krb5_error_code make_too_big_error(kdc_realm_t *kdc_active_realm,
+-                                          krb5_data **out);
+-
+ struct dispatch_state {
+     loop_respond_fn respond;
+     void *arg;
+@@ -47,6 +44,41 @@ struct dispatch_state {
+     krb5_context kdc_err_context;
+ };
+ 
++
++static krb5_error_code
++make_too_big_error(krb5_context context, krb5_principal tgsprinc,
++                   krb5_data **out)
++{
++    krb5_error errpkt;
++    krb5_error_code retval;
++    krb5_data *scratch;
++
++    *out = NULL;
++    memset(&errpkt, 0, sizeof(errpkt));
++
++    retval = krb5_us_timeofday(context, &errpkt.stime, &errpkt.susec);
++    if (retval)
++        return retval;
++    errpkt.error = KRB_ERR_RESPONSE_TOO_BIG;
++    errpkt.server = tgsprinc;
++    errpkt.client = NULL;
++    errpkt.text.length = 0;
++    errpkt.text.data = 0;
++    errpkt.e_data.length = 0;
++    errpkt.e_data.data = 0;
++    scratch = malloc(sizeof(*scratch));
++    if (scratch == NULL)
++        return ENOMEM;
++    retval = krb5_mk_error(context, &errpkt, scratch);
++    if (retval) {
++        free(scratch);
++        return retval;
++    }
++
++    *out = scratch;
++    return 0;
++}
++
+ static void
+ finish_dispatch(struct dispatch_state *state, krb5_error_code code,
+                 krb5_data *response)
+@@ -54,12 +86,17 @@ finish_dispatch(struct dispatch_state *state, krb5_error_code code,
+     loop_respond_fn oldrespond = state->respond;
+     void *oldarg = state->arg;
+     kdc_realm_t *kdc_active_realm = state->active_realm;
++    krb5_principal tgsprinc = NULL;
++
++    if (kdc_active_realm != NULL)
++        tgsprinc = kdc_active_realm->realm_tgsprinc;
+ 
+     if (state->is_tcp == 0 && response &&
+         response->length > (unsigned int)max_dgram_reply_size) {
+-        krb5_free_data(kdc_context, response);
++        krb5_free_data(state->kdc_err_context, response);
+         response = NULL;
+-        code = make_too_big_error(kdc_active_realm, &response);
++        code = make_too_big_error(state->kdc_err_context, tgsprinc,
++                                  &response);
+         if (code)
+             krb5_klog_syslog(LOG_ERR, "error constructing "
+                              "KRB_ERR_RESPONSE_TOO_BIG error: %s",
+@@ -208,38 +245,6 @@ done:
+     finish_dispatch_cache(state, retval, response);
+ }
+ 
+-static krb5_error_code
+-make_too_big_error(kdc_realm_t *kdc_active_realm, krb5_data **out)
+-{
+-    krb5_error errpkt;
+-    krb5_error_code retval;
+-    krb5_data *scratch;
+-
+-    *out = NULL;
+-    memset(&errpkt, 0, sizeof(errpkt));
+-
+-    retval = krb5_us_timeofday(kdc_context, &errpkt.stime, &errpkt.susec);
+-    if (retval)
+-        return retval;
+-    errpkt.error = KRB_ERR_RESPONSE_TOO_BIG;
+-    errpkt.server = tgs_server;
+-    errpkt.client = NULL;
+-    errpkt.text.length = 0;
+-    errpkt.text.data = 0;
+-    errpkt.e_data.length = 0;
+-    errpkt.e_data.data = 0;
+-    scratch = malloc(sizeof(*scratch));
+-    if (scratch == NULL)
+-        return ENOMEM;
+-    retval = krb5_mk_error(kdc_context, &errpkt, scratch);
+-    if (retval) {
+-        free(scratch);
+-        return retval;
+-    }
+-
+-    *out = scratch;
+-    return 0;
+-}
+ 
+ krb5_context get_context(void *handle)
+ {
diff --git a/SOURCES/Fix-some-broken-tests-for-Python-3.patch b/SOURCES/Fix-some-broken-tests-for-Python-3.patch
new file mode 100644
index 0000000..42825b0
--- /dev/null
+++ b/SOURCES/Fix-some-broken-tests-for-Python-3.patch
@@ -0,0 +1,81 @@
+From eb60404564852a262d4082c3e38086742afb1bd9 Mon Sep 17 00:00:00 2001
+From: Robbie Harwood <rharwood@redhat.com>
+Date: Mon, 16 Jul 2018 16:44:01 -0400
+Subject: [PATCH] Fix some broken tests for Python 3
+
+Remove python2 dependencies in .travis.yml and add python3-paste.
+Convert t_daemon.py and jsonwalker.py to python3.  csjon has no
+python3 version, so replace it with python's built-in JSON module.
+
+python3-pyrad isn't available for Trusty, so krad and OTP tests are
+currently not exercised by Travis.
+
+[ghudson@mit.edu: squashed commits; edited commit message]
+
+ticket: 8710
+(cherry picked from commit d1fb3551c0dff5c3e6555b31fcbf04ff04d577fe)
+[rharwood@redhat.com: .travis.yml]
+---
+ src/lib/krad/t_daemon.py |  2 +-
+ src/tests/jsonwalker.py  | 16 +++++-----------
+ 2 files changed, 6 insertions(+), 12 deletions(-)
+
+diff --git a/src/lib/krad/t_daemon.py b/src/lib/krad/t_daemon.py
+index 7d7a5d0c8..7668cd7f8 100755
+--- a/src/lib/krad/t_daemon.py
++++ b/src/lib/krad/t_daemon.py
+@@ -23,7 +23,7 @@
+ # NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ 
+-import StringIO
++from io import StringIO
+ import os
+ import sys
+ import signal
+diff --git a/src/tests/jsonwalker.py b/src/tests/jsonwalker.py
+index 7a0675e08..1880363d2 100644
+--- a/src/tests/jsonwalker.py
++++ b/src/tests/jsonwalker.py
+@@ -1,10 +1,5 @@
+ import sys
+-try:
+-    import cjson
+-except ImportError:
+-    print("Warning: skipping audit log verification because the cjson module" \
+-          " is unavailable")
+-    sys.exit(0)
++import json
+ from collections import defaultdict
+ from optparse import OptionParser
+ 
+@@ -72,7 +67,7 @@ class Parser(object):
+         """
+         Generator that works through dictionary.
+         """
+-        for a,v in adict.iteritems():
++        for a,v in adict.items():
+             if isinstance(v,dict):
+                 for (attrpath,u) in self._walk(v):
+                     yield (a+'.'+attrpath,u)
+@@ -93,17 +88,16 @@ if __name__ == '__main__':
+         with open(options.filename, 'r') as f:
+             content = list()
+             for l in f:
+-                content.append(cjson.decode(l.rstrip()))
++                content.append(json.loads(l.rstrip()))
+         f.close()
+     else:
+-        print('Input file in jason format is required')
++        print('Input file in JSON format is required')
+         exit()
+ 
+     defaults = None
+     if options.defaults is not None:
+         with open(options.defaults, 'r') as f:
+-            defaults = cjson.decode(f.read())
+-        f.close()
++            defaults = json.load(f)
+ 
+     # run test
+     p = Parser(defaults)
diff --git a/SOURCES/Implement-k5_buf_init_dynamic_zap.patch b/SOURCES/Implement-k5_buf_init_dynamic_zap.patch
new file mode 100644
index 0000000..28fd16b
--- /dev/null
+++ b/SOURCES/Implement-k5_buf_init_dynamic_zap.patch
@@ -0,0 +1,149 @@
+From 3d651a6e234bed4c4d4865a56c5fa47dab89a5a6 Mon Sep 17 00:00:00 2001
+From: Greg Hudson <ghudson@mit.edu>
+Date: Mon, 26 Mar 2018 11:12:39 -0400
+Subject: [PATCH] Implement k5_buf_init_dynamic_zap
+
+Add a variant of dynamic k5buf objects which zeroes memory when
+reallocating or freeing the buffer.
+
+(cherry picked from commit 8ee8246c14702dc03b02e31b9fb5b7c2bb674bfb)
+---
+ src/include/k5-buf.h                          |  6 ++-
+ src/util/support/k5buf.c                      | 41 +++++++++++++++----
+ src/util/support/libkrb5support-fixed.exports |  1 +
+ 3 files changed, 39 insertions(+), 9 deletions(-)
+
+diff --git a/src/include/k5-buf.h b/src/include/k5-buf.h
+index 1223916a6..48e2a7d53 100644
+--- a/src/include/k5-buf.h
++++ b/src/include/k5-buf.h
+@@ -45,7 +45,7 @@
+  */
+ 
+ /* Buffer type values */
+-enum k5buftype { K5BUF_ERROR, K5BUF_FIXED, K5BUF_DYNAMIC };
++enum k5buftype { K5BUF_ERROR, K5BUF_FIXED, K5BUF_DYNAMIC, K5BUF_DYNAMIC_ZAP };
+ 
+ struct k5buf {
+     enum k5buftype buftype;
+@@ -63,6 +63,10 @@ void k5_buf_init_fixed(struct k5buf *buf, char *data, size_t space);
+ /* Initialize a k5buf using an internally allocated dynamic buffer. */
+ void k5_buf_init_dynamic(struct k5buf *buf);
+ 
++/* Initialize a k5buf using an internally allocated dynamic buffer, zeroing
++ * memory when reallocating or freeing. */
++void k5_buf_init_dynamic_zap(struct k5buf *buf);
++
+ /* Add a C string to BUF. */
+ void k5_buf_add(struct k5buf *buf, const char *data);
+ 
+diff --git a/src/util/support/k5buf.c b/src/util/support/k5buf.c
+index 35978f238..b2b5e5b67 100644
+--- a/src/util/support/k5buf.c
++++ b/src/util/support/k5buf.c
+@@ -37,7 +37,7 @@
+ /*
+  * Structure invariants:
+  *
+- * buftype is K5BUF_FIXED, K5BUF_DYNAMIC, or K5BUF_ERROR
++ * buftype is K5BUF_FIXED, K5BUF_DYNAMIC, K5BUF_DYNAMIC_ZAP, or K5BUF_ERROR
+  * if buftype is K5BUF_ERROR, the other fields are NULL or 0
+  * if buftype is not K5BUF_ERROR:
+  *   space > 0
+@@ -77,22 +77,35 @@ ensure_space(struct k5buf *buf, size_t len)
+         return 1;
+     if (buf->buftype == K5BUF_FIXED) /* Can't resize a fixed buffer. */
+         goto error_exit;
+-    assert(buf->buftype == K5BUF_DYNAMIC);
++    assert(buf->buftype == K5BUF_DYNAMIC || buf->buftype == K5BUF_DYNAMIC_ZAP);
+     new_space = buf->space * 2;
+     while (new_space - buf->len - 1 < len) {
+         if (new_space > SIZE_MAX / 2)
+             goto error_exit;
+         new_space *= 2;
+     }
+-    new_data = realloc(buf->data, new_space);
+-    if (new_data == NULL)
+-        goto error_exit;
++    if (buf->buftype == K5BUF_DYNAMIC_ZAP) {
++        /* realloc() could leave behind a partial copy of sensitive data. */
++        new_data = malloc(new_space);
++        if (new_data == NULL)
++            goto error_exit;
++        memcpy(new_data, buf->data, buf->len);
++        new_data[buf->len] = '\0';
++        zap(buf->data, buf->len);
++        free(buf->data);
++    } else {
++        new_data = realloc(buf->data, new_space);
++        if (new_data == NULL)
++            goto error_exit;
++    }
+     buf->data = new_data;
+     buf->space = new_space;
+     return 1;
+ 
+ error_exit:
+-    if (buf->buftype == K5BUF_DYNAMIC)
++    if (buf->buftype == K5BUF_DYNAMIC_ZAP)
++        zap(buf->data, buf->len);
++    if (buf->buftype == K5BUF_DYNAMIC_ZAP || buf->buftype == K5BUF_DYNAMIC)
+         free(buf->data);
+     set_error(buf);
+     return 0;
+@@ -123,6 +136,14 @@ k5_buf_init_dynamic(struct k5buf *buf)
+     *endptr(buf) = '\0';
+ }
+ 
++void
++k5_buf_init_dynamic_zap(struct k5buf *buf)
++{
++    k5_buf_init_dynamic(buf);
++    if (buf->buftype == K5BUF_DYNAMIC)
++        buf->buftype = K5BUF_DYNAMIC_ZAP;
++}
++
+ void
+ k5_buf_add(struct k5buf *buf, const char *data)
+ {
+@@ -163,7 +184,7 @@ k5_buf_add_vfmt(struct k5buf *buf, const char *fmt, va_list ap)
+     }
+ 
+     /* Optimistically format the data directly into the dynamic buffer. */
+-    assert(buf->buftype == K5BUF_DYNAMIC);
++    assert(buf->buftype == K5BUF_DYNAMIC || buf->buftype == K5BUF_DYNAMIC_ZAP);
+     va_copy(apcopy, ap);
+     r = vsnprintf(endptr(buf), remaining, fmt, apcopy);
+     va_end(apcopy);
+@@ -197,6 +218,8 @@ k5_buf_add_vfmt(struct k5buf *buf, const char *fmt, va_list ap)
+         memcpy(endptr(buf), tmp, r + 1);
+         buf->len += r;
+     }
++    if (buf->buftype == K5BUF_DYNAMIC_ZAP)
++        zap(tmp, strlen(tmp));
+     free(tmp);
+ }
+ 
+@@ -241,7 +264,9 @@ k5_buf_free(struct k5buf *buf)
+ {
+     if (buf->buftype == K5BUF_ERROR)
+         return;
+-    assert(buf->buftype == K5BUF_DYNAMIC);
++    assert(buf->buftype == K5BUF_DYNAMIC || buf->buftype == K5BUF_DYNAMIC_ZAP);
++    if (buf->buftype == K5BUF_DYNAMIC_ZAP)
++        zap(buf->data, buf->len);
+     free(buf->data);
+     set_error(buf);
+ }
+diff --git a/src/util/support/libkrb5support-fixed.exports b/src/util/support/libkrb5support-fixed.exports
+index cb9bf0826..a5e2ade04 100644
+--- a/src/util/support/libkrb5support-fixed.exports
++++ b/src/util/support/libkrb5support-fixed.exports
+@@ -3,6 +3,7 @@ k5_base64_encode
+ k5_bcmp
+ k5_buf_init_fixed
+ k5_buf_init_dynamic
++k5_buf_init_dynamic_zap
+ k5_buf_add
+ k5_buf_add_len
+ k5_buf_add_fmt
diff --git a/SOURCES/In-FIPS-mode-add-plaintext-fallback-for-RC4-usages-a.patch b/SOURCES/In-FIPS-mode-add-plaintext-fallback-for-RC4-usages-a.patch
new file mode 100644
index 0000000..b01f0bc
--- /dev/null
+++ b/SOURCES/In-FIPS-mode-add-plaintext-fallback-for-RC4-usages-a.patch
@@ -0,0 +1,354 @@
+From e04d483890496a1747f3cdb20a4df5285147f59b Mon Sep 17 00:00:00 2001
+From: Robbie Harwood <rharwood@redhat.com>
+Date: Tue, 31 Jul 2018 13:47:26 -0400
+Subject: [PATCH] In FIPS mode, add plaintext fallback for RC4 usages and taint
+
+(cherry picked from commit a327e3bf5b992ac829c7b2d3317fb7d93b1c88ef)
+(cherry picked from commit 2bd85da058d2d73eb2818a8e64656fec9b21b3c3)
+---
+ src/lib/krad/attr.c      | 45 +++++++++++++++++++++++++++++-----------
+ src/lib/krad/attrset.c   |  5 +++--
+ src/lib/krad/internal.h  | 13 ++++++++++--
+ src/lib/krad/packet.c    | 22 +++++++++++---------
+ src/lib/krad/remote.c    | 10 +++++++--
+ src/lib/krad/t_attr.c    |  3 ++-
+ src/lib/krad/t_attrset.c |  4 +++-
+ 7 files changed, 72 insertions(+), 30 deletions(-)
+
+diff --git a/src/lib/krad/attr.c b/src/lib/krad/attr.c
+index 9c13d9d75..275327e67 100644
+--- a/src/lib/krad/attr.c
++++ b/src/lib/krad/attr.c
+@@ -30,6 +30,7 @@
+ #include <k5-int.h>
+ #include "internal.h"
+ 
++#include <openssl/crypto.h>
+ #include <string.h>
+ 
+ /* RFC 2865 */
+@@ -38,7 +39,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 +53,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},
+@@ -128,7 +132,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;
+@@ -154,8 +159,14 @@ 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 (FIPS_mode()) {
++            /* 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);
+@@ -180,7 +191,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;
+@@ -204,8 +216,14 @@ 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 (FIPS_mode()) {
++            /* 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);
+@@ -248,7 +266,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;
+ 
+@@ -265,7 +283,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
+@@ -274,6 +293,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)
+@@ -288,7 +308,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 03c613716..d89982a13 100644
+--- a/src/lib/krad/attrset.c
++++ b/src/lib/krad/attrset.c
+@@ -167,7 +167,8 @@ krad_attrset_copy(const krad_attrset *set, krad_attrset **copy)
+ krb5_error_code
+ kr_attrset_encode(const krad_attrset *set, const char *secret,
+                   const unsigned char *auth,
+-                  unsigned char outbuf[MAX_ATTRSETSIZE], size_t *outlen)
++                  unsigned char outbuf[MAX_ATTRSETSIZE], size_t *outlen,
++                  krb5_boolean *is_fips)
+ {
+     unsigned char buffer[MAX_ATTRSIZE];
+     krb5_error_code retval;
+@@ -181,7 +182,7 @@ kr_attrset_encode(const krad_attrset *set, const char *secret,
+ 
+     K5_TAILQ_FOREACH(a, &set->list, list) {
+         retval = kr_attr_encode(set->ctx, secret, auth, a->type, &a->attr,
+-                                buffer, &attrlen);
++                                buffer, &attrlen, is_fips);
+         if (retval != 0)
+             return retval;
+ 
+diff --git a/src/lib/krad/internal.h b/src/lib/krad/internal.h
+index 996a89372..a53ce31ce 100644
+--- a/src/lib/krad/internal.h
++++ b/src/lib/krad/internal.h
+@@ -49,6 +49,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);
+@@ -57,7 +64,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
+@@ -69,7 +77,8 @@ kr_attr_decode(krb5_context ctx, const char *secret, const unsigned char *auth,
+ krb5_error_code
+ kr_attrset_encode(const krad_attrset *set, const char *secret,
+                   const unsigned char *auth,
+-                  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
+diff --git a/src/lib/krad/packet.c b/src/lib/krad/packet.c
+index c597174b6..794ac84c4 100644
+--- a/src/lib/krad/packet.c
++++ b/src/lib/krad/packet.c
+@@ -32,6 +32,7 @@
+ #include <string.h>
+ 
+ #include <arpa/inet.h>
++#include <openssl/crypto.h>
+ 
+ typedef unsigned char uchar;
+ 
+@@ -53,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;
+@@ -187,8 +182,13 @@ 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 (FIPS_mode()) {
++        /* 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;
+@@ -276,7 +276,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), pkt_attr(pkt),
+-                               &attrset_len);
++                               &attrset_len, &pkt->is_fips);
+     if (retval != 0)
+         goto error;
+ 
+@@ -314,7 +314,7 @@ 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), pkt_attr(pkt),
+-                               &attrset_len);
++                               &attrset_len, &pkt->is_fips);
+     if (retval != 0)
+         goto error;
+ 
+@@ -451,6 +451,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 437f7e91a..0f90443ce 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)
+@@ -359,7 +359,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;
+             }
+@@ -455,6 +455,12 @@ kr_remote_send(krad_remote *rr, krad_code code, krad_attrset *attrs,
+                                      (krad_packet_iter_cb)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 eb2a780c8..4d285ad9d 100644
+--- a/src/lib/krad/t_attr.c
++++ b/src/lib/krad/t_attr.c
+@@ -50,6 +50,7 @@ main()
+     const char *tmp;
+     krb5_data in;
+     size_t len;
++    krb5_boolean is_fips = FALSE;
+ 
+     noerror(krb5_init_context(&ctx));
+ 
+@@ -73,7 +74,7 @@ main()
+     in = string2data((char *)decoded);
+     retval = kr_attr_encode(ctx, secret, auth,
+                             krad_attr_name2num("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 7928335ca..0f9576253 100644
+--- a/src/lib/krad/t_attrset.c
++++ b/src/lib/krad/t_attrset.c
+@@ -49,6 +49,7 @@ main()
+     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()
+     noerror(krad_attrset_add(set, krad_attr_name2num("User-Password"), &tmp));
+ 
+     /* Encode attrset. */
+-    noerror(kr_attrset_encode(set, "foo", auth, buffer, &encode_len));
++    noerror(kr_attrset_encode(set, "foo", auth, buffer, &encode_len,
++                              &is_fips));
+     krad_attrset_free(set);
+ 
+     /* Manually encode User-Name. */
diff --git a/SOURCES/Include-etype-info-in-for-hardware-preauth-hints.patch b/SOURCES/Include-etype-info-in-for-hardware-preauth-hints.patch
new file mode 100644
index 0000000..82aba62
--- /dev/null
+++ b/SOURCES/Include-etype-info-in-for-hardware-preauth-hints.patch
@@ -0,0 +1,38 @@
+From bbc68d1657306a61a7646dd7b9690f67705e24be Mon Sep 17 00:00:00 2001
+From: Greg Hudson <ghudson@mit.edu>
+Date: Wed, 3 Jan 2018 11:59:14 -0500
+Subject: [PATCH] Include etype-info in for hardware preauth hints
+
+If a principal has the requires_hwauth bit set, include PA-ETYPE-INFO
+or PA-ETYPE-INFO2 padata in the PREAUTH_REQUIRED error, as preauth
+mechs involving hardware tokens may also use the principal's Kerberos
+password.
+
+ticket: 8629
+(cherry picked from commit ba92da05accc524b8037453b63ced1a6c65fd2a1)
+---
+ src/kdc/kdc_preauth.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/src/kdc/kdc_preauth.c b/src/kdc/kdc_preauth.c
+index 81d0b8cff..739c5e776 100644
+--- a/src/kdc/kdc_preauth.c
++++ b/src/kdc/kdc_preauth.c
+@@ -144,7 +144,7 @@ static preauth_system static_preauth_systems[] = {
+     {
+         "etype-info",
+         KRB5_PADATA_ETYPE_INFO,
+-        0,
++        PA_HARDWARE,
+         NULL,
+         NULL,
+         NULL,
+@@ -155,7 +155,7 @@ static preauth_system static_preauth_systems[] = {
+     {
+         "etype-info2",
+         KRB5_PADATA_ETYPE_INFO2,
+-        0,
++        PA_HARDWARE,
+         NULL,
+         NULL,
+         NULL,
diff --git a/SOURCES/Include-preauth-name-in-trace-output-if-possible.patch b/SOURCES/Include-preauth-name-in-trace-output-if-possible.patch
new file mode 100644
index 0000000..fe88920
--- /dev/null
+++ b/SOURCES/Include-preauth-name-in-trace-output-if-possible.patch
@@ -0,0 +1,514 @@
+From b623881ec039bffc758f53906f7e4f9b884f1cf4 Mon Sep 17 00:00:00 2001
+From: Robbie Harwood <rharwood@redhat.com>
+Date: Thu, 15 Mar 2018 14:37:28 -0400
+Subject: [PATCH] Include preauth name in trace output if possible
+
+Add a {patype} trace format specifier for a single pa-type value.  Add
+a krb5_preauthtype to string conversion function to trace machinery
+and use it when formatting {patype} or {patypes}.
+
+[ghudson@mit.edu: wrote conversion function; edited commit message]
+
+ticket: 8653 (new)
+(cherry picked from commit 9c68fe39b018666eabe033b639c1f35d03ba51c7)
+---
+ src/include/k5-trace.h      |  17 +--
+ src/lib/krb5/os/t_trace.ref |   2 +-
+ src/lib/krb5/os/trace.c     |  61 +++++++++-
+ src/tests/t_pkinit.py       |  43 +++----
+ src/tests/t_preauth.py      | 216 ++++++++++++++++++------------------
+ 5 files changed, 200 insertions(+), 139 deletions(-)
+
+diff --git a/src/include/k5-trace.h b/src/include/k5-trace.h
+index 390a8b7d6..5f7eb9517 100644
+--- a/src/include/k5-trace.h
++++ b/src/include/k5-trace.h
+@@ -75,6 +75,7 @@
+  *   {cksum}       const krb5_checksum *, display cksumtype and hex checksum
+  *   {princ}       krb5_principal, unparse and display
+  *   {ptype}       krb5_int32, krb5_principal type, display name
++ *   {patype}      krb5_preauthtype, a single padata type number
+  *   {patypes}     krb5_pa_data **, display list of padata type numbers
+  *   {etype}       krb5_enctype, display shortest name of enctype
+  *   {etypes}      krb5_enctype *, display list of enctypes
+@@ -232,14 +233,14 @@ void krb5int_trace(krb5_context context, const char *fmt, ...);
+ #define TRACE_INIT_CREDS_PREAUTH_DECRYPT_FAIL(c, code)                  \
+     TRACE(c, "Decrypt with preauth AS key failed: {kerr}", code)
+ #define TRACE_INIT_CREDS_PREAUTH_MORE(c, patype)                \
+-    TRACE(c, "Continuing preauth mech {int}", (int)patype)
++    TRACE(c, "Continuing preauth mech {patype}", patype)
+ #define TRACE_INIT_CREDS_PREAUTH_NONE(c)        \
+     TRACE(c, "Sending unauthenticated request")
+ #define TRACE_INIT_CREDS_PREAUTH_OPTIMISTIC(c)  \
+     TRACE(c, "Attempting optimistic preauth")
+ #define TRACE_INIT_CREDS_PREAUTH_TRYAGAIN(c, patype, code)              \
+-    TRACE(c, "Recovering from KDC error {int} using preauth mech {int}", \
+-          (int)patype, (int)code)
++    TRACE(c, "Recovering from KDC error {int} using preauth mech {patype}", \
++          patype, (int)code)
+ #define TRACE_INIT_CREDS_RESTART_FAST(c)        \
+     TRACE(c, "Restarting to upgrade to FAST")
+ #define TRACE_INIT_CREDS_RESTART_PREAUTH_FAILED(c)                      \
+@@ -290,7 +291,7 @@ void krb5int_trace(krb5_context context, const char *fmt, ...);
+ 
+ #define TRACE_PREAUTH_CONFLICT(c, name1, name2, patype)                 \
+     TRACE(c, "Preauth module {str} conflicts with module {str} for pa " \
+-          "type {int}", name1, name2, (int) patype)
++          "type {patype}", name1, name2, patype)
+ #define TRACE_PREAUTH_COOKIE(c, len, data)                      \
+     TRACE(c, "Received cookie: {lenstr}", (size_t) len, data)
+ #define TRACE_PREAUTH_ENC_TS_KEY_GAK(c, keyblock)                       \
+@@ -302,8 +303,8 @@ void krb5int_trace(krb5_context context, const char *fmt, ...);
+     TRACE(c, "Selected etype info: etype {etype}, salt \"{data}\", " \
+           "params \"{data}\"", etype, salt, s2kparams)
+ #define TRACE_PREAUTH_INFO_FAIL(c, patype, code)                        \
+-    TRACE(c, "Preauth builtin info function failure, type={int}: {kerr}", \
+-          (int) patype, code)
++    TRACE(c, "Preauth builtin info function failure, type={patype}: {kerr}", \
++          patype, code)
+ #define TRACE_PREAUTH_INPUT(c, padata)                          \
+     TRACE(c, "Processing preauth types: {patypes}", padata)
+ #define TRACE_PREAUTH_OUTPUT(c, padata)                                 \
+@@ -314,8 +315,8 @@ void krb5int_trace(krb5_context context, const char *fmt, ...);
+ #define TRACE_PREAUTH_SAM_KEY_GAK(c, keyblock)                  \
+     TRACE(c, "AS key obtained for SAM: {keyblock}", keyblock)
+ #define TRACE_PREAUTH_SALT(c, salt, patype)                          \
+-    TRACE(c, "Received salt \"{data}\" via padata type {int}", salt, \
+-          (int) patype)
++    TRACE(c, "Received salt \"{data}\" via padata type {patype}", salt, \
++          patype)
+ #define TRACE_PREAUTH_SKIP(c, name, patype)                           \
+     TRACE(c, "Skipping previously used preauth module {str} ({int})", \
+           name, (int) patype)
+diff --git a/src/lib/krb5/os/t_trace.ref b/src/lib/krb5/os/t_trace.ref
+index ca5818a1e..bd5d9b6b6 100644
+--- a/src/lib/krb5/os/t_trace.ref
++++ b/src/lib/krb5/os/t_trace.ref
+@@ -38,7 +38,7 @@ int, krb5_principal type: Windows 2000 UPN and SID
+ int, krb5_principal type: NT 4 style name
+ int, krb5_principal type: NT 4 style name and SID
+ int, krb5_principal type: ?
+-krb5_pa_data **, display list of padata type numbers: 3, 0
++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: des-cbc-crc
+ krb5_enctype *, display list of enctypes: 5, rc4-hmac-exp, 511
+diff --git a/src/lib/krb5/os/trace.c b/src/lib/krb5/os/trace.c
+index 779f184cb..10b4f0c14 100644
+--- a/src/lib/krb5/os/trace.c
++++ b/src/lib/krb5/os/trace.c
+@@ -123,6 +123,50 @@ principal_type_string(krb5_int32 type)
+     }
+ }
+ 
++static char *
++padata_type_string(krb5_preauthtype type)
++{
++    switch (type) {
++    case KRB5_PADATA_TGS_REQ: return "PA-TGS-REQ";
++    case KRB5_PADATA_ENC_TIMESTAMP: return "PA-ENC-TIMESTAMP";
++    case KRB5_PADATA_PW_SALT: return "PA-PW-SALT";
++    case KRB5_PADATA_ENC_UNIX_TIME: return "PA-ENC-UNIX-TIME";
++    case KRB5_PADATA_ENC_SANDIA_SECURID: return "PA-SANDIA-SECUREID";
++    case KRB5_PADATA_SESAME: return "PA-SESAME";
++    case KRB5_PADATA_OSF_DCE: return "PA-OSF-DCE";
++    case KRB5_CYBERSAFE_SECUREID: return "PA-CYBERSAFE-SECUREID";
++    case KRB5_PADATA_AFS3_SALT: return "PA-AFS3-SALT";
++    case KRB5_PADATA_ETYPE_INFO: return "PA-ETYPE-INFO";
++    case KRB5_PADATA_SAM_CHALLENGE: return "PA-SAM-CHALLENGE";
++    case KRB5_PADATA_SAM_RESPONSE: return "PA-SAM-RESPONSE";
++    case KRB5_PADATA_PK_AS_REQ_OLD: return "PA-PK-AS-REQ_OLD";
++    case KRB5_PADATA_PK_AS_REP_OLD: return "PA-PK-AS-REP_OLD";
++    case KRB5_PADATA_PK_AS_REQ: return "PA-PK-AS-REQ";
++    case KRB5_PADATA_PK_AS_REP: return "PA-PK-AS-REP";
++    case KRB5_PADATA_ETYPE_INFO2: return "PA-ETYPE-INFO2";
++    case KRB5_PADATA_SVR_REFERRAL_INFO: return "PA-SVR-REFERRAL-INFO";
++    case KRB5_PADATA_SAM_REDIRECT: return "PA-SAM-REDIRECT";
++    case KRB5_PADATA_GET_FROM_TYPED_DATA: return "PA-GET-FROM-TYPED-DATA";
++    case KRB5_PADATA_SAM_CHALLENGE_2: return "PA-SAM-CHALLENGE2";
++    case KRB5_PADATA_SAM_RESPONSE_2: return "PA-SAM-RESPONSE2";
++    case KRB5_PADATA_PAC_REQUEST: return "PA-PAC-REQUEST";
++    case KRB5_PADATA_FOR_USER: return "PA-FOR_USER";
++    case KRB5_PADATA_S4U_X509_USER: return "PA-FOR-X509-USER";
++    case KRB5_PADATA_AS_CHECKSUM: return "PA-AS-CHECKSUM";
++    case KRB5_PADATA_FX_COOKIE: return "PA-FX-COOKIE";
++    case KRB5_PADATA_FX_FAST: return "PA-FX-FAST";
++    case KRB5_PADATA_FX_ERROR: return "PA-FX-ERROR";
++    case KRB5_PADATA_ENCRYPTED_CHALLENGE: return "PA-ENCRYPTED-CHALLENGE";
++    case KRB5_PADATA_OTP_CHALLENGE: return "PA-OTP-CHALLENGE";
++    case KRB5_PADATA_OTP_REQUEST: return "PA-OTP-REQUEST";
++    case KRB5_PADATA_OTP_PIN_CHANGE: return "PA-OTP-PIN-CHANGE";
++    case KRB5_PADATA_PKINIT_KX: return "PA-PKINIT-KX";
++    case KRB5_ENCPADATA_REQ_ENC_PA_REP: return "PA-REQ-ENC-PA-REP";
++    case KRB5_PADATA_AS_FRESHNESS: return "PA_AS_FRESHNESS";
++    default: return NULL;
++    }
++}
++
+ static char *
+ trace_format(krb5_context context, const char *fmt, va_list ap)
+ {
+@@ -140,6 +184,8 @@ trace_format(krb5_context context, const char *fmt, va_list ap)
+     krb5_key key;
+     const krb5_checksum *cksum;
+     krb5_pa_data **padata;
++    krb5_preauthtype pa_type;
++    const char *name;
+     krb5_ccache ccache;
+     krb5_keytab keytab;
+     krb5_creds *creds;
+@@ -271,10 +317,23 @@ trace_format(krb5_context context, const char *fmt, va_list ap)
+             if (padata == NULL || *padata == NULL)
+                 k5_buf_add(&buf, "(empty)");
+             for (; padata != NULL && *padata != NULL; padata++) {
+-                k5_buf_add_fmt(&buf, "%d", (int)(*padata)->pa_type);
++                pa_type = (*padata)->pa_type;
++                name = padata_type_string(pa_type);
++                if (name != NULL)
++                    k5_buf_add_fmt(&buf, "%s (%d)", name, (int)pa_type);
++                else
++                    k5_buf_add_fmt(&buf, "%d", (int)pa_type);
++
+                 if (*(padata + 1) != NULL)
+                     k5_buf_add(&buf, ", ");
+             }
++        } else if (strcmp(tmpbuf, "patype") == 0) {
++            pa_type = va_arg(ap, krb5_preauthtype);
++            name = padata_type_string(pa_type);
++            if (name != NULL)
++                k5_buf_add_fmt(&buf, "%s (%d)", name, (int)pa_type);
++            else
++                k5_buf_add_fmt(&buf, "%d", (int)pa_type);
+         } else if (strcmp(tmpbuf, "etype") == 0) {
+             etype = va_arg(ap, krb5_enctype);
+             if (krb5_enctype_to_name(etype, TRUE, tmpbuf, sizeof(tmpbuf)) == 0)
+diff --git a/src/tests/t_pkinit.py b/src/tests/t_pkinit.py
+index 5bc60cb1e..0e964c689 100755
+--- a/src/tests/t_pkinit.py
++++ b/src/tests/t_pkinit.py
+@@ -164,18 +164,19 @@ realm.stop_kdc()
+ realm.start_kdc()
+ 
+ # Run the basic test - PKINIT with FILE: identity, with no password on the key.
++msgs = ('Sending unauthenticated request',
++        '/Additional pre-authentication required',
++        'Preauthenticating using KDC method data',
++        'PKINIT client received freshness token from KDC',
++        'PKINIT loading CA certs and CRLs from FILE',
++        'PKINIT client making DH request',
++        ' preauth for next request: PA-FX-COOKIE (133), PA-PK-AS-REQ (16)',
++        'PKINIT client verified DH reply',
++        'PKINIT client found id-pkinit-san in KDC cert',
++        'PKINIT client matched KDC principal krbtgt/')
+ realm.kinit(realm.user_princ,
+             flags=['-X', 'X509_user_identity=%s' % file_identity],
+-            expected_trace=('Sending unauthenticated request',
+-                            '/Additional pre-authentication required',
+-                            'Preauthenticating using KDC method data',
+-                            'PKINIT client received freshness token from KDC',
+-                            'PKINIT loading CA certs and CRLs from FILE',
+-                            'PKINIT client making DH request',
+-                            'Produced preauth for next request: 133, 16',
+-                            'PKINIT client verified DH reply',
+-                            'PKINIT client found id-pkinit-san in KDC cert',
+-                            'PKINIT client matched KDC principal krbtgt/'))
++            expected_trace=msgs)
+ realm.klist(realm.user_princ)
+ realm.run([kvno, realm.host_princ])
+ 
+@@ -194,19 +195,19 @@ minbits_kdc_conf = {'realms': {'$realm': {'pkinit_dh_min_bits': '4096'}}}
+ minbits_env = realm.special_env('restrict', True, kdc_conf=minbits_kdc_conf)
+ realm.stop_kdc()
+ realm.start_kdc(env=minbits_env)
+-expected_trace = ('Sending unauthenticated request',
+-                  '/Additional pre-authentication required',
+-                  'Preauthenticating using KDC method data',
+-                  'Preauth module pkinit (16) (real) returned: 0/Success',
+-                  'Produced preauth for next request: 133, 16',
+-                  '/Key parameters not accepted',
+-                  'Preauth tryagain input types (16): 109, 133',
+-                  'trying again with KDC-provided parameters',
+-                  'Preauth module pkinit (16) tryagain returned: 0/Success',
+-                  'Followup preauth for next request: 16, 133')
++msgs = ('Sending unauthenticated request',
++        '/Additional pre-authentication required',
++        'Preauthenticating using KDC method data',
++        'Preauth module pkinit (16) (real) returned: 0/Success',
++        ' preauth for next request: PA-FX-COOKIE (133), PA-PK-AS-REQ (16)',
++        '/Key parameters not accepted',
++        'Preauth tryagain input types (16): 109, PA-FX-COOKIE (133)',
++        'trying again with KDC-provided parameters',
++        'Preauth module pkinit (16) tryagain returned: 0/Success',
++        ' preauth for next request: PA-PK-AS-REQ (16), PA-FX-COOKIE (133)')
+ realm.kinit(realm.user_princ,
+             flags=['-X', 'X509_user_identity=%s' % file_identity],
+-            expected_trace=expected_trace)
++            expected_trace=msgs)
+ 
+ # Test enforcement of required freshness tokens.  (We can leave
+ # freshness tokens required after this test.)
+diff --git a/src/tests/t_preauth.py b/src/tests/t_preauth.py
+index fec0bf619..efb3ea20d 100644
+--- a/src/tests/t_preauth.py
++++ b/src/tests/t_preauth.py
+@@ -18,15 +18,15 @@ realm.kinit('nokeyuser', password('user'), expected_code=1,
+ # PA-FX-COOKIE; 2 is encrypted timestamp.
+ 
+ # Test normal preauth flow.
+-expected_trace = ('Sending unauthenticated request',
+-                  '/Additional pre-authentication required',
+-                  'Preauthenticating using KDC method data',
+-                  'Processing preauth types:',
+-                  'Preauth module test (-123) (real) returned: 0/Success',
+-                  'Produced preauth for next request: 133, -123',
+-                  'Decrypted AS reply')
++msgs = ('Sending unauthenticated request',
++        '/Additional pre-authentication required',
++        'Preauthenticating using KDC method data',
++        'Processing preauth types:',
++        'Preauth module test (-123) (real) returned: 0/Success',
++        'Produced preauth for next request: PA-FX-COOKIE (133), -123',
++        'Decrypted AS reply')
+ realm.run(['./icred', realm.user_princ, password('user')],
+-          expected_msg='testval', expected_trace=expected_trace)
++          expected_msg='testval', expected_trace=msgs)
+ 
+ # Test successful optimistic preauth.
+ expected_trace = ('Attempting optimistic preauth',
+@@ -39,136 +39,136 @@ realm.run(['./icred', '-o', '-123', realm.user_princ, password('user')],
+ 
+ # Test optimistic preauth failing on client, followed by successful
+ # preauth using the same module.
+-expected_trace = ('Attempting optimistic preauth',
+-                  'Processing preauth types: -123',
+-                  '/induced optimistic fail',
+-                  'Sending unauthenticated request',
+-                  '/Additional pre-authentication required',
+-                  'Preauthenticating using KDC method data',
+-                  'Processing preauth types:',
+-                  'Preauth module test (-123) (real) returned: 0/Success',
+-                  'Produced preauth for next request: 133, -123',
+-                  'Decrypted AS reply')
++msgs = ('Attempting optimistic preauth',
++        'Processing preauth types: -123',
++        '/induced optimistic fail',
++        'Sending unauthenticated request',
++        '/Additional pre-authentication required',
++        'Preauthenticating using KDC method data',
++        'Processing preauth types:',
++        'Preauth module test (-123) (real) returned: 0/Success',
++        'Produced preauth for next request: PA-FX-COOKIE (133), -123',
++        'Decrypted AS reply')
+ realm.run(['./icred', '-o', '-123', '-X', 'fail_optimistic', realm.user_princ,
+            password('user')], expected_msg='testval',
+-          expected_trace=expected_trace)
++          expected_trace=msgs)
+ 
+ # Test optimistic preauth failing on KDC, followed by successful preauth
+ # using the same module.
+ realm.run([kadminl, 'setstr', realm.user_princ, 'failopt', 'yes'])
+-expected_trace = ('Attempting optimistic preauth',
+-                  'Processing preauth types: -123',
+-                  'Preauth module test (-123) (real) returned: 0/Success',
+-                  'Produced preauth for next request: -123',
+-                  '/Preauthentication failed',
+-                  'Preauthenticating using KDC method data',
+-                  'Processing preauth types:',
+-                  'Preauth module test (-123) (real) returned: 0/Success',
+-                  'Produced preauth for next request: 133, -123',
+-                  'Decrypted AS reply')
++msgs = ('Attempting optimistic preauth',
++        'Processing preauth types: -123',
++        'Preauth module test (-123) (real) returned: 0/Success',
++        'Produced preauth for next request: -123',
++        '/Preauthentication failed',
++        'Preauthenticating using KDC method data',
++        'Processing preauth types:',
++        'Preauth module test (-123) (real) returned: 0/Success',
++        'Produced preauth for next request: PA-FX-COOKIE (133), -123',
++        'Decrypted AS reply')
+ realm.run(['./icred', '-o', '-123', realm.user_princ, password('user')],
+-          expected_msg='testval', expected_trace=expected_trace)
++          expected_msg='testval', expected_trace=msgs)
+ realm.run([kadminl, 'delstr', realm.user_princ, 'failopt'])
+ 
+ # Test KDC_ERR_MORE_PREAUTH_DATA_REQUIRED and secure cookies.
+ realm.run([kadminl, 'setstr', realm.user_princ, '2rt', 'secondtrip'])
+-expected_trace = ('Sending unauthenticated request',
+-                  '/Additional pre-authentication required',
+-                  'Preauthenticating using KDC method data',
+-                  'Processing preauth types:',
+-                  'Preauth module test (-123) (real) returned: 0/Success',
+-                  'Produced preauth for next request: 133, -123',
+-                  '/More preauthentication data is required',
+-                  'Continuing preauth mech -123',
+-                  'Processing preauth types: -123, 133',
+-                  'Produced preauth for next request: 133, -123',
+-                  'Decrypted AS reply')
++msgs = ('Sending unauthenticated request',
++        '/Additional pre-authentication required',
++        'Preauthenticating using KDC method data',
++        'Processing preauth types:',
++        'Preauth module test (-123) (real) returned: 0/Success',
++        'Produced preauth for next request: PA-FX-COOKIE (133), -123',
++        '/More preauthentication data is required',
++        'Continuing preauth mech -123',
++        'Processing preauth types: -123, PA-FX-COOKIE (133)',
++        'Produced preauth for next request: PA-FX-COOKIE (133), -123',
++        'Decrypted AS reply')
+ realm.run(['./icred', realm.user_princ, password('user')],
+-          expected_msg='2rt: secondtrip', expected_trace=expected_trace)
++          expected_msg='2rt: secondtrip', expected_trace=msgs)
+ 
+ # Test client-side failure after KDC_ERR_MORE_PREAUTH_DATA_REQUIRED,
+ # falling back to encrypted timestamp.
+-expected_trace = ('Sending unauthenticated request',
+-                  '/Additional pre-authentication required',
+-                  'Preauthenticating using KDC method data',
+-                  'Processing preauth types:',
+-                  'Preauth module test (-123) (real) returned: 0/Success',
+-                  'Produced preauth for next request: 133, -123',
+-                  '/More preauthentication data is required',
+-                  'Continuing preauth mech -123',
+-                  'Processing preauth types: -123, 133',
+-                  '/induced 2rt fail',
+-                  'Preauthenticating using KDC method data',
+-                  'Processing preauth types:',
+-                  'Encrypted timestamp (for ',
+-                  'module encrypted_timestamp (2) (real) returned: 0/Success',
+-                  'Produced preauth for next request: 133, 2',
+-                  'Decrypted AS reply')
++msgs = ('Sending unauthenticated request',
++        '/Additional pre-authentication required',
++        'Preauthenticating using KDC method data',
++        'Processing preauth types:',
++        'Preauth module test (-123) (real) returned: 0/Success',
++        'Produced preauth for next request: PA-FX-COOKIE (133), -123',
++        '/More preauthentication data is required',
++        'Continuing preauth mech -123',
++        'Processing preauth types: -123, PA-FX-COOKIE (133)',
++        '/induced 2rt fail',
++        'Preauthenticating using KDC method data',
++        'Processing preauth types:',
++        'Encrypted timestamp (for ',
++        'module encrypted_timestamp (2) (real) returned: 0/Success',
++        'preauth for next request: PA-FX-COOKIE (133), PA-ENC-TIMESTAMP (2)',
++        'Decrypted AS reply')
+ realm.run(['./icred', '-X', 'fail_2rt', realm.user_princ, password('user')],
+-          expected_msg='2rt: secondtrip', expected_trace=expected_trace)
++          expected_msg='2rt: secondtrip', expected_trace=msgs)
+ 
+ # Test KDC-side failure after KDC_ERR_MORE_PREAUTH_DATA_REQUIRED,
+ # falling back to encrypted timestamp.
+ realm.run([kadminl, 'setstr', realm.user_princ, 'fail2rt', 'yes'])
+-expected_trace = ('Sending unauthenticated request',
+-                  '/Additional pre-authentication required',
+-                  'Preauthenticating using KDC method data',
+-                  'Processing preauth types:',
+-                  'Preauth module test (-123) (real) returned: 0/Success',
+-                  'Produced preauth for next request: 133, -123',
+-                  '/More preauthentication data is required',
+-                  'Continuing preauth mech -123',
+-                  'Processing preauth types: -123, 133',
+-                  'Preauth module test (-123) (real) returned: 0/Success',
+-                  'Produced preauth for next request: 133, -123',
+-                  '/Preauthentication failed',
+-                  'Preauthenticating using KDC method data',
+-                  'Processing preauth types:',
+-                  'Encrypted timestamp (for ',
+-                  'module encrypted_timestamp (2) (real) returned: 0/Success',
+-                  'Produced preauth for next request: 133, 2',
+-                  'Decrypted AS reply')
++msgs = ('Sending unauthenticated request',
++        '/Additional pre-authentication required',
++        'Preauthenticating using KDC method data',
++        'Processing preauth types:',
++        'Preauth module test (-123) (real) returned: 0/Success',
++        'Produced preauth for next request: PA-FX-COOKIE (133), -123',
++        '/More preauthentication data is required',
++        'Continuing preauth mech -123',
++        'Processing preauth types: -123, PA-FX-COOKIE (133)',
++        'Preauth module test (-123) (real) returned: 0/Success',
++        'Produced preauth for next request: PA-FX-COOKIE (133), -123',
++        '/Preauthentication failed',
++        'Preauthenticating using KDC method data',
++        'Processing preauth types:',
++        'Encrypted timestamp (for ',
++        'module encrypted_timestamp (2) (real) returned: 0/Success',
++        'preauth for next request: PA-FX-COOKIE (133), PA-ENC-TIMESTAMP (2)',
++        'Decrypted AS reply')
+ realm.run(['./icred', realm.user_princ, password('user')],
+-          expected_msg='2rt: secondtrip', expected_trace=expected_trace)
++          expected_msg='2rt: secondtrip', expected_trace=msgs)
+ realm.run([kadminl, 'delstr', realm.user_princ, 'fail2rt'])
+ 
+ # Test tryagain flow by inducing a KDC_ERR_ENCTYPE_NOSUPP error on the KDC.
+ realm.run([kadminl, 'setstr', realm.user_princ, 'err', 'testagain'])
+-expected_trace = ('Sending unauthenticated request',
+-                  '/Additional pre-authentication required',
+-                  'Preauthenticating using KDC method data',
+-                  'Processing preauth types:',
+-                  'Preauth module test (-123) (real) returned: 0/Success',
+-                  'Produced preauth for next request: 133, -123',
+-                  '/KDC has no support for encryption type',
+-                  'Recovering from KDC error 14 using preauth mech -123',
+-                  'Preauth tryagain input types (-123): -123, 133',
+-                  'Preauth module test (-123) tryagain returned: 0/Success',
+-                  'Followup preauth for next request: -123, 133',
+-                  'Decrypted AS reply')
++msgs = ('Sending unauthenticated request',
++        '/Additional pre-authentication required',
++        'Preauthenticating using KDC method data',
++        'Processing preauth types:',
++        'Preauth module test (-123) (real) returned: 0/Success',
++        'Produced preauth for next request: PA-FX-COOKIE (133), -123',
++        '/KDC has no support for encryption type',
++        'Recovering from KDC error 14 using preauth mech -123',
++        'Preauth tryagain input types (-123): -123, PA-FX-COOKIE (133)',
++        'Preauth module test (-123) tryagain returned: 0/Success',
++        'Followup preauth for next request: -123, PA-FX-COOKIE (133)',
++        'Decrypted AS reply')
+ realm.run(['./icred', realm.user_princ, password('user')],
+-          expected_msg='tryagain: testagain', expected_trace=expected_trace)
++          expected_msg='tryagain: testagain', expected_trace=msgs)
+ 
+ # Test a client-side tryagain failure, falling back to encrypted
+ # timestamp.
+-expected_trace = ('Sending unauthenticated request',
+-                  '/Additional pre-authentication required',
+-                  'Preauthenticating using KDC method data',
+-                  'Processing preauth types:',
+-                  'Preauth module test (-123) (real) returned: 0/Success',
+-                  'Produced preauth for next request: 133, -123',
+-                  '/KDC has no support for encryption type',
+-                  'Recovering from KDC error 14 using preauth mech -123',
+-                  'Preauth tryagain input types (-123): -123, 133',
+-                  '/induced tryagain fail',
+-                  'Preauthenticating using KDC method data',
+-                  'Processing preauth types:',
+-                  'Encrypted timestamp (for ',
+-                  'module encrypted_timestamp (2) (real) returned: 0/Success',
+-                  'Produced preauth for next request: 133, 2',
+-                  'Decrypted AS reply')
++msgs = ('Sending unauthenticated request',
++        '/Additional pre-authentication required',
++        'Preauthenticating using KDC method data',
++        'Processing preauth types:',
++        'Preauth module test (-123) (real) returned: 0/Success',
++        'Produced preauth for next request: PA-FX-COOKIE (133), -123',
++        '/KDC has no support for encryption type',
++        'Recovering from KDC error 14 using preauth mech -123',
++        'Preauth tryagain input types (-123): -123, PA-FX-COOKIE (133)',
++        '/induced tryagain fail',
++        'Preauthenticating using KDC method data',
++        'Processing preauth types:',
++        'Encrypted timestamp (for ',
++        'module encrypted_timestamp (2) (real) returned: 0/Success',
++        'preauth for next request: PA-FX-COOKIE (133), PA-ENC-TIMESTAMP (2)',
++        'Decrypted AS reply')
+ realm.run(['./icred', '-X', 'fail_tryagain', realm.user_princ,
+-           password('user')], expected_trace=expected_trace)
++           password('user')], expected_trace=msgs)
+ 
+ # Test that multiple stepwise initial creds operations can be
+ # performed with the same krb5_context, with proper tracking of
diff --git a/SOURCES/Log-when-non-root-ksu-authorization-fails.patch b/SOURCES/Log-when-non-root-ksu-authorization-fails.patch
new file mode 100644
index 0000000..704b5a9
--- /dev/null
+++ b/SOURCES/Log-when-non-root-ksu-authorization-fails.patch
@@ -0,0 +1,35 @@
+From 9dd3a84f324979c29e8ab4b472e98dfa73e6b290 Mon Sep 17 00:00:00 2001
+From: Robbie Harwood <rharwood@redhat.com>
+Date: Mon, 7 May 2018 16:42:59 -0400
+Subject: [PATCH] Log when non-root ksu authorization fails
+
+If non-root user attempts to ksu but is denied by policy, log to
+syslog at LOG_WARNING in keeping with other failure messages.
+
+ticket: 8270
+(cherry picked from commit 6cfa5c113e981f14f70ccafa20abfa5c46b665ba)
+---
+ src/clients/ksu/main.c | 10 ++++++++++
+ 1 file changed, 10 insertions(+)
+
+diff --git a/src/clients/ksu/main.c b/src/clients/ksu/main.c
+index c6321c01b..35ff8978f 100644
+--- a/src/clients/ksu/main.c
++++ b/src/clients/ksu/main.c
+@@ -417,6 +417,16 @@ main (argc, argv)
+     if (hp){
+         if (gb_err) fprintf(stderr, "%s", gb_err);
+         fprintf(stderr, _("account %s: authorization failed\n"), target_user);
++
++        if (cmd != NULL) {
++            syslog(LOG_WARNING,
++                   "Account %s: authorization for %s for execution of %s failed",
++                   target_user, source_user, cmd);
++        } else {
++            syslog(LOG_WARNING, "Account %s: authorization of %s failed",
++                   target_user, source_user);
++        }
++
+         exit(1);
+     }
+ 
diff --git a/SOURCES/Make-docs-build-python3-compatible.patch b/SOURCES/Make-docs-build-python3-compatible.patch
new file mode 100644
index 0000000..58a3e86
--- /dev/null
+++ b/SOURCES/Make-docs-build-python3-compatible.patch
@@ -0,0 +1,36 @@
+From 16c745b7e9e239535a8c71dc7022b477a5165e01 Mon Sep 17 00:00:00 2001
+From: Robbie Harwood <rharwood@redhat.com>
+Date: Wed, 13 Jun 2018 15:07:48 -0400
+Subject: [PATCH] Make docs build python3-compatible
+
+python3 removed execfile(), which we use for loading version data and
+paths information in docs.  Call exec() directly instead.
+
+ticket: 8692 (new)
+(cherry picked from commit a7c6d98480f1e33454173f88381921472d72f80a)
+---
+ doc/conf.py | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/doc/conf.py b/doc/conf.py
+index 25ba214a8..0555808e6 100644
+--- a/doc/conf.py
++++ b/doc/conf.py
+@@ -50,7 +50,7 @@ copyright = u'1985-2018, MIT'
+ # The version info for the project you're documenting, acts as replacement for
+ # |version| and |release|, also used in various other places throughout the
+ # built documents.
+-execfile("version.py")
++exec(open("version.py").read())
+ # The short X.Y version.
+ r_list = [r_major, r_minor]
+ if r_patch:
+@@ -238,7 +238,7 @@ if 'mansubs' in tags:
+     ckeytab = '``@CKTNAME@``'
+ elif 'pathsubs' in tags:
+     # Read configured paths from a file produced by the build system.
+-    execfile('paths.py')
++    exec(open("paths.py").read())
+ else:
+     bindir = ':ref:`BINDIR <paths>`'
+     sbindir = ':ref:`SBINDIR <paths>`'
diff --git a/SOURCES/Make-krb5kdc-p-affect-TCP-ports.patch b/SOURCES/Make-krb5kdc-p-affect-TCP-ports.patch
new file mode 100644
index 0000000..ac5bc30
--- /dev/null
+++ b/SOURCES/Make-krb5kdc-p-affect-TCP-ports.patch
@@ -0,0 +1,67 @@
+From 5587c1de938324faa1871e08ccfc835415acb443 Mon Sep 17 00:00:00 2001
+From: Greg Hudson <ghudson@mit.edu>
+Date: Tue, 17 Jul 2018 11:29:19 -0400
+Subject: [PATCH] Make krb5kdc -p affect TCP ports
+
+Now that the KDC listens for TCP connections by default (ticket 6731),
+the "-p" option should affect both UDP and TCP default listening
+ports.
+
+ticket: 8715 (new)
+(cherry picked from commit eb514587acc5c357bf0f554199bf0489b5515f8b)
+---
+ doc/admin/admin_commands/krb5kdc.rst | 12 ++++++------
+ src/kdc/main.c                       | 12 ++++--------
+ 2 files changed, 10 insertions(+), 14 deletions(-)
+
+diff --git a/doc/admin/admin_commands/krb5kdc.rst b/doc/admin/admin_commands/krb5kdc.rst
+index 7ec4ee4d3..bda2c015c 100644
+--- a/doc/admin/admin_commands/krb5kdc.rst
++++ b/doc/admin/admin_commands/krb5kdc.rst
+@@ -57,12 +57,12 @@ The **-P** *pid_file* option tells the KDC to write its PID into
+ the KDC is still running and to allow init scripts to stop the correct
+ process.
+ 
+-The **-p** *portnum* option specifies the default UDP port numbers
+-which the KDC should listen on for Kerberos version 5 requests, as a
+-comma-separated list.  This value overrides the UDP port numbers
+-specified in the :ref:`kdcdefaults` section of :ref:`kdc.conf(5)`, but
+-may be overridden by realm-specific values.  If no value is given from
+-any source, the default port is 88.
++The **-p** *portnum* option specifies the default UDP and TCP port
++numbers which the KDC should listen on for Kerberos version 5
++requests, as a comma-separated list.  This value overrides the port
++numbers specified in the :ref:`kdcdefaults` section of
++:ref:`kdc.conf(5)`, but may be overridden by realm-specific values.
++If no value is given from any source, the default port is 88.
+ 
+ The **-w** *numworkers* option tells the KDC to fork *numworkers*
+ processes to listen to the KDC ports and process requests in parallel.
+diff --git a/src/kdc/main.c b/src/kdc/main.c
+index ccac3a759..89dac23ae 100644
+--- a/src/kdc/main.c
++++ b/src/kdc/main.c
+@@ -793,19 +793,15 @@ initialize_realms(krb5_context kcontext, int argc, char **argv,
+             pid_file = optarg;
+             break;
+         case 'p':
+-            if (def_udp_listen)
+-                free(def_udp_listen);
++            free(def_udp_listen);
++            free(def_tcp_listen);
+             def_udp_listen = strdup(optarg);
+-            if (!def_udp_listen) {
++            def_tcp_listen = strdup(optarg);
++            if (def_udp_listen == NULL || def_tcp_listen == NULL) {
+                 fprintf(stderr, _(" KDC cannot initialize. Not enough "
+                                   "memory\n"));
+                 exit(1);
+             }
+-#if 0 /* not yet */
+-            if (default_tcp_ports)
+-                free(default_tcp_ports);
+-            default_tcp_ports = strdup(optarg);
+-#endif
+             break;
+         case 'T':
+             time_offset = atoi(optarg);
diff --git a/SOURCES/Move-zap-definition-to-k5-platform.h.patch b/SOURCES/Move-zap-definition-to-k5-platform.h.patch
new file mode 100644
index 0000000..f181701
--- /dev/null
+++ b/SOURCES/Move-zap-definition-to-k5-platform.h.patch
@@ -0,0 +1,151 @@
+From ee941a490268bb045ec7e153bdf229adcd6d2f73 Mon Sep 17 00:00:00 2001
+From: Greg Hudson <ghudson@mit.edu>
+Date: Mon, 26 Mar 2018 10:54:29 -0400
+Subject: [PATCH] Move zap() definition to k5-platform.h
+
+Make it possible to use zap() in parts of the code which should not
+include k5-int.h by moving its definition to k5-platform.h.
+
+(cherry picked from commit df6bef6f9ea6a5f6f3956a2988cd658c78aae817)
+---
+ src/include/k5-int.h      | 45 -------------------------------------
+ src/include/k5-platform.h | 47 ++++++++++++++++++++++++++++++++++++++-
+ src/util/support/zap.c    |  4 ++--
+ 3 files changed, 48 insertions(+), 48 deletions(-)
+
+diff --git a/src/include/k5-int.h b/src/include/k5-int.h
+index 1c1d9783b..69b81a7f7 100644
+--- a/src/include/k5-int.h
++++ b/src/include/k5-int.h
+@@ -639,51 +639,6 @@ krb5int_arcfour_gsscrypt(const krb5_keyblock *keyblock, krb5_keyusage usage,
+ krb5_error_code
+ k5_sha256(const krb5_data *in, size_t n, uint8_t out[K5_SHA256_HASHLEN]);
+ 
+-/*
+- * Attempt to zero memory in a way that compilers won't optimize out.
+- *
+- * This mechanism should work even for heap storage about to be freed,
+- * or automatic storage right before we return from a function.
+- *
+- * Then, even if we leak uninitialized memory someplace, or UNIX
+- * "core" files get created with world-read access, some of the most
+- * sensitive data in the process memory will already be safely wiped.
+- *
+- * We're not going so far -- yet -- as to try to protect key data that
+- * may have been written into swap space....
+- */
+-#ifdef _WIN32
+-# define zap(ptr, len) SecureZeroMemory(ptr, len)
+-#elif defined(__STDC_LIB_EXT1__)
+-/*
+- * Use memset_s() which cannot be optimized out.  Avoid memset_s(NULL, 0, 0, 0)
+- * which would cause a runtime constraint violation.
+- */
+-static inline void zap(void *ptr, size_t len)
+-{
+-    if (len > 0)
+-        memset_s(ptr, len, 0, len);
+-}
+-#elif defined(__GNUC__) || defined(__clang__)
+-/*
+- * Use an asm statement which declares a memory clobber to force the memset to
+- * be carried out.  Avoid memset(NULL, 0, 0) which has undefined behavior.
+- */
+-static inline void zap(void *ptr, size_t len)
+-{
+-    if (len > 0)
+-        memset(ptr, 0, len);
+-    __asm__ __volatile__("" : : "r" (ptr) : "memory");
+-}
+-#else
+-/*
+- * Use a function from libkrb5support to defeat inlining unless link-time
+- * optimization is used.  The function uses a volatile pointer, which prevents
+- * current compilers from optimizing out the memset.
+- */
+-# define zap(ptr, len) krb5int_zap(ptr, len)
+-#endif
+-
+ /* Convenience function: zap and free ptr if it is non-NULL. */
+ static inline void
+ zapfree(void *ptr, size_t len)
+diff --git a/src/include/k5-platform.h b/src/include/k5-platform.h
+index 548c0486d..07ef6a4ca 100644
+--- a/src/include/k5-platform.h
++++ b/src/include/k5-platform.h
+@@ -40,7 +40,7 @@
+  * + [v]asprintf
+  * + strerror_r
+  * + mkstemp
+- * + zap (support function; macro is in k5-int.h)
++ * + zap (support function and macro)
+  * + constant time memory comparison
+  * + path manipulation
+  * + _, N_, dgettext, bindtextdomain (for localization)
+@@ -1022,6 +1022,51 @@ extern int krb5int_gettimeofday(struct timeval *tp, void *ignore);
+ #define gettimeofday krb5int_gettimeofday
+ #endif
+ 
++/*
++ * Attempt to zero memory in a way that compilers won't optimize out.
++ *
++ * This mechanism should work even for heap storage about to be freed,
++ * or automatic storage right before we return from a function.
++ *
++ * Then, even if we leak uninitialized memory someplace, or UNIX
++ * "core" files get created with world-read access, some of the most
++ * sensitive data in the process memory will already be safely wiped.
++ *
++ * We're not going so far -- yet -- as to try to protect key data that
++ * may have been written into swap space....
++ */
++#ifdef _WIN32
++# define zap(ptr, len) SecureZeroMemory(ptr, len)
++#elif defined(__STDC_LIB_EXT1__)
++/*
++ * Use memset_s() which cannot be optimized out.  Avoid memset_s(NULL, 0, 0, 0)
++ * which would cause a runtime constraint violation.
++ */
++static inline void zap(void *ptr, size_t len)
++{
++    if (len > 0)
++        memset_s(ptr, len, 0, len);
++}
++#elif defined(__GNUC__) || defined(__clang__)
++/*
++ * Use an asm statement which declares a memory clobber to force the memset to
++ * be carried out.  Avoid memset(NULL, 0, 0) which has undefined behavior.
++ */
++static inline void zap(void *ptr, size_t len)
++{
++    if (len > 0)
++        memset(ptr, 0, len);
++    __asm__ __volatile__("" : : "r" (ptr) : "memory");
++}
++#else
++/*
++ * Use a function from libkrb5support to defeat inlining unless link-time
++ * optimization is used.  The function uses a volatile pointer, which prevents
++ * current compilers from optimizing out the memset.
++ */
++# define zap(ptr, len) krb5int_zap(ptr, len)
++#endif
++
+ extern void krb5int_zap(void *ptr, size_t len);
+ 
+ /*
+diff --git a/src/util/support/zap.c b/src/util/support/zap.c
+index ed31630db..2f6cdd70e 100644
+--- a/src/util/support/zap.c
++++ b/src/util/support/zap.c
+@@ -25,8 +25,8 @@
+  */
+ 
+ /*
+- * krb5int_zap() is used by zap() (a static inline function defined in
+- * k5-int.h) on non-Windows, non-gcc compilers, in order to prevent the
++ * krb5int_zap() is used by zap() (a macro or static inline function defined in
++ * k5-platform.h) on non-Windows, non-gcc compilers, in order to prevent the
+  * compiler from inlining and optimizing out the memset() call.
+  */
+ 
diff --git a/SOURCES/Process-profile-includedir-in-sorted-order.patch b/SOURCES/Process-profile-includedir-in-sorted-order.patch
new file mode 100644
index 0000000..92efffc
--- /dev/null
+++ b/SOURCES/Process-profile-includedir-in-sorted-order.patch
@@ -0,0 +1,114 @@
+From 5d868264bca1771aa16abbc8cc0aefb0e1750a73 Mon Sep 17 00:00:00 2001
+From: Greg Hudson <ghudson@mit.edu>
+Date: Wed, 6 Jun 2018 17:58:41 -0400
+Subject: [PATCH] Process profile includedir in sorted order
+
+In the profile library, use k5_dir_filenames() so that files within an
+included directory are read in a predictable order (alphanumeric
+within the C locale).
+
+ticket: 8686
+(cherry picked from commit f574eda48740ad192f51e9a382a205e2ea0e60ad)
+---
+ doc/admin/conf_files/krb5_conf.rst |  4 ++-
+ src/util/profile/prof_parse.c      | 56 +++++-------------------------
+ 2 files changed, 12 insertions(+), 48 deletions(-)
+
+diff --git a/doc/admin/conf_files/krb5_conf.rst b/doc/admin/conf_files/krb5_conf.rst
+index 2574e5c26..ce545492d 100644
+--- a/doc/admin/conf_files/krb5_conf.rst
++++ b/doc/admin/conf_files/krb5_conf.rst
+@@ -60,7 +60,9 @@ alphanumeric characters, dashes, or underscores.  Starting in release
+ 1.15, files with names ending in ".conf" are also included, unless the
+ name begins with ".".  Included profile files are syntactically
+ independent of their parents, so each included file must begin with a
+-section header.
++section header.  Starting in release 1.17, files are read in
++alphanumeric order; in previous releases, they may be read in any
++order.
+ 
+ The krb5.conf file can specify that configuration should be obtained
+ from a loadable module, rather than the file itself, using the
+diff --git a/src/util/profile/prof_parse.c b/src/util/profile/prof_parse.c
+index 1baceea9e..531e4a099 100644
+--- a/src/util/profile/prof_parse.c
++++ b/src/util/profile/prof_parse.c
+@@ -246,59 +246,22 @@ static int valid_name(const char *filename)
+  * Include files within dirname.  Only files with names ending in ".conf", or
+  * consisting entirely of alphanumeric characters, dashes, and underscores are
+  * included.  This restriction avoids including editor backup files, .rpmsave
+- * files, and the like.
++ * files, and the like.  Files are processed in alphanumeric order.
+  */
+ static errcode_t parse_include_dir(const char *dirname,
+                                    struct profile_node *root_section)
+ {
+-#ifdef _WIN32
+-    char *wildcard = NULL, *pathname;
+-    WIN32_FIND_DATA ffd;
+-    HANDLE handle;
+     errcode_t retval = 0;
++    char **fnames, *pathname;
++    int i;
+ 
+-    if (asprintf(&wildcard, "%s\\*", dirname) < 0)
+-        return ENOMEM;
+-
+-    handle = FindFirstFile(wildcard, &ffd);
+-    if (handle == INVALID_HANDLE_VALUE) {
+-        retval = PROF_FAIL_INCLUDE_DIR;
+-        goto cleanup;
+-    }
+-
+-    do {
+-        if (!valid_name(ffd.cFileName))
+-            continue;
+-        if (asprintf(&pathname, "%s\\%s", dirname, ffd.cFileName) < 0) {
+-            retval = ENOMEM;
+-            break;
+-        }
+-        retval = parse_include_file(pathname, root_section);
+-        free(pathname);
+-        if (retval)
+-            break;
+-    } while (FindNextFile(handle, &ffd) != 0);
+-
+-    FindClose(handle);
+-
+-cleanup:
+-    free(wildcard);
+-    return retval;
+-
+-#else /* not _WIN32 */
+-
+-    DIR     *dir;
+-    char    *pathname;
+-    errcode_t retval = 0;
+-    struct dirent *ent;
+-
+-    dir = opendir(dirname);
+-    if (dir == NULL)
++    if (k5_dir_filenames(dirname, &fnames) != 0)
+         return PROF_FAIL_INCLUDE_DIR;
+-    while ((ent = readdir(dir)) != NULL) {
+-        if (!valid_name(ent->d_name))
++
++    for (i = 0; fnames != NULL && fnames[i] != NULL; i++) {
++        if (!valid_name(fnames[i]))
+             continue;
+-        if (asprintf(&pathname, "%s/%s", dirname, ent->d_name) < 0) {
++        if (asprintf(&pathname, "%s/%s", dirname, fnames[i]) < 0) {
+             retval = ENOMEM;
+             break;
+         }
+@@ -307,9 +270,8 @@ cleanup:
+         if (retval)
+             break;
+     }
+-    closedir(dir);
++    k5_free_filenames(fnames);
+     return retval;
+-#endif /* not _WIN32 */
+ }
+ 
+ static errcode_t parse_line(char *line, struct parse_state *state,
diff --git a/SOURCES/Refactor-KDC-krb5_pa_data-utility-functions.patch b/SOURCES/Refactor-KDC-krb5_pa_data-utility-functions.patch
new file mode 100644
index 0000000..41e7cbe
--- /dev/null
+++ b/SOURCES/Refactor-KDC-krb5_pa_data-utility-functions.patch
@@ -0,0 +1,393 @@
+From 7c59b7ee063489a4259c34b725728fee7e411c46 Mon Sep 17 00:00:00 2001
+From: Greg Hudson <ghudson@mit.edu>
+Date: Thu, 21 Dec 2017 11:28:52 -0500
+Subject: [PATCH] Refactor KDC krb5_pa_data utility functions
+
+Move alloc_padata from fast_util.c to kdc_util.c and make it
+non-static so it can be used by other files.  Rename it to
+alloc_pa_data for consistency with add_pa_data_element.  Make it
+correctly handle zero length using a null contents pointer.
+
+Make add_pa_data_element claim both the container and contents memory
+from the caller, now that callers can use alloc_pa_data to simplify
+allocation and copying.  Remove the copy parameter and the unused
+context parameter, and put the list parameter first.  Adjust all
+callers accordingly, making small simplifications to memory handling
+where applicable.
+
+(cherry picked from commit 4af478c18b02e1d2444a328bb79e6976ef3d312b)
+---
+ src/kdc/fast_util.c   |  28 +------
+ src/kdc/kdc_preauth.c |  14 ++--
+ src/kdc/kdc_util.c    | 187 +++++++++++++++++++++---------------------
+ src/kdc/kdc_util.h    |   8 +-
+ 4 files changed, 109 insertions(+), 128 deletions(-)
+
+diff --git a/src/kdc/fast_util.c b/src/kdc/fast_util.c
+index e05107ef3..6a3fc11b9 100644
+--- a/src/kdc/fast_util.c
++++ b/src/kdc/fast_util.c
+@@ -451,36 +451,12 @@ kdc_fast_hide_client(struct kdc_request_state *state)
+     return (state->fast_options & KRB5_FAST_OPTION_HIDE_CLIENT_NAMES) != 0;
+ }
+ 
+-/* Allocate a pa-data entry with an uninitialized buffer of size len. */
+-static krb5_error_code
+-alloc_padata(krb5_preauthtype pa_type, size_t len, krb5_pa_data **out)
+-{
+-    krb5_pa_data *pa;
+-    uint8_t *buf;
+-
+-    *out = NULL;
+-    buf = malloc(len);
+-    if (buf == NULL)
+-        return ENOMEM;
+-    pa = malloc(sizeof(*pa));
+-    if (pa == NULL) {
+-        free(buf);
+-        return ENOMEM;
+-    }
+-    pa->magic = KV5M_PA_DATA;
+-    pa->pa_type = pa_type;
+-    pa->length = len;
+-    pa->contents = buf;
+-    *out = pa;
+-    return 0;
+-}
+-
+ /* Create a pa-data entry with the specified type and contents. */
+ static krb5_error_code
+ make_padata(krb5_preauthtype pa_type, const void *contents, size_t len,
+             krb5_pa_data **out)
+ {
+-    if (alloc_padata(pa_type, len, out) != 0)
++    if (alloc_pa_data(pa_type, len, out) != 0)
+         return ENOMEM;
+     memcpy((*out)->contents, contents, len);
+     return 0;
+@@ -720,7 +696,7 @@ kdc_fast_make_cookie(krb5_context context, struct kdc_request_state *state,
+         goto cleanup;
+ 
+     /* Construct the cookie pa-data entry. */
+-    ret = alloc_padata(KRB5_PADATA_FX_COOKIE, 8 + enc.ciphertext.length, &pa);
++    ret = alloc_pa_data(KRB5_PADATA_FX_COOKIE, 8 + enc.ciphertext.length, &pa);
+     memcpy(pa->contents, "MIT1", 4);
+     store_32_be(kvno, pa->contents + 4);
+     memcpy(pa->contents + 8, enc.ciphertext.data, enc.ciphertext.length);
+diff --git a/src/kdc/kdc_preauth.c b/src/kdc/kdc_preauth.c
+index 739c5e776..edc30bd83 100644
+--- a/src/kdc/kdc_preauth.c
++++ b/src/kdc/kdc_preauth.c
+@@ -1617,18 +1617,20 @@ return_referral_enc_padata( krb5_context context,
+ {
+     krb5_error_code             code;
+     krb5_tl_data                tl_data;
+-    krb5_pa_data                pa_data;
++    krb5_pa_data                *pa;
+ 
+     tl_data.tl_data_type = KRB5_TL_SVR_REFERRAL_DATA;
+     code = krb5_dbe_lookup_tl_data(context, server, &tl_data);
+     if (code || tl_data.tl_data_length == 0)
+         return 0;
+ 
+-    pa_data.magic = KV5M_PA_DATA;
+-    pa_data.pa_type = KRB5_PADATA_SVR_REFERRAL_INFO;
+-    pa_data.length = tl_data.tl_data_length;
+-    pa_data.contents = tl_data.tl_data_contents;
+-    return add_pa_data_element(context, &pa_data, &reply->enc_padata, TRUE);
++    code = alloc_pa_data(KRB5_PADATA_SVR_REFERRAL_INFO, tl_data.tl_data_length,
++                         &pa);
++    if (code)
++        return code;
++    memcpy(pa->contents, tl_data.tl_data_contents, tl_data.tl_data_length);
++    /* add_pa_data_element() claims pa on success or failure. */
++    return add_pa_data_element(&reply->enc_padata, pa);
+ }
+ 
+ krb5_error_code
+diff --git a/src/kdc/kdc_util.c b/src/kdc/kdc_util.c
+index 754570c01..13111215d 100644
+--- a/src/kdc/kdc_util.c
++++ b/src/kdc/kdc_util.c
+@@ -1353,9 +1353,9 @@ kdc_make_s4u2self_rep(krb5_context context,
+                       krb5_enc_kdc_rep_part *reply_encpart)
+ {
+     krb5_error_code             code;
+-    krb5_data                   *data = NULL;
++    krb5_data                   *der_user_id = NULL, *der_s4u_x509_user = NULL;
+     krb5_pa_s4u_x509_user       rep_s4u_user;
+-    krb5_pa_data                padata;
++    krb5_pa_data                *pa;
+     krb5_enctype                enctype;
+     krb5_keyusage               usage;
+ 
+@@ -1366,7 +1366,7 @@ kdc_make_s4u2self_rep(krb5_context context,
+     rep_s4u_user.user_id.options =
+         req_s4u_user->user_id.options & KRB5_S4U_OPTS_USE_REPLY_KEY_USAGE;
+ 
+-    code = encode_krb5_s4u_userid(&rep_s4u_user.user_id, &data);
++    code = encode_krb5_s4u_userid(&rep_s4u_user.user_id, &der_user_id);
+     if (code != 0)
+         goto cleanup;
+ 
+@@ -1377,29 +1377,25 @@ kdc_make_s4u2self_rep(krb5_context context,
+ 
+     code = krb5_c_make_checksum(context, req_s4u_user->cksum.checksum_type,
+                                 tgs_subkey != NULL ? tgs_subkey : tgs_session,
+-                                usage, data,
+-                                &rep_s4u_user.cksum);
++                                usage, der_user_id, &rep_s4u_user.cksum);
+     if (code != 0)
+         goto cleanup;
+ 
+-    krb5_free_data(context, data);
+-    data = NULL;
+-
+-    code = encode_krb5_pa_s4u_x509_user(&rep_s4u_user, &data);
++    code = encode_krb5_pa_s4u_x509_user(&rep_s4u_user, &der_s4u_x509_user);
+     if (code != 0)
+         goto cleanup;
+ 
+-    padata.magic = KV5M_PA_DATA;
+-    padata.pa_type = KRB5_PADATA_S4U_X509_USER;
+-    padata.length = data->length;
+-    padata.contents = (krb5_octet *)data->data;
+-
+-    code = add_pa_data_element(context, &padata, &reply->padata, FALSE);
++    /* Add a padata element, stealing memory from der_s4u_x509_user. */
++    code = alloc_pa_data(KRB5_PADATA_S4U_X509_USER, 0, &pa);
++    if (code != 0)
++        goto cleanup;
++    pa->length = der_s4u_x509_user->length;
++    pa->contents = (uint8_t *)der_s4u_x509_user->data;
++    der_s4u_x509_user->data = NULL;
++    /* add_pa_data_element() claims pa on success or failure. */
++    code = add_pa_data_element(&reply->padata, pa);
+     if (code != 0)
+         goto cleanup;
+-
+-    free(data);
+-    data = NULL;
+ 
+     if (tgs_subkey != NULL)
+         enctype = tgs_subkey->enctype;
+@@ -1413,33 +1409,27 @@ kdc_make_s4u2self_rep(krb5_context context,
+      */
+     if ((req_s4u_user->user_id.options & KRB5_S4U_OPTS_USE_REPLY_KEY_USAGE) &&
+         enctype_requires_etype_info_2(enctype) == FALSE) {
+-        padata.length = req_s4u_user->cksum.length +
+-            rep_s4u_user.cksum.length;
+-        padata.contents = malloc(padata.length);
+-        if (padata.contents == NULL) {
+-            code = ENOMEM;
++        code = alloc_pa_data(KRB5_PADATA_S4U_X509_USER,
++                             req_s4u_user->cksum.length +
++                             rep_s4u_user.cksum.length, &pa);
++        if (code != 0)
+             goto cleanup;
+-        }
++        memcpy(pa->contents,
++               req_s4u_user->cksum.contents, req_s4u_user->cksum.length);
++        memcpy(&pa->contents[req_s4u_user->cksum.length],
++               rep_s4u_user.cksum.contents, rep_s4u_user.cksum.length);
+ 
+-        memcpy(padata.contents,
+-               req_s4u_user->cksum.contents,
+-               req_s4u_user->cksum.length);
+-        memcpy(&padata.contents[req_s4u_user->cksum.length],
+-               rep_s4u_user.cksum.contents,
+-               rep_s4u_user.cksum.length);
+-
+-        code = add_pa_data_element(context,&padata,
+-                                   &reply_encpart->enc_padata, FALSE);
+-        if (code != 0) {
+-            free(padata.contents);
++        /* add_pa_data_element() claims pa on success or failure. */
++        code = add_pa_data_element(&reply_encpart->enc_padata, pa);
++        if (code != 0)
+             goto cleanup;
+-        }
+     }
+ 
+ cleanup:
+     if (rep_s4u_user.cksum.contents != NULL)
+         krb5_free_checksum_contents(context, &rep_s4u_user.cksum);
+-    krb5_free_data(context, data);
++    krb5_free_data(context, der_user_id);
++    krb5_free_data(context, der_s4u_x509_user);
+ 
+     return code;
+ }
+@@ -1707,46 +1697,50 @@ enctype_requires_etype_info_2(krb5_enctype enctype)
+     }
+ }
+ 
+-/* XXX where are the generic helper routines for this? */
++/* Allocate a pa-data entry with an uninitialized buffer of size len. */
+ krb5_error_code
+-add_pa_data_element(krb5_context context,
+-                    krb5_pa_data *padata,
+-                    krb5_pa_data ***inout_padata,
+-                    krb5_boolean copy)
++alloc_pa_data(krb5_preauthtype pa_type, size_t len, krb5_pa_data **out)
+ {
+-    int                         i;
+-    krb5_pa_data                **p;
++    krb5_pa_data *pa;
++    uint8_t *buf = NULL;
+ 
+-    if (*inout_padata != NULL) {
+-        for (i = 0; (*inout_padata)[i] != NULL; i++)
+-            ;
+-    } else
+-        i = 0;
+-
+-    p = realloc(*inout_padata, (i + 2) * sizeof(krb5_pa_data *));
+-    if (p == NULL)
+-        return ENOMEM;
+-
+-    *inout_padata = p;
+-
+-    p[i] = (krb5_pa_data *)malloc(sizeof(krb5_pa_data));
+-    if (p[i] == NULL)
+-        return ENOMEM;
+-    *(p[i]) = *padata;
+-
+-    p[i + 1] = NULL;
+-
+-    if (copy) {
+-        p[i]->contents = (krb5_octet *)malloc(padata->length);
+-        if (p[i]->contents == NULL) {
+-            free(p[i]);
+-            p[i] = NULL;
++    *out = NULL;
++    if (len > 0) {
++        buf = malloc(len);
++        if (buf == NULL)
+             return ENOMEM;
+-        }
+-
+-        memcpy(p[i]->contents, padata->contents, padata->length);
+     }
++    pa = malloc(sizeof(*pa));
++    if (pa == NULL) {
++        free(buf);
++        return ENOMEM;
++    }
++    pa->magic = KV5M_PA_DATA;
++    pa->pa_type = pa_type;
++    pa->length = len;
++    pa->contents = buf;
++    *out = pa;
++    return 0;
++}
+ 
++/* Add pa to list, claiming its memory.  Free pa on failure. */
++krb5_error_code
++add_pa_data_element(krb5_pa_data ***list, krb5_pa_data *pa)
++{
++    size_t count;
++    krb5_pa_data **newlist;
++
++    for (count = 0; *list != NULL && (*list)[count] != NULL; count++);
++
++    newlist = realloc(*list, (count + 2) * sizeof(*newlist));
++    if (newlist == NULL) {
++        free(pa->contents);
++        free(pa);
++        return ENOMEM;
++    }
++    newlist[count] = pa;
++    newlist[count + 1] = NULL;
++    *list = newlist;
+     return 0;
+ }
+ 
+@@ -1850,38 +1844,47 @@ kdc_handle_protected_negotiation(krb5_context context,
+ {
+     krb5_error_code retval = 0;
+     krb5_checksum checksum;
+-    krb5_data *out = NULL;
+-    krb5_pa_data pa, *pa_in;
++    krb5_data *der_cksum = NULL;
++    krb5_pa_data *pa, *pa_in;
++
++    memset(&checksum, 0, sizeof(checksum));
++
+     pa_in = krb5int_find_pa_data(context, request->padata,
+                                  KRB5_ENCPADATA_REQ_ENC_PA_REP);
+     if (pa_in == NULL)
+         return 0;
+-    pa.magic = KV5M_PA_DATA;
+-    pa.pa_type = KRB5_ENCPADATA_REQ_ENC_PA_REP;
+-    memset(&checksum, 0, sizeof(checksum));
+-    retval = krb5_c_make_checksum(context,0, reply_key,
+-                                  KRB5_KEYUSAGE_AS_REQ, req_pkt, &checksum);
++
++    /* Compute and encode a checksum over the AS-REQ. */
++    retval = krb5_c_make_checksum(context, 0, reply_key, KRB5_KEYUSAGE_AS_REQ,
++                                  req_pkt, &checksum);
+     if (retval != 0)
+         goto cleanup;
+-    retval = encode_krb5_checksum(&checksum, &out);
++    retval = encode_krb5_checksum(&checksum, &der_cksum);
+     if (retval != 0)
+         goto cleanup;
+-    pa.contents = (krb5_octet *) out->data;
+-    pa.length = out->length;
+-    retval = add_pa_data_element(context, &pa, out_enc_padata, FALSE);
++
++    /* Add a pa-data element to the list, stealing memory from der_cksum. */
++    retval = alloc_pa_data(KRB5_ENCPADATA_REQ_ENC_PA_REP, 0, &pa);
+     if (retval)
+         goto cleanup;
+-    out->data = NULL;
+-    pa.magic = KV5M_PA_DATA;
+-    pa.pa_type = KRB5_PADATA_FX_FAST;
+-    pa.length = 0;
+-    pa.contents = NULL;
+-    retval = add_pa_data_element(context, &pa, out_enc_padata, FALSE);
++    pa->length = der_cksum->length;
++    pa->contents = (uint8_t *)der_cksum->data;
++    der_cksum->data = NULL;
++    /* add_pa_data_element() claims pa on success or failure. */
++    retval = add_pa_data_element(out_enc_padata, pa);
++    if (retval)
++        goto cleanup;
++
++    /* Add a zero-length PA-FX-FAST element to the list. */
++    retval = alloc_pa_data(KRB5_PADATA_FX_FAST, 0, &pa);
++    if (retval)
++        goto cleanup;
++    /* add_pa_data_element() claims pa on success or failure. */
++    retval = add_pa_data_element(out_enc_padata, pa);
++
+ cleanup:
+-    if (checksum.contents)
+-        krb5_free_checksum_contents(context, &checksum);
+-    if (out != NULL)
+-        krb5_free_data(context, out);
++    krb5_free_checksum_contents(context, &checksum);
++    krb5_free_data(context, der_cksum);
+     return retval;
+ }
+ 
+diff --git a/src/kdc/kdc_util.h b/src/kdc/kdc_util.h
+index c57d48f73..198eab9c4 100644
+--- a/src/kdc/kdc_util.h
++++ b/src/kdc/kdc_util.h
+@@ -202,10 +202,10 @@ void
+ free_padata_context(krb5_context context, void *padata_context);
+ 
+ krb5_error_code
+-add_pa_data_element (krb5_context context,
+-                     krb5_pa_data *padata,
+-                     krb5_pa_data ***out_padata,
+-                     krb5_boolean copy);
++alloc_pa_data(krb5_preauthtype pa_type, size_t len, krb5_pa_data **out);
++
++krb5_error_code
++add_pa_data_element(krb5_pa_data ***list, krb5_pa_data *pa);
+ 
+ /* kdc_preauth_ec.c */
+ krb5_error_code
diff --git a/SOURCES/Remove-incorrect-KDC-assertion.patch b/SOURCES/Remove-incorrect-KDC-assertion.patch
new file mode 100644
index 0000000..dda0928
--- /dev/null
+++ b/SOURCES/Remove-incorrect-KDC-assertion.patch
@@ -0,0 +1,59 @@
+From 2a96564f6fd53f2e1e8424d865c02349bfe5b818 Mon Sep 17 00:00:00 2001
+From: Isaac Boukris <iboukris@gmail.com>
+Date: Sat, 15 Dec 2018 11:56:36 +0200
+Subject: [PATCH] Remove incorrect KDC assertion
+
+The assertion in return_enc_padata() is reachable because
+kdc_make_s4u2self_rep() may have previously added encrypted padata.
+It is no longer necessary because the code uses add_pa_data_element()
+instead of allocating a new list.
+
+CVE-2018-20217:
+
+In MIT krb5 1.8 or later, an authenticated user who can obtain a TGT
+using an older encryption type (DES, DES3, or RC4) can cause an
+assertion failure in the KDC by sending an S4U2Self request.
+
+[ghudson@mit.edu: rewrote commit message with CVE description]
+
+(cherry picked from commit 94e5eda5bb94d1d44733a49c3d9b6d1e42c74def)
+
+ticket: 8767
+version_fixed: 1.16.3
+
+(cherry picked from commit 56870f9456da78d77a667dfc03a6d90f948dc3a5)
+---
+ src/kdc/kdc_preauth.c     | 1 -
+ src/tests/gssapi/t_s4u.py | 7 +++++++
+ 2 files changed, 7 insertions(+), 1 deletion(-)
+
+diff --git a/src/kdc/kdc_preauth.c b/src/kdc/kdc_preauth.c
+index 811c16368..6f0cf68d9 100644
+--- a/src/kdc/kdc_preauth.c
++++ b/src/kdc/kdc_preauth.c
+@@ -1666,7 +1666,6 @@ return_enc_padata(krb5_context context, krb5_data *req_pkt,
+     krb5_error_code code = 0;
+     /* This should be initialized and only used for Win2K compat and other
+      * specific standardized uses such as FAST negotiation. */
+-    assert(reply_encpart->enc_padata == NULL);
+     if (is_referral) {
+         code = return_referral_enc_padata(context, reply_encpart, server);
+         if (code)
+diff --git a/src/tests/gssapi/t_s4u.py b/src/tests/gssapi/t_s4u.py
+index fc9d9e8a4..f65000453 100755
+--- a/src/tests/gssapi/t_s4u.py
++++ b/src/tests/gssapi/t_s4u.py
+@@ -139,6 +139,13 @@ if 'auth1: user@' not in out or 'auth2: user@' not in out:
+ 
+ realm.stop()
+ 
++for realm in multipass_realms(create_host=False, get_creds=False):
++    service1 = 'service/1@%s' % realm.realm
++    realm.addprinc(service1)
++    realm.extract_keytab(service1, realm.keytab)
++    realm.kinit(service1, None, ['-k'])
++    realm.run(['./t_s4u', 'p:user', '-'])
++
+ # Exercise cross-realm S4U2Self.  The query in the foreign realm will
+ # fail, but we can check that the right server principal was used.
+ r1, r2 = cross_realms(2, create_user=False)
diff --git a/SOURCES/Remove-nodes-option-from-make-certs-scripts.patch b/SOURCES/Remove-nodes-option-from-make-certs-scripts.patch
new file mode 100644
index 0000000..402f5fb
--- /dev/null
+++ b/SOURCES/Remove-nodes-option-from-make-certs-scripts.patch
@@ -0,0 +1,45 @@
+From 83da5675551dba13fee837adc26ce885a061dbc1 Mon Sep 17 00:00:00 2001
+From: Robbie Harwood <rharwood@redhat.com>
+Date: Thu, 3 May 2018 14:40:45 -0400
+Subject: [PATCH] Remove "-nodes" option from make-certs scripts
+
+The openssl command does not recognize options after positional
+arguments, so in "openssl genrsa $KEYSIZE -nodes", the "-nodes" was
+ignored as a excess positional argument prior to OpenSSL 1.1.0h, and
+now causes an error.  "-nodes" is an option to the openssl req and
+pkcs12 subcommands, but genrsa creates unencrypted keys by default.
+
+[ghudson@mit.edu: edited commit message]
+
+(cherry picked from commit 928a36aae326d496c9a73f2cd41b4da45eef577c)
+---
+ src/tests/dejagnu/pkinit-certs/make-certs.sh | 2 +-
+ src/tests/dejagnu/proxy-certs/make-certs.sh  | 2 +-
+ 2 files changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/src/tests/dejagnu/pkinit-certs/make-certs.sh b/src/tests/dejagnu/pkinit-certs/make-certs.sh
+index 63f0c6f75..387311aed 100755
+--- a/src/tests/dejagnu/pkinit-certs/make-certs.sh
++++ b/src/tests/dejagnu/pkinit-certs/make-certs.sh
+@@ -114,7 +114,7 @@ extendedKeyUsage = $CLIENT_EKU_LIST
+ EOF
+ 
+ # Generate a private key.
+-openssl genrsa $KEYSIZE -nodes > privkey.pem
++openssl genrsa $KEYSIZE > privkey.pem
+ openssl rsa -in privkey.pem -out privkey-enc.pem -des3 -passout pass:encrypted
+ 
+ # Generate a "CA" certificate.
+diff --git a/src/tests/dejagnu/proxy-certs/make-certs.sh b/src/tests/dejagnu/proxy-certs/make-certs.sh
+index 1191bf05e..24ef91bde 100755
+--- a/src/tests/dejagnu/proxy-certs/make-certs.sh
++++ b/src/tests/dejagnu/proxy-certs/make-certs.sh
+@@ -79,7 +79,7 @@ extendedKeyUsage = $PROXY_EKU_LIST
+ EOF
+ 
+ # Generate a private key.
+-openssl genrsa $KEYSIZE -nodes > privkey.pem
++openssl genrsa $KEYSIZE > privkey.pem
+ 
+ # Generate a "CA" certificate.
+ SUBJECT=signer openssl req -config openssl.cnf -new -x509 -extensions exts_ca \
diff --git a/SOURCES/Remove-outdated-note-in-krb5kdc-man-page.patch b/SOURCES/Remove-outdated-note-in-krb5kdc-man-page.patch
new file mode 100644
index 0000000..6845b89
--- /dev/null
+++ b/SOURCES/Remove-outdated-note-in-krb5kdc-man-page.patch
@@ -0,0 +1,37 @@
+From 65130d13c59c13b7e5e07cfe69421ce1a08c0b7f Mon Sep 17 00:00:00 2001
+From: Greg Hudson <ghudson@mit.edu>
+Date: Tue, 17 Jul 2018 11:33:03 -0400
+Subject: [PATCH] Remove outdated note in krb5kdc man page
+
+Commit af5b77c887bfff24603715f8296c00d5eb839b0c (ticket 8348) removed
+the interface-scanning workaround for platforms without pktinfo
+support, so there is no longer an interaction between the krb5kdc -w
+option and this workaround.
+
+ticket: 8716 (new)
+tags: pullup
+target_version: 1.16-next
+
+(cherry picked from commit 728b66ab867e31c4c338c6a6309d629d39a4ec3f)
+---
+ doc/admin/admin_commands/krb5kdc.rst | 7 -------
+ 1 file changed, 7 deletions(-)
+
+diff --git a/doc/admin/admin_commands/krb5kdc.rst b/doc/admin/admin_commands/krb5kdc.rst
+index bda2c015c..b605b563d 100644
+--- a/doc/admin/admin_commands/krb5kdc.rst
++++ b/doc/admin/admin_commands/krb5kdc.rst
+@@ -72,13 +72,6 @@ will relay SIGHUP signals to the worker subprocesses, and will
+ terminate the worker subprocess if the it is itself terminated or if
+ any other worker process exits.
+ 
+-.. note::
+-
+-          On operating systems which do not have *pktinfo* support,
+-          using worker processes will prevent the KDC from listening
+-          for UDP packets on network interfaces created after the KDC
+-          starts.
+-
+ The **-x** *db_args* option specifies database-specific arguments.
+ See :ref:`Database Options <dboptions>` in :ref:`kadmin(1)` for
+ supported arguments.
diff --git a/SOURCES/Report-extended-errors-in-kinit-k-t-KDB.patch b/SOURCES/Report-extended-errors-in-kinit-k-t-KDB.patch
new file mode 100644
index 0000000..6859b55
--- /dev/null
+++ b/SOURCES/Report-extended-errors-in-kinit-k-t-KDB.patch
@@ -0,0 +1,27 @@
+From 3b3e31316ae247e18ea22293dffbc8f604338fa7 Mon Sep 17 00:00:00 2001
+From: Greg Hudson <ghudson@mit.edu>
+Date: Sat, 17 Mar 2018 22:47:34 -0400
+Subject: [PATCH] Report extended errors in kinit -k -t KDB:
+
+In kinit, if we recreate the context using kinit_kdb_init(), also
+reset the global errctx so that we use the new context to retrieve
+extended error messages.
+
+ticket: 8652 (new)
+(cherry picked from commit d4d902d317a2acc46ee71094a33a9203b6135275)
+---
+ src/clients/kinit/kinit.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/src/clients/kinit/kinit.c b/src/clients/kinit/kinit.c
+index a518284ea..3fdae2878 100644
+--- a/src/clients/kinit/kinit.c
++++ b/src/clients/kinit/kinit.c
+@@ -718,6 +718,7 @@ k5_kinit(struct k_opts *opts, struct k5_data *k5)
+ #ifndef _WIN32
+         if (strncmp(opts->keytab_name, "KDB:", 4) == 0) {
+             ret = kinit_kdb_init(&k5->ctx, k5->me->realm.data);
++            errctx = k5->ctx;
+             if (ret) {
+                 com_err(progname, ret,
+                         _("while setting up KDB keytab for realm %s"),
diff --git a/SOURCES/Restrict-pre-authentication-fallback-cases.patch b/SOURCES/Restrict-pre-authentication-fallback-cases.patch
new file mode 100644
index 0000000..f519557
--- /dev/null
+++ b/SOURCES/Restrict-pre-authentication-fallback-cases.patch
@@ -0,0 +1,491 @@
+From 70f41a8dafaadfb43aba4918564c22460f812dca Mon Sep 17 00:00:00 2001
+From: Greg Hudson <ghudson@mit.edu>
+Date: Thu, 5 Apr 2018 16:23:34 -0400
+Subject: [PATCH] Restrict pre-authentication fallback cases
+
+Add a new callback disable_fallback() and call it from each clpreauth
+module when it generates a client message using credentials to
+authenticate.  (For SPAKE, this is the message responding to a
+challenge; for all other current mechanisms, it is the first and only
+client message.)  If disable_fallback() is called, do not try another
+mechanism after a KDC error.
+
+Remove k5_reset_preauth_types_tried() and its call sites, so that
+preauth mechanisms which are tried optimistically will no longer be
+retried after a failure.
+
+ticket: 8654
+(cherry picked from commit 7a24a088c16d326127dd2b29084d4ca085c70d10)
+---
+ src/include/krb5/clpreauth_plugin.h      | 14 ++++
+ src/lib/krb5/krb/get_in_tkt.c            | 21 +++---
+ src/lib/krb5/krb/init_creds_ctx.h        |  1 +
+ src/lib/krb5/krb/int-proto.h             |  3 -
+ src/lib/krb5/krb/preauth2.c              | 23 +++----
+ src/lib/krb5/krb/preauth_ec.c            |  1 +
+ src/lib/krb5/krb/preauth_encts.c         |  2 +
+ src/lib/krb5/krb/preauth_otp.c           |  4 ++
+ src/lib/krb5/krb/preauth_sam2.c          |  1 +
+ src/plugins/preauth/pkinit/pkinit_clnt.c |  1 +
+ src/plugins/preauth/spake/spake_client.c |  4 ++
+ src/plugins/preauth/test/cltest.c        | 11 +++
+ src/tests/t_preauth.py                   | 88 +++++++++++++++++++++---
+ src/tests/t_spake.py                     |  9 +--
+ 14 files changed, 134 insertions(+), 49 deletions(-)
+
+diff --git a/src/include/krb5/clpreauth_plugin.h b/src/include/krb5/clpreauth_plugin.h
+index 0106734ad..5317669b7 100644
+--- a/src/include/krb5/clpreauth_plugin.h
++++ b/src/include/krb5/clpreauth_plugin.h
+@@ -160,7 +160,21 @@ typedef struct krb5_clpreauth_callbacks_st {
+     krb5_error_code (*set_cc_config)(krb5_context context,
+                                      krb5_clpreauth_rock rock,
+                                      const char *key, const char *data);
++
+     /* End of version 2 clpreauth callbacks (added in 1.11). */
++
++    /*
++     * Prevent further fallbacks to other preauth mechanisms if the KDC replies
++     * with an error.  (The module itself can still respond to errors with its
++     * tryagain method, or continue after KDC_ERR_MORE_PREAUTH_DATA_REQUIRED
++     * errors with its process method.)  A module should invoke this callback
++     * from the process method when it generates an authenticated request using
++     * credentials; often this will be the first or only client message
++     * generated by the mechanism.
++     */
++    void (*disable_fallback)(krb5_context context, krb5_clpreauth_rock rock);
++
++    /* End of version 3 clpreauth callbacks (added in 1.17). */
+ } *krb5_clpreauth_callbacks;
+ 
+ /*
+diff --git a/src/lib/krb5/krb/get_in_tkt.c b/src/lib/krb5/krb/get_in_tkt.c
+index 1d96ff163..c026bbc6d 100644
+--- a/src/lib/krb5/krb/get_in_tkt.c
++++ b/src/lib/krb5/krb/get_in_tkt.c
+@@ -1331,9 +1331,7 @@ init_creds_step_request(krb5_context context,
+         krb5_free_pa_data(context, ctx->optimistic_padata);
+         ctx->optimistic_padata = NULL;
+         if (code) {
+-            /* Make an unauthenticated request, and possibly try again using
+-             * the same mechanisms as we tried optimistically. */
+-            k5_reset_preauth_types_tried(ctx);
++            /* Make an unauthenticated request. */
+             krb5_clear_error_message(context);
+             code = 0;
+         }
+@@ -1361,6 +1359,9 @@ init_creds_step_request(krb5_context context,
+     /* Don't continue after a keyboard interrupt. */
+     if (code == KRB5_LIBOS_PWDINTR)
+         goto cleanup;
++    /* Don't continue if fallback is disabled. */
++    if (code && ctx->fallback_disabled)
++        goto cleanup;
+     if (code) {
+         /* See if we can try a different preauth mech before giving up. */
+         k5_save_ctx_error(context, code, &save);
+@@ -1549,16 +1550,10 @@ init_creds_step_reply(krb5_context context,
+         } else if (reply_code == KDC_ERR_PREAUTH_FAILED && retry) {
+             note_req_timestamp(context, ctx, ctx->err_reply->stime,
+                                ctx->err_reply->susec);
+-            if (ctx->method_padata == NULL) {
+-                /* Optimistic preauth failed on the KDC.  Allow all mechanisms
+-                 * to be tried again using method data. */
+-                k5_reset_preauth_types_tried(ctx);
+-            } else {
+-                /* Don't try again with the mechanism that failed. */
+-                code = k5_preauth_note_failed(ctx, ctx->selected_preauth_type);
+-                if (code)
+-                    goto cleanup;
+-            }
++            /* Don't try again with the mechanism that failed. */
++            code = k5_preauth_note_failed(ctx, ctx->selected_preauth_type);
++            if (code)
++                goto cleanup;
+             ctx->selected_preauth_type = KRB5_PADATA_NONE;
+             /* Accept or update method data if the KDC sent it. */
+             if (ctx->err_padata != NULL)
+diff --git a/src/lib/krb5/krb/init_creds_ctx.h b/src/lib/krb5/krb/init_creds_ctx.h
+index b19410a13..7ba61e17c 100644
+--- a/src/lib/krb5/krb/init_creds_ctx.h
++++ b/src/lib/krb5/krb/init_creds_ctx.h
+@@ -60,6 +60,7 @@ struct _krb5_init_creds_context {
+     krb5_enctype etype;
+     krb5_boolean info_pa_permitted;
+     krb5_boolean restarted;
++    krb5_boolean fallback_disabled;
+     struct krb5_responder_context_st rctx;
+     krb5_preauthtype selected_preauth_type;
+     krb5_preauthtype allowed_preauth_type;
+diff --git a/src/lib/krb5/krb/int-proto.h b/src/lib/krb5/krb/int-proto.h
+index cda9010e3..d20133885 100644
+--- a/src/lib/krb5/krb/int-proto.h
++++ b/src/lib/krb5/krb/int-proto.h
+@@ -197,9 +197,6 @@ k5_init_preauth_context(krb5_context context);
+ void
+ k5_free_preauth_context(krb5_context context);
+ 
+-void
+-k5_reset_preauth_types_tried(krb5_init_creds_context ctx);
+-
+ krb5_error_code
+ k5_preauth_note_failed(krb5_init_creds_context ctx, krb5_preauthtype pa_type);
+ 
+diff --git a/src/lib/krb5/krb/preauth2.c b/src/lib/krb5/krb/preauth2.c
+index 451e0b7a8..1f17ec2b0 100644
+--- a/src/lib/krb5/krb/preauth2.c
++++ b/src/lib/krb5/krb/preauth2.c
+@@ -203,18 +203,6 @@ cleanup:
+     free_handles(context, list);
+ }
+ 
+-/* Reset the memory of which preauth types we have already tried. */
+-void
+-k5_reset_preauth_types_tried(krb5_init_creds_context ctx)
+-{
+-    krb5_preauth_req_context reqctx = ctx->preauth_reqctx;
+-
+-    if (reqctx == NULL)
+-        return;
+-    free(reqctx->failed);
+-    reqctx->failed = NULL;
+-}
+-
+ /* Add pa_type to the list of types which has previously failed. */
+ krb5_error_code
+ k5_preauth_note_failed(krb5_init_creds_context ctx, krb5_preauthtype pa_type)
+@@ -553,8 +541,14 @@ set_cc_config(krb5_context context, krb5_clpreauth_rock rock,
+     return ret;
+ }
+ 
++static void
++disable_fallback(krb5_context context, krb5_clpreauth_rock rock)
++{
++    ((krb5_init_creds_context)rock)->fallback_disabled = TRUE;
++}
++
+ static struct krb5_clpreauth_callbacks_st callbacks = {
+-    2,
++    3,
+     get_etype,
+     fast_armor,
+     get_as_key,
+@@ -564,7 +558,8 @@ static struct krb5_clpreauth_callbacks_st callbacks = {
+     responder_get_answer,
+     need_as_key,
+     get_cc_config,
+-    set_cc_config
++    set_cc_config,
++    disable_fallback
+ };
+ 
+ /* Tweak the request body, for now adding any enctypes which the module claims
+diff --git a/src/lib/krb5/krb/preauth_ec.c b/src/lib/krb5/krb/preauth_ec.c
+index c1aa9090f..75aab770e 100644
+--- a/src/lib/krb5/krb/preauth_ec.c
++++ b/src/lib/krb5/krb/preauth_ec.c
+@@ -138,6 +138,7 @@ ec_process(krb5_context context, krb5_clpreauth_moddata moddata,
+             encoded_ts->data = NULL;
+             *out_padata = pa;
+             pa = NULL;
++            cb->disable_fallback(context, rock);
+         }
+         free(pa);
+         krb5_free_data(context, encoded_ts);
+diff --git a/src/lib/krb5/krb/preauth_encts.c b/src/lib/krb5/krb/preauth_encts.c
+index cec384227..45bf9da92 100644
+--- a/src/lib/krb5/krb/preauth_encts.c
++++ b/src/lib/krb5/krb/preauth_encts.c
+@@ -109,6 +109,8 @@ encts_process(krb5_context context, krb5_clpreauth_moddata moddata,
+     *out_padata = pa;
+     pa = NULL;
+ 
++    cb->disable_fallback(context, rock);
++
+ cleanup:
+     krb5_free_data(context, ts);
+     krb5_free_data(context, enc_ts);
+diff --git a/src/lib/krb5/krb/preauth_otp.c b/src/lib/krb5/krb/preauth_otp.c
+index 48fcbb5d5..13e584657 100644
+--- a/src/lib/krb5/krb/preauth_otp.c
++++ b/src/lib/krb5/krb/preauth_otp.c
+@@ -1123,6 +1123,10 @@ otp_client_process(krb5_context context, krb5_clpreauth_moddata moddata,
+ 
+     /* Encode the request into the pa_data output. */
+     retval = set_pa_data(req, pa_data_out);
++    if (retval != 0)
++        goto error;
++    cb->disable_fallback(context, rock);
++
+ error:
+     krb5_free_data_contents(context, &value);
+     krb5_free_data_contents(context, &pin);
+diff --git a/src/lib/krb5/krb/preauth_sam2.c b/src/lib/krb5/krb/preauth_sam2.c
+index c8a330655..4c70021a9 100644
+--- a/src/lib/krb5/krb/preauth_sam2.c
++++ b/src/lib/krb5/krb/preauth_sam2.c
+@@ -410,6 +410,7 @@ sam2_process(krb5_context context, krb5_clpreauth_moddata moddata,
+     sam_padata[1] = NULL;
+ 
+     *out_padata = sam_padata;
++    cb->disable_fallback(context, rock);
+ 
+     return(0);
+ }
+diff --git a/src/plugins/preauth/pkinit/pkinit_clnt.c b/src/plugins/preauth/pkinit/pkinit_clnt.c
+index 9483d69e5..77e9e5308 100644
+--- a/src/plugins/preauth/pkinit/pkinit_clnt.c
++++ b/src/plugins/preauth/pkinit/pkinit_clnt.c
+@@ -179,6 +179,7 @@ pa_pkinit_gen_req(krb5_context context,
+ 
+     *out_padata = return_pa_data;
+     return_pa_data = NULL;
++    cb->disable_fallback(context, rock);
+ 
+ cleanup:
+     krb5_free_data(context, der_req);
+diff --git a/src/plugins/preauth/spake/spake_client.c b/src/plugins/preauth/spake/spake_client.c
+index 47a6ba26c..00734a13b 100644
+--- a/src/plugins/preauth/spake/spake_client.c
++++ b/src/plugins/preauth/spake/spake_client.c
+@@ -278,6 +278,10 @@ process_challenge(krb5_context context, groupstate *gstate, reqstate *st,
+         goto cleanup;
+     TRACE_SPAKE_SEND_RESPONSE(context);
+     ret = convert_to_padata(response, pa_out);
++    if (ret)
++        goto cleanup;
++
++    cb->disable_fallback(context, rock);
+ 
+ cleanup:
+     krb5_free_keyblock(context, k0);
+diff --git a/src/plugins/preauth/test/cltest.c b/src/plugins/preauth/test/cltest.c
+index f5f7c5aba..51b848481 100644
+--- a/src/plugins/preauth/test/cltest.c
++++ b/src/plugins/preauth/test/cltest.c
+@@ -53,6 +53,9 @@
+  * - If the "fail_optimistic", "fail_2rt", or "fail_tryagain" gic options are
+  *   set, it fails with a recognizable error string at the requested point in
+  *   processing.
++ *
++ * - If the "disable_fallback" gic option is set, fallback is disabled when a
++ *   client message is generated.
+  */
+ 
+ #include "k5-int.h"
+@@ -66,6 +69,7 @@ struct client_state {
+     krb5_boolean fail_optimistic;
+     krb5_boolean fail_2rt;
+     krb5_boolean fail_tryagain;
++    krb5_boolean disable_fallback;
+ };
+ 
+ struct client_request_state {
+@@ -81,6 +85,7 @@ test_init(krb5_context context, krb5_clpreauth_moddata *moddata_out)
+     assert(st != NULL);
+     st->indicators = NULL;
+     st->fail_optimistic = st->fail_2rt = st->fail_tryagain = FALSE;
++    st->disable_fallback = FALSE;
+     *moddata_out = (krb5_clpreauth_moddata)st;
+     return 0;
+ }
+@@ -138,6 +143,8 @@ test_process(krb5_context context, krb5_clpreauth_moddata moddata,
+             return KRB5_PREAUTH_FAILED;
+         }
+         *out_pa_data = make_pa_list("optimistic", 10);
++        if (st->disable_fallback)
++            cb->disable_fallback(context, rock);
+         return 0;
+     } else if (reqst->second_round_trip) {
+         printf("2rt: %.*s\n", pa_data->length, pa_data->contents);
+@@ -166,6 +173,8 @@ test_process(krb5_context context, krb5_clpreauth_moddata moddata,
+ 
+     indstr = (st->indicators != NULL) ? st->indicators : "";
+     *out_pa_data = make_pa_list(indstr, strlen(indstr));
++    if (st->disable_fallback)
++        cb->disable_fallback(context, rock);
+     return 0;
+ }
+ 
+@@ -212,6 +221,8 @@ test_gic_opt(krb5_context kcontext, krb5_clpreauth_moddata moddata,
+         st->fail_2rt = TRUE;
+     } else if (strcmp(attr, "fail_tryagain") == 0) {
+         st->fail_tryagain = TRUE;
++    } else if (strcmp(attr, "disable_fallback") == 0) {
++        st->disable_fallback = TRUE;
+     }
+     return 0;
+ }
+diff --git a/src/tests/t_preauth.py b/src/tests/t_preauth.py
+index efb3ea20d..32e35b08b 100644
+--- a/src/tests/t_preauth.py
++++ b/src/tests/t_preauth.py
+@@ -37,8 +37,8 @@ expected_trace = ('Attempting optimistic preauth',
+ realm.run(['./icred', '-o', '-123', realm.user_princ, password('user')],
+           expected_trace=expected_trace)
+ 
+-# Test optimistic preauth failing on client, followed by successful
+-# preauth using the same module.
++# Test optimistic preauth failing on client, falling back to encrypted
++# timestamp.
+ msgs = ('Attempting optimistic preauth',
+         'Processing preauth types: -123',
+         '/induced optimistic fail',
+@@ -46,15 +46,15 @@ msgs = ('Attempting optimistic preauth',
+         '/Additional pre-authentication required',
+         'Preauthenticating using KDC method data',
+         'Processing preauth types:',
+-        'Preauth module test (-123) (real) returned: 0/Success',
+-        'Produced preauth for next request: PA-FX-COOKIE (133), -123',
++        'Encrypted timestamp (for ',
++        'module encrypted_timestamp (2) (real) returned: 0/Success',
++        'preauth for next request: PA-FX-COOKIE (133), PA-ENC-TIMESTAMP (2)',
+         'Decrypted AS reply')
+ realm.run(['./icred', '-o', '-123', '-X', 'fail_optimistic', realm.user_princ,
+-           password('user')], expected_msg='testval',
+-          expected_trace=msgs)
++           password('user')], expected_trace=msgs)
+ 
+-# Test optimistic preauth failing on KDC, followed by successful preauth
+-# using the same module.
++# Test optimistic preauth failing on KDC, falling back to encrypted
++# timestamp.
+ realm.run([kadminl, 'setstr', realm.user_princ, 'failopt', 'yes'])
+ msgs = ('Attempting optimistic preauth',
+         'Processing preauth types: -123',
+@@ -63,11 +63,24 @@ msgs = ('Attempting optimistic preauth',
+         '/Preauthentication failed',
+         'Preauthenticating using KDC method data',
+         'Processing preauth types:',
+-        'Preauth module test (-123) (real) returned: 0/Success',
+-        'Produced preauth for next request: PA-FX-COOKIE (133), -123',
++        'Encrypted timestamp (for ',
++        'module encrypted_timestamp (2) (real) returned: 0/Success',
++        'preauth for next request: PA-FX-COOKIE (133), PA-ENC-TIMESTAMP (2)',
+         'Decrypted AS reply')
+ realm.run(['./icred', '-o', '-123', realm.user_princ, password('user')],
+-          expected_msg='testval', expected_trace=msgs)
++          expected_trace=msgs)
++# Leave failopt set for the next test.
++
++# Test optimistic preauth failing on KDC, stopping because the test
++# module disabled fallback.
++msgs = ('Attempting optimistic preauth',
++        'Processing preauth types: -123',
++        'Preauth module test (-123) (real) returned: 0/Success',
++        'Produced preauth for next request: -123',
++        '/Preauthentication failed')
++realm.run(['./icred', '-X', 'disable_fallback', '-o', '-123', realm.user_princ,
++           password('user')], expected_code=1,
++          expected_msg='Preauthentication failed', expected_trace=msgs)
+ realm.run([kadminl, 'delstr', realm.user_princ, 'failopt'])
+ 
+ # Test KDC_ERR_MORE_PREAUTH_DATA_REQUIRED and secure cookies.
+@@ -107,6 +120,23 @@ msgs = ('Sending unauthenticated request',
+ realm.run(['./icred', '-X', 'fail_2rt', realm.user_princ, password('user')],
+           expected_msg='2rt: secondtrip', expected_trace=msgs)
+ 
++# Test client-side failure after KDC_ERR_MORE_PREAUTH_DATA_REQUIRED,
++# stopping because the test module disabled fallback.
++msgs = ('Sending unauthenticated request',
++        '/Additional pre-authentication required',
++        'Preauthenticating using KDC method data',
++        'Processing preauth types:',
++        'Preauth module test (-123) (real) returned: 0/Success',
++        'Produced preauth for next request: PA-FX-COOKIE (133), -123',
++        '/More preauthentication data is required',
++        'Continuing preauth mech -123',
++        'Processing preauth types: -123, PA-FX-COOKIE (133)',
++        '/induced 2rt fail')
++realm.run(['./icred', '-X', 'fail_2rt', '-X', 'disable_fallback',
++           realm.user_princ, password('user')], expected_code=1,
++          expected_msg='Pre-authentication failed: induced 2rt fail',
++          expected_trace=msgs)
++
+ # Test KDC-side failure after KDC_ERR_MORE_PREAUTH_DATA_REQUIRED,
+ # falling back to encrypted timestamp.
+ realm.run([kadminl, 'setstr', realm.user_princ, 'fail2rt', 'yes'])
+@@ -130,6 +160,25 @@ msgs = ('Sending unauthenticated request',
+         'Decrypted AS reply')
+ realm.run(['./icred', realm.user_princ, password('user')],
+           expected_msg='2rt: secondtrip', expected_trace=msgs)
++# Leave fail2rt set for the next test.
++
++# Test KDC-side failure after KDC_ERR_MORE_PREAUTH_DATA_REQUIRED,
++# stopping because the test module disabled fallback.
++msgs = ('Sending unauthenticated request',
++        '/Additional pre-authentication required',
++        'Preauthenticating using KDC method data',
++        'Processing preauth types:',
++        'Preauth module test (-123) (real) returned: 0/Success',
++        'Produced preauth for next request: PA-FX-COOKIE (133), -123',
++        '/More preauthentication data is required',
++        'Continuing preauth mech -123',
++        'Processing preauth types: -123, PA-FX-COOKIE (133)',
++        'Preauth module test (-123) (real) returned: 0/Success',
++        'Produced preauth for next request: PA-FX-COOKIE (133), -123',
++        '/Preauthentication failed')
++realm.run(['./icred', '-X', 'disable_fallback',
++           realm.user_princ, password('user')], expected_code=1,
++          expected_msg='Preauthentication failed', expected_trace=msgs)
+ realm.run([kadminl, 'delstr', realm.user_princ, 'fail2rt'])
+ 
+ # Test tryagain flow by inducing a KDC_ERR_ENCTYPE_NOSUPP error on the KDC.
+@@ -170,6 +219,23 @@ msgs = ('Sending unauthenticated request',
+ realm.run(['./icred', '-X', 'fail_tryagain', realm.user_princ,
+            password('user')], expected_trace=msgs)
+ 
++# Test a client-side tryagain failure, stopping because the test
++# module disabled fallback.
++msgs = ('Sending unauthenticated request',
++        '/Additional pre-authentication required',
++        'Preauthenticating using KDC method data',
++        'Processing preauth types:',
++        'Preauth module test (-123) (real) returned: 0/Success',
++        'Produced preauth for next request: PA-FX-COOKIE (133), -123',
++        '/KDC has no support for encryption type',
++        'Recovering from KDC error 14 using preauth mech -123',
++        'Preauth tryagain input types (-123): -123, PA-FX-COOKIE (133)',
++        '/induced tryagain fail')
++realm.run(['./icred', '-X', 'fail_tryagain', '-X', 'disable_fallback',
++           realm.user_princ, password('user')], expected_code=1,
++          expected_msg='KDC has no support for encryption type',
++          expected_trace=msgs)
++
+ # Test that multiple stepwise initial creds operations can be
+ # performed with the same krb5_context, with proper tracking of
+ # clpreauth module request handles.
+diff --git a/src/tests/t_spake.py b/src/tests/t_spake.py
+index a81a238b4..5b47e62d3 100644
+--- a/src/tests/t_spake.py
++++ b/src/tests/t_spake.py
+@@ -31,9 +31,7 @@ for gnum, gname in groups:
+                 'Decrypted AS reply')
+         realm.kinit('user', 'pw', expected_trace=msgs)
+ 
+-        # Test an unsuccessful authentication.  (The client will try
+-        # again with encrypted timestamp, which isn't really desired,
+-        # but check for that as long as it is expected.)
++        # Test an unsuccessful authentication.
+         msgs = ('/Additional pre-authentication required',
+                 'Selected etype info:',
+                 'Sending SPAKE support message',
+@@ -42,9 +40,6 @@ for gnum, gname in groups:
+                 'Continuing preauth mech PA-SPAKE (151)',
+                 'SPAKE challenge received with group ' + str(gnum),
+                 'Sending SPAKE response',
+-                '/Preauthentication failed',
+-                'Encrypted timestamp ',
+-                'for next request: PA-FX-COOKIE (133), PA-ENC-TIMESTAMP (2)',
+                 '/Preauthentication failed')
+         realm.kinit('user', 'wrongpw', expected_code=1, expected_trace=msgs)
+ 
+@@ -114,8 +109,6 @@ msgs = ('Attempting optimistic preauth',
+         'for next request: PA-SPAKE (151)',
+         '/Preauthentication failed',
+         'Selected etype info:',
+-        'SPAKE challenge with group 1 rejected',
+-        'spake (151) (real) returned: -1765328360/Preauthentication failed',
+         'Encrypted timestamp ',
+         'for next request: PA-FX-COOKIE (133), PA-ENC-TIMESTAMP (2)',
+         'AS key determined by preauth:',
diff --git a/SOURCES/Simplify-kdc_preauth.c-systems-table.patch b/SOURCES/Simplify-kdc_preauth.c-systems-table.patch
new file mode 100644
index 0000000..08853d4
--- /dev/null
+++ b/SOURCES/Simplify-kdc_preauth.c-systems-table.patch
@@ -0,0 +1,738 @@
+From 65f078dfc68f5680e87e686a59970291b64ebd95 Mon Sep 17 00:00:00 2001
+From: Greg Hudson <ghudson@mit.edu>
+Date: Sun, 11 Feb 2018 15:23:35 -0500
+Subject: [PATCH] Simplify kdc_preauth.c systems table
+
+Get rid of static_preauth_systems, and replace it with explicit calls
+to helper functions in get_preauth_hint_list() and return_padata().
+Stop preallocating pa-data lists, instead reallocating on each
+addition using add_pa_data_element().  Also simplify
+maybe_add_etype_info2() using add_pa_data_element().
+
+The KRB5_PADATA_PAC_REQUEST table entry did nothing, and was probably
+originally added back when the KDC would error out on unrecognized
+padata types.  The KRB5_PADATA_SERVER_REFERRAL entry has been disabled
+since it was first added.
+
+(cherry picked from commit fea1a488924faa3938ef723feaa1ff12d22a91ff)
+---
+ src/kdc/kdc_preauth.c | 526 +++++++++++++++---------------------------
+ 1 file changed, 184 insertions(+), 342 deletions(-)
+
+diff --git a/src/kdc/kdc_preauth.c b/src/kdc/kdc_preauth.c
+index edc30bd83..6f34dc289 100644
+--- a/src/kdc/kdc_preauth.c
++++ b/src/kdc/kdc_preauth.c
+@@ -101,108 +101,14 @@ typedef struct preauth_system_st {
+     krb5_kdcpreauth_loop_fn loop;
+ } preauth_system;
+ 
++static preauth_system *preauth_systems;
++static size_t n_preauth_systems;
++
+ static krb5_error_code
+ make_etype_info(krb5_context context, krb5_preauthtype pa_type,
+                 krb5_principal client, krb5_key_data *client_key,
+                 krb5_enctype enctype, krb5_pa_data **pa_out);
+ 
+-static void
+-get_etype_info(krb5_context context, krb5_kdc_req *request,
+-               krb5_kdcpreauth_callbacks cb, krb5_kdcpreauth_rock rock,
+-               krb5_kdcpreauth_moddata moddata, krb5_preauthtype pa_type,
+-               krb5_kdcpreauth_edata_respond_fn respond, void *arg);
+-
+-static krb5_error_code
+-return_etype_info(krb5_context, krb5_pa_data *padata,
+-                  krb5_data *req_pkt, krb5_kdc_req *request,
+-                  krb5_kdc_rep *reply, krb5_keyblock *encrypting_key,
+-                  krb5_pa_data **send_pa, krb5_kdcpreauth_callbacks cb,
+-                  krb5_kdcpreauth_rock rock, krb5_kdcpreauth_moddata moddata,
+-                  krb5_kdcpreauth_modreq modreq);
+-
+-static krb5_error_code
+-return_pw_salt(krb5_context, krb5_pa_data *padata,
+-               krb5_data *req_pkt, krb5_kdc_req *request, krb5_kdc_rep *reply,
+-               krb5_keyblock *encrypting_key, krb5_pa_data **send_pa,
+-               krb5_kdcpreauth_callbacks cb, krb5_kdcpreauth_rock rock,
+-               krb5_kdcpreauth_moddata moddata, krb5_kdcpreauth_modreq modreq);
+-
+-
+-
+-static preauth_system static_preauth_systems[] = {
+-    {
+-        "FAST",
+-        KRB5_PADATA_FX_FAST,
+-        PA_HARDWARE,
+-        NULL,
+-        NULL,
+-        NULL,
+-        NULL,
+-        NULL,
+-        0
+-    },
+-    {
+-        "etype-info",
+-        KRB5_PADATA_ETYPE_INFO,
+-        PA_HARDWARE,
+-        NULL,
+-        NULL,
+-        NULL,
+-        get_etype_info,
+-        0,
+-        return_etype_info
+-    },
+-    {
+-        "etype-info2",
+-        KRB5_PADATA_ETYPE_INFO2,
+-        PA_HARDWARE,
+-        NULL,
+-        NULL,
+-        NULL,
+-        get_etype_info,
+-        0,
+-        return_etype_info
+-    },
+-    {
+-        "pw-salt",
+-        KRB5_PADATA_PW_SALT,
+-        PA_PSEUDO,              /* Don't include this in the error list */
+-        NULL,
+-        NULL,
+-        NULL,
+-        0,
+-        0,
+-        return_pw_salt
+-    },
+-    {
+-        "pac-request",
+-        KRB5_PADATA_PAC_REQUEST,
+-        PA_PSEUDO,
+-        NULL,
+-        NULL,
+-        NULL,
+-        NULL,
+-        NULL,
+-        NULL
+-    },
+-#if 0
+-    {
+-        "server-referral",
+-        KRB5_PADATA_SERVER_REFERRAL,
+-        PA_PSEUDO,
+-        0,
+-        0,
+-        return_server_referral
+-    },
+-#endif
+-};
+-
+-#define NUM_STATIC_PREAUTH_SYSTEMS (sizeof(static_preauth_systems) /    \
+-                                    sizeof(*static_preauth_systems))
+-
+-static preauth_system *preauth_systems;
+-static size_t n_preauth_systems;
+-
+ /* Get all available kdcpreauth vtables and a count of preauth types they
+  * support.  Return an empty list on failure. */
+ static void
+@@ -284,7 +190,6 @@ load_preauth_plugins(struct server_handle *handle, krb5_context context,
+     get_plugin_vtables(context, &vtables, &n_tables, &n_systems);
+ 
+     /* Allocate the list of static and plugin preauth systems. */
+-    n_systems += NUM_STATIC_PREAUTH_SYSTEMS;
+     preauth_systems = calloc(n_systems + 1, sizeof(preauth_system));
+     if (preauth_systems == NULL)
+         goto cleanup;
+@@ -292,13 +197,8 @@ load_preauth_plugins(struct server_handle *handle, krb5_context context,
+     if (get_realm_names(handle, &realm_names))
+         goto cleanup;
+ 
+-    /* Add the static system to the list first.  No static systems require
+-     * initialization, so just make a direct copy. */
+-    memcpy(preauth_systems, static_preauth_systems,
+-           sizeof(static_preauth_systems));
+-
+     /* Add the dynamically-loaded mechanisms to the list. */
+-    n_systems = NUM_STATIC_PREAUTH_SYSTEMS;
++    n_systems = 0;
+     for (i = 0; i < n_tables; i++) {
+         /* Try to initialize this module. */
+         vt = &vtables[i];
+@@ -622,7 +522,9 @@ find_pa_system(int type, preauth_system **preauth)
+ {
+     preauth_system *ap;
+ 
+-    ap = preauth_systems ? preauth_systems : static_preauth_systems;
++    if (preauth_systems == NULL)
++        return KRB5_PREAUTH_BAD_TYPE;
++    ap = preauth_systems;
+     while ((ap->type != -1) && (ap->type != type))
+         ap++;
+     if (ap->type == -1)
+@@ -776,6 +678,98 @@ const char *missing_required_preauth(krb5_db_entry *client,
+     return 0;
+ }
+ 
++/* Return true if request's enctypes indicate support for etype-info2. */
++static krb5_boolean
++requires_info2(const krb5_kdc_req *request)
++{
++    int i;
++
++    for (i = 0; i < request->nktypes; i++) {
++        if (enctype_requires_etype_info_2(request->ktype[i]))
++            return TRUE;
++    }
++    return FALSE;
++}
++
++/* Add PA-ETYPE-INFO2 and possibly PA-ETYPE-INFO entries to pa_list as
++ * appropriate for the request and client principal. */
++static krb5_error_code
++add_etype_info(krb5_context context, krb5_kdcpreauth_rock rock,
++               krb5_pa_data ***pa_list)
++{
++    krb5_error_code ret;
++    krb5_pa_data *pa;
++
++    if (rock->client_key == NULL)
++        return 0;
++
++    if (!requires_info2(rock->request)) {
++        /* Include PA-ETYPE-INFO only for old clients. */
++        ret = make_etype_info(context, KRB5_PADATA_ETYPE_INFO,
++                              rock->client->princ, rock->client_key,
++                              rock->client_keyblock->enctype, &pa);
++        if (ret)
++            return ret;
++        /* add_pa_data_element() claims pa on success or failure. */
++        ret = add_pa_data_element(pa_list, pa);
++        if (ret)
++            return ret;
++    }
++
++    /* Always include PA-ETYPE-INFO2. */
++    ret = make_etype_info(context, KRB5_PADATA_ETYPE_INFO2,
++                          rock->client->princ, rock->client_key,
++                          rock->client_keyblock->enctype, &pa);
++    if (ret)
++        return ret;
++    /* add_pa_data_element() claims pa on success or failure. */
++    return add_pa_data_element(pa_list, pa);
++}
++
++/* Add PW-SALT or AFS3-SALT entries to pa_list as appropriate for the request
++ * and client principal. */
++static krb5_error_code
++add_pw_salt(krb5_context context, krb5_kdcpreauth_rock rock,
++            krb5_pa_data ***pa_list)
++{
++    krb5_error_code ret;
++    krb5_pa_data *pa;
++    krb5_data *salt = NULL;
++    krb5_int16 salttype;
++
++    /* Only include this pa-data for old clients. */
++    if (rock->client_key == NULL || requires_info2(rock->request))
++        return 0;
++
++    ret = krb5_dbe_compute_salt(context, rock->client_key,
++                                rock->request->client, &salttype, &salt);
++    if (ret)
++        return 0;
++
++    if (salttype == KRB5_KDB_SALTTYPE_AFS3) {
++        ret = alloc_pa_data(KRB5_PADATA_AFS3_SALT, salt->length + 1, &pa);
++        if (ret)
++            goto cleanup;
++        memcpy(pa->contents, salt->data, salt->length);
++        pa->contents[salt->length] = '\0';
++    } else {
++        /* Steal memory from salt to make the pa-data entry. */
++        ret = alloc_pa_data(KRB5_PADATA_PW_SALT, 0, &pa);
++        if (ret)
++            goto cleanup;
++        pa->length = salt->length;
++        pa->contents = (uint8_t *)salt->data;
++        salt->data = NULL;
++    }
++
++    /* add_pa_data_element() claims pa on success or failure. */
++    ret = add_pa_data_element(pa_list, pa);
++
++cleanup:
++    krb5_free_data(context, salt);
++    return ret;
++}
++
+ struct hint_state {
+     kdc_hint_respond_fn respond;
+     void *arg;
+@@ -787,7 +781,7 @@ struct hint_state {
+ 
+     int hw_only;
+     preauth_system *ap;
+-    krb5_pa_data **pa_data, **pa_cur;
++    krb5_pa_data **pa_data;
+     krb5_preauthtype pa_type;
+ };
+ 
+@@ -799,7 +793,7 @@ hint_list_finish(struct hint_state *state, krb5_error_code code)
+     kdc_realm_t *kdc_active_realm = state->realm;
+ 
+     if (!code) {
+-        if (state->pa_data[0] == 0) {
++        if (state->pa_data == NULL) {
+             krb5_klog_syslog(LOG_INFO,
+                              _("%spreauth required but hint list is empty"),
+                              state->hw_only ? "hw" : "");
+@@ -820,20 +814,27 @@ hint_list_next(struct hint_state *arg);
+ static void
+ finish_get_edata(void *arg, krb5_error_code code, krb5_pa_data *pa)
+ {
++    krb5_error_code ret;
+     struct hint_state *state = arg;
+ 
+     if (code == 0) {
+         if (pa == NULL) {
+-            /* Include an empty value of the current type. */
+-            pa = calloc(1, sizeof(*pa));
+-            pa->magic = KV5M_PA_DATA;
+-            pa->pa_type = state->pa_type;
++            ret = alloc_pa_data(state->pa_type, 0, &pa);
++            if (ret)
++                goto error;
+         }
+-        *state->pa_cur++ = pa;
++        /* add_pa_data_element() claims pa on success or failure. */
++        ret = add_pa_data_element(&state->pa_data, pa);
++        if (ret)
++            goto error;
+     }
+ 
+     state->ap++;
+     hint_list_next(state);
++    return;
++
++error:
++    hint_list_finish(state, ret);
+ }
+ 
+ static void
+@@ -870,16 +871,16 @@ get_preauth_hint_list(krb5_kdc_req *request, krb5_kdcpreauth_rock rock,
+                       krb5_pa_data ***e_data_out, kdc_hint_respond_fn respond,
+                       void *arg)
+ {
++    kdc_realm_t *kdc_active_realm = rock->rstate->realm_data;
+     struct hint_state *state;
++    krb5_pa_data *pa;
+ 
+     *e_data_out = NULL;
+ 
+     /* Allocate our state. */
+     state = calloc(1, sizeof(*state));
+-    if (state == NULL) {
+-        (*respond)(arg);
+-        return;
+-    }
++    if (state == NULL)
++        goto error;
+     state->hw_only = isflagset(rock->client->attributes,
+                                KRB5_KDB_REQUIRES_HW_AUTH);
+     state->respond = respond;
+@@ -888,17 +889,27 @@ get_preauth_hint_list(krb5_kdc_req *request, krb5_kdcpreauth_rock rock,
+     state->rock = rock;
+     state->realm = rock->rstate->realm_data;
+     state->e_data_out = e_data_out;
+-
+-    state->pa_data = calloc(n_preauth_systems + 1, sizeof(krb5_pa_data *));
+-    if (!state->pa_data) {
+-        free(state);
+-        (*respond)(arg);
+-        return;
+-    }
+-
+-    state->pa_cur = state->pa_data;
++    state->pa_data = NULL;
+     state->ap = preauth_systems;
++
++    /* Add an empty PA-FX-FAST element to advertise FAST support. */
++    if (alloc_pa_data(KRB5_PADATA_FX_FAST, 0, &pa) != 0)
++        goto error;
++    /* add_pa_data_element() claims pa on success or failure. */
++    if (add_pa_data_element(&state->pa_data, pa) != 0)
++        goto error;
++
++    if (add_etype_info(kdc_context, rock, &state->pa_data) != 0)
++        goto error;
++
+     hint_list_next(state);
++    return;
++
++error:
++    if (state != NULL)
++        krb5_free_pa_data(kdc_context, state->pa_data);
++    free(state);
++    (*respond)(arg);
+ }
+ 
+ /*
+@@ -1029,10 +1040,10 @@ filter_preauth_error(krb5_error_code code)
+ static krb5_error_code
+ maybe_add_etype_info2(struct padata_state *state, krb5_error_code code)
+ {
++    krb5_error_code ret;
+     krb5_context context = state->context;
+     krb5_kdcpreauth_rock rock = state->rock;
+-    krb5_pa_data **list = state->pa_e_data;
+-    size_t count;
++    krb5_pa_data *pa;
+ 
+     /* Only add key information when requesting another preauth round trip. */
+     if (code != KRB5KDC_ERR_MORE_PREAUTH_DATA_REQUIRED)
+@@ -1048,18 +1059,14 @@ maybe_add_etype_info2(struct padata_state *state, krb5_error_code code)
+                              KRB5_PADATA_FX_COOKIE) != NULL)
+         return 0;
+ 
+-    /* Reallocate state->pa_e_data to make room for the etype-info2 element. */
+-    for (count = 0; list != NULL && list[count] != NULL; count++);
+-    list = realloc(list, (count + 2) * sizeof(*list));
+-    if (list == NULL)
+-        return ENOMEM;
+-    list[count] = list[count + 1] = NULL;
+-    state->pa_e_data = list;
++    ret = make_etype_info(context, KRB5_PADATA_ETYPE_INFO2,
++                          rock->client->princ, rock->client_key,
++                          rock->client_keyblock->enctype, &pa);
++    if (ret)
++        return ret;
+ 
+-    /* Generate an etype-info2 element in the new slot. */
+-    return make_etype_info(context, KRB5_PADATA_ETYPE_INFO2,
+-                           rock->client->princ, rock->client_key,
+-                           rock->client_keyblock->enctype, &list[count]);
++    /* add_pa_data_element() claims pa on success or failure. */
++    return add_pa_data_element(&state->pa_e_data, pa);
+ }
+ 
+ /* Release state and respond to the AS-REQ processing code with the result of
+@@ -1279,17 +1286,20 @@ return_padata(krb5_context context, krb5_kdcpreauth_rock rock,
+ {
+     krb5_error_code             retval;
+     krb5_pa_data **             padata;
+-    krb5_pa_data **             send_pa_list;
+-    krb5_pa_data **             send_pa;
++    krb5_pa_data **             send_pa_list = NULL;
++    krb5_pa_data *              send_pa;
+     krb5_pa_data *              pa = 0;
+     krb5_pa_data null_item;
+     preauth_system *            ap;
+-    int *                       pa_order;
++    int *                       pa_order = NULL;
+     int *                       pa_type;
+     int                         size = 0;
+     krb5_kdcpreauth_modreq      *modreq_ptr;
+     krb5_boolean                key_modified;
+     krb5_keyblock               original_key;
++
++    memset(&original_key, 0, sizeof(original_key));
++
+     if ((!*padata_context) &&
+         (make_padata_context(context, padata_context) != 0)) {
+         return KRB5KRB_ERR_GENERIC;
+@@ -1300,26 +1310,18 @@ return_padata(krb5_context context, krb5_kdcpreauth_rock rock,
+             size++;
+     }
+ 
+-    if ((send_pa_list = malloc((size+1) * sizeof(krb5_pa_data *))) == NULL)
+-        return ENOMEM;
+-    if ((pa_order = malloc((size+1) * sizeof(int))) == NULL) {
+-        free(send_pa_list);
+-        return ENOMEM;
+-    }
++    pa_order = k5calloc(size + 1, sizeof(int), &retval);
++    if (pa_order == NULL)
++        goto cleanup;
+     sort_pa_order(context, request, pa_order);
+ 
+     retval = krb5_copy_keyblock_contents(context, encrypting_key,
+                                          &original_key);
+-    if (retval) {
+-        free(send_pa_list);
+-        free(pa_order);
+-        return retval;
+-    }
++    if (retval)
++        goto cleanup;
+     key_modified = FALSE;
+     null_item.contents = NULL;
+     null_item.length = 0;
+-    send_pa = send_pa_list;
+-    *send_pa = 0;
+ 
+     for (pa_type = pa_order; *pa_type != -1; pa_type++) {
+         ap = &preauth_systems[*pa_type];
+@@ -1349,20 +1351,30 @@ return_padata(krb5_context context, krb5_kdcpreauth_rock rock,
+                 }
+             }
+         }
++        send_pa = NULL;
+         retval = ap->return_padata(context, pa, req_pkt, request, reply,
+-                                   encrypting_key, send_pa, &callbacks, rock,
++                                   encrypting_key, &send_pa, &callbacks, rock,
+                                    ap->moddata, *modreq_ptr);
+         if (retval)
+             goto cleanup;
+ 
+-        if (*send_pa)
+-            send_pa++;
+-        *send_pa = 0;
++        if (send_pa != NULL) {
++            /* add_pa_data_element() claims send_pa on success or failure. */
++            retval = add_pa_data_element(&send_pa_list, send_pa);
++            if (retval)
++                goto cleanup;
++        }
+     }
+ 
+-    retval = 0;
++    /* Add etype-info and pw-salt pa-data as needed. */
++    retval = add_etype_info(context, rock, &send_pa_list);
++    if (retval)
++        goto cleanup;
++    retval = add_pw_salt(context, rock, &send_pa_list);
++    if (retval)
++        goto cleanup;
+ 
+-    if (send_pa_list[0]) {
++    if (send_pa_list != NULL) {
+         reply->padata = send_pa_list;
+         send_pa_list = 0;
+     }
+@@ -1370,8 +1382,7 @@ return_padata(krb5_context context, krb5_kdcpreauth_rock rock,
+ cleanup:
+     krb5_free_keyblock_contents(context, &original_key);
+     free(pa_order);
+-    if (send_pa_list)
+-        krb5_free_pa_data(context, send_pa_list);
++    krb5_free_pa_data(context, send_pa_list);
+ 
+     return (retval);
+ }
+@@ -1438,9 +1449,8 @@ make_etype_info(krb5_context context, krb5_preauthtype pa_type,
+                 krb5_enctype enctype, krb5_pa_data **pa_out)
+ {
+     krb5_error_code retval;
+-    krb5_pa_data *pa = NULL;
+     krb5_etype_info_entry **entry = NULL;
+-    krb5_data *scratch = NULL;
++    krb5_data *der_etype_info = NULL;
+     int etype_info2 = (pa_type == KRB5_PADATA_ETYPE_INFO2);
+ 
+     *pa_out = NULL;
+@@ -1454,125 +1464,23 @@ make_etype_info(krb5_context context, krb5_preauthtype pa_type,
+         goto cleanup;
+ 
+     if (etype_info2)
+-        retval = encode_krb5_etype_info2(entry, &scratch);
++        retval = encode_krb5_etype_info2(entry, &der_etype_info);
+     else
+-        retval = encode_krb5_etype_info(entry, &scratch);
++        retval = encode_krb5_etype_info(entry, &der_etype_info);
+     if (retval)
+         goto cleanup;
+-    pa = k5alloc(sizeof(*pa), &retval);
+-    if (pa == NULL)
++
++    /* Steal the data from der_etype_info to create a pa-data element. */
++    retval = alloc_pa_data(pa_type, 0, pa_out);
++    if (retval)
+         goto cleanup;
+-    pa->magic = KV5M_PA_DATA;
+-    pa->pa_type = pa_type;
+-    pa->contents = (unsigned char *)scratch->data;
+-    pa->length = scratch->length;
+-    scratch->data = NULL;
+-    *pa_out = pa;
++    (*pa_out)->contents = (uint8_t *)der_etype_info->data;
++    (*pa_out)->length = der_etype_info->length;
++    der_etype_info->data = NULL;
+ 
+ cleanup:
+     krb5_free_etype_info(context, entry);
+-    krb5_free_data(context, scratch);
+-    return retval;
+-}
+-
+-/* Return true if request's enctypes indicate support for etype-info2. */
+-static krb5_boolean
+-requires_info2(const krb5_kdc_req *request)
+-{
+-    int i;
+-
+-    for (i = 0; i < request->nktypes; i++) {
+-        if (enctype_requires_etype_info_2(request->ktype[i]))
+-            return TRUE;
+-    }
+-    return FALSE;
+-}
+-
+-/* Generate hint list padata for PA-ETYPE-INFO or PA-ETYPE-INFO2. */
+-static void
+-get_etype_info(krb5_context context, krb5_kdc_req *request,
+-               krb5_kdcpreauth_callbacks cb, krb5_kdcpreauth_rock rock,
+-               krb5_kdcpreauth_moddata moddata, krb5_preauthtype pa_type,
+-               krb5_kdcpreauth_edata_respond_fn respond, void *arg)
+-{
+-    krb5_error_code ret;
+-    krb5_pa_data *pa = NULL;
+-
+-    if (rock->client_key == NULL) {
+-        ret = KRB5KDC_ERR_PADATA_TYPE_NOSUPP;
+-    } else if (pa_type == KRB5_PADATA_ETYPE_INFO && requires_info2(request)) {
+-        ret = KRB5KDC_ERR_PADATA_TYPE_NOSUPP;
+-    } else {
+-        ret = make_etype_info(context, pa_type, rock->client->princ,
+-                              rock->client_key, rock->client_keyblock->enctype,
+-                              &pa);
+-    }
+-    (*respond)(arg, ret, pa);
+-}
+-
+-/* Generate AS-REP padata for PA-ETYPE-INFO or PA-ETYPE-INFO2. */
+-static krb5_error_code
+-return_etype_info(krb5_context context, krb5_pa_data *padata,
+-                  krb5_data *req_pkt, krb5_kdc_req *request,
+-                  krb5_kdc_rep *reply, krb5_keyblock *encrypting_key,
+-                  krb5_pa_data **send_pa, krb5_kdcpreauth_callbacks cb,
+-                  krb5_kdcpreauth_rock rock, krb5_kdcpreauth_moddata moddata,
+-                  krb5_kdcpreauth_modreq modreq)
+-{
+-    *send_pa = NULL;
+-    if (rock->client_key == NULL)
+-        return 0;
+-    if (padata->pa_type == KRB5_PADATA_ETYPE_INFO && requires_info2(request))
+-        return 0;
+-    return make_etype_info(context, padata->pa_type, rock->client->princ,
+-                           rock->client_key, encrypting_key->enctype, send_pa);
+-}
+-
+-static krb5_error_code
+-return_pw_salt(krb5_context context, krb5_pa_data *in_padata,
+-               krb5_data *req_pkt, krb5_kdc_req *request, krb5_kdc_rep *reply,
+-               krb5_keyblock *encrypting_key, krb5_pa_data **send_pa,
+-               krb5_kdcpreauth_callbacks cb, krb5_kdcpreauth_rock rock,
+-               krb5_kdcpreauth_moddata moddata, krb5_kdcpreauth_modreq modreq)
+-{
+-    krb5_error_code     retval;
+-    krb5_pa_data *      padata;
+-    krb5_data *         salt = NULL;
+-    krb5_int16          salttype;
+-    krb5_key_data *     client_key = rock->client_key;
+-
+-    if (client_key == NULL || requires_info2(request))
+-        return 0;
+-
+-    retval = krb5_dbe_compute_salt(context, client_key, request->client,
+-                                   &salttype, &salt);
+-    if (retval)
+-        return 0;
+-
+-    padata = k5alloc(sizeof(*padata), &retval);
+-    if (padata == NULL)
+-        goto cleanup;
+-    padata->magic = KV5M_PA_DATA;
+-
+-    if (salttype == KRB5_KDB_SALTTYPE_AFS3) {
+-        padata->contents = k5memdup0(salt->data, salt->length, &retval);
+-        if (padata->contents == NULL)
+-            goto cleanup;
+-        padata->pa_type = KRB5_PADATA_AFS3_SALT;
+-        padata->length = salt->length + 1;
+-    } else {
+-        padata->pa_type = KRB5_PADATA_PW_SALT;
+-        padata->length = salt->length;
+-        padata->contents = (krb5_octet *)salt->data;
+-        salt->data = NULL;
+-    }
+-
+-    *send_pa = padata;
+-    padata = NULL;
+-
+-cleanup:
+-    free(padata);
+-    krb5_free_data(context, salt);
++    krb5_free_data(context, der_etype_info);
+     return retval;
+ }
+ 
+@@ -1656,69 +1564,3 @@ return_enc_padata(krb5_context context, krb5_data *req_pkt,
+ cleanup:
+     return code;
+ }
+-
+-
+-#if 0
+-static krb5_error_code return_server_referral(krb5_context context,
+-                                              krb5_pa_data * padata,
+-                                              krb5_db_entry *client,
+-                                              krb5_db_entry *server,
+-                                              krb5_kdc_req *request,
+-                                              krb5_kdc_rep *reply,
+-                                              krb5_key_data *client_key,
+-                                              krb5_keyblock *encrypting_key,
+-                                              krb5_pa_data **send_pa)
+-{
+-    krb5_error_code             code;
+-    krb5_tl_data                tl_data;
+-    krb5_pa_data                *pa_data;
+-    krb5_enc_data               enc_data;
+-    krb5_data                   plain;
+-    krb5_data                   *enc_pa_data;
+-
+-    *send_pa = NULL;
+-
+-    tl_data.tl_data_type = KRB5_TL_SERVER_REFERRAL;
+-
+-    code = krb5_dbe_lookup_tl_data(context, server, &tl_data);
+-    if (code || tl_data.tl_data_length == 0)
+-        return 0; /* no server referrals to return */
+-
+-    plain.length = tl_data.tl_data_length;
+-    plain.data = tl_data.tl_data_contents;
+-
+-    /* Encrypt ServerReferralData */
+-    code = krb5_encrypt_helper(context, encrypting_key,
+-                               KRB5_KEYUSAGE_PA_SERVER_REFERRAL_DATA,
+-                               &plain, &enc_data);
+-    if (code)
+-        return code;
+-
+-    /* Encode ServerReferralData into PA-SERVER-REFERRAL-DATA */
+-    code = encode_krb5_enc_data(&enc_data, &enc_pa_data);
+-    if (code) {
+-        krb5_free_data_contents(context, &enc_data.ciphertext);
+-        return code;
+-    }
+-
+-    krb5_free_data_contents(context, &enc_data.ciphertext);
+-
+-    /* Return PA-SERVER-REFERRAL-DATA */
+-    pa_data = (krb5_pa_data *)malloc(sizeof(*pa_data));
+-    if (pa_data == NULL) {
+-        krb5_free_data(context, enc_pa_data);
+-        return ENOMEM;
+-    }
+-
+-    pa_data->magic = KV5M_PA_DATA;
+-    pa_data->pa_type = KRB5_PADATA_SVR_REFERRAL_INFO;
+-    pa_data->length = enc_pa_data->length;
+-    pa_data->contents = enc_pa_data->data;
+-
+-    free(enc_pa_data); /* don't free contents */
+-
+-    *send_pa = pa_data;
+-
+-    return 0;
+-}
+-#endif
diff --git a/SOURCES/Use-SHA-256-instead-of-MD5-for-audit-ticket-IDs.patch b/SOURCES/Use-SHA-256-instead-of-MD5-for-audit-ticket-IDs.patch
new file mode 100644
index 0000000..26df25a
--- /dev/null
+++ b/SOURCES/Use-SHA-256-instead-of-MD5-for-audit-ticket-IDs.patch
@@ -0,0 +1,53 @@
+From a9bc03fe03ef4b00bcdad13c99bb4c376a8b9964 Mon Sep 17 00:00:00 2001
+From: Greg Hudson <ghudson@mit.edu>
+Date: Tue, 10 Jul 2018 16:17:15 -0400
+Subject: [PATCH] Use SHA-256 instead of MD5 for audit ticket IDs
+
+ticket: 8711 (new)
+(cherry picked from commit c1e1bfa26bd2f045e88e6013c500fca9428c98f3)
+---
+ src/kdc/kdc_audit.c | 21 ++++++++++-----------
+ 1 file changed, 10 insertions(+), 11 deletions(-)
+
+diff --git a/src/kdc/kdc_audit.c b/src/kdc/kdc_audit.c
+index c9a7f9f9d..f40913dc8 100644
+--- a/src/kdc/kdc_audit.c
++++ b/src/kdc/kdc_audit.c
+@@ -146,7 +146,7 @@ kau_make_tkt_id(krb5_context context,
+ {
+     krb5_error_code ret = 0;
+     char *hash = NULL, *ptr;
+-    krb5_checksum cksum;
++    uint8_t hashbytes[K5_SHA256_HASHLEN];
+     unsigned int i;
+ 
+     *out = NULL;
+@@ -154,19 +154,18 @@ kau_make_tkt_id(krb5_context context,
+     if (ticket == NULL)
+         return EINVAL;
+ 
+-    ret = krb5_c_make_checksum(context, CKSUMTYPE_RSA_MD5, NULL, 0,
+-                               &ticket->enc_part.ciphertext, &cksum);
++    ret = k5_sha256(&ticket->enc_part.ciphertext, 1, hashbytes);
+     if (ret)
+         return ret;
+ 
+-    hash = k5alloc(cksum.length * 2 + 1, &ret);
+-    if (hash != NULL) {
+-        for (i = 0, ptr = hash; i < cksum.length; i++, ptr += 2)
+-            snprintf(ptr, 3, "%02X", cksum.contents[i]);
+-        *ptr = '\0';
+-        *out = hash;
+-    }
+-    krb5_free_checksum_contents(context, &cksum);
++    hash = k5alloc(sizeof(hashbytes) * 2 + 1, &ret);
++    if (hash == NULL)
++        return ret;
++
++    for (i = 0, ptr = hash; i < sizeof(hashbytes); i++, ptr += 2)
++        snprintf(ptr, 3, "%02X", hashbytes[i]);
++    *ptr = '\0';
++    *out = hash;
+ 
+     return 0;
+ }
diff --git a/SOURCES/Use-k5_buf_init_dynamic_zap-where-appropriate.patch b/SOURCES/Use-k5_buf_init_dynamic_zap-where-appropriate.patch
new file mode 100644
index 0000000..3d3bcd8
--- /dev/null
+++ b/SOURCES/Use-k5_buf_init_dynamic_zap-where-appropriate.patch
@@ -0,0 +1,62 @@
+From c5df16a88027d7f9b6eb53b1c3fa949d6538616b Mon Sep 17 00:00:00 2001
+From: Greg Hudson <ghudson@mit.edu>
+Date: Mon, 26 Mar 2018 11:24:49 -0400
+Subject: [PATCH] Use k5_buf_init_dynamic_zap where appropriate
+
+(cherry picked from commit 9172599008f3a6790d4a9a67acff58049742dcb6)
+---
+ src/lib/krb5/ccache/cc_file.c    | 4 ++--
+ src/lib/krb5/ccache/cc_keyring.c | 2 +-
+ src/util/support/utf8_conv.c     | 4 +++-
+ 3 files changed, 6 insertions(+), 4 deletions(-)
+
+diff --git a/src/lib/krb5/ccache/cc_file.c b/src/lib/krb5/ccache/cc_file.c
+index 6789c09e1..9263a0054 100644
+--- a/src/lib/krb5/ccache/cc_file.c
++++ b/src/lib/krb5/ccache/cc_file.c
+@@ -758,7 +758,7 @@ fcc_next_cred(krb5_context context, krb5_ccache id, krb5_cc_cursor *cursor,
+ 
+     memset(creds, 0, sizeof(*creds));
+     k5_cc_mutex_lock(context, &data->lock);
+-    k5_buf_init_dynamic(&buf);
++    k5_buf_init_dynamic_zap(&buf);
+ 
+     ret = krb5_lock_file(context, fileno(fcursor->fp), KRB5_LOCKMODE_SHARED);
+     if (ret)
+@@ -982,7 +982,7 @@ fcc_store(krb5_context context, krb5_ccache id, krb5_creds *creds)
+         goto cleanup;
+ 
+     /* Marshal the cred and write it to the file with a single append write. */
+-    k5_buf_init_dynamic(&buf);
++    k5_buf_init_dynamic_zap(&buf);
+     k5_marshal_cred(&buf, version, creds);
+     ret = k5_buf_status(&buf);
+     if (ret)
+diff --git a/src/lib/krb5/ccache/cc_keyring.c b/src/lib/krb5/ccache/cc_keyring.c
+index fba710b1b..8419f6ebf 100644
+--- a/src/lib/krb5/ccache/cc_keyring.c
++++ b/src/lib/krb5/ccache/cc_keyring.c
+@@ -1295,7 +1295,7 @@ krcc_store(krb5_context context, krb5_ccache id, krb5_creds *creds)
+         goto errout;
+ 
+     /* Serialize credential using the file ccache version 4 format. */
+-    k5_buf_init_dynamic(&buf);
++    k5_buf_init_dynamic_zap(&buf);
+     k5_marshal_cred(&buf, 4, creds);
+     ret = k5_buf_status(&buf);
+     if (ret)
+diff --git a/src/util/support/utf8_conv.c b/src/util/support/utf8_conv.c
+index 5cfc2c512..08cef4168 100644
+--- a/src/util/support/utf8_conv.c
++++ b/src/util/support/utf8_conv.c
+@@ -99,7 +99,9 @@ k5_utf8_to_utf16le(const char *utf8, uint8_t **utf16_out, size_t *nbytes_out)
+     *utf16_out = NULL;
+     *nbytes_out = 0;
+ 
+-    k5_buf_init_dynamic(&buf);
++    /* UTF-16 conversion is used for RC4 string-to-key, so treat this data as
++     * sensitive. */
++    k5_buf_init_dynamic_zap(&buf);
+ 
+     /* Examine next UTF-8 character. */
+     while (*utf8 != '\0') {
diff --git a/SOURCES/Use-libkrb5support-hex-functions-where-appropriate.patch b/SOURCES/Use-libkrb5support-hex-functions-where-appropriate.patch
new file mode 100644
index 0000000..eab05bc
--- /dev/null
+++ b/SOURCES/Use-libkrb5support-hex-functions-where-appropriate.patch
@@ -0,0 +1,869 @@
+From 19109505ad04efdfd70df3ee922e22bcf5a294f3 Mon Sep 17 00:00:00 2001
+From: Greg Hudson <ghudson@mit.edu>
+Date: Mon, 19 Feb 2018 00:52:35 -0500
+Subject: [PATCH] Use libkrb5support hex functions where appropriate
+
+(cherry picked from commit b0c700608be7455041a8afc0e4502e8783ee7f30)
+---
+ src/kadmin/dbutil/deps                        | 16 ++---
+ src/kadmin/dbutil/tabdump.c                   | 19 +++---
+ src/kadmin/ktutil/deps                        | 13 ++--
+ src/kadmin/ktutil/ktutil_funcs.c              | 30 ++++-----
+ src/lib/crypto/crypto_tests/deps              | 39 ++++++-----
+ src/lib/crypto/crypto_tests/t_cksum.c         | 35 +++-------
+ src/lib/crypto/crypto_tests/t_crc.c           | 28 ++------
+ src/lib/crypto/crypto_tests/t_hmac.c          | 34 +++++-----
+ src/plugins/kdb/ldap/ldap_util/deps           | 18 ++---
+ .../kdb/ldap/ldap_util/kdb5_ldap_services.c   | 32 +++------
+ .../kdb/ldap/ldap_util/kdb5_ldap_services.h   |  2 -
+ src/plugins/kdb/ldap/libkdb_ldap/deps         | 19 +++---
+ .../kdb/ldap/libkdb_ldap/ldap_service_stash.c | 65 +++----------------
+ .../kdb/ldap/libkdb_ldap/ldap_service_stash.h |  3 -
+ .../kdb/ldap/libkdb_ldap/libkdb_ldap.exports  |  1 -
+ src/slave/deps                                | 15 +++--
+ src/slave/kproplog.c                          | 11 ++--
+ src/tests/gssapi/deps                         | 14 ++--
+ src/tests/gssapi/t_prf.c                      | 13 ++--
+ 19 files changed, 152 insertions(+), 255 deletions(-)
+
+diff --git a/src/kadmin/dbutil/deps b/src/kadmin/dbutil/deps
+index 4dcc33628..8b0965aac 100644
+--- a/src/kadmin/dbutil/deps
++++ b/src/kadmin/dbutil/deps
+@@ -185,14 +185,14 @@ $(OUTPRE)tabdump.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \
+   $(top_srcdir)/include/gssrpc/xdr.h $(top_srcdir)/include/iprop.h \
+   $(top_srcdir)/include/iprop_hdr.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/kdb.h $(top_srcdir)/include/kdb_log.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 kdb5_util.h tabdump.c \
+-  tdumputil.h
++  $(top_srcdir)/include/k5-hex.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/kdb_log.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 \
++  kdb5_util.h tabdump.c tdumputil.h
+ $(OUTPRE)tdumputil.$(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 \
+diff --git a/src/kadmin/dbutil/tabdump.c b/src/kadmin/dbutil/tabdump.c
+index fb36b060a..2f313dbb0 100644
+--- a/src/kadmin/dbutil/tabdump.c
++++ b/src/kadmin/dbutil/tabdump.c
+@@ -32,6 +32,7 @@
+ 
+ #include <k5-int.h>
+ #include "k5-platform.h"        /* for asprintf */
++#include "k5-hex.h"
+ 
+ #include <limits.h>
+ #include <stdio.h>
+@@ -230,9 +231,7 @@ static int
+ write_data(struct rec_args *args, krb5_data *data)
+ {
+     int ret;
+-    char *p;
+-    size_t i;
+-    struct k5buf buf;
++    char *hex;
+     struct rechandle *h = args->rh;
+     struct tdopts *opts = args->opts;
+ 
+@@ -241,17 +240,15 @@ write_data(struct rec_args *args, krb5_data *data)
+             return -1;
+         return 0;
+     }
+-    k5_buf_init_dynamic(&buf);
+-    p = data->data;
+-    for (i = 0; i < data->length; i++)
+-        k5_buf_add_fmt(&buf, "%02x", (unsigned char)p[i]);
+ 
+-    if (buf.data == NULL) {
+-        errno = ENOMEM;
++    ret = k5_hex_encode(data->data, data->length, FALSE, &hex);
++    if (ret) {
++        errno = ret;
+         return -1;
+     }
+-    ret = writefield(h, "%s", (char *)buf.data);
+-    k5_buf_free(&buf);
++
++    ret = writefield(h, "%s", hex);
++    free(hex);
+     return ret;
+ }
+ 
+diff --git a/src/kadmin/ktutil/deps b/src/kadmin/ktutil/deps
+index 4df399924..5863e63c7 100644
+--- a/src/kadmin/ktutil/deps
++++ b/src/kadmin/ktutil/deps
+@@ -18,9 +18,10 @@ $(OUTPRE)ktutil_funcs.$(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 ktutil.h ktutil_funcs.c
++  $(top_srcdir)/include/k5-hex.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 \
++  ktutil.h ktutil_funcs.c
+diff --git a/src/kadmin/ktutil/ktutil_funcs.c b/src/kadmin/ktutil/ktutil_funcs.c
+index 7a3aa0dca..5843e24b7 100644
+--- a/src/kadmin/ktutil/ktutil_funcs.c
++++ b/src/kadmin/ktutil/ktutil_funcs.c
+@@ -29,6 +29,7 @@
+  */
+ 
+ #include "k5-int.h"
++#include "k5-hex.h"
+ #include "ktutil.h"
+ #include <string.h>
+ #include <ctype.h>
+@@ -106,9 +107,8 @@ krb5_error_code ktutil_add(context, list, princ_str, kvno,
+     krb5_keyblock key;
+     char buf[BUFSIZ];
+     char promptstr[1024];
+-
+-    char *cp;
+-    int i, tmp;
++    uint8_t *keybytes;
++    size_t keylen;
+     unsigned int pwsize = BUFSIZ;
+ 
+     retval = krb5_parse_name(context, princ_str, &princ);
+@@ -199,24 +199,18 @@ krb5_error_code ktutil_add(context, list, princ_str, kvno,
+             goto cleanup;
+         }
+ 
+-        lp->entry->key.enctype = enctype;
+-        lp->entry->key.contents = (krb5_octet *) malloc((strlen(buf) + 1) / 2);
+-        if (!lp->entry->key.contents) {
+-            retval = ENOMEM;
++        retval = k5_hex_decode(buf, &keybytes, &keylen);
++        if (retval) {
++            if (retval == EINVAL) {
++                fprintf(stderr, _("addent: Illegal character in key.\n"));
++                retval = 0;
++            }
+             goto cleanup;
+         }
+ 
+-        i = 0;
+-        for (cp = buf; *cp; cp += 2) {
+-            if (!isxdigit((int) cp[0]) || !isxdigit((int) cp[1])) {
+-                fprintf(stderr, _("addent: Illegal character in key.\n"));
+-                retval = 0;
+-                goto cleanup;
+-            }
+-            sscanf(cp, "%02x", &tmp);
+-            lp->entry->key.contents[i++] = (krb5_octet) tmp;
+-        }
+-        lp->entry->key.length = i;
++        lp->entry->key.enctype = enctype;
++        lp->entry->key.contents = keybytes;
++        lp->entry->key.length = keylen;
+     }
+     lp->entry->principal = princ;
+     lp->entry->vno = kvno;
+diff --git a/src/lib/crypto/crypto_tests/deps b/src/lib/crypto/crypto_tests/deps
+index bc5422a06..5d94a593d 100644
+--- a/src/lib/crypto/crypto_tests/deps
++++ b/src/lib/crypto/crypto_tests/deps
+@@ -73,12 +73,13 @@ $(OUTPRE)t_hmac.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \
+   $(srcdir)/../builtin/crypto_mod.h $(srcdir)/../builtin/sha2/sha2.h \
+   $(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 t_hmac.c
++  $(top_srcdir)/include/k5-hex.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 \
++  t_hmac.c
+ $(OUTPRE)t_pkcs5.$(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 \
+@@ -143,12 +144,13 @@ $(OUTPRE)t_cksum.$(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 t_cksum.c
++  $(top_srcdir)/include/k5-hex.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 \
++  t_cksum.c
+ $(OUTPRE)t_cksums.$(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 \
+@@ -165,12 +167,13 @@ $(OUTPRE)t_crc.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \
+   $(srcdir)/../builtin/crypto_mod.h $(srcdir)/../builtin/sha2/sha2.h \
+   $(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 t_crc.c
++  $(top_srcdir)/include/k5-hex.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 \
++  t_crc.c
+ $(OUTPRE)t_mddriver.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \
+   $(BUILDTOP)/include/krb5/krb5.h $(BUILDTOP)/include/osconf.h \
+   $(BUILDTOP)/include/profile.h $(COM_ERR_DEPS) $(srcdir)/../builtin/aes/aes.h \
+diff --git a/src/lib/crypto/crypto_tests/t_cksum.c b/src/lib/crypto/crypto_tests/t_cksum.c
+index 2200fe76e..0edaeb850 100644
+--- a/src/lib/crypto/crypto_tests/t_cksum.c
++++ b/src/lib/crypto/crypto_tests/t_cksum.c
+@@ -27,6 +27,7 @@
+ /* Test checksum and checksum compatability for rsa-md[4,5]-des. */
+ 
+ #include "k5-int.h"
++#include "k5-hex.h"
+ 
+ #define MD5_K5BETA_COMPAT
+ #define MD4_K5BETA_COMPAT
+@@ -50,29 +51,6 @@ print_checksum(char *text, int number, char *message, krb5_checksum *checksum)
+     printf("\n");
+ }
+ 
+-static void
+-parse_hexstring(const char *s, krb5_checksum *cksum)
+-{
+-    size_t i, len;
+-    unsigned int byte;
+-    unsigned char *cp;
+-
+-    len = strlen(s);
+-    cp = malloc(len / 2);
+-    cksum->contents = cp;
+-    if (cp == NULL) {
+-        cksum->length = 0;
+-        return;
+-    }
+-    cksum->length = len / 2;
+-    for (i = 0; i + 1 < len; i += 2) {
+-        sscanf(&s[i], "%2x", &byte);
+-        *cp++ = byte;
+-    }
+-    cksum->checksum_type = CKTYPE;
+-    cksum->magic = KV5M_CHECKSUM;
+-}
+-
+ /*
+  * Test the checksum verification of Old Style (tm) and correct RSA-MD[4,5]-DES
+  * checksums.
+@@ -86,6 +64,7 @@ main(argc, argv)
+     char **argv;
+ {
+     int                   msgindex;
++    size_t                len;
+     krb5_boolean          valid;
+     krb5_keyblock         keyblock;
+     krb5_key              key;
+@@ -150,12 +129,14 @@ main(argc, argv)
+         free(checksum.contents);
+ 
+         /* Verify a known-good checksum for this plaintext. */
+-        parse_hexstring(argv[msgindex+1], &knowncksum);
+-        if (knowncksum.contents == NULL) {
+-            printf("parse_hexstring failed\n");
+-            kret = 1;
++        kret = k5_hex_decode(argv[msgindex + 1], &knowncksum.contents, &len);
++        if (kret) {
++            printf("k5_hex_decode failed\n");
+             break;
+         }
++        knowncksum.length = len;
++        knowncksum.checksum_type = CKTYPE;
++        knowncksum.magic = KV5M_CHECKSUM;
+         kret = krb5_k_verify_checksum(NULL, key, 0, &plaintext, &knowncksum,
+                                       &valid);
+         if (kret != 0) {
+diff --git a/src/lib/crypto/crypto_tests/t_crc.c b/src/lib/crypto/crypto_tests/t_crc.c
+index 190773252..1a35cfba5 100644
+--- a/src/lib/crypto/crypto_tests/t_crc.c
++++ b/src/lib/crypto/crypto_tests/t_crc.c
+@@ -32,6 +32,7 @@
+ #include <stdio.h>
+ #include <stdlib.h>
+ #include <string.h>
++#include <k5-hex.h>
+ #include "crypto_int.h"
+ 
+ #define HEX 1
+@@ -139,31 +140,12 @@ timetest(unsigned int nblk, unsigned int blksiz)
+ }
+ #endif
+ 
+-static void gethexstr(char *data, size_t *outlen, unsigned char *outbuf,
+-                      size_t buflen)
+-{
+-    size_t inlen;
+-    char *cp, buf[3];
+-    long n;
+-
+-    inlen = strlen(data);
+-    *outlen = 0;
+-    for (cp = data; (size_t) (cp - data) < inlen; cp += 2) {
+-        strncpy(buf, cp, 2);
+-        buf[2] = '\0';
+-        n = strtol(buf, NULL, 16);
+-        outbuf[(*outlen)++] = n;
+-        if (*outlen > buflen)
+-            break;
+-    }
+-}
+-
+ static void
+ verify(void)
+ {
+     unsigned int i;
+     struct crc_trial trial;
+-    unsigned char buf[4];
++    uint8_t *bytes;
+     size_t len;
+     unsigned long cksum;
+     char *typestr;
+@@ -179,9 +161,11 @@ verify(void)
+             break;
+         case HEX:
+             typestr = "HEX";
+-            gethexstr(trial.data, &len, buf, 4);
++            if (k5_hex_decode(trial.data, &bytes, &len) != 0)
++                abort();
+             cksum = 0;
+-            mit_crc32(buf, len, &cksum);
++            mit_crc32(bytes, len, &cksum);
++            free(bytes);
+             break;
+         default:
+             typestr = "BOGUS";
+diff --git a/src/lib/crypto/crypto_tests/t_hmac.c b/src/lib/crypto/crypto_tests/t_hmac.c
+index 8961380ea..93d54828f 100644
+--- a/src/lib/crypto/crypto_tests/t_hmac.c
++++ b/src/lib/crypto/crypto_tests/t_hmac.c
+@@ -34,6 +34,7 @@
+ #include <string.h>
+ #include <ctype.h>
+ 
++#include <k5-hex.h>
+ #include "crypto_int.h"
+ 
+ #define ASIZE(ARRAY) (sizeof(ARRAY)/sizeof(ARRAY[0]))
+@@ -136,12 +137,10 @@ static void test_hmac()
+ {
+     krb5_keyblock key;
+     krb5_data in, out;
+-    char outbuf[20];
+-    char stroutbuf[80];
++    char outbuf[20], *hexdigest;
+     krb5_error_code err;
+-    unsigned int i, j;
++    unsigned int i;
+     int lose = 0;
+-    struct k5buf buf;
+ 
+     /* RFC 2202 test vector.  */
+     static const struct hmac_test md5tests[] = {
+@@ -151,13 +150,13 @@ static void test_hmac()
+                 0xb, 0xb, 0xb, 0xb, 0xb, 0xb, 0xb, 0xb,
+             },
+             8, "Hi There",
+-            "0x9294727a3638bb1c13f48ef8158bfc9d"
++            "9294727a3638bb1c13f48ef8158bfc9d"
+         },
+ 
+         {
+             4, "Jefe",
+             28, "what do ya want for nothing?",
+-            "0x750c783e6ab0b503eaa86e310a5db738"
++            "750c783e6ab0b503eaa86e310a5db738"
+         },
+ 
+         {
+@@ -172,7 +171,7 @@ static void test_hmac()
+                 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+                 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+             },
+-            "0x56be34521d144c88dbb8c733f0e8b3f6"
++            "56be34521d144c88dbb8c733f0e8b3f6"
+         },
+ 
+         {
+@@ -188,7 +187,7 @@ static void test_hmac()
+                 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
+                 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
+             },
+-            "0x697eaf0aca3a3aea3a75164746ffaa79"
++            "697eaf0aca3a3aea3a75164746ffaa79"
+         },
+ 
+         {
+@@ -197,7 +196,7 @@ static void test_hmac()
+                 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c
+             },
+             20, "Test With Truncation",
+-            "0x56461ef2342edc00f9bab995690efd4c"
++            "56461ef2342edc00f9bab995690efd4c"
+         },
+ 
+         {
+@@ -212,7 +211,7 @@ static void test_hmac()
+                 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+             },
+             54, "Test Using Larger Than Block-Size Key - Hash Key First",
+-            "0x6b1ab7fe4bd7bf8f0b62e6ce61b9d0cd"
++            "6b1ab7fe4bd7bf8f0b62e6ce61b9d0cd"
+         },
+ 
+         {
+@@ -228,7 +227,7 @@ static void test_hmac()
+             },
+             73,
+             "Test Using Larger Than Block-Size Key and Larger Than One Block-Size Data",
+-            "0x6f630fad67cda0ee1fb1f562db3aa53e"
++            "6f630fad67cda0ee1fb1f562db3aa53e"
+         },
+     };
+ 
+@@ -246,19 +245,16 @@ static void test_hmac()
+             exit(1);
+         }
+ 
+-        k5_buf_init_fixed(&buf, stroutbuf, sizeof(stroutbuf));
+-        k5_buf_add(&buf, "0x");
+-        for (j = 0; j < out.length; j++)
+-            k5_buf_add_fmt(&buf, "%02x", 0xff & outbuf[j]);
+-        if (k5_buf_status(&buf) != 0)
++        if (k5_hex_encode(out.data, out.length, FALSE, &hexdigest) != 0)
+             abort();
+-        if (strcmp(stroutbuf, md5tests[i].hexdigest)) {
++        if (strcmp(hexdigest, md5tests[i].hexdigest)) {
+             printf("*** CHECK FAILED!\n"
+-                   "\tReturned: %s.\n"
+-                   "\tExpected: %s.\n", stroutbuf, md5tests[i].hexdigest);
++                   "\tReturned: 0x%s.\n"
++                   "\tExpected: 0x%s.\n", hexdigest, md5tests[i].hexdigest);
+             lose++;
+         } else
+             printf("Matches expected result.\n");
++        free(hexdigest);
+     }
+ 
+     /* Do again with SHA-1 tests....  */
+diff --git a/src/plugins/kdb/ldap/ldap_util/deps b/src/plugins/kdb/ldap/ldap_util/deps
+index 75d4dd0cf..be0194c00 100644
+--- a/src/plugins/kdb/ldap/ldap_util/deps
++++ b/src/plugins/kdb/ldap/ldap_util/deps
+@@ -89,15 +89,15 @@ $(OUTPRE)kdb5_ldap_services.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \
+   $(srcdir)/../libkdb_ldap/ldap_krbcontainer.h $(srcdir)/../libkdb_ldap/ldap_misc.h \
+   $(srcdir)/../libkdb_ldap/ldap_realm.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/kdb.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 \
+-  $(top_srcdir)/lib/kdb/kdb5.h kdb5_ldap_list.h kdb5_ldap_policy.h \
+-  kdb5_ldap_realm.h kdb5_ldap_services.c kdb5_ldap_services.h \
+-  kdb5_ldap_util.h
++  $(top_srcdir)/include/k5-hex.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/plugin.h $(top_srcdir)/include/port-sockets.h \
++  $(top_srcdir)/include/socket-utils.h $(top_srcdir)/lib/kdb/kdb5.h \
++  kdb5_ldap_list.h kdb5_ldap_policy.h kdb5_ldap_realm.h \
++  kdb5_ldap_services.c kdb5_ldap_services.h kdb5_ldap_util.h
+ $(OUTPRE)getdate.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \
+   $(BUILDTOP)/include/krb5/krb5.h $(COM_ERR_DEPS) $(top_srcdir)/include/krb5.h \
+   getdate.c
+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 3d6994c67..ce038fc3d 100644
+--- a/src/plugins/kdb/ldap/ldap_util/kdb5_ldap_services.c
++++ b/src/plugins/kdb/ldap/ldap_util/kdb5_ldap_services.c
+@@ -37,6 +37,7 @@
+  */
+ 
+ #include <k5-int.h>
++#include <k5-hex.h>
+ #include "kdb5_ldap_util.h"
+ #include "kdb5_ldap_list.h"
+ 
+@@ -96,11 +97,10 @@ kdb5_ldap_stash_service_password(int argc, char **argv)
+     char *service_object = NULL;
+     char *file_name = NULL, *tmp_file = NULL;
+     char passwd[MAX_SERVICE_PASSWD_LEN];
+-    char *str = NULL;
++    char *str = NULL, *hexpasswd = NULL;
+     char line[MAX_LEN];
+     FILE *pfile = NULL;
+     krb5_boolean print_usage = FALSE;
+-    krb5_data hexpasswd = {0, 0, NULL};
+     mode_t old_mode = 0;
+ 
+     /*
+@@ -183,21 +183,12 @@ kdb5_ldap_stash_service_password(int argc, char **argv)
+     }
+ 
+     /* Convert the password to hexadecimal */
+-    {
+-        krb5_data pwd;
+-
+-        pwd.length = passwd_len;
+-        pwd.data = passwd;
+-
+-        ret = tohex(pwd, &hexpasswd);
+-        if (ret != 0) {
+-            com_err(me, ret,
+-                    _("Failed to convert the password to hexadecimal"));
+-            memset(passwd, 0, passwd_len);
+-            goto cleanup;
+-        }
++    ret = k5_hex_encode(passwd, passwd_len, FALSE, &hexpasswd);
++    zap(passwd, passwd_len);
++    if (ret != 0) {
++        com_err(me, ret, _("Failed to convert the password to hexadecimal"));
++        goto cleanup;
+     }
+-    memset(passwd, 0, passwd_len);
+ 
+     /* TODO: file lock for the service password file */
+ 
+@@ -225,7 +216,7 @@ kdb5_ldap_stash_service_password(int argc, char **argv)
+     if (str == NULL) {
+         if (feof(pfile)) {
+             /* If the service object dn is not present in the service password file */
+-            if (fprintf(pfile, "%s#{HEX}%s\n", service_object, hexpasswd.data) < 0) {
++            if (fprintf(pfile, "%s#{HEX}%s\n", service_object, hexpasswd) < 0) {
+                 com_err(me, errno,
+                         _("Failed to write service object password to file"));
+                 fclose(pfile);
+@@ -277,7 +268,7 @@ kdb5_ldap_stash_service_password(int argc, char **argv)
+         while (fgets(line, MAX_LEN, pfile) != NULL) {
+             if (((str = strstr(line, service_object)) != NULL) &&
+                 (line[strlen(service_object)] == '#')) {
+-                if (fprintf(newfile, "%s#{HEX}%s\n", service_object, hexpasswd.data) < 0) {
++                if (fprintf(newfile, "%s#{HEX}%s\n", service_object, hexpasswd) < 0) {
+                     com_err(me, errno, _("Failed to write service object "
+                                          "password to file"));
+                     fclose(newfile);
+@@ -322,10 +313,7 @@ kdb5_ldap_stash_service_password(int argc, char **argv)
+ 
+ cleanup:
+ 
+-    if (hexpasswd.length != 0) {
+-        memset(hexpasswd.data, 0, hexpasswd.length);
+-        free(hexpasswd.data);
+-    }
++    zapfreestr(hexpasswd);
+ 
+     if (service_object)
+         free(service_object);
+diff --git a/src/plugins/kdb/ldap/ldap_util/kdb5_ldap_services.h b/src/plugins/kdb/ldap/ldap_util/kdb5_ldap_services.h
+index cf652c578..08af62e17 100644
+--- a/src/plugins/kdb/ldap/ldap_util/kdb5_ldap_services.h
++++ b/src/plugins/kdb/ldap/ldap_util/kdb5_ldap_services.h
+@@ -32,6 +32,4 @@
+ #define MAX_LEN                 1024
+ #define MAX_SERVICE_PASSWD_LEN  256
+ 
+-extern int tohex(krb5_data, krb5_data *);
+-
+ extern void kdb5_ldap_stash_service_password(int argc, char **argv);
+diff --git a/src/plugins/kdb/ldap/libkdb_ldap/deps b/src/plugins/kdb/ldap/libkdb_ldap/deps
+index 1ff28553f..afca604dc 100644
+--- a/src/plugins/kdb/ldap/libkdb_ldap/deps
++++ b/src/plugins/kdb/ldap/libkdb_ldap/deps
+@@ -220,15 +220,16 @@ ldap_service_stash.so ldap_service_stash.po $(OUTPRE)ldap_service_stash.$(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/plugin.h $(top_srcdir)/include/port-sockets.h \
+-  $(top_srcdir)/include/socket-utils.h $(top_srcdir)/lib/kdb/kdb5.h \
+-  kdb_ldap.h ldap_handle.h ldap_krbcontainer.h ldap_main.h \
+-  ldap_misc.h ldap_realm.h ldap_service_stash.c ldap_service_stash.h
++  $(top_srcdir)/include/k5-gmt_mktime.h $(top_srcdir)/include/k5-hex.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/plugin.h \
++  $(top_srcdir)/include/port-sockets.h $(top_srcdir)/include/socket-utils.h \
++  $(top_srcdir)/lib/kdb/kdb5.h kdb_ldap.h ldap_handle.h \
++  ldap_krbcontainer.h ldap_main.h ldap_misc.h ldap_realm.h \
++  ldap_service_stash.c ldap_service_stash.h
+ kdb_xdr.so kdb_xdr.po $(OUTPRE)kdb_xdr.$(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 \
+diff --git a/src/plugins/kdb/ldap/libkdb_ldap/ldap_service_stash.c b/src/plugins/kdb/ldap/libkdb_ldap/ldap_service_stash.c
+index 87a2118ff..cb30f4a7f 100644
+--- a/src/plugins/kdb/ldap/libkdb_ldap/ldap_service_stash.c
++++ b/src/plugins/kdb/ldap/libkdb_ldap/ldap_service_stash.c
+@@ -31,16 +31,16 @@
+ #include "ldap_main.h"
+ #include "kdb_ldap.h"
+ #include "ldap_service_stash.h"
++#include <k5-hex.h>
+ #include <ctype.h>
+ 
+ /* Decode a password of the form {HEX}<hexstring>. */
+ static krb5_error_code
+ dec_password(krb5_context context, const char *str, char **password_out)
+ {
++    krb5_error_code ret;
++    uint8_t *bytes;
+     size_t len;
+-    const unsigned char *p;
+-    unsigned char *password, *q;
+-    unsigned int k;
+ 
+     *password_out = NULL;
+ 
+@@ -48,30 +48,15 @@ dec_password(krb5_context context, const char *str, char **password_out)
+         k5_setmsg(context, EINVAL, _("Not a hexadecimal password"));
+         return EINVAL;
+     }
+-    str += 5;
+ 
+-    len = strlen(str);
+-    if (len % 2 != 0) {
+-        k5_setmsg(context, EINVAL, _("Password corrupt"));
+-        return EINVAL;
++    ret = k5_hex_decode(str + 5, &bytes, &len);
++    if (ret) {
++        if (ret == EINVAL)
++            k5_setmsg(context, ret, _("Password corrupt"));
++        return ret;
+     }
+ 
+-    q = password = malloc(len / 2 + 1);
+-    if (password == NULL)
+-        return ENOMEM;
+-
+-    for (p = (unsigned char *)str; *p != '\0'; p += 2) {
+-        if (!isxdigit(*p) || !isxdigit(p[1])) {
+-            free(password);
+-            k5_setmsg(context, EINVAL, _("Password corrupt"));
+-            return EINVAL;
+-        }
+-        sscanf((char *)p, "%2x", &k);
+-        *q++ = k;
+-    }
+-    *q = '\0';
+-
+-    *password_out = (char *)password;
++    *password_out = (char *)bytes;
+     return 0;
+ }
+ 
+@@ -128,35 +113,3 @@ krb5_ldap_readpassword(krb5_context context, const char *filename,
+     /* Extract the plain password information. */
+     return dec_password(context, val, password_out);
+ }
+-
+-/* Encodes a sequence of bytes in hexadecimal */
+-
+-int
+-tohex(krb5_data in, krb5_data *ret)
+-{
+-    unsigned int       i=0;
+-    int                err = 0;
+-
+-    ret->length = 0;
+-    ret->data = NULL;
+-
+-    ret->data = malloc((unsigned int)in.length * 2 + 1 /*Null termination */);
+-    if (ret->data == NULL) {
+-        err = ENOMEM;
+-        goto cleanup;
+-    }
+-    ret->length = in.length * 2;
+-    ret->data[ret->length] = 0;
+-
+-    for (i = 0; i < in.length; i++)
+-        snprintf(ret->data + 2 * i, 3, "%02x", in.data[i] & 0xff);
+-
+-cleanup:
+-
+-    if (ret->length == 0) {
+-        free(ret->data);
+-        ret->data = NULL;
+-    }
+-
+-    return err;
+-}
+diff --git a/src/plugins/kdb/ldap/libkdb_ldap/ldap_service_stash.h b/src/plugins/kdb/ldap/libkdb_ldap/ldap_service_stash.h
+index dbf62443a..03cf9a1f7 100644
+--- a/src/plugins/kdb/ldap/libkdb_ldap/ldap_service_stash.h
++++ b/src/plugins/kdb/ldap/libkdb_ldap/ldap_service_stash.h
+@@ -37,7 +37,4 @@ krb5_error_code
+ krb5_ldap_readpassword(krb5_context context, const char *filename,
+                        const char *name, char **password_out);
+ 
+-int
+-tohex(krb5_data, krb5_data *);
+-
+ #endif
+diff --git a/src/plugins/kdb/ldap/libkdb_ldap/libkdb_ldap.exports b/src/plugins/kdb/ldap/libkdb_ldap/libkdb_ldap.exports
+index 2342f1db8..5376d3453 100644
+--- a/src/plugins/kdb/ldap/libkdb_ldap/libkdb_ldap.exports
++++ b/src/plugins/kdb/ldap/libkdb_ldap/libkdb_ldap.exports
+@@ -1,4 +1,3 @@
+-tohex
+ krb5_ldap_open
+ krb5_ldap_close
+ krb5_ldap_db_init
+diff --git a/src/slave/deps b/src/slave/deps
+index c3677a5e1..c0f558ecd 100644
+--- a/src/slave/deps
++++ b/src/slave/deps
+@@ -64,10 +64,11 @@ $(OUTPRE)kproplog.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \
+   $(top_srcdir)/include/gssrpc/xdr.h $(top_srcdir)/include/iprop.h \
+   $(top_srcdir)/include/iprop_hdr.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/kdb.h $(top_srcdir)/include/kdb_log.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 kproplog.c
++  $(top_srcdir)/include/k5-hex.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/kdb_log.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 \
++  kproplog.c
+diff --git a/src/slave/kproplog.c b/src/slave/kproplog.c
+index 4f19eeb8c..d4aed7ba6 100644
+--- a/src/slave/kproplog.c
++++ b/src/slave/kproplog.c
+@@ -9,6 +9,7 @@
+  */
+ 
+ #include "k5-int.h"
++#include "k5-hex.h"
+ #include <locale.h>
+ #include <sys/types.h>
+ #include <sys/mman.h>
+@@ -106,15 +107,15 @@ print_deltat(uint32_t *deltat)
+ static void
+ print_hex(const char *tag, utf8str_t *str)
+ {
+-    unsigned int i;
+     unsigned int len;
++    char *hex;
+ 
+     len = str->utf8str_t_len;
+ 
+-    printf("\t\t\t%s(%d): 0x", tag, len);
+-    for (i = 0; i < len; i++)
+-        printf("%02x", (krb5_octet)str->utf8str_t_val[i]);
+-    printf("\n");
++    if (k5_hex_encode(str->utf8str_t_val, len, FALSE, &hex) != 0)
++        abort();
++    printf("\t\t\t%s(%d): 0x%s\n", tag, len, hex);
++    free(hex);
+ }
+ 
+ /* Display string primitive. */
+diff --git a/src/tests/gssapi/deps b/src/tests/gssapi/deps
+index b784deb63..0b50d9ed3 100644
+--- a/src/tests/gssapi/deps
++++ b/src/tests/gssapi/deps
+@@ -149,13 +149,13 @@ $(OUTPRE)t_prf.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \
+   $(srcdir)/../../lib/gssapi/krb5/gssapiP_krb5.h $(srcdir)/../../lib/gssapi/krb5/gssapi_krb5.h \
+   $(srcdir)/../../lib/gssapi/mechglue/mechglue.h $(srcdir)/../../lib/gssapi/mechglue/mglueP.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 \
+-  common.h t_prf.c
++  $(top_srcdir)/include/k5-gmt_mktime.h $(top_srcdir)/include/k5-hex.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 common.h t_prf.c
+ $(OUTPRE)t_s4u.$(OBJEXT): $(BUILDTOP)/include/gssapi/gssapi.h \
+   $(BUILDTOP)/include/gssapi/gssapi_ext.h $(BUILDTOP)/include/gssapi/gssapi_krb5.h \
+   $(BUILDTOP)/include/krb5/krb5.h $(COM_ERR_DEPS) $(top_srcdir)/include/krb5.h \
+diff --git a/src/tests/gssapi/t_prf.c b/src/tests/gssapi/t_prf.c
+index 2c8c85188..6a698ce0f 100644
+--- a/src/tests/gssapi/t_prf.c
++++ b/src/tests/gssapi/t_prf.c
+@@ -24,6 +24,7 @@
+  */
+ 
+ #include "k5-int.h"
++#include "k5-hex.h"
+ #include "common.h"
+ #include "mglueP.h"
+ #include "gssapiP_krb5.h"
+@@ -109,12 +110,14 @@ static struct {
+ static size_t
+ fromhex(const char *hexstr, unsigned char *out)
+ {
+-    const char *p;
+-    size_t count;
++    uint8_t *bytes;
++    size_t len;
+ 
+-    for (p = hexstr, count = 0; *p != '\0'; p += 2, count++)
+-        sscanf(p, "%2hhx", &out[count]);
+-    return count;
++    if (k5_hex_decode(hexstr, &bytes, &len) != 0)
++        abort();
++    memcpy(out, bytes, len);
++    free(bytes);
++    return len;
+ }
+ 
+ int
diff --git a/SOURCES/Zap-copy-of-secret-in-RC4-string-to-key.patch b/SOURCES/Zap-copy-of-secret-in-RC4-string-to-key.patch
new file mode 100644
index 0000000..7502c25
--- /dev/null
+++ b/SOURCES/Zap-copy-of-secret-in-RC4-string-to-key.patch
@@ -0,0 +1,30 @@
+From 55a8161c3f5238df522447499a38bf2e9497b074 Mon Sep 17 00:00:00 2001
+From: Dylan Gray <35609490+Dylan-MSFT@users.noreply.github.com>
+Date: Fri, 13 Jul 2018 15:09:01 -0700
+Subject: [PATCH] Zap copy of secret in RC4 string-to-key
+
+Commit b8814745049b5f401e3ae39a81dc1e14598ae48c (ticket 8576) added a
+zero-terminated copy of the input string in
+krb5int_arcfour_string_to_key().  This copy should be zeroed when
+freed as the input string typically contains a password.
+
+[ghudson@mit.edu: rewrote commit message]
+
+ticket: 8713 (new)
+---
+ src/lib/crypto/krb/s2k_rc4.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/src/lib/crypto/krb/s2k_rc4.c b/src/lib/crypto/krb/s2k_rc4.c
+index 081a91217..f7e699d60 100644
+--- a/src/lib/crypto/krb/s2k_rc4.c
++++ b/src/lib/crypto/krb/s2k_rc4.c
+@@ -25,7 +25,7 @@ krb5int_arcfour_string_to_key(const struct krb5_keytypes *ktp,
+     if (utf8 == NULL)
+         return err;
+     err = k5_utf8_to_utf16le(utf8, &copystr, &copystrlen);
+-    free(utf8);
++    zapfree(utf8, string->length);
+     if (err)
+         return err;
+ 
diff --git a/SOURCES/Zap-data-when-freeing-krb5_spake_factor.patch b/SOURCES/Zap-data-when-freeing-krb5_spake_factor.patch
new file mode 100644
index 0000000..9ce2462
--- /dev/null
+++ b/SOURCES/Zap-data-when-freeing-krb5_spake_factor.patch
@@ -0,0 +1,29 @@
+From 5d970e16e768a134e65ee7cf367b8f34a80e0980 Mon Sep 17 00:00:00 2001
+From: Greg Hudson <ghudson@mit.edu>
+Date: Tue, 27 Mar 2018 15:42:28 -0400
+Subject: [PATCH] Zap data when freeing krb5_spake_factor
+
+krb5_spake_factor structures will sometimes hold sensitive data when
+second-factor SPAKE is implemented, so should be zapped when freed.
+
+ticket: 8647
+(cherry picked from commit 9cc94a3f1ce06a4430f684300a747ec079102403)
+---
+ src/lib/krb5/krb/kfree.c | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+diff --git a/src/lib/krb5/krb/kfree.c b/src/lib/krb5/krb/kfree.c
+index e1ea1494a..71e7fcad0 100644
+--- a/src/lib/krb5/krb/kfree.c
++++ b/src/lib/krb5/krb/kfree.c
+@@ -897,7 +897,9 @@ k5_free_spake_factor(krb5_context context, krb5_spake_factor *val)
+ {
+     if (val == NULL)
+         return;
+-    krb5_free_data(context, val->data);
++    if (val->data != NULL)
++        zapfree(val->data->data, val->data->length);
++    free(val->data);
+     free(val);
+ }
+ 
diff --git a/SOURCES/kadm5.acl b/SOURCES/kadm5.acl
new file mode 100644
index 0000000..dc93eb0
--- /dev/null
+++ b/SOURCES/kadm5.acl
@@ -0,0 +1 @@
+*/admin@EXAMPLE.COM	*
diff --git a/SOURCES/kadmin.service b/SOURCES/kadmin.service
new file mode 100644
index 0000000..f1677c6
--- /dev/null
+++ b/SOURCES/kadmin.service
@@ -0,0 +1,15 @@
+[Unit]
+Description=Kerberos 5 Password-changing and Administration
+Wants=network-online.target
+After=syslog.target network.target network-online.target
+AssertPathExists=!/var/kerberos/krb5kdc/kpropd.acl
+
+[Service]
+Type=forking
+PIDFile=/var/run/kadmind.pid
+EnvironmentFile=-/etc/sysconfig/kadmin
+ExecStart=/usr/sbin/kadmind -P /var/run/kadmind.pid $KADMIND_ARGS
+ExecReload=/bin/kill -HUP $MAINPID
+
+[Install]
+WantedBy=multi-user.target
diff --git a/SOURCES/kadmin.sysconfig b/SOURCES/kadmin.sysconfig
new file mode 100644
index 0000000..fa72039
--- /dev/null
+++ b/SOURCES/kadmin.sysconfig
@@ -0,0 +1 @@
+KADMIND_ARGS=
diff --git a/SOURCES/kadmind.logrotate b/SOURCES/kadmind.logrotate
new file mode 100644
index 0000000..52a66c4
--- /dev/null
+++ b/SOURCES/kadmind.logrotate
@@ -0,0 +1,9 @@
+/var/log/kadmind.log {
+    missingok
+    notifempty
+    monthly
+    rotate 12
+    postrotate
+	/bin/kill -HUP `cat /var/run/kadmind.pid 2>/dev/null` 2> /dev/null || true
+    endscript
+}
diff --git a/SOURCES/kdc.conf b/SOURCES/kdc.conf
new file mode 100644
index 0000000..b2e5e9b
--- /dev/null
+++ b/SOURCES/kdc.conf
@@ -0,0 +1,13 @@
+[kdcdefaults]
+    kdc_ports = 88
+    kdc_tcp_ports = 88
+    spake_preauth_kdc_challenge = edwards25519
+
+[realms]
+EXAMPLE.COM = {
+     #master_key_type = aes256-cts
+     acl_file = /var/kerberos/krb5kdc/kadm5.acl
+     dict_file = /usr/share/dict/words
+     admin_keytab = /var/kerberos/krb5kdc/kadm5.keytab
+     supported_enctypes = aes256-cts:normal aes128-cts:normal des3-hmac-sha1:normal arcfour-hmac:normal camellia256-cts:normal camellia128-cts:normal
+}
diff --git a/SOURCES/kprop.service b/SOURCES/kprop.service
new file mode 100644
index 0000000..7b5d4b9
--- /dev/null
+++ b/SOURCES/kprop.service
@@ -0,0 +1,13 @@
+[Unit]
+Description=Kerberos 5 Propagation
+Wants=network-online.target
+After=syslog.target network.target network-online.target
+AssertPathExists=/var/kerberos/krb5kdc/kpropd.acl
+
+[Service]
+Type=forking
+EnvironmentFile=-/etc/sysconfig/kprop
+ExecStart=/usr/sbin/kpropd $KPROPD_ARGS
+
+[Install]
+WantedBy=multi-user.target
diff --git a/SOURCES/kprop.sysconfig b/SOURCES/kprop.sysconfig
new file mode 100644
index 0000000..f43e8bb
--- /dev/null
+++ b/SOURCES/kprop.sysconfig
@@ -0,0 +1 @@
+KPROPD_ARGS=
diff --git a/SOURCES/krb5-1.11-kpasswdtest.patch b/SOURCES/krb5-1.11-kpasswdtest.patch
new file mode 100644
index 0000000..ddd3ec2
--- /dev/null
+++ b/SOURCES/krb5-1.11-kpasswdtest.patch
@@ -0,0 +1,21 @@
+From fc2953ce9ce06ff896b1687e1c0cc9b8a4357d09 Mon Sep 17 00:00:00 2001
+From: Robbie Harwood <rharwood@redhat.com>
+Date: Tue, 23 Aug 2016 16:52:01 -0400
+Subject: [PATCH] krb5-1.11-kpasswdtest.patch
+
+---
+ src/kadmin/testing/proto/krb5.conf.proto | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/src/kadmin/testing/proto/krb5.conf.proto b/src/kadmin/testing/proto/krb5.conf.proto
+index 00c442978..9c4bc1de7 100644
+--- a/src/kadmin/testing/proto/krb5.conf.proto
++++ b/src/kadmin/testing/proto/krb5.conf.proto
+@@ -9,6 +9,7 @@
+ 	__REALM__ = {
+ 		kdc = __KDCHOST__:1750
+ 		admin_server = __KDCHOST__:1751
++		kpasswd_server = __KDCHOST__:1752
+ 		database_module = foobar_db2_module_blah
+ 	}
+ 
diff --git a/SOURCES/krb5-1.11-run_user_0.patch b/SOURCES/krb5-1.11-run_user_0.patch
new file mode 100644
index 0000000..febb3b3
--- /dev/null
+++ b/SOURCES/krb5-1.11-run_user_0.patch
@@ -0,0 +1,44 @@
+From b0adf9a65d5c22a77cf957ceb1c298baff01555d Mon Sep 17 00:00:00 2001
+From: Robbie Harwood <rharwood@redhat.com>
+Date: Tue, 23 Aug 2016 16:49:57 -0400
+Subject: [PATCH] krb5-1.11-run_user_0.patch
+
+A hack: if we're looking at creating a ccache directory directly below
+the /run/user/0 directory, and /run/user/0 doesn't exist, try to create
+it, too.
+---
+ src/lib/krb5/ccache/cc_dir.c | 14 ++++++++++++++
+ 1 file changed, 14 insertions(+)
+
+diff --git a/src/lib/krb5/ccache/cc_dir.c b/src/lib/krb5/ccache/cc_dir.c
+index 73f0fe62d..4850c0d07 100644
+--- a/src/lib/krb5/ccache/cc_dir.c
++++ b/src/lib/krb5/ccache/cc_dir.c
+@@ -61,6 +61,8 @@
+ 
+ #include <dirent.h>
+ 
++#define ROOT_SPECIAL_DCC_PARENT "/run/user/0"
++
+ extern const krb5_cc_ops krb5_dcc_ops;
+ extern const krb5_cc_ops krb5_fcc_ops;
+ 
+@@ -237,6 +239,18 @@ verify_dir(krb5_context context, const char *dirname)
+ 
+     if (stat(dirname, &st) < 0) {
+         if (errno == ENOENT) {
++            if (strncmp(dirname, ROOT_SPECIAL_DCC_PARENT "/",
++                        sizeof(ROOT_SPECIAL_DCC_PARENT)) == 0 &&
++                stat(ROOT_SPECIAL_DCC_PARENT, &st) < 0 &&
++                errno == ENOENT) {
++#ifdef USE_SELINUX
++                selabel = krb5int_push_fscreatecon_for(ROOT_SPECIAL_DCC_PARENT);
++#endif
++                status = mkdir(ROOT_SPECIAL_DCC_PARENT, S_IRWXU);
++#ifdef USE_SELINUX
++                krb5int_pop_fscreatecon(selabel);
++#endif
++            }
+ #ifdef USE_SELINUX
+             selabel = krb5int_push_fscreatecon_for(dirname);
+ #endif
diff --git a/SOURCES/krb5-1.12-api.patch b/SOURCES/krb5-1.12-api.patch
new file mode 100644
index 0000000..9eba2ff
--- /dev/null
+++ b/SOURCES/krb5-1.12-api.patch
@@ -0,0 +1,37 @@
+From abb19d2d2eac5f9f6e4a1bf26f59f3a62143dab9 Mon Sep 17 00:00:00 2001
+From: Robbie Harwood <rharwood@redhat.com>
+Date: Tue, 23 Aug 2016 16:47:00 -0400
+Subject: [PATCH] krb5-1.12-api.patch
+
+Reference docs don't define what happens if you call krb5_realm_compare() with
+malformed krb5_principal structures.  Define a behavior which keeps it from
+crashing if applications don't check ahead of time.
+---
+ src/lib/krb5/krb/princ_comp.c | 7 +++++++
+ 1 file changed, 7 insertions(+)
+
+diff --git a/src/lib/krb5/krb/princ_comp.c b/src/lib/krb5/krb/princ_comp.c
+index a6936107d..0ed78833b 100644
+--- a/src/lib/krb5/krb/princ_comp.c
++++ b/src/lib/krb5/krb/princ_comp.c
+@@ -36,6 +36,10 @@ realm_compare_flags(krb5_context context,
+     const krb5_data *realm1 = &princ1->realm;
+     const krb5_data *realm2 = &princ2->realm;
+ 
++    if (princ1 == NULL || princ2 == NULL)
++        return FALSE;
++    if (realm1 == NULL || realm2 == NULL)
++        return FALSE;
+     if (realm1->length != realm2->length)
+         return FALSE;
+     if (realm1->length == 0)
+@@ -88,6 +92,9 @@ krb5_principal_compare_flags(krb5_context context,
+     krb5_principal upn2 = NULL;
+     krb5_boolean ret = FALSE;
+ 
++    if (princ1 == NULL || princ2 == NULL)
++        return FALSE;
++
+     if (flags & KRB5_PRINCIPAL_COMPARE_ENTERPRISE) {
+         /* Treat UPNs as if they were real principals */
+         if (princ1->type == KRB5_NT_ENTERPRISE_PRINCIPAL) {
diff --git a/SOURCES/krb5-1.12-ksu-path.patch b/SOURCES/krb5-1.12-ksu-path.patch
new file mode 100644
index 0000000..19b9e73
--- /dev/null
+++ b/SOURCES/krb5-1.12-ksu-path.patch
@@ -0,0 +1,22 @@
+From 7f076496c7441cd108929aa05dbe009f34054bf5 Mon Sep 17 00:00:00 2001
+From: Robbie Harwood <rharwood@redhat.com>
+Date: Tue, 23 Aug 2016 16:32:09 -0400
+Subject: [PATCH] krb5-1.12-ksu-path.patch
+
+Set the default PATH to the one set by login.
+---
+ src/clients/ksu/Makefile.in | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/src/clients/ksu/Makefile.in b/src/clients/ksu/Makefile.in
+index 5755bb58a..9d58f29b5 100644
+--- a/src/clients/ksu/Makefile.in
++++ b/src/clients/ksu/Makefile.in
+@@ -1,6 +1,6 @@
+ mydir=clients$(S)ksu
+ BUILDTOP=$(REL)..$(S)..
+-DEFINES = -DGET_TGT_VIA_PASSWD -DPRINC_LOOK_AHEAD -DCMD_PATH='"/bin /local/bin"'
++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@
diff --git a/SOURCES/krb5-1.12-ktany.patch b/SOURCES/krb5-1.12-ktany.patch
new file mode 100644
index 0000000..de59827
--- /dev/null
+++ b/SOURCES/krb5-1.12-ktany.patch
@@ -0,0 +1,366 @@
+From 01acbf3cbd60bd460e6ec6702589451d19c89933 Mon Sep 17 00:00:00 2001
+From: Robbie Harwood <rharwood@redhat.com>
+Date: Tue, 23 Aug 2016 16:33:53 -0400
+Subject: [PATCH] krb5-1.12-ktany.patch
+
+Adds an "ANY" keytab type which is a list of other keytab locations to search
+when searching for a specific entry.  When iterated through, it only presents
+the contents of the first keytab.
+---
+ src/lib/krb5/keytab/Makefile.in |   3 +
+ src/lib/krb5/keytab/kt_any.c    | 292 ++++++++++++++++++++++++++++++++
+ src/lib/krb5/keytab/ktbase.c    |   7 +-
+ 3 files changed, 301 insertions(+), 1 deletion(-)
+ create mode 100644 src/lib/krb5/keytab/kt_any.c
+
+diff --git a/src/lib/krb5/keytab/Makefile.in b/src/lib/krb5/keytab/Makefile.in
+index 2a8fceb00..ffd179fb2 100644
+--- a/src/lib/krb5/keytab/Makefile.in
++++ b/src/lib/krb5/keytab/Makefile.in
+@@ -12,6 +12,7 @@ STLIBOBJS= \
+ 	ktfr_entry.o	\
+ 	ktremove.o	\
+ 	ktfns.o		\
++	kt_any.o	\
+ 	kt_file.o	\
+ 	kt_memory.o	\
+ 	kt_srvtab.o	\
+@@ -24,6 +25,7 @@ OBJS=	\
+ 	$(OUTPRE)ktfr_entry.$(OBJEXT)	\
+ 	$(OUTPRE)ktremove.$(OBJEXT)	\
+ 	$(OUTPRE)ktfns.$(OBJEXT)	\
++	$(OUTPRE)kt_any.$(OBJEXT)	\
+ 	$(OUTPRE)kt_file.$(OBJEXT)	\
+ 	$(OUTPRE)kt_memory.$(OBJEXT)	\
+ 	$(OUTPRE)kt_srvtab.$(OBJEXT)	\
+@@ -36,6 +38,7 @@ SRCS=	\
+ 	$(srcdir)/ktfr_entry.c	\
+ 	$(srcdir)/ktremove.c	\
+ 	$(srcdir)/ktfns.c	\
++	$(srcdir)/kt_any.c	\
+ 	$(srcdir)/kt_file.c	\
+ 	$(srcdir)/kt_memory.c	\
+ 	$(srcdir)/kt_srvtab.c	\
+diff --git a/src/lib/krb5/keytab/kt_any.c b/src/lib/krb5/keytab/kt_any.c
+new file mode 100644
+index 000000000..1b9b7765b
+--- /dev/null
++++ b/src/lib/krb5/keytab/kt_any.c
+@@ -0,0 +1,292 @@
++/*
++ * lib/krb5/keytab/kt_any.c
++ *
++ * Copyright 1998, 1999 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.  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.
++ * 
++ *
++ * krb5_kta_ops
++ */
++
++#include "k5-int.h"
++
++typedef struct _krb5_ktany_data {
++    char *name;
++    krb5_keytab *choices;
++    int nchoices;
++} krb5_ktany_data;
++
++typedef struct _krb5_ktany_cursor_data {
++    int which;
++    krb5_kt_cursor cursor;
++} krb5_ktany_cursor_data;
++
++static krb5_error_code krb5_ktany_resolve
++	          (krb5_context,
++		   const char *,
++		   krb5_keytab *);
++static krb5_error_code krb5_ktany_get_name
++	          (krb5_context context,
++		   krb5_keytab id,
++		   char *name,
++		   unsigned int len);
++static krb5_error_code krb5_ktany_close
++	          (krb5_context context,
++		   krb5_keytab id);
++static krb5_error_code krb5_ktany_get_entry
++	          (krb5_context context,
++		   krb5_keytab id,
++		   krb5_const_principal principal,
++		   krb5_kvno kvno,
++		   krb5_enctype enctype,
++		   krb5_keytab_entry *entry);
++static krb5_error_code krb5_ktany_start_seq_get
++	          (krb5_context context,
++		   krb5_keytab id,
++		   krb5_kt_cursor *cursorp);
++static krb5_error_code krb5_ktany_next_entry
++	          (krb5_context context,
++		   krb5_keytab id,
++		   krb5_keytab_entry *entry,
++		   krb5_kt_cursor *cursor);
++static krb5_error_code krb5_ktany_end_seq_get
++	          (krb5_context context,
++		   krb5_keytab id,
++		   krb5_kt_cursor *cursor);
++static void cleanup
++	          (krb5_context context,
++		   krb5_ktany_data *data,
++		   int nchoices);
++
++struct _krb5_kt_ops krb5_kta_ops = {
++    0,
++    "ANY", 	/* Prefix -- this string should not appear anywhere else! */
++    krb5_ktany_resolve,
++    krb5_ktany_get_name,
++    krb5_ktany_close,
++    krb5_ktany_get_entry,
++    krb5_ktany_start_seq_get,
++    krb5_ktany_next_entry,
++    krb5_ktany_end_seq_get,
++    NULL,
++    NULL,
++    NULL,
++};
++
++static krb5_error_code
++krb5_ktany_resolve(context, name, id)
++    krb5_context context;
++    const char *name;
++    krb5_keytab *id;
++{
++    const char *p, *q;
++    char *copy;
++    krb5_error_code kerror;
++    krb5_ktany_data *data;
++    int i;
++
++    /* Allocate space for our data and remember a copy of the name. */
++    if ((data = (krb5_ktany_data *)malloc(sizeof(krb5_ktany_data))) == NULL)
++	return(ENOMEM);
++    if ((data->name = (char *)malloc(strlen(name) + 1)) == NULL) {
++	free(data);
++	return(ENOMEM);
++    }
++    strcpy(data->name, name);
++
++    /* Count the number of choices and allocate memory for them. */
++    data->nchoices = 1;
++    for (p = name; (q = strchr(p, ',')) != NULL; p = q + 1)
++	data->nchoices++;
++    if ((data->choices = (krb5_keytab *)
++	 malloc(data->nchoices * sizeof(krb5_keytab))) == NULL) {
++	free(data->name);
++	free(data);
++	return(ENOMEM);
++    }
++
++    /* Resolve each of the choices. */
++    i = 0;
++    for (p = name; (q = strchr(p, ',')) != NULL; p = q + 1) {
++	/* Make a copy of the choice name so we can terminate it. */
++	if ((copy = (char *)malloc(q - p + 1)) == NULL) {
++	    cleanup(context, data, i);
++	    return(ENOMEM);
++	}
++	memcpy(copy, p, q - p);
++	copy[q - p] = 0;
++
++	/* Try resolving the choice name. */
++	kerror = krb5_kt_resolve(context, copy, &data->choices[i]);
++	free(copy);
++	if (kerror) {
++	    cleanup(context, data, i);
++	    return(kerror);
++	}
++	i++;
++    }
++    if ((kerror = krb5_kt_resolve(context, p, &data->choices[i]))) {
++	cleanup(context, data, i);
++	return(kerror);
++    }
++
++    /* Allocate and fill in an ID for the caller. */
++    if ((*id = (krb5_keytab)malloc(sizeof(**id))) == NULL) {
++	cleanup(context, data, i);
++	return(ENOMEM);
++    }
++    (*id)->ops = &krb5_kta_ops;
++    (*id)->data = (krb5_pointer)data;
++    (*id)->magic = KV5M_KEYTAB;
++
++    return(0);
++}
++
++static krb5_error_code
++krb5_ktany_get_name(context, id, name, len)
++    krb5_context context;
++    krb5_keytab id;
++    char *name;
++    unsigned int len;
++{
++    krb5_ktany_data *data = (krb5_ktany_data *)id->data;
++
++    if (len < strlen(data->name) + 1)
++	return(KRB5_KT_NAME_TOOLONG);
++    strcpy(name, data->name);
++    return(0);
++}
++
++static krb5_error_code
++krb5_ktany_close(context, id)
++    krb5_context context;
++    krb5_keytab id;
++{
++    krb5_ktany_data *data = (krb5_ktany_data *)id->data;
++
++    cleanup(context, data, data->nchoices);
++    id->ops = 0;
++    free(id);
++    return(0);
++}
++
++static krb5_error_code
++krb5_ktany_get_entry(context, id, principal, kvno, enctype, entry)
++    krb5_context context;
++    krb5_keytab id;
++    krb5_const_principal principal;
++    krb5_kvno kvno;
++    krb5_enctype enctype;
++    krb5_keytab_entry *entry;
++{
++    krb5_ktany_data *data = (krb5_ktany_data *)id->data;
++    krb5_error_code kerror = KRB5_KT_NOTFOUND;
++    int i;
++
++    for (i = 0; i < data->nchoices; i++) {
++	if ((kerror = krb5_kt_get_entry(context, data->choices[i], principal,
++					kvno, enctype, entry)) != ENOENT)
++	    return kerror;
++    }
++    return kerror;
++}
++
++static krb5_error_code
++krb5_ktany_start_seq_get(context, id, cursorp)
++    krb5_context context;
++    krb5_keytab id;
++    krb5_kt_cursor *cursorp;
++{
++    krb5_ktany_data *data = (krb5_ktany_data *)id->data;
++    krb5_ktany_cursor_data *cdata;
++    krb5_error_code kerror = ENOENT;
++    int i;
++
++    if ((cdata = (krb5_ktany_cursor_data *)
++	 malloc(sizeof(krb5_ktany_cursor_data))) == NULL)
++	return(ENOMEM);
++
++    /* Find a choice which can handle the serialization request. */
++    for (i = 0; i < data->nchoices; i++) {
++	if ((kerror = krb5_kt_start_seq_get(context, data->choices[i],
++					    &cdata->cursor)) == 0)
++	    break;
++	else if (kerror != ENOENT) {
++	    free(cdata);
++	    return(kerror);
++	}
++    }
++
++    if (i == data->nchoices) {
++	/* Everyone returned ENOENT, so no go. */
++	free(cdata);
++	return(kerror);
++    }
++
++    cdata->which = i;
++    *cursorp = (krb5_kt_cursor)cdata;
++    return(0);
++}
++
++static krb5_error_code
++krb5_ktany_next_entry(context, id, entry, cursor)
++    krb5_context context;
++    krb5_keytab id;
++    krb5_keytab_entry *entry;
++    krb5_kt_cursor *cursor;
++{
++    krb5_ktany_data *data = (krb5_ktany_data *)id->data;
++    krb5_ktany_cursor_data *cdata = (krb5_ktany_cursor_data *)*cursor;
++    krb5_keytab choice_id;
++
++    choice_id = data->choices[cdata->which];
++    return(krb5_kt_next_entry(context, choice_id, entry, &cdata->cursor));
++}
++
++static krb5_error_code
++krb5_ktany_end_seq_get(context, id, cursor)
++    krb5_context context;
++    krb5_keytab id;
++    krb5_kt_cursor *cursor;
++{
++    krb5_ktany_data *data = (krb5_ktany_data *)id->data;
++    krb5_ktany_cursor_data *cdata = (krb5_ktany_cursor_data *)*cursor;
++    krb5_keytab choice_id;
++    krb5_error_code kerror;
++
++    choice_id = data->choices[cdata->which];
++    kerror = krb5_kt_end_seq_get(context, choice_id, &cdata->cursor);
++    free(cdata);
++    return(kerror);
++}
++
++static void
++cleanup(context, data, nchoices)
++    krb5_context context;
++    krb5_ktany_data *data;
++    int nchoices;
++{
++    int i;
++
++    free(data->name);
++    for (i = 0; i < nchoices; i++)
++	krb5_kt_close(context, data->choices[i]);
++    free(data->choices);
++    free(data);
++}
+diff --git a/src/lib/krb5/keytab/ktbase.c b/src/lib/krb5/keytab/ktbase.c
+index 0d39b2940..6534d7c52 100644
+--- a/src/lib/krb5/keytab/ktbase.c
++++ b/src/lib/krb5/keytab/ktbase.c
+@@ -57,14 +57,19 @@ extern const krb5_kt_ops krb5_ktf_ops;
+ extern const krb5_kt_ops krb5_ktf_writable_ops;
+ extern const krb5_kt_ops krb5_kts_ops;
+ extern const krb5_kt_ops krb5_mkt_ops;
++extern const krb5_kt_ops krb5_kta_ops;
+ 
+ struct krb5_kt_typelist {
+     const krb5_kt_ops *ops;
+     const struct krb5_kt_typelist *next;
+ };
++static struct krb5_kt_typelist krb5_kt_typelist_any = {
++    &krb5_kta_ops,
++    NULL
++};
+ const static struct krb5_kt_typelist krb5_kt_typelist_srvtab = {
+     &krb5_kts_ops,
+-    NULL
++    &krb5_kt_typelist_any
+ };
+ const static struct krb5_kt_typelist krb5_kt_typelist_memory = {
+     &krb5_mkt_ops,
diff --git a/SOURCES/krb5-1.12.1-pam.patch b/SOURCES/krb5-1.12.1-pam.patch
new file mode 100644
index 0000000..97c1e8f
--- /dev/null
+++ b/SOURCES/krb5-1.12.1-pam.patch
@@ -0,0 +1,770 @@
+From 4cbb4325a86d1d71fa45d254221ec460c41b434d Mon Sep 17 00:00:00 2001
+From: Robbie Harwood <rharwood@redhat.com>
+Date: Tue, 23 Aug 2016 16:29:58 -0400
+Subject: [PATCH] krb5-1.12.1-pam.patch
+
+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.
+---
+ src/aclocal.m4              |  67 +++++++
+ src/clients/ksu/Makefile.in |   8 +-
+ src/clients/ksu/main.c      |  88 +++++++-
+ src/clients/ksu/pam.c       | 389 ++++++++++++++++++++++++++++++++++++
+ src/clients/ksu/pam.h       |  57 ++++++
+ src/configure.in            |   2 +
+ 6 files changed, 608 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 d6d1279c3..5c9c13e5f 100644
+--- a/src/aclocal.m4
++++ b/src/aclocal.m4
+@@ -1696,3 +1696,70 @@ AC_DEFUN(KRB5_AC_PERSISTENT_KEYRING,[
+       ]))
+ ])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"
++if test "$withpam" != no ; then
++	AC_MSG_RESULT([checking for PAM...])
++	PAM_LIBS=
++
++	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
++	fi
++
++	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=
++	else
++		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 b2fcbf240..5755bb58a 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='"/bin /local/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 7ff676ca7..c6321c01b 100644
+--- a/src/clients/ksu/main.c
++++ b/src/clients/ksu/main.c
+@@ -26,6 +26,7 @@
+  * KSU was writen 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"
+@@ -515,6 +521,23 @@ main (argc, 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 "
+@@ -575,6 +598,24 @@ main (argc, 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){
+@@ -632,6 +673,30 @@ main (argc, 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");
+@@ -729,7 +794,7 @@ main (argc, 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);
+@@ -759,16 +824,35 @@ main (argc, argv)
+             if (ret_pid == -1) {
+                 com_err(prog_name, errno, _("while calling waitpid"));
+             }
+-            sweep_up(ksu_context, cc_target);
++            if( !keep_target_cache ) {
++                sweep_up(ksu_context, cc_target);
++            }
+             exit (statusp);
+         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 000000000..cbfe48704
+--- /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 000000000..0ab76569c
+--- /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.in b/src/configure.in
+index 10f45eb12..7288a71ec 100644
+--- a/src/configure.in
++++ b/src/configure.in
+@@ -1306,6 +1306,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'
diff --git a/SOURCES/krb5-1.13-dirsrv-accountlock.patch b/SOURCES/krb5-1.13-dirsrv-accountlock.patch
new file mode 100644
index 0000000..ff5f73e
--- /dev/null
+++ b/SOURCES/krb5-1.13-dirsrv-accountlock.patch
@@ -0,0 +1,75 @@
+From bd9a3cc0c53f6dc47a124eb6e8f698c7f1d3cd36 Mon Sep 17 00:00:00 2001
+From: Robbie Harwood <rharwood@redhat.com>
+Date: Tue, 23 Aug 2016 16:47:44 -0400
+Subject: [PATCH] krb5-1.13-dirsrv-accountlock.patch
+
+Treat 'nsAccountLock: true' the same as 'loginDisabled: true'.  Updated from
+original version filed as RT#5891.
+---
+ src/aclocal.m4                                  |  9 +++++++++
+ src/plugins/kdb/ldap/libkdb_ldap/ldap_misc.c    | 17 +++++++++++++++++
+ .../kdb/ldap/libkdb_ldap/ldap_principal.c       |  3 +++
+ 3 files changed, 29 insertions(+)
+
+diff --git a/src/aclocal.m4 b/src/aclocal.m4
+index 5eeaa2d8a..1fd243094 100644
+--- a/src/aclocal.m4
++++ b/src/aclocal.m4
+@@ -1677,6 +1677,15 @@ if test "$with_ldap" = yes; then
+   AC_MSG_NOTICE(enabling OpenLDAP database backend module support)
+   OPENLDAP_PLUGIN=yes
+ fi
++AC_ARG_WITH([dirsrv-account-locking],
++[  --with-dirsrv-account-locking       compile 389/Red Hat/Fedora/Netscape Directory Server database backend module],
++[case "$withval" in
++    yes | no) ;;
++    *)  AC_MSG_ERROR(Invalid option value --with-dirsrv-account-locking="$withval") ;;
++esac], with_dirsrv_account_locking=no)
++if test $with_dirsrv_account_locking = yes; then
++    AC_DEFINE(HAVE_DIRSRV_ACCOUNT_LOCKING,1,[Define if LDAP KDB interface should heed 389 DS's nsAccountLock attribute.])
++fi
+ ])dnl
+ dnl
+ dnl If libkeyutils exists (on Linux) include it and use keyring ccache
+diff --git a/src/plugins/kdb/ldap/libkdb_ldap/ldap_misc.c b/src/plugins/kdb/ldap/libkdb_ldap/ldap_misc.c
+index 5b9d1e9fa..4e7270065 100644
+--- a/src/plugins/kdb/ldap/libkdb_ldap/ldap_misc.c
++++ b/src/plugins/kdb/ldap/libkdb_ldap/ldap_misc.c
+@@ -1652,6 +1652,23 @@ populate_krb5_db_entry(krb5_context context, krb5_ldap_context *ldap_context,
+     ret = krb5_dbe_update_tl_data(context, entry, &userinfo_tl_data);
+     if (ret)
+         goto cleanup;
++#ifdef HAVE_DIRSRV_ACCOUNT_LOCKING
++    {
++        krb5_timestamp              expiretime=0;
++        char                        *is_login_disabled=NULL;
++
++        /* LOGIN DISABLED */
++        ret = krb5_ldap_get_string(ld, ent, "nsAccountLock", &is_login_disabled,
++                                   &attr_present);
++        if (ret)
++            goto cleanup;
++        if (attr_present == TRUE) {
++            if (strcasecmp(is_login_disabled, "TRUE")== 0)
++                entry->attributes |= KRB5_KDB_DISALLOW_ALL_TIX;
++            free (is_login_disabled);
++        }
++    }
++#endif
+ 
+     ret = krb5_read_tkt_policy(context, ldap_context, entry, tktpolname);
+     if (ret)
+diff --git a/src/plugins/kdb/ldap/libkdb_ldap/ldap_principal.c b/src/plugins/kdb/ldap/libkdb_ldap/ldap_principal.c
+index d722dbfa6..5e8e9a897 100644
+--- a/src/plugins/kdb/ldap/libkdb_ldap/ldap_principal.c
++++ b/src/plugins/kdb/ldap/libkdb_ldap/ldap_principal.c
+@@ -54,6 +54,9 @@ char     *principal_attributes[] = { "krbprincipalname",
+                                      "krbLastFailedAuth",
+                                      "krbLoginFailedCount",
+                                      "krbLastSuccessfulAuth",
++#ifdef HAVE_DIRSRV_ACCOUNT_LOCKING
++                                     "nsAccountLock",
++#endif
+                                      "krbLastPwdChange",
+                                      "krbLastAdminUnlock",
+                                      "krbPrincipalAuthInd",
diff --git a/SOURCES/krb5-1.15-beta1-buildconf.patch b/SOURCES/krb5-1.15-beta1-buildconf.patch
new file mode 100644
index 0000000..a949727
--- /dev/null
+++ b/SOURCES/krb5-1.15-beta1-buildconf.patch
@@ -0,0 +1,70 @@
+From 162ba7fbce23d82719956de1b126e48fe676e9d1 Mon Sep 17 00:00:00 2001
+From: Robbie Harwood <rharwood@redhat.com>
+Date: Tue, 23 Aug 2016 16:45:26 -0400
+Subject: [PATCH] krb5-1.15-beta1-buildconf.patch
+
+Build binaries in this package as RELRO PIEs, libraries as partial RELRO,
+and install shared libraries with the execute bit set on them.  Prune out
+the -L/usr/lib* and PIE flags where they might leak out and affect
+apps which just want to link with the libraries. FIXME: needs to check and
+not just assume that the compiler supports using these flags.
+---
+ src/build-tools/krb5-config.in | 7 +++++++
+ src/config/pre.in              | 2 +-
+ src/config/shlib.conf          | 5 +++--
+ 3 files changed, 11 insertions(+), 3 deletions(-)
+
+diff --git a/src/build-tools/krb5-config.in b/src/build-tools/krb5-config.in
+index c17cb5eb5..1891dea99 100755
+--- a/src/build-tools/krb5-config.in
++++ b/src/build-tools/krb5-config.in
+@@ -226,6 +226,13 @@ if test -n "$do_libs"; then
+ 	    -e 's#\$(PTHREAD_CFLAGS)#'"$PTHREAD_CFLAGS"'#' \
+ 	    -e 's#\$(CFLAGS)##'`
+ 
++    if test `dirname $libdir` = /usr ; then
++        lib_flags=`echo $lib_flags | sed -e "s#-L$libdir##" -e "s#$RPATH_FLAG$libdir##"`
++    fi
++    lib_flags=`echo $lib_flags | sed -e "s#-fPIE##g" -e "s#-pie##g"`
++    lib_flags=`echo $lib_flags | sed -e "s#-Wl,-z,relro##g"`
++    lib_flags=`echo $lib_flags | sed -e "s#-Wl,-z,now##g"`
++
+     if test $library = 'kdb'; then
+ 	lib_flags="$lib_flags -lkdb5 $KDB5_DB_LIB"
+ 	library=krb5
+diff --git a/src/config/pre.in b/src/config/pre.in
+index d4714d29a..03f5c8890 100644
+--- a/src/config/pre.in
++++ b/src/config/pre.in
+@@ -185,7 +185,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) $(INSTALL_STRIP) -m 4755
+ ## This is needed because autoconf will sometimes define @exec_prefix@ to be
+ ## ${prefix}.
+ prefix=@prefix@
+diff --git a/src/config/shlib.conf b/src/config/shlib.conf
+index 3e4af6c02..2b20c3fda 100644
+--- a/src/config/shlib.conf
++++ b/src/config/shlib.conf
+@@ -423,7 +423,7 @@ mips-*-netbsd*)
+ 	# Linux ld doesn't default to stuffing the SONAME field...
+ 	# Use objdump -x to examine the fields of the library
+ 	# UNDEF_CHECK is suppressed by --enable-asan
+-	LDCOMBINE='$(CC) -shared -fPIC -Wl,-h,$(LIBPREFIX)$(LIBBASE)$(SHLIBSEXT) $(UNDEF_CHECK)'
++	LDCOMBINE='$(CC) -shared -fPIC -Wl,-h,$(LIBPREFIX)$(LIBBASE)$(SHLIBSEXT) $(UNDEF_CHECK)  -Wl,-z,relro -Wl,--warn-shared-textrel'
+ 	UNDEF_CHECK='-Wl,--no-undefined'
+ 	# $(EXPORT_CHECK) runs export-check.pl when in maintainer mode.
+ 	LDCOMBINE_TAIL='-Wl,--version-script binutils.versions $(EXPORT_CHECK)'
+@@ -435,7 +435,8 @@ mips-*-netbsd*)
+ 	SHLIB_EXPFLAGS='$(SHLIB_RPATH_FLAGS) $(SHLIB_DIRS) $(SHLIB_EXPLIBS)'
+ 	PROFFLAGS=-pg
+ 	PROG_RPATH_FLAGS='$(RPATH_FLAG)$(PROG_RPATH)'
+-	CC_LINK_SHARED='$(CC) $(PROG_LIBPATH) $(PROG_RPATH_FLAGS) $(CFLAGS) $(LDFLAGS)'
++	CC_LINK_SHARED='$(CC) $(PROG_LIBPATH) $(PROG_RPATH_FLAGS) $(CFLAGS) -pie -Wl,-z,relro -Wl,-z,now $(LDFLAGS)'
++	INSTALL_SHLIB='${INSTALL} -m755'
+ 	CC_LINK_STATIC='$(CC) $(PROG_LIBPATH) $(CFLAGS) $(LDFLAGS)'
+ 	CXX_LINK_SHARED='$(CXX) $(PROG_LIBPATH) $(PROG_RPATH_FLAGS) $(CXXFLAGS) $(LDFLAGS)'
+ 	CXX_LINK_STATIC='$(CXX) $(PROG_LIBPATH) $(CXXFLAGS) $(LDFLAGS)'
diff --git a/SOURCES/krb5-1.15.1-selinux-label.patch b/SOURCES/krb5-1.15.1-selinux-label.patch
new file mode 100644
index 0000000..728c72e
--- /dev/null
+++ b/SOURCES/krb5-1.15.1-selinux-label.patch
@@ -0,0 +1,1065 @@
+From c79d3881fefb6108306eb56cff62de03897d4bbc Mon Sep 17 00:00:00 2001
+From: Robbie Harwood <rharwood@redhat.com>
+Date: Tue, 23 Aug 2016 16:30:53 -0400
+Subject: [PATCH] krb5-1.15.1-selinux-label.patch
+
+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.
+---
+ src/aclocal.m4                                |  49 +++
+ src/build-tools/krb5-config.in                |   3 +-
+ src/config/pre.in                             |   3 +-
+ src/configure.in                              |   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/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/lib/krb5/rcache/rc_dfl.c                  |  13 +
+ 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/slave/kpropd.c                            |   9 +
+ src/util/profile/prof_file.c                  |   3 +-
+ src/util/support/Makefile.in                  |   3 +-
+ src/util/support/selinux.c                    | 406 ++++++++++++++++++
+ 25 files changed, 587 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 5c9c13e5f..6257dba40 100644
+--- a/src/aclocal.m4
++++ b/src/aclocal.m4
+@@ -89,6 +89,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
+@@ -1763,3 +1764,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"
++if test "$withselinux" != no ; then
++       AC_MSG_RESULT([checking for libselinux...])
++       SELINUX_LIBS=
++       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
++       fi
++
++       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
++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 f6184da3f..c17cb5eb5 100755
+--- a/src/build-tools/krb5-config.in
++++ b/src/build-tools/krb5-config.in
+@@ -41,6 +41,7 @@ DL_LIB='@DL_LIB@'
+ DEFCCNAME='@DEFCCNAME@'
+ DEFKTNAME='@DEFKTNAME@'
+ DEFCKTNAME='@DEFCKTNAME@'
++SELINUX_LIBS='@SELINUX_LIBS@'
+ 
+ LIBS='@LIBS@'
+ GEN_LIB=@GEN_LIB@
+@@ -255,7 +256,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 $GEN_LIB $LIBS $DL_LIB"
++    # linking, we would output "-lkrb5support $GEN_LIB $LIBS $SELINUX_LIBS $DL_LIB"
+     # here.
+ 
+     echo $lib_flags
+diff --git a/src/config/pre.in b/src/config/pre.in
+index 3f267eb1f..d4714d29a 100644
+--- a/src/config/pre.in
++++ b/src/config/pre.in
+@@ -177,6 +177,7 @@ LD = $(PURE) @LD@
+ KRB_INCLUDES = -I$(BUILDTOP)/include -I$(top_srcdir)/include
+ LDFLAGS = @LDFLAGS@
+ LIBS = @LIBS@
++SELINUX_LIBS=@SELINUX_LIBS@
+ 
+ INSTALL=@INSTALL@
+ INSTALL_STRIP=
+@@ -399,7 +400,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) $(GEN_LIB) $(LIBS) $(DL_LIB)
++KRB5_BASE_LIBS	= $(KRB5_LIB) $(K5CRYPTO_LIB) $(COM_ERR_LIB) $(SUPPORT_LIB) $(GEN_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.in b/src/configure.in
+index 7288a71ec..2b6d5baa7 100644
+--- a/src/configure.in
++++ b/src/configure.in
+@@ -1308,6 +1308,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 e1b1cb040..9378ae047 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 000000000..dfaaa847c
+--- /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 c86e78274..e81bb0a6d 100644
+--- a/src/include/krb5/krb5.hin
++++ b/src/include/krb5/krb5.hin
+@@ -87,6 +87,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 aca136f0b..22e926ae4 100644
+--- a/src/kadmin/dbutil/dump.c
++++ b/src/kadmin/dbutil/dump.c
+@@ -148,12 +148,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;
+ 
+@@ -194,7 +203,7 @@ prep_ok_file(krb5_context context, char *file_name, int *fd)
+         return 0;
+     }
+ 
+-    *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);
+         exit_status++;
+diff --git a/src/kdc/main.c b/src/kdc/main.c
+index f2226da25..ccac3a759 100644
+--- a/src/kdc/main.c
++++ b/src/kdc/main.c
+@@ -873,7 +873,7 @@ write_pid_file(const char *path)
+     FILE *file;
+     unsigned long pid;
+ 
+-    file = fopen(path, "w");
++    file = WRITABLEFOPEN(path, "w");
+     if (file == NULL)
+         return errno;
+     pid = (unsigned long) getpid();
+diff --git a/src/lib/kadm5/logger.c b/src/lib/kadm5/logger.c
+index ce79fabf7..c53a5743f 100644
+--- a/src/lib/kadm5/logger.c
++++ b/src/lib/kadm5/logger.c
+@@ -414,7 +414,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");
+@@ -918,7 +918,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 766d3002a..6466417b7 100644
+--- a/src/lib/kdb/kdb_log.c
++++ b/src/lib/kdb/kdb_log.c
+@@ -476,7 +476,7 @@ ulog_map(krb5_context context, const char *logname, uint32_t ulogentries)
+     int ulogfd = -1;
+ 
+     if (stat(logname, &st) == -1) {
+-        ulogfd = open(logname, O_RDWR | O_CREAT, 0600);
++        ulogfd = THREEPARAMOPEN(logname, O_RDWR | O_CREAT, 0600);
+         if (ulogfd == -1)
+             return errno;
+ 
+diff --git a/src/lib/krb5/ccache/cc_dir.c b/src/lib/krb5/ccache/cc_dir.c
+index bba64e516..73f0fe62d 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 091f2c43f..ecc97ee2f 100644
+--- a/src/lib/krb5/keytab/kt_file.c
++++ b/src/lib/krb5/keytab/kt_file.c
+@@ -1024,14 +1024,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 e97ce5fe5..779f184cb 100644
+--- a/src/lib/krb5/os/trace.c
++++ b/src/lib/krb5/os/trace.c
+@@ -398,7 +398,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/lib/krb5/rcache/rc_dfl.c b/src/lib/krb5/rcache/rc_dfl.c
+index 1e0cb22c9..f5e93b1ab 100644
+--- a/src/lib/krb5/rcache/rc_dfl.c
++++ b/src/lib/krb5/rcache/rc_dfl.c
+@@ -793,6 +793,9 @@ krb5_rc_dfl_expunge_locked(krb5_context context, krb5_rcache id)
+     krb5_error_code retval = 0;
+     krb5_rcache tmp;
+     krb5_deltat lifespan = t->lifespan;  /* save original lifespan */
++#ifdef USE_SELINUX
++    void *selabel;
++#endif
+ 
+     if (! t->recovering) {
+         name = t->name;
+@@ -814,7 +817,17 @@ krb5_rc_dfl_expunge_locked(krb5_context context, krb5_rcache id)
+     retval = krb5_rc_resolve(context, tmp, 0);
+     if (retval)
+         goto cleanup;
++#ifdef USE_SELINUX
++    if (t->d.fn != NULL)
++        selabel = krb5int_push_fscreatecon_for(t->d.fn);
++    else
++        selabel = NULL;
++#endif
+     retval = krb5_rc_initialize(context, tmp, lifespan);
++#ifdef USE_SELINUX
++    if (selabel != NULL)
++        krb5int_pop_fscreatecon(selabel);
++#endif
+     if (retval)
+         goto cleanup;
+     for (q = t->a; q; q = q->na) {
+diff --git a/src/plugins/kdb/db2/adb_openclose.c b/src/plugins/kdb/db2/adb_openclose.c
+index 7db30a33b..2b9d01921 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 d23587a59..e2825650b 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 2977b17f3..d5809a5a9 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"
+ 
+@@ -203,7 +204,7 @@ __bt_open(fname, flags, mode, openinfo, dflags)
+ 			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 862dbb164..686a960c9 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"
+@@ -129,7 +130,7 @@ __kdb2_hash_open(file, flags, mode, info, dflags)
+ 		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 d8b26e701..b0daa7c02 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"
+ 
+@@ -68,7 +69,8 @@ __rec_open(fname, flags, mode, openinfo, dflags)
+ 	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 022156a5e..3d6994c67 100644
+--- a/src/plugins/kdb/ldap/ldap_util/kdb5_ldap_services.c
++++ b/src/plugins/kdb/ldap/ldap_util/kdb5_ldap_services.c
+@@ -203,7 +203,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));
+@@ -244,6 +244,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;
+ 
+@@ -255,7 +258,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/slave/kpropd.c b/src/slave/kpropd.c
+index d621f108f..99676cc97 100644
+--- a/src/slave/kpropd.c
++++ b/src/slave/kpropd.c
+@@ -488,6 +488,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);
+@@ -543,9 +546,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/util/profile/prof_file.c b/src/util/profile/prof_file.c
+index 907c119bb..0f5462aea 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 0bf0b7a87..58ac2e333 100644
+--- a/src/util/support/Makefile.in
++++ b/src/util/support/Makefile.in
+@@ -69,6 +69,7 @@ IPC_SYMS= \
+ 
+ STLIBOBJS= \
+ 	threads.o \
++	selinux.o \
+ 	init-addrinfo.o \
+ 	plugins.o \
+ 	errors.o \
+@@ -149,7 +150,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 000000000..6d41f3244
+--- /dev/null
++++ b/src/util/support/selinux.c
+@@ -0,0 +1,406 @@
++/*
++ * 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 "../../include/autoconf.h"
++
++#ifdef USE_SELINUX
++
++#include <k5-label.h>
++#include <k5-platform.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 security_context_t
++push_fscreatecon(const char *pathname, mode_t mode)
++{
++    security_context_t previous, configuredsc, currentsc, derivedsc;
++    context_t current, derived;
++    const char *fullpath, *currentuser;
++    char *genpath;
++
++    previous = configuredsc = currentsc = derivedsc = NULL;
++    current = derived = NULL;
++    genpath = 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(security_context_t 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;
++    security_context_t 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;
++    security_context_t 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;
++    security_context_t 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;
++    security_context_t 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;
++    security_context_t 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 */
diff --git a/SOURCES/krb5-1.16.1.tar.gz.asc b/SOURCES/krb5-1.16.1.tar.gz.asc
new file mode 100644
index 0000000..9a11343
--- /dev/null
+++ b/SOURCES/krb5-1.16.1.tar.gz.asc
@@ -0,0 +1,17 @@
+-----BEGIN PGP SIGNATURE-----
+Version: GnuPG v1
+
+iQIVAwUAWushEwy6CFdfg3LfAQJ+eBAAijTUBfXzCuxCwbDhCFYb1fIbHMkKkTuq
+knFKv0VbALW1qUAj5v35A6GjDam6a33bMvGX8MzbGK/a9IDkpvaaXP/c37V4OfiQ
+MhA6uQl0vxBMoCZqAFEVcWd6+M/0rY0WBZKpXRiZxxuSNPnSXn1l9fQAcrYKGb7I
+YpaAWnzw+cc1k4Xi+GaaSghEYA4dX7TXh1fViJyHaNSESYZjH3J6wEdPm6LtZk6q
+GwJw/ieMQi8djde0AhCbzMHWiaeW3jNPOJmpd3mpY04BAAkzGCyRiYGscxb6ge4u
+ag2fojv7rbnJxDzy9RO0ZP0+fVPDMwInZ5GHPftbraSDFkTH2JBAYFudPsLDAoRK
+FdjLeHpvuU5ifXWrLyshVYYfeXSe0fHz9Xhfhq2/OmfBD6vQl5k86z8IqxNm4ujy
+ziypmTzHFnP/sBKlMgSMdDEKoKZHxevVQM5eJQd1XGexmwogkSPX8mwoEc0q4dtZ
+h5w/fCu4ERA0BihvnQMZCZgwe32pO27ccPc6PqNHffUSLOq74J4gBHeoAoZ+SYPu
+33oG7wxh+8WONzEGujl1lmxHFstij/njg8nULQ6bo6hSZnlMD0gU59mG9seC2jjr
+E4aM4TXd1ixxPzM/cqxfI9SalytwYW0gn7Vuyj3P8xIZ5GQZiTsD7XWJqzb3xHmA
+2JSQt4TK3Cc=
+=9z9K
+-----END PGP SIGNATURE-----
diff --git a/SOURCES/krb5-1.3.1-dns.patch b/SOURCES/krb5-1.3.1-dns.patch
new file mode 100644
index 0000000..1af7c12
--- /dev/null
+++ b/SOURCES/krb5-1.3.1-dns.patch
@@ -0,0 +1,22 @@
+From 2338e73d8dced4f85d6b4f5a0f7df21033ac78c1 Mon Sep 17 00:00:00 2001
+From: Robbie Harwood <rharwood@redhat.com>
+Date: Tue, 23 Aug 2016 16:46:21 -0400
+Subject: [PATCH] krb5-1.3.1-dns.patch
+
+We want to be able to use --with-netlib and --enable-dns at the same time.
+---
+ src/aclocal.m4 | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/src/aclocal.m4 b/src/aclocal.m4
+index 6257dba40..5eeaa2d8a 100644
+--- a/src/aclocal.m4
++++ b/src/aclocal.m4
+@@ -726,6 +726,7 @@ AC_HELP_STRING([--with-netlib=LIBS], use user defined resolver library),
+ 	LIBS="$LIBS $withval"
+ 	AC_MSG_RESULT("netlib will use \'$withval\'")
+   fi
++  KRB5_AC_ENABLE_DNS
+ ],dnl
+ [AC_LIBRARY_NET]
+ )])dnl
diff --git a/SOURCES/krb5-1.9-debuginfo.patch b/SOURCES/krb5-1.9-debuginfo.patch
new file mode 100644
index 0000000..5b0f5bc
--- /dev/null
+++ b/SOURCES/krb5-1.9-debuginfo.patch
@@ -0,0 +1,39 @@
+From 20bc1c9b1d37138d1a8538f9cef22108c8fabf4f Mon Sep 17 00:00:00 2001
+From: Robbie Harwood <rharwood@redhat.com>
+Date: Tue, 23 Aug 2016 16:49:25 -0400
+Subject: [PATCH] krb5-1.9-debuginfo.patch
+
+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.
+---
+ src/kadmin/cli/Makefile.in                 | 5 +++++
+ src/plugins/kdb/ldap/ldap_util/Makefile.in | 2 +-
+ 2 files changed, 6 insertions(+), 1 deletion(-)
+
+diff --git a/src/kadmin/cli/Makefile.in b/src/kadmin/cli/Makefile.in
+index adfea6e2b..d1327e400 100644
+--- a/src/kadmin/cli/Makefile.in
++++ b/src/kadmin/cli/Makefile.in
+@@ -37,3 +37,8 @@ clean-unix::
+ # 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 8669c2436..a22f23c02 100644
+--- a/src/plugins/kdb/ldap/ldap_util/Makefile.in
++++ b/src/plugins/kdb/ldap/ldap_util/Makefile.in
+@@ -20,7 +20,7 @@ $(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)
diff --git a/SOURCES/krb5-krb5kdc.conf b/SOURCES/krb5-krb5kdc.conf
new file mode 100644
index 0000000..eadeb51
--- /dev/null
+++ b/SOURCES/krb5-krb5kdc.conf
@@ -0,0 +1 @@
+d /var/run/krb5kdc 0755 root root
diff --git a/SOURCES/krb5.conf b/SOURCES/krb5.conf
new file mode 100644
index 0000000..99b8859
--- /dev/null
+++ b/SOURCES/krb5.conf
@@ -0,0 +1,28 @@
+# To opt out of the system crypto-policies configuration of krb5, remove the
+# symlink at /etc/krb5.conf.d/crypto-policies which will not be recreated.
+includedir /etc/krb5.conf.d/
+
+[logging]
+    default = FILE:/var/log/krb5libs.log
+    kdc = FILE:/var/log/krb5kdc.log
+    admin_server = FILE:/var/log/kadmind.log
+
+[libdefaults]
+    dns_lookup_realm = false
+    ticket_lifetime = 24h
+    renew_lifetime = 7d
+    forwardable = true
+    rdns = false
+    pkinit_anchors = /etc/pki/tls/certs/ca-bundle.crt
+    spake_preauth_groups = edwards25519
+#    default_realm = EXAMPLE.COM
+
+[realms]
+# EXAMPLE.COM = {
+#     kdc = kerberos.example.com
+#     admin_server = kerberos.example.com
+# }
+
+[domain_realm]
+# .example.com = EXAMPLE.COM
+# example.com = EXAMPLE.COM
diff --git a/SOURCES/krb5kdc.logrotate b/SOURCES/krb5kdc.logrotate
new file mode 100644
index 0000000..1100ed3
--- /dev/null
+++ b/SOURCES/krb5kdc.logrotate
@@ -0,0 +1,9 @@
+/var/log/krb5kdc.log {
+    missingok
+    notifempty
+    monthly
+    rotate 12
+    postrotate
+	/bin/kill -HUP `cat /var/run/krb5kdc.pid 2>/dev/null` 2> /dev/null || true
+    endscript
+}
diff --git a/SOURCES/krb5kdc.service b/SOURCES/krb5kdc.service
new file mode 100644
index 0000000..806b062
--- /dev/null
+++ b/SOURCES/krb5kdc.service
@@ -0,0 +1,14 @@
+[Unit]
+Description=Kerberos 5 KDC
+Wants=network-online.target
+After=syslog.target network.target network-online.target
+
+[Service]
+Type=forking
+PIDFile=/var/run/krb5kdc.pid
+EnvironmentFile=-/etc/sysconfig/krb5kdc
+ExecStart=/usr/sbin/krb5kdc -P /var/run/krb5kdc.pid $KRB5KDC_ARGS
+ExecReload=/bin/kill -HUP $MAINPID
+
+[Install]
+WantedBy=multi-user.target
diff --git a/SOURCES/krb5kdc.sysconfig b/SOURCES/krb5kdc.sysconfig
new file mode 100644
index 0000000..791216d
--- /dev/null
+++ b/SOURCES/krb5kdc.sysconfig
@@ -0,0 +1 @@
+KRB5KDC_ARGS=
diff --git a/SOURCES/ksu.pamd b/SOURCES/ksu.pamd
new file mode 100644
index 0000000..66f5b2c
--- /dev/null
+++ b/SOURCES/ksu.pamd
@@ -0,0 +1,4 @@
+#%PAM-1.0
+auth    include  su
+account include  su
+session include  su
diff --git a/SOURCES/noport.c b/SOURCES/noport.c
new file mode 100644
index 0000000..22088eb
--- /dev/null
+++ b/SOURCES/noport.c
@@ -0,0 +1,111 @@
+#define _GNU_SOURCE
+#include <sys/socket.h>
+#include <dlfcn.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <netinet/in.h>
+
+static int
+port_is_okay(unsigned short port)
+{
+	char *p, *q;
+	long l;
+
+	p = getenv("NOPORT");
+	while ((p != NULL) && (*p != '\0')) {
+		l = strtol(p, &q, 10);
+		if ((q == NULL) || (q == p)) {
+			break;
+		}
+		if ((*q == '\0') || (*q == ',')) {
+			if (port == l) {
+				errno = ECONNREFUSED;
+				return -1;
+			}
+		}
+		p = q;
+		p += strspn(p, ",");
+	}
+	return 0;
+}
+
+int
+connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen)
+{
+	unsigned short port;
+	static int (*next_connect)(int, const struct sockaddr *, socklen_t);
+
+	if (next_connect == NULL) {
+		next_connect = dlsym(RTLD_NEXT, "connect");
+		if (next_connect == NULL) {
+			errno = ENOSYS;
+			return -1;
+		}
+	}
+
+	if (getenv("NOPORT") == NULL) {
+		return next_connect(sockfd, addr, addrlen);
+	}
+
+	switch (addr->sa_family) {
+	case AF_INET:
+		port = ntohs(((struct sockaddr_in *)addr)->sin_port);
+		if (port_is_okay(port) != 0) {
+			return -1;
+		}
+		break;
+	case AF_INET6:
+		port = ntohs(((struct sockaddr_in6 *)addr)->sin6_port);
+		if (port_is_okay(port) != 0) {
+			return -1;
+		}
+		break;
+	default:
+		break;
+	}
+	return next_connect(sockfd, addr, addrlen);
+}
+
+ssize_t
+sendto(int sockfd, const void *buf, size_t len, int flags,
+       const struct sockaddr *dest_addr, socklen_t addrlen)
+{
+	unsigned short port;
+	static int (*next_sendto)(int, const void *, size_t, int,
+				  const struct sockaddr *, socklen_t);
+
+	if (next_sendto == NULL) {
+		next_sendto = dlsym(RTLD_NEXT, "sendto");
+		if (next_sendto == NULL) {
+			errno = ENOSYS;
+			return -1;
+		}
+	}
+
+	if (getenv("NOPORT") == NULL) {
+		return next_sendto(sockfd, buf, len, flags, dest_addr, addrlen);
+	}
+
+	if (dest_addr != NULL) {
+		switch (dest_addr->sa_family) {
+		case AF_INET:
+			port = ((struct sockaddr_in *)dest_addr)->sin_port;
+			port = ntohs(port);
+			if (port_is_okay(port) != 0) {
+				return -1;
+			}
+			break;
+		case AF_INET6:
+			port = ((struct sockaddr_in6 *)dest_addr)->sin6_port;
+			port = ntohs(port);
+			if (port_is_okay(port) != 0) {
+				return -1;
+			}
+			break;
+		default:
+			break;
+		}
+	}
+	return next_sendto(sockfd, buf, len, flags, dest_addr, addrlen);
+}
diff --git a/SPECS/krb5.spec b/SPECS/krb5.spec
new file mode 100644
index 0000000..2afc2af
--- /dev/null
+++ b/SPECS/krb5.spec
@@ -0,0 +1,3710 @@
+%global WITH_DIRSRV 1
+
+# Set this so that find-lang.sh will recognize the .po files.
+%global gettext_domain mit-krb5
+# Guess where the -libs subpackage's docs are going to go.
+%define libsdocdir %{?_pkgdocdir:%(echo %{_pkgdocdir} | sed -e s,krb5,krb5-libs,g)}%{!?_pkgdocdir:%{_docdir}/%{name}-libs-%{version}}
+# Figure out where the default ccache lives and how we set it.
+%global configure_default_ccache_name 1
+%global configured_default_ccache_name KEYRING:persistent:%%{uid}
+
+# leave empty or set to e.g., -beta2
+%global prerelease %{nil}
+
+# Should be in form 5.0, 6.1, etc.
+%global kdbversion 7.0
+
+Summary: The Kerberos network authentication system
+Name: krb5
+Version: 1.16.1
+# for prerelease, should be e.g., 0.% {prerelease}.1% { ?dist } (without spaces)
+Release: 22%{?dist}
+
+# lookaside-cached sources; two downloads and a build artifact
+Source0: https://web.mit.edu/kerberos/dist/krb5/1.16/krb5-%{version}%{prerelease}.tar.gz
+# rharwood has trust path to signing key and verifies on check-in
+Source1: https://web.mit.edu/kerberos/dist/krb5/1.16/krb5-%{version}%{prerelease}.tar.gz.asc
+# This source is generated during the build because it is documentation.
+# To override this behavior (e.g., new upstream version), do:
+#     tar cfT krb5-1.15.2-pdfs.tar /dev/null
+# or the like.  This logic persists due to how slow the stranger Fedora
+# architecture builders are.  5 minutes on my laptop, 45 on koji easy.
+Source3: krb5-%{version}%{prerelease}-pdfs.tar
+
+# Numbering is a relic of old init systems etc.  It's easiest to just leave.
+Source2: kprop.service
+Source4: kadmin.service
+Source5: krb5kdc.service
+Source6: krb5.conf
+Source10: kdc.conf
+Source11: kadm5.acl
+Source19: krb5kdc.sysconfig
+Source20: kadmin.sysconfig
+Source21: kprop.sysconfig
+Source29: ksu.pamd
+Source33: krb5kdc.logrotate
+Source34: kadmind.logrotate
+Source39: krb5-krb5kdc.conf
+
+# Carry this locally until it's available in a packaged form.
+Source100: noport.c
+
+Patch26: krb5-1.12.1-pam.patch
+Patch27: krb5-1.15.1-selinux-label.patch
+Patch28: krb5-1.12-ksu-path.patch
+Patch29: krb5-1.12-ktany.patch
+Patch30: krb5-1.15-beta1-buildconf.patch
+Patch31: krb5-1.3.1-dns.patch
+Patch32: krb5-1.12-api.patch
+Patch33: krb5-1.13-dirsrv-accountlock.patch
+Patch34: krb5-1.9-debuginfo.patch
+Patch35: krb5-1.11-run_user_0.patch
+Patch36: krb5-1.11-kpasswdtest.patch
+Patch40: Fix-hex-conversion-of-PKINIT-certid-strings.patch
+Patch41: Exit-with-status-0-from-kadmind.patch
+Patch42: Include-etype-info-in-for-hardware-preauth-hints.patch
+Patch43: Fix-securid_sam2-preauth-for-non-default-salt.patch
+Patch44: Refactor-KDC-krb5_pa_data-utility-functions.patch
+Patch45: Simplify-kdc_preauth.c-systems-table.patch
+Patch46: Add-PKINIT-client-support-for-freshness-token.patch
+Patch47: Add-PKINIT-KDC-support-for-freshness-token.patch
+Patch49: Fix-read-overflow-in-KDC-sort_pa_data.patch
+Patch50: Include-preauth-name-in-trace-output-if-possible.patch
+Patch51: Report-extended-errors-in-kinit-k-t-KDB.patch
+Patch52: Add-libkrb5support-hex-functions-and-tests.patch
+Patch53: Use-libkrb5support-hex-functions-where-appropriate.patch
+Patch54: Add-ASN.1-encoders-and-decoders-for-SPAKE-types.patch
+Patch55: Add-k5_buf_add_vfmt-to-k5buf-interface.patch
+Patch56: Add-vector-support-to-k5_sha256.patch
+Patch57: Move-zap-definition-to-k5-platform.h.patch
+Patch58: Implement-k5_buf_init_dynamic_zap.patch
+Patch59: Use-k5_buf_init_dynamic_zap-where-appropriate.patch
+Patch60: Add-SPAKE-preauth-support.patch
+Patch61: Add-doc-index-entries-for-SPAKE-constants.patch
+Patch62: Fix-SPAKE-memory-leak.patch
+Patch64: Zap-data-when-freeing-krb5_spake_factor.patch
+Patch65: Be-more-careful-asking-for-AS-key-in-SPAKE-client.patch
+Patch68: Restrict-pre-authentication-fallback-cases.patch
+Patch69: Remove-nodes-option-from-make-certs-scripts.patch
+Patch70: Fix-segfault-in-finish_dispatch.patch
+Patch71: Log-when-non-root-ksu-authorization-fails.patch
+Patch72: Add-k5_dir_filenames-to-libkrb5support.patch
+Patch73: Process-profile-includedir-in-sorted-order.patch
+Patch74: Make-docs-build-python3-compatible.patch
+Patch75: Add-flag-to-disable-encrypted-timestamp-on-client.patch
+Patch76: Explicitly-look-for-python2-in-configure.in.patch
+Patch77: Use-SHA-256-instead-of-MD5-for-audit-ticket-IDs.patch
+Patch78: Add-k5test-mark-function.patch
+Patch79: Convert-Python-tests-to-Python-3.patch
+Patch80: Zap-copy-of-secret-in-RC4-string-to-key.patch
+Patch81: Fix-some-broken-tests-for-Python-3.patch
+Patch82: Eliminate-preprocessor-disabled-dead-code.patch
+Patch83: Make-krb5kdc-p-affect-TCP-ports.patch
+Patch84: Remove-outdated-note-in-krb5kdc-man-page.patch
+Patch85: Fix-k5test-prompts-for-Python-3.patch
+Patch86: Become-FIPS-aware.patch
+Patch87: In-FIPS-mode-add-plaintext-fallback-for-RC4-usages-a.patch
+Patch88: Remove-incorrect-KDC-assertion.patch
+
+License: MIT
+URL: http://web.mit.edu/kerberos/www/
+Group: System Environment/Libraries
+BuildRequires: autoconf, bison, cmake, flex, gawk, gettext, pkgconfig, sed
+BuildRequires: gcc
+BuildRequires: libcom_err-devel, libedit-devel, libss-devel
+BuildRequires: gzip, ncurses-devel
+BuildRequires: python3-sphinx, texlive-pdftex, latexmk
+
+# For autosetup
+BuildRequires: git
+
+# Originally from \usepackage directives produced by sphinx:
+BuildRequires: tex(babel.sty)
+BuildRequires: tex(bookmark.sty)
+BuildRequires: tex(capt-of.sty)
+BuildRequires: tex(eqparbox.sty)
+BuildRequires: tex(fancybox.sty)
+BuildRequires: tex(fncychap.sty)
+BuildRequires: tex(fontenc.sty)
+BuildRequires: tex(framed.sty)
+BuildRequires: tex(hyperref.sty)
+BuildRequires: tex(ifthen.sty)
+BuildRequires: tex(inputenc.sty)
+BuildRequires: tex(longtable.sty)
+BuildRequires: tex(multirow.sty)
+BuildRequires: tex(needspace.sty)
+BuildRequires: tex(report.cls)
+BuildRequires: tex(tabulary.sty)
+BuildRequires: tex(threeparttable.sty)
+BuildRequires: tex(times.sty)
+BuildRequires: tex(titlesec.sty)
+BuildRequires: tex(upquote.sty)
+BuildRequires: tex(wrapfig.sty)
+
+# Typical fonts, and the commands which we need to have present.
+BuildRequires: texlive, texlive-latex, texlive-texmf-fonts
+BuildRequires: /usr/bin/pdflatex /usr/bin/makeindex
+BuildRequires: keyutils, keyutils-libs-devel >= 1.5.8
+BuildRequires: libselinux-devel
+BuildRequires: pam-devel
+BuildRequires: systemd-units
+
+# For the test framework.
+BuildRequires: perl-interpreter, dejagnu, tcl-devel, python3
+BuildRequires: net-tools, rpcbind
+BuildRequires: hostname
+BuildRequires: iproute
+BuildRequires: libverto-devel
+BuildRequires: openldap-devel
+BuildRequires: openssl-devel >= 0.9.8
+
+%ifarch %{ix86} x86_64
+BuildRequires: yasm
+%endif
+
+BuildRequires: nss_wrapper
+BuildRequires: socket_wrapper
+
+%description
+Kerberos V5 is a trusted-third-party network authentication system,
+which can improve your network's security by eliminating the insecure
+practice of sending passwords over the network in unencrypted form.
+
+%package devel
+Summary: Development files needed to compile Kerberos 5 programs
+Group: Development/Libraries
+Requires: %{name}-libs%{?_isa} = %{version}-%{release}
+Requires: libkadm5%{?_isa} = %{version}-%{release}
+Requires: libcom_err-devel
+Requires: keyutils-libs-devel, libselinux-devel
+Requires: libverto-devel
+Provides: krb5-kdb-version = %{kdbversion}
+
+%description devel
+Kerberos is a network authentication system. The krb5-devel package
+contains the header files and libraries needed for compiling Kerberos
+5 programs. If you want to develop Kerberos-aware programs, you need
+to install this package.
+
+%package libs
+Summary: The non-admin shared libraries used by Kerberos 5
+Group: System Environment/Libraries
+Requires: coreutils, gawk, grep, sed
+Requires: keyutils-libs >= 1.5.8
+Requires: /etc/crypto-policies/back-ends/krb5.config
+
+%description libs
+Kerberos is a network authentication system. The krb5-libs package
+contains the shared libraries needed by Kerberos 5. If you are using
+Kerberos, you need to install this package.
+
+%package server
+Group: System Environment/Daemons
+Summary: The KDC and related programs for Kerberos 5
+Requires: %{name}-libs%{?_isa} = %{version}-%{release}
+Requires(post): systemd-units
+Requires(preun): systemd-units
+Requires(postun): systemd-units
+# we drop files in its directory, but we don't want to own that directory
+Requires: logrotate
+# we specify /usr/share/dict/words as the default dict_file in kdc.conf
+Requires: /usr/share/dict/words
+# for run-time, and for parts of the test suite
+BuildRequires: libverto-module-base
+Requires: libverto-module-base
+%ifarch x86_64
+Obsoletes: %{name}-server-%{version}-%{release}.i686
+%endif
+%ifarch ppc64
+Obsoletes: %{name}-server-%{version}-%{release}.ppc
+%endif
+%ifarch s390x
+Obsoletes: %{name}-server-%{version}-%{release}.s390
+%endif
+Requires: libkadm5%{?_isa} = %{version}-%{release}
+
+%description server
+Kerberos is a network authentication system. The krb5-server package
+contains the programs that must be installed on a Kerberos 5 key
+distribution center (KDC).  If you are installing a Kerberos 5 KDC,
+you need to install this package (in other words, most people should
+NOT install this package).
+
+%package server-ldap
+Group: System Environment/Daemons
+Summary: The LDAP storage plugin for the Kerberos 5 KDC
+Requires: %{name}-server%{?_isa} = %{version}-%{release}
+Requires: %{name}-libs%{?_isa} = %{version}-%{release}
+Requires: libkadm5%{?_isa} = %{version}-%{release}
+%ifarch x86_64
+Obsoletes: %{name}-server-ldap-%{version}-%{release}.i686
+%endif
+%ifarch ppc64
+Obsoletes: %{name}-server-ldap-%{version}-%{release}.ppc
+%endif
+%ifarch s390x
+Obsoletes: %{name}-server-ldap-%{version}-%{release}.s390
+%endif
+
+%description server-ldap
+Kerberos is a network authentication system. The krb5-server package
+contains the programs that must be installed on a Kerberos 5 key
+distribution center (KDC).  If you are installing a Kerberos 5 KDC,
+and you wish to use a directory server to store the data for your
+realm, you need to install this package.
+
+%package workstation
+Summary: Kerberos 5 programs for use on workstations
+Group: System Environment/Base
+Requires: %{name}-libs%{?_isa} = %{version}-%{release}
+Requires: libkadm5%{?_isa} = %{version}-%{release}
+
+%description workstation
+Kerberos is a network authentication system. The krb5-workstation
+package contains the basic Kerberos programs (kinit, klist, kdestroy,
+kpasswd). If your network uses Kerberos, this package should be
+installed on every workstation.
+
+%package pkinit
+Summary: The PKINIT module for Kerberos 5
+Group: System Environment/Libraries
+Requires: %{name}-libs%{?_isa} = %{version}-%{release}
+Obsoletes: krb5-pkinit-openssl < %{version}-%{release}
+Provides: krb5-pkinit-openssl = %{version}-%{release}
+
+%description pkinit
+Kerberos is a network authentication system. The krb5-pkinit
+package contains the PKINIT plugin, which allows clients
+to obtain initial credentials from a KDC using a private key and a
+certificate.
+
+%package -n libkadm5
+Summary: Kerberos 5 Administrative libraries
+Group: System Environment/Base
+Requires: %{name}-libs%{?_isa} = %{version}-%{release}
+
+%description -n libkadm5
+Kerberos is a network authentication system. The libkadm5 package
+contains only the libkadm5clnt and libkadm5serv shared objects. This
+interface is not considered stable.
+
+%prep
+%autosetup -S git -n %{name}-%{version}%{prerelease} -a 3
+ln NOTICE LICENSE
+
+# Take the execute bit off of documentation.
+chmod -x doc/ccapi/*.html
+
+# Generate an FDS-compatible LDIF file.
+inldif=src/plugins/kdb/ldap/libkdb_ldap/kerberos.ldif
+cat > '60kerberos.ldif' << EOF
+# This is a variation on kerberos.ldif which 389 Directory Server will like.
+dn: cn=schema
+EOF
+egrep -iv '(^$|^dn:|^changetype:|^add:)' $inldif | \
+sed -r 's,^		,                ,g' | \
+sed -r 's,^	,        ,g' >> 60kerberos.ldif
+touch -r $inldif 60kerberos.ldif
+
+# Rebuild the configure scripts.
+pushd src
+autoreconf -fiv
+popd
+
+# Mess with some of the default ports that we use for testing, so that multiple
+# builds going on the same host don't step on each other.
+cfg="src/kadmin/testing/proto/kdc.conf.proto \
+     src/kadmin/testing/proto/krb5.conf.proto \
+     src/lib/kadm5/unit-test/api.current/init-v2.exp \
+     src/util/k5test.py"
+LONG_BIT=`getconf LONG_BIT`
+PORT=`expr 61000 + $LONG_BIT - 48`
+sed -i -e s,61000,`expr "$PORT" + 0`,g $cfg
+PORT=`expr 1750 + $LONG_BIT - 48`
+sed -i -e s,1750,`expr "$PORT" + 0`,g $cfg
+sed -i -e s,1751,`expr "$PORT" + 1`,g $cfg
+sed -i -e s,1752,`expr "$PORT" + 2`,g $cfg
+PORT=`expr 8888 + $LONG_BIT - 48`
+sed -i -e s,8888,`expr "$PORT" - 0`,g $cfg
+sed -i -e s,8887,`expr "$PORT" - 1`,g $cfg
+sed -i -e s,8886,`expr "$PORT" - 2`,g $cfg
+PORT=`expr 7777 + $LONG_BIT - 48`
+sed -i -e s,7777,`expr "$PORT" + 0`,g $cfg
+sed -i -e s,7778,`expr "$PORT" + 1`,g $cfg
+
+%build
+# Go ahead and supply tcl info, because configure doesn't know how to find it.
+source %{_libdir}/tclConfig.sh
+pushd src
+
+# Set this so that configure will have a value even if the current version of
+# autoconf doesn't set one.
+export runstatedir=%{_localstatedir}/run
+# Work out the CFLAGS and CPPFLAGS which we intend to use.
+INCLUDES=-I%{_includedir}/et
+CFLAGS="`echo $RPM_OPT_FLAGS $DEFINES $INCLUDES -fPIC -fno-strict-aliasing -fstack-protector-all`"
+CPPFLAGS="`echo $DEFINES $INCLUDES`"
+%configure \
+	CC="%{__cc}" \
+	CFLAGS="$CFLAGS" \
+	CPPFLAGS="$CPPFLAGS" \
+	SS_LIB="-lss" \
+	--enable-shared \
+	--localstatedir=%{_var}/kerberos \
+	--disable-rpath \
+	--without-krb5-config \
+	--with-system-et \
+	--with-system-ss \
+	--with-netlib=-lresolv \
+	--with-tcl \
+	--enable-dns-for-realm \
+	--with-ldap \
+%if %{WITH_DIRSRV}
+	--with-dirsrv-account-locking \
+%endif
+	--enable-pkinit \
+	--with-crypto-impl=openssl \
+	--with-pkinit-crypto-impl=openssl \
+	--with-tls-impl=openssl \
+	--with-system-verto \
+	--with-pam \
+	--with-selinux \
+	--with-prng-alg=os \
+	|| (cat config.log; exit 1)
+# Now build it.
+make
+popd
+
+# Sanity check the KDC_RUN_DIR.
+configured_kdcrundir=`grep KDC_RUN_DIR src/include/osconf.h | awk '{print $NF}'`
+configured_kdcrundir=`eval echo $configured_kdcrundir`
+if test "$configured_kdcrundir" != %{_localstatedir}/run/krb5kdc ; then
+	exit 1
+fi
+
+# Build the docs.
+make -C src/doc paths.py version.py
+cp src/doc/paths.py doc/
+mkdir -p build-man build-html build-pdf
+sphinx-build -a -b man   -t pathsubs doc build-man
+sphinx-build -a -b html  -t pathsubs doc build-html
+rm -fr build-html/_sources
+sphinx-build -a -b latex -t pathsubs doc build-pdf
+# Build the PDFs if we didn't have pre-built ones.
+for pdf in admin appdev basic build plugindev user ; do
+	test -s build-pdf/$pdf.pdf || make -C build-pdf
+done
+# new krb5-%{version}-pdf
+tar -cf "krb5-%{version}%{prerelease}-pdfs.tar.new" build-pdf/*.pdf
+
+# We need to cut off any access to locally-running nameservers, too.
+%{__cc} -fPIC -shared -o noport.so -Wall -Wextra $RPM_SOURCE_DIR/noport.c
+
+%check
+%ifarch i686
+# i686 isn't an installable arch - it's only for multilib.  So don't
+# bother testing the client or server code.  (Library code is already
+# not testable in brew/koji/copr.)
+exit 0
+%endif
+
+mkdir nss_wrapper
+
+# Set things up to use the test wrappers.
+export NSS_WRAPPER_HOSTNAME=test.example.com
+export NSS_WRAPPER_HOSTS="$PWD/nss_wrapper/fakehosts"
+echo "127.0.0.1 $NSS_WRAPPER_HOSTNAME localhost" > $NSS_WRAPPER_HOSTS
+export NOPORT='53,111'
+export SOCKET_WRAPPER_DIR="$PWD/sockets" ; mkdir -p $SOCKET_WRAPPER_DIR
+export LD_PRELOAD="$PWD/noport.so:libnss_wrapper.so:libsocket_wrapper.so"
+
+# ugh.  COPR doesn't expose the keyring, so try to cope.
+%if 0%{?copr_username:1}
+%global keyctl :
+%else
+%global keyctl keyctl
+%endif
+
+# Run the test suite. We can't actually run the whole thing in the build
+# system, but we can at least run more than we used to.  The build system may
+# give us a revoked session keyring, so run affected tests with a new one.
+make -C src runenv.py
+: make -C src check TMPDIR=%{_tmppath}
+%{keyctl} session - make -C src/lib check TMPDIR=%{_tmppath} OFFLINE=yes
+make -C src/kdc check TMPDIR=%{_tmppath}
+%{keyctl} session - make -C src/appl check TMPDIR=%{_tmppath}
+make -C src/clients check TMPDIR=%{_tmppath}
+%{keyctl} session - make -C src/util check TMPDIR=%{_tmppath}
+
+%install
+[ "$RPM_BUILD_ROOT" != '/' ] && rm -rf -- "$RPM_BUILD_ROOT"
+
+# Sample KDC config files (bundled kdc.conf and kadm5.acl).
+mkdir -p $RPM_BUILD_ROOT%{_var}/kerberos/krb5kdc
+install -pm 600 %{SOURCE10} $RPM_BUILD_ROOT%{_var}/kerberos/krb5kdc/
+install -pm 600 %{SOURCE11} $RPM_BUILD_ROOT%{_var}/kerberos/krb5kdc/
+
+# Where per-user keytabs live by default.
+mkdir -p $RPM_BUILD_ROOT%{_var}/kerberos/krb5/user
+
+# Default configuration file for everything.
+mkdir -p $RPM_BUILD_ROOT/etc
+install -pm 644 %{SOURCE6} $RPM_BUILD_ROOT/etc/krb5.conf
+
+# Default include on this directory
+mkdir -p $RPM_BUILD_ROOT/etc/krb5.conf.d
+ln -sv /etc/crypto-policies/back-ends/krb5.config $RPM_BUILD_ROOT/etc/krb5.conf.d/crypto-policies
+
+# Parent of configuration file for list of loadable GSS mechs ("mechs").  This
+# location is not relative to sysconfdir, but is hard-coded in g_initialize.c.
+mkdir -m 755 -p $RPM_BUILD_ROOT/etc/gss
+# Parent of groups of configuration files for a list of loadable GSS mechs
+# ("mechs").  This location is not relative to sysconfdir, and is also
+# hard-coded in g_initialize.c.
+mkdir -m 755 -p $RPM_BUILD_ROOT/etc/gss/mech.d
+
+# If the default configuration needs to start specifying a default cache
+# location, add it now, then fixup the timestamp so that it looks the same.
+%if 0%{?configure_default_ccache_name}
+export DEFCCNAME="%{configured_default_ccache_name}"
+awk '{print}
+     /^#    default_realm/{print "    default_ccache_name =", ENVIRON["DEFCCNAME"]}' \
+     %{SOURCE6} > $RPM_BUILD_ROOT/etc/krb5.conf
+touch -r %{SOURCE6} $RPM_BUILD_ROOT/etc/krb5.conf
+grep default_ccache_name $RPM_BUILD_ROOT/etc/krb5.conf
+%endif
+
+# Server init scripts (krb5kdc,kadmind,kpropd) and their sysconfig files.
+mkdir -p $RPM_BUILD_ROOT%{_unitdir}
+for unit in \
+	%{SOURCE5}\
+	%{SOURCE4} \
+	%{SOURCE2} ; do
+	# In the past, the init script was supposed to be named after the
+	# service that the started daemon provided.  Changing their names
+	# is an upgrade-time problem I'm in no hurry to deal with.
+	install -pm 644 ${unit} $RPM_BUILD_ROOT%{_unitdir}
+done
+mkdir -p $RPM_BUILD_ROOT/%{_tmpfilesdir}
+install -pm 644 %{SOURCE39} $RPM_BUILD_ROOT/%{_tmpfilesdir}/
+mkdir -p $RPM_BUILD_ROOT/%{_localstatedir}/run/krb5kdc
+
+mkdir -p $RPM_BUILD_ROOT/etc/sysconfig
+for sysconfig in \
+	%{SOURCE19}\
+	%{SOURCE20}\
+	%{SOURCE21} ; do
+	install -pm 644 ${sysconfig} \
+	$RPM_BUILD_ROOT/etc/sysconfig/`basename ${sysconfig} .sysconfig`
+done
+
+# logrotate configuration files
+mkdir -p $RPM_BUILD_ROOT/etc/logrotate.d/
+for logrotate in \
+	%{SOURCE33} \
+	%{SOURCE34} ; do
+	install -pm 644 ${logrotate} \
+	$RPM_BUILD_ROOT/etc/logrotate.d/`basename ${logrotate} .logrotate`
+done
+
+# PAM configuration files.
+mkdir -p $RPM_BUILD_ROOT/etc/pam.d/
+for pam in \
+	%{SOURCE29} ; do
+	install -pm 644 ${pam} \
+	$RPM_BUILD_ROOT/etc/pam.d/`basename ${pam} .pamd`
+done
+
+# Plug-in directories.
+install -pdm 755 $RPM_BUILD_ROOT/%{_libdir}/krb5/plugins/preauth
+install -pdm 755 $RPM_BUILD_ROOT/%{_libdir}/krb5/plugins/kdb
+install -pdm 755 $RPM_BUILD_ROOT/%{_libdir}/krb5/plugins/authdata
+
+# The rest of the binaries, headers, libraries, and docs.
+make -C src DESTDIR=$RPM_BUILD_ROOT EXAMPLEDIR=%{libsdocdir}/examples install
+
+# Munge krb5-config yet again.  This is totally wrong for 64-bit, but chunks
+# of the buildconf patch already conspire to strip out /usr/<anything> from the
+# list of link flags, and it helps prevent file conflicts on multilib systems.
+sed -r -i -e 's|^libdir=/usr/lib(64)?$|libdir=/usr/lib|g' $RPM_BUILD_ROOT%{_bindir}/krb5-config
+
+# Temporay workaround for krb5-config reading too much from LDFLAGS.
+# Upstream: http://krbdev.mit.edu/rt/Ticket/Display.html?id=8159
+sed -r -i -e "s/-specs=\/.+?\/redhat-hardened-ld//g" $RPM_BUILD_ROOT%{_bindir}/krb5-config
+
+if [[ "$(< $RPM_BUILD_ROOT%{_bindir}/krb5-config )" == *redhat-hardened-ld* ]] ; then
+	printf '# redhat-hardened-ld for krb5-config failed' 1>&2
+	exit 1
+fi
+
+# Install processed man pages.
+for section in 1 5 8 ; do
+	install -m 644 build-man/*.${section} \
+		       $RPM_BUILD_ROOT/%{_mandir}/man${section}/
+done
+
+# This script just tells you to send bug reports to krb5-bugs@mit.edu, but
+# since we don't have a man page for it, just drop it.
+rm -- "$RPM_BUILD_ROOT/%{_sbindir}/krb5-send-pr"
+
+# These files are already packaged elsewhere
+rm -- "$RPM_BUILD_ROOT/%{_docdir}/krb5-libs/examples/kdc.conf"
+rm -- "$RPM_BUILD_ROOT/%{_docdir}/krb5-libs/examples/krb5.conf"
+rm -- "$RPM_BUILD_ROOT/%{_docdir}/krb5-libs/examples/services.append"
+
+# This is only needed for tests
+rm -- "$RPM_BUILD_ROOT/%{_libdir}/krb5/plugins/preauth/test.so"
+
+%find_lang %{gettext_domain}
+
+%ldconfig_scriptlets libs
+
+%triggerun libs -- krb5-libs < 1.15.1-5
+if ! grep -q 'includedir /etc/krb5.conf.d' /etc/krb5.conf ; then
+    sed -i '1i # To opt out of the system crypto-policies configuration of krb5, remove the\n# symlink at /etc/krb5.conf.d/crypto-policies which will not be recreated.\nincludedir /etc/krb5.conf.d/\n' /etc/krb5.conf
+fi
+exit 0
+
+%ldconfig_scriptlets server-ldap
+
+%post server
+%systemd_post krb5kdc.service kadmin.service kprop.service
+# assert sanity.  A cleaner solution probably exists but it is opaque
+/bin/systemctl daemon-reload
+exit 0
+
+%preun server
+%systemd_preun krb5kdc.service kadmin.service kprop.service
+exit 0
+
+%postun server
+%systemd_postun_with_restart krb5kdc.service kadmin.service kprop.service
+exit 0
+
+%ldconfig_scriptlets -n libkadm5
+
+%files workstation
+%doc src/config-files/services.append
+%doc src/config-files/krb5.conf
+%doc build-html/*
+%doc build-pdf/user.pdf build-pdf/basic.pdf
+%attr(0755,root,root) %doc src/config-files/convert-config-files
+
+# Clients of the KDC, including tools you're likely to need if you're running
+# app servers other than those built from this source package.
+%{_bindir}/kdestroy
+%{_mandir}/man1/kdestroy.1*
+%{_bindir}/kinit
+%{_mandir}/man1/kinit.1*
+%{_bindir}/klist
+%{_mandir}/man1/klist.1*
+%{_bindir}/kpasswd
+%{_mandir}/man1/kpasswd.1*
+%{_bindir}/kswitch
+%{_mandir}/man1/kswitch.1*
+
+%{_bindir}/kvno
+%{_mandir}/man1/kvno.1*
+%{_bindir}/kadmin
+%{_mandir}/man1/kadmin.1*
+%{_bindir}/k5srvutil
+%{_mandir}/man1/k5srvutil.1*
+%{_bindir}/ktutil
+%{_mandir}/man1/ktutil.1*
+
+# Doesn't really fit anywhere else.
+%attr(4755,root,root) %{_bindir}/ksu
+%{_mandir}/man1/ksu.1*
+%config(noreplace) /etc/pam.d/ksu
+
+%files server
+%docdir %{_mandir}
+%doc build-pdf/admin.pdf build-pdf/build.pdf
+%doc src/config-files/kdc.conf
+%{_unitdir}/krb5kdc.service
+%{_unitdir}/kadmin.service
+%{_unitdir}/kprop.service
+%{_tmpfilesdir}/krb5-krb5kdc.conf
+%dir %{_localstatedir}/run/krb5kdc
+%config(noreplace) /etc/sysconfig/krb5kdc
+%config(noreplace) /etc/sysconfig/kadmin
+%config(noreplace) /etc/sysconfig/kprop
+%config(noreplace) /etc/logrotate.d/krb5kdc
+%config(noreplace) /etc/logrotate.d/kadmind
+
+%dir %{_var}/kerberos
+%dir %{_var}/kerberos/krb5kdc
+%config(noreplace) %{_var}/kerberos/krb5kdc/kdc.conf
+%config(noreplace) %{_var}/kerberos/krb5kdc/kadm5.acl
+
+%dir %{_libdir}/krb5
+%dir %{_libdir}/krb5/plugins
+%dir %{_libdir}/krb5/plugins/kdb
+%dir %{_libdir}/krb5/plugins/preauth
+%dir %{_libdir}/krb5/plugins/authdata
+%{_libdir}/krb5/plugins/preauth/otp.so
+%{_libdir}/krb5/plugins/kdb/db2.so
+
+# KDC binaries and configuration.
+%{_mandir}/man5/kadm5.acl.5*
+%{_mandir}/man5/kdc.conf.5*
+%{_sbindir}/kadmin.local
+%{_mandir}/man8/kadmin.local.8*
+%{_sbindir}/kadmind
+%{_mandir}/man8/kadmind.8*
+%{_sbindir}/kdb5_util
+%{_mandir}/man8/kdb5_util.8*
+%{_sbindir}/kprop
+%{_mandir}/man8/kprop.8*
+%{_sbindir}/kpropd
+%{_mandir}/man8/kpropd.8*
+%{_sbindir}/kproplog
+%{_mandir}/man8/kproplog.8*
+%{_sbindir}/krb5kdc
+%{_mandir}/man8/krb5kdc.8*
+
+# This is here for people who want to test their server.  It was formerly also
+# included in -devel.
+%{_bindir}/sclient
+%{_mandir}/man1/sclient.1*
+%{_sbindir}/sserver
+%{_mandir}/man8/sserver.8*
+
+%files server-ldap
+%docdir %{_mandir}
+%doc src/plugins/kdb/ldap/libkdb_ldap/kerberos.ldif
+%doc src/plugins/kdb/ldap/libkdb_ldap/kerberos.schema
+%doc 60kerberos.ldif
+%dir %{_libdir}/krb5
+%dir %{_libdir}/krb5/plugins
+%dir %{_libdir}/krb5/plugins/kdb
+%{_libdir}/krb5/plugins/kdb/kldap.so
+%{_libdir}/libkdb_ldap.so
+%{_libdir}/libkdb_ldap.so.*
+%{_mandir}/man8/kdb5_ldap_util.8.gz
+%{_sbindir}/kdb5_ldap_util
+
+%files libs -f %{gettext_domain}.lang
+%doc README NOTICE
+%{!?_licensedir:%global license %%doc}
+%license LICENSE
+%docdir %{_mandir}
+# These are hard-coded, not-dependent-on-the-configure-script paths.
+%dir /etc/gss
+%dir /etc/gss/mech.d
+%dir /etc/krb5.conf.d
+%config(noreplace) /etc/krb5.conf
+%config(noreplace) /etc/krb5.conf.d/crypto-policies
+/%{_mandir}/man5/.k5identity.5*
+/%{_mandir}/man5/.k5login.5*
+/%{_mandir}/man5/k5identity.5*
+/%{_mandir}/man5/k5login.5*
+/%{_mandir}/man5/krb5.conf.5*
+%{_libdir}/libgssapi_krb5.so.*
+%{_libdir}/libgssrpc.so.*
+%{_libdir}/libk5crypto.so.*
+%{_libdir}/libkdb5.so.*
+%{_libdir}/libkrad.so.*
+%{_libdir}/libkrb5.so.*
+%{_libdir}/libkrb5support.so.*
+%dir %{_libdir}/krb5
+%dir %{_libdir}/krb5/plugins
+%dir %{_libdir}/krb5/plugins/*
+%{_libdir}/krb5/plugins/tls/k5tls.so
+%{_libdir}/krb5/plugins/preauth/spake.so
+%dir %{_var}/kerberos
+%dir %{_var}/kerberos/krb5
+%dir %{_var}/kerberos/krb5/user
+
+%files pkinit
+%dir %{_libdir}/krb5
+%dir %{_libdir}/krb5/plugins
+%dir %{_libdir}/krb5/plugins/preauth
+%{_libdir}/krb5/plugins/preauth/pkinit.so
+
+%files devel
+%docdir %{_mandir}
+%doc build-pdf/appdev.pdf build-pdf/plugindev.pdf
+
+%{_includedir}/*
+%{_libdir}/libgssapi_krb5.so
+%{_libdir}/libgssrpc.so
+%{_libdir}/libk5crypto.so
+%{_libdir}/libkdb5.so
+%{_libdir}/libkrad.so
+%{_libdir}/libkrb5.so
+%{_libdir}/libkrb5support.so
+%{_libdir}/pkgconfig/*
+
+%{_bindir}/krb5-config
+%{_mandir}/man1/krb5-config.1*
+
+# Protocol test clients.
+%{_bindir}/sim_client
+%{_bindir}/gss-client
+%{_bindir}/uuclient
+
+# Protocol test servers.
+%{_sbindir}/sim_server
+%{_sbindir}/gss-server
+%{_sbindir}/uuserver
+
+%files -n libkadm5
+%{_libdir}/libkadm5clnt.so
+%{_libdir}/libkadm5clnt_mit.so
+%{_libdir}/libkadm5srv.so
+%{_libdir}/libkadm5srv_mit.so
+%{_libdir}/libkadm5clnt_mit.so.*
+%{_libdir}/libkadm5srv_mit.so.*
+
+%changelog
+* Thu Feb 07 2019 Robbie Harwood <rharwood@redhat.com> - 1.16.1-22
+- Remove incorrect KDC assertion
+- Resolves: #1673016
+
+* Fri Feb 01 2019 Robbie Harwood <rharwood@redhat.com> - 1.16.1-21
+- Fix RC4 blocking in FIPS mode
+- Resolves: #1660222
+
+* Thu Dec 20 2018 Robbie Harwood <rharwood@redhat.com> - 1.16.1-20
+- Gain FIPS awareness
+- Resolves: #1660222
+
+* Wed Aug 01 2018 Robbie Harwood <rharwood@redhat.com> - 1.16.1-19
+- In FIPS mode, add plaintext fallback for RC4 usages and taint
+
+* Thu Jul 26 2018 Robbie Harwood <rharwood@redhat.com> - 1.16.1-18
+- Fix k5test prompts for Python 3
+
+* Thu Jul 19 2018 Robbie Harwood <rharwood@redhat.com> - 1.16.1-17
+- Remove outdated note in krb5kdc man page
+
+* Thu Jul 19 2018 Robbie Harwood <rharwood@redhat.com> - 1.16.1-16
+- Make krb5kdc -p affect TCP ports
+
+* Thu Jul 19 2018 Robbie Harwood <rharwood@redhat.com> - 1.16.1-15
+- Eliminate preprocessor-disabled dead code
+
+* Wed Jul 18 2018 Robbie Harwood <rharwood@redhat.com> - 1.16.1-14
+- Fix some broken tests for Python 3
+
+* Mon Jul 16 2018 Robbie Harwood <rharwood@redhat.com> - 1.16.1-13
+- Zap copy of secret in RC4 string-to-key
+
+* Thu Jul 12 2018 Robbie Harwood <rharwood@redhat.com> - 1.16.1-12
+- Convert Python tests to Python 3
+
+* Wed Jul 11 2018 Robbie Harwood <rharwood@redhat.com> - 1.16.1-11
+- Add build dependency on gcc
+
+* Tue Jul 10 2018 Robbie Harwood <rharwood@redhat.com> - 1.16.1-10
+- Use SHA-256 instead of MD5 for audit ticket IDs
+
+* Fri Jul 06 2018 Robbie Harwood <rharwood@redhat.com> - 1.16.1-9
+- Add BuildRequires on python2 so we can run tests at build-time
+
+* Fri Jul 06 2018 Robbie Harwood <rharwood@redhat.com> - 1.16.1-8
+- Explicitly look for python2 in configure.in
+
+* Thu Jun 14 2018 Robbie Harwood <rharwood@redhat.com> - 1.16.1-7
+- Add flag to disable encrypted timestamp on client
+
+* Thu Jun 14 2018 Robbie Harwood <rharwood@redhat.com> - 1.16.1-6
+- Switch to python3-sphinx for docs
+- Resolves: #1590928
+
+* Thu Jun 14 2018 Robbie Harwood <rharwood@redhat.com> - 1.16.1-5
+- Make docs build python3-compatible
+- Resolves: #1590928
+
+* Thu Jun 07 2018 Robbie Harwood <rharwood@redhat.com> - 1.16.1-4
+- Update includedir processing to match upstream
+
+* Fri Jun 01 2018 Robbie Harwood <rharwood@redhat.com> - 1.16.1-3
+- Log when non-root ksu authorization fails
+- Resolves: #1575771
+
+* Fri May 04 2018 Robbie Harwood <rharwood@redhat.com> - 1.16.1-2
+- Remove "-nodes" option from make-certs scripts
+
+* Fri May 04 2018 Robbie Harwood <rharwood@redhat.com> - 1.16.1-1
+- New upstream release - 1.16.1
+
+* Thu May 03 2018 Robbie Harwood <rharwood@redhat.com> - 1.16-27
+- Fix configuration of default ccache name to match file indentation
+
+* Mon Apr 30 2018 Robbie Harwood <rharwood@redhat.com> - 1.16-26
+- Set error message on KCM get_princ failure
+
+* Mon Apr 30 2018 Robbie Harwood <rharwood@redhat.com> - 1.16-25
+- Set error message on KCM get_princ failure
+
+* Tue Apr 24 2018 Robbie Harwood <rharwood@redhat.com> - 1.16-24
+- Fix KDC null dereference on large TGS replies
+
+* Mon Apr 23 2018 Robbie Harwood <rharwood@redhat.com> - 1.16-23
+- Explicitly use openssl rather than builtin crypto
+- Resolves: #1570910
+
+* Tue Apr 17 2018 Robbie Harwood <rharwood@redhat.com> - 1.16-22
+- Merge duplicate subsections in profile library
+
+* Mon Apr 09 2018 Robbie Harwood <rharwood@redhat.com> - 1.16-21
+- Restrict pre-authentication fallback cases
+
+* Tue Apr 03 2018 Robbie Harwood <rharwood@redhat.com> - 1.16-20
+- Be more careful asking for AS key in SPAKE client
+
+* Mon Apr 02 2018 Robbie Harwood <rharwood@redhat.com> - 1.16-19
+- Zap data when freeing krb5_spake_factor
+
+* Thu Mar 29 2018 Robbie Harwood <rharwood@redhat.com> - 1.16-18
+- Continue after KRB5_CC_END in KCM cache iteration
+
+* Tue Mar 27 2018 Robbie Harwood <rharwood@redhat.com> - 1.16-17
+- Fix SPAKE memory leak
+
+* Tue Mar 27 2018 Robbie Harwood <rharwood@redhat.com> - 1.16-16
+- Fix gitignore problem with previous patchset
+
+* Tue Mar 27 2018 Robbie Harwood <rharwood@redhat.com> - 1.16-15
+- Add SPAKE support
+- Improve protections on internal sensitive buffers
+- Improve internal hex encoding/decoding
+
+* Tue Mar 20 2018 Robbie Harwood <rharwood@redhat.com> - 1.16-14
+- Fix problem with ccache_name logic in previous build
+
+* Tue Mar 20 2018 Robbie Harwood <rharwood@redhat.com> - 1.16-13
+- Add pkinit_anchors default value to krb5.conf
+- Reindent krb5.conf to not be terrible
+
+* Tue Mar 20 2018 Robbie Harwood <rharwood@redhat.com> - 1.16-12
+- Log preauth names in trace output
+- Misc bugfixes from upstream
+
+* Mon Mar 19 2018 Robbie Harwood <rharwood@redhat.com> - 1.16-11
+- Add PKINIT KDC support for freshness token
+
+* Wed Mar 14 2018 Robbie Harwood <rharwood@redhat.com> - 1.16-10
+- Exit with status 0 from kadmind
+
+* Tue Mar 13 2018 Robbie Harwood <rharwood@redhat.com> - 1.16-9
+- Fix hex conversion of PKINIT certid strings
+
+* Wed Mar 07 2018 Robbie Harwood <rharwood@redhat.com> - 1.16-8
+- Fix capaths "." values on client
+- Resolves: 1551099
+
+* Tue Feb 13 2018 Robbie Harwood <rharwood@redhat.com> - 1.16-7
+- Fix flaws in LDAP DN checking
+- CVE-2018-5729, CVE-2018-5730
+
+* Mon Feb 12 2018 Robbie Harwood <rharwood@redhat.com> - 1.16-6
+- Fix a leak in the previous commit
+- Restore dist macro that was accidentally removed
+- Resolves: #1540939
+
+* Wed Feb 07 2018 Fedora Release Engineering <releng@fedoraproject.org> - 1.16-5
+- Rebuilt for https://fedoraproject.org/wiki/Fedora_28_Mass_Rebuild
+
+* Sat Feb 03 2018 Igor Gnatenko <ignatenkobrain@fedoraproject.org> - 1.16-4
+- Switch to %%ldconfig_scriptlets
+
+* Mon Jan 29 2018 Robbie Harwood <rharwood@redhat.com> - 1.16-3
+- Process included directories in alphabetical order
+
+* Tue Dec 12 2017 Robbie Harwood <rharwood@redhat.com> - 1.16-2
+- Fix network service dependencies
+- Resolves: #1525230
+
+* Wed Dec 06 2017 Robbie Harwood <rharwood@redhat.com> - 1.16-1
+- New upstream release (1.16)
+- No changes from beta2
+
+* Mon Nov 27 2017 Robbie Harwood <rharwood@redhat.com> - 1.16-0.beta2.1
+- New upstream prerelease (1.16-beta2)
+
+* Tue Oct 24 2017 Robbie Harwood <rharwood@redhat.com> - 1.16-0.beta1.4
+- Fix CVE-2017-15088 (Buffer overflow in get_matching_data())
+
+* Mon Oct 23 2017 Robbie Harwood <rharwood@redhat.com> - 1.16-0.beta1.3
+- Drop dependency on python2-pyrad (dead upstream, broken with new python)
+
+* Mon Oct 09 2017 Robbie Harwood <rharwood@redhat.com> - 1.16-0.beta1.2
+- Actually bump kdbversion like I was supposed to
+
+* Thu Oct 05 2017 Robbie Harwood <rharwood@redhat.com> - 1.16-0.beta1.1
+- New upstream prerelease (1.16-beta1)
+
+* Thu Sep 28 2017 Robbie Harwood <rharwood@redhat.com> - 1.15.2-2
+- Add German translation
+
+* Mon Sep 25 2017 Robbie Harwood <rharwood@redhat.com> - 1.15.2-1
+- New upstream release - krb5-1.15.2
+- Adjust patches as appropriate
+
+* Wed Sep 06 2017 Robbie Harwood <rharwood@redhat.com> - 1.15.1-28
+- Save other programs from worrying about CVE-2017-11462
+- Resolves: #1488873
+- Resolves: #1488874
+
+* Tue Sep 05 2017 Robbie Harwood <rharwood@redhat.com> - 1.15.1-27
+- Add hostname-based ccselect module
+- Resolves: #1463665
+
+* Tue Sep 05 2017 Robbie Harwood <rharwood@redhat.com> - 1.15.1-26
+- Backport upstream certauth EKU fixes
+
+* Fri Aug 25 2017 Robbie Harwood <rharwood@redhat.com> - 1.15.1-25
+- Backport certauth eku security fix
+
+* Mon Aug 21 2017 Robbie Harwood <rharwood@redhat.com> - 1.15.1-24
+- Backport kdc policy plugin, but this time with dependencies
+
+* Mon Aug 21 2017 Robbie Harwood <rharwood@redhat.com> - 1.15.1-23
+- Backport kdcpolicy interface
+
+* Wed Aug 16 2017 Robbie Harwood <rharwood@redhat.com> - 1.15.1-22
+
+* Mon Aug 07 2017 Robbie Harwood <rharwood@redhat.com> - 1.15.1-21
+- Display an error message if ocsp pkinit is requested
+
+* Wed Aug 02 2017 Robbie Harwood <rharwood@redhat.com> - 1.15.1-20
+- Disable dns_canonicalize_hostname.  This may break some setups.
+
+* Wed Aug 02 2017 Robbie Harwood <rharwood@redhat.com> - 1.15.1-19
+- Re-enable test suite on ppc64le (no other changes)
+
+* Wed Jul 26 2017 Fedora Release Engineering <releng@fedoraproject.org> - 1.15.1-18
+- Rebuilt for https://fedoraproject.org/wiki/Fedora_27_Mass_Rebuild
+
+* Thu Jul 20 2017 Robbie Harwood <rharwood@redhat.com> - 1.15.1-17
+- Fix CVE-2017-11368 (remote triggerable assertion failure)
+
+* Wed Jul 19 2017 Robbie Harwood <rharwood@redhat.com> - 1.15.1-16
+- Explicitly require python2 packages
+
+* Wed Jul 19 2017 Robbie Harwood <rharwood@redhat.com> - 1.15.1-15
+- Add support to query the SSF of a context
+- Pick up rename of perl dependency
+
+* Thu Jul 06 2017 Robbie Harwood <rharwood@redhat.com> - 1.15.1-14
+-  Fix leaks in gss_inquire_cred_by_oid()
+
+* Mon Jun 26 2017 Robbie Harwood <rharwood@redhat.com> - 1.15.1-13
+- Fix arch name (ppc64le, not ppc64el)
+- Related-to: #1464381
+
+* Mon Jun 26 2017 Robbie Harwood <rharwood@redhat.com> - 1.15.1-12
+- Skip test suite on ppc64el
+- Related-to: #1464381
+
+* Fri Jun 23 2017 Robbie Harwood <rharwood@redhat.com> - 1.15.1-11
+- Include more test suite changes from upstream
+- Resolves: #1464381
+
+* Wed Jun 07 2017 Robbie Harwood <rharwood@redhat.com> - 1.15.1-10
+- Fix custom build with -DDEBUG
+
+* Wed May 24 2017 Robbie Harwood <rharwood@redhat.com> - 1.15.1-9
+- Use standard trigger logic for krb5 snippet
+
+* Fri Apr 28 2017 Robbie Harwood <rharwood@redhat.com> - 1.15.1-8
+- Add kprop service env config file
+
+* Wed Apr 19 2017 Robbie Harwood <rharwood@redhat.com> - 1.15.1-7
+- Update backports of certauth and corresponding test
+
+* Thu Apr 13 2017 Robbie Harwood <rharwood@redhat.com> - 1.15.1-6
+- Include fixes for previous commit
+- Resolves: #1433083
+
+* Thu Apr 13 2017 Robbie Harwood <rharwood@redhat.com> - 1.15.1-5
+- Automatically add includedir where not present
+- Try removing sleep statement to see if it is still needed
+- Resolves: #1433083
+
+* Fri Apr 07 2017 Robbie Harwood <rharwood@redhat.com> - 1.15.1-4
+- Fix use of enterprise principals with forwarding
+
+* Wed Mar 22 2017 Robbie Harwood <rharwood@redhat.com> - 1.15.1-3
+- Backport certauth plugin and related pkinit changes
+
+* Tue Mar 07 2017 Robbie Harwood <rharwood@redhat.com> - 1.15.1-2
+- Remove duplication between subpackages
+- Resolves: #1250228
+
+* Fri Mar 03 2017 Robbie Harwood <rharwood@redhat.com> - 1.15.1-1
+- New upstream release - 1.15.1
+
+* Wed Mar 01 2017 Robbie Harwood <rharwood@redhat.com> - 1.15-9
+- Patch build by disabling failing test; will fix properly soon
+
+* Fri Feb 17 2017 Robbie Harwood <rharwood@redhat.com> - 1.15-8
+- Hammer refresh around transient rawhide issue
+
+* Fri Feb 17 2017 Robbie Harwood <rharwood@redhat.com> - 1.15-7
+- Backport fix for GSSAPI fallback realm
+
+* Tue Feb 07 2017 Robbie Harwood <rharwood@redhat.com> - 1.15-6
+- Move krb5-kdb-version provides from -libs to -devel
+
+* Fri Jan 20 2017 Robbie Harwood <rharwood@redhat.com> - 1.15-5
+- Add free hook to KDB; increments KDB version
+- Add KDB version flag
+
+* Mon Dec 05 2016 Robbie Harwood <rharwood@redhat.com> - 1.15-4
+- New upstream release
+
+* Wed Nov 16 2016 Robbie Harwood <rharwood@redhat.com> - 1.15-beta2-3
+- New upstream release
+
+* Thu Nov 10 2016 Robbie Harwood <rharwood@redhat.com> - 1.15-beta1-2
+- Ensure we can build with the new CFLAGS
+- Remove the git versioning in patches
+
+* Thu Oct 20 2016 Robbie Harwood <rharwood@redhat.com> - 1.15-beta1-1
+- New upstream release
+- Update selinux with RHEL hygene
+- Resolves: #1314096
+
+* Tue Oct 11 2016 Tomáš Mráz <tmraz@redhat.com> - 1.14.4-6
+- rebuild with OpenSSL 1.1.0, added backported upstream patch
+
+* Fri Sep 30 2016 Robbie Harwood <rharwood@redhat.com> - 1.14.4-5
+- Properly close krad sockets
+- Resolves: #1380836
+
+* Fri Sep 30 2016 Robbie Harwood <rharwood@redhat.com> - 1.14.4-4
+- Fix backward check in kprop.service
+
+* Fri Sep 30 2016 Robbie Harwood <rharwood@redhat.com> - 1.14.4-3
+- Switch to using autosetup macro.
+  - Patches come from git, so it is easiest to just make a git repo
+
+* Thu Sep 22 2016 Robbie Harwood <rharwood@redhat.com> - 1.14.4-2
+- Backport getrandom() support
+- Remove patch numbering
+
+* Mon Sep 19 2016 Robbie Harwood <rharwood@redhat.com> - 1.14.4-1
+- New upstream release
+- Update names and numbers to match external git
+
+* Mon Sep 19 2016 Robbie Harwood <rharwood@redhat.com> - 1.14.3-9
+- Add krb5_db_register_keytab
+- Resolves: #1376812
+
+* Mon Aug 29 2016 Robbie Harwood <rharwood@redhat.com> - 1.14.3-8
+- Use responder for non-preauth AS requests
+- Resolves: #1370622
+
+* Mon Aug 29 2016 Robbie Harwood <rharwood@redhat.com> - 1.14.3-7
+- Guess Samba client mutual flag using ap_option
+- Resolves: #1370980
+
+* Thu Aug 25 2016 Robbie Harwood <rharwood@redhat.com> - 1.14.3-6
+- Fix KDC return code and set prompt types for OTP client preauth
+- Resolves: #1370072
+
+* Mon Aug 15 2016 Robbie Harwood <rharwood@redhat.com> - 1.14.3-5
+- Turn OFD locks back on with glibc workaround
+- Resolves: #1274922
+
+* Wed Aug 10 2016 Robbie Harwood <rharwood@redhat.com> - 1.14.3-4
+- Fix use of KKDCPP with SNI
+- Resolves: #1365027
+
+* Fri Aug 05 2016 Robbie Harwood <rharwood@redhat.com> - 1.14.3-3
+- Make krb5-devel depend on libkadm5
+- Resolves: #1364487
+
+* Wed Aug 03 2016 Robbie Harwood <rharwood@redhat.com> - 1.14.3-2
+- Up-port a bunch of stuff from the el-7.3 cycle
+- Resolves: #1255450, #1314989
+
+* Mon Aug 01 2016 Robbie Harwood <rharwood@redhat.com> - 1.14.3-1
+- New upstream version 1.14.3
+
+* Thu Jul 28 2016 Robbie Harwood <rharwood@redhat.com> - 1.14.1-9
+- Fix CVE-2016-3120
+- Resolves: #1361051
+
+* Wed Jun 22 2016 Robbie Harwood <rharwood@redhat.com> - 1.14.1-8
+- Fix incorrect recv() size calculation in libkrad
+
+* Thu Jun 16 2016 Robbie Harwood <rharwood@redhat.com> - 1.14.1-7
+- Separate out the kadm5 libs
+
+* Fri May 27 2016 Robbie Harwood <rharwood@redhat.com> - 1.14.1-6
+- Fix setting of AS key in OTP preauth failure
+
+* Tue Apr 05 2016 Robbie Harwood <rharwood@redhat.com> - 1.14.1-5
+- Use the correct patches this time.
+- Resolves: #1321135
+
+* Mon Apr 04 2016 Robbie Harwood <rharwood@redhat.com> - 1.14.1-4
+- Add send/receive sendto_kdc hooks and corresponding tests
+- Resolves: #1321135
+
+* Fri Mar 18 2016 Robbie Harwood <rharwood@redhat.com> - 1.14.1-3
+- Fix CVE-2016-3119 (NULL deref in LDAP module)
+
+* Thu Mar 17 2016 Robbie Harwood <rharwood@redhat.com> - 1.14.1-2
+- Backport OID mech fix
+- Resolves: #1317609
+
+* Mon Feb 29 2016 Robbie Harwood <rharwood@redhat.com> - 1.14.1-1
+- New rawhide, new upstream version
+- Drop CVE patches
+- Rename fix_interposer.patch to acquire_cred_interposer.patch
+- Update acquire_cred_interposer.patch to apply to new source
+
+* Mon Feb 22 2016 Robbie Harwood <rharwood@redhat.com> - 1.14-23
+- Fix log file permissions patch with our selinux
+- Resolves: #1309421
+
+* Fri Feb 19 2016 Robbie Harwood <rharwood@redhat.com> - 1.14-22
+- Backport my interposer fixes from upstream
+  - Supersedes krb5-mechglue_inqure_attrs.patch
+
+* Tue Feb 16 2016 Robbie Harwood <rharwood@redhat.com> - 1.14-21
+- Adjust dependency on crypto-polices to be just the file we want
+- Patch courtesy of lslebodn
+- Resolves: #1308984
+
+* Thu Feb 04 2016 Fedora Release Engineering <releng@fedoraproject.org> - 1.14-20
+- Rebuilt for https://fedoraproject.org/wiki/Fedora_24_Mass_Rebuild
+
+* Thu Jan 28 2016 Robbie Harwood <rharwood@redhat.com> - 1.14-19
+- Replace _kadmin/_kprop with systemd macros
+- Remove traces of upstart from fedora package per policy
+- Resolves: #1290185
+
+* Wed Jan 27 2016 Robbie Harwood <rharwood@redhat.com> - 1.14-18
+- Fix CVE-2015-8629, CVE-2015-8630, CVE-2015-8631
+
+* Thu Jan 21 2016 Robbie Harwood <rharwood@redhat.com> - 1.14-17
+- Make krb5kdc.log not world-readable by default
+- Resolves: #1276484
+
+* Thu Jan 21 2016 Robbie Harwood <rharwood@redhat.com> - 1.14-16
+- Allow verification of attributes on krb5.conf
+
+* Wed Jan 20 2016 Robbie Harwood <rharwood@redhat.com> - 1.14-15
+- Use "new" systemd macros for service handling.  (Thanks vpavlin!)
+- Resolves: #850399
+
+* Wed Jan 20 2016 Robbie Harwood <rharwood@redhat.com> - 1.14-14
+- Remove WITH_NSS macro (always false)
+- Remove WITH_SYSTEMD macro (always true)
+- Remove WITH_LDAP macro (always true)
+- Remove WITH_OPENSSL macro (always true)
+
+* Fri Jan 08 2016 Robbie Harwood <rharwood@redhat.com> - 1.14-13
+- Backport fix for chrome crash in spnego_gss_inquire_context
+- Resolves: #1295893
+
+* Wed Dec 16 2015 Robbie Harwood <rharwood@redhat.com> - 1.14-12
+- Backport patch to fix mechglue for gss_inqure_attrs_for_mech()
+
+* Thu Dec 03 2015 Robbie Harwood <rharwood@redhat.com> - 1.14-11
+- Backport interposer fix (#1284985)
+- Drop workaround pwsize initialization patch (gcc has been fixed)
+
+* Tue Nov 24 2015 Robbie Harwood <rharwood@redhat.com> - 1.14-10
+- Fix FTBFS by no longer working around bug in nss_wrapper
+
+* Mon Nov 23 2015 Robbie Harwood <rharwood@redhat.com> - 1.14-9
+- Upstream release.  No actual change from beta, just version bump
+- Clean up unused parts of spec file
+
+* Mon Nov 16 2015 Robbie Harwood <rharwood@redhat.com> - 1.14-beta2-8
+- New upstream beta version
+
+* Wed Nov 04 2015 Robbie Harwood <rharwood@redhat.com> - 1.14-beta1-7
+- Patch CVE-2015-2698
+
+* Tue Oct 27 2015 Robbie Harwood <rharwood@redhat.com> - 1.14-beta1-6
+- Patch CVE-2015-2697, CVE-2015-2696, CVE-2015-2695
+
+* Thu Oct 22 2015 Robbie Harwood <rharwood@redhat.com> - 1.14-beta1-5
+- Ensure pwsize is initialized in chpass_util.c
+
+* Thu Oct 22 2015 Robbie Harwood <rharwood@redhat.com> - 1.14-beta1-4
+- Fix typo of crypto-policies file in previous version
+
+* Mon Oct 19 2015 Robbie Harwood <rharwood@redhat.com> - 1.14-beta1-3
+- Start using crypto-policies
+
+* Mon Oct 19 2015 Robbie Harwood <rharwood@redhat.com> - 1.14-beta1-2
+- TEMPORARILY disable usage of OFD locks as a workaround for x86
+
+* Thu Oct 15 2015 Robbie Harwood <rharwood@redhat.com> - 1.14-beta1-1
+- New upstream beta version
+
+* Thu Oct 08 2015 Robbie Harwood <rharwood@redhat.com> - 1.13.2-13
+- Work around KDC client prinicipal in referrals issue (#1259844)
+
+* Thu Oct 01 2015 Robbie Harwood <rharwood@redhat.com> - 1.13.2-12
+- Enable building with bad system /etc/krb5.conf
+
+* Wed Sep 23 2015 Robbie Harwood <rharwood@redhat.com> - 1.13.2-11
+- Drop dependency on pax, ksh
+- Remove support for fedora < 20
+
+* Wed Sep 23 2015 Robbie Harwood <rharwood@redhat.com> - 1.13.2-10
+- Nix /usr/share/krb5.conf.d to reduce complexity
+
+* Wed Sep 23 2015 Robbie Harwood <rharwood@redhat.com> - 1.13.2-9
+- Depend on crypto-policies which provides /etc/krb5.conf.d (#1225792)
+
+* Thu Sep 10 2015 Robbie Harwood <rharwood@redhat.com> - 1.13.2-8
+- Remove dependency on systemd-sysv which is no longer needed for fedora > 20
+  This also fixes a fail-to-build issue.
+- Miscalaneous spec cleanup fixes
+
+* Thu Sep 10 2015 Robbie Harwood <rharwood@redhat.com> - 1.13.2-7
+- Support config snippets in /etc/krb5.conf.d/ and /usr/share/krb5.conf.d/
+  (#1225792, #1146370, #1145808)
+
+* Thu Jun 25 2015 Roland Mainz <rmainz@redhat.com> - 1.13.2-6
+- Use system nss_wrapper and socket_wrapper for testing.
+  Patch by Andreas Schneider <asn@redhat.com>
+
+* Thu Jun 25 2015 Roland Mainz <rmainz@redhat.com> - 1.13.2-5
+- Remove Zanata test glue and related workarounds
+  - Bug #1234292 ("IPA server cannot be run in container due to incorrect /usr/sbin/_kadmind")
+  - Bug #1234326 ("krb5-server introduces new rpm dependency on ksh")
+
+* Thu Jun 18 2015 Roland Mainz <rmainz@redhat.com> - 1.13.2-4
+- Fix dependicy on binfmt.service
+
+* Wed Jun 17 2015 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 1.13.2-3
+- Rebuilt for https://fedoraproject.org/wiki/Fedora_23_Mass_Rebuild
+
+* Tue Jun 2 2015 Roland Mainz <rmainz@redhat.com> - 1.13.2-2
+- Add patch to fix Redhat Bug #1227542 ("[SELinux] AVC denials may appear
+  when kadmind starts"). The issue was caused by an unneeded |htons()|
+  which triggered SELinux AVC denials due to the "random" port usage.
+
+* Thu May 21 2015 Roland Mainz <rmainz@redhat.com> - 1.13.2-1
+- Add fix for RedHat Bug #1164304 ("Upstream unit tests loads
+  the installed shared libraries instead the ones from the build")
+
+* Thu May 14 2015 Roland Mainz <rmainz@redhat.com> - 1.13.2-0
+- Update to krb5-1.13.2
+  - drop patch for krb5-1.13.2-CVE_2015_2694_requires_preauth_bypass_in_PKINIT_enabled_KDC, fixed in krb5-1.13.2
+  - drop patch for krb5-1.12.1-CVE_2014_5355_fix_krb5_read_message_handling, fixed in krb5-1.13.2
+- Add script processing for upcoming Zanata l10n support
+- Minor spec cleanup
+
+* Mon May 4 2015 Roland Mainz <rmainz@redhat.com> - 1.13.1-4
+- fix for CVE-2015-2694 (#1216133) "requires_preauth bypass
+  in PKINIT-enabled KDC".
+  In MIT krb5 1.12 and later, when the KDC is configured with
+  PKINIT support, an unauthenticated remote attacker can
+  bypass the requires_preauth flag on a client principal and
+  obtain a ciphertext encrypted in the principal's long-term
+  key.  This ciphertext could be used to conduct an off-line
+  dictionary attack against the user's password.
+
+* Wed Mar 25 2015 Roland Mainz <rmainz@redhat.com> - 1.13.1-3
+- Add temporay workaround for RH bug #1204646 ("krb5-config
+  returns wrong -specs path") which modifies krb5-config post
+  build so that development of krb5 dependicies gets unstuck.
+  This MUST be removed before rawhide becomes F23 ...
+
+* Thu Mar 19 2015 Roland Mainz <rmainz@redhat.com> - 1.13.1-2
+- fix for CVE-2014-5355 (#1193939) "krb5: unauthenticated
+  denial of service in recvauth_common() and others"  
+
+* Fri Feb 13 2015 Roland Mainz <rmainz@redhat.com> - 1.13.1-1
+- Update to krb5-1.13.1
+  - drop patch for CVE_2014_5353_fix_LDAP_misused_policy_name_crash, fixed in krb5-1.13.1
+  - drop patch for kinit -C loops (MIT/krb5 bug #243), fixed in krb5-1.13.1
+  - drop patch for CVEs { 2014-9421, 2014-9422, 2014-9423, 2014-5352 }, fixed in krb5-1.13.1
+- Minor spec cleanup
+
+* Wed Feb 4 2015 Roland Mainz <rmainz@redhat.com> - 1.13-8
+- fix for CVE-2014-5352 (#1179856) "gss_process_context_token()
+  incorrectly frees context (MITKRB5-SA-2015-001)"
+- fix for CVE-2014-9421 (#1179857) "kadmind doubly frees partial
+  deserialization results (MITKRB5-SA-2015-001)"
+- fix for CVE-2014-9422 (#1179861) "kadmind incorrectly
+  validates server principal name (MITKRB5-SA-2015-001)"
+- fix for CVE-2014-9423 (#1179863) "libgssrpc server applications
+  leak uninitialized bytes (MITKRB5-SA-2015-001)"
+
+* Wed Feb 4 2015 Roland Mainz <rmainz@redhat.com> - 1.13-7
+- Remove "python-sphinx-latex" and "tar" from the build requirements
+  to fix build failures on F22 machines.
+- Minor spec cleanup
+
+* Mon Feb 02 2015 Nathaniel McCallum <npmccallum@redhat.com> - 1.13-6
+- Support KDC_ERR_MORE_PREAUTH_DATA_REQUIRED (RT#8063)
+
+* Mon Jan 26 2015 Roland Mainz <rmainz@redhat.com> - 1.13-5
+- fix for kinit -C loops (#1184629, MIT/krb5 issue 243, "Do not
+  loop on principal unknown errors").
+- Added "python-sphinx-latex" to the build requirements
+  to fix build failures on F22 machines.
+
+* Thu Dec 18 2014 Roland Mainz <rmainz@redhat.com> - 1.13-4
+- fix for CVE-2014-5354 (#1174546) "krb5: NULL pointer
+  dereference when using keyless entries"  
+
+* Wed Dec 17 2014 Roland Mainz <rmainz@redhat.com> - 1.13-3
+- fix for CVE-2014-5353 (#1174543) "Fix LDAP misused policy
+  name crash"  
+
+* Wed Oct 29 2014 Roland Mainz <rmainz@redhat.com> - 1.13-2
+- Bump 1%%{?dist} to 2%%{?dist} to workaround RPM sort issue
+  which would lead yum updates to treat the last alpha as newer
+  than the final version.  
+
+* Wed Oct 29 2014 Roland Mainz <rmainz@redhat.com> - 1.13-1
+- Update from krb5-1.13-alpha1 to final krb5-1.13
+- Removed patch for CVE-2014-5351 (#1145425) "krb5: current
+  keys returned when randomizing the keys for a service principal" -
+  now part of upstream sources
+- Use patch for glibc |eventfd()| prototype mismatch (#1147887) only
+  for Fedora > 20
+
+* Tue Sep 30 2014 Roland Mainz <rmainz@redhat.com> - 1.13-0.alpha1.3
+- fix build failure caused by change of prototype for glibc
+  |eventfd()| (#1147887)
+
+* Mon Sep 29 2014 Roland Mainz <rmainz@redhat.com> - 1.13-0.alpha1.3
+- fix for CVE-2014-5351 (#1145425) "krb5: current keys returned when
+  randomizing the keys for a service principal"
+
+* Mon Sep  8 2014 Nalin Dahyabhai <nalin@redhat.com> - 1.13-0.alpha1.3
+- fix the problem where the %%license file has been a dangling symlink
+
+* Tue Aug 26 2014 Nalin Dahyabhai <nalin@redhat.com> - 1.13-0.alpha1.2
+- kpropd hasn't bothered with -S since 1.11; stop trying to use that flag
+  in the systemd unit file
+
+* Fri Aug 22 2014 Nalin Dahyabhai <nalin@redhat.com> - 1.13-0.alpha1.1
+- update to 1.13 alpha1
+  - drop upstreamed and backported patches
+
+* Wed Aug 20 2014 Nalin Dahyabhai <nalin@redhat.com> - 1.12.2-3
+- pull in upstream fix for an incorrect check on the value returned by a
+  strdup() call (#1132062)
+
+* Sun Aug 17 2014 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 1.12.2-2
+- Rebuilt for https://fedoraproject.org/wiki/Fedora_21_22_Mass_Rebuild
+
+* Fri Aug 15 2014 Nalin Dahyabhai <nalin@redhat.com> - 1.12.2-1
+- update to 1.12.2
+  - drop patch for RT#7820, fixed in 1.12.2
+  - drop patch for #231147, fixed as RT#3277 in 1.12.2
+  - drop patch for RT#7818, fixed in 1.12.2
+  - drop patch for RT#7836, fixed in 1.12.2
+  - drop patch for RT#7858, fixed in 1.12.2
+  - drop patch for RT#7924, fixed in 1.12.2
+  - drop patch for RT#7926, fixed in 1.12.2
+  - drop patches for CVE-2014-4341/CVE-2014-4342, included in 1.12.2
+  - drop patch for CVE-2014-4343, included in 1.12.2
+  - drop patch for CVE-2014-4344, included in 1.12.2
+  - drop patch for CVE-2014-4345, included in 1.12.2
+- replace older proposed changes for ksu with backports of the changes
+  after review and merging upstream (#1015559, #1026099, #1118347)
+
+* Thu Aug  7 2014 Nalin Dahyabhai <nalin@redhat.com> - 1.12.1-14
+- incorporate fix for MITKRB5-SA-2014-001 (CVE-2014-4345)
+
+* Mon Jul 21 2014 Nalin Dahyabhai <nalin@redhat.com> - 1.12.1-13
+- gssapi: pull in upstream fix for a possible NULL dereference
+  in spnego (CVE-2014-4344)
+
+* Wed Jul 16 2014 Nalin Dahyabhai <nalin@redhat.com> - 1.12.1-12
+- gssapi: pull in proposed fix for a double free in initiators (David
+  Woodhouse, CVE-2014-4343, #1117963)
+
+* Sat Jul 12 2014 Tom Callaway <spot@fedoraproject.org> - 1.12.1-11
+- fix license handling
+
+* Mon Jul  7 2014 Nalin Dahyabhai <nalin@redhat.com> - 1.12.1-10
+- pull in fix for denial of service by injection of malformed GSSAPI tokens
+  (CVE-2014-4341, CVE-2014-4342, #1116181)
+
+* Tue Jun 24 2014 Nalin Dahyabhai <nalin@redhat.com> - 1.12.1-9
+- pull in changes from upstream which add processing of the contents of
+  /etc/gss/mech.d/*.conf when loading GSS modules (#1102839)
+
+* Thu Jun 12 2014 Nalin Dahyabhai <nalin@redhat.com> - 1.12.1-8
+- pull in fix for building against tcl 8.6 (#1107061)
+
+* Sun Jun 08 2014 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 1.12.1-7
+- Rebuilt for https://fedoraproject.org/wiki/Fedora_21_Mass_Rebuild
+
+* Tue Mar 04 2014 Nathaniel McCallum <npmccallum@redhat.com> - 1.12.1-6
+- Backport fix for change password requests when using FAST (RT#7868)
+
+* Mon Feb 17 2014 Nalin Dahyabhai <nalin@redhat.com> - 1.12.1-5
+- spnego: pull in patch from master to restore preserving the OID of the
+  mechanism the initiator requested when we have multiple OIDs for the same
+  mechanism, so that we reply using the same mechanism OID and the initiator
+  doesn't get confused (#1066000, RT#7858)
+
+* Fri Feb  7 2014 Nalin Dahyabhai <nalin@redhat.com> - 1.12.1-4
+- pull in patch from master to move the default directory which the KDC uses
+  when computing the socket path for a local OTP daemon from the database
+  directory (/var/kerberos/krb5kdc) to the newly-added run directory
+  (/run/krb5kdc), in line with what we're expecting in 1.13 (RT#7859, more
+  of #1040056 as #1063905)
+- add a tmpfiles.d configuration file to have /run/krb5kdc created at
+  boot-time
+- own /var/run/krb5kdc
+
+* Fri Jan 31 2014 Nalin Dahyabhai <nalin@redhat.com> - 1.12.1-3
+- refresh nss_wrapper and add socket_wrapper to the %%check environment
+
+* Fri Jan 31 2014 Nalin Dahyabhai <nalin@redhat.com>
+- add currently-proposed changes to teach ksu about credential cache
+  collections and the default_ccache_name setting (#1015559,#1026099)
+
+* Tue Jan 21 2014 Nalin Dahyabhai <nalin@redhat.com> - 1.12.1-2
+- pull in multiple changes to allow replay caches to be added to a GSS
+  credential store as "rcache"-type credentials (RT#7818/#7819/#7836,
+  #1056078/#1056080)
+
+* Fri Jan 17 2014 Nalin Dahyabhai <nalin@redhat.com> - 1.12.1-1
+- update to 1.12.1
+  - drop patch for RT#7794, included now
+  - drop patch for RT#7797, included now
+  - drop patch for RT#7803, included now
+  - drop patch for RT#7805, included now
+  - drop patch for RT#7807, included now
+  - drop patch for RT#7045, included now
+  - drop patches for RT#7813 and RT#7815, included now
+  - add patch to always retrieve the KDC time offsets from keyring caches,
+    so that we don't mistakenly interpret creds as expired before their
+    time when our clock is ahead of the KDC's (RT#7820, #1030607)
+
+* Mon Jan 13 2014 Nalin Dahyabhai <nalin@redhat.com> - 1.12-11
+- update the PIC patch for iaesx86.s to not use ELF relocations to the version
+  that landed upstream (RT#7815, #1045699)
+
+* Thu Jan  9 2014 Nalin Dahyabhai <nalin@redhat.com>
+- pass -Wl,--warn-shared-textrel to the compiler when we're creating shared
+  libraries
+
+* Thu Jan  9 2014 Nalin Dahyabhai <nalin@redhat.com> - 1.12-10
+- amend the PIC patch for iaesx86.s to also save/restore ebx in the
+  functions where we modify it, because the ELF spec says we need to
+
+* Mon Jan  6 2014 Nalin Dahyabhai <nalin@redhat.com> - 1.12-9
+- grab a more-commented version of the most recent patch from upstream
+  master
+- make a guess at making the 32-bit AES-NI implementation sufficiently
+  position-independent to not require execmod permissions for libk5crypto
+  (more of #1045699)
+
+* Thu Jan  2 2014 Nalin Dahyabhai <nalin@redhat.com> - 1.12-8
+- add patch from Dhiru Kholia for the AES-NI implementations to allow
+  libk5crypto to be properly marked as not needing an executable stack
+  on arches where they're used (#1045699, and so many others)
+
+* Thu Jan  2 2014 Nalin Dahyabhai <nalin@redhat.com> - 1.12-7
+- revert that last change for a bit while sorting out execstack when we
+  use AES-NI (#1045699)
+
+* Thu Dec 19 2013 Nalin Dahyabhai <nalin@redhat.com> - 1.12-6
+- add yasm as a build requirement for AES-NI support, on arches that have
+  yasm and AES-NI
+
+* Thu Dec 19 2013 Nalin Dahyabhai <nalin@redhat.com> - 1.12-5
+- pull in fix from master to make reporting of errors encountered by
+  the SPNEGO mechanism work better (RT#7045, part of #1043962)
+
+* Thu Dec 19 2013 Nalin Dahyabhai <nalin@redhat.com>
+- update a test wrapper to properly handle things that the new libkrad does,
+  and add python-pyrad as a build requirement so that we can run its tests
+
+* Wed Dec 18 2013 Nalin Dahyabhai <nalin@redhat.com> - 1.12-4
+- revise previous patch to initialize one more element
+
+* Wed Dec 18 2013 Nalin Dahyabhai <nalin@redhat.com> - 1.12-3
+- backport fixes to krb5_copy_context (RT#7807, #1044735/#1044739)
+
+* Wed Dec 18 2013 Nalin Dahyabhai <nalin@redhat.com> - 1.12-2
+- pull in fix from master to return a NULL pointer rather than allocating
+  zero bytes of memory if we read a zero-length input token (RT#7794, part of
+  #1043962)
+- pull in fix from master to ignore an empty token from an acceptor if
+  we've already finished authenticating (RT#7797, part of #1043962)
+- pull in fix from master to avoid a memory leak when a mechanism's
+  init_sec_context function fails (RT#7803, part of #1043962)
+- pull in fix from master to avoid a memory leak in a couple of error
+  cases which could occur while obtaining acceptor credentials (RT#7805, part
+  of #1043962)
+
+* Wed Dec 11 2013 Nalin Dahyabhai <nalin@redhat.com> - 1.12-1
+- update to 1.12 final
+
+* Mon Dec  2 2013 Nalin Dahyabhai <nalin@redhat.com> - 1.12-beta2.0
+- update to beta2
+  - drop obsolete backports for storing KDC time offsets and expiration times
+    in keyring credential caches
+
+* Tue Nov 19 2013 Nalin Dahyabhai <nalin@redhat.com> - 1.12-beta1.0
+- rebase to master
+- update to beta1
+  - drop obsolete backport of fix for RT#7706
+
+* Mon Nov 18 2013 Nalin Dahyabhai <nalin@redhat.com> - 1.11.4-2
+- pull in fix to store KDC time offsets in keyring credential caches (RT#7768,
+  #1030607)
+- pull in fix to set expiration times on credentials stored in keyring
+  credential caches (RT#7769, #1031724)
+
+* Tue Nov 12 2013 Nalin Dahyabhai <nalin@redhat.com> - 1.11.4-1
+- update to 1.11.4
+  - drop patch for RT#7650, obsoleted
+  - drop patch for RT#7706, obsoleted as RT#7723
+  - drop patch for CVE-2013-1418/CVE-2013-6800, included in 1.11.4
+
+* Tue Nov 12 2013 Nalin Dahyabhai <nalin@redhat.com> - 1.11.3-31
+- switch to the simplified version of the patch for #1029110 (RT#7764)
+
+* Mon Nov 11 2013 Nalin Dahyabhai <nalin@redhat.com> - 1.11.3-30
+- check more thoroughly for errors when resolving KEYRING ccache names of type
+  "persistent", which should only have a numeric UID as the next part of the
+  name (#1029110)
+
+* Tue Nov  5 2013 Nalin Dahyabhai <nalin@redhat.com> - 1.11.3-29
+- incorporate upstream patch for remote crash of KDCs which serve multiple
+  realms simultaneously (RT#7756, CVE-2013-1418/CVE-2013-6800,
+  #1026997/#1031501)
+
+* Mon Nov  4 2013 Nalin Dahyabhai <nalin@redhat.com> - 1.11.3-28
+- drop patch to add additional access() checks to ksu - they add to breakage
+  when non-FILE: caches are in use (#1026099), shouldn't be resulting in any
+  benefit, and clash with proposed changes to fix its cache handling
+
+* Tue Oct 22 2013 Nalin Dahyabhai <nalin@redhat.com> - 1.11.3-27
+- add some minimal description to the top of the wrapper scripts we use
+  when starting krb5kdc and kadmind to describe why they exist (tooling)
+
+* Thu Oct 17 2013 Nalin Dahyabhai <nalin@redhat.com> - 1.12-alpha1.0
+- initial update to alpha1
+  - drop backport of persistent keyring support
+  - drop backport for RT#7689
+  - drop obsolete patch for fixing a use-before-init in a test program
+  - drop obsolete patch teaching config.guess/config.sub about aarch64-linux
+  - drop backport for RT#7598
+  - drop backport for RT#7172
+  - drop backport for RT#7642
+  - drop backport for RT#7643
+  - drop patches from master to not test GSSRPC-over-UDP and to not
+    depend on the portmapper, which are areas where our build systems
+    often give us trouble, too; obsolete
+  - drop backports for RT#7682
+  - drop backport for RT#7709
+  - drop backport for RT#7590 and partial backport for RT#7680
+  - drop OTP backport
+  - drop backports for RT#7656 and RT#7657
+- BuildRequires: libedit-devel to prefer it
+- BuildRequires: pkgconfig, since configure uses it
+
+* Wed Oct 16 2013 Nalin Dahyabhai <nalin@redhat.com> - 1.11.3-26
+- create and own /etc/gss (#1019937)
+
+* Tue Oct 15 2013 Nalin Dahyabhai <nalin@redhat.com> - 1.11.3-25
+- pull up fix for importing previously-exported credential caches in the
+  gssapi library (RT# 7706, #1019420)
+
+* Mon Oct 14 2013 Nalin Dahyabhai <nalin@redhat.com> - 1.11.3-24
+- backport the callback to use the libkrb5 prompter when we can't load PEM
+  files for PKINIT (RT#7590, includes part of #965721/#1016690)
+- extract the rest of the fix #965721/#1016690 from the changes for RT#7680
+
+* Mon Oct 14 2013 Nalin Dahyabhai <nalin@redhat.com> - 1.11.3-23
+- fix trigger scriptlet's invocation of sed (#1016945)
+
+* Fri Oct  4 2013 Nalin Dahyabhai <nalin@redhat.com> - 1.11.3-22
+- rebuild with keyutils 1.5.8 (part of #1012043)
+
+* Wed Oct  2 2013 Nalin Dahyabhai <nalin@redhat.com> - 1.11.3-21
+- switch to the version of persistent-keyring that was just merged to
+  master (RT#7711), along with related changes to kinit (RT#7689)
+- go back to setting default_ccache_name to a KEYRING type
+
+* Mon Sep 30 2013 Nalin Dahyabhai <nalin@redhat.com> - 1.11.3-20
+- pull up fix for not calling a kdb plugin's check-transited-path
+  method before calling the library's default version, which only knows
+  how to read what's in the configuration file (RT#7709, #1013664)
+
+* Thu Sep 26 2013 Nalin Dahyabhai <nalin@redhat.com> - 1.11.3-19
+- configure --without-krb5-config so that we don't pull in the old default
+  ccache name when we want to stop setting a default ccache name at configure-
+  time
+
+* Wed Sep 25 2013 Nalin Dahyabhai <nalin@redhat.com> - 1.11.3-18
+- fix broken dependency on awk (should be gawk, rdieter)
+
+* Wed Sep 25 2013 Nalin Dahyabhai <nalin@redhat.com> - 1.11.3-17
+- add missing dependency on newer keyutils-libs (#1012034)
+
+* Tue Sep 24 2013 Nalin Dahyabhai <nalin@redhat.com> - 1.11.3-16
+- back out setting default_ccache_name to the new default for now, resetting
+  it to the old default while the kernel/keyutils bits get sorted (sgallagh)
+
+* Mon Sep 23 2013 Nalin Dahyabhai <nalin@redhat.com> - 1.11.3-15
+- add explicit build-time dependency on a version of keyutils that's new
+  enough to include keyctl_get_persistent() (more of #991148)
+
+* Thu Sep 19 2013 Nalin Dahyabhai <nalin@redhat.com> - 1.11.3-14
+- incorporate Simo's updated backport of his updated persistent-keyring changes
+  (more of #991148)
+
+* Fri Sep 13 2013 Nalin Dahyabhai <nalin@redhat.com> - 1.11.3-13
+- don't break during %%check when the session keyring is revoked
+
+* Fri Sep 13 2013 Nalin Dahyabhai <nalin@redhat.com> - 1.11.3-12
+- pull the newer F21 defaults back to F20 (sgallagh)
+
+* Mon Sep  9 2013 Nalin Dahyabhai <nalin@redhat.com>
+- only apply the patch to autocreate /run/user/0 when we're hard-wiring the
+  default ccache location to be under it; otherwise it's unnecessary
+
+* Mon Sep  9 2013 Nalin Dahyabhai <nalin@redhat.com> 1.11.3-11
+- don't let comments intended for one scriptlet become part of the "script"
+  that gets passed to ldconfig as part of another one (Mattias Ellert, #1005675)
+
+* Fri Sep  6 2013 Nalin Dahyabhai <nalin@redhat.com> 1.11.3-10
+- incorporate Simo's backport of his persistent-keyring changes (#991148)
+- restore build-time default DEFCCNAME on Fedora 21 and later and EL, and
+  instead set default_ccache_name in the default krb5.conf's [libdefaults]
+  section (#991148)
+- on releases where we expect krb5.conf to be configured with a
+  default_ccache_name, add it whenever we upgrade from an older version of
+  the package that wouldn't have included it in its default configuration
+  file (#991148)
+
+* Fri Aug 23 2013 Nalin Dahyabhai <nalin@redhat.com> 1.11.3-9
+- take another stab at accounting for UnversionedDocdirs for the -libs
+  subpackage (spotted by ssorce)
+- switch to just the snapshot of nss_wrapper we were using, since we
+  no longer need to carry anything that isn't in the cwrap.org repository
+  (ssorce)
+
+* Thu Aug 15 2013 Nalin Dahyabhai <nalin@redhat.com> 1.11.3-8
+- drop a patch we weren't not applying (build tooling)
+- wrap kadmind and kpropd in scripts which check for the presence/absence
+  of files which dictate particular exit codes before exec'ing the actual
+  binaries, instead of trying to use ConditionPathExists in the unit files
+  to accomplish that, so that we exit with failure properly when what we
+  expect isn't actually in effect on the system (#800343)
+
+* Mon Jul 29 2013 Nalin Dahyabhai <nalin@redhat.com> 1.11.3-7
+- attempt to account for UnversionedDocdirs for the -libs subpackage
+
+* Fri Jul 26 2013 Nalin Dahyabhai <nalin@redhat.com> 1.11.3-6
+- tweak configuration files used during tests to try to reduce the number
+  of conflicts encountered when builds for multiple arches land on the same
+  builder
+
+* Mon Jul 22 2013 Nalin Dahyabhai <nalin@redhat.com> 1.11.3-5
+- pull up changes to allow GSSAPI modules to provide more functions
+  (RT#7682, #986564/#986565)
+
+* Fri Jul 19 2013 Nalin Dahyabhai <nalin@redhat.com> 1.11.3-4
+- use (a bundled, for now, copy of) nss_wrapper to let us run some of the
+  self-tests at build-time in more places than we could previously (#978756)
+- cover inconsistencies in whether or not there's a local caching nameserver
+  that's willing to answer when the build environment doesn't have a
+  resolver configuration, so that nss_wrapper's faking of the local
+  hostname can be complete
+
+* Mon Jul  1 2013 Nalin Dahyabhai <nalin@redhat.com> 1.11.3-3
+- specify dependencies on the same arch of krb5-libs by using the %%{?_isa}
+  suffix, to avoid dragging 32-bit libraries onto 64-bit systems (#980155)
+
+* Thu Jun 13 2013 Nalin Dahyabhai <nalin@redhat.com> 1.11.3-2
+- special-case /run/user/0, attempting to create it when resolving a
+  directory cache below it fails due to ENOENT and we find that it doesn't
+  already exist, either, before attempting to create the directory cache
+  (maybe helping, maybe just making things more confusing for #961235)
+
+* Tue Jun  4 2013 Nalin Dahyabhai <nalin@redhat.com> 1.11.3-1
+- update to 1.11.3
+  - drop patch for RT#7605, fixed in this release
+  - drop patch for CVE-2002-2443, fixed in this release
+  - drop patch for RT#7369, fixed in this release
+- pull upstream fix for breaking t_skew.py by adding the patch for #961221
+
+* Fri May 31 2013 Nalin Dahyabhai <nalin@redhat.com> 1.11.2-10
+- respin with updated version of patch for RT#7650 (#969331)
+
+* Thu May 30 2013 Nalin Dahyabhai <nalin@redhat.com> 1.11.2-9
+- don't forget to set the SELinux label when creating the directory for
+  a DIR: ccache
+- pull in proposed fix for attempts to get initial creds, which end up
+  following referrals, incorrectly trying to always use master KDCs if
+  they talked to a master at any point (should fix RT#7650)
+
+* Thu May 30 2013 Nalin Dahyabhai <nalin@redhat.com> 1.11.2-8
+- pull in patches from master to not test GSSRPC-over-UDP and to not
+  depend on the portmapper, which are areas where our build systems
+  often give us trouble, too
+
+* Tue May 28 2013 Nalin Dahyabhai <nalin@redhat.com> 1.11.2-7
+- backport fix for not being able to verify the list of transited realms
+  in GSS acceptors (RT#7639, #959685)
+- backport fix for not being able to pass an empty password to the
+  get-init-creds APIs and have them actually use it (RT#7642, #960001)
+- add backported proposed fix to use the unauthenticated server time
+  as the basis for computing the requested credential expiration times,
+  rather than the client's idea of the current time, which could be
+  significantly incorrect (#961221)
+
+* Tue May 21 2013 Nalin Dahyabhai <nalin@redhat.com> 1.11.2-6
+- pull in upstream fix to start treating a KRB5CCNAME value that begins
+  with DIR:: the same as it would a DIR: value with just one ccache file
+  in it (RT#7172, #965574)
+
+* Mon May 13 2013 Nalin Dahyabhai <nalin@redhat.com> 1.11.2-5
+- pull up fix for UDP ping-pong flaw in kpasswd service (CVE-2002-2443,
+  #962531,#962534)
+
+* Mon Apr 29 2013 Nathaniel McCallum <npmccallum@redhat.com> 1.11.2-4
+- Update otp patches
+- Merge otp patches into a single patch
+- Add keycheck patch
+
+* Tue Apr 23 2013 Nalin Dahyabhai <nalin@redhat.com> 1.11.2-3
+- pull the changing of the compiled-in default ccache location to
+  DIR:/run/user/%%{uid}/krb5cc back into F19, in line with SSSD and
+  the most recent pam_krb5 build
+
+* Wed Apr 17 2013 Nalin Dahyabhai <nalin@redhat.com> 1.11.2-2
+- correct some configuration file paths which the KDC_DIR patch missed
+
+* Mon Apr 15 2013 Nalin Dahyabhai <nalin@redhat.com> 1.11.2-1
+- update to 1.11.2
+  - drop pulled in patch for RT#7586, included in this release
+  - drop pulled in patch for RT#7592, included in this release
+- pull in fix for keeping track of the message type when parsing FAST requests
+  in the KDC (RT#7605, #951843) (also #951965)
+
+* Fri Apr 12 2013 Nalin Dahyabhai <nalin@redhat.com> 1.11.1-9
+- move the compiled-in default ccache location from the previous default of
+  FILE:/tmp/krb5cc_%%{uid} to DIR:/run/user/%%{uid}/krb5cc (part of #949588)
+
+* Tue Apr 09 2013 Nathaniel McCallum <npmccallum@redhat.com> - 1.11.1-8
+- Update otp backport patches (libk5radius => libkrad)
+
+* Wed Apr  3 2013 Nalin Dahyabhai <nalin@redhat.com> 1.11.1-7
+- when testing the RPC library, treat denials from the local portmapper the
+  same as a portmapper-not-running situation, to allow other library tests
+  to be run while building the package
+
+* Thu Mar 28 2013 Nalin Dahyabhai <nalin@redhat.com> 1.11.1-6
+- create and own /var/kerberos/krb5/user instead of /var/kerberos/kdc/user,
+  since that's what the libraries actually look for
+- add buildrequires on nss-myhostname, in an attempt to get more of the tests
+  to run properly during builds
+- pull in Simo's patch to recognize "client_keytab" as a key type which can
+  be passed in to gss_acquire_cred_from() (RT#7598)
+
+* Tue Mar 26 2013 Nalin Dahyabhai <nalin@redhat.com> 1.11.1-5
+- pull up Simo's patch to mark the correct mechanism on imported GSSAPI
+  contexts (RT#7592)
+- go back to using reconf to run autoconf and autoheader (part of #925640)
+- add temporary patch to use newer config.guess/config.sub (more of #925640)
+
+* Mon Mar 18 2013 Nalin Dahyabhai <nalin@redhat.com>
+- fix a version comparison to expect newer texlive build requirements when
+  %%{_rhel} > 6 rather than when it's > 7
+
+* Mon Mar 11 2013 Nathaniel McCallum <npmccallum@redhat.com> 1.11.1-4
+- Add libverto-devel requires for krb5-devel
+- Add otp support
+
+* Thu Feb 28 2013 Nalin Dahyabhai <nalin@redhat.com> 1.11.1-3
+- fix a memory leak when acquiring credentials using a keytab (RT#7586, #911110)
+
+* Wed Feb 27 2013 Nalin Dahyabhai <nalin@redhat.com> 1.11.1-2
+- prebuild PDF docs to reduce multilib differences (internal tooling, #884065)
+- drop the kerberos-iv portreserve file, and drop the rest on systemd systems
+- escape uses of macros in comments (more of #884065)
+
+* Mon Feb 25 2013 Nalin Dahyabhai <nalin@redhat.com> 1.11.1-1
+- update to 1.11.1
+  - drop patch for noticing negative timeouts being passed to the poll()
+    wrapper in the client transmit functions
+
+* Fri Feb  8 2013 Nalin Dahyabhai <nalin@redhat.com> 1.11-2
+- set "rdns = false" in the default krb5.conf (#908323,#908324)
+
+* Tue Dec 18 2012 Nalin Dahyabhai <nalin@redhat.com> 1.11-1
+- update to 1.11 release
+
+* Thu Dec 13 2012 Nalin Dahyabhai <nalin@redhat.com> 1.11-0.beta2.0
+- update to 1.11 beta 2
+
+* Thu Dec 13 2012 Nalin Dahyabhai <nalin@redhat.com>
+- when building with our bundled copy of libverto, package it in with -libs
+  rather than with -server (#886049)
+
+* Wed Nov 21 2012 Nalin Dahyabhai <nalin@redhat.com> 1.11-0.beta1.0
+- update to 1.11 beta 1
+
+* Fri Nov 16 2012 Nalin Dahyabhai <nalin@redhat.com> 1.11-0.alpha1.1
+- handle releases where texlive packaging wasn't yet as complicated as it
+  is in Fedora 18
+- fix an uninitialized-variable error building one of the test programs
+
+* Fri Nov 16 2012 Nalin Dahyabhai <nalin@redhat.com> 1.11-0.alpha1.0
+- move the rather large pile of html and pdf docs to -workstation, so
+  that just having something that links to the libraries won't drag
+  them onto a system, and we avoid having to sort out hard-coded paths
+  that include %%{_libdir} showing up in docs in multilib packages
+- actually create %%{_var}/kerberos/kdc/user, so that it can be packaged
+- correct the list of packaged man pages
+- don't dummy up required tex stylesheets, require them
+- require pdflatex and makeindex
+
+* Thu Nov 15 2012 Nalin Dahyabhai <nalin@redhat.com>
+- update to 1.11 alpha 1
+  - drop backported patch for RT #7406
+  - drop backported patch for RT #7407
+  - drop backported patch for RT #7408
+  - the new docs system generates PDFs, so stop including them as sources
+  - drop backported patch to allow deltat.y to build with the usual
+    warning flags and the current gcc
+  - drop backported fix for disabling use of a replay cache when verifying
+    initial credentials
+  - drop backported fix for teaching PKINIT clients which trust the KDC's
+    certificate directly to verify signed-data messages that are signed with
+    the KDC's certificate, when the blobs don't include a copy of the KDC's
+    certificate
+  - drop backported patches to make keytab-based authentication attempts
+    work better when the client tells the KDC that it supports a particular
+    cipher, but doesn't have a key for it in the keytab
+  - drop backported fix for avoiding spurious clock skew when a TGT is
+    decrypted long after the KDC sent it to the client which decrypts it
+  - move the cross-referenced HTML docs into the -libs package to avoid
+    broken internal links
+  - drop patches to fixup paths in man pages, shouldn't be needed any more
+
+* Wed Oct 17 2012 Nalin Dahyabhai <nalin@redhat.com> 1.10.3-7
+- tag a couple of other patches which we still need to be applied during
+  %%{?_rawbuild} builds (zmraz)
+
+* Tue Sep 25 2012 Nalin Dahyabhai <nalin@redhat.com> 1.10.3-6
+- actually pull up the patch for RT#7063, and not some other ticket (#773496)
+
+* Mon Sep 10 2012 Nalin Dahyabhai <nalin@redhat.com> 1.10.3-5
+- add patch based on one from Filip Krska to not call poll() with a negative
+  timeout when the caller's intent is for us to just stop calling it (#838548)
+
+* Fri Sep  7 2012 Nalin Dahyabhai <nalin@redhat.com>
+- on EL6, conflict with libsmbclient before 3.5.10-124, which is when it
+  stopped linking with a symbol which we no longer export (#771687)
+- pull up patch for RT#7063, in which not noticing a prompt for a long
+  time throws the client library's idea of the time difference between it
+  and the KDC really far out of whack (#773496)
+- add a backport of more patches to set the client's list of supported enctypes
+  when using a keytab to be the list of types of keys in the keytab, plus the
+  list of other types the client supports but for which it doesn't have keys,
+  in that order, so that KDCs have a better chance of being able to issue
+  tickets with session keys of types that the client can use (#837855)
+
+* Thu Sep  6 2012 Nalin Dahyabhai <nalin@redhat.com> 1.10.3-4
+- cut down the number of times we load SELinux labeling configuration from
+  a minimum of two times to actually one (more of #845125)
+
+* Thu Aug 30 2012 Nalin Dahyabhai <nalin@redhat.com> 1.10.3-3
+- backport patch to disable replay detection in krb5_verify_init_creds()
+  while reading the AP-REQ that's generated in the same function (RT#7229)
+
+* Thu Aug 30 2012 Nalin Dahyabhai <nalin@redhat.com> 1.10.3-2
+- undo rename from krb5-pkinit-openssl to krb5-pkinit on EL6
+- version the Obsoletes: on the krb5-pkinit-openssl to krb5-pkinit rename
+- reintroduce the init scripts for non-systemd releases
+- forward-port %%{?_rawbuild} annotations from EL6 packaging
+
+* Thu Aug  9 2012 Nalin Dahyabhai <nalin@redhat.com> 1.10.3-1
+- update to 1.10.3, rolling in the fixes from MITKRB5-SA-2012-001
+
+* Thu Aug  2 2012 Nalin Dahyabhai <nalin@redhat.com> 1.10.2-7
+- selinux: hang on to the list of selinux contexts, freeing and reloading
+  it only when the file we read it from is modified, freeing it when the
+  shared library is being unloaded (#845125)
+
+* Thu Aug  2 2012 Nalin Dahyabhai <nalin@redhat.com> 1.10.2-6
+- go back to not messing with library file paths on Fedora 17: it breaks
+  file path dependencies in other packages, and since Fedora 17 is already
+  released, breaking that is our fault
+
+* Tue Jul 31 2012 Nalin Dahyabhai <nalin@redhat.com> 1.10.2-5
+- add upstream patch to fix freeing an uninitialized pointer and dereferencing
+  another uninitialized pointer in the KDC (MITKRB5-SA-2012-001, CVE-2012-1014
+  and CVE-2012-1015, #844779 and #844777)
+- fix a thinko in whether or not we mess around with devel .so symlinks on
+  systems without a separate /usr (sbose)
+
+* Fri Jul 27 2012 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 1.10.2-4
+- Rebuilt for https://fedoraproject.org/wiki/Fedora_18_Mass_Rebuild
+
+* Fri Jun 22 2012 Nalin Dahyabhai <nalin@redhat.com> 1.10.2-3
+- backport a fix to allow a PKINIT client to handle SignedData from a KDC
+  that's signed with a certificate that isn't in the SignedData, but which
+  is available as an anchor or intermediate on the client (RT#7183)
+
+* Tue Jun  5 2012 Nalin Dahyabhai <nalin@redhat.com> 1.10.2-2
+- back out this labeling change (dwalsh):
+  - when building the new label for a file we're about to create, also mix
+    in the current range, in addition to the current user
+
+* Fri Jun  1 2012 Nalin Dahyabhai <nalin@redhat.com> 1.10.2-1
+- update to 1.10.2
+  - when building the new label for a file we're about to create, also mix
+    in the current range, in addition to the current user
+  - also package the PDF format admin, user, and install guides
+  - drop some PDFs that no longer get built right
+- add a backport of Stef's patch to set the client's list of supported
+  enctypes to match the types of keys that we have when we are using a
+  keytab to try to get initial credentials, so that a KDC won't send us
+  an AS reply that we can't encrypt (RT#2131, #748528)
+- don't shuffle around any shared libraries on releases with no-separate-/usr,
+  since /usr/lib is the same place as /lib
+- add explicit buildrequires: on 'hostname', for the tests, on systems where
+  it's in its own package, and require net-tools, which used to provide the
+  command, everywhere
+
+* Mon May  7 2012 Nalin Dahyabhai <nalin@redhat.com>
+- skip the setfscreatecon() if fopen() is passed "rb" as the open mode (part
+  of #819115)
+
+* Tue May  1 2012 Nalin Dahyabhai <nalin@redhat.com> 1.10.1-3
+- have -server require /usr/share/dict/words, which we set as the default
+  dict_file in kdc.conf (#817089)
+
+* Tue Mar 20 2012 Nalin Dahyabhai <nalin@redhat.com> 1.10.1-2
+- change back dns_lookup_kdc to the default setting (Stef Walter, #805318)
+- comment out example.com examples in default krb5.conf (Stef Walter, #805320)
+
+* Fri Mar  9 2012 Nalin Dahyabhai <nalin@redhat.com> 1.10.1-1
+- update to 1.10.1
+  - drop the KDC crash fix
+  - drop the KDC lookaside cache fix
+  - drop the fix for kadmind RPC ACLs (CVE-2012-1012)
+
+* Wed Mar  7 2012 Nalin Dahyabhai <nalin@redhat.com> 1.10-5
+- when removing -workstation, remove our files from the info index while
+  the file is still there, in %%preun, rather than %%postun, and use the
+  compressed file's name (#801035)
+
+* Tue Feb 21 2012 Nathaniel McCallum <nathaniel@natemccallum.com> - 1.10-4
+- Fix string RPC ACLs (RT#7093); CVE-2012-1012
+
+* Tue Jan 31 2012 Nathaniel McCallum <nathaniel@natemccallum.com> - 1.10-3
+- Add upstream lookaside cache behavior fix (RT#7082)
+
+* Mon Jan 30 2012 Nalin Dahyabhai <nalin@redhat.com> 1.10-2
+- add patch to accept keytab entries with vno==0 as matches when we're
+  searching for an entry with a specific name/kvno (#230382/#782211,RT#3349)
+
+* Mon Jan 30 2012 Nalin Dahyabhai <nalin@redhat.com> 1.10-1
+- update to 1.10 final
+
+* Thu Jan 26 2012 Nathaniel McCallum <nathaniel@natemccallum.com> - 1.10-0.beta1.2
+- Add upstream crashfix patch (RT#7081)
+
+* Thu Jan 12 2012 Nalin Dahyabhai <nalin@redhat.com> 1.10-0.beta1.1
+- update to beta 1
+
+* Wed Jan 11 2012 Peter Robinson <pbrobinson@gmail.com>
+- mktemp was long obsoleted by coreutils
+
+* Wed Jan  4 2012 Nalin Dahyabhai <nalin@redhat.com> 1.10-0.alpha2.2
+- modify the deltat grammar to also tell gcc (4.7) to suppress
+  "maybe-uninitialized" warnings in addition to the "uninitialized" warnings
+  it's already being told to suppress (RT#7080)
+
+* Tue Dec 20 2011 Nalin Dahyabhai <nalin@redhat.com> 1.10-0.alpha2.1
+- update to alpha 2
+- drop a couple of patches which were integrated for alpha 2
+
+* Tue Dec 13 2011 Nalin Dahyabhai <nalin@redhat.com> 1.10-0.alpha1.3
+- pull in patch for RT#7046: tag a ccache containing credentials obtained via
+  S4U2Proxy with the principal name of the proxying principal (part of #761317)
+  so that the default principal name can be set to that of the client for which
+  it is proxying, which results in the ccache looking more normal to consumers
+  of the ccache that don't care that there's proxying going on
+- pull in patch for RT#7047: allow tickets obtained via S4U2Proxy to be cached
+  (more of #761317)
+- pull in patch for RT#7048: allow PAC verification to only bother trying to
+  verify the signature with keys that it's given (still more of #761317)
+
+* Tue Dec  6 2011 Nalin Dahyabhai <nalin@redhat.com> 1.10-0.alpha1.2
+- apply upstream patch to fix a null pointer dereference when processing
+  TGS requests (CVE-2011-1530, #753748)
+
+* Wed Nov 30 2011 Nalin Dahyabhai <nalin@redhat.com> 1.10-0.alpha1.1
+- correct a bug in the fix for #754001 so that the file creation context is
+  consistently reset
+
+* Tue Nov 15 2011 Nalin Dahyabhai <nalin@redhat.com> 1.10-0.alpha1.0
+- update to 1.10 alpha 1
+- on newer releases where we can assume NSS >= 3.13, configure PKINIT to build
+  using NSS
+- on newer releases where we build PKINIT using NSS, configure libk5crypto to
+  build using NSS
+- rename krb5-pkinit-openssl to krb5-pkinit on newer releases where we're
+  expecting to build PKINIT using NSS instead
+- during %%check, run check in the library and kdc subdirectories, which
+  should be able to run inside of the build system without issue
+
+* Wed Oct 26 2011 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 1.9.1-19
+- Rebuilt for glibc bug#747377
+
+* Tue Oct 18 2011 Nalin Dahyabhai <nalin@redhat.com> 1.9.1-18
+- apply upstream patch to fix a null pointer dereference with the LDAP kdb
+  backend (CVE-2011-1527, #744125), an assertion failure with multiple kdb
+  backends (CVE-2011-1528), and a null pointer dereference with multiple kdb
+  backends (CVE-2011-1529) (#737711)
+
+* Thu Oct 13 2011 Nalin Dahyabhai <nalin@redhat.com> 1.9.1-17
+- pull in patch from trunk to rename krb5int_pac_sign() to krb5_pac_sign() and
+  make it public (#745533)
+
+* Fri Oct  7 2011 Nalin Dahyabhai <nalin@redhat.com> 1.9.1-16
+- kadmin.service: fix #723723 again
+- kadmin.service,krb5kdc.service: remove optional use of $KRB5REALM in command
+  lines, because systemd parsing doesn't handle alternate value shell variable
+  syntax
+- kprop.service: add missing Type=forking so that systemd doesn't assume simple
+- kprop.service: expect the ACL configuration to be there, not absent
+- handle a harder-to-trigger assertion failure that starts cropping up when we
+  exit the transmit loop on time (#739853)
+
+* Sun Oct  2 2011 Tom Callaway <spot@fedoraproject.org> 1.9.1-15
+- hardcode pid file as option in krb5kdc.service
+
+* Fri Sep 30 2011 Tom Callaway <spot@fedoraproject.org> 1.9.1-14
+- fix pid path in krb5kdc.service
+
+* Mon Sep 19 2011 Tom Callaway <spot@fedoraproject.org> 1.9.1-13
+- convert to systemd
+
+* Tue Sep  6 2011 Nalin Dahyabhai <nalin@redhat.com> 1.9.1-12
+- pull in upstream patch for RT#6952, confusion following referrals for
+  cross-realm auth (#734341)
+- pull in build-time deps for the tests
+
+* Thu Sep  1 2011 Nalin Dahyabhai <nalin@redhat.com> 1.9.1-11
+- switch to the upstream patch for #727829
+
+* Wed Aug 31 2011 Nalin Dahyabhai <nalin@redhat.com> 1.9.1-10
+- handle an assertion failure that starts cropping up when the patch for
+  using poll (#701446) meets servers that aren't running KDCs or against
+  which the connection fails for other reasons (#727829, #734172)
+
+* Mon Aug  8 2011 Nalin Dahyabhai <nalin@redhat.com> 1.9.1-9
+- override the default build rules to not delete temporary y.tab.c files,
+  so that they can be packaged, allowing debuginfo files which point to them
+  do so usefully (#729044)
+
+* Fri Jul 22 2011 Nalin Dahyabhai <nalin@redhat.com> 1.9.1-8
+- build shared libraries with partial RELRO support (#723995)
+- filter out potentially multiple instances of -Wl,-z,relro from krb5-config
+  output, now that it's in the buildroot's default LDFLAGS
+- pull in a patch to fix losing track of the replay cache FD, from SVN by
+  way of Kevin Coffman
+
+* Wed Jul 20 2011 Nalin Dahyabhai <nalin@redhat.com> 1.9.1-7
+- kadmind.init: drop the attempt to detect no-database-present errors (#723723),
+  which is too fragile in cases where the database has been manually moved or
+  is accessed through another kdb plugin
+
+* Tue Jul 19 2011 Nalin Dahyabhai <nalin@redhat.com> 1.9.1-6
+- backport fixes to teach libkrb5 to use descriptors higher than FD_SETSIZE
+  to talk to a KDC by using poll() if it's detected at compile-time (#701446,
+  RT#6905)
+
+* Thu Jun 23 2011 Nalin Dahyabhai <nalin@redhat.com> 1.9.1-5
+- pull a fix from SVN to try to avoid triggering a PTR lookup in getaddrinfo()
+  during krb5_sname_to_principal(), and to let getaddrinfo() decide whether or
+  not to ask for an IPv6 address based on the set of configured interfaces
+  (#717378, RT#6922)
+- pull a fix from SVN to use AI_ADDRCONFIG more often (RT#6923)
+
+* Mon Jun 20 2011 Nalin Dahyabhai <nalin@redhat.com> 1.9.1-4
+- apply upstream patch by way of Burt Holzman to fall back to a non-referral
+  method in cases where we might be derailed by a KDC that rejects the
+  canonicalize option (for example, those from the RHEL 2.1 or 3 era) (#715074)
+
+* Tue Jun 14 2011 Nalin Dahyabhai <nalin@redhat.com> 1.9.1-3
+- pull a fix from SVN to get libgssrpc clients (e.g. kadmin) authenticating
+  using the old protocol over IPv4 again (RT#6920)
+
+* Tue Jun 14 2011 Nalin Dahyabhai <nalin@redhat.com>
+- incorporate a fix to teach the file labeling bits about when replay caches
+  are expunged (#576093)
+
+* Thu May 26 2011 Nalin Dahyabhai <nalin@redhat.com>
+- switch to the upstream patch for #707145
+
+* Wed May 25 2011 Nalin Dahyabhai <nalin@redhat.com> 1.9.1-2
+- klist: don't trip over referral entries when invoked with -s (#707145,
+  RT#6915)
+
+* Fri May  6 2011 Nalin Dahyabhai <nalin@redhat.com>
+- fixup URL in a comment
+- when built with NSS, require 3.12.10 rather than 3.12.9
+
+* Thu May  5 2011 Nalin Dahyabhai <nalin@redhat.com> 1.9.1-1
+- update to 1.9.1:
+  - drop no-longer-needed patches for CVE-2010-4022, CVE-2011-0281,
+    CVE-2011-0282, CVE-2011-0283, CVE-2011-0284, CVE-2011-0285
+
+* Wed Apr 13 2011 Nalin Dahyabhai <nalin@redhat.com> 1.9-9
+- kadmind: add upstream patch to fix free() on an invalid pointer (#696343,
+  MITKRB5-SA-2011-004, CVE-2011-0285)
+
+* Mon Apr  4 2011 Nalin Dahyabhai <nalin@redhat.com>
+- don't discard the error code from an error message received in response
+  to a change-password request (#658871, RT#6893)
+
+* Fri Apr  1 2011 Nalin Dahyabhai <nalin@redhat.com>
+- override INSTALL_SETUID at build-time so that ksu is installed into
+  the buildroot with the right permissions (part of #225974)
+
+* Fri Mar 18 2011 Nalin Dahyabhai <nalin@redhat.com> 1.9-8
+- backport change from SVN to fix a computed-value-not-used warning in
+  kpropd (#684065)
+
+* Tue Mar 15 2011 Nalin Dahyabhai <nalin@redhat.com> 1.9-7
+- turn off NSS as the backend for libk5crypto for now to work around its
+  DES string2key not working (#679012)
+- add revised upstream patch to fix double-free in KDC while returning
+  typed-data with errors (MITKRB5-SA-2011-003, CVE-2011-0284, #674325)
+
+* Thu Feb 17 2011 Nalin Dahyabhai <nalin@redhat.com>
+- throw in a not-applied-by-default patch to try to make pkinit debugging
+  into a run-time boolean option named "pkinit_debug"
+
+* Wed Feb 16 2011 Nalin Dahyabhai <nalin@redhat.com> 1.9-6
+- turn on NSS as the backend for libk5crypto, adding nss-devel as a build
+  dependency when that switch is flipped
+
+* Wed Feb  9 2011 Nalin Dahyabhai <nalin@redhat.com> 1.9-5
+- krb5kdc init script: prototype some changes to do a quick spot-check
+  of the TGS and kadmind keys and warn if there aren't any non-weak keys
+  on file for them (to flush out parts of #651466)
+
+* Tue Feb  8 2011 Nalin Dahyabhai <nalin@redhat.com> 1.9-4
+- add upstream patches to fix standalone kpropd exiting if the per-client
+  child process exits with an error (MITKRB5-SA-2011-001), a hang or crash
+  in the KDC when using the LDAP kdb backend, and an uninitialized pointer
+  use in the KDC (MITKRB5-SA-2011-002) (CVE-2010-4022, #664009,
+  CVE-2011-0281, #668719, CVE-2011-0282, #668726, CVE-2011-0283, #676126)
+
+* Mon Feb 07 2011 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 1.9-3
+- Rebuilt for https://fedoraproject.org/wiki/Fedora_15_Mass_Rebuild
+
+* Mon Feb  7 2011 Nalin Dahyabhai <nalin@redhat.com>
+- fix a compile error in the SELinux labeling patch when -DDEBUG is used (Sumit
+  Bose)
+
+* Tue Feb  1 2011 Nalin Dahyabhai <nalin@redhat.com>
+- properly advertise that the kpropd init script now supports force-reload
+  (Zbysek Mraz, #630587)
+
+* Wed Jan 26 2011 Nalin Dahyabhai <nalin@redhat.com> 1.9-2
+- pkinit: when verifying signed data, use the CMS APIs for better
+  interoperability (#636985, RT#6851)
+
+* Wed Dec 22 2010 Nalin Dahyabhai <nalin@redhat.com> 1.9-1
+- update to 1.9 final
+
+* Mon Dec 20 2010 Nalin Dahyabhai <nalin@redhat.com> 1.9-0.beta3.1
+- fix link flags and permissions on shared libraries (ausil)
+
+* Thu Dec 16 2010 Nalin Dahyabhai <nalin@redhat.com> 1.9-0.beta3.0
+- update to 1.9 beta 3
+
+* Mon Dec  6 2010 Nalin Dahyabhai <nalin@redhat.com> 1.9-0.beta2.0
+- update to 1.9 beta 2
+
+* Tue Nov  9 2010 Nalin Dahyabhai <nalin@redhat.com> 1.9-0.beta1.1
+- drop not-needed-since-1.8 build dependency on rsh (ssorce)
+
+* Fri Nov  5 2010 Nalin Dahyabhai <nalin@redhat.com> 1.9-0.beta1.0
+- start moving to 1.9 with beta 1
+  - drop patches for RT#5755, RT#6762, RT#6774, RT#6775
+  - drop no-longer-needed backport patch for #539423
+  - drop no-longer-needed patch for CVE-2010-1322
+- if WITH_NSS is set, built with --with-crypto-impl=nss (requires NSS 3.12.9)
+
+* Tue Oct  5 2010 Nalin Dahyabhai <nalin@redhat.com> 1.8.3-8
+- incorporate upstream patch to fix uninitialized pointer crash in the KDC's
+  authorization data handling (CVE-2010-1322, #636335)
+
+* Mon Oct  4 2010 Nalin Dahyabhai <nalin@redhat.com> 1.8.3-7
+- rebuild
+
+* Mon Oct  4 2010 Nalin Dahyabhai <nalin@redhat.com> 1.8.3-6
+- pull down patches from trunk to implement k5login_authoritative and
+  k5login_directory settings for krb5.conf (#539423)
+
+* Wed Sep 29 2010 jkeating - 1.8.3-5
+- Rebuilt for gcc bug 634757
+
+* Wed Sep 15 2010 Nalin Dahyabhai <nalin@redhat.com> 1.8.3-4
+- fix reading of keyUsage extensions when attempting to select pkinit client
+  certs (part of #629022, RT#6775)
+- fix selection of pkinit client certs when one or more don't include a
+  subjectAltName extension (part of #629022, RT#6774)
+
+* Fri Sep  3 2010 Nalin Dahyabhai <nalin@redhat.com> 1.8.3-3
+- build with -fstack-protector-all instead of the default -fstack-protector,
+  so that we add checking to more functions (i.e., all of them) (#629950)
+- also link binaries with -Wl,-z,relro,-z,now (part of #629950)
+
+* Tue Aug 24 2010 Nalin Dahyabhai <nalin@redhat.com> 1.8.3-2
+- fix a logic bug in computing key expiration times (RT#6762, #627022)
+
+* Wed Aug  4 2010 Nalin Dahyabhai <nalin@redhat.com> 1.8.3-1
+- update to 1.8.3
+  - drop backports of fixes for gss context expiration and error table
+    registration/deregistration mismatch
+  - drop patch for upstream #6750
+
+* Wed Jul  7 2010 Nalin Dahyabhai <nalin@redhat.com> 1.8.2-3
+- tell krb5kdc and kadmind to create pid files, since they can
+- add logrotate configuration files for krb5kdc and kadmind (#462658)
+- fix parsing of the pidfile option in the KDC (upstream #6750)
+
+* Mon Jun 21 2010 Nalin Dahyabhai <nalin@redhat.com> 1.8.2-2
+- libgssapi: pull in patch from svn to stop returning context-expired errors
+  when the ticket which was used to set up the context expires (#605366,
+  upstream #6739)
+
+* Mon Jun 21 2010 Nalin Dahyabhai <nalin@redhat.com>
+- pull up fix for upstream #6745, in which the gssapi library would add the
+  wrong error table but subsequently attempt to unload the right one
+
+* Thu Jun 10 2010 Nalin Dahyabhai <nalin@redhat.com> 1.8.2-1
+- update to 1.8.2
+  - drop patches for CVE-2010-1320, CVE-2010-1321
+
+* Tue Jun  1 2010 Nalin Dahyabhai <nalin@redhat.com> 1.8.1-7
+- rebuild
+
+* Thu May 27 2010 Nalin Dahyabhai <nalin@redhat.com>
+- ksu: move session management calls to before we drop privileges, like
+  su does (#596887), and don't skip the PAM account check for root or the
+  same user (more of #540769)
+
+* Mon May 24 2010 Nalin Dahyabhai <nalin@redhat.com> 1.8.1-6
+- make krb5-server-ldap also depend on the same version-release of krb5-libs,
+  as the other subpackages do, if only to make it clearer than it is when we
+  just do it through krb5-server
+- drop explicit linking with libtinfo for applications that use libss, now
+  that readline itself links with libtinfo (as of readline-5.2-3, since
+  fedora 7 or so)
+- go back to building without strict aliasing (compiler warnings in gssrpc)
+
+* Tue May 18 2010 Nalin Dahyabhai <nalin@redhat.com> 1.8.1-5
+- add patch to correct GSSAPI library null pointer dereference which could be
+  triggered by malformed client requests (CVE-2010-1321, #582466)
+
+* Tue May  4 2010 Nalin Dahyabhai <nalin@redhat.com> 1.8.1-4
+- fix output of kprop's init script's "status" and "reload" commands (#588222)
+
+* Tue Apr 20 2010 Nalin Dahyabhai <nalin@redhat.com> 1.8.1-3
+- incorporate patch to fix double-free in the KDC (CVE-2010-1320, #581922)
+
+* Wed Apr 14 2010 Nalin Dahyabhai <nalin@redhat.com> 1.8.1-2
+- fix a typo in kerberos.ldif
+
+* Fri Apr  9 2010 Nalin Dahyabhai <nalin@redhat.com> 1.8.1-1
+- update to 1.8.1
+  - no longer need patches for #555875, #561174, #563431, RT#6661, CVE-2010-0628
+- replace buildrequires on tetex-latex with one on texlive-latex, which is
+  the package that provides it now
+
+* Thu Apr  8 2010 Nalin Dahyabhai <nalin@redhat.com>
+- kdc.conf: no more need to suggest a v4 mode, or listening on the v4 port
+
+* Thu Apr  8 2010 Nalin Dahyabhai <nalin@redhat.com>
+- drop patch to suppress key expiration warnings sent from the KDC in
+  the last-req field, as the KDC is expected to just be configured to either
+  send them or not as a particular key approaches expiration (#556495)
+
+* Tue Mar 23 2010 Nalin Dahyabhai <nalin@redhat.com> - 1.8-5
+- add upstream fix for denial-of-service in SPNEGO (CVE-2010-0628, #576325)
+- kdc.conf: no more need to suggest keeping keys with v4-compatible salting
+
+* Fri Mar 19 2010 Nalin Dahyabhai <nalin@redhat.com> - 1.8-4
+- remove the krb5-appl bits (the -workstation-clients and -workstation-servers
+  subpackages) now that krb5-appl is its own package
+- replace our patch for #563431 (kpasswd doesn't fall back to guessing your
+  principal name using your user name if you don't have a ccache) with the
+  one upstream uses
+
+* Fri Mar 12 2010 Nalin Dahyabhai <nalin@redhat.com> - 1.8-3
+- add documentation for the ticket_lifetime option (#561174)
+
+* Mon Mar  8 2010 Nalin Dahyabhai <nalin@redhat.com> - 1.8-2
+- pull up patch to get the client libraries to correctly perform password
+  changes over IPv6 (Sumit Bose, RT#6661)
+
+* Fri Mar  5 2010 Nalin Dahyabhai <nalin@redhat.com> - 1.8-1
+- update to 1.8
+  - temporarily bundling the krb5-appl package (split upstream as of 1.8)
+    until its package review is complete
+  - profile.d scriptlets are now only needed by -workstation-clients
+  - adjust paths in init scripts
+  - drop upstreamed fix for KDC denial of service (CVE-2010-0283)
+  - drop patch to check the user's password correctly using crypt(), which
+    isn't a code path we hit when we're using PAM
+
+* Wed Mar  3 2010 Nalin Dahyabhai <nalin@redhat.com> - 1.7.1-6
+- fix a null pointer dereference and crash introduced in our PAM patch that
+  would happen if ftpd was given the name of a user who wasn't known to the
+  local system, limited to being triggerable by gssapi-authenticated clients by
+  the default xinetd config (Olivier Fourdan, #569472)
+
+* Tue Mar  2 2010 Nalin Dahyabhai <nalin@redhat.com> - 1.7.1-5
+- fix a regression (not labeling a kdb database lock file correctly, #569902)
+
+* Thu Feb 25 2010 Nalin Dahyabhai <nalin@redhat.com> - 1.7.1-4
+- move the package changelog to the end to match the usual style (jdennis)
+- scrub out references to $RPM_SOURCE_DIR (jdennis)
+- include a symlink to the readme with the name LICENSE so that people can
+  find it more easily (jdennis)
+
+* Wed Feb 17 2010 Nalin Dahyabhai <nalin@redhat.com> - 1.7.1-3
+- pull up the change to make kpasswd's behavior better match the docs
+  when there's no ccache (#563431)
+
+* Tue Feb 16 2010 Nalin Dahyabhai <nalin@redhat.com> - 1.7.1-2
+- apply patch from upstream to fix KDC denial of service (CVE-2010-0283,
+  #566002)
+
+* Wed Feb  3 2010 Nalin Dahyabhai <nalin@redhat.com> - 1.7.1-1
+- update to 1.7.1
+  - don't trip AD lockout on wrong password (#542687, #554351)
+  - incorporates fixes for CVE-2009-4212 and CVE-2009-3295
+  - fixes gss_krb5_copy_ccache() when SPNEGO is used
+- move sim_client/sim_server, gss-client/gss-server, uuclient/uuserver to
+  the devel subpackage, better lining up with the expected krb5/krb5-appl
+  split in 1.8
+- drop kvno,kadmin,k5srvutil,ktutil from -workstation-servers, as it already
+  depends on -workstation which also includes them
+
+* Mon Jan 25 2010 Nalin Dahyabhai <nalin@redhat.com> - 1.7-23
+- tighten up default permissions on kdc.conf and kadm5.acl (#558343)
+
+* Fri Jan 22 2010 Nalin Dahyabhai <nalin@redhat.com> - 1.7-22
+- use portreserve correctly -- portrelease takes the basename of the file
+  whose entries should be released, so we need three files, not one
+
+* Mon Jan 18 2010 Nalin Dahyabhai <nalin@redhat.com> - 1.7-21
+- suppress warnings of impending password expiration if expiration is more than
+  seven days away when the KDC reports it via the last-req field, just as we
+  already do when it reports expiration via the key-expiration field (#556495)
+- link with libtinfo rather than libncurses, when we can, in future RHEL
+
+* Fri Jan 15 2010 Nalin Dahyabhai <nalin@redhat.com> - 1.7-20
+- krb5_get_init_creds_password: check opte->flags instead of options->flags
+  when checking whether or not we get to use the prompter callback (#555875)
+
+* Thu Jan 14 2010 Nalin Dahyabhai <nalin@redhat.com> - 1.7-19
+- use portreserve to make sure the KDC can always bind to the kerberos-iv
+  port, kpropd can always bind to the krb5_prop port, and that kadmind can
+  always bind to the kerberos-adm port (#555279)
+- correct inadvertent use of macros in the changelog (rpmlint)
+
+* Tue Jan 12 2010 Nalin Dahyabhai <nalin@redhat.com> - 1.7-18
+- add upstream patch for integer underflow during AES and RC4 decryption
+  (CVE-2009-4212), via Tom Yu (#545015)
+
+* Wed Jan  6 2010 Nalin Dahyabhai <nalin@redhat.com> - 1.7-17
+- put the conditional back for the -devel subpackage
+- back down to the earlier version of the patch for #551764; the backported
+  alternate version was incomplete
+
+* Tue Jan  5 2010 Nalin Dahyabhai <nalin@redhat.com> - 1.7-16
+- use %%global instead of %%define
+- pull up proposed patch for creating previously-not-there lock files for
+  kdb databases when 'kdb5_util' is called to 'load' (#551764)
+
+* Mon Jan  4 2010 Dennis Gregorovic <dgregor@redhat.com>
+- fix conditional for future RHEL
+
+* Mon Jan  4 2010 Nalin Dahyabhai <nalin@redhat.com> - 1.7-15
+- add upstream patch for KDC crash during referral processing (CVE-2009-3295),
+  via Tom Yu (#545002)
+
+* Mon Dec 21 2009 Nalin Dahyabhai <nalin@redhat.com> - 1.7-14
+- refresh patch for #542868 from trunk
+
+* Thu Dec 10 2009 Nalin Dahyabhai <nalin@redhat.com>
+- move man pages that live in the -libs subpackage into the regular
+  %%{_mandir} tree where they'll still be found if that package is the
+  only one installed (#529319)
+
+* Wed Dec  9 2009 Nalin Dahyabhai <nalin@redhat.com> - 1.7-13
+- and put it back in
+
+* Tue Dec  8 2009 Nalin Dahyabhai <nalin@redhat.com>
+- back that last change out
+
+* Tue Dec  8 2009 Nalin Dahyabhai <nalin@redhat.com> - 1.7-12
+- try to make gss_krb5_copy_ccache() work correctly for spnego (#542868)
+
+* Fri Dec  4 2009 Nalin Dahyabhai <nalin@redhat.com>
+- make krb5-config suppress CFLAGS output when called with --libs (#544391)
+
+* Thu Dec  3 2009 Nalin Dahyabhai <nalin@redhat.com> - 1.7-11
+- ksu: move account management checks to before we drop privileges, like
+  su does (#540769)
+- selinux: set the user part of file creation contexts to match the current
+  context instead of what we looked up
+- configure with --enable-dns-for-realm instead of --enable-dns, which isn't
+  recognized any more
+
+* Fri Nov 20 2009 Nalin Dahyabhai <nalin@redhat.com> - 1.7-10
+- move /etc/pam.d/ksu from krb5-workstation-servers to krb5-workstation,
+  where it's actually needed (#538703)
+
+* Fri Oct 23 2009 Nalin Dahyabhai <nalin@redhat.com> - 1.7-9
+- add some conditional logic to simplify building on older Fedora releases
+
+* Tue Oct 13 2009 Nalin Dahyabhai <nalin@redhat.com>
+- don't forget the README
+
+* Mon Sep 14 2009 Nalin Dahyabhai <nalin@redhat.com> - 1.7-8
+- specify the location of the subsystem lock when using the status() function
+  in the kadmind and kpropd init scripts, so that we get the right error when
+  we're dead but have a lock file - requires initscripts 8.99 (#521772)
+
+* Tue Sep  8 2009 Nalin Dahyabhai <nalin@redhat.com>
+- if the init script fails to start krb5kdc/kadmind/kpropd because it's already
+  running (according to status()), return 0 (part of #521772)
+
+* Mon Aug 24 2009 Nalin Dahyabhai <nalin@redhat.com> - 1.7-7
+- work around a compile problem with new openssl
+
+* Fri Aug 21 2009 Tomas Mraz <tmraz@redhat.com> - 1.7-6
+- rebuilt with new openssl
+
+* Fri Jul 24 2009 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 1.7-5
+- Rebuilt for https://fedoraproject.org/wiki/Fedora_12_Mass_Rebuild
+
+* Tue Jul  7 2009 Nalin Dahyabhai <nalin@redhat.com> 1.7-5
+- rebuild to pick up the current forms of various patches
+
+* Mon Jul  6 2009 Nalin Dahyabhai <nalin@redhat.com>
+- simplify the man pages patch by only preprocessing the files we care about
+  and moving shared configure.in logic into a shared function
+- catch the case of ftpd printing file sizes using %%i, when they might be
+  bigger than an int now
+
+* Tue Jun 30 2009 Nalin Dahyabhai <nalin@redhat.com> 1.7-4
+- try to merge and clean up all the large file support for ftp and rcp
+  - ftpd no longer prints a negative length when sending a large file
+    from a 32-bit host
+
+* Tue Jun 30 2009 Nalin Dahyabhai <nalin@redhat.com>
+- pam_rhosts_auth.so's been gone, use pam_rhosts.so instead
+
+* Mon Jun 29 2009 Nalin Dahyabhai <nalin@redhat.com> 1.7-3
+- switch buildrequires: and requires: on e2fsprogs-devel into
+  buildrequires: and requires: on libss-devel, libcom_err-devel, per
+  sandeen on fedora-devel-list
+
+* Fri Jun 26 2009 Nalin Dahyabhai <nalin@redhat.com>
+- fix a type mismatch in krb5_copy_error_message()
+- ftp: fix some odd use of strlen()
+- selinux labeling: use selabel_open() family of functions rather than
+  matchpathcon(), bail on it if attempting to get the mutex lock fails
+
+* Tue Jun 16 2009 Nalin Dahyabhai <nalin@redhat.com>
+- compile with %%{?_smp_mflags} (Steve Grubb)
+- drop the bit where we munge part of the error table header, as it's not
+  needed any more
+
+* Fri Jun  5 2009 Nalin Dahyabhai <nalin@redhat.com> 1.7-2
+- add and own %%{_libdir}/krb5/plugins/authdata
+
+* Thu Jun  4 2009 Nalin Dahyabhai <nalin@redhat.com> 1.7-1
+- update to 1.7
+  - no need to work around build issues with ASN1BUF_OMIT_INLINE_FUNCS
+  - configure recognizes --enable/--disable-pkinit now
+  - configure can take --disable-rpath now
+  - no more libdes425, krb524d, krb425.info
+  - kadmin/k5srvutil/ktutil are user commands now
+  - new kproplog
+  - FAST encrypted-challenge plugin is new
+- drop static build logic
+- drop pam_krb5-specific configuration from the default krb5.conf
+- drop only-use-v5 flags being passed to various things started by xinetd
+- put %%{krb5prefix}/sbin in everyone's path, too (#504525)
+
+* Tue May 19 2009 Nalin Dahyabhai <nalin@redhat.com> 1.6.3-106
+- add an auth stack to ksu's PAM configuration so that pam_setcred() calls
+  won't just fail
+
+* Mon May 11 2009 Nalin Dahyabhai <nalin@redhat.com> 1.6.3-105
+- make PAM support for ksu also set PAM_RUSER
+
+* Thu Apr 23 2009 Nalin Dahyabhai <nalin@redhat.com> 1.6.3-104
+- extend PAM support to ksu: perform account and session management for the
+  target user
+- pull up and merge James Leddy's changes to also set PAM_RHOST in PAM-aware
+  network-facing services
+
+* Tue Apr 21 2009 Nalin Dahyabhai <nalin@redhat.com> 1.6.3-103
+- fix a typo in a ksu error message (Marek Mahut)
+- "rev" works the way the test suite expects now, so don't disable tests
+  that use it
+
+* Mon Apr 20 2009 Nalin Dahyabhai <nalin@redhat.com> 1.6.3-102
+- add LSB-style init script info
+
+* Fri Apr 17 2009 Nalin Dahyabhai <nalin@redhat.com>
+- explicitly run the pdf generation script using sh (part of #225974)
+
+* Tue Apr  7 2009 Nalin Dahyabhai <nalin@redhat.com> 1.6.3-101
+- add patches for read overflow and null pointer dereference in the
+  implementation of the SPNEGO mechanism (CVE-2009-0844, CVE-2009-0845)
+- add patch for attempt to free uninitialized pointer in libkrb5
+  (CVE-2009-0846)
+- add patch to fix length validation bug in libkrb5 (CVE-2009-0847)
+- put the krb5-user .info file into just -workstation and not also
+  -workstation-clients
+
+* Mon Apr  6 2009 Nalin Dahyabhai <nalin@redhat.com> 1.6.3-100
+- turn off krb4 support (it won't be part of the 1.7 release, but do it now)
+- use triggeruns to properly shut down and disable krb524d when -server and
+  -workstation-servers gets upgraded, because it's gone now
+- move the libraries to /%%{_lib}, but leave --libdir alone so that plugins
+  get installed and are searched for in the same locations (#473333)
+- clean up buildprereq/prereqs, explicit mktemp requires, and add the
+  ldconfig for the -server-ldap subpackage (part of #225974)
+- escape possible macros in the changelog (part of #225974)
+- fixup summary texts (part of #225974)
+- take the execute bit off of the protocol docs (part of #225974)
+- unflag init scripts as configuration files (part of #225974)
+- make the kpropd init script treat 'reload' as 'restart' (part of #225974)
+
+* Tue Mar 17 2009 Nalin Dahyabhai <nalin@redhat.com> 1.6.3-19
+- libgssapi_krb5: backport fix for some errors which can occur when
+  we fail to set up the server half of a context (CVE-2009-0845)
+
+* Wed Feb 25 2009 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 1.6.3-18
+- Rebuilt for https://fedoraproject.org/wiki/Fedora_11_Mass_Rebuild
+
+* Fri Jan 16 2009 Nalin Dahyabhai <nalin@redhat.com> 1.6.3-17
+- rebuild
+
+* Thu Sep  4 2008 Nalin Dahyabhai <nalin@redhat.com>
+- if we successfully change the user's password during an attempt to get
+  initial credentials, but then fail to get initial creds from a non-master
+  using the new password, retry against the master (#432334)
+
+* Tue Aug  5 2008 Tom "spot" Callaway <tcallawa@redhat.com> 1.6.3-16
+- fix license tag
+
+* Wed Jul 16 2008 Nalin Dahyabhai <nalin@redhat.com>
+- clear fuzz out of patches, dropping a man page patch which is no longer
+  necessary
+- quote %%{__cc} where needed because it includes whitespace now
+- define ASN1BUF_OMIT_INLINE_FUNCS at compile-time (for now) to keep building
+
+* Fri Jul 11 2008 Nalin Dahyabhai <nalin@redhat.com> 1.6.3-15
+- build with -fno-strict-aliasing, which is needed because the library
+  triggers these warnings
+- don't forget to label principal database lock files
+- fix the labeling patch so that it doesn't break bootstrapping
+
+* Sat Jun 14 2008 Tom "spot" Callaway <tcallawa@redhat.com> 1.6.3-14
+- generate src/include/krb5/krb5.h before building
+- fix conditional for sparcv9
+
+* Wed Apr 16 2008 Nalin Dahyabhai <nalin@redhat.com> 1.6.3-13
+- ftp: use the correct local filename during mget when the 'case' option is
+  enabled (#442713)
+
+* Fri Apr  4 2008 Nalin Dahyabhai <nalin@redhat.com> 1.6.3-12
+- stop exporting kadmin keys to a keytab file when kadmind starts -- the
+  daemon's been able to use the database directly for a long long time now
+- belatedly add aes128,aes256 to the default set of supported key types
+
+* Tue Apr  1 2008 Nalin Dahyabhai <nalin@redhat.com> 1.6.3-11
+- libgssapi_krb5: properly export the acceptor subkey when creating a lucid
+  context (Kevin Coffman, via the nfs4 mailing list)
+
+* Tue Mar 18 2008 Nalin Dahyabhai <nalin@redhat.com> 1.6.3-10
+- add fixes from MITKRB5-SA-2008-001 for use of null or dangling pointer
+  when v4 compatibility is enabled on the KDC (CVE-2008-0062, CVE-2008-0063,
+  #432620, #432621)
+- add fixes from MITKRB5-SA-2008-002 for array out-of-bounds accesses when
+  high-numbered descriptors are used (CVE-2008-0947, #433596)
+- add backport bug fix for an attempt to free non-heap memory in
+  libgssapi_krb5 (CVE-2007-5901, #415321)
+- add backport bug fix for a double-free in out-of-memory situations in
+  libgssapi_krb5 (CVE-2007-5971, #415351)
+
+* Tue Mar 18 2008 Nalin Dahyabhai <nalin@redhat.com> 1.6.3-9
+- rework file labeling patch to not depend on fragile preprocessor trickery,
+  in another attempt at fixing #428355 and friends
+
+* Tue Feb 26 2008 Nalin Dahyabhai <nalin@redhat.com> 1.6.3-8
+- ftp: add patch to fix "runique on" case when globbing fixes applied
+- stop adding a redundant but harmless call to initialize the gssapi internals
+
+* Mon Feb 25 2008 Nalin Dahyabhai <nalin@redhat.com>
+- add patch to suppress double-processing of /etc/krb5.conf when we build
+  with --sysconfdir=/etc, thereby suppressing double-logging (#231147)
+
+* Mon Feb 25 2008 Nalin Dahyabhai <nalin@redhat.com>
+- remove a patch, to fix problems with interfaces which are "up" but which
+  have no address assigned, which conflicted with a different fix for the same
+  problem in 1.5 (#200979)
+
+* Mon Feb 25 2008 Nalin Dahyabhai <nalin@redhat.com>
+- ftp: don't lose track of a descriptor on passive get when the server fails to
+  open a file
+
+* Mon Feb 25 2008 Nalin Dahyabhai <nalin@redhat.com>
+- in login, allow PAM to interact with the user when they've been strongly
+  authenticated
+- in login, signal PAM when we're changing an expired password that it's an
+  expired password, so that when cracklib flags a password as being weak it's
+  treated as an error even if we're running as root
+
+* Mon Feb 18 2008 Nalin Dahyabhai <nalin@redhat.com> 1.6.3-7
+- drop netdb patch
+- kdb_ldap: add patch to treat 'nsAccountLock: true' as an indication that
+  the DISALLOW_ALL_TIX flag is set on an entry, for better interop with Fedora,
+  Netscape, Red Hat Directory Server (Simo Sorce)
+
+* Wed Feb 13 2008 Nalin Dahyabhai <nalin@redhat.com> 1.6.3-6
+- patch to avoid depending on <netdb.h> to define NI_MAXHOST and NI_MAXSERV
+
+* Tue Feb 12 2008 Nalin Dahyabhai <nalin@redhat.com> 1.6.3-5
+- enable patch for key-expiration reporting
+- enable patch to make kpasswd fall back to TCP if UDP fails (#251206)
+- enable patch to make kpasswd use the right sequence number on retransmit
+- enable patch to allow mech-specific creds delegated under spnego to be found
+  when searching for creds
+
+* Wed Jan  2 2008 Nalin Dahyabhai <nalin@redhat.com> 1.6.3-4
+- some init script cleanups
+  - drop unquoted check and silent exit for "$NETWORKING" (#426852, #242502)
+  - krb524: don't barf on missing database if it looks like we're using kldap,
+    same as for kadmin
+  - return non-zero status for missing files which cause startup to
+    fail (#242502)
+
+* Tue Dec 18 2007 Nalin Dahyabhai <nalin@redhat.com> 1.6.3-3
+- allocate space for the nul-terminator in the local pathname when looking up
+  a file context, and properly free a previous context (Jose Plans, #426085)
+
+* Wed Dec  5 2007 Nalin Dahyabhai <nalin@redhat.com> 1.6.3-2
+- rebuild
+
+* Tue Oct 23 2007 Nalin Dahyabhai <nalin@redhat.com> 1.6.3-1
+- update to 1.6.3, dropping now-integrated patches for CVE-2007-3999
+  and CVE-2007-4000 (the new pkinit module is built conditionally and goes
+  into the -pkinit-openssl package, at least for now, to make a buildreq
+  loop with openssl avoidable)
+
+* Wed Oct 17 2007 Nalin Dahyabhai <nalin@redhat.com> 1.6.2-10
+- make proper use of pam_loginuid and pam_selinux in rshd and ftpd
+
+* Fri Oct 12 2007 Nalin Dahyabhai <nalin@redhat.com>
+- make krb5.conf %%verify(not md5 size mtime) in addition to
+  %%config(noreplace), like /etc/nsswitch.conf (#329811)
+
+* Mon Oct  1 2007 Nalin Dahyabhai <nalin@redhat.com> 1.6.2-9
+- apply the fix for CVE-2007-4000 instead of the experimental patch for
+  setting ok-as-delegate flags
+
+* Tue Sep 11 2007 Nalin Dahyabhai <nalin@redhat.com> 1.6.2-8
+- move the db2 kdb plugin from -server to -libs, because a multilib libkdb
+  might need it
+
+* Tue Sep 11 2007 Nalin Dahyabhai <nalin@redhat.com> 1.6.2-7
+- also perform PAM session and credential management when ftpd accepts a
+  client using strong authentication, missed earlier
+- also label kadmind log files and files created by the db2 plugin
+
+* Thu Sep  6 2007 Nalin Dahyabhai <nalin@redhat.com> 1.6.2-6
+- incorporate updated fix for CVE-2007-3999 (CVE-2007-4743)
+- fix incorrect call to "test" in the kadmin init script (#252322,#287291)
+
+* Tue Sep  4 2007 Nalin Dahyabhai <nalin@redhat.com> 1.6.2-5
+- incorporate fixes for MITKRB5-SA-2007-006 (CVE-2007-3999, CVE-2007-4000)
+
+* Sat Aug 25 2007 Nalin Dahyabhai <nalin@redhat.com> 1.6.2-4
+- cover more cases in labeling files on creation
+- add missing gawk build dependency
+
+* Thu Aug 23 2007 Nalin Dahyabhai <nalin@redhat.com> 1.6.2-3
+- rebuild
+
+* Thu Jul 26 2007 Nalin Dahyabhai <nalin@redhat.com> 1.6.2-2
+- kdc.conf: default to listening for TCP clients, too (#248415)
+
+* Thu Jul 19 2007 Nalin Dahyabhai <nalin@redhat.com> 1.6.2-1
+- update to 1.6.2
+- add "buildrequires: texinfo-tex" to get texi2pdf
+
+* Wed Jun 27 2007 Nalin Dahyabhai <nalin@redhat.com> 1.6.1-8
+- incorporate fixes for MITKRB5-SA-2007-004 (CVE-2007-2442,CVE-2007-2443)
+  and MITKRB5-SA-2007-005 (CVE-2007-2798)
+
+* Mon Jun 25 2007 Nalin Dahyabhai <nalin@redhat.com> 1.6.1-7
+- reintroduce missing %%postun for the non-split_workstation case
+
+* Mon Jun 25 2007 Nalin Dahyabhai <nalin@redhat.com> 1.6.1-6
+- rebuild
+
+* Mon Jun 25 2007 Nalin Dahyabhai <nalin@redhat.com> 1.6.1-5.1
+- rebuild
+
+* Sun Jun 24 2007 Nalin Dahyabhai <nalin@redhat.com> 1.6.1-5
+- add missing pam-devel build requirement, force selinux-or-fail build
+
+* Sun Jun 24 2007 Nalin Dahyabhai <nalin@redhat.com> 1.6.1-4
+- rebuild
+
+* Sun Jun 24 2007 Nalin Dahyabhai <nalin@redhat.com> 1.6.1-3
+- label all files at creation-time according to the SELinux policy (#228157)
+
+* Fri Jun 22 2007 Nalin Dahyabhai <nalin@redhat.com>
+- perform PAM account / session management in krshd (#182195,#195922)
+- perform PAM authentication and account / session management in ftpd
+- perform PAM authentication, account / session management, and password-
+  changing in login.krb5 (#182195,#195922)
+
+* Fri Jun 22 2007 Nalin Dahyabhai <nalin@redhat.com>
+- preprocess kerberos.ldif into a format FDS will like better, and include
+  that as a doc file as well
+
+* Fri Jun 22 2007 Nalin Dahyabhai <nalin@redhat.com>
+- switch man pages to being generated with the right paths in them
+- drop old, incomplete SELinux patch
+- add patch from Greg Hudson to make srvtab routines report missing-file errors
+  at same point that keytab routines do (#241805)
+
+* Thu May 24 2007 Nalin Dahyabhai <nalin@redhat.com> 1.6.1-2
+- pull patch from svn to undo unintentional chattiness in ftp
+- pull patch from svn to handle NULL krb5_get_init_creds_opt structures
+  better in a couple of places where they're expected
+
+* Wed May 23 2007 Nalin Dahyabhai <nalin@redhat.com> 1.6.1-1
+- update to 1.6.1
+  - drop no-longer-needed patches for CVE-2007-0956,CVE-2007-0957,CVE-2007-1216
+  - drop patch for sendto bug in 1.6, fixed in 1.6.1
+
+* Fri May 18 2007 Nalin Dahyabhai <nalin@redhat.com>
+- kadmind.init: don't fail outright if the default principal database
+  isn't there if it looks like we might be using the kldap plugin
+- kadmind.init: attempt to extract the key for the host-specific kadmin
+  service when we try to create the keytab
+
+* Wed May 16 2007 Nalin Dahyabhai <nalin@redhat.com> 1.6-6
+- omit dependent libraries from the krb5-config --libs output, as using
+  shared libraries (no more static libraries) makes them unnecessary and
+  they're not part of the libkrb5 interface (patch by Rex Dieter, #240220)
+  (strips out libkeyutils, libresolv, libdl)
+
+* Fri May  4 2007 Nalin Dahyabhai <nalin@redhat.com> 1.6-5
+- pull in keyutils as a build requirement to get the "KEYRING:" ccache type,
+  because we've merged
+
+* Fri May  4 2007 Nalin Dahyabhai <nalin@redhat.com> 1.6-4
+- fix an uninitialized length value which could cause a crash when parsing
+  key data coming from a directory server
+- correct a typo in the krb5.conf man page ("ldap_server"->"ldap_servers")
+
+* Fri Apr 13 2007 Nalin Dahyabhai <nalin@redhat.com>
+- move the default acl_file, dict_file, and admin_keytab settings to
+  the part of the default/example kdc.conf where they'll actually have
+  an effect (#236417)
+
+* Thu Apr  5 2007 Nalin Dahyabhai <nalin@redhat.com> 1.5-24
+- merge security fixes from RHSA-2007:0095
+
+* Tue Apr  3 2007 Nalin Dahyabhai <nalin@redhat.com> 1.6-3
+- add patch to correct unauthorized access via krb5-aware telnet
+  daemon (#229782, CVE-2007-0956)
+- add patch to fix buffer overflow in krb5kdc and kadmind
+  (#231528, CVE-2007-0957)
+- add patch to fix double-free in kadmind (#231537, CVE-2007-1216)
+
+* Thu Mar 22 2007 Nalin Dahyabhai <nalin@redhat.com>
+- back out buildrequires: keyutils-libs-devel for now
+
+* Thu Mar 22 2007 Nalin Dahyabhai <nalin@redhat.com> 1.6-2
+- add buildrequires: on keyutils-libs-devel to enable use of keyring ccaches,
+  dragging keyutils-libs in as a dependency
+
+* Mon Mar 19 2007 Nalin Dahyabhai <nalin@redhat.com> 1.5-23
+- fix bug ID in changelog
+
+* Thu Mar 15 2007 Nalin Dahyabhai <nalin@redhat.com> 1.5-22
+
+* Thu Mar 15 2007 Nalin Dahyabhai <nalin@redhat.com> 1.5-21
+- add preliminary patch to fix buffer overflow in krb5kdc and kadmind
+  (#231528, CVE-2007-0957)
+- add preliminary patch to fix double-free in kadmind (#231537, CVE-2007-1216)
+
+* Wed Feb 28 2007 Nalin Dahyabhai <nalin@redhat.com>
+- add patch to build semi-useful static libraries, but don't apply it unless
+  we need them
+
+* Tue Feb 27 2007 Nalin Dahyabhai <nalin@redhat.com> - 1.5-20
+- temporarily back out %%post changes, fix for #143289 for security update
+- add preliminary patch to correct unauthorized access via krb5-aware telnet
+
+* Mon Feb 19 2007 Nalin Dahyabhai <nalin@redhat.com>
+- make profile.d scriptlets mode 644 instead of 755 (part of #225974)
+
+* Tue Jan 30 2007 Nalin Dahyabhai <nalin@redhat.com> 1.6-1
+- clean up quoting of command-line arguments passed to the krsh/krlogin
+  wrapper scripts
+
+* Mon Jan 22 2007 Nalin Dahyabhai <nalin@redhat.com>
+- initial update to 1.6, pre-package-reorg
+- move workstation daemons to a new subpackage (#81836, #216356, #217301), and
+  make the new subpackage require xinetd (#211885)
+
+* Mon Jan 22 2007 Nalin Dahyabhai <nalin@redhat.com> - 1.5-18
+- make use of install-info more failsafe (Ville Skyttä, #223704)
+- preserve timestamps on shell scriptlets at %%install-time
+
+* Tue Jan 16 2007 Nalin Dahyabhai <nalin@redhat.com> - 1.5-17
+- move to using pregenerated PDF docs to cure multilib conflicts (#222721)
+
+* Fri Jan 12 2007 Nalin Dahyabhai <nalin@redhat.com> - 1.5-16
+- update backport of the preauth module interface (part of #194654)
+
+* Tue Jan  9 2007 Nalin Dahyabhai <nalin@redhat.com> - 1.5-14
+- apply fixes from Tom Yu for MITKRB5-SA-2006-002 (CVE-2006-6143) (#218456)
+- apply fixes from Tom Yu for MITKRB5-SA-2006-003 (CVE-2006-6144) (#218456)
+
+* Wed Dec 20 2006 Nalin Dahyabhai <nalin@redhat.com> - 1.5-12
+- update backport of the preauth module interface
+
+* Mon Oct 30 2006 Nalin Dahyabhai <nalin@redhat.com>
+- update backport of the preauth module interface
+- add proposed patches 4566, 4567
+- add proposed edata reporting interface for KDC
+- add temporary placeholder for module global context fixes
+
+* Mon Oct 23 2006 Nalin Dahyabhai <nalin@redhat.com> - 1.5-11
+- don't bail from the KDC init script if there's no database, it may be in
+  a different location than the default (fenlason)
+- remove the [kdc] section from the default krb5.conf -- doesn't seem to have
+  been applicable for a while
+
+* Wed Oct 18 2006 Nalin Dahyabhai <nalin@redhat.com> - 1.5-10
+- rename krb5.sh and krb5.csh so that they don't overlap (#210623)
+- way-late application of added error info in kadmind.init (#65853)
+
+* Wed Oct 18 2006 Nalin Dahyabhai <nalin@redhat.com> - 1.5-9.pal_18695
+- add backport of in-development preauth module interface (#208643)
+
+* Mon Oct  9 2006 Nalin Dahyabhai <nalin@redhat.com> - 1.5-9
+- provide docs in PDF format instead of as tex source (Enrico Scholz, #209943)
+
+* Wed Oct  4 2006 Nalin Dahyabhai <nalin@redhat.com> - 1.5-8
+- add missing shebang headers to krsh and krlogin wrapper scripts (#209238)
+
+* Wed Sep  6 2006 Nalin Dahyabhai <nalin@redhat.com> - 1.5-7
+- set SS_LIB at configure-time so that libss-using apps get working readline
+  support (#197044)
+
+* Fri Aug 18 2006 Nalin Dahyabhai <nalin@redhat.com> - 1.5-6
+- switch to the updated patch for MITKRB-SA-2006-001
+
+* Tue Aug  8 2006 Nalin Dahyabhai <nalin@redhat.com> - 1.5-5
+- apply patch to address MITKRB-SA-2006-001 (CVE-2006-3084)
+
+* Mon Aug  7 2006 Nalin Dahyabhai <nalin@redhat.com> - 1.5-4
+- ensure that the gssapi library's been initialized before walking the
+  internal mechanism list in gss_release_oid(), needed if called from
+  gss_release_name() right after a gss_import_name() (#198092)
+
+* Tue Jul 25 2006 Nalin Dahyabhai <nalin@redhat.com> - 1.5-3
+- rebuild
+
+* Tue Jul 25 2006 Nalin Dahyabhai <nalin@redhat.com> - 1.5-2
+- pull up latest revision of patch to reduce lockups in rsh/rshd
+
+* Mon Jul 17 2006 Nalin Dahyabhai <nalin@redhat.com> - 1.5-1.2
+- rebuild
+
+* Wed Jul 12 2006 Jesse Keating <jkeating@redhat.com> - 1.5-1.1
+- rebuild
+
+* Thu Jul  6 2006 Nalin Dahyabhai <nalin@redhat.com> 1.5-1
+- build
+
+* Wed Jul  5 2006 Nalin Dahyabhai <nalin@redhat.com> 1.5-0
+- update to 1.5
+
+* Fri Jun 23 2006 Nalin Dahyabhai <nalin@redhat.com> 1.4.3-9
+- mark profile.d config files noreplace (Laurent Rineau, #196447)
+
+* Thu Jun  8 2006 Nalin Dahyabhai <nalin@redhat.com> 1.4.3-8
+- add buildprereq for autoconf
+
+* Mon May 22 2006 Nalin Dahyabhai <nalin@redhat.com> 1.4.3-7
+- further munge krb5-config so that 'libdir=/usr/lib' is given even on 64-bit
+  architectures, to avoid multilib conflicts; other changes will conspire to
+  strip out the -L flag which uses this, so it should be harmless (#192692)
+
+* Fri Apr 28 2006 Nalin Dahyabhai <nalin@redhat.com> 1.4.3-6
+- adjust the patch which removes the use of rpath to also produce a
+  krb5-config which is okay in multilib environments (#190118)
+- make the name-of-the-tempfile comment which compile_et adds to error code
+  headers always list the same file to avoid conflicts on multilib installations
+- strip SIZEOF_LONG out of krb5.h so that it doesn't conflict on multilib boxes
+- strip GSS_SIZEOF_LONG out of gssapi.h so that it doesn't conflict on mulitlib
+  boxes
+
+* Fri Apr 14 2006 Stepan Kasal <skasal@redhat.com> 1.4.3-5
+- Fix formatting typo in kinit.1 (krb5-kinit-man-typo.patch)
+
+* Fri Feb 10 2006 Jesse Keating <jkeating@redhat.com> 1.4.3-4.1
+- bump again for double-long bug on ppc(64)
+
+* Mon Feb  6 2006 Nalin Dahyabhai <nalin@redhat.com> 1.4.3-4
+- give a little bit more information to the user when kinit gets the catch-all
+  I/O error (#180175)
+
+* Thu Jan 19 2006 Nalin Dahyabhai <nalin@redhat.com> 1.4.3-3
+- rebuild properly when pthread_mutexattr_setrobust_np() is defined but not
+  declared, such as with recent glibc when _GNU_SOURCE isn't being used
+
+* Thu Jan 19 2006 Matthias Clasen <mclasen@redhat.com> 1.4.3-2
+- Use full paths in krb5.sh to avoid path lookups
+
+* Fri Dec 09 2005 Jesse Keating <jkeating@redhat.com>
+- rebuilt
+
+* Thu Dec  1 2005 Nalin Dahyabhai <nalin@redhat.com>
+- login: don't truncate passwords before passing them into crypt(), in
+  case they're significant (#149476)
+
+* Thu Nov 17 2005 Nalin Dahyabhai <nalin@redhat.com> 1.4.3-1
+- update to 1.4.3
+- make ksu setuid again (#137934, others)
+
+* Tue Sep 13 2005 Nalin Dahyabhai <nalin@redhat.com> 1.4.2-4
+- mark %%{krb5prefix}/man so that files which are packaged within it are
+  flagged as %%doc (#168163)
+
+* Tue Sep  6 2005 Nalin Dahyabhai <nalin@redhat.com> 1.4.2-3
+- add an xinetd configuration file for encryption-only telnetd, parallelling
+  the kshell/ekshell pair (#167535)
+
+* Wed Aug 31 2005 Nalin Dahyabhai <nalin@redhat.com> 1.4.2-2
+- change the default configured encryption type for KDC databases to the
+  compiled-in default of des3-hmac-sha1 (#57847)
+
+* Thu Aug 11 2005 Nalin Dahyabhai <nalin@redhat.com> 1.4.2-1
+- update to 1.4.2, incorporating the fixes for MIT-KRB5-SA-2005-002 and
+  MIT-KRB5-SA-2005-003
+
+* Wed Jun 29 2005 Nalin Dahyabhai <nalin@redhat.com> 1.4.1-6
+- rebuild
+
+* Wed Jun 29 2005 Nalin Dahyabhai <nalin@redhat.com> 1.4.1-5
+- fix telnet client environment variable disclosure the same way NetKit's
+  telnet client did (CAN-2005-0488) (#159305)
+- keep apps which call krb5_principal_compare() or krb5_realm_compare() with
+  malformed or NULL principal structures from crashing outright (Thomas Biege)
+  (#161475)
+
+* Tue Jun 28 2005 Nalin Dahyabhai <nalin@redhat.com>
+- apply fixes from draft of MIT-KRB5-SA-2005-002 (CAN-2005-1174,CAN-2005-1175)
+  (#157104)
+- apply fixes from draft of MIT-KRB5-SA-2005-003 (CAN-2005-1689) (#159755)
+
+* Fri Jun 24 2005 Nalin Dahyabhai <nalin@redhat.com> 1.4.1-4
+- fix double-close in keytab handling
+- add port of fixes for CAN-2004-0175 to krb5-aware rcp (#151612)
+
+* Fri May 13 2005 Nalin Dahyabhai <nalin@redhat.com> 1.4.1-3
+- prevent spurious EBADF in krshd when stdin is closed by the client while
+  the command is running (#151111)
+
+* Fri May 13 2005 Martin Stransky <stransky@redhat.com> 1.4.1-2
+- add deadlock patch, removed old patch
+
+* Fri May  6 2005 Nalin Dahyabhai <nalin@redhat.com> 1.4.1-1
+- update to 1.4.1, incorporating fixes for CAN-2005-0468 and CAN-2005-0469
+- when starting the KDC or kadmind, if KRB5REALM is set via the /etc/sysconfig
+  file for the service, pass it as an argument for the -r flag
+
+* Wed Mar 23 2005 Nalin Dahyabhai <nalin@redhat.com> 1.4-3
+- drop krshd patch for now
+
+* Thu Mar 17 2005 Nalin Dahyabhai <nalin@redhat.com>
+- add draft fix from Tom Yu for slc_add_reply() buffer overflow (CAN-2005-0469)
+- add draft fix from Tom Yu for env_opt_add() buffer overflow (CAN-2005-0468)
+
+* Wed Mar 16 2005 Nalin Dahyabhai <nalin@redhat.com> 1.4-2
+- don't include <term.h> into the telnet client when we're not using curses
+
+* Thu Feb 24 2005 Nalin Dahyabhai <nalin@redhat.com> 1.4-1
+- update to 1.4
+  - v1.4 kadmin client requires a v1.4 kadmind on the server, or use the "-O"
+    flag to specify that it should communicate with the server using the older
+    protocol
+  - new libkrb5support library
+  - v5passwdd and kadmind4 are gone
+  - versioned symbols
+- pick up $KRB5KDC_ARGS from /etc/sysconfig/krb5kdc, if it exists, and pass
+  it on to krb5kdc
+- pick up $KADMIND_ARGS from /etc/sysconfig/kadmin, if it exists, and pass
+  it on to kadmind
+- pick up $KRB524D_ARGS from /etc/sysconfig/krb524, if it exists, and pass
+  it on to krb524d *instead of* "-m"
+- set "forwardable" in [libdefaults] in the default krb5.conf to match the
+  default setting which we supply for pam_krb5
+- set a default of 24h for "ticket_lifetime" in [libdefaults], reflecting the
+  compiled-in default
+
+* Mon Dec 20 2004 Nalin Dahyabhai <nalin@redhat.com> 1.3.6-3
+- rebuild
+
+* Mon Dec 20 2004 Nalin Dahyabhai <nalin@redhat.com> 1.3.6-2
+- rebuild
+
+* Mon Dec 20 2004 Nalin Dahyabhai <nalin@redhat.com> 1.3.6-1
+- update to 1.3.6, which includes the previous fix
+
+* Mon Dec 20 2004 Nalin Dahyabhai <nalin@redhat.com> 1.3.5-8
+- apply fix from Tom Yu for MITKRB5-SA-2004-004 (CAN-2004-1189)
+
+* Fri Dec 17 2004 Martin Stransky <stransky@redhat.com> 1.3.5-7
+- fix deadlock during file transfer via rsync/krsh
+- thanks goes to James Antill for hint
+
+* Fri Nov 26 2004 Nalin Dahyabhai <nalin@redhat.com> 1.3.5-6
+- rebuild
+
+* Mon Nov 22 2004 Nalin Dahyabhai <nalin@redhat.com> 1.3.5-3
+- fix predictable-tempfile-name bug in krb5-send-pr (CAN-2004-0971, #140036)
+
+* Tue Nov 16 2004 Nalin Dahyabhai <nalin@redhat.com>
+- silence compiler warning in kprop by using an in-memory ccache with a fixed
+  name instead of an on-disk ccache with a name generated by tmpnam()
+
+* Tue Nov 16 2004 Nalin Dahyabhai <nalin@redhat.com> 1.3.5-2
+- fix globbing patch port mode (#139075)
+
+* Mon Nov  1 2004 Nalin Dahyabhai <nalin@redhat.com> 1.3.5-1
+- fix segfault in telnet due to incorrect checking of gethostbyname_r result
+  codes (#129059)
+
+* Fri Oct 15 2004 Nalin Dahyabhai <nalin@redhat.com>
+- remove rc4-hmac:norealm and rc4-hmac:onlyrealm from the default list of
+  supported keytypes in kdc.conf -- they produce exactly the same keys as
+  rc4-hmac:normal because rc4 string-to-key ignores salts
+- nuke kdcrotate -- there are better ways to balance the load on KDCs, and
+  the SELinux policy for it would have been scary-looking
+- update to 1.3.5, mainly to include MITKRB5SA 2004-002 and 2004-003
+
+* Tue Aug 31 2004 Nalin Dahyabhai <nalin@redhat.com> 1.3.4-7
+- rebuild
+
+* Tue Aug 24 2004 Nalin Dahyabhai <nalin@redhat.com> 1.3.4-6
+- rebuild
+
+* Tue Aug 24 2004 Nalin Dahyabhai <nalin@redhat.com> 1.3.4-5
+- incorporate revised fixes from Tom Yu for CAN-2004-0642, CAN-2004-0644,
+  CAN-2004-0772
+
+* Mon Aug 23 2004 Nalin Dahyabhai <nalin@redhat.com> 1.3.4-4
+- rebuild
+
+* Mon Aug 23 2004 Nalin Dahyabhai <nalin@redhat.com> 1.3.4-3
+- incorporate fixes from Tom Yu for CAN-2004-0642, CAN-2004-0772
+  (MITKRB5-SA-2004-002, #130732)
+- incorporate fixes from Tom Yu for CAN-2004-0644 (MITKRB5-SA-2004-003, #130732)
+
+* Tue Jul 27 2004 Nalin Dahyabhai <nalin@redhat.com> 1.3.4-2
+- fix indexing error in server sorting patch (#127336)
+
+* Tue Jun 15 2004 Elliot Lee <sopwith@redhat.com>
+- rebuilt
+
+* Mon Jun 14 2004 Nalin Dahyabhai <nalin@redhat.com> 1.3.4-0.1
+- update to 1.3.4 final
+
+* Mon Jun  7 2004 Nalin Dahyabhai <nalin@redhat.com> 1.3.4-0
+- update to 1.3.4 beta1
+- remove MITKRB5-SA-2004-001, included in 1.3.4
+
+* Mon Jun  7 2004 Nalin Dahyabhai <nalin@redhat.com> 1.3.3-8
+- rebuild
+
+* Fri Jun  4 2004 Nalin Dahyabhai <nalin@redhat.com> 1.3.3-7
+- rebuild
+
+* Fri Jun  4 2004 Nalin Dahyabhai <nalin@redhat.com> 1.3.3-6
+- apply updated patch from MITKRB5-SA-2004-001 (revision 2004-06-02)
+
+* Tue Jun  1 2004 Nalin Dahyabhai <nalin@redhat.com> 1.3.3-5
+- rebuild
+
+* Tue Jun  1 2004 Nalin Dahyabhai <nalin@redhat.com> 1.3.3-4
+- apply patch from MITKRB5-SA-2004-001 (#125001)
+
+* Wed May 12 2004 Thomas Woerner <twoerner@redhat.com> 1.3.3-3
+- removed rpath
+
+* Thu Apr 15 2004 Nalin Dahyabhai <nalin@redhat.com> 1.3.3-2
+- re-enable large file support, fell out in 1.3-1
+- patch rcp to use long long and %%lld format specifiers when reporting file
+  sizes on large files
+
+* Tue Apr 13 2004 Nalin Dahyabhai <nalin@redhat.com> 1.3.3-1
+- update to 1.3.3
+
+* Wed Mar 10 2004 Nalin Dahyabhai <nalin@redhat.com> 1.3.2-1
+- update to 1.3.2
+
+* Mon Mar  8 2004 Nalin Dahyabhai <nalin@redhat.com> 1.3.1-12
+- rebuild
+
+* Tue Mar 02 2004 Elliot Lee <sopwith@redhat.com> 1.3.1-11.1
+- rebuilt
+
+* Fri Feb 13 2004 Elliot Lee <sopwith@redhat.com> 1.3.1-11
+- rebuilt
+
+* Mon Feb  9 2004 Nalin Dahyabhai <nalin@redhat.com> 1.3.1-10
+- catch krb4 send_to_kdc cases in kdc preference patch
+
+* Mon Feb  2 2004 Nalin Dahyabhai <nalin@redhat.com> 1.3.1-9
+- remove patch to set TERM in klogind which, combined with the upstream fix in
+  1.3.1, actually produces the bug now (#114762)
+
+* Mon Jan 19 2004 Nalin Dahyabhai <nalin@redhat.com> 1.3.1-8
+- when iterating over lists of interfaces which are "up" from getifaddrs(),
+  skip over those which have no address (#113347)
+
+* Mon Jan 12 2004 Nalin Dahyabhai <nalin@redhat.com>
+- prefer the kdc which last replied to a request when sending requests to kdcs
+
+* Mon Nov 24 2003 Nalin Dahyabhai <nalin@redhat.com> 1.3.1-7
+- fix combination of --with-netlib and --enable-dns (#82176)
+
+* Tue Nov 18 2003 Nalin Dahyabhai <nalin@redhat.com>
+- remove libdefault ticket_lifetime option from the default krb5.conf, it is
+  ignored by libkrb5
+
+* Thu Sep 25 2003 Nalin Dahyabhai <nalin@redhat.com> 1.3.1-6
+- fix bug in patch to make rlogind start login with a clean environment a la
+  netkit rlogin, spotted and fixed by Scott McClung
+
+* Tue Sep 23 2003 Nalin Dahyabhai <nalin@redhat.com> 1.3.1-5
+- include profile.d scriptlets in krb5-devel so that krb5-config will be in
+  the path if krb5-workstation isn't installed, reported by Kir Kolyshkin
+
+* Mon Sep  8 2003 Nalin Dahyabhai <nalin@redhat.com>
+- add more etypes (arcfour) to the default enctype list in kdc.conf
+- don't apply previous patch, refused upstream
+
+* Fri Sep  5 2003 Nalin Dahyabhai <nalin@redhat.com> 1.3.1-4
+- fix 32/64-bit bug storing and retrieving the issue_date in v4 credentials
+
+* Wed Sep 3 2003 Dan Walsh <dwalsh@redhat.com> 1.3.1-3
+- Don't check for write access on /etc/krb5.conf if SELinux
+
+* Tue Aug 26 2003 Nalin Dahyabhai <nalin@redhat.com> 1.3.1-2
+- fixup some int/pointer varargs wackiness
+
+* Tue Aug  5 2003 Nalin Dahyabhai <nalin@redhat.com> 1.3.1-1
+- rebuild
+
+* Mon Aug  4 2003 Nalin Dahyabhai <nalin@redhat.com> 1.3.1-0
+- update to 1.3.1
+
+* Thu Jul 24 2003 Nalin Dahyabhai <nalin@redhat.com> 1.3-2
+- pull fix for non-compliant encoding of salt field in etype-info2 preauth
+  data from 1.3.1 beta 1, until 1.3.1 is released.
+
+* Mon Jul 21 2003 Nalin Dahyabhai <nalin@redhat.com> 1.3-1
+- update to 1.3
+
+* Mon Jul  7 2003 Nalin Dahyabhai <nalin@redhat.com> 1.2.8-4
+- correctly use stdargs
+
+* Wed Jun 18 2003 Nalin Dahyabhai <nalin@redhat.com> 1.3-0.beta.4
+- test update to 1.3 beta 4
+- ditch statglue build option
+- krb5-devel requires e2fsprogs-devel, which now provides libss and libcom_err
+
+* Wed Jun 04 2003 Elliot Lee <sopwith@redhat.com>
+- rebuilt
+
+* Wed May 21 2003 Jeremy Katz <katzj@redhat.com> 1.2.8-2
+- gcc 3.3 doesn't implement varargs.h, include stdarg.h instead
+
+* Wed Apr  9 2003 Nalin Dahyabhai <nalin@redhat.com> 1.2.8-1
+- update to 1.2.8
+
+* Mon Mar 31 2003 Nalin Dahyabhai <nalin@redhat.com> 1.2.7-14
+- fix double-free of enc_part2 in krb524d
+
+* Fri Mar 21 2003 Nalin Dahyabhai <nalin@redhat.com> 1.2.7-13
+- update to latest patch kit for MITKRB5-SA-2003-004
+
+* Wed Mar 19 2003 Nalin Dahyabhai <nalin@redhat.com> 1.2.7-12
+- add patch included in MITKRB5-SA-2003-003 (CAN-2003-0028)
+
+* Mon Mar 17 2003 Nalin Dahyabhai <nalin@redhat.com> 1.2.7-11
+- add patches from patchkit from MITKRB5-SA-2003-004 (CAN-2003-0138 and
+  CAN-2003-0139)
+
+* Thu Mar  6 2003 Nalin Dahyabhai <nalin@redhat.com> 1.2.7-10
+- rebuild
+
+* Thu Mar  6 2003 Nalin Dahyabhai <nalin@redhat.com> 1.2.7-9
+- fix buffer underrun in unparsing certain principals (CAN-2003-0082)
+
+* Tue Feb  4 2003 Nalin Dahyabhai <nalin@redhat.com> 1.2.7-8
+- add patch to document the reject-bad-transited option in kdc.conf
+
+* Mon Feb  3 2003 Nalin Dahyabhai <nalin@redhat.com>
+- add patch to fix server-side crashes when principals have no
+  components (CAN-2003-0072)
+
+* Thu Jan 23 2003 Nalin Dahyabhai <nalin@redhat.com> 1.2.7-7
+- add patch from Mark Cox for exploitable bugs in ftp client
+
+* Wed Jan 22 2003 Tim Powers <timp@redhat.com>
+- rebuilt
+
+* Wed Jan 15 2003 Nalin Dahyabhai <nalin@redhat.com> 1.2.7-5
+- use PICFLAGS when building code from the ktany patch
+
+* Thu Jan  9 2003 Bill Nottingham <notting@redhat.com> 1.2.7-4
+- debloat
+
+* Tue Jan  7 2003 Jeremy Katz <katzj@redhat.com> 1.2.7-3
+- include .so.* symlinks as well as .so.*.*
+
+* Mon Dec  9 2002 Jakub Jelinek <jakub@redhat.com> 1.2.7-2
+- always #include <errno.h> to access errno, never do it directly
+- enable LFS on a bunch of other 32-bit arches
+
+* Wed Dec  4 2002 Nalin Dahyabhai <nalin@redhat.com>
+- increase the maximum name length allowed by kuserok() to the higher value
+  used in development versions
+
+* Mon Dec  2 2002 Nalin Dahyabhai <nalin@redhat.com>
+- install src/krb524/README as README.krb524 in the -servers package,
+  includes information about converting for AFS principals
+
+* Fri Nov 15 2002 Nalin Dahyabhai <nalin@redhat.com> 1.2.7-1
+- update to 1.2.7
+- disable use of tcl
+
+* Mon Nov 11 2002 Nalin Dahyabhai <nalin@redhat.com>
+- update to 1.2.7-beta2 (internal only, not for release), dropping dnsparse
+  and kadmind4 fixes
+
+* Wed Oct 23 2002 Nalin Dahyabhai <nalin@redhat.com> 1.2.6-5
+- add patch for buffer overflow in kadmind4 (not used by default)
+
+* Fri Oct 11 2002 Nalin Dahyabhai <nalin@redhat.com> 1.2.6-4
+- drop a hunk from the dnsparse patch which is actually redundant (thanks to
+  Tom Yu)
+
+* Wed Oct  9 2002 Nalin Dahyabhai <nalin@redhat.com> 1.2.6-3
+- patch to handle truncated dns responses
+
+* Mon Oct  7 2002 Nalin Dahyabhai <nalin@redhat.com> 1.2.6-2
+- remove hashless key types from the default kdc.conf, they're not supposed to
+  be there, noted by Sam Hartman on krbdev
+
+* Fri Sep 27 2002 Nalin Dahyabhai <nalin@redhat.com> 1.2.6-1
+- update to 1.2.6
+
+* Fri Sep 13 2002 Nalin Dahyabhai <nalin@redhat.com> 1.2.5-7
+- use %%{_lib} for the sake of multilib systems
+
+* Fri Aug  2 2002 Nalin Dahyabhai <nalin@redhat.com> 1.2.5-6
+- add patch from Tom Yu for exploitable bugs in rpc code used in kadmind
+
+* Tue Jul 23 2002 Nalin Dahyabhai <nalin@redhat.com> 1.2.5-5
+- fix bug in krb5.csh which would cause the path check to always succeed
+
+* Fri Jul 19 2002 Jakub Jelinek <jakub@redhat.com> 1.2.5-4
+- build even libdb.a with -fPIC and $RPM_OPT_FLAGS.
+
+* Fri Jun 21 2002 Tim Powers <timp@redhat.com>
+- automated rebuild
+
+* Sun May 26 2002 Tim Powers <timp@redhat.com>
+- automated rebuild
+
+* Wed May  1 2002 Nalin Dahyabhai <nalin@redhat.com> 1.2.5-1
+- update to 1.2.5
+- disable statglue
+
+* Fri Mar  1 2002 Nalin Dahyabhai <nalin@redhat.com> 1.2.4-1
+- update to 1.2.4
+
+* Wed Feb 20 2002 Nalin Dahyabhai <nalin@redhat.com> 1.2.3-5
+- rebuild in new environment
+- reenable statglue
+
+* Sat Jan 26 2002 Florian La Roche <Florian.LaRoche@redhat.de>
+- prereq chkconfig for the server subpackage
+
+* Wed Jan 16 2002 Nalin Dahyabhai <nalin@redhat.com> 1.2.3-3
+- build without -g3, which gives us large static libraries in -devel
+
+* Tue Jan 15 2002 Nalin Dahyabhai <nalin@redhat.com> 1.2.3-2
+- reintroduce ld.so.conf munging in the -libs %%post
+
+* Thu Jan 10 2002 Nalin Dahyabhai <nalin@redhat.com> 1.2.3-1
+- rename the krb5 package back to krb5-libs; the previous rename caused
+  something of an uproar
+- update to 1.2.3, which includes the FTP and telnetd fixes
+- configure without --enable-dns-for-kdc --enable-dns-for-realm, which now set
+  the default behavior instead of enabling the feature (the feature is enabled
+  by --enable-dns, which we still use)
+- reenable optimizations on Alpha
+- support more encryption types in the default kdc.conf (heads-up from post
+  to comp.protocols.kerberos by Jason Heiss)
+
+* Fri Aug  3 2001 Nalin Dahyabhai <nalin@redhat.com> 1.2.2-14
+- rename the krb5-libs package to krb5 (naming a subpackage -libs when there
+  is no main package is silly)
+- move defaults for PAM to the appdefaults section of krb5.conf -- this is
+  the area where the krb5_appdefault_* functions look for settings)
+- disable statglue (warning: breaks binary compatibility with previous
+  packages, but has to be broken at some point to work correctly with
+  unpatched versions built with newer versions of glibc)
+
+* Fri Aug  3 2001 Nalin Dahyabhai <nalin@redhat.com> 1.2.2-13
+- bump release number and rebuild
+
+* Wed Aug  1 2001 Nalin Dahyabhai <nalin@redhat.com>
+- add patch to fix telnetd vulnerability
+
+* Fri Jul 20 2001 Nalin Dahyabhai <nalin@redhat.com>
+- tweak statglue.c to fix stat/stat64 aliasing problems
+- be cleaner in use of gcc to build shlibs
+
+* Wed Jul 11 2001 Nalin Dahyabhai <nalin@redhat.com>
+- use gcc to build shared libraries
+
+* Wed Jun 27 2001 Nalin Dahyabhai <nalin@redhat.com>
+- add patch to support "ANY" keytab type (i.e.,
+  "default_keytab_name = ANY:FILE:/etc/krb5.keytab,SRVTAB:/etc/srvtab"
+  patch from Gerald Britton, #42551)
+- build with -D_FILE_OFFSET_BITS=64 to get large file I/O in ftpd (#30697)
+- patch ftpd to use long long and %%lld format specifiers to support the SIZE
+  command on large files (also #30697)
+- don't use LOG_AUTH as an option value when calling openlog() in ksu (#45965)
+- implement reload in krb5kdc and kadmind init scripts (#41911)
+- lose the krb5server init script (not using it any more)
+
+* Sun Jun 24 2001 Elliot Lee <sopwith@redhat.com>
+- Bump release + rebuild.
+
+* Tue May 29 2001 Nalin Dahyabhai <nalin@redhat.com>
+- pass some structures by address instead of on the stack in krb5kdc
+
+* Tue May 22 2001 Nalin Dahyabhai <nalin@redhat.com>
+- rebuild in new environment
+
+* Thu Apr 26 2001 Nalin Dahyabhai <nalin@redhat.com>
+- add patch from Tom Yu to fix ftpd overflows (#37731)
+
+* Wed Apr 18 2001 Than Ngo <than@redhat.com>
+- disable optimizations on the alpha again
+
+* Fri Mar 30 2001 Nalin Dahyabhai <nalin@redhat.com>
+- add in glue code to make sure that libkrb5 continues to provide a
+  weak copy of stat()
+
+* Thu Mar 15 2001 Nalin Dahyabhai <nalin@redhat.com>
+- build alpha with -O0 for now
+
+* Thu Mar  8 2001 Nalin Dahyabhai <nalin@redhat.com>
+- fix the kpropd init script
+
+* Mon Mar  5 2001 Nalin Dahyabhai <nalin@redhat.com>
+- update to 1.2.2, which fixes some bugs relating to empty ETYPE-INFO
+- re-enable optimization on Alpha
+
+* Thu Feb  8 2001 Nalin Dahyabhai <nalin@redhat.com>
+- build alpha with -O0 for now
+- own %%{_var}/kerberos
+
+* Tue Feb  6 2001 Nalin Dahyabhai <nalin@redhat.com>
+- own the directories which are created for each package (#26342)
+
+* Tue Jan 23 2001 Nalin Dahyabhai <nalin@redhat.com>
+- gettextize init scripts
+
+* Fri Jan 19 2001 Nalin Dahyabhai <nalin@redhat.com>
+- add some comments to the ksu patches for the curious
+- re-enable optimization on alphas
+
+* Mon Jan 15 2001 Nalin Dahyabhai <nalin@redhat.com>
+- fix krb5-send-pr (#18932) and move it from -server to -workstation
+- buildprereq libtermcap-devel
+- temporariliy disable optimization on alphas
+- gettextize init scripts
+
+* Tue Dec  5 2000 Nalin Dahyabhai <nalin@redhat.com>
+- force -fPIC
+
+* Fri Dec  1 2000 Nalin Dahyabhai <nalin@redhat.com>
+- rebuild in new environment
+
+* Tue Oct 31 2000 Nalin Dahyabhai <nalin@redhat.com>
+- add bison as a BuildPrereq (#20091)
+
+* Mon Oct 30 2000 Nalin Dahyabhai <nalin@redhat.com>
+- change /usr/dict/words to /usr/share/dict/words in default kdc.conf (#20000)
+
+* Thu Oct  5 2000 Nalin Dahyabhai <nalin@redhat.com>
+- apply kpasswd bug fixes from David Wragg
+
+* Wed Oct  4 2000 Nalin Dahyabhai <nalin@redhat.com>
+- make krb5-libs obsolete the old krb5-configs package (#18351)
+- don't quit from the kpropd init script if there's no principal database so
+  that you can propagate the first time without running kpropd manually
+- don't complain if /etc/ld.so.conf doesn't exist in the -libs %%post
+
+* Tue Sep 12 2000 Nalin Dahyabhai <nalin@redhat.com>
+- fix credential forwarding problem in klogind (goof in KRB5CCNAME handling)
+  (#11588)
+- fix heap corruption bug in FTP client (#14301)
+
+* Wed Aug 16 2000 Nalin Dahyabhai <nalin@redhat.com>
+- fix summaries and descriptions
+- switched the default transfer protocol from PORT to PASV as proposed on
+  bugzilla (#16134), and to match the regular ftp package's behavior
+
+* Wed Jul 19 2000 Jeff Johnson <jbj@redhat.com>
+- rebuild to compress man pages.
+
+* Sat Jul 15 2000 Bill Nottingham <notting@redhat.com>
+- move initscript back
+
+* Fri Jul 14 2000 Nalin Dahyabhai <nalin@redhat.com>
+- disable servers by default to keep linuxconf from thinking they need to be
+  started when they don't
+
+* Thu Jul 13 2000 Prospector <bugzilla@redhat.com>
+- automatic rebuild
+
+* Mon Jul 10 2000 Nalin Dahyabhai <nalin@redhat.com>
+- change cleanup code in post to not tickle chkconfig
+- add grep as a Prereq: for -libs
+
+* Thu Jul  6 2000 Nalin Dahyabhai <nalin@redhat.com>
+- move condrestarts to postun
+- make xinetd configs noreplace
+- add descriptions to xinetd configs
+- add /etc/init.d as a prereq for the -server package
+- patch to properly truncate $TERM in krlogind
+
+* Fri Jun 30 2000 Nalin Dahyabhai <nalin@redhat.com>
+- update to 1.2.1
+- back out Tom Yu's patch, which is a big chunk of the 1.2 -> 1.2.1 update
+- start using the official source tarball instead of its contents
+
+* Thu Jun 29 2000 Nalin Dahyabhai <nalin@redhat.com>
+- Tom Yu's patch to fix compatibility between 1.2 kadmin and 1.1.1 kadmind
+- pull out 6.2 options in the spec file (sonames changing in 1.2 means it's not
+  compatible with other stuff in 6.2, so no need)
+
+* Wed Jun 28 2000 Nalin Dahyabhai <nalin@redhat.com>
+- tweak graceful start/stop logic in post and preun
+
+* Mon Jun 26 2000 Nalin Dahyabhai <nalin@redhat.com>
+- update to the 1.2 release
+- ditch a lot of our patches which went upstream
+- enable use of DNS to look up things at build-time
+- disable use of DNS to look up things at run-time in default krb5.conf
+- change ownership of the convert-config-files script to root.root
+- compress PS docs
+- fix some typos in the kinit man page
+- run condrestart in server post, and shut down in preun
+
+* Mon Jun 19 2000 Nalin Dahyabhai <nalin@redhat.com>
+- only remove old krb5server init script links if the init script is there
+
+* Sat Jun 17 2000 Nalin Dahyabhai <nalin@redhat.com>
+- disable kshell and eklogin by default
+
+* Thu Jun 15 2000 Nalin Dahyabhai <nalin@redhat.com>
+- patch mkdir/rmdir problem in ftpcmd.y
+- add condrestart option to init script
+- split the server init script into three pieces and add one for kpropd
+
+* Wed Jun 14 2000 Nalin Dahyabhai <nalin@redhat.com>
+- make sure workstation servers are all disabled by default
+- clean up krb5server init script
+
+* Fri Jun  9 2000 Nalin Dahyabhai <nalin@redhat.com>
+- apply second set of buffer overflow fixes from Tom Yu
+- fix from Dirk Husung for a bug in buffer cleanups in the test suite
+- work around possibly broken rev binary in running test suite
+- move default realm configs from /var/kerberos to %%{_var}/kerberos
+
+* Tue Jun  6 2000 Nalin Dahyabhai <nalin@redhat.com>
+- make ksu and v4rcp owned by root
+
+* Sat Jun  3 2000 Nalin Dahyabhai <nalin@redhat.com>
+- use %%{_infodir} to better comply with FHS
+- move .so files to -devel subpackage
+- tweak xinetd config files (bugs #11833, #11835, #11836, #11840)
+- fix package descriptions again
+
+* Wed May 24 2000 Nalin Dahyabhai <nalin@redhat.com>
+- change a LINE_MAX to 1024, fix from Ken Raeburn
+- add fix for login vulnerability in case anyone rebuilds without krb4 compat
+- add tweaks for byte-swapping macros in krb.h, also from Ken
+- add xinetd config files
+- make rsh and rlogin quieter
+- build with debug to fix credential forwarding
+- add rsh as a build-time req because the configure scripts look for it to
+  determine paths
+
+* Wed May 17 2000 Nalin Dahyabhai <nalin@redhat.com>
+- fix config_subpackage logic
+
+* Tue May 16 2000 Nalin Dahyabhai <nalin@redhat.com>
+- remove setuid bit on v4rcp and ksu in case the checks previously added
+  don't close all of the problems in ksu
+- apply patches from Jeffrey Schiller to fix overruns Chris Evans found
+- reintroduce configs subpackage for use in the errata
+- add PreReq: sh-utils
+
+* Mon May 15 2000 Nalin Dahyabhai <nalin@redhat.com>
+- fix double-free in the kdc (patch merged into MIT tree)
+- include convert-config-files script as a documentation file
+
+* Wed May 03 2000 Nalin Dahyabhai <nalin@redhat.com>
+- patch ksu man page because the -C option never works
+- add access() checks and disable debug mode in ksu
+- modify default ksu build arguments to specify more directories in CMD_PATH
+  and to use getusershell()
+
+* Wed May 03 2000 Bill Nottingham <notting@redhat.com>
+- fix configure stuff for ia64
+
+* Mon Apr 10 2000 Nalin Dahyabhai <nalin@redhat.com>
+- add LDCOMBINE=-lc to configure invocation to use libc versioning (bug #10653)
+- change Requires: for/in subpackages to include %%{version}
+
+* Wed Apr 05 2000 Nalin Dahyabhai <nalin@redhat.com>
+- add man pages for kerberos(1), kvno(1), .k5login(5)
+- add kvno to -workstation
+
+* Mon Apr 03 2000 Nalin Dahyabhai <nalin@redhat.com>
+- Merge krb5-configs back into krb5-libs.  The krb5.conf file is marked as
+  a %%config file anyway.
+- Make krb5.conf a noreplace config file.
+
+* Thu Mar 30 2000 Nalin Dahyabhai <nalin@redhat.com>
+- Make klogind pass a clean environment to children, like NetKit's rlogind does.
+
+* Wed Mar 08 2000 Nalin Dahyabhai <nalin@redhat.com>
+- Don't enable the server by default.
+- Compress info pages.
+- Add defaults for the PAM module to krb5.conf
+
+* Mon Mar 06 2000 Nalin Dahyabhai <nalin@redhat.com>
+- Correct copyright: it's exportable now, provided the proper paperwork is
+  filed with the government.
+
+* Fri Mar 03 2000 Nalin Dahyabhai <nalin@redhat.com>
+- apply Mike Friedman's patch to fix format string problems
+- don't strip off argv[0] when invoking regular rsh/rlogin
+
+* Thu Mar 02 2000 Nalin Dahyabhai <nalin@redhat.com>
+- run kadmin.local correctly at startup
+
+* Mon Feb 28 2000 Nalin Dahyabhai <nalin@redhat.com>
+- pass absolute path to kadm5.keytab if/when extracting keys at startup
+
+* Sat Feb 19 2000 Nalin Dahyabhai <nalin@redhat.com>
+- fix info page insertions
+
+* Wed Feb  9 2000 Nalin Dahyabhai <nalin@redhat.com>
+- tweak server init script to automatically extract kadm5 keys if
+  /var/kerberos/krb5kdc/kadm5.keytab doesn't exist yet
+- adjust package descriptions
+
+* Thu Feb  3 2000 Nalin Dahyabhai <nalin@redhat.com>
+- fix for potentially gzipped man pages
+
+* Fri Jan 21 2000 Nalin Dahyabhai <nalin@redhat.com>
+- fix comments in krb5-configs
+
+* Fri Jan  7 2000 Nalin Dahyabhai <nalin@redhat.com>
+- move /usr/kerberos/bin to end of PATH
+
+* Tue Dec 28 1999 Nalin Dahyabhai <nalin@redhat.com>
+- install kadmin header files
+
+* Tue Dec 21 1999 Nalin Dahyabhai <nalin@redhat.com>
+- patch around TIOCGTLC defined on alpha and remove warnings from libpty.h
+- add installation of info docs
+- remove krb4 compat patch because it doesn't fix workstation-side servers
+
+* Mon Dec 20 1999 Nalin Dahyabhai <nalin@redhat.com>
+- remove hesiod dependency at build-time
+
+* Sun Dec 19 1999 Nalin Dahyabhai <nsdahya1@eos.ncsu.edu>
+- rebuild on 1.1.1
+
+* Thu Oct  7 1999 Nalin Dahyabhai <nsdahya1@eos.ncsu.edu>
+- clean up init script for server, verify that it works [jlkatz]
+- clean up rotation script so that rc likes it better
+- add clean stanza
+
+* Mon Oct  4 1999 Nalin Dahyabhai <nsdahya1@eos.ncsu.edu>
+- backed out ncurses and makeshlib patches
+- update for krb5-1.1
+- add KDC rotation to rc.boot, based on ideas from Michael's C version
+
+* Mon Sep 27 1999 Nalin Dahyabhai <nsdahya1@eos.ncsu.edu>
+- added -lncurses to telnet and telnetd makefiles
+
+* Mon Jul  5 1999 Nalin Dahyabhai <nsdahya1@eos.ncsu.edu>
+- added krb5.csh and krb5.sh to /etc/profile.d
+
+* Tue Jun 22 1999 Nalin Dahyabhai <nsdahya1@eos.ncsu.edu>
+- broke out configuration files
+
+* Mon Jun 14 1999 Nalin Dahyabhai <nsdahya1@eos.ncsu.edu>
+- fixed server package so that it works now
+
+* Sat May 15 1999 Nalin Dahyabhai <nsdahya1@eos.ncsu.edu>
+- started changelog (previous package from zedz.net)
+- updated existing 1.0.5 RPM from Eos Linux to krb5 1.0.6
+- added --force to makeinfo commands to skip errors during build