.deps
.libs
+.a.out.dSYM
+.dSYM
gss_LTLIBRARIES = libmech_eap.la
-libmech_eap_la_CFLAGS = -g -Wall -fno-strict-aliasing @KRB5_CFLAGS@ @TARGET_CFLAGS@
-libmech_eap_la_LDFLAGS = -export-symbols mech_eap.exports -version-info 0:0:0 @KRB5_LDFLAGS@ @TARGET_LDFLAGS@
-libmech_eap_la_LIBADD = @KRB5_LIBS@
+libmech_eap_la_CFLAGS = -DBUILD_GSSEAP_LIB -g -Wall -fno-strict-aliasing @EAP_CFLAGS@ @KRB5_CFLAGS@ @TARGET_CFLAGS@
+libmech_eap_la_LDFLAGS = -export-symbols mech_eap.exports -version-info 0:0:0 @EAP_LDFLAGS@ @KRB5_LDFLAGS@ @TARGET_LDFLAGS@
+libmech_eap_la_LIBADD = @EAP_LIBS@ @KRB5_LIBS@
libmech_eap_la_SOURCES = \
accept_sec_context.c \
init_sec_context.c \
inquire_context.c \
inquire_cred.c \
+ inquire_cred_by_oid.c \
inquire_mechs_for_name.c \
inquire_names_for_mech.c \
+ inquire_sec_context_by_oid.c \
map_name_to_any.c \
process_context_token.c \
pseudo_random.c \
release_cred.c \
release_name.c \
set_name_attribute.c \
+ set_cred_option.c \
+ set_sec_context_option.c \
store_cred.c \
unwrap.c \
unwrap_iov.c \
+ util_context.c \
+ util_cksum.c \
+ util_cred.c \
+ util_crypt.c \
+ util_name.c \
verify_mic.c \
wrap.c \
wrap_iov.c \
dnl Based on the one from the Boinc project by Reinhard
AC_DEFUN([AX_CHECK_KRB5],
-[AC_MSG_CHECKING(for Kerberos)
+[AC_MSG_CHECKING(for GSS-API and Kerberos implementation)
KRB5_DIR=
found_krb5="no"
AC_ARG_WITH(krb5,
krb5dir="$dir"
if test -f "$dir/include/krb5.h"; then
found_krb5="yes";
- krb5_DIR="${krb5dir}"
- krb5_CFLAGS="-I$krb5dir/include";
+ KRB5_DIR="${krb5dir}"
+ KRB5_CFLAGS="-I$krb5dir/include";
break;
fi
- if test -f "$dir/include/krb5.h"; then
- found_krb5="yes";
- krb5_DIR="${krb5dir}"
- krb5_CFLAGS="-I$krb5dir/include/";
- break
- fi
done
AC_MSG_RESULT($found_krb5)
if test x_$found_krb5 != x_yes; then
AC_MSG_ERROR([
----------------------------------------------------------------------
- Cannot find krb5 libraries.
+ Cannot find GSS-API/Kerberos libraries.
Please install MIT or Heimdal or specify installation directory with
--with-krb5=(dir).
])
else
printf "Kerberos found in $krb5dir\n";
- krb5_LIBS="-lgssapi_krb5 -lkrb5";
- krb5_LDFLAGS="-L$krb5dir/lib";
+ KRB5_LIBS="-lgssapi_krb5 -lkrb5";
+ KRB5_LDFLAGS="-L$krb5dir/lib";
AC_SUBST(KRB5_CFLAGS)
AC_SUBST(KRB5_LDFLAGS)
AC_SUBST(KRB5_LIBS)
fi
])dnl
+
+AC_DEFUN([AX_CHECK_EAP],
+[AC_MSG_CHECKING(for EAP implementation)
+EAP_DIR=
+found_eap="no"
+AC_ARG_WITH(eap,
+ AC_HELP_STRING([--with-eap],
+ [Use eap (in specified installation directory)]),
+ [check_eap_dir="$withval"],
+ [check_eap_dir=])
+for dir in $check_eap_dir /usr /usr/local ; do
+ eapdir="$dir"
+ if test -f "$dir/src/eap_peer/eap.h"; then
+ found_eap="yes";
+ EAP_DIR="${eapdir}"
+ EAP_CFLAGS="-I$eapdir/src/common -I$eapdir/src -I$eapdir/src/utils";
+ break;
+ fi
+done
+AC_MSG_RESULT($found_eap)
+if test x_$found_eap != x_yes; then
+ AC_MSG_ERROR([
+----------------------------------------------------------------------
+ Cannot find EAP libraries.
+
+ Please install wpa_supplicant or specify installation directory with
+ --with-eap=(dir).
+----------------------------------------------------------------------
+])
+else
+ printf "EAP found in $eapdir\n";
+ EAP_LIBS="-leap";
+ EAP_LDFLAGS="-L$eapdir/eap_example";
+ AC_SUBST(EAP_CFLAGS)
+ AC_SUBST(EAP_LDFLAGS)
+ AC_SUBST(EAP_LIBS)
+fi
+])dnl
+
AC_SUBST(TARGET_CFLAGS)
AC_SUBST(TARGET_LDFLAGS)
AX_CHECK_KRB5
+AX_CHECK_EAP
AC_CONFIG_FILES([Makefile])
AC_OUTPUT
#ifndef _GSSAPIP_EAP_H_
#define _GSSAPIP_EAP_H_ 1
-#include <gssapi/gssapi.h>
-#include <krb5.h>
+#include <assert.h>
+#include <string.h>
+#include <errno.h>
+#include <time.h>
+/* GSS includes */
+#include <gssapi/gssapi.h>
+#include <gssapi/gssapi_ext.h>
#include "gssapi_eap.h"
+/* EAP includes */
+#define IEEE8021X_EAPOL 1
+
+#include <common.h>
+#include <eap_peer/eap.h>
+#include <eap_peer/eap_config.h>
+#include <wpabuf.h>
+
+/* Kerberos includes */
+#include <krb5.h>
+
struct gss_name_struct {
OM_uint32 flags;
- krb5_principal principal;
+ krb5_principal kerberosName;
void *aaa;
void *assertion;
};
struct gss_cred_id_struct {
OM_uint32 flags;
- gss_name_t initiatorName;
- gss_name_t acceptorName;
+ gss_name_t name;
gss_buffer_desc password;
+ time_t expiryTime;
};
#define CTX_FLAG_INITIATOR 0x00000001
+#define CTX_IS_INITIATOR(ctx) (((ctx)->flags & CTX_FLAG_INITIATOR) != 0)
+
enum eap_gss_state {
EAP_STATE_AUTHENTICATE = 1,
EAP_STATE_KEY_TRANSPORT,
EAP_STATE_ESTABLISHED
};
+#define CTX_IS_ESTABLISHED(ctx) ((ctx)->state == EAP_STATE_ESTABLISHED)
+
+/* Initiator context flags */
+#define CTX_FLAG_EAP_SUCCESS 0x00010000
+#define CTX_FLAG_EAP_RESTART 0x00020000
+#define CTX_FLAG_EAP_FAIL 0x00040000
+#define CTX_FLAG_EAP_RESP 0x00080000
+#define CTX_FLAG_EAP_NO_RESP 0x00100000
+#define CTX_FLAG_EAP_REQ 0x00200000
+#define CTX_FLAG_EAP_PORT_ENABLED 0x00400000
+#define CTX_FLAG_EAP_ALT_ACCEPT 0x00800000
+#define CTX_FLAG_EAP_ALT_REJECT 0x01000000
+
+struct eap_gss_initiator_ctx {
+ struct wpabuf *eapReqData;
+ unsigned int idleWhile;
+ struct eap_peer_config eapConfig;
+ struct eap_sm *eap;
+};
+
+/* Acceptor context flags */
+struct eap_gss_acceptor_ctx {
+};
+
struct gss_ctx_id_struct {
enum eap_gss_state state;
OM_uint32 flags;
OM_uint32 gssFlags;
krb5_context kerberosCtx;
gss_OID mechanismUsed;
+ krb5_enctype encryptionType;
krb5_cksumtype checksumType;
krb5_keyblock *encryptionKey;
gss_name_t initiatorName;
gss_name_t acceptorName;
- OM_uint32 lifetime;
+ time_t expiryTime;
+ union {
+ struct eap_gss_initiator_ctx initiator;
+ #define initiatorCtx ctxU.initiator
+ struct eap_gss_acceptor_ctx acceptor;
+ #define acceptorCtx ctxU.acceptor
+ } ctxU;
+ uint64_t sendSeq, recvSeq;
+ void *seqState;
+};
+
+#define TOK_FLAG_SENDER_IS_ACCEPTOR 0x01
+#define TOK_FLAG_WRAP_CONFIDENTIAL 0x02
+#define TOK_FLAG_ACCEPTOR_SUBKEY 0x04
+
+enum gss_eap_token_type {
+ TOK_TYPE_MIC = 0x0404,
+ TOK_TYPE_WRAP = 0x0504,
+ TOK_TYPE_DELETE = 0x0405
};
+/* Helper APIs */
+OM_uint32 gssEapAllocContext(OM_uint32 *minor, gss_ctx_id_t *pCtx);
+OM_uint32 gssEapReleaseContext(OM_uint32 *minor, gss_ctx_id_t *pCtx);
+
+OM_uint32 gssEapAllocName(OM_uint32 *minor, gss_name_t *pName);
+OM_uint32 gssEapReleaseName(OM_uint32 *minor, gss_name_t *pName);
+
+OM_uint32 gssEapAllocCred(OM_uint32 *minor, gss_cred_id_t *pCred);
+OM_uint32 gssEapReleaseCred(OM_uint32 *minor, gss_cred_id_t *pCred);
+
+/* Kerberos token services */
+#define KRB_USAGE_ACCEPTOR_SEAL 22
+#define KRB_USAGE_ACCEPTOR_SIGN 23
+#define KRB_USAGE_INITIATOR_SEAL 24
+#define KRB_USAGE_INITIATOR_SIGN 25
+
+#if 0
+#define KRB_KEYTYPE(key) ((key)->keytype)
+#else
+#define KRB_KEYTYPE(key) ((key)->enctype)
+#endif
+
+/* util_crypt.c */
+int
+gssEapEncrypt(krb5_context context, int dce_style, size_t ec,
+ size_t rrc, krb5_keyblock *key, int usage, krb5_pointer iv,
+ gss_iov_buffer_desc *iov, int iov_count);
+
+int
+gssEapDecrypt(krb5_context context, int dce_style, size_t ec,
+ size_t rrc, krb5_keyblock *key, int usage, krb5_pointer iv,
+ gss_iov_buffer_desc *iov, int iov_count);
+
+krb5_cryptotype
+gssEapTranslateCryptoFlag(OM_uint32 type);
+
+gss_iov_buffer_t
+gssEapLocateIov(gss_iov_buffer_desc *iov,
+ int iov_count,
+ OM_uint32 type);
+
+void
+gssEapIovMessageLength(gss_iov_buffer_desc *iov,
+ int iov_count,
+ size_t *data_length,
+ size_t *assoc_data_length);
+
+void
+gssEapReleaseIov(gss_iov_buffer_desc *iov, int iov_count);
+
+int
+gssEapIsIntegrityOnly(gss_iov_buffer_desc *iov, int iov_count);
+
+int
+gssEapAllocIov(gss_iov_buffer_t iov, size_t size);
+
+/* util_cksum.c */
+int
+gssEapSign(krb5_context context,
+ krb5_cksumtype type,
+ size_t rrc,
+ krb5_keyblock *key,
+ krb5_keyusage sign_usage,
+ gss_iov_buffer_desc *iov,
+ int iov_count);
+
+int
+gssEapVerify(krb5_context context,
+ krb5_cksumtype type,
+ size_t rrc,
+ krb5_keyblock *key,
+ krb5_keyusage sign_usage,
+ gss_iov_buffer_desc *iov,
+ int iov_count,
+ int *valid);
+
+/* wrap_iov.c */
+OM_uint32
+gssEapWrapOrGetMIC(OM_uint32 *minor,
+ gss_ctx_id_t ctx,
+ int conf_req_flag,
+ int *conf_state,
+ gss_iov_buffer_desc *iov,
+ int iov_count,
+ enum gss_eap_token_type toktype);
+
+OM_uint32
+gssEapUnwrapOrVerifyMIC(OM_uint32 *minor_status,
+ gss_ctx_id_t ctx,
+ int *conf_state,
+ gss_qop_t *qop_state,
+ gss_iov_buffer_desc *iov,
+ int iov_count,
+ enum gss_eap_token_type toktype);
+
+/* Helper macros */
+#define GSSEAP_CALLOC(count, size) (calloc((count), (size)))
+#define GSSEAP_FREE(ptr) (free((ptr)))
+#define GSSEAP_MALLOC(size) (malloc((size)))
+#define GSSEAP_REALLOC(ptr, size) (realloc((ptr), (size)))
+
+#define GSSEAP_NOT_IMPLEMENTED do { \
+ assert(0 && "not implemented"); \
+ *minor = ENOSYS; \
+ return GSS_S_FAILURE; \
+ } while (0)
+
#endif /* _GSSAPIP_EAP_H_ */
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
+/*
+ * lib/gssapi/krb5/k5sealv3iov.c
+ *
+ * Copyright 2008 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ * require a specific license from the United States Government.
+ * It is the responsibility of any person or organization contemplating
+ * export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ *
+ *
+ */
#include "gssapiP_eap.h"
OM_uint32
+gssEapUnwrapOrVerifyMIC(OM_uint32 *minor_status,
+ gss_ctx_id_t ctx,
+ int *conf_state,
+ gss_qop_t *qop_state,
+ gss_iov_buffer_desc *iov,
+ int iov_count,
+ enum gss_eap_token_type toktype)
+{
+ OM_uint32 code;
+ gss_iov_buffer_t header;
+ gss_iov_buffer_t padding;
+ gss_iov_buffer_t trailer;
+ unsigned char acceptor_flag;
+ unsigned char *ptr = NULL;
+ int key_usage;
+ size_t rrc, ec;
+ size_t data_length, assoc_data_length;
+ uint64_t seqnum;
+ krb5_boolean valid;
+ krb5_cksumtype cksumtype;
+ int conf_flag = 0;
+
+ *minor_status = 0;
+
+ if (qop_state != NULL)
+ *qop_state = GSS_C_QOP_DEFAULT;
+
+ if (!CTX_IS_ESTABLISHED(ctx))
+ return GSS_S_NO_CONTEXT;
+
+ header = gssEapLocateIov(iov, iov_count, GSS_IOV_BUFFER_TYPE_HEADER);
+ assert(header != NULL);
+
+ padding = gssEapLocateIov(iov, iov_count, GSS_IOV_BUFFER_TYPE_PADDING);
+ if (padding != NULL && padding->buffer.length != 0)
+ return GSS_S_DEFECTIVE_TOKEN;
+
+ trailer = gssEapLocateIov(iov, iov_count, GSS_IOV_BUFFER_TYPE_TRAILER);
+
+ acceptor_flag = CTX_IS_INITIATOR(ctx) ? TOK_FLAG_SENDER_IS_ACCEPTOR : 0;
+ key_usage = (toktype == TOK_TYPE_WRAP
+ ? (!CTX_IS_INITIATOR(ctx)
+ ? KRB_USAGE_INITIATOR_SEAL
+ : KRB_USAGE_ACCEPTOR_SEAL)
+ : (!CTX_IS_INITIATOR(ctx)
+ ? KRB_USAGE_INITIATOR_SIGN
+ : KRB_USAGE_ACCEPTOR_SIGN));
+
+ gssEapIovMessageLength(iov, iov_count, &data_length, &assoc_data_length);
+
+ ptr = (unsigned char *)header->buffer.value;
+
+ if (header->buffer.length < 16) {
+ *minor_status = 0;
+ return GSS_S_DEFECTIVE_TOKEN;
+ }
+
+ if ((ptr[2] & TOK_FLAG_SENDER_IS_ACCEPTOR) != acceptor_flag) {
+ return GSS_S_BAD_SIG;
+ }
+
+ if (ptr[2] & TOK_FLAG_ACCEPTOR_SUBKEY) {
+ return GSS_S_BAD_SIG;
+ }
+
+ if (toktype == TOK_TYPE_WRAP) {
+ unsigned int k5_trailerlen;
+
+ if (load_16_be(ptr) != TOK_TYPE_WRAP)
+ goto defective;
+ conf_flag = ((ptr[2] & TOK_FLAG_WRAP_CONFIDENTIAL) != 0);
+ if (ptr[3] != 0xFF)
+ goto defective;
+ ec = load_16_be(ptr + 4);
+ rrc = load_16_be(ptr + 6);
+ seqnum = load_64_be(ptr + 8);
+
+ code = krb5_c_crypto_length(ctx->kerberosCtx,
+ KRB_KEYTYPE(ctx->encryptionKey),
+ conf_flag ? KRB5_CRYPTO_TYPE_TRAILER :
+ KRB5_CRYPTO_TYPE_CHECKSUM,
+ &k5_trailerlen);
+ if (code != 0) {
+ *minor_status = code;
+ return GSS_S_FAILURE;
+ }
+
+ /* Deal with RRC */
+ if (trailer == NULL) {
+ size_t desired_rrc = k5_trailerlen;
+
+ if (conf_flag) {
+ desired_rrc += 16; /* E(Header) */
+
+ if ((ctx->gssFlags & GSS_C_DCE_STYLE) == 0)
+ desired_rrc += ec;
+ }
+
+ /* According to MS, we only need to deal with a fixed RRC for DCE */
+ if (rrc != desired_rrc)
+ goto defective;
+ } else if (rrc != 0) {
+ goto defective;
+ }
+
+ if (conf_flag) {
+ unsigned char *althdr;
+
+ /* Decrypt */
+ code = gssEapDecrypt(ctx->kerberosCtx,
+ ((ctx->gssFlags & GSS_C_DCE_STYLE) != 0),
+ ec, rrc, ctx->encryptionKey,
+ key_usage, 0, iov, iov_count);
+ if (code != 0) {
+ *minor_status = code;
+ return GSS_S_BAD_SIG;
+ }
+
+ /* Validate header integrity */
+ if (trailer == NULL)
+ althdr = (unsigned char *)header->buffer.value + 16 + ec;
+ else
+ althdr = (unsigned char *)trailer->buffer.value + ec;
+
+ if (load_16_be(althdr) != TOK_TYPE_WRAP
+ || althdr[2] != ptr[2]
+ || althdr[3] != ptr[3]
+ || memcmp(althdr + 8, ptr + 8, 8) != 0) {
+ *minor_status = 0;
+ return GSS_S_BAD_SIG;
+ }
+ } else {
+ /* Verify checksum: note EC is checksum size here, not padding */
+ if (ec != k5_trailerlen)
+ goto defective;
+
+ /* Zero EC, RRC before computing checksum */
+ store_16_be(0, ptr + 4);
+ store_16_be(0, ptr + 6);
+
+ code = gssEapVerify(ctx->kerberosCtx, cksumtype, rrc,
+ ctx->encryptionKey, key_usage,
+ iov, iov_count, &valid);
+ if (code != 0 || valid == FALSE) {
+ *minor_status = code;
+ return GSS_S_BAD_SIG;
+ }
+ }
+
+ code = g_order_check(&ctx->seqState, seqnum);
+ } else if (toktype == TOK_TYPE_MIC) {
+ if (load_16_be(ptr) != TOK_TYPE_MIC)
+ goto defective;
+
+ verify_mic_1:
+ if (ptr[3] != 0xFF)
+ goto defective;
+ seqnum = load_64_be(ptr + 8);
+
+ code = gssEapVerify(ctx->kerberosCtx, cksumtype, 0,
+ ctx->encryptionKey, key_usage,
+ iov, iov_count, &valid);
+ if (code != 0 || valid == FALSE) {
+ *minor_status = code;
+ return GSS_S_BAD_SIG;
+ }
+ code = g_order_check(&ctx->seqState, seqnum);
+ } else if (toktype == TOK_TYPE_DELETE) {
+ if (load_16_be(ptr) != TOK_TYPE_DELETE)
+ goto defective;
+ goto verify_mic_1;
+ } else {
+ goto defective;
+ }
+
+ *minor_status = 0;
+
+ if (conf_state != NULL)
+ *conf_state = conf_flag;
+
+ return code;
+
+defective:
+ *minor_status = 0;
+
+ return GSS_S_DEFECTIVE_TOKEN;
+}
+
+OM_uint32
gss_unwrap_iov(OM_uint32 *minor,
gss_ctx_id_t ctx,
int *conf_state,
gss_iov_buffer_desc *iov,
int iov_count)
{
- GSSEAP_NOT_IMPLEMENTED;
+ return gssEapUnwrapOrVerifyMIC(minor, ctx,
+ iov, iov_count, conf_state,
+ qop_state, TOK_TYPE_WRAP);
+
}
gssEapAllocContext(OM_uint32 *minor,
gss_ctx_id_t *pCtx)
{
+ OM_uint32 tmpMinor;
gss_ctx_id_t ctx;
assert(*pCtx == GSS_C_NO_CONTEXT);
return GSS_S_FAILURE;
}
+ *minor = krb5_init_context(&ctx->kerberosCtx);
+ if (*minor != 0) {
+ gssEapReleaseContext(&tmpMinor, &ctx);
+ return GSS_S_FAILURE;
+ }
+
*pCtx = ctx;
return GSS_S_COMPLETE;
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
+/*
+ * Copyright 2008 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ * require a specific license from the United States Government.
+ * It is the responsibility of any person or organization contemplating
+ * export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ */
#include "gssapiP_eap.h"
OM_uint32
+gssEapWrapOrGetMIC(OM_uint32 *minor,
+ gss_ctx_id_t ctx,
+ int conf_req_flag,
+ int *conf_state,
+ gss_iov_buffer_desc *iov,
+ int iov_count,
+ enum gss_eap_token_type toktype)
+{
+ krb5_error_code code = 0;
+ gss_iov_buffer_t header;
+ gss_iov_buffer_t padding;
+ gss_iov_buffer_t trailer;
+ unsigned char acceptor_flag;
+ unsigned char *outbuf = NULL;
+ unsigned char *tbuf = NULL;
+ int key_usage;
+ size_t rrc = 0;
+ unsigned int gss_headerlen, gss_trailerlen;
+ size_t data_length, assoc_data_length;
+
+ if (!CTX_IS_ESTABLISHED(ctx)) {
+ return GSS_S_NO_CONTEXT;
+ }
+
+ acceptor_flag = CTX_IS_INITIATOR(ctx) ? 0 : TOK_FLAG_SENDER_IS_ACCEPTOR;
+ key_usage = ((toktype == TOK_TYPE_WRAP)
+ ? (CTX_IS_INITIATOR(ctx)
+ ? KRB_USAGE_INITIATOR_SEAL
+ : KRB_USAGE_ACCEPTOR_SEAL)
+ : (CTX_IS_INITIATOR(ctx)
+ ? KRB_USAGE_INITIATOR_SIGN
+ : KRB_USAGE_ACCEPTOR_SIGN));
+
+ gssEapIovMessageLength(iov, iov_count, &data_length, &assoc_data_length);
+
+ header = gssEapLocateIov(iov, iov_count, GSS_IOV_BUFFER_TYPE_HEADER);
+ if (header == NULL) {
+ *minor = EINVAL;
+ return GSS_S_FAILURE;
+ }
+
+ padding = gssEapLocateIov(iov, iov_count, GSS_IOV_BUFFER_TYPE_PADDING);
+ if (padding != NULL)
+ padding->buffer.length = 0;
+
+ trailer = gssEapLocateIov(iov, iov_count, GSS_IOV_BUFFER_TYPE_TRAILER);
+
+ if (toktype == TOK_TYPE_WRAP && conf_req_flag) {
+ unsigned int k5_headerlen, k5_trailerlen, k5_padlen;
+ size_t ec = 0;
+ size_t conf_data_length = data_length - assoc_data_length;
+
+ code = krb5_c_crypto_length(ctx->kerberosCtx, ctx->encryptionType,
+ KRB5_CRYPTO_TYPE_HEADER, &k5_headerlen);
+ if (code != 0)
+ goto cleanup;
+
+ code = krb5_c_padding_length(ctx->kerberosCtx, ctx->encryptionType,
+ conf_data_length + 16 /* E(Header) */,
+ &k5_padlen);
+ if (code != 0)
+ goto cleanup;
+
+ if (k5_padlen == 0 && (ctx->gssFlags & GSS_C_DCE_STYLE)) {
+ /* Windows rejects AEAD tokens with non-zero EC */
+ code = krb5_c_block_size(ctx->kerberosCtx, ctx->encryptionType, &ec);
+ if (code != 0)
+ goto cleanup;
+ } else
+ ec = k5_padlen;
+
+ code = krb5_c_crypto_length(ctx->kerberosCtx, ctx->encryptionType,
+ KRB5_CRYPTO_TYPE_TRAILER, &k5_trailerlen);
+ if (code != 0)
+ goto cleanup;
+
+ gss_headerlen = 16 /* Header */ + k5_headerlen;
+ gss_trailerlen = ec + 16 /* E(Header) */ + k5_trailerlen;
+
+ if (trailer == NULL) {
+ rrc = gss_trailerlen;
+ /* Workaround for Windows bug where it rotates by EC + RRC */
+ if (ctx->gssFlags & GSS_C_DCE_STYLE)
+ rrc -= ec;
+ gss_headerlen += gss_trailerlen;
+ }
+
+ if (header->type & GSS_IOV_BUFFER_FLAG_ALLOCATE) {
+ code = gssEapAllocIov(header, (size_t) gss_headerlen);
+ } else if (header->buffer.length < gss_headerlen)
+ code = KRB5_BAD_MSIZE;
+ if (code != 0)
+ goto cleanup;
+ outbuf = (unsigned char *)header->buffer.value;
+ header->buffer.length = (size_t) gss_headerlen;
+
+ if (trailer != NULL) {
+ if (trailer->type & GSS_IOV_BUFFER_FLAG_ALLOCATE)
+ code = gssEapAllocIov(trailer, (size_t) gss_trailerlen);
+ else if (trailer->buffer.length < gss_trailerlen)
+ code = KRB5_BAD_MSIZE;
+ if (code != 0)
+ goto cleanup;
+ trailer->buffer.length = (size_t) gss_trailerlen;
+ }
+
+ /* TOK_ID */
+ store_16_be((uint16_t)toktype, outbuf);
+ /* flags */
+ outbuf[2] = (acceptor_flag
+ | (conf_req_flag ? TOK_FLAG_WRAP_CONFIDENTIAL : 0)
+ | (0 ? TOK_FLAG_ACCEPTOR_SUBKEY : 0));
+ /* filler */
+ outbuf[3] = 0xFF;
+ /* EC */
+ store_16_be(ec, outbuf + 4);
+ /* RRC */
+ store_16_be(0, outbuf + 6);
+ store_64_be(ctx->sendSeq, outbuf + 8);
+
+ /* EC | copy of header to be encrypted, located in (possibly rotated) trailer */
+ if (trailer == NULL)
+ tbuf = (unsigned char *)header->buffer.value + 16; /* Header */
+ else
+ tbuf = (unsigned char *)trailer->buffer.value;
+
+ memset(tbuf, 0xFF, ec);
+ memcpy(tbuf + ec, header->buffer.value, 16);
+
+ code = gssEapEncrypt(ctx->kerberosCtx,
+ ((ctx->gssFlags & GSS_C_DCE_STYLE) != 0),
+ ec, rrc, ctx->encryptionKey,
+ key_usage, 0, iov, iov_count);
+ if (code != 0)
+ goto cleanup;
+
+ /* RRC */
+ store_16_be(rrc, outbuf + 6);
+
+ ctx->sendSeq++;
+ } else if (toktype == TOK_TYPE_WRAP && !conf_req_flag) {
+ wrap_with_checksum:
+
+ gss_headerlen = 16;
+
+ code = krb5_c_crypto_length(ctx->kerberosCtx, ctx->encryptionType,
+ KRB5_CRYPTO_TYPE_CHECKSUM,
+ &gss_trailerlen);
+ if (code != 0)
+ goto cleanup;
+
+ assert(gss_trailerlen <= 0xFFFF);
+
+ if (trailer == NULL) {
+ rrc = gss_trailerlen;
+ gss_headerlen += gss_trailerlen;
+ }
+
+ if (header->type & GSS_IOV_BUFFER_FLAG_ALLOCATE)
+ code = gssEapAllocIov(header, (size_t) gss_headerlen);
+ else if (header->buffer.length < gss_headerlen)
+ code = KRB5_BAD_MSIZE;
+ if (code != 0)
+ goto cleanup;
+ outbuf = (unsigned char *)header->buffer.value;
+ header->buffer.length = (size_t) gss_headerlen;
+
+ if (trailer != NULL) {
+ if (trailer->type & GSS_IOV_BUFFER_FLAG_ALLOCATE)
+ code = gssEapAllocIov(trailer, (size_t) gss_trailerlen);
+ else if (trailer->buffer.length < gss_trailerlen)
+ code = KRB5_BAD_MSIZE;
+ if (code != 0)
+ goto cleanup;
+ trailer->buffer.length = (size_t) gss_trailerlen;
+ }
+
+ /* TOK_ID */
+ store_16_be((uint16_t)toktype, outbuf);
+ /* flags */
+ outbuf[2] = (acceptor_flag
+ | (0 ? TOK_FLAG_ACCEPTOR_SUBKEY : 0));
+ /* filler */
+ outbuf[3] = 0xFF;
+ if (toktype == TOK_TYPE_WRAP) {
+ /* Use 0 for checksum calculation, substitute
+ * checksum length later.
+ */
+ /* EC */
+ store_16_be(0, outbuf + 4);
+ /* RRC */
+ store_16_be(0, outbuf + 6);
+ } else {
+ /* MIC and DEL store 0xFF in EC and RRC */
+ store_16_be(0xFFFF, outbuf + 4);
+ store_16_be(0xFFFF, outbuf + 6);
+ }
+ store_64_be(ctx->sendSeq, outbuf + 8);
+
+ code = gssEapSign(ctx->kerberosCtx, ctx->checksumType,
+ rrc, ctx->encryptionKey, key_usage,
+ iov, iov_count);
+ if (code != 0)
+ goto cleanup;
+
+ ctx->sendSeq++;
+
+ if (toktype == TOK_TYPE_WRAP) {
+ /* Fix up EC field */
+ store_16_be(gss_trailerlen, outbuf + 4);
+ /* Fix up RRC field */
+ store_16_be(rrc, outbuf + 6);
+ }
+ } else if (toktype == TOK_TYPE_MIC) {
+ trailer = NULL;
+ goto wrap_with_checksum;
+ } else if (toktype == TOK_TYPE_DELETE) {
+ goto wrap_with_checksum;
+ } else {
+ abort();
+ }
+
+ code = 0;
+
+cleanup:
+ if (code != 0)
+ gssEapReleaseIov(iov, iov_count);
+
+ *minor = code;
+
+ if (code == 0)
+ return GSS_S_FAILURE;
+ else
+ return GSS_S_COMPLETE;
+}
+
+OM_uint32
gss_wrap_iov(OM_uint32 *minor,
gss_ctx_id_t ctx,
int conf_req_flag,
gss_iov_buffer_desc *iov,
int iov_count)
{
- GSSEAP_NOT_IMPLEMENTED;
+ return gssEapWrapOrGetMIC(minor, ctx, conf_req_flag, conf_state,
+ iov, iov_count, TOK_TYPE_WRAP);
}