File 0101-Fix-IAKERB-context-aliasing-bugs-CVE-2015-2696.patch of Package krb5.4201

The patch comprises two commits in which the second one depends on the first one.
Line numbers are re-adjusted to work with this older version of Kerberos.
- Howard Guo <hguo@suse.com>

From d750ef3130b76dd079e863ed395eb3620a37386b Mon Sep 17 00:00:00 2001
From: Greg Hudson <ghudson@mit.edu>
Date: Sat, 7 Sep 2013 21:13:48 -0400
Subject: [PATCH] Add GSSAPI IOV MIC functions

Add gss_get_mic_iov, gss_get_mic_iov_length, and gss_verify_mic_iov
functions, which work similarly to the corresponding IOV wrap
functions.  Add a new buffer type GSS_IOV_BUFFER_TYPE_MIC_TOKEN for
the destination buffer.

Most of the internal code for this was already present, and just
needed to be fixed up and adjusted to use the new buffer type for the
MIC token.

ticket: 7705 (new)

From e04f0283516e80d2f93366e0d479d13c9b5c8c2a Mon Sep 17 00:00:00 2001
From: Nicolas Williams <nico@twosigma.com>
Date: Mon, 14 Sep 2015 12:28:36 -0400
Subject: [PATCH] Fix IAKERB context aliasing bugs [CVE-2015-2696]

The IAKERB mechanism currently replaces its context handle with the
krb5 mechanism handle upon establishment, under the assumption that
most GSS functions are only called after context establishment.  This
assumption is incorrect, and can lead to aliasing violations for some
programs.  Maintain the IAKERB context structure after context
establishment and add new IAKERB entry points to refer to it with that
type.  Add initiate and established flags to the IAKERB context
structure for use in gss_inquire_context() prior to context
establishment.

CVE-2015-2696:

In MIT krb5 1.9 and later, applications which call
gss_inquire_context() on a partially-established IAKERB context can
cause the GSS-API library to read from a pointer using the wrong type,
generally causing a process crash.  Java server applications using the
native JGSS provider are vulnerable to this bug.  A carefully crafted
IAKERB packet might allow the gss_inquire_context() call to succeed
with attacker-determined results, but applications should not make
access control decisions based on gss_inquire_context() results prior
to context establishment.

    CVSSv2 Vector: AV:N/AC:M/Au:N/C:N/I:N/A:C/E:POC/RL:OF/RC:C

[ghudson@mit.edu: several bugfixes, style changes, and edge-case
behavior changes; commit message and CVE description]

ticket: 8244
target_version: 1.14
tags: pullup

diff -rupN krb5-1.11.3/src/lib/gssapi/generic/gssapi_ext.h krb5-1.11.3-patched/src/lib/gssapi/generic/gssapi_ext.h
--- krb5-1.11.3/src/lib/gssapi/generic/gssapi_ext.h	2015-10-29 14:32:44.753908816 +0100
+++ krb5-1.11.3-patched/src/lib/gssapi/generic/gssapi_ext.h	2015-10-29 14:49:40.362708161 +0100
@@ -238,6 +238,7 @@ typedef struct gss_iov_buffer_desc_struc
 #define GSS_IOV_BUFFER_TYPE_PADDING	    9	/* Padding */
 #define GSS_IOV_BUFFER_TYPE_STREAM	    10	/* Complete wrap token */
 #define GSS_IOV_BUFFER_TYPE_SIGN_ONLY	    11	/* Sign only packet data */
+#define GSS_IOV_BUFFER_TYPE_MIC_TOKEN	    12	/* MIC token destination */
 
 #define GSS_IOV_BUFFER_FLAG_MASK	    0xFFFF0000
 #define GSS_IOV_BUFFER_FLAG_ALLOCATE	    0x00010000	/* indicates GSS should allocate */
@@ -325,6 +326,46 @@ OM_uint32 KRB5_CALLCONV gss_wrap_iov_len
     gss_iov_buffer_desc *, /* iov */
     int);		/* iov_count */
 
+/*
+ * Produce a GSSAPI MIC token for a sequence of buffers.  All SIGN_ONLY and
+ * DATA buffers will be signed, in the order they appear.  One MIC_TOKEN buffer
+ * must be included for the result.  Suitable space should be provided for the
+ * MIC_TOKEN buffer by calling gss_get_mic_iov_length, or the ALLOCATE flag
+ * should be set on that buffer.  If the ALLOCATE flag is used, use
+ * gss_release_iov_buffer to free the allocated buffer within the iov list when
+ * it is no longer needed.
+ */
+OM_uint32 KRB5_CALLCONV gss_get_mic_iov
+(
+    OM_uint32 *,	/* minor_status */
+    gss_ctx_id_t,	/* context_handle */
+    gss_qop_t,		/* qop_req */
+    gss_iov_buffer_desc *, /* iov */
+    int);		/* iov_count */
+
+/*
+ * Query the MIC_TOKEN buffer length within the iov list.
+ */
+OM_uint32 KRB5_CALLCONV gss_get_mic_iov_length(
+    OM_uint32 *,	/* minor_status */
+    gss_ctx_id_t,	/* context_handle */
+    gss_qop_t,		/* qop_req */
+    gss_iov_buffer_desc *, /* iov */
+    int);		/* iov_count */
+
+/*
+ * Verify the MIC_TOKEN buffer within the iov list against the SIGN_ONLY and
+ * DATA buffers in the order they appear.  Return values are the same as for
+ * gss_verify_mic.
+ */
+OM_uint32 KRB5_CALLCONV gss_verify_mic_iov
+(
+    OM_uint32 *,	/* minor_status */
+    gss_ctx_id_t,	/* context_handle */
+    gss_qop_t *,	/* qop_state */
+    gss_iov_buffer_desc *, /* iov */
+    int);		/* iov_count */
+
 /*
  * Release buffers that have the ALLOCATED flag set.
  */
diff -rupN krb5-1.11.3/src/lib/gssapi/krb5/gssapi_krb5.c krb5-1.11.3-patched/src/lib/gssapi/krb5/gssapi_krb5.c
--- krb5-1.11.3/src/lib/gssapi/krb5/gssapi_krb5.c	2015-10-29 14:32:44.757908834 +0100
+++ krb5-1.11.3-patched/src/lib/gssapi/krb5/gssapi_krb5.c	2015-10-29 14:49:40.362708161 +0100
@@ -345,7 +345,7 @@ static struct {
     }
 };
 
-static OM_uint32 KRB5_CALLCONV
+OM_uint32 KRB5_CALLCONV
 krb5_gss_inquire_sec_context_by_oid (OM_uint32 *minor_status,
                                      const gss_ctx_id_t context_handle,
                                      const gss_OID desired_object,
@@ -462,7 +462,7 @@ static struct {
 };
 #endif
 
-static OM_uint32 KRB5_CALLCONV
+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,
@@ -902,6 +902,104 @@ static struct gss_config krb5_mechanism
     krb5_gss_acquire_cred_with_password,
     krb5_gss_export_cred,
     krb5_gss_import_cred,
+    NULL,               /* import_sec_context_by_mech */
+    NULL,               /* import_name_by_mech */
+    NULL,               /* import_cred_by_mech */
+    krb5_gss_get_mic_iov,
+    krb5_gss_verify_mic_iov,
+    krb5_gss_get_mic_iov_length,
+};
+
+/* Functions which use security contexts or acquire creds are IAKERB-specific;
+ * other functions can borrow from the krb5 mech. */
+static struct gss_config iakerb_mechanism = {
+    { GSS_MECH_KRB5_OID_LENGTH, GSS_MECH_KRB5_OID },
+    NULL,
+    iakerb_gss_acquire_cred,
+    krb5_gss_release_cred,
+    iakerb_gss_init_sec_context,
+#ifdef LEAN_CLIENT
+    NULL,
+#else
+    iakerb_gss_accept_sec_context,
+#endif
+    iakerb_gss_process_context_token,
+    iakerb_gss_delete_sec_context,
+    iakerb_gss_context_time,
+    iakerb_gss_get_mic,
+    iakerb_gss_verify_mic,
+#if defined(IOV_SHIM_EXERCISE_WRAP) || defined(IOV_SHIM_EXERCISE)
+    NULL,
+#else
+    iakerb_gss_wrap,
+#endif
+#if defined(IOV_SHIM_EXERCISE_UNWRAP) || defined(IOV_SHIM_EXERCISE)
+    NULL,
+#else
+    iakerb_gss_unwrap,
+#endif
+    krb5_gss_display_status,
+    krb5_gss_indicate_mechs,
+    krb5_gss_compare_name,
+    krb5_gss_display_name,
+    krb5_gss_import_name,
+    krb5_gss_release_name,
+    krb5_gss_inquire_cred,
+    NULL,                /* add_cred */
+#ifdef LEAN_CLIENT
+    NULL,
+    NULL,
+#else
+    iakerb_gss_export_sec_context,
+    NULL,
+#endif
+    krb5_gss_inquire_cred_by_mech,
+    krb5_gss_inquire_names_for_mech,
+    iakerb_gss_inquire_context,
+    krb5_gss_internal_release_oid,
+    iakerb_gss_wrap_size_limit,
+    krb5_gss_localname,
+    krb5_gss_authorize_localname,
+    krb5_gss_export_name,
+    krb5_gss_duplicate_name,
+    krb5_gss_store_cred,
+    iakerb_gss_inquire_sec_context_by_oid,
+    krb5_gss_inquire_cred_by_oid,
+    iakerb_gss_set_sec_context_option,
+    krb5_gssspi_set_cred_option,
+    krb5_gssspi_mech_invoke,
+    NULL,                /* wrap_aead */
+    NULL,                /* unwrap_aead */
+    iakerb_gss_wrap_iov,
+    iakerb_gss_unwrap_iov,
+    iakerb_gss_wrap_iov_length,
+    NULL,               /* complete_auth_token */
+    NULL,               /* acquire_cred_impersonate_name */
+    NULL,               /* add_cred_impersonate_name */
+    NULL,               /* display_name_ext */
+    krb5_gss_inquire_name,
+    krb5_gss_get_name_attribute,
+    krb5_gss_set_name_attribute,
+    krb5_gss_delete_name_attribute,
+    krb5_gss_export_name_composite,
+    krb5_gss_map_name_to_any,
+    krb5_gss_release_any_name_mapping,
+    iakerb_gss_pseudo_random,
+    NULL,               /* set_neg_mechs */
+    krb5_gss_inquire_saslname_for_mech,
+    krb5_gss_inquire_mech_for_saslname,
+    krb5_gss_inquire_attrs_for_mech,
+    krb5_gss_acquire_cred_from,
+    krb5_gss_store_cred_into,
+    iakerb_gss_acquire_cred_with_password,
+    krb5_gss_export_cred,
+    krb5_gss_import_cred,
+    NULL,               /* import_sec_context_by_mech */
+    NULL,               /* import_name_by_mech */
+    NULL,               /* import_cred_by_mech */
+    iakerb_gss_get_mic_iov,
+    iakerb_gss_verify_mic_iov,
+    iakerb_gss_get_mic_iov_length,
 };
 
 #ifdef _GSS_STATIC_LINK
@@ -909,15 +1007,6 @@ static struct gss_config krb5_mechanism
 static int gss_iakerbmechglue_init(void)
 {
     struct gss_mech_config mech_iakerb;
-    struct gss_config iakerb_mechanism = krb5_mechanism;
-
-    /* IAKERB mechanism mirrors krb5, but with different context SPIs */
-    iakerb_mechanism.gss_accept_sec_context = iakerb_gss_accept_sec_context;
-    iakerb_mechanism.gss_init_sec_context   = iakerb_gss_init_sec_context;
-    iakerb_mechanism.gss_delete_sec_context = iakerb_gss_delete_sec_context;
-    iakerb_mechanism.gss_acquire_cred       = iakerb_gss_acquire_cred;
-    iakerb_mechanism.gssspi_acquire_cred_with_password
-                                    = iakerb_gss_acquire_cred_with_password;
 
     memset(&mech_iakerb, 0, sizeof(mech_iakerb));
     mech_iakerb.mech = &iakerb_mechanism;
diff -rupN krb5-1.11.3/src/lib/gssapi/krb5/gssapiP_krb5.h krb5-1.11.3-patched/src/lib/gssapi/krb5/gssapiP_krb5.h
--- krb5-1.11.3/src/lib/gssapi/krb5/gssapiP_krb5.h	2015-10-29 14:32:44.757908834 +0100
+++ krb5-1.11.3-patched/src/lib/gssapi/krb5/gssapiP_krb5.h	2015-10-29 14:49:40.362708161 +0100
@@ -403,6 +403,9 @@ gss_iov_buffer_t kg_locate_iov (gss_iov_
               int iov_count,
               OM_uint32 type);
 
+gss_iov_buffer_t kg_locate_header_iov(gss_iov_buffer_desc *iov, int iov_count,
+                                      int toktype);
+
 void kg_iov_msglen(gss_iov_buffer_desc *iov,
               int iov_count,
               size_t *data_length,
@@ -428,7 +431,8 @@ krb5_error_code kg_make_checksum_iov_v3(
                 krb5_key key,
                 krb5_keyusage sign_usage,
                 gss_iov_buffer_desc *iov,
-                int iov_count);
+                int iov_count,
+                int toktype);
 
 krb5_error_code kg_verify_checksum_iov_v3(krb5_context context,
                 krb5_cksumtype type,
@@ -437,6 +441,7 @@ krb5_error_code kg_verify_checksum_iov_v
                 krb5_keyusage sign_usage,
                 gss_iov_buffer_desc *iov,
                 int iov_count,
+                int toktype,
                 krb5_boolean *valid);
 
 OM_uint32 kg_seal_iov (OM_uint32 *minor_status,
@@ -462,7 +467,8 @@ OM_uint32 kg_seal_iov_length(OM_uint32 *
            gss_qop_t qop_req,
            int *conf_state,
            gss_iov_buffer_desc *iov,
-           int iov_count);
+           int iov_count,
+           int toktype);
 
 krb5_cryptotype kg_translate_flag_iov(OM_uint32 type);
 
@@ -611,6 +617,21 @@ OM_uint32 KRB5_CALLCONV krb5_gss_accept_
 );
 #endif /* LEAN_CLIENT */
 
+OM_uint32 KRB5_CALLCONV krb5_gss_inquire_sec_context_by_oid
+(OM_uint32*,       /* minor_status */
+ const gss_ctx_id_t,
+ /* context_handle */
+ const gss_OID,    /* desired_object */
+ gss_buffer_set_t* /* data_set */
+);
+
+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 */
+);
+
 OM_uint32 KRB5_CALLCONV krb5_gss_process_context_token
 (OM_uint32*,       /* minor_status */
  gss_ctx_id_t,     /* context_handle */
@@ -700,6 +721,22 @@ OM_uint32 KRB5_CALLCONV krb5_gss_get_mic
  gss_buffer_t                /* message_token */
 );
 
+OM_uint32 KRB5_CALLCONV krb5_gss_get_mic_iov
+(OM_uint32 *,                /* minor_status */
+ gss_ctx_id_t,               /* context_handle */
+ gss_qop_t,                  /* qop_req */
+ gss_iov_buffer_desc *,      /* iov */
+ int                         /* iov_count */
+);
+
+OM_uint32 KRB5_CALLCONV krb5_gss_get_mic_iov_length
+(OM_uint32 *,                /* minor_status */
+ gss_ctx_id_t,               /* context_handle */
+ gss_qop_t,                  /* qop_req */
+ gss_iov_buffer_desc *,      /* iov */
+ int                         /* iov_count */
+);
+
 OM_uint32 KRB5_CALLCONV krb5_gss_verify_mic
 (OM_uint32 *,           /* minor_status */
  gss_ctx_id_t,               /* context_handle */
@@ -708,6 +745,40 @@ OM_uint32 KRB5_CALLCONV krb5_gss_verify_
  gss_qop_t *                 /* qop_state */
 );
 
+
+OM_uint32 KRB5_CALLCONV krb5_gss_verify_mic_iov
+(OM_uint32 *,                /* minor_status */
+ gss_ctx_id_t,               /* context_handle */
+ gss_qop_t *,                /* qop_state */
+ gss_iov_buffer_desc *,      /* iov */
+ int                         /* iov_count */
+);
+
+
+OM_uint32 KRB5_CALLCONV krb5_gss_get_mic_iov
+(OM_uint32 *,                /* minor_status */
+ gss_ctx_id_t,               /* context_handle */
+ gss_qop_t,                  /* qop_req */
+ gss_iov_buffer_desc *,      /* iov */
+ int                         /* iov_count */
+);
+
+OM_uint32 KRB5_CALLCONV krb5_gss_get_mic_iov_length
+(OM_uint32 *,                /* minor_status */
+ gss_ctx_id_t,               /* context_handle */
+ gss_qop_t,                  /* qop_req */
+ gss_iov_buffer_desc *,      /* iov */
+ int                         /* iov_count */
+);
+
+OM_uint32 KRB5_CALLCONV krb5_gss_verify_mic_iov
+(OM_uint32 *,                /* minor_status */
+ gss_ctx_id_t,               /* context_handle */
+ gss_qop_t *,                /* qop_state */
+ gss_iov_buffer_desc *,      /* iov */
+ int                         /* iov_count */
+);
+
 OM_uint32 KRB5_CALLCONV krb5_gss_wrap
 (OM_uint32 *,           /* minor_status */
  gss_ctx_id_t,               /* context_handle */
@@ -1266,6 +1337,105 @@ OM_uint32 KRB5_CALLCONV
 krb5_gss_import_cred(OM_uint32 *minor_status, gss_buffer_t token,
                      gss_cred_id_t *cred_handle);
 
+OM_uint32 KRB5_CALLCONV
+iakerb_gss_process_context_token(OM_uint32 *minor_status,
+                                 const gss_ctx_id_t context_handle,
+                                 const gss_buffer_t token_buffer);
+
+OM_uint32 KRB5_CALLCONV
+iakerb_gss_context_time(OM_uint32 *minor_status, gss_ctx_id_t context_handle,
+                        OM_uint32 *time_rec);
+
+OM_uint32 KRB5_CALLCONV
+iakerb_gss_inquire_context(OM_uint32 *minor_status,
+                           gss_ctx_id_t context_handle, gss_name_t *src_name,
+                           gss_name_t *targ_name, OM_uint32 *lifetime_rec,
+                           gss_OID *mech_type, OM_uint32 *ctx_flags,
+                           int *locally_initiated, int *opened);
+
+OM_uint32 KRB5_CALLCONV
+iakerb_gss_get_mic(OM_uint32 *minor_status, gss_ctx_id_t context_handle,
+                   gss_qop_t qop_req, gss_buffer_t message_buffer,
+                   gss_buffer_t message_token);
+
+OM_uint32 KRB5_CALLCONV
+iakerb_gss_get_mic_iov(OM_uint32 *minor_status, gss_ctx_id_t context_handle,
+                       gss_qop_t qop_req, gss_iov_buffer_desc *iov,
+                       int iov_count);
+
+OM_uint32 KRB5_CALLCONV
+iakerb_gss_get_mic_iov_length(OM_uint32 *minor_status,
+                              gss_ctx_id_t context_handle, gss_qop_t qop_req,
+                              gss_iov_buffer_desc *iov, int iov_count);
+
+OM_uint32 KRB5_CALLCONV
+iakerb_gss_verify_mic(OM_uint32 *minor_status, gss_ctx_id_t context_handle,
+                      gss_buffer_t msg_buffer, gss_buffer_t token_buffer,
+                      gss_qop_t *qop_state);
+
+OM_uint32 KRB5_CALLCONV
+iakerb_gss_verify_mic_iov(OM_uint32 *minor_status, gss_ctx_id_t context_handle,
+                          gss_qop_t *qop_state, gss_iov_buffer_desc *iov,
+                          int iov_count);
+
+OM_uint32 KRB5_CALLCONV
+iakerb_gss_wrap(OM_uint32 *minor_status, gss_ctx_id_t context_handle,
+                int conf_req_flag, gss_qop_t qop_req,
+                gss_buffer_t input_message_buffer, int *conf_state,
+                gss_buffer_t output_message_buffer);
+
+OM_uint32 KRB5_CALLCONV
+iakerb_gss_wrap_iov(OM_uint32 *minor_status, gss_ctx_id_t context_handle,
+                    int conf_req_flag, gss_qop_t qop_req, int *conf_state,
+                    gss_iov_buffer_desc *iov, int iov_count);
+
+OM_uint32 KRB5_CALLCONV
+iakerb_gss_wrap_iov_length(OM_uint32 *minor_status,
+                           gss_ctx_id_t context_handle, int conf_req_flag,
+                           gss_qop_t qop_req, int *conf_state,
+                           gss_iov_buffer_desc *iov, int iov_count);
+
+OM_uint32 KRB5_CALLCONV
+iakerb_gss_unwrap(OM_uint32 *minor_status, gss_ctx_id_t context_handle,
+                  gss_buffer_t input_message_buffer,
+                  gss_buffer_t output_message_buffer, int *conf_state,
+                  gss_qop_t *qop_state);
+
+OM_uint32 KRB5_CALLCONV
+iakerb_gss_unwrap_iov(OM_uint32 *minor_status, gss_ctx_id_t context_handle,
+                      int *conf_state, gss_qop_t *qop_state,
+                      gss_iov_buffer_desc *iov, int iov_count);
+
+OM_uint32 KRB5_CALLCONV
+iakerb_gss_wrap_size_limit(OM_uint32 *minor_status,
+                           gss_ctx_id_t context_handle, int conf_req_flag,
+                           gss_qop_t qop_req, OM_uint32 req_output_size,
+                           OM_uint32 *max_input_size);
+
+#ifndef LEAN_CLIENT
+OM_uint32 KRB5_CALLCONV
+iakerb_gss_export_sec_context(OM_uint32 *minor_status,
+                              gss_ctx_id_t *context_handle,
+                              gss_buffer_t interprocess_token);
+#endif /* LEAN_CLIENT */
+
+OM_uint32 KRB5_CALLCONV
+iakerb_gss_inquire_sec_context_by_oid(OM_uint32 *minor_status,
+                                      const gss_ctx_id_t context_handle,
+                                      const gss_OID desired_object,
+                                      gss_buffer_set_t *data_set);
+
+OM_uint32 KRB5_CALLCONV
+iakerb_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);
+
+OM_uint32 KRB5_CALLCONV
+iakerb_gss_pseudo_random(OM_uint32 *minor_status, gss_ctx_id_t context_handle,
+                         int prf_key, const gss_buffer_t prf_in,
+                         ssize_t desired_output_len, gss_buffer_t prf_out);
+
 /* Magic string to identify exported krb5 GSS credentials.  Increment this if
  * the format changes. */
 #define CRED_EXPORT_MAGIC "K5C1"
diff -rupN krb5-1.11.3/src/lib/gssapi/krb5/iakerb.c krb5-1.11.3-patched/src/lib/gssapi/krb5/iakerb.c
--- krb5-1.11.3/src/lib/gssapi/krb5/iakerb.c	2015-10-29 14:32:44.757908834 +0100
+++ krb5-1.11.3-patched/src/lib/gssapi/krb5/iakerb.c	2015-10-29 14:33:53.338212385 +0100
@@ -47,6 +47,8 @@ struct _iakerb_ctx_id_rec {
     gss_ctx_id_t gssc;
     krb5_data conv;                     /* conversation for checksumming */
     unsigned int count;                 /* number of round trips */
+    int initiate;
+    int established;
     krb5_get_init_creds_opt *gic_opts;
 };
 
@@ -694,7 +696,7 @@ cleanup:
  * Allocate and initialise an IAKERB context
  */
 static krb5_error_code
-iakerb_alloc_context(iakerb_ctx_id_t *pctx)
+iakerb_alloc_context(iakerb_ctx_id_t *pctx, int initiate)
 {
     iakerb_ctx_id_t ctx;
     krb5_error_code code;
@@ -708,6 +710,8 @@ iakerb_alloc_context(iakerb_ctx_id_t *pc
     ctx->magic = KG_IAKERB_CONTEXT;
     ctx->state = IAKERB_AS_REQ;
     ctx->count = 0;
+    ctx->initiate = initiate;
+    ctx->established = 0;
 
     code = krb5_gss_init_context(&ctx->k5c);
     if (code != 0)
@@ -731,7 +735,7 @@ iakerb_gss_delete_sec_context(OM_uint32
                               gss_ctx_id_t *context_handle,
                               gss_buffer_t output_token)
 {
-    OM_uint32 major_status = GSS_S_COMPLETE;
+    iakerb_ctx_id_t iakerb_ctx = (iakerb_ctx_id_t)*context_handle;
 
     if (output_token != GSS_C_NO_BUFFER) {
         output_token->length = 0;
@@ -739,23 +743,10 @@ iakerb_gss_delete_sec_context(OM_uint32
     }
 
     *minor_status = 0;
+    *context_handle = GSS_C_NO_CONTEXT;
+    iakerb_release_context(iakerb_ctx);
 
-    if (*context_handle != GSS_C_NO_CONTEXT) {
-        iakerb_ctx_id_t iakerb_ctx = (iakerb_ctx_id_t)*context_handle;
-
-        if (iakerb_ctx->magic == KG_IAKERB_CONTEXT) {
-            iakerb_release_context(iakerb_ctx);
-            *context_handle = GSS_C_NO_CONTEXT;
-        } else {
-            assert(iakerb_ctx->magic == KG_CONTEXT);
-
-            major_status = krb5_gss_delete_sec_context(minor_status,
-                                                       context_handle,
-                                                       output_token);
-        }
-    }
-
-    return major_status;
+    return GSS_S_COMPLETE;
 }
 
 static krb5_boolean
@@ -801,7 +792,7 @@ iakerb_gss_accept_sec_context(OM_uint32
     int initialContextToken = (*context_handle == GSS_C_NO_CONTEXT);
 
     if (initialContextToken) {
-        code = iakerb_alloc_context(&ctx);
+        code = iakerb_alloc_context(&ctx, 0);
         if (code != 0)
             goto cleanup;
 
@@ -853,11 +844,8 @@ iakerb_gss_accept_sec_context(OM_uint32
                                                        time_rec,
                                                        delegated_cred_handle,
                                                        &exts);
-        if (major_status == GSS_S_COMPLETE) {
-            *context_handle = ctx->gssc;
-            ctx->gssc = NULL;
-            iakerb_release_context(ctx);
-        }
+        if (major_status == GSS_S_COMPLETE)
+            ctx->established = 1;
         if (mech_type != NULL)
             *mech_type = (gss_OID)gss_mech_krb5;
     }
@@ -896,7 +884,7 @@ iakerb_gss_init_sec_context(OM_uint32 *m
     int initialContextToken = (*context_handle == GSS_C_NO_CONTEXT);
 
     if (initialContextToken) {
-        code = iakerb_alloc_context(&ctx);
+        code = iakerb_alloc_context(&ctx, 1);
         if (code != 0) {
             *minor_status = code;
             goto cleanup;
@@ -982,11 +970,8 @@ iakerb_gss_init_sec_context(OM_uint32 *m
                                                      ret_flags,
                                                      time_rec,
                                                      &exts);
-        if (major_status == GSS_S_COMPLETE) {
-            *context_handle = ctx->gssc;
-            ctx->gssc = GSS_C_NO_CONTEXT;
-            iakerb_release_context(ctx);
-        }
+        if (major_status == GSS_S_COMPLETE)
+            ctx->established = 1;
         if (actual_mech_type != NULL)
             *actual_mech_type = (gss_OID)gss_mech_krb5;
     } else {
@@ -1009,3 +994,309 @@ cleanup:
 
     return major_status;
 }
+
+OM_uint32 KRB5_CALLCONV
+iakerb_gss_unwrap(OM_uint32 *minor_status, gss_ctx_id_t context_handle,
+                  gss_buffer_t input_message_buffer,
+                  gss_buffer_t output_message_buffer, int *conf_state,
+                  gss_qop_t *qop_state)
+{
+    iakerb_ctx_id_t ctx = (iakerb_ctx_id_t)context_handle;
+
+    if (ctx->gssc == GSS_C_NO_CONTEXT)
+        return GSS_S_NO_CONTEXT;
+
+    return krb5_gss_unwrap(minor_status, ctx->gssc, input_message_buffer,
+                           output_message_buffer, conf_state, qop_state);
+}
+
+OM_uint32 KRB5_CALLCONV
+iakerb_gss_wrap(OM_uint32 *minor_status, gss_ctx_id_t context_handle,
+                int conf_req_flag, gss_qop_t qop_req,
+                gss_buffer_t input_message_buffer, int *conf_state,
+                gss_buffer_t output_message_buffer)
+{
+    iakerb_ctx_id_t ctx = (iakerb_ctx_id_t)context_handle;
+
+    if (ctx->gssc == GSS_C_NO_CONTEXT)
+        return GSS_S_NO_CONTEXT;
+
+    return krb5_gss_wrap(minor_status, ctx->gssc, conf_req_flag, qop_req,
+                         input_message_buffer, conf_state,
+                         output_message_buffer);
+}
+
+OM_uint32 KRB5_CALLCONV
+iakerb_gss_process_context_token(OM_uint32 *minor_status,
+                                 const gss_ctx_id_t context_handle,
+                                 const gss_buffer_t token_buffer)
+{
+    iakerb_ctx_id_t ctx = (iakerb_ctx_id_t)context_handle;
+
+    if (ctx->gssc == GSS_C_NO_CONTEXT)
+        return GSS_S_DEFECTIVE_TOKEN;
+
+    return krb5_gss_process_context_token(minor_status, ctx->gssc,
+                                          token_buffer);
+}
+
+OM_uint32 KRB5_CALLCONV
+iakerb_gss_context_time(OM_uint32 *minor_status, gss_ctx_id_t context_handle,
+                        OM_uint32 *time_rec)
+{
+    iakerb_ctx_id_t ctx = (iakerb_ctx_id_t)context_handle;
+
+    if (ctx->gssc == GSS_C_NO_CONTEXT)
+        return GSS_S_NO_CONTEXT;
+
+    return krb5_gss_context_time(minor_status, ctx->gssc, time_rec);
+}
+
+#ifndef LEAN_CLIENT
+
+OM_uint32 KRB5_CALLCONV
+iakerb_gss_export_sec_context(OM_uint32 *minor_status,
+                              gss_ctx_id_t *context_handle,
+                              gss_buffer_t interprocess_token)
+{
+    OM_uint32 maj;
+    iakerb_ctx_id_t ctx = (iakerb_ctx_id_t)context_handle;
+
+    /* We don't currently support exporting partially established contexts. */
+    if (!ctx->established)
+        return GSS_S_UNAVAILABLE;
+
+    maj = krb5_gss_export_sec_context(minor_status, &ctx->gssc,
+                                      interprocess_token);
+    if (ctx->gssc == GSS_C_NO_CONTEXT) {
+        iakerb_release_context(ctx);
+        *context_handle = GSS_C_NO_CONTEXT;
+    }
+    return maj;
+}
+
+/*
+ * Until we implement partial context exports, there are no SPNEGO exported
+ * context tokens, only tokens for the underlying krb5 context.  So we do not
+ * need to implement an iakerb_gss_import_sec_context() yet; it would be
+ * unreachable except via a manually constructed token.
+ */
+
+#endif /* LEAN_CLIENT */
+
+OM_uint32 KRB5_CALLCONV
+iakerb_gss_inquire_context(OM_uint32 *minor_status,
+                           gss_ctx_id_t context_handle, gss_name_t *src_name,
+                           gss_name_t *targ_name, OM_uint32 *lifetime_rec,
+                           gss_OID *mech_type, OM_uint32 *ctx_flags,
+                           int *initiate, int *opened)
+{
+    OM_uint32 ret;
+    iakerb_ctx_id_t ctx = (iakerb_ctx_id_t)context_handle;
+
+    if (src_name != NULL)
+        *src_name = GSS_C_NO_NAME;
+    if (targ_name != NULL)
+        *targ_name = GSS_C_NO_NAME;
+    if (lifetime_rec != NULL)
+        *lifetime_rec = 0;
+    if (mech_type != NULL)
+        *mech_type = (gss_OID)gss_mech_iakerb;
+    if (ctx_flags != NULL)
+        *ctx_flags = 0;
+    if (initiate != NULL)
+        *initiate = ctx->initiate;
+    if (opened != NULL)
+        *opened = ctx->established;
+
+    if (ctx->gssc == GSS_C_NO_CONTEXT)
+        return GSS_S_COMPLETE;
+
+    ret = krb5_gss_inquire_context(minor_status, ctx->gssc, src_name,
+                                   targ_name, lifetime_rec, mech_type,
+                                   ctx_flags, initiate, opened);
+
+    if (!ctx->established) {
+        /* Report IAKERB as the mech OID until the context is established. */
+        if (mech_type != NULL)
+            *mech_type = (gss_OID)gss_mech_iakerb;
+
+        /* We don't support exporting partially-established contexts. */
+        if (ctx_flags != NULL)
+            *ctx_flags &= ~GSS_C_TRANS_FLAG;
+    }
+
+    return ret;
+}
+
+OM_uint32 KRB5_CALLCONV
+iakerb_gss_wrap_size_limit(OM_uint32 *minor_status,
+                           gss_ctx_id_t context_handle, int conf_req_flag,
+                           gss_qop_t qop_req, OM_uint32 req_output_size,
+                           OM_uint32 *max_input_size)
+{
+    iakerb_ctx_id_t ctx = (iakerb_ctx_id_t)context_handle;
+
+    if (ctx->gssc == GSS_C_NO_CONTEXT)
+        return GSS_S_NO_CONTEXT;
+
+    return krb5_gss_wrap_size_limit(minor_status, ctx->gssc, conf_req_flag,
+                                    qop_req, req_output_size, max_input_size);
+}
+
+OM_uint32 KRB5_CALLCONV
+iakerb_gss_get_mic(OM_uint32 *minor_status, gss_ctx_id_t context_handle,
+                   gss_qop_t qop_req, gss_buffer_t message_buffer,
+                   gss_buffer_t message_token)
+{
+    iakerb_ctx_id_t ctx = (iakerb_ctx_id_t)context_handle;
+
+    if (ctx->gssc == GSS_C_NO_CONTEXT)
+        return GSS_S_NO_CONTEXT;
+
+    return krb5_gss_get_mic(minor_status, ctx->gssc, qop_req, message_buffer,
+                            message_token);
+}
+
+OM_uint32 KRB5_CALLCONV
+iakerb_gss_verify_mic(OM_uint32 *minor_status, gss_ctx_id_t context_handle,
+                      gss_buffer_t msg_buffer, gss_buffer_t token_buffer,
+                      gss_qop_t *qop_state)
+{
+    iakerb_ctx_id_t ctx = (iakerb_ctx_id_t)context_handle;
+
+    if (ctx->gssc == GSS_C_NO_CONTEXT)
+        return GSS_S_NO_CONTEXT;
+
+    return krb5_gss_verify_mic(minor_status, ctx->gssc, msg_buffer,
+                               token_buffer, qop_state);
+}
+
+OM_uint32 KRB5_CALLCONV
+iakerb_gss_inquire_sec_context_by_oid(OM_uint32 *minor_status,
+                                      const gss_ctx_id_t context_handle,
+                                      const gss_OID desired_object,
+                                      gss_buffer_set_t *data_set)
+{
+    iakerb_ctx_id_t ctx = (iakerb_ctx_id_t)context_handle;
+
+    if (ctx->gssc == GSS_C_NO_CONTEXT)
+        return GSS_S_UNAVAILABLE;
+
+    return krb5_gss_inquire_sec_context_by_oid(minor_status, ctx->gssc,
+                                               desired_object, data_set);
+}
+
+OM_uint32 KRB5_CALLCONV
+iakerb_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)
+{
+    iakerb_ctx_id_t ctx = (iakerb_ctx_id_t)*context_handle;
+
+    if (ctx == NULL || ctx->gssc == GSS_C_NO_CONTEXT)
+        return GSS_S_UNAVAILABLE;
+
+    return krb5_gss_set_sec_context_option(minor_status, &ctx->gssc,
+                                           desired_object, value);
+}
+
+OM_uint32 KRB5_CALLCONV
+iakerb_gss_wrap_iov(OM_uint32 *minor_status, gss_ctx_id_t context_handle,
+                    int conf_req_flag, gss_qop_t qop_req, int *conf_state,
+                    gss_iov_buffer_desc *iov, int iov_count)
+{
+    iakerb_ctx_id_t ctx = (iakerb_ctx_id_t)context_handle;
+
+    if (ctx->gssc == GSS_C_NO_CONTEXT)
+        return GSS_S_NO_CONTEXT;
+
+    return krb5_gss_wrap_iov(minor_status, ctx->gssc, conf_req_flag, qop_req,
+                             conf_state, iov, iov_count);
+}
+
+OM_uint32 KRB5_CALLCONV
+iakerb_gss_unwrap_iov(OM_uint32 *minor_status, gss_ctx_id_t context_handle,
+                      int *conf_state, gss_qop_t *qop_state,
+                      gss_iov_buffer_desc *iov, int iov_count)
+{
+    iakerb_ctx_id_t ctx = (iakerb_ctx_id_t)context_handle;
+
+    if (ctx->gssc == GSS_C_NO_CONTEXT)
+        return GSS_S_NO_CONTEXT;
+
+    return krb5_gss_unwrap_iov(minor_status, ctx->gssc, conf_state, qop_state,
+                               iov, iov_count);
+}
+
+OM_uint32 KRB5_CALLCONV
+iakerb_gss_wrap_iov_length(OM_uint32 *minor_status,
+                           gss_ctx_id_t context_handle, int conf_req_flag,
+                           gss_qop_t qop_req, int *conf_state,
+                           gss_iov_buffer_desc *iov, int iov_count)
+{
+    iakerb_ctx_id_t ctx = (iakerb_ctx_id_t)context_handle;
+
+    if (ctx->gssc == GSS_C_NO_CONTEXT)
+        return GSS_S_NO_CONTEXT;
+
+    return krb5_gss_wrap_iov_length(minor_status, ctx->gssc, conf_req_flag,
+                                    qop_req, conf_state, iov, iov_count);
+}
+
+OM_uint32 KRB5_CALLCONV
+iakerb_gss_pseudo_random(OM_uint32 *minor_status, gss_ctx_id_t context_handle,
+                         int prf_key, const gss_buffer_t prf_in,
+                         ssize_t desired_output_len, gss_buffer_t prf_out)
+{
+    iakerb_ctx_id_t ctx = (iakerb_ctx_id_t)context_handle;
+
+    if (ctx->gssc == GSS_C_NO_CONTEXT)
+        return GSS_S_NO_CONTEXT;
+
+    return krb5_gss_pseudo_random(minor_status, ctx->gssc, prf_key, prf_in,
+                                  desired_output_len, prf_out);
+}
+
+OM_uint32 KRB5_CALLCONV
+iakerb_gss_get_mic_iov(OM_uint32 *minor_status, gss_ctx_id_t context_handle,
+                       gss_qop_t qop_req, gss_iov_buffer_desc *iov,
+                       int iov_count)
+{
+    iakerb_ctx_id_t ctx = (iakerb_ctx_id_t)context_handle;
+
+    if (ctx->gssc == GSS_C_NO_CONTEXT)
+        return GSS_S_NO_CONTEXT;
+
+    return krb5_gss_get_mic_iov(minor_status, ctx->gssc, qop_req, iov,
+                                iov_count);
+}
+
+OM_uint32 KRB5_CALLCONV
+iakerb_gss_verify_mic_iov(OM_uint32 *minor_status, gss_ctx_id_t context_handle,
+                          gss_qop_t *qop_state, gss_iov_buffer_desc *iov,
+                          int iov_count)
+{
+    iakerb_ctx_id_t ctx = (iakerb_ctx_id_t)context_handle;
+
+    if (ctx->gssc == GSS_C_NO_CONTEXT)
+        return GSS_S_NO_CONTEXT;
+
+    return krb5_gss_verify_mic_iov(minor_status, ctx->gssc, qop_state, iov,
+                                   iov_count);
+}
+
+OM_uint32 KRB5_CALLCONV
+iakerb_gss_get_mic_iov_length(OM_uint32 *minor_status,
+                              gss_ctx_id_t context_handle, gss_qop_t qop_req,
+                              gss_iov_buffer_desc *iov, int iov_count)
+{
+    iakerb_ctx_id_t ctx = (iakerb_ctx_id_t)context_handle;
+
+    if (ctx->gssc == GSS_C_NO_CONTEXT)
+        return GSS_S_NO_CONTEXT;
+
+    return krb5_gss_get_mic_iov_length(minor_status, ctx->gssc, qop_req, iov,
+                                       iov_count);
+}
diff -rupN krb5-1.11.3/src/lib/gssapi/krb5/k5sealiov.c krb5-1.11.3-patched/src/lib/gssapi/krb5/k5sealiov.c
--- krb5-1.11.3/src/lib/gssapi/krb5/k5sealiov.c	2015-10-29 14:32:44.757908834 +0100
+++ krb5-1.11.3-patched/src/lib/gssapi/krb5/k5sealiov.c	2015-10-29 14:49:40.362708161 +0100
@@ -51,17 +51,16 @@ make_seal_token_v1_iov(krb5_context cont
     unsigned char *ptr;
     krb5_keyusage sign_usage = KG_USAGE_SIGN;
 
-    assert(toktype == KG_TOK_WRAP_MSG);
-
     md5cksum.length = cksum.length = 0;
     md5cksum.contents = cksum.contents = NULL;
 
-    header = kg_locate_iov(iov, iov_count, GSS_IOV_BUFFER_TYPE_HEADER);
+    header = kg_locate_header_iov(iov, iov_count, toktype);
     if (header == NULL)
         return EINVAL;
 
     padding = kg_locate_iov(iov, iov_count, GSS_IOV_BUFFER_TYPE_PADDING);
-    if (padding == NULL && (ctx->gss_flags & GSS_C_DCE_STYLE) == 0)
+    if (padding == NULL && toktype == KG_TOK_WRAP_MSG &&
+        (ctx->gss_flags & GSS_C_DCE_STYLE) == 0)
         return EINVAL;
 
     trailer = kg_locate_iov(iov, iov_count, GSS_IOV_BUFFER_TYPE_TRAILER);
@@ -171,7 +170,7 @@ make_seal_token_v1_iov(krb5_context cont
         goto cleanup;
     md5cksum.length = k5_trailerlen;
 
-    if (k5_headerlen != 0) {
+    if (k5_headerlen != 0 && toktype == KG_TOK_WRAP_MSG) {
         code = kg_make_confounder(context, ctx->enc->keyblock.enctype,
                                   ptr + 14 + ctx->cksum_size);
         if (code != 0)
@@ -332,7 +331,8 @@ kg_seal_iov_length(OM_uint32 *minor_stat
                    gss_qop_t qop_req,
                    int *conf_state,
                    gss_iov_buffer_desc *iov,
-                   int iov_count)
+                   int iov_count,
+                   int toktype)
 {
     krb5_gss_ctx_id_rec *ctx;
     gss_iov_buffer_t header, trailer, padding;
@@ -341,7 +341,7 @@ kg_seal_iov_length(OM_uint32 *minor_stat
     unsigned int k5_headerlen = 0, k5_trailerlen = 0, k5_padlen = 0;
     krb5_error_code code;
     krb5_context context;
-    int dce_style;
+    int dce_or_mic;
 
     if (qop_req != GSS_C_QOP_DEFAULT) {
         *minor_status = (OM_uint32)G_UNKNOWN_QOP;
@@ -354,7 +354,7 @@ kg_seal_iov_length(OM_uint32 *minor_stat
         return GSS_S_NO_CONTEXT;
     }
 
-    header = kg_locate_iov(iov, iov_count, GSS_IOV_BUFFER_TYPE_HEADER);
+    header = kg_locate_header_iov(iov, iov_count, toktype);
     if (header == NULL) {
         *minor_status = EINVAL;
         return GSS_S_FAILURE;
@@ -366,12 +366,15 @@ kg_seal_iov_length(OM_uint32 *minor_stat
         INIT_IOV_DATA(trailer);
     }
 
-    dce_style = ((ctx->gss_flags & GSS_C_DCE_STYLE) != 0);
+    /* MIC tokens and DCE-style wrap tokens have similar length considerations:
+     * no padding, and the framing surrounds the header only, not the data. */
+    dce_or_mic = ((ctx->gss_flags & GSS_C_DCE_STYLE) != 0 ||
+                  toktype == KG_TOK_MIC_MSG);
 
     /* For CFX, EC is used instead of padding, and is placed in header or trailer */
     padding = kg_locate_iov(iov, iov_count, GSS_IOV_BUFFER_TYPE_PADDING);
     if (padding == NULL) {
-        if (conf_req_flag && ctx->proto == 0 && !dce_style) {
+        if (conf_req_flag && ctx->proto == 0 && !dce_or_mic) {
             *minor_status = EINVAL;
             return GSS_S_FAILURE;
         }
@@ -425,7 +428,7 @@ kg_seal_iov_length(OM_uint32 *minor_stat
                 return GSS_S_FAILURE;
             }
 
-            if (k5_padlen == 0 && dce_style) {
+            if (k5_padlen == 0 && dce_or_mic) {
                 /* Windows rejects AEAD tokens with non-zero EC */
                 code = krb5_c_block_size(context, enctype, &ec);
                 if (code != 0) {
@@ -439,7 +442,7 @@ kg_seal_iov_length(OM_uint32 *minor_stat
         } else {
             gss_trailerlen = k5_trailerlen; /* Kerb-Checksum */
         }
-    } else if (!dce_style) {
+    } else if (!dce_or_mic) {
         k5_padlen = (ctx->sealalg == SEAL_ALG_MICROSOFT_RC4) ? 1 : 8;
 
         if (k5_padlen == 1)
@@ -458,14 +461,14 @@ kg_seal_iov_length(OM_uint32 *minor_stat
 
         data_size = 14 /* Header */ + ctx->cksum_size + k5_headerlen;
 
-        if (!dce_style)
+        if (!dce_or_mic)
             data_size += data_length;
 
         gss_headerlen = g_token_size(ctx->mech_used, data_size);
 
         /* g_token_size() will include data_size as well as the overhead, so
          * subtract data_length just to get the overhead (ie. token size) */
-        if (!dce_style)
+        if (!dce_or_mic)
             gss_headerlen -= data_length;
     }
 
@@ -519,13 +522,13 @@ krb5_gss_wrap_iov_length(OM_uint32 *mino
 {
     OM_uint32 major_status;
 
-    major_status = kg_seal_iov_length(minor_status, context_handle, conf_req_flag,
-                                      qop_req, conf_state, iov, iov_count);
+    major_status = kg_seal_iov_length(minor_status, context_handle,
+                                      conf_req_flag, qop_req, conf_state, iov,
+                                      iov_count, KG_TOK_WRAP_MSG);
     return major_status;
 }
 
-#if 0
-OM_uint32
+OM_uint32 KRB5_CALLCONV
 krb5_gss_get_mic_iov(OM_uint32 *minor_status,
                      gss_ctx_id_t context_handle,
                      gss_qop_t qop_req,
@@ -541,19 +544,17 @@ krb5_gss_get_mic_iov(OM_uint32 *minor_st
     return major_status;
 }
 
-OM_uint32
+OM_uint32 KRB5_CALLCONV
 krb5_gss_get_mic_iov_length(OM_uint32 *minor_status,
                             gss_ctx_id_t context_handle,
-                            int conf_req_flag,
                             gss_qop_t qop_req,
-                            int *conf_state,
                             gss_iov_buffer_desc *iov,
                             int iov_count)
 {
     OM_uint32 major_status;
 
-    major_status = kg_seal_iov_length(minor_status, context_handle, conf_req_flag,
-                                      qop_req, conf_state, iov, iov_count);
+    major_status = kg_seal_iov_length(minor_status, context_handle, FALSE,
+                                      qop_req, NULL, iov, iov_count,
+                                      KG_TOK_MIC_MSG);
     return major_status;
 }
-#endif
Binary files krb5-1.11.3/src/lib/gssapi/krb5/.k5sealiov.c.swp and krb5-1.11.3-patched/src/lib/gssapi/krb5/.k5sealiov.c.swp differ
diff -rupN krb5-1.11.3/src/lib/gssapi/krb5/k5sealv3iov.c krb5-1.11.3-patched/src/lib/gssapi/krb5/k5sealv3iov.c
--- krb5-1.11.3/src/lib/gssapi/krb5/k5sealv3iov.c	2015-10-29 14:32:44.757908834 +0100
+++ krb5-1.11.3-patched/src/lib/gssapi/krb5/k5sealv3iov.c	2015-10-29 14:49:40.362708161 +0100
@@ -76,7 +76,7 @@ gss_krb5int_make_seal_token_v3_iov(krb5_
 
     kg_iov_msglen(iov, iov_count, &data_length, &assoc_data_length);
 
-    header = kg_locate_iov(iov, iov_count, GSS_IOV_BUFFER_TYPE_HEADER);
+    header = kg_locate_header_iov(iov, iov_count, toktype);
     if (header == NULL)
         return EINVAL;
 
@@ -240,7 +240,7 @@ gss_krb5int_make_seal_token_v3_iov(krb5_
 
         code = kg_make_checksum_iov_v3(context, cksumtype,
                                        rrc, key, key_usage,
-                                       iov, iov_count);
+                                       iov, iov_count, toktype);
         if (code != 0)
             goto cleanup;
 
@@ -302,7 +302,7 @@ gss_krb5int_unseal_v3_iov(krb5_context c
     if (qop_state != NULL)
         *qop_state = GSS_C_QOP_DEFAULT;
 
-    header = kg_locate_iov(iov, iov_count, GSS_IOV_BUFFER_TYPE_HEADER);
+    header = kg_locate_header_iov(iov, iov_count, toktype);
     assert(header != NULL);
 
     padding = kg_locate_iov(iov, iov_count, GSS_IOV_BUFFER_TYPE_PADDING);
@@ -421,7 +421,7 @@ gss_krb5int_unseal_v3_iov(krb5_context c
 
             code = kg_verify_checksum_iov_v3(context, cksumtype, rrc,
                                              key, key_usage,
-                                             iov, iov_count, &valid);
+                                             iov, iov_count, toktype, &valid);
             if (code != 0 || valid == FALSE) {
                 *minor_status = code;
                 return GSS_S_BAD_SIG;
@@ -438,9 +438,12 @@ gss_krb5int_unseal_v3_iov(krb5_context c
             goto defective;
         seqnum = load_64_be(ptr + 8);
 
-        code = kg_verify_checksum_iov_v3(context, cksumtype, 0,
+        /* For MIC tokens, the GSS header and checksum are in the same buffer.
+         * Fake up an RRC so that the checksum is expected in the header. */
+        rrc = (trailer != NULL) ? 0 : header->buffer.length - 16;
+        code = kg_verify_checksum_iov_v3(context, cksumtype, rrc,
                                          key, key_usage,
-                                         iov, iov_count, &valid);
+                                         iov, iov_count, toktype, &valid);
         if (code != 0 || valid == FALSE) {
             *minor_status = code;
             return GSS_S_BAD_SIG;
diff -rupN krb5-1.11.3/src/lib/gssapi/krb5/k5unsealiov.c krb5-1.11.3-patched/src/lib/gssapi/krb5/k5unsealiov.c
--- krb5-1.11.3/src/lib/gssapi/krb5/k5unsealiov.c	2015-10-29 14:32:44.757908834 +0100
+++ krb5-1.11.3-patched/src/lib/gssapi/krb5/k5unsealiov.c	2015-10-29 14:55:59.288699583 +0100
@@ -57,12 +57,10 @@ kg_unseal_v1_iov(krb5_context context,
     size_t sumlen;
     krb5_keyusage sign_usage = KG_USAGE_SIGN;
 
-    assert(toktype == KG_TOK_WRAP_MSG);
-
     md5cksum.length = cksum.length = 0;
     md5cksum.contents = cksum.contents = NULL;
 
-    header = kg_locate_iov(iov, iov_count, GSS_IOV_BUFFER_TYPE_HEADER);
+    header = kg_locate_header_iov(iov, iov_count, toktype);
     assert(header != NULL);
 
     trailer = kg_locate_iov(iov, iov_count, GSS_IOV_BUFFER_TYPE_TRAILER);
@@ -324,7 +322,7 @@ kg_unseal_iov_token(OM_uint32 *minor_sta
     int toktype2;
     int vfyflags = 0;
 
-    header = kg_locate_iov(iov, iov_count, GSS_IOV_BUFFER_TYPE_HEADER);
+    header = kg_locate_header_iov(iov, iov_count, toktype);
     if (header == NULL) {
         *minor_status = EINVAL;
         return GSS_S_FAILURE;
@@ -336,7 +334,8 @@ kg_unseal_iov_token(OM_uint32 *minor_sta
     ptr = (unsigned char *)header->buffer.value;
     input_length = header->buffer.length;
 
-    if ((ctx->gss_flags & GSS_C_DCE_STYLE) == 0) {
+    if ((ctx->gss_flags & GSS_C_DCE_STYLE) == 0 &&
+        toktype == KG_TOK_WRAP_MSG) {
         size_t data_length, assoc_data_length;
 
         kg_iov_msglen(iov, iov_count, &data_length, &assoc_data_length);
@@ -666,8 +665,7 @@ krb5_gss_unwrap_iov(OM_uint32 *minor_sta
     return major_status;
 }
 
-#if 0
-OM_uint32
+OM_uint32 KRB5_CALLCONV
 krb5_gss_verify_mic_iov(OM_uint32 *minor_status,
                         gss_ctx_id_t context_handle,
                         gss_qop_t *qop_state,
@@ -678,8 +676,7 @@ krb5_gss_verify_mic_iov(OM_uint32 *minor
 
     major_status = kg_unseal_iov(minor_status, context_handle,
                                  NULL, qop_state,
-                                 iov, iov_count, KG_TOK_WRAP_MSG);
+                                 iov, iov_count, KG_TOK_MIC_MSG);
 
     return major_status;
 }
-#endif
diff -rupN krb5-1.11.3/src/lib/gssapi/krb5/util_cksum.c krb5-1.11.3-patched/src/lib/gssapi/krb5/util_cksum.c
--- krb5-1.11.3/src/lib/gssapi/krb5/util_cksum.c	2015-10-29 14:32:44.757908834 +0100
+++ krb5-1.11.3-patched/src/lib/gssapi/krb5/util_cksum.c	2015-10-29 14:49:40.362708161 +0100
@@ -122,15 +122,13 @@ kg_make_checksum_iov_v1(krb5_context con
     krb5_error_code code;
     gss_iov_buffer_desc *header;
     krb5_crypto_iov *kiov;
-    size_t kiov_count;
     int i = 0, j;
     size_t conf_len = 0, token_header_len;
 
-    header = kg_locate_iov(iov, iov_count, GSS_IOV_BUFFER_TYPE_HEADER);
+    header = kg_locate_header_iov(iov, iov_count, toktype);
     assert(header != NULL);
 
-    kiov_count = 3 + iov_count;
-    kiov = (krb5_crypto_iov *)xmalloc(kiov_count * sizeof(krb5_crypto_iov));
+    kiov = calloc(iov_count + 3, sizeof(krb5_crypto_iov));
     if (kiov == NULL)
         return ENOMEM;
 
@@ -172,7 +170,7 @@ kg_make_checksum_iov_v1(krb5_context con
         i++;
     }
 
-    code = krb5_k_make_checksum_iov(context, type, seq, sign_usage, kiov, kiov_count);
+    code = krb5_k_make_checksum_iov(context, type, seq, sign_usage, kiov, i);
     if (code == 0) {
         checksum->length = kiov[0].data.length;
         checksum->contents = (unsigned char *)kiov[0].data.data;
@@ -192,6 +190,7 @@ checksum_iov_v3(krb5_context context,
                 krb5_keyusage sign_usage,
                 gss_iov_buffer_desc *iov,
                 int iov_count,
+                int toktype,
                 krb5_boolean verify,
                 krb5_boolean *valid)
 {
@@ -210,7 +209,7 @@ checksum_iov_v3(krb5_context context,
     if (code != 0)
         return code;
 
-    header = kg_locate_iov(iov, iov_count, GSS_IOV_BUFFER_TYPE_HEADER);
+    header = kg_locate_header_iov(iov, iov_count, toktype);
     assert(header != NULL);
 
     trailer = kg_locate_iov(iov, iov_count, GSS_IOV_BUFFER_TYPE_TRAILER);
@@ -273,10 +272,11 @@ kg_make_checksum_iov_v3(krb5_context con
                         krb5_key key,
                         krb5_keyusage sign_usage,
                         gss_iov_buffer_desc *iov,
-                        int iov_count)
+                        int iov_count,
+                        int toktype)
 {
     return checksum_iov_v3(context, type, rrc, key,
-                           sign_usage, iov, iov_count, 0, NULL);
+                           sign_usage, iov, iov_count, toktype, 0, NULL);
 }
 
 krb5_error_code
@@ -287,8 +287,9 @@ kg_verify_checksum_iov_v3(krb5_context c
                           krb5_keyusage sign_usage,
                           gss_iov_buffer_desc *iov,
                           int iov_count,
+                          int toktype,
                           krb5_boolean *valid)
 {
     return checksum_iov_v3(context, type, rrc, key,
-                           sign_usage, iov, iov_count, 1, valid);
+                           sign_usage, iov, iov_count, toktype, 1, valid);
 }
diff -rupN krb5-1.11.3/src/lib/gssapi/krb5/util_crypt.c krb5-1.11.3-patched/src/lib/gssapi/krb5/util_crypt.c
--- krb5-1.11.3/src/lib/gssapi/krb5/util_crypt.c	2015-10-29 14:32:44.757908834 +0100
+++ krb5-1.11.3-patched/src/lib/gssapi/krb5/util_crypt.c	2015-10-29 14:49:40.362708161 +0100
@@ -626,6 +626,17 @@ kg_locate_iov(gss_iov_buffer_desc *iov,
     return p;
 }
 
+/* Return the IOV where the GSSAPI token header should be placed (and possibly
+ * the checksum as well, depending on the token type). */
+gss_iov_buffer_t
+kg_locate_header_iov(gss_iov_buffer_desc *iov, int iov_count, int toktype)
+{
+    if (toktype == KG_TOK_MIC_MSG)
+        return kg_locate_iov(iov, iov_count, GSS_IOV_BUFFER_TYPE_MIC_TOKEN);
+    else
+        return kg_locate_iov(iov, iov_count, GSS_IOV_BUFFER_TYPE_HEADER);
+}
+
 void
 kg_iov_msglen(gss_iov_buffer_desc *iov, int iov_count, size_t *data_length_p,
               size_t *assoc_data_length_p)
diff -rupN krb5-1.11.3/src/lib/gssapi/libgssapi_krb5.exports krb5-1.11.3-patched/src/lib/gssapi/libgssapi_krb5.exports
--- krb5-1.11.3/src/lib/gssapi/libgssapi_krb5.exports	2015-10-29 14:32:44.757908834 +0100
+++ krb5-1.11.3-patched/src/lib/gssapi/libgssapi_krb5.exports	2015-10-29 14:49:40.362708161 +0100
@@ -65,6 +65,8 @@ gss_export_name
 gss_export_name_composite
 gss_export_sec_context
 gss_get_mic
+gss_get_mic_iov
+gss_get_mic_iov_length
 gss_get_name_attribute
 gss_import_cred
 gss_import_name
@@ -139,6 +141,7 @@ gss_unwrap_iov
 gss_userok
 gss_verify
 gss_verify_mic
+gss_verify_mic_iov
 gss_wrap
 gss_wrap_aead
 gss_wrap_iov
diff -rupN krb5-1.11.3/src/lib/gssapi/mechglue/g_unwrap_iov.c krb5-1.11.3-patched/src/lib/gssapi/mechglue/g_unwrap_iov.c
--- krb5-1.11.3/src/lib/gssapi/mechglue/g_unwrap_iov.c	2015-10-29 14:32:44.753908816 +0100
+++ krb5-1.11.3-patched/src/lib/gssapi/mechglue/g_unwrap_iov.c	2015-10-29 14:49:40.362708161 +0100
@@ -111,3 +111,28 @@ int			iov_count;
 
     return (GSS_S_BAD_MECH);
 }
+
+OM_uint32 KRB5_CALLCONV
+gss_verify_mic_iov(OM_uint32 *minor_status, gss_ctx_id_t context_handle,
+		   gss_qop_t *qop_state, gss_iov_buffer_desc *iov,
+		   int iov_count)
+{
+    OM_uint32 status;
+    gss_union_ctx_id_t ctx;
+    gss_mechanism mech;
+
+    status = val_unwrap_iov_args(minor_status, context_handle, NULL,
+				 qop_state, iov, iov_count);
+    if (status != GSS_S_COMPLETE)
+	return status;
+
+    /* Select the approprate underlying mechanism routine and call it. */
+    ctx = (gss_union_ctx_id_t)context_handle;
+    mech = gssint_get_mechanism(ctx->mech_type);
+    if (mech == NULL)
+	return GSS_S_BAD_MECH;
+    if (mech->gss_verify_mic_iov == NULL)
+	return GSS_S_UNAVAILABLE;
+    return mech->gss_verify_mic_iov(minor_status, ctx->internal_ctx_id,
+				    qop_state, iov, iov_count);
+}
diff -rupN krb5-1.11.3/src/lib/gssapi/mechglue/g_wrap_iov.c krb5-1.11.3-patched/src/lib/gssapi/mechglue/g_wrap_iov.c
--- krb5-1.11.3/src/lib/gssapi/mechglue/g_wrap_iov.c	2015-10-29 14:32:44.753908816 +0100
+++ krb5-1.11.3-patched/src/lib/gssapi/mechglue/g_wrap_iov.c	2015-10-29 14:49:40.362708161 +0100
@@ -176,6 +176,55 @@ int			iov_count;
 }
 
 OM_uint32 KRB5_CALLCONV
+gss_get_mic_iov(OM_uint32 *minor_status, gss_ctx_id_t context_handle,
+		gss_qop_t qop_req, gss_iov_buffer_desc *iov, int iov_count)
+{
+    OM_uint32 status;
+    gss_union_ctx_id_t ctx;
+    gss_mechanism mech;
+
+    status = val_wrap_iov_args(minor_status, context_handle, 0, qop_req, NULL,
+			       iov, iov_count);
+    if (status != GSS_S_COMPLETE)
+	return status;
+
+    /* Select the approprate underlying mechanism routine and call it. */
+    ctx = (gss_union_ctx_id_t)context_handle;
+    mech = gssint_get_mechanism(ctx->mech_type);
+    if (mech == NULL)
+	return GSS_S_BAD_MECH;
+    if (mech->gss_get_mic_iov == NULL)
+	return GSS_S_UNAVAILABLE;
+    return mech->gss_get_mic_iov(minor_status, ctx->internal_ctx_id, qop_req,
+				 iov, iov_count);
+}
+
+OM_uint32 KRB5_CALLCONV
+gss_get_mic_iov_length(OM_uint32 *minor_status, gss_ctx_id_t context_handle,
+		       gss_qop_t qop_req, gss_iov_buffer_desc *iov,
+		       int iov_count)
+{
+    OM_uint32 status;
+    gss_union_ctx_id_t ctx;
+    gss_mechanism mech;
+
+    status = val_wrap_iov_args(minor_status, context_handle, 0, qop_req, NULL,
+			       iov, iov_count);
+    if (status != GSS_S_COMPLETE)
+	return status;
+
+    /* Select the approprate underlying mechanism routine and call it. */
+    ctx = (gss_union_ctx_id_t)context_handle;
+    mech = gssint_get_mechanism(ctx->mech_type);
+    if (mech == NULL)
+	return GSS_S_BAD_MECH;
+    if (mech->gss_get_mic_iov_length == NULL)
+	return GSS_S_UNAVAILABLE;
+    return mech->gss_get_mic_iov_length(minor_status, ctx->internal_ctx_id,
+					qop_req, iov, iov_count);
+}
+
+OM_uint32 KRB5_CALLCONV
 gss_release_iov_buffer (minor_status,
 			iov,
 			iov_count)
diff -rupN krb5-1.11.3/src/lib/gssapi/mechglue/mglueP.h krb5-1.11.3-patched/src/lib/gssapi/mechglue/mglueP.h
--- krb5-1.11.3/src/lib/gssapi/mechglue/mglueP.h	2015-10-29 14:32:44.753908816 +0100
+++ krb5-1.11.3-patched/src/lib/gssapi/mechglue/mglueP.h	2015-10-29 14:49:40.362708161 +0100
@@ -674,6 +674,35 @@ typedef struct gss_config {
 	    gss_cred_id_t *		/* cred_handle */
 	/* */);
 
+	/* get_mic_iov extensions, added in 1.12 */
+
+	OM_uint32	(KRB5_CALLCONV *gss_get_mic_iov)
+	(
+	    OM_uint32 *,		/* minor_status */
+	    gss_ctx_id_t,		/* context_handle */
+	    gss_qop_t,			/* qop_req */
+	    gss_iov_buffer_desc *,	/* iov */
+	    int				/* iov_count */
+	);
+
+	OM_uint32	(KRB5_CALLCONV *gss_verify_mic_iov)
+	(
+	    OM_uint32 *,		/* minor_status */
+	    gss_ctx_id_t,		/* context_handle */
+	    gss_qop_t *,		/* qop_state */
+	    gss_iov_buffer_desc *,	/* iov */
+	    int				/* iov_count */
+	);
+
+	OM_uint32	(KRB5_CALLCONV *gss_get_mic_iov_length)
+	(
+	    OM_uint32 *,		/* minor_status */
+	    gss_ctx_id_t,		/* context_handle */
+	    gss_qop_t,			/* qop_req */
+	    gss_iov_buffer_desc *,	/* iov */
+	    int				/* iov_count */
+	);
+
 } *gss_mechanism;
 
 /*
diff -rupN krb5-1.11.3/src/lib/gssapi/spnego/gssapiP_spnego.h krb5-1.11.3-patched/src/lib/gssapi/spnego/gssapiP_spnego.h
--- krb5-1.11.3/src/lib/gssapi/spnego/gssapiP_spnego.h	2015-10-29 14:32:44.753908816 +0100
+++ krb5-1.11.3-patched/src/lib/gssapi/spnego/gssapiP_spnego.h	2015-10-29 14:49:40.362708161 +0100
@@ -629,6 +629,33 @@ spnego_gss_import_cred(
 	gss_cred_id_t *cred_handle
 );
 
+OM_uint32 KRB5_CALLCONV
+spnego_gss_get_mic_iov(
+	OM_uint32 *minor_status,
+	gss_ctx_id_t context_handle,
+	gss_qop_t qop_req,
+	gss_iov_buffer_desc *iov,
+	int iov_count
+);
+
+OM_uint32 KRB5_CALLCONV
+spnego_gss_verify_mic_iov(
+	OM_uint32 *minor_status,
+	gss_ctx_id_t context_handle,
+	gss_qop_t *qop_state,
+	gss_iov_buffer_desc *iov,
+	int iov_count
+);
+
+OM_uint32 KRB5_CALLCONV
+spnego_gss_get_mic_iov_length(
+	OM_uint32 *minor_status,
+	gss_ctx_id_t context_handle,
+	gss_qop_t qop_req,
+	gss_iov_buffer_desc *iov,
+	int iov_count
+);
+
 #ifdef	__cplusplus
 }
 #endif
diff -rupN krb5-1.11.3/src/lib/gssapi/spnego/spnego_mech.c krb5-1.11.3-patched/src/lib/gssapi/spnego/spnego_mech.c
--- krb5-1.11.3/src/lib/gssapi/spnego/spnego_mech.c	2015-10-29 14:32:44.753908816 +0100
+++ krb5-1.11.3-patched/src/lib/gssapi/spnego/spnego_mech.c	2015-10-29 14:49:40.366708181 +0100
@@ -279,6 +279,12 @@ static struct gss_config spnego_mechanis
 	spnego_gss_acquire_cred_with_password,
 	spnego_gss_export_cred,
 	spnego_gss_import_cred,
+	NULL,				/* gssspi_import_sec_context_by_mech */
+	NULL,				/* gssspi_import_name_by_mech */
+	NULL,				/* gssspi_import_cred_by_mech */
+	spnego_gss_get_mic_iov,
+	spnego_gss_verify_mic_iov,
+	spnego_gss_get_mic_iov_length
 };
 
 #ifdef _GSS_STATIC_LINK
@@ -2841,6 +2847,33 @@ spnego_gss_import_cred(OM_uint32 *minor_
 	return (ret);
 }
 
+OM_uint32 KRB5_CALLCONV
+spnego_gss_get_mic_iov(OM_uint32 *minor_status, gss_ctx_id_t context_handle,
+		       gss_qop_t qop_req, gss_iov_buffer_desc *iov,
+		       int iov_count)
+{
+    return gss_get_mic_iov(minor_status, context_handle, qop_req, iov,
+			   iov_count);
+}
+
+OM_uint32 KRB5_CALLCONV
+spnego_gss_verify_mic_iov(OM_uint32 *minor_status, gss_ctx_id_t context_handle,
+			  gss_qop_t *qop_state, gss_iov_buffer_desc *iov,
+			  int iov_count)
+{
+    return gss_verify_mic_iov(minor_status, context_handle, qop_state, iov,
+			      iov_count);
+}
+
+OM_uint32 KRB5_CALLCONV
+spnego_gss_get_mic_iov_length(OM_uint32 *minor_status,
+			      gss_ctx_id_t context_handle, gss_qop_t qop_req,
+			      gss_iov_buffer_desc *iov, int iov_count)
+{
+    return gss_get_mic_iov_length(minor_status, context_handle, qop_req, iov,
+				  iov_count);
+}
+
 /*
  * We will release everything but the ctx_handle so that it
  * can be passed back to init/accept context. This routine should
diff -rupN krb5-1.11.3/src/lib/gssapi32.def krb5-1.11.3-patched/src/lib/gssapi32.def
--- krb5-1.11.3/src/lib/gssapi32.def	2015-10-29 14:32:44.757908834 +0100
+++ krb5-1.11.3-patched/src/lib/gssapi32.def	2015-10-29 14:49:40.366708181 +0100
@@ -176,3 +176,7 @@ EXPORTS
 	gss_store_cred_into				@141
 	gss_export_cred					@142
 	gss_import_cred					@143
+; Added in 1.12
+	gss_get_mic_iov					@144
+	gss_get_mic_iov_length				@145
+	gss_verify_mic_iov				@146
openSUSE Build Service is sponsored by