From c99b2003e283d5d94d70f1ac47e47cc203a22e08 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Love=20H=C3=B6rnquist=20=C3=85strand?= Date: Mon, 22 Jun 2009 17:56:41 +0000 Subject: [PATCH] Implement gss_wrap_iov, gss_unwrap_iov for CFX type encryption types. git-svn-id: svn://svn.h5l.se/heimdal/trunk/heimdal@25286 ec53bebd-3082-4978-b11e-865c3cabbd6b --- TODO-iov | 5 + cf/Makefile.am.common | 2 +- lib/gssapi/gssapi/gssapi.h | 61 +-- lib/gssapi/krb5/8003.c | 2 - lib/gssapi/krb5/accept_sec_context.c | 2 - lib/gssapi/krb5/acquire_cred.c | 2 - lib/gssapi/krb5/add_cred.c | 2 - lib/gssapi/krb5/{context_time.c => aeap.c} | 101 ++-- lib/gssapi/krb5/arcfour.c | 2 - lib/gssapi/krb5/canonicalize_name.c | 2 - lib/gssapi/krb5/ccache_name.c | 2 - lib/gssapi/krb5/cfx.c | 774 ++++++++++++++++++++++++++- lib/gssapi/krb5/compare_name.c | 2 - lib/gssapi/krb5/compat.c | 3 - lib/gssapi/krb5/context_time.c | 2 - lib/gssapi/krb5/copy_ccache.c | 2 - lib/gssapi/krb5/decapsulate.c | 2 - lib/gssapi/krb5/delete_sec_context.c | 2 - lib/gssapi/krb5/display_name.c | 2 - lib/gssapi/krb5/display_status.c | 2 - lib/gssapi/krb5/duplicate_name.c | 2 - lib/gssapi/krb5/encapsulate.c | 2 - lib/gssapi/krb5/export_name.c | 2 - lib/gssapi/krb5/export_sec_context.c | 2 - lib/gssapi/krb5/external.c | 2 - lib/gssapi/krb5/get_mic.c | 2 - lib/gssapi/krb5/import_name.c | 2 - lib/gssapi/krb5/import_sec_context.c | 2 - lib/gssapi/krb5/indicate_mechs.c | 2 - lib/gssapi/krb5/init.c | 2 - lib/gssapi/krb5/init_sec_context.c | 4 +- lib/gssapi/krb5/inquire_context.c | 2 - lib/gssapi/krb5/inquire_cred.c | 2 - lib/gssapi/krb5/inquire_cred_by_mech.c | 2 - lib/gssapi/krb5/inquire_cred_by_oid.c | 2 - lib/gssapi/krb5/inquire_mechs_for_name.c | 2 - lib/gssapi/krb5/inquire_names_for_mech.c | 3 - lib/gssapi/krb5/inquire_sec_context_by_oid.c | 2 - lib/gssapi/krb5/prf.c | 2 - lib/gssapi/krb5/process_context_token.c | 2 - lib/gssapi/krb5/release_buffer.c | 2 - lib/gssapi/krb5/release_cred.c | 2 - lib/gssapi/krb5/release_name.c | 2 - lib/gssapi/krb5/sequence.c | 2 - lib/gssapi/krb5/set_cred_option.c | 2 - lib/gssapi/krb5/set_sec_context_option.c | 2 - lib/gssapi/krb5/test_acquire_cred.c | 2 - lib/gssapi/krb5/test_cfx.c | 2 - lib/gssapi/krb5/test_cred.c | 2 - lib/gssapi/krb5/test_kcred.c | 2 - lib/gssapi/krb5/test_oid.c | 2 - lib/gssapi/krb5/test_sequence.c | 2 - lib/gssapi/krb5/ticket_flags.c | 2 - lib/gssapi/krb5/unwrap.c | 2 - lib/gssapi/krb5/verify_mic.c | 2 - lib/gssapi/krb5/wrap.c | 4 +- lib/gssapi/mech/gss_aeap.c | 58 +- lib/gssapi/test_context.c | 147 +++-- lib/krb5/aes-test.c | 296 +++++++++- lib/krb5/crypto.c | 277 +++++++--- lib/krb5/version-script.map | 2 + tests/gss/check-context.in | 19 +- 62 files changed, 1468 insertions(+), 382 deletions(-) create mode 100644 TODO-iov copy lib/gssapi/krb5/{context_time.c => aeap.c} (53%) diff --git a/TODO-iov b/TODO-iov new file mode 100644 index 000000000..6217960fe --- /dev/null +++ b/TODO-iov @@ -0,0 +1,5 @@ + +make iov work for arcfour +make iov work for ntlm +interop test +make TYPE_STREAM work diff --git a/cf/Makefile.am.common b/cf/Makefile.am.common index 154ee866c..ce5538e1a 100644 --- a/cf/Makefile.am.common +++ b/cf/Makefile.am.common @@ -2,7 +2,7 @@ SUFFIXES = .et .h -DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir)/include +DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir)/include -I$(top_srcdir)/include AM_CPPFLAGS = $(INCLUDES_roken) diff --git a/lib/gssapi/gssapi/gssapi.h b/lib/gssapi/gssapi/gssapi.h index 9fe2bb8b4..07c4b3632 100644 --- a/lib/gssapi/gssapi/gssapi.h +++ b/lib/gssapi/gssapi/gssapi.h @@ -768,42 +768,6 @@ gss_pseudo_random gss_buffer_t prf_out ); -/* - * AEAD support - */ - -OM_uint32 GSSAPI_LIB_FUNCTION -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 GSSAPI_LIB_FUNCTION -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 GSSAPI_LIB_FUNCTION -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 GSSAPI_LIB_FUNCTION -gss_release_iov_buffer(OM_uint32 * /* minor_status */, - gss_iov_buffer_desc * /* iov */, - int /* iov_count */); - - OM_uint32 gss_store_cred(OM_uint32 * /* minor_status */, gss_cred_id_t /* input_cred_handle */, @@ -899,6 +863,31 @@ gss_decapsulate_token(gss_buffer_t /* input_token */, +/* + * AEAD support + */ + +/* + * GSS_IOV + */ + +OM_uint32 GSSAPI_LIB_FUNCTION +gss_wrap_iov(OM_uint32 *, gss_ctx_id_t, int, gss_qop_t, int *, + gss_iov_buffer_desc *, int); + + +OM_uint32 GSSAPI_LIB_FUNCTION +gss_unwrap_iov(OM_uint32 *, gss_ctx_id_t, int *, gss_qop_t *, + gss_iov_buffer_desc *, int); + +OM_uint32 GSSAPI_LIB_FUNCTION +gss_wrap_iov_length(OM_uint32 *, gss_ctx_id_t, int, gss_qop_t, int *, + gss_iov_buffer_desc *, int); + +OM_uint32 GSSAPI_LIB_FUNCTION +gss_release_iov_buffer(OM_uint32 *, gss_iov_buffer_desc *, int); + + #ifdef __cplusplus } #endif diff --git a/lib/gssapi/krb5/8003.c b/lib/gssapi/krb5/8003.c index f5181cc31..a6f0165e7 100644 --- a/lib/gssapi/krb5/8003.c +++ b/lib/gssapi/krb5/8003.c @@ -33,8 +33,6 @@ #include "gsskrb5_locl.h" -RCSID("$Id$"); - krb5_error_code _gsskrb5_encode_om_uint32(OM_uint32 n, u_char *p) { diff --git a/lib/gssapi/krb5/accept_sec_context.c b/lib/gssapi/krb5/accept_sec_context.c index e0944852a..f1097d649 100644 --- a/lib/gssapi/krb5/accept_sec_context.c +++ b/lib/gssapi/krb5/accept_sec_context.c @@ -33,8 +33,6 @@ #include "gsskrb5_locl.h" -RCSID("$Id$"); - HEIMDAL_MUTEX gssapi_keytab_mutex = HEIMDAL_MUTEX_INITIALIZER; krb5_keytab _gsskrb5_keytab; diff --git a/lib/gssapi/krb5/acquire_cred.c b/lib/gssapi/krb5/acquire_cred.c index bfab5667b..4f6f38e67 100644 --- a/lib/gssapi/krb5/acquire_cred.c +++ b/lib/gssapi/krb5/acquire_cred.c @@ -33,8 +33,6 @@ #include "gsskrb5_locl.h" -RCSID("$Id$"); - OM_uint32 __gsskrb5_ccache_lifetime(OM_uint32 *minor_status, krb5_context context, diff --git a/lib/gssapi/krb5/add_cred.c b/lib/gssapi/krb5/add_cred.c index aa96a45e4..adc8a09fa 100644 --- a/lib/gssapi/krb5/add_cred.c +++ b/lib/gssapi/krb5/add_cred.c @@ -33,8 +33,6 @@ #include "gsskrb5_locl.h" -RCSID("$Id$"); - OM_uint32 _gsskrb5_add_cred ( OM_uint32 *minor_status, const gss_cred_id_t input_cred_handle, diff --git a/lib/gssapi/krb5/context_time.c b/lib/gssapi/krb5/aeap.c similarity index 53% copy from lib/gssapi/krb5/context_time.c copy to lib/gssapi/krb5/aeap.c index 323038993..09dd7105e 100644 --- a/lib/gssapi/krb5/context_time.c +++ b/lib/gssapi/krb5/aeap.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997 - 2003 Kungliga Tekniska Högskolan + * Copyright (c) 2008 Kungliga Tekniska Högskolan * (Royal Institute of Technology, Stockholm, Sweden). * All rights reserved. * @@ -33,63 +33,68 @@ #include "gsskrb5_locl.h" -RCSID("$Id$"); +#include -OM_uint32 -_gsskrb5_lifetime_left(OM_uint32 *minor_status, - krb5_context context, - OM_uint32 lifetime, - OM_uint32 *lifetime_rec) +OM_uint32 GSSAPI_LIB_FUNCTION +_gk_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) { - krb5_timestamp timeret; - krb5_error_code kret; + const gsskrb5_ctx ctx = (const gsskrb5_ctx) context_handle; + krb5_context context; - if (lifetime == 0) { - *lifetime_rec = GSS_C_INDEFINITE; - return GSS_S_COMPLETE; - } + GSSAPI_KRB5_INIT (&context); - kret = krb5_timeofday(context, &timeret); - if (kret) { - *minor_status = kret; - return GSS_S_FAILURE; - } + if (ctx->more_flags & IS_CFX) + return _gssapi_wrap_cfx_iov(minor_status, ctx, context, + conf_req_flag, conf_state, + iov, iov_count); - if (lifetime < timeret) - *lifetime_rec = 0; - else - *lifetime_rec = lifetime - timeret; - - return GSS_S_COMPLETE; + return GSS_S_FAILURE; } - -OM_uint32 _gsskrb5_context_time - (OM_uint32 * minor_status, - const gss_ctx_id_t context_handle, - OM_uint32 * time_rec - ) +OM_uint32 GSSAPI_LIB_FUNCTION +_gk_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) { - krb5_context context; - OM_uint32 lifetime; - OM_uint32 major_status; - const gsskrb5_ctx ctx = (const gsskrb5_ctx) context_handle; - - GSSAPI_KRB5_INIT (&context); + const gsskrb5_ctx ctx = (const gsskrb5_ctx) context_handle; + krb5_context context; - HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex); - lifetime = ctx->lifetime; - HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex); + GSSAPI_KRB5_INIT (&context); - major_status = _gsskrb5_lifetime_left(minor_status, context, - lifetime, time_rec); - if (major_status != GSS_S_COMPLETE) - return major_status; + if (ctx->more_flags & IS_CFX) + return _gssapi_unwrap_cfx_iov(minor_status, ctx, context, + conf_state, qop_state, iov, iov_count); - *minor_status = 0; + return GSS_S_FAILURE; +} - if (*time_rec == 0) - return GSS_S_CONTEXT_EXPIRED; - - return GSS_S_COMPLETE; +OM_uint32 GSSAPI_LIB_FUNCTION +_gk_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) +{ + const gsskrb5_ctx ctx = (const gsskrb5_ctx) context_handle; + krb5_context context; + + GSSAPI_KRB5_INIT (&context); + + if (ctx->more_flags & IS_CFX) + return _gssapi_wrap_iov_length_cfx(minor_status, ctx, context, + conf_req_flag, qop_req, conf_state, + iov, iov_count); + + return GSS_S_FAILURE; } diff --git a/lib/gssapi/krb5/arcfour.c b/lib/gssapi/krb5/arcfour.c index b48cfebcf..e7331b011 100644 --- a/lib/gssapi/krb5/arcfour.c +++ b/lib/gssapi/krb5/arcfour.c @@ -33,8 +33,6 @@ #include "gsskrb5_locl.h" -RCSID("$Id$"); - /* * Implements draft-brezak-win2k-krb-rc4-hmac-04.txt * diff --git a/lib/gssapi/krb5/canonicalize_name.c b/lib/gssapi/krb5/canonicalize_name.c index 3a206b1be..7e0c3fe72 100644 --- a/lib/gssapi/krb5/canonicalize_name.c +++ b/lib/gssapi/krb5/canonicalize_name.c @@ -33,8 +33,6 @@ #include "gsskrb5_locl.h" -RCSID("$Id$"); - OM_uint32 _gsskrb5_canonicalize_name ( OM_uint32 * minor_status, const gss_name_t input_name, diff --git a/lib/gssapi/krb5/ccache_name.c b/lib/gssapi/krb5/ccache_name.c index b7144c11e..1577fb20d 100644 --- a/lib/gssapi/krb5/ccache_name.c +++ b/lib/gssapi/krb5/ccache_name.c @@ -33,8 +33,6 @@ #include "gsskrb5_locl.h" -RCSID("$Id$"); - char *last_out_name; OM_uint32 diff --git a/lib/gssapi/krb5/cfx.c b/lib/gssapi/krb5/cfx.c index c52d49b6c..b6f421c27 100644 --- a/lib/gssapi/krb5/cfx.c +++ b/lib/gssapi/krb5/cfx.c @@ -32,10 +32,8 @@ #include "gsskrb5_locl.h" -RCSID("$Id$"); - /* - * Implementation of draft-ietf-krb-wg-gssapi-cfx-06.txt + * Implementation of RFC 4121 */ #define CFXSentByAcceptor (1 << 0) @@ -96,13 +94,14 @@ _gsskrb5cfx_wrap_length_cfx(krb5_context context, return 0; } -OM_uint32 _gssapi_wrap_size_cfx(OM_uint32 *minor_status, - const gsskrb5_ctx ctx, - krb5_context context, - int conf_req_flag, - gss_qop_t qop_req, - OM_uint32 req_output_size, - OM_uint32 *max_input_size) +OM_uint32 +_gssapi_wrap_size_cfx(OM_uint32 *minor_status, + const gsskrb5_ctx ctx, + krb5_context context, + int conf_req_flag, + gss_qop_t qop_req, + OM_uint32 req_output_size, + OM_uint32 *max_input_size) { krb5_error_code ret; @@ -198,11 +197,764 @@ rrc_rotate(void *data, size_t len, uint16_t rrc, krb5_boolean unrotate) return 0; } + +static gss_iov_buffer_desc * +find_buffer(gss_iov_buffer_desc *iov, int iov_count, OM_uint32 type) +{ + int i; + + for (i = 0; i < iov_count; i++) + if (type == GSS_IOV_BUFFER_TYPE(iov[i].type)) + return &iov[i]; + return NULL; +} + +static OM_uint32 +allocate_buffer(OM_uint32 *minor_status, gss_iov_buffer_desc *buffer, size_t size) +{ + if (buffer->type & GSS_IOV_BUFFER_TYPE_FLAG_ALLOCATED) { + if (buffer->buffer.length == size) + return GSS_S_COMPLETE; + free(buffer->buffer.value); + } + + buffer->buffer.value = malloc(size); + buffer->buffer.length = size; + if (buffer->buffer.value == NULL) { + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + buffer->type |= GSS_IOV_BUFFER_TYPE_FLAG_ALLOCATED; + + return GSS_S_COMPLETE; +} + + + +OM_uint32 +_gssapi_wrap_cfx_iov(OM_uint32 *minor_status, + gsskrb5_ctx ctx, + krb5_context context, + int conf_req_flag, + int *conf_state, + gss_iov_buffer_desc *iov, + int iov_count) +{ + OM_uint32 major_status, junk; + gss_iov_buffer_desc *header, *trailer, *padding; + size_t gsshsize, k5hsize; + size_t gsstsize, k5tsize; + size_t i, padlength, rrc = 0, ec = 0; + gss_cfx_wrap_token token; + krb5_error_code ret; + int32_t seq_number; + unsigned usage; + krb5_crypto_iov *data = NULL; + int paddingoffset = 0; + + header = find_buffer(iov, iov_count, GSS_IOV_BUFFER_TYPE_HEADER); + if (header == NULL) { + *minor_status = EINVAL; + return GSS_S_FAILURE; + } + + krb5_crypto_length(context, ctx->crypto, KRB5_CRYPTO_TYPE_PADDING, &padlength); + + padding = find_buffer(iov, iov_count, GSS_IOV_BUFFER_TYPE_PADDING); + if (padlength != 0 && padding == NULL) { + *minor_status = EINVAL; + return GSS_S_FAILURE; + } + + trailer = find_buffer(iov, iov_count, GSS_IOV_BUFFER_TYPE_TRAILER); + + if (conf_req_flag) { + ec = padlength; + + krb5_crypto_length(context, ctx->crypto, KRB5_CRYPTO_TYPE_TRAILER, &k5tsize); + krb5_crypto_length(context, ctx->crypto, KRB5_CRYPTO_TYPE_HEADER, &k5hsize); + + gsshsize = k5hsize + sizeof(*token); + gsstsize = k5tsize + sizeof(*token); /* encrypted token stored in trailer */ + + } else { + + krb5_crypto_length(context, ctx->crypto, KRB5_CRYPTO_TYPE_CHECKSUM, &k5tsize); + + gsshsize = sizeof(*token); + gsstsize = k5tsize; + } + + /* + * + */ + + if (trailer == NULL) { + /* conf_req_flag=0 doesn't support DCE_STYLE */ + if (conf_req_flag == 0) { + *minor_status = EINVAL; + major_status = GSS_S_FAILURE; + goto failure; + } + rrc = gsstsize; + if (IS_DCE_STYLE(ctx)) + rrc -= ec; + gsshsize += gsstsize; + gsstsize = 0; + } else if (GSS_IOV_BUFFER_FLAGS(trailer->type) & GSS_IOV_BUFFER_TYPE_FLAG_ALLOCATE) { + major_status = allocate_buffer(minor_status, trailer, gsstsize); + if (major_status) + goto failure; + } else if (trailer->buffer.length < gsstsize) { + *minor_status = KRB5_BAD_MSIZE; + major_status = GSS_S_FAILURE; + goto failure; + } else + trailer->buffer.length = gsstsize; + + /* + * + */ + + if (GSS_IOV_BUFFER_FLAGS(header->type) & GSS_IOV_BUFFER_TYPE_FLAG_ALLOCATE) { + major_status = allocate_buffer(minor_status, header, gsshsize); + if (major_status != GSS_S_COMPLETE) + goto failure; + } else if (header->buffer.length < gsshsize) { + *minor_status = KRB5_BAD_MSIZE; + major_status = GSS_S_FAILURE; + goto failure; + } else + header->buffer.length = gsshsize; + + token = (gss_cfx_wrap_token)header->buffer.value; + + token->TOK_ID[0] = 0x05; + token->TOK_ID[1] = 0x04; + token->Flags = 0; + token->Filler = 0xFF; + + if (ctx->more_flags & ACCEPTOR_SUBKEY) + token->Flags |= CFXAcceptorSubkey; + + if (ctx->more_flags & LOCAL) + usage = KRB5_KU_USAGE_INITIATOR_SEAL; + else + usage = KRB5_KU_USAGE_ACCEPTOR_SEAL; + + if (conf_req_flag) { + /* + * In Wrap tokens with confidentiality, the EC field is + * used to encode the size (in bytes) of the random filler. + */ + token->Flags |= CFXSealed; + token->EC[0] = (padlength >> 8) & 0xFF; + token->EC[1] = (padlength >> 0) & 0xFF; + + } else { + /* + * In Wrap tokens without confidentiality, the EC field is + * used to encode the size (in bytes) of the trailing + * checksum. + * + * This is not used in the checksum calcuation itself, + * because the checksum length could potentially vary + * depending on the data length. + */ + token->EC[0] = 0; + token->EC[1] = 0; + } + + /* + * In Wrap tokens that provide for confidentiality, the RRC + * field in the header contains the hex value 00 00 before + * encryption. + * + * In Wrap tokens that do not provide for confidentiality, + * both the EC and RRC fields in the appended checksum + * contain the hex value 00 00 for the purpose of calculating + * the checksum. + */ + token->RRC[0] = 0; + token->RRC[1] = 0; + + HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex); + krb5_auth_con_getlocalseqnumber(context, + ctx->auth_context, + &seq_number); + _gsskrb5_encode_be_om_uint32(0, &token->SND_SEQ[0]); + _gsskrb5_encode_be_om_uint32(seq_number, &token->SND_SEQ[4]); + krb5_auth_con_setlocalseqnumber(context, + ctx->auth_context, + ++seq_number); + HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex); + + data = calloc(iov_count + 3, sizeof(data[0])); + if (data == NULL) { + *minor_status = ENOMEM; + major_status = GSS_S_FAILURE; + goto failure; + } + + if (conf_req_flag) { + /* + plain packet: + + {"header" | encrypt(plaintext-data | padding | E"header")} + + Expanded, this is with with RRC = 0: + + {"header" | krb5-header | plaintext-data | padding | E"header" | krb5-trailer } + + In DCE-RPC mode == no trailer: RRC = gss "trailer" == length(padding | E"header" | krb5-trailer) + + {"header" | padding | E"header" | krb5-trailer | krb5-header | plaintext-data } + */ + + i = 0; + data[i].flags = KRB5_CRYPTO_TYPE_HEADER; + data[i].data.data = ((uint8_t *)header->buffer.value) + header->buffer.length - k5hsize; + data[i].data.length = k5hsize; + + for (i = 1; i < iov_count + 1; i++) { + switch (GSS_IOV_BUFFER_TYPE(iov[i - 1].type)) { + case GSS_IOV_BUFFER_TYPE_DATA: + data[i].flags = KRB5_CRYPTO_TYPE_DATA; + break; + case GSS_IOV_BUFFER_TYPE_PADDING: + data[i].flags = KRB5_CRYPTO_TYPE_PADDING; + paddingoffset = i; + break; + case GSS_IOV_BUFFER_TYPE_SIGN_ONLY: + data[i].flags = KRB5_CRYPTO_TYPE_SIGN_ONLY; + break; + default: + data[i].flags = KRB5_CRYPTO_TYPE_EMPTY; + break; + } + data[i].data.length = iov[i - 1].buffer.length; + data[i].data.data = iov[i - 1].buffer.value; + } + + /* + * Any necessary padding is added here to ensure that the + * encrypted token header is always at the end of the + * ciphertext. + */ + + /* XXX KRB5_CRYPTO_TYPE_PADDING */ + + /* encrypted CFX header in trailer (or after the header if in + DCE mode). Copy in header into E"header" + */ + data[i].flags = KRB5_CRYPTO_TYPE_DATA; + if (trailer) + data[i].data.data = trailer->buffer.value; + else + data[i].data.data = ((uint8_t *)header->buffer.value) + header->buffer.length - k5hsize - k5tsize - sizeof(*token); + + data[i].data.length = sizeof(*token); + memcpy(data[i].data.data, token, sizeof(*token)); + i++; + + /* Kerberos trailer comes after the gss trailer */ + data[i].flags = KRB5_CRYPTO_TYPE_TRAILER; + data[i].data.data = ((uint8_t *)data[i-1].data.data) + sizeof(*token); + data[i].data.length = k5tsize; + i++; + + ret = krb5_encrypt_iov_ivec(context, ctx->crypto, usage, data, i, NULL); + if (ret != 0) { + *minor_status = ret; + major_status = GSS_S_FAILURE; + goto failure; + } + + if (rrc) { + token->RRC[0] = (rrc >> 8) & 0xFF; + token->RRC[1] = (rrc >> 0) & 0xFF; + } + + if (paddingoffset) + padding->buffer.length = data[paddingoffset].data.length; + + } else { + /* + plain packet: + + {data | "header" | gss-trailer (krb5 checksum) + + don't do RRC != 0 + + */ + + for (i = 0; i < iov_count; i++) { + switch (GSS_IOV_BUFFER_TYPE(iov[i].type)) { + case GSS_IOV_BUFFER_TYPE_DATA: + case GSS_IOV_BUFFER_TYPE_PADDING: + data[i].flags = KRB5_CRYPTO_TYPE_DATA; + break; + case GSS_IOV_BUFFER_TYPE_SIGN_ONLY: + data[i].flags = KRB5_CRYPTO_TYPE_SIGN_ONLY; + break; + default: + data[i].flags = KRB5_CRYPTO_TYPE_EMPTY; + break; + } + data[i].data.length = iov[i].buffer.length; + data[i].data.data = iov[i].buffer.value; + } + + data[i].flags = KRB5_CRYPTO_TYPE_DATA; + data[i].data.data = header->buffer.value; + data[i].data.length = header->buffer.length; + i++; + + data[i].flags = KRB5_CRYPTO_TYPE_CHECKSUM; + data[i].data.data = trailer->buffer.value; + data[i].data.length = trailer->buffer.length; + i++; + + ret = krb5_create_checksum_iov(context, ctx->crypto, usage, data, i, NULL); + if (ret) { + *minor_status = ret; + major_status = GSS_S_FAILURE; + goto failure; + } + + token->EC[0] = (trailer->buffer.length >> 8) & 0xFF; + token->EC[1] = (trailer->buffer.length >> 0) & 0xFF; + } + + if (conf_state != NULL) + *conf_state = conf_req_flag; + + free(data); + + *minor_status = 0; + return GSS_S_COMPLETE; + + failure: + if (data) + free(data); + + gss_release_iov_buffer(&junk, iov, iov_count); + + return major_status; +} + +/* This is slowpath */ +static OM_uint32 +unrotate_iov(OM_uint32 *minor_status, size_t rrc, gss_iov_buffer_desc *iov, int iov_count) +{ + uint8_t *p, *q; + size_t len = 0, skip; + int i; + + for (i = 0; i < iov_count; i++) + if (GSS_IOV_BUFFER_TYPE(iov[i].type) == GSS_IOV_BUFFER_TYPE_DATA || + GSS_IOV_BUFFER_TYPE(iov[i].type) == GSS_IOV_BUFFER_TYPE_PADDING || + GSS_IOV_BUFFER_TYPE(iov[i].type) == GSS_IOV_BUFFER_TYPE_TRAILER) + len += iov[i].buffer.length; + + p = malloc(len); + if (p == NULL) { + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + q = p; + + /* copy up */ + + for (i = 0; i < iov_count; i++) { + if (GSS_IOV_BUFFER_TYPE(iov[i].type) == GSS_IOV_BUFFER_TYPE_DATA || + GSS_IOV_BUFFER_TYPE(iov[i].type) == GSS_IOV_BUFFER_TYPE_PADDING || + GSS_IOV_BUFFER_TYPE(iov[i].type) == GSS_IOV_BUFFER_TYPE_TRAILER) + { + memcpy(q, iov[i].buffer.value, iov[i].buffer.length); + q += iov[i].buffer.length; + } + } + assert((q - p) == len); + + /* unrotate first part */ + q = p + rrc; + skip = rrc; + for (i = 0; i < iov_count; i++) { + if (GSS_IOV_BUFFER_TYPE(iov[i].type) == GSS_IOV_BUFFER_TYPE_DATA || + GSS_IOV_BUFFER_TYPE(iov[i].type) == GSS_IOV_BUFFER_TYPE_PADDING || + GSS_IOV_BUFFER_TYPE(iov[i].type) == GSS_IOV_BUFFER_TYPE_TRAILER) + { + if (iov[i].buffer.length <= skip) { + skip -= iov[i].buffer.length; + } else { + memcpy(((uint8_t *)iov[i].buffer.value) + skip, q, iov[i].buffer.length - skip); + q += iov[i].buffer.length - skip; + skip = 0; + } + } + } + /* copy trailer */ + q = p; + skip = rrc; + for (i = 0; i < iov_count; i++) { + if (GSS_IOV_BUFFER_TYPE(iov[i].type) == GSS_IOV_BUFFER_TYPE_DATA || + GSS_IOV_BUFFER_TYPE(iov[i].type) == GSS_IOV_BUFFER_TYPE_PADDING || + GSS_IOV_BUFFER_TYPE(iov[i].type) == GSS_IOV_BUFFER_TYPE_TRAILER) + { + memcpy(q, iov[i].buffer.value, MIN(iov[i].buffer.length, skip)); + if (iov[i].buffer.length > skip) + break; + skip -= iov[i].buffer.length; + q += iov[i].buffer.length; + } + } + return GSS_S_COMPLETE; +} + + +OM_uint32 +_gssapi_unwrap_cfx_iov(OM_uint32 *minor_status, + gsskrb5_ctx ctx, + krb5_context context, + int *conf_state, + gss_qop_t *qop_state, + gss_iov_buffer_desc *iov, + int iov_count) +{ + OM_uint32 seq_number_lo, seq_number_hi, major_status, junk; + gss_iov_buffer_desc *header, *trailer; + gss_cfx_wrap_token token, ttoken; + u_char token_flags; + krb5_error_code ret; + unsigned usage; + uint16_t ec, rrc; + krb5_crypto_iov *data = NULL; + int i, j; + + *minor_status = 0; + + header = find_buffer(iov, iov_count, GSS_IOV_BUFFER_TYPE_HEADER); + if (header == NULL) { + *minor_status = EINVAL; + return GSS_S_FAILURE; + } + + if (header->buffer.length < sizeof(*token)) /* we check exact below */ + return GSS_S_DEFECTIVE_TOKEN; + + trailer = find_buffer(iov, iov_count, GSS_IOV_BUFFER_TYPE_TRAILER); + + token = (gss_cfx_wrap_token)header->buffer.value; + + if (token->TOK_ID[0] != 0x05 || token->TOK_ID[1] != 0x04) + return GSS_S_DEFECTIVE_TOKEN; + + /* Ignore unknown flags */ + token_flags = token->Flags & + (CFXSentByAcceptor | CFXSealed | CFXAcceptorSubkey); + + if (token_flags & CFXSentByAcceptor) { + if ((ctx->more_flags & LOCAL) == 0) + return GSS_S_DEFECTIVE_TOKEN; + } + + if (ctx->more_flags & ACCEPTOR_SUBKEY) { + if ((token_flags & CFXAcceptorSubkey) == 0) + return GSS_S_DEFECTIVE_TOKEN; + } else { + if (token_flags & CFXAcceptorSubkey) + return GSS_S_DEFECTIVE_TOKEN; + } + + if (token->Filler != 0xFF) + return GSS_S_DEFECTIVE_TOKEN; + + if (conf_state != NULL) + *conf_state = (token_flags & CFXSealed) ? 1 : 0; + + ec = (token->EC[0] << 8) | token->EC[1]; + rrc = (token->RRC[0] << 8) | token->RRC[1]; + + /* + * Check sequence number + */ + _gsskrb5_decode_be_om_uint32(&token->SND_SEQ[0], &seq_number_hi); + _gsskrb5_decode_be_om_uint32(&token->SND_SEQ[4], &seq_number_lo); + if (seq_number_hi) { + /* no support for 64-bit sequence numbers */ + *minor_status = ERANGE; + return GSS_S_UNSEQ_TOKEN; + } + + HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex); + ret = _gssapi_msg_order_check(ctx->order, seq_number_lo); + if (ret != 0) { + *minor_status = 0; + HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex); + return ret; + } + HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex); + + /* + * Decrypt and/or verify checksum + */ + + if (ctx->more_flags & LOCAL) { + usage = KRB5_KU_USAGE_ACCEPTOR_SEAL; + } else { + usage = KRB5_KU_USAGE_INITIATOR_SEAL; + } + + data = calloc(iov_count + 3, sizeof(data[0])); + if (data == NULL) { + *minor_status = ENOMEM; + major_status = GSS_S_FAILURE; + goto failure; + } + + if (token_flags & CFXSealed) { + size_t k5tsize, k5hsize; + + krb5_crypto_length(context, ctx->crypto, KRB5_CRYPTO_TYPE_HEADER, &k5hsize); + krb5_crypto_length(context, ctx->crypto, KRB5_CRYPTO_TYPE_TRAILER, &k5tsize); + + /* Rotate by RRC; bogus to do this in-place XXX */ + /* Check RRC */ + + if (trailer == NULL) { + size_t gsstsize = k5tsize + sizeof(*token); + size_t gsshsize = k5hsize + sizeof(*token); + + if (IS_DCE_STYLE(ctx)) + gsstsize += ec; + gsshsize += gsstsize; + + if (rrc != gsstsize) { + major_status = GSS_S_DEFECTIVE_TOKEN; + goto failure; + } + if (header->buffer.length != gsshsize) { + major_status = GSS_S_DEFECTIVE_TOKEN; + goto failure; + } + } else if (trailer->buffer.length != sizeof(*token) + k5tsize) { + major_status = GSS_S_DEFECTIVE_TOKEN; + goto failure; + } else if (header->buffer.length != sizeof(*token) + k5hsize) { + major_status = GSS_S_DEFECTIVE_TOKEN; + goto failure; + } else if (rrc != 0) { + /* go though slowpath */ + major_status = unrotate_iov(minor_status, rrc, iov, iov_count); + if (major_status) + goto failure; + } + + i = 0; + data[i].flags = KRB5_CRYPTO_TYPE_HEADER; + data[i].data.data = ((uint8_t *)header->buffer.value) + header->buffer.length - k5hsize; + data[i].data.length = k5hsize; + i++; + + for (j = 0; j < iov_count; i++, j++) { + switch (GSS_IOV_BUFFER_TYPE(iov[j].type)) { + case GSS_IOV_BUFFER_TYPE_DATA: + case GSS_IOV_BUFFER_TYPE_PADDING: + data[i].flags = KRB5_CRYPTO_TYPE_DATA; + break; + case GSS_IOV_BUFFER_TYPE_SIGN_ONLY: + data[i].flags = KRB5_CRYPTO_TYPE_SIGN_ONLY; + break; + default: + data[i].flags = KRB5_CRYPTO_TYPE_EMPTY; + break; + } + data[i].data.length = iov[j].buffer.length; + data[i].data.data = iov[j].buffer.value; + } + + /* encrypted CFX header in trailer (or after the header if in + DCE mode). Copy in header into E"header" + */ + data[i].flags = KRB5_CRYPTO_TYPE_DATA; + if (trailer) + data[i].data.data = trailer->buffer.value; + else + data[i].data.data = ((uint8_t *)header->buffer.value) + header->buffer.length - k5hsize - k5tsize - sizeof(*token); + data[i].data.length = sizeof(*token); + ttoken = (gss_cfx_wrap_token)data[i].data.data; + i++; + + /* Kerberos trailer comes after the gss trailer */ + data[i].flags = KRB5_CRYPTO_TYPE_TRAILER; + data[i].data.data = ((uint8_t *)data[i-1].data.data) + sizeof(*token); + data[i].data.length = k5tsize; + i++; + + ret = krb5_decrypt_iov_ivec(context, ctx->crypto, usage, data, i, NULL); + if (ret != 0) { + *minor_status = ret; + major_status = GSS_S_FAILURE; + goto failure; + } + + ttoken->RRC[0] = token->RRC[0]; + ttoken->RRC[1] = token->RRC[1]; + + /* Check the integrity of the header */ + if (memcmp(ttoken, token, sizeof(*token)) != 0) { + major_status = GSS_S_BAD_MIC; + goto failure; + } + } else { + /* Check RRC */ + if (rrc != 0) { + *minor_status = EINVAL; + major_status = GSS_S_FAILURE; + goto failure; + } + + if (trailer == NULL) { + *minor_status = EINVAL; + major_status = GSS_S_FAILURE; + goto failure; + } + + if (trailer->buffer.length != ec) { + *minor_status = EINVAL; + major_status = GSS_S_FAILURE; + goto failure; + } + + for (i = 0; i < iov_count; i++) { + switch (GSS_IOV_BUFFER_TYPE(iov[i].type)) { + case GSS_IOV_BUFFER_TYPE_DATA: + case GSS_IOV_BUFFER_TYPE_PADDING: + data[i].flags = KRB5_CRYPTO_TYPE_DATA; + break; + case GSS_IOV_BUFFER_TYPE_SIGN_ONLY: + data[i].flags = KRB5_CRYPTO_TYPE_SIGN_ONLY; + break; + default: + data[i].flags = KRB5_CRYPTO_TYPE_EMPTY; + break; + } + data[i].data.length = iov[i].buffer.length; + data[i].data.data = iov[i].buffer.value; + } + + data[i].flags = KRB5_CRYPTO_TYPE_DATA; + data[i].data.data = header->buffer.value; + data[i].data.length = header->buffer.length; + i++; + + data[i].flags = KRB5_CRYPTO_TYPE_CHECKSUM; + data[i].data.data = trailer->buffer.value; + data[i].data.length = trailer->buffer.length; + i++; + + token = (gss_cfx_wrap_token)header->buffer.value; + token->EC[0] = 0; + token->EC[1] = 0; + token->RRC[0] = 0; + token->RRC[1] = 0; + + ret = krb5_verify_checksum_iov(context, ctx->crypto, usage, data, i, NULL); + if (ret) { + *minor_status = ret; + major_status = GSS_S_FAILURE; + goto failure; + } + } + + if (qop_state != NULL) { + *qop_state = GSS_C_QOP_DEFAULT; + } + + free(data); + + *minor_status = 0; + return GSS_S_COMPLETE; + + failure: + if (data) + free(data); + + gss_release_iov_buffer(&junk, iov, iov_count); + + return major_status; +} + +OM_uint32 +_gssapi_wrap_iov_length_cfx(OM_uint32 *minor_status, + gsskrb5_ctx ctx, + krb5_context context, + int conf_req_flag, + gss_qop_t qop_req, + int *conf_state, + gss_iov_buffer_desc *iov, + int iov_count) +{ + size_t size; + int i; + size_t *padding = NULL; + + GSSAPI_KRB5_INIT (&context); + *minor_status = 0; + + for (size = 0, i = 0; i < iov_count; i++) { + switch(GSS_IOV_BUFFER_TYPE(iov[i].type)) { + case GSS_IOV_BUFFER_TYPE_EMPTY: + break; + case GSS_IOV_BUFFER_TYPE_DATA: + size += iov[i].buffer.length; + break; + case GSS_IOV_BUFFER_TYPE_HEADER: + *minor_status = krb5_crypto_length(context, ctx->crypto, KRB5_CRYPTO_TYPE_HEADER, &iov[i].buffer.length); + if (*minor_status) + return GSS_S_FAILURE; + break; + case GSS_IOV_BUFFER_TYPE_TRAILER: + *minor_status = krb5_crypto_length(context, ctx->crypto, KRB5_CRYPTO_TYPE_TRAILER, &iov[i].buffer.length); + if (*minor_status) + return GSS_S_FAILURE; + break; + case GSS_IOV_BUFFER_TYPE_PADDING: + if (padding != NULL) { + *minor_status = 0; + return GSS_S_FAILURE; + } + padding = &iov[i].buffer.length; + break; + case GSS_IOV_BUFFER_TYPE_SIGN_ONLY: + break; + default: + *minor_status = EINVAL; + return GSS_S_FAILURE; + } + } + if (padding) { + size_t pad; + krb5_crypto_length(context, ctx->crypto, KRB5_CRYPTO_TYPE_PADDING, &pad); + if (pad > 1) { + *padding = pad - (size % pad); + if (*padding == pad) + *padding = 0; + } else + *padding = 0; + } + + return GSS_S_COMPLETE; +} + + + + OM_uint32 _gssapi_wrap_cfx(OM_uint32 *minor_status, const gsskrb5_ctx ctx, krb5_context context, int conf_req_flag, - gss_qop_t qop_req, const gss_buffer_t input_message_buffer, int *conf_state, gss_buffer_t output_message_buffer) diff --git a/lib/gssapi/krb5/compare_name.c b/lib/gssapi/krb5/compare_name.c index fbb0f0218..f45e4df3e 100644 --- a/lib/gssapi/krb5/compare_name.c +++ b/lib/gssapi/krb5/compare_name.c @@ -33,8 +33,6 @@ #include "gsskrb5_locl.h" -RCSID("$Id$"); - OM_uint32 _gsskrb5_compare_name (OM_uint32 * minor_status, const gss_name_t name1, diff --git a/lib/gssapi/krb5/compat.c b/lib/gssapi/krb5/compat.c index 012602c07..221d219c6 100644 --- a/lib/gssapi/krb5/compat.c +++ b/lib/gssapi/krb5/compat.c @@ -33,9 +33,6 @@ #include "gsskrb5_locl.h" -RCSID("$Id$"); - - static krb5_error_code check_compat(OM_uint32 *minor_status, krb5_context context, krb5_const_principal name, diff --git a/lib/gssapi/krb5/context_time.c b/lib/gssapi/krb5/context_time.c index 323038993..987ceea4a 100644 --- a/lib/gssapi/krb5/context_time.c +++ b/lib/gssapi/krb5/context_time.c @@ -33,8 +33,6 @@ #include "gsskrb5_locl.h" -RCSID("$Id$"); - OM_uint32 _gsskrb5_lifetime_left(OM_uint32 *minor_status, krb5_context context, diff --git a/lib/gssapi/krb5/copy_ccache.c b/lib/gssapi/krb5/copy_ccache.c index 40a8fab1b..a4b28f91e 100644 --- a/lib/gssapi/krb5/copy_ccache.c +++ b/lib/gssapi/krb5/copy_ccache.c @@ -33,8 +33,6 @@ #include "gsskrb5_locl.h" -RCSID("$Id$"); - #if 0 OM_uint32 gss_krb5_copy_ccache(OM_uint32 *minor_status, diff --git a/lib/gssapi/krb5/decapsulate.c b/lib/gssapi/krb5/decapsulate.c index a2a5de9fe..7ccf0b0f7 100644 --- a/lib/gssapi/krb5/decapsulate.c +++ b/lib/gssapi/krb5/decapsulate.c @@ -33,8 +33,6 @@ #include "gsskrb5_locl.h" -RCSID("$Id$"); - /* * return the length of the mechanism in token or -1 * (which implies that the token was bad - GSS_S_DEFECTIVE_TOKEN diff --git a/lib/gssapi/krb5/delete_sec_context.c b/lib/gssapi/krb5/delete_sec_context.c index ea0831815..b3d436ea0 100644 --- a/lib/gssapi/krb5/delete_sec_context.c +++ b/lib/gssapi/krb5/delete_sec_context.c @@ -33,8 +33,6 @@ #include "gsskrb5_locl.h" -RCSID("$Id$"); - OM_uint32 _gsskrb5_delete_sec_context(OM_uint32 * minor_status, gss_ctx_id_t * context_handle, diff --git a/lib/gssapi/krb5/display_name.c b/lib/gssapi/krb5/display_name.c index 0b3773151..6487d8488 100644 --- a/lib/gssapi/krb5/display_name.c +++ b/lib/gssapi/krb5/display_name.c @@ -33,8 +33,6 @@ #include "gsskrb5_locl.h" -RCSID("$Id$"); - OM_uint32 _gsskrb5_display_name (OM_uint32 * minor_status, const gss_name_t input_name, diff --git a/lib/gssapi/krb5/display_status.c b/lib/gssapi/krb5/display_status.c index 4136c25e5..f9d84fc76 100644 --- a/lib/gssapi/krb5/display_status.c +++ b/lib/gssapi/krb5/display_status.c @@ -33,8 +33,6 @@ #include "gsskrb5_locl.h" -RCSID("$Id$"); - static const char * calling_error(OM_uint32 v) { diff --git a/lib/gssapi/krb5/duplicate_name.c b/lib/gssapi/krb5/duplicate_name.c index 2b5e5c0ef..b0188acd5 100644 --- a/lib/gssapi/krb5/duplicate_name.c +++ b/lib/gssapi/krb5/duplicate_name.c @@ -33,8 +33,6 @@ #include "gsskrb5_locl.h" -RCSID("$Id$"); - OM_uint32 _gsskrb5_duplicate_name ( OM_uint32 * minor_status, const gss_name_t src_name, diff --git a/lib/gssapi/krb5/encapsulate.c b/lib/gssapi/krb5/encapsulate.c index 838a34d7d..79cd9232e 100644 --- a/lib/gssapi/krb5/encapsulate.c +++ b/lib/gssapi/krb5/encapsulate.c @@ -33,8 +33,6 @@ #include "gsskrb5_locl.h" -RCSID("$Id$"); - void _gssapi_encap_length (size_t data_len, size_t *len, diff --git a/lib/gssapi/krb5/export_name.c b/lib/gssapi/krb5/export_name.c index bad73611d..705bb70d9 100644 --- a/lib/gssapi/krb5/export_name.c +++ b/lib/gssapi/krb5/export_name.c @@ -33,8 +33,6 @@ #include "gsskrb5_locl.h" -RCSID("$Id$"); - OM_uint32 _gsskrb5_export_name (OM_uint32 * minor_status, const gss_name_t input_name, diff --git a/lib/gssapi/krb5/export_sec_context.c b/lib/gssapi/krb5/export_sec_context.c index 305d5c334..3d3870a6b 100644 --- a/lib/gssapi/krb5/export_sec_context.c +++ b/lib/gssapi/krb5/export_sec_context.c @@ -33,8 +33,6 @@ #include "gsskrb5_locl.h" -RCSID("$Id$"); - OM_uint32 _gsskrb5_export_sec_context ( OM_uint32 * minor_status, diff --git a/lib/gssapi/krb5/external.c b/lib/gssapi/krb5/external.c index 1c28f7c14..df23776a6 100644 --- a/lib/gssapi/krb5/external.c +++ b/lib/gssapi/krb5/external.c @@ -34,8 +34,6 @@ #include "gsskrb5_locl.h" #include -RCSID("$Id$"); - /* * The implementation must reserve static storage for a * gss_OID_desc object containing the value diff --git a/lib/gssapi/krb5/get_mic.c b/lib/gssapi/krb5/get_mic.c index 66aaba44d..ad3009c73 100644 --- a/lib/gssapi/krb5/get_mic.c +++ b/lib/gssapi/krb5/get_mic.c @@ -33,8 +33,6 @@ #include "gsskrb5_locl.h" -RCSID("$Id$"); - static OM_uint32 mic_des (OM_uint32 * minor_status, diff --git a/lib/gssapi/krb5/import_name.c b/lib/gssapi/krb5/import_name.c index 8f5387fe2..d488ce754 100644 --- a/lib/gssapi/krb5/import_name.c +++ b/lib/gssapi/krb5/import_name.c @@ -33,8 +33,6 @@ #include "gsskrb5_locl.h" -RCSID("$Id$"); - static OM_uint32 parse_krb5_name (OM_uint32 *minor_status, krb5_context context, diff --git a/lib/gssapi/krb5/import_sec_context.c b/lib/gssapi/krb5/import_sec_context.c index ba1a977d2..2af942338 100644 --- a/lib/gssapi/krb5/import_sec_context.c +++ b/lib/gssapi/krb5/import_sec_context.c @@ -33,8 +33,6 @@ #include "gsskrb5_locl.h" -RCSID("$Id$"); - OM_uint32 _gsskrb5_import_sec_context ( OM_uint32 * minor_status, diff --git a/lib/gssapi/krb5/indicate_mechs.c b/lib/gssapi/krb5/indicate_mechs.c index 3702106e7..b1d18bd24 100644 --- a/lib/gssapi/krb5/indicate_mechs.c +++ b/lib/gssapi/krb5/indicate_mechs.c @@ -33,8 +33,6 @@ #include "gsskrb5_locl.h" -RCSID("$Id$"); - OM_uint32 _gsskrb5_indicate_mechs (OM_uint32 * minor_status, gss_OID_set * mech_set diff --git a/lib/gssapi/krb5/init.c b/lib/gssapi/krb5/init.c index b28e6a4c1..3a22c33ed 100644 --- a/lib/gssapi/krb5/init.c +++ b/lib/gssapi/krb5/init.c @@ -33,8 +33,6 @@ #include "gsskrb5_locl.h" -RCSID("$Id$"); - static HEIMDAL_MUTEX context_mutex = HEIMDAL_MUTEX_INITIALIZER; static int created_key; static HEIMDAL_thread_key context_key; diff --git a/lib/gssapi/krb5/init_sec_context.c b/lib/gssapi/krb5/init_sec_context.c index 4b632bd95..35ab9dd88 100644 --- a/lib/gssapi/krb5/init_sec_context.c +++ b/lib/gssapi/krb5/init_sec_context.c @@ -33,8 +33,6 @@ #include "gsskrb5_locl.h" -RCSID("$Id$"); - /* * copy the addresses from `input_chan_bindings' (if any) to * the auth context `ac' @@ -697,7 +695,7 @@ repl_mutual if (actual_mech_type) *actual_mech_type = GSS_KRB5_MECHANISM; - if (ctx->flags & GSS_C_DCE_STYLE) { + if (IS_DCE_STYLE(ctx)) { /* There is no OID wrapping. */ indata.length = input_token->length; indata.data = input_token->value; diff --git a/lib/gssapi/krb5/inquire_context.c b/lib/gssapi/krb5/inquire_context.c index 188a6135a..381ffc9e6 100644 --- a/lib/gssapi/krb5/inquire_context.c +++ b/lib/gssapi/krb5/inquire_context.c @@ -33,8 +33,6 @@ #include "gsskrb5_locl.h" -RCSID("$Id$"); - OM_uint32 _gsskrb5_inquire_context ( OM_uint32 * minor_status, const gss_ctx_id_t context_handle, diff --git a/lib/gssapi/krb5/inquire_cred.c b/lib/gssapi/krb5/inquire_cred.c index 27e301492..518736d78 100644 --- a/lib/gssapi/krb5/inquire_cred.c +++ b/lib/gssapi/krb5/inquire_cred.c @@ -33,8 +33,6 @@ #include "gsskrb5_locl.h" -RCSID("$Id$"); - OM_uint32 _gsskrb5_inquire_cred (OM_uint32 * minor_status, const gss_cred_id_t cred_handle, diff --git a/lib/gssapi/krb5/inquire_cred_by_mech.c b/lib/gssapi/krb5/inquire_cred_by_mech.c index 1fd973394..9da1ac43f 100644 --- a/lib/gssapi/krb5/inquire_cred_by_mech.c +++ b/lib/gssapi/krb5/inquire_cred_by_mech.c @@ -33,8 +33,6 @@ #include "gsskrb5_locl.h" -RCSID("$Id$"); - OM_uint32 _gsskrb5_inquire_cred_by_mech ( OM_uint32 * minor_status, const gss_cred_id_t cred_handle, diff --git a/lib/gssapi/krb5/inquire_cred_by_oid.c b/lib/gssapi/krb5/inquire_cred_by_oid.c index 5a35202a6..f32342f1d 100644 --- a/lib/gssapi/krb5/inquire_cred_by_oid.c +++ b/lib/gssapi/krb5/inquire_cred_by_oid.c @@ -32,8 +32,6 @@ #include "gsskrb5_locl.h" -RCSID("$Id$"); - OM_uint32 _gsskrb5_inquire_cred_by_oid (OM_uint32 * minor_status, const gss_cred_id_t cred_handle, diff --git a/lib/gssapi/krb5/inquire_mechs_for_name.c b/lib/gssapi/krb5/inquire_mechs_for_name.c index 5d54bd650..5fa3c302a 100644 --- a/lib/gssapi/krb5/inquire_mechs_for_name.c +++ b/lib/gssapi/krb5/inquire_mechs_for_name.c @@ -33,8 +33,6 @@ #include "gsskrb5_locl.h" -RCSID("$Id$"); - OM_uint32 _gsskrb5_inquire_mechs_for_name ( OM_uint32 * minor_status, const gss_name_t input_name, diff --git a/lib/gssapi/krb5/inquire_names_for_mech.c b/lib/gssapi/krb5/inquire_names_for_mech.c index 9eba7b7f4..591343307 100644 --- a/lib/gssapi/krb5/inquire_names_for_mech.c +++ b/lib/gssapi/krb5/inquire_names_for_mech.c @@ -33,9 +33,6 @@ #include "gsskrb5_locl.h" -RCSID("$Id$"); - - static gss_OID *name_list[] = { &GSS_C_NT_HOSTBASED_SERVICE, &GSS_C_NT_USER_NAME, diff --git a/lib/gssapi/krb5/inquire_sec_context_by_oid.c b/lib/gssapi/krb5/inquire_sec_context_by_oid.c index f8ef2a3aa..ce01e666f 100644 --- a/lib/gssapi/krb5/inquire_sec_context_by_oid.c +++ b/lib/gssapi/krb5/inquire_sec_context_by_oid.c @@ -32,8 +32,6 @@ #include "gsskrb5_locl.h" -RCSID("$Id$"); - static int oid_prefix_equal(gss_OID oid_enc, gss_OID prefix_enc, unsigned *suffix) { diff --git a/lib/gssapi/krb5/prf.c b/lib/gssapi/krb5/prf.c index 9fd13f51b..76ae3b78e 100644 --- a/lib/gssapi/krb5/prf.c +++ b/lib/gssapi/krb5/prf.c @@ -33,8 +33,6 @@ #include "gsskrb5_locl.h" -RCSID("$Id$"); - OM_uint32 _gsskrb5_pseudo_random(OM_uint32 *minor_status, gss_ctx_id_t context_handle, diff --git a/lib/gssapi/krb5/process_context_token.c b/lib/gssapi/krb5/process_context_token.c index 3229b3629..1c9d44588 100644 --- a/lib/gssapi/krb5/process_context_token.c +++ b/lib/gssapi/krb5/process_context_token.c @@ -33,8 +33,6 @@ #include "gsskrb5_locl.h" -RCSID("$Id$"); - OM_uint32 _gsskrb5_process_context_token ( OM_uint32 *minor_status, const gss_ctx_id_t context_handle, diff --git a/lib/gssapi/krb5/release_buffer.c b/lib/gssapi/krb5/release_buffer.c index 18e027993..b704e001e 100644 --- a/lib/gssapi/krb5/release_buffer.c +++ b/lib/gssapi/krb5/release_buffer.c @@ -33,8 +33,6 @@ #include "gsskrb5_locl.h" -RCSID("$Id$"); - OM_uint32 _gsskrb5_release_buffer (OM_uint32 * minor_status, gss_buffer_t buffer diff --git a/lib/gssapi/krb5/release_cred.c b/lib/gssapi/krb5/release_cred.c index 62674a1d5..5eec3c48c 100644 --- a/lib/gssapi/krb5/release_cred.c +++ b/lib/gssapi/krb5/release_cred.c @@ -33,8 +33,6 @@ #include "gsskrb5_locl.h" -RCSID("$Id$"); - OM_uint32 _gsskrb5_release_cred (OM_uint32 * minor_status, gss_cred_id_t * cred_handle diff --git a/lib/gssapi/krb5/release_name.c b/lib/gssapi/krb5/release_name.c index 5491052c5..0fafc275d 100644 --- a/lib/gssapi/krb5/release_name.c +++ b/lib/gssapi/krb5/release_name.c @@ -33,8 +33,6 @@ #include "gsskrb5_locl.h" -RCSID("$Id$"); - OM_uint32 _gsskrb5_release_name (OM_uint32 * minor_status, gss_name_t * input_name diff --git a/lib/gssapi/krb5/sequence.c b/lib/gssapi/krb5/sequence.c index 6391d4442..fbbc5b6c7 100644 --- a/lib/gssapi/krb5/sequence.c +++ b/lib/gssapi/krb5/sequence.c @@ -33,8 +33,6 @@ #include "gsskrb5_locl.h" -RCSID("$Id$"); - #define DEFAULT_JITTER_WINDOW 20 struct gss_msg_order { diff --git a/lib/gssapi/krb5/set_cred_option.c b/lib/gssapi/krb5/set_cred_option.c index 2a2390f8d..15d7632e4 100644 --- a/lib/gssapi/krb5/set_cred_option.c +++ b/lib/gssapi/krb5/set_cred_option.c @@ -32,8 +32,6 @@ #include "gsskrb5_locl.h" -RCSID("$Id$"); - /* 1.2.752.43.13.17 */ static gss_OID_desc gss_krb5_cred_no_ci_flags_x_oid_desc = {6, rk_UNCONST("\x2a\x85\x70\x2b\x0d\x11")}; diff --git a/lib/gssapi/krb5/set_sec_context_option.c b/lib/gssapi/krb5/set_sec_context_option.c index 460cfe942..096e83504 100644 --- a/lib/gssapi/krb5/set_sec_context_option.c +++ b/lib/gssapi/krb5/set_sec_context_option.c @@ -36,8 +36,6 @@ #include "gsskrb5_locl.h" -RCSID("$Id$"); - static OM_uint32 get_bool(OM_uint32 *minor_status, const gss_buffer_t value, diff --git a/lib/gssapi/krb5/test_acquire_cred.c b/lib/gssapi/krb5/test_acquire_cred.c index bae948ad4..7abb35dd9 100644 --- a/lib/gssapi/krb5/test_acquire_cred.c +++ b/lib/gssapi/krb5/test_acquire_cred.c @@ -34,8 +34,6 @@ #include "gsskrb5_locl.h" #include -RCSID("$Id$"); - static void print_time(OM_uint32 time_rec) { diff --git a/lib/gssapi/krb5/test_cfx.c b/lib/gssapi/krb5/test_cfx.c index 698f459eb..28b403ba1 100644 --- a/lib/gssapi/krb5/test_cfx.c +++ b/lib/gssapi/krb5/test_cfx.c @@ -33,8 +33,6 @@ #include "gsskrb5_locl.h" -RCSID("$Id$"); - struct range { size_t lower; size_t upper; diff --git a/lib/gssapi/krb5/test_cred.c b/lib/gssapi/krb5/test_cred.c index 8585dd668..1acdad2e4 100644 --- a/lib/gssapi/krb5/test_cred.c +++ b/lib/gssapi/krb5/test_cred.c @@ -35,8 +35,6 @@ #include #include -RCSID("$Id$"); - static void gss_print_errors (int min_stat) { diff --git a/lib/gssapi/krb5/test_kcred.c b/lib/gssapi/krb5/test_kcred.c index 0f5069499..bdb9e8379 100644 --- a/lib/gssapi/krb5/test_kcred.c +++ b/lib/gssapi/krb5/test_kcred.c @@ -35,8 +35,6 @@ #include #include -RCSID("$Id$"); - static int version_flag = 0; static int help_flag = 0; diff --git a/lib/gssapi/krb5/test_oid.c b/lib/gssapi/krb5/test_oid.c index c16d32178..00219b91e 100644 --- a/lib/gssapi/krb5/test_oid.c +++ b/lib/gssapi/krb5/test_oid.c @@ -33,8 +33,6 @@ #include "gsskrb5_locl.h" -RCSID("$Id$"); - int main(int argc, char **argv) { diff --git a/lib/gssapi/krb5/test_sequence.c b/lib/gssapi/krb5/test_sequence.c index cdbff9a03..b0f207270 100644 --- a/lib/gssapi/krb5/test_sequence.c +++ b/lib/gssapi/krb5/test_sequence.c @@ -33,8 +33,6 @@ #include "gsskrb5_locl.h" -RCSID("$Id$"); - /* correct ordering */ OM_uint32 pattern1[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13 diff --git a/lib/gssapi/krb5/ticket_flags.c b/lib/gssapi/krb5/ticket_flags.c index 736df427b..df5f11d8f 100644 --- a/lib/gssapi/krb5/ticket_flags.c +++ b/lib/gssapi/krb5/ticket_flags.c @@ -33,8 +33,6 @@ #include "gsskrb5_locl.h" -RCSID("$Id$"); - OM_uint32 _gsskrb5_get_tkt_flags(OM_uint32 *minor_status, gsskrb5_ctx ctx, diff --git a/lib/gssapi/krb5/unwrap.c b/lib/gssapi/krb5/unwrap.c index 1b325552a..9de6b9593 100644 --- a/lib/gssapi/krb5/unwrap.c +++ b/lib/gssapi/krb5/unwrap.c @@ -33,8 +33,6 @@ #include "gsskrb5_locl.h" -RCSID("$Id$"); - static OM_uint32 unwrap_des (OM_uint32 * minor_status, diff --git a/lib/gssapi/krb5/verify_mic.c b/lib/gssapi/krb5/verify_mic.c index 6eb7ae4b0..c7e16e81f 100644 --- a/lib/gssapi/krb5/verify_mic.c +++ b/lib/gssapi/krb5/verify_mic.c @@ -33,8 +33,6 @@ #include "gsskrb5_locl.h" -RCSID("$Id$"); - static OM_uint32 verify_mic_des (OM_uint32 * minor_status, diff --git a/lib/gssapi/krb5/wrap.c b/lib/gssapi/krb5/wrap.c index edbd6645f..9627cc20b 100644 --- a/lib/gssapi/krb5/wrap.c +++ b/lib/gssapi/krb5/wrap.c @@ -33,8 +33,6 @@ #include "gsskrb5_locl.h" -RCSID("$Id$"); - /* * Return initiator subkey, or if that doesn't exists, the subkey. */ @@ -522,7 +520,7 @@ OM_uint32 _gsskrb5_wrap if (ctx->more_flags & IS_CFX) return _gssapi_wrap_cfx (minor_status, ctx, context, conf_req_flag, - qop_req, input_message_buffer, conf_state, + input_message_buffer, conf_state, output_message_buffer); HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex); diff --git a/lib/gssapi/mech/gss_aeap.c b/lib/gssapi/mech/gss_aeap.c index cbe0cd146..9c784f42d 100644 --- a/lib/gssapi/mech/gss_aeap.c +++ b/lib/gssapi/mech/gss_aeap.c @@ -3,27 +3,39 @@ */ #include "mech_locl.h" -RCSID("$Id$"); /** * Encrypts or sign the data. * + * This is a more complicated version of gss_wrap(), it allows the + * caller to use AEAD data (signed header/trailer) and allow greater + * controll over where the encrypted data is placed. + * * The maximum packet size is gss_context_stream_sizes.max_msg_size. * - * The caller needs provide the folloing buffers: + * The caller needs provide the folloing buffers when using in conf_req_flag=1 mode: * * - HEADER (of size gss_context_stream_sizes.header) - * SIGN_ONLY (optional, zero or more) - * DATA - * SIGN_ONLY (optional, zero or more) - * PADDING (of size gss_context_stream_sizes.blocksize) + * { DATA or SIGN_ONLY } (optional, zero or more) + * PADDING (of size gss_context_stream_sizes.blocksize, if zero padding is zero, can be omitted) * TRAILER (of size gss_context_stream_sizes.trailer) * * - on DCE-RPC mode, the caller can skip PADDING and TRAILER if the - * DATA elements is padded to a block bountry. + * DATA elements is padded to a block bountry and header is of at + * least size gss_context_stream_sizes.header + gss_context_stream_sizes.trailer. + * + * HEADER, PADDING, TRAILER will be shrunken to the size required to transmit any of them too large. * * To generate gss_wrap() compatible packets, use: HEADER | DATA | PADDING | TRAILER * + * When used in conf_req_flag=0, + * + * - HEADER (of size gss_context_stream_sizes.header) + * { DATA or SIGN_ONLY } (optional, zero or more) + * PADDING (of size gss_context_stream_sizes.blocksize, if zero padding is zero, can be omitted) + * TRAILER (of size gss_context_stream_sizes.trailer) + * + * * The input sizes of HEADER, PADDING and TRAILER can be fetched using gss_wrap_iov_length() or * gss_context_query_attributes(). * @@ -65,6 +77,13 @@ gss_wrap_iov(OM_uint32 * minor_status, iov, iov_count); } +/** + * Decrypt or verifies the signature on the data. + * + * + * @ingroup gssapi + */ + OM_uint32 GSSAPI_LIB_FUNCTION gss_unwrap_iov(OM_uint32 *minor_status, gss_ctx_id_t context_handle, @@ -99,7 +118,18 @@ gss_unwrap_iov(OM_uint32 *minor_status, iov, iov_count); } -OM_uint32 GSSAPI_LIB_FUNCTION +/** + * Update the length fields in iov buffer for the types: + * - GSS_IOV_BUFFER_TYPE_HEADER + * - GSS_IOV_BUFFER_TYPE_PADDING + * - GSS_IOV_BUFFER_TYPE_TRAILER + * + * Consider using gss_context_query_attributes() to fetch the data instead. + * + * @ingroup gssapi + */ + +OM_uint32 GSSAPI_LIB_FUNCTION gss_wrap_iov_length(OM_uint32 * minor_status, gss_ctx_id_t context_handle, int conf_req_flag, @@ -132,6 +162,13 @@ gss_wrap_iov_length(OM_uint32 * minor_status, iov, iov_count); } +/** + * Free all buffer allocated by gss_wrap_iov() or gss_unwrap_iov() by + * looking at the GSS_IOV_BUFFER_TYPE_FLAG_ALLOCATED flag. + * + * @ingroup gssapi + */ + OM_uint32 GSSAPI_LIB_FUNCTION gss_release_iov_buffer(OM_uint32 *minor_status, gss_iov_buffer_desc *iov, @@ -146,9 +183,10 @@ gss_release_iov_buffer(OM_uint32 *minor_status, return GSS_S_CALL_INACCESSIBLE_READ; for (i = 0; i < iov_count; i++) { - if (iov[i].type & GSS_IOV_BUFFER_TYPE_FLAG_ALLOCATED) + if ((iov[i].type & GSS_IOV_BUFFER_TYPE_FLAG_ALLOCATED) == 0) continue; gss_release_buffer(&junk, &iov[i].buffer); + iov[i].type &= ~GSS_IOV_BUFFER_TYPE_FLAG_ALLOCATED; } return GSS_S_COMPLETE; } @@ -159,6 +197,8 @@ gss_release_iov_buffer(OM_uint32 *minor_status, * SSPI equivalent if this function is QueryContextAttributes. * * - GSS_C_ATTR_STREAM_SIZES data is a gss_context_stream_sizes. + * + * @ingroup gssapi */ static gss_OID_desc gss_c_attr_stream_sizes_desc = diff --git a/lib/gssapi/test_context.c b/lib/gssapi/test_context.c index 1dab3b51a..27f83da52 100644 --- a/lib/gssapi/test_context.c +++ b/lib/gssapi/test_context.c @@ -49,6 +49,7 @@ static int dns_canon_flag = -1; static int mutual_auth_flag = 0; static int dce_style_flag = 0; static int wrapunwrap_flag = 0; +static int iov_flag = 0; static int getverifymic_flag = 0; static int deleg_flag = 0; static int policy_deleg_flag = 0; @@ -79,7 +80,7 @@ string_to_oid(const char *name) for (i = 0; i < sizeof(o2n)/sizeof(o2n[0]); i++) if (strcasecmp(name, o2n[i].name) == 0) return *o2n[i].oid; - errx(1, "name %s not unknown", name); + errx(1, "name '%s' not unknown", name); } static const char * @@ -255,38 +256,60 @@ wrapunwrap(gss_ctx_id_t cctx, gss_ctx_id_t sctx, int flags, gss_OID mechoid) #endif } +#define USE_CONF 1 +#define USE_HEADER_ONLY 2 +#define USE_SIGN_ONLY 4 +#define FORCE_IOV 8 + static void -wrapunwrap_ext(gss_ctx_id_t cctx, gss_ctx_id_t sctx, int flags, gss_OID mechoid) +wrapunwrap_iov(gss_ctx_id_t cctx, gss_ctx_id_t sctx, int flags, gss_OID mechoid) { krb5_data token, header, trailer; OM_uint32 min_stat, maj_stat; gss_qop_t qop_state; - int conf_state; - gss_iov_buffer_desc iov[6]; + int conf_state, conf_state2; + gss_iov_buffer_desc iov[5]; unsigned char *p; int iov_len; + char header_data[9] = "ABCheader"; + char trailer_data[10] = "trailerXYZ"; + + char token_data[16] = "0123456789abcdef"; memset(&iov, 0, sizeof(iov)); - header.data = "ABCheader"; - header.length = 9; - token.data = "0123456789abcdef"; + if (flags & USE_SIGN_ONLY) { + header.data = header_data; + header.length = 9; + trailer.data = trailer_data; + trailer.length = 10; + } else { + header.data = NULL; + header.length = 0; + trailer.data = NULL; + trailer.length = 0; + } + + token.data = token_data; token.length = 16; - trailer.data = "trailerXYZ"; - trailer.length = 10; iov_len = sizeof(iov)/sizeof(iov[0]); - if (flags & 2) - iov_len -= 2; /* skip trailer and padding, aka dce-style */ + memset(iov, 0, sizeof(iov)); + + if (flags & USE_HEADER_ONLY) + iov_len -= 1; /* skip trailer */ iov[0].type = GSS_IOV_BUFFER_TYPE_HEADER | GSS_IOV_BUFFER_TYPE_FLAG_ALLOCATE; + if (header.length != 0) { iov[1].type = GSS_IOV_BUFFER_TYPE_SIGN_ONLY; iov[1].buffer.length = header.length; iov[1].buffer.value = header.data; } else { iov[1].type = GSS_IOV_BUFFER_TYPE_EMPTY; + iov[1].buffer.length = 0; + iov[1].buffer.value = NULL; } iov[2].type = GSS_IOV_BUFFER_TYPE_DATA; iov[2].buffer.length = token.length; @@ -297,60 +320,68 @@ wrapunwrap_ext(gss_ctx_id_t cctx, gss_ctx_id_t sctx, int flags, gss_OID mechoid) iov[3].buffer.value = trailer.data; } else { iov[3].type = GSS_IOV_BUFFER_TYPE_EMPTY; + iov[3].buffer.length = 0; + iov[3].buffer.value = NULL; } - iov[4].type = GSS_IOV_BUFFER_TYPE_PADDING | GSS_IOV_BUFFER_TYPE_FLAG_ALLOCATE; - iov[5].type = GSS_IOV_BUFFER_TYPE_TRAILER | GSS_IOV_BUFFER_TYPE_FLAG_ALLOCATE; + iov[4].type = GSS_IOV_BUFFER_TYPE_TRAILER | GSS_IOV_BUFFER_TYPE_FLAG_ALLOCATE; + iov[4].buffer.length = 0; + iov[4].buffer.value = 0; - maj_stat = gss_wrap_iov_length(&min_stat, cctx, flags & 1, 0, &conf_state, - iov, iov_len); - if (maj_stat != GSS_S_COMPLETE) - errx(1, "gss_wrap_iov_length failed"); - - maj_stat = gss_wrap_iov(&min_stat, cctx, flags & 1, 0, &conf_state, + maj_stat = gss_wrap_iov(&min_stat, cctx, flags & USE_CONF, 0, &conf_state, iov, iov_len); if (maj_stat != GSS_S_COMPLETE) errx(1, "gss_wrap_iov failed"); - token.length = iov[0].buffer.length + iov[2].buffer.length + iov[4].buffer.length + iov[5].buffer.length; - token.data = malloc(token.length); + token.length = + iov[0].buffer.length + + iov[1].buffer.length + + iov[2].buffer.length + + iov[3].buffer.length + + iov[4].buffer.length; + token.data = emalloc(token.length); p = token.data; memcpy(p, iov[0].buffer.value, iov[0].buffer.length); p += iov[0].buffer.length; + memcpy(p, iov[1].buffer.value, iov[1].buffer.length); + p += iov[1].buffer.length; memcpy(p, iov[2].buffer.value, iov[2].buffer.length); p += iov[2].buffer.length; + memcpy(p, iov[3].buffer.value, iov[3].buffer.length); + p += iov[3].buffer.length; memcpy(p, iov[4].buffer.value, iov[4].buffer.length); p += iov[4].buffer.length; - memcpy(p, iov[5].buffer.value, iov[5].buffer.length); - p += iov[5].buffer.length; - iov_len = 3; + assert(p - ((unsigned char *)token.data) == token.length); - if (header.length != 0) { - iov[0].type = GSS_IOV_BUFFER_TYPE_SIGN_ONLY; - iov[0].buffer.length = header.length; - iov[0].buffer.value = header.data; - } else { - iov[0].type = GSS_IOV_BUFFER_TYPE_EMPTY; - } - iov[1].type = GSS_IOV_BUFFER_TYPE_DATA; - iov[1].buffer.length = token.length; - iov[1].buffer.value = token.data; + if ((flags & (USE_SIGN_ONLY|FORCE_IOV)) == 0) { + gss_buffer_desc input, output; - if (trailer.length != 0) { - iov[2].type = GSS_IOV_BUFFER_TYPE_SIGN_ONLY; - iov[2].buffer.length = trailer.length; - iov[2].buffer.value = trailer.data; + input.value = token.data; + input.length = token.length; + + maj_stat = gss_unwrap(&min_stat, sctx, &input, + &output, &conf_state2, &qop_state); + + if (maj_stat != GSS_S_COMPLETE) + errx(1, "gss_unwrap failed: %s", + gssapi_err(maj_stat, min_stat, mechoid)); + + gss_release_buffer(&min_stat, &output); } else { - iov[2].type = GSS_IOV_BUFFER_TYPE_EMPTY; + maj_stat = gss_unwrap_iov(&min_stat, sctx, &conf_state2, &qop_state, + iov, iov_len); + + if (maj_stat != GSS_S_COMPLETE) + errx(1, "gss_unwrap_iov failed: %x %s", flags, + gssapi_err(maj_stat, min_stat, mechoid)); + } + if (conf_state2 != conf_state) + errx(1, "conf state wrong for iov: %x", flags); - maj_stat = gss_unwrap_iov(&min_stat, sctx, &conf_state, &qop_state, - iov, iov_len); - if (maj_stat != GSS_S_COMPLETE) - errx(1, "gss_unwrap_iov failed: %s", - gssapi_err(maj_stat, min_stat, mechoid)); + free(token.data); } static void @@ -405,6 +436,7 @@ static struct getargs args[] = { {"mutual-auth",0, arg_flag, &mutual_auth_flag,"mutual auth", NULL }, {"dce-style",0, arg_flag, &dce_style_flag, "dce-style", NULL }, {"wrapunwrap",0, arg_flag, &wrapunwrap_flag, "wrap/unwrap", NULL }, + {"iov", 0, arg_flag, &iov_flag, "wrap/unwrap iov", NULL }, {"getverifymic",0, arg_flag, &getverifymic_flag, "get and verify mic", NULL }, {"delegate",0, arg_flag, &deleg_flag, "delegate credential", NULL }, @@ -499,7 +531,7 @@ main(int argc, char **argv) /* XXX should be actual_mech */ if (gss_oid_equal(mechoid, GSS_KRB5_MECHANISM)) { krb5_context context; - time_t time, skew; + time_t time; gss_buffer_desc authz_data; gss_buffer_desc in, out1, out2; krb5_keyblock *keyblock, *keyblock2; @@ -549,13 +581,10 @@ main(int argc, char **argv) errx(1, "gsskrb5_extract_authtime_from_sec_context failed: %s", gssapi_err(maj_stat, min_stat, actual_mech)); - skew = abs(time - now); - if (skew > krb5_get_max_time_skew(context)) { + if (time > now) errx(1, "gsskrb5_extract_authtime_from_sec_context failed: " - "time skew too great %llu > %llu", - (unsigned long long)skew, - (unsigned long long)krb5_get_max_time_skew(context)); - } + "time authtime is before now: %ld %ld", + (long)time, (long)now); maj_stat = gsskrb5_extract_service_keyblock(&min_stat, sctx, @@ -698,14 +727,20 @@ main(int argc, char **argv) wrapunwrap(cctx, sctx, 1, actual_mech); wrapunwrap(sctx, cctx, 0, actual_mech); wrapunwrap(sctx, cctx, 1, actual_mech); + } -#if 0 - wrapunwrap_ext(cctx, sctx, 1, actual_mech); - wrapunwrap_ext(cctx, sctx, 2, actual_mech); - wrapunwrap_ext(cctx, sctx, 3, actual_mech); -#endif + if (iov_flag) { + wrapunwrap_iov(cctx, sctx, 0, actual_mech); + wrapunwrap_iov(cctx, sctx, USE_CONF, actual_mech); + wrapunwrap_iov(cctx, sctx, USE_CONF|USE_HEADER_ONLY, actual_mech); + + wrapunwrap_iov(cctx, sctx, FORCE_IOV, actual_mech); + wrapunwrap_iov(cctx, sctx, USE_CONF|FORCE_IOV, actual_mech); + wrapunwrap_iov(cctx, sctx, USE_CONF|USE_HEADER_ONLY|FORCE_IOV, actual_mech); + wrapunwrap_iov(cctx, sctx, USE_CONF|USE_HEADER_ONLY|USE_SIGN_ONLY, actual_mech); } + if (getverifymic_flag) { getverifymic(cctx, sctx, actual_mech); getverifymic(cctx, sctx, actual_mech); diff --git a/lib/krb5/aes-test.c b/lib/krb5/aes-test.c index e135e338f..54e0237e0 100644 --- a/lib/krb5/aes-test.c +++ b/lib/krb5/aes-test.c @@ -33,6 +33,7 @@ #include "krb5_locl.h" #include #include +#include #ifdef HAVE_OPENSSL #include @@ -324,30 +325,31 @@ krb_enc_iov2(krb5_context context, krb5_data *clear) { krb5_crypto_iov iov[4]; + krb5_data decrypt; int ret; - char *p; + char *p, *q; size_t len, i; p = clear->data; len = clear->length; iov[0].flags = KRB5_CRYPTO_TYPE_HEADER; - iov[0].data.length = krb5_crypto_length(context, crypto, iov[0].flags); + krb5_crypto_length(context, crypto, iov[0].flags, &iov[0].data.length); iov[0].data.data = emalloc(iov[0].data.length); - iov[1].flags = KRB5_CRYPTO_TYPE_TRAILER; - iov[1].data.length = krb5_crypto_length(context, crypto, iov[1].flags); + iov[1].flags = KRB5_CRYPTO_TYPE_DATA; + iov[1].data.length = len; iov[1].data.data = emalloc(iov[1].data.length); + memcpy(iov[1].data.data, p, iov[1].data.length); - iov[2].flags = KRB5_CRYPTO_TYPE_DATA; - iov[2].data.length = len; + /* padding buffer */ + iov[2].flags = KRB5_CRYPTO_TYPE_PADDING; + krb5_crypto_length(context, crypto, KRB5_CRYPTO_TYPE_PADDING, &iov[2].data.length); iov[2].data.data = emalloc(iov[2].data.length); - memcpy(iov[2].data.data, p, iov[2].data.length); - /* padding buffer */ - iov[3].flags = KRB5_CRYPTO_TYPE_PADDING; - iov[3].data.length = krb5_crypto_length(context, crypto, KRB5_CRYPTO_TYPE_PADDING); - iov[3].data.data = emalloc(iov[4].data.length); + iov[3].flags = KRB5_CRYPTO_TYPE_TRAILER; + krb5_crypto_length(context, crypto, iov[3].flags, &iov[3].data.length); + iov[3].data.data = emalloc(iov[3].data.length); ret = krb5_encrypt_iov_ivec(context, crypto, usage, iov, sizeof(iov)/sizeof(iov[0]), NULL); @@ -360,33 +362,54 @@ krb_enc_iov2(krb5_context context, if (len != cipher_len) errx(1, "cipher len wrong"); - /* now decrypt */ + /* + * Plain decrypt + */ + + p = q = emalloc(len); + for (i = 0; i < sizeof(iov)/sizeof(iov[0]); i++) { + memcpy(q, iov[i].data.data, iov[i].data.length); + q += iov[i].data.length; + } + + ret = krb5_decrypt(context, crypto, usage, p, len, &decrypt); + if (ret) + krb5_err(context, 1, ret, "krb5_decrypt"); + else + krb5_data_free(&decrypt); + + free(p); + + /* + * Now decrypt use iov + */ /* padding turn into data */ - p = emalloc(iov[2].data.length + iov[3].data.length); + p = emalloc(iov[1].data.length + iov[2].data.length); - memcpy(p, iov[2].data.data, iov[2].data.length); - memcpy(p + iov[2].data.length, iov[3].data.data, iov[3].data.length); + memcpy(p, iov[1].data.data, iov[1].data.length); + memcpy(p + iov[1].data.length, iov[2].data.data, iov[2].data.length); + free(iov[1].data.data); free(iov[2].data.data); - free(iov[3].data.data); - iov[2].data.data = p; - iov[2].data.length += iov[3].data.length; + iov[1].data.data = p; + iov[1].data.length += iov[2].data.length; - iov[3].flags = KRB5_CRYPTO_TYPE_EMPTY; + iov[2].flags = KRB5_CRYPTO_TYPE_EMPTY; + iov[2].data.length = 0; ret = krb5_decrypt_iov_ivec(context, crypto, usage, iov, sizeof(iov)/sizeof(iov[0]), NULL); if (ret) - errx(1, "decrypt iov failed: %d", ret); + krb5_err(context, 1, ret, "decrypt iov failed: %d", ret); - if (clear->length != iov[2].data.length) + if (clear->length != iov[1].data.length) errx(1, "length incorrect"); p = clear->data; - if (memcmp(iov[2].data.data, p, iov[2].data.length) != 0) - errx(1, "iov[2] incorrect"); + if (memcmp(iov[1].data.data, p, iov[1].data.length) != 0) + errx(1, "iov[1] incorrect"); return 0; } @@ -408,14 +431,14 @@ krb_enc_iov(krb5_context context, len = cipher->length; iov[0].flags = KRB5_CRYPTO_TYPE_HEADER; - iov[0].data.length = krb5_crypto_length(context, crypto, iov[0].flags); + krb5_crypto_length(context, crypto, iov[0].flags, &iov[0].data.length); iov[0].data.data = emalloc(iov[0].data.length); memcpy(iov[0].data.data, p, iov[0].data.length); p += iov[0].data.length; len -= iov[0].data.length; iov[1].flags = KRB5_CRYPTO_TYPE_TRAILER; - iov[1].data.length = krb5_crypto_length(context, crypto, iov[1].flags); + krb5_crypto_length(context, crypto, iov[1].flags, &iov[1].data.length); iov[1].data.data = emalloc(iov[1].data.length); memcpy(iov[1].data.data, p + len - iov[1].data.length, iov[1].data.length); len -= iov[1].data.length; @@ -428,7 +451,7 @@ krb_enc_iov(krb5_context context, ret = krb5_decrypt_iov_ivec(context, crypto, usage, iov, sizeof(iov)/sizeof(iov[0]), NULL); if (ret) - errx(1, "krb_enc_iov decrypt iov failed: %d", ret); + krb5_err(context, 1, ret, "krb_enc_iov decrypt iov failed: %d", ret); if (clear->length != iov[2].data.length) errx(1, "length incorrect"); @@ -440,6 +463,43 @@ krb_enc_iov(krb5_context context, return 0; } +static int +krb_checksum_iov(krb5_context context, + krb5_crypto crypto, + unsigned usage, + krb5_data *plain) +{ + krb5_crypto_iov iov[4]; + int ret; + char *p; + size_t len; + + p = plain->data; + len = plain->length; + + iov[0].flags = KRB5_CRYPTO_TYPE_CHECKSUM; + krb5_crypto_length(context, crypto, iov[0].flags, &iov[0].data.length); + iov[0].data.data = emalloc(iov[0].data.length); + + iov[1].flags = KRB5_CRYPTO_TYPE_DATA; + iov[1].data.length = len; + iov[1].data.data = p; + + iov[2].flags = KRB5_CRYPTO_TYPE_TRAILER; + krb5_crypto_length(context, crypto, iov[0].flags, &iov[2].data.length); + iov[2].data.data = malloc(iov[2].data.length); + + ret = krb5_create_checksum_iov(context, crypto, usage, + iov, sizeof(iov)/sizeof(iov[0]), NULL); + if (ret) + krb5_err(context, 1, ret, "krb5_create_checksum_iov failed"); + + ret = krb5_verify_checksum_iov(context, crypto, usage, iov, sizeof(iov)/sizeof(iov[0]), NULL); + if (ret) + krb5_err(context, 1, ret, "krb5_verify_checksum_iov"); + + return 0; +} static int @@ -548,6 +608,10 @@ krb_enc_test(krb5_context context) if (ret) errx(1, "krb_enc_iov2 failed with %d for test %d", ret, i); + ret = krb_checksum_iov(context, crypto, krbencs[i].usage, &plain); + if (ret) + errx(1, "krb_checksum_iov failed with %d for test %d", ret, i); + krb5_crypto_destroy(context, crypto); ret = krb_enc_mit(context, krbencs[i].enctype, &kb, @@ -559,6 +623,184 @@ krb_enc_test(krb5_context context) return 0; } +static int +iov_test(krb5_context context) +{ + krb5_enctype enctype = ENCTYPE_AES256_CTS_HMAC_SHA1_96; + krb5_error_code ret; + krb5_crypto crypto; + krb5_keyblock key; + krb5_data signonly, in, in2; + krb5_crypto_iov iov[6]; + size_t len, i; + unsigned char *base, *p; + + ret = krb5_generate_random_keyblock(context, enctype, &key); + if (ret) + krb5_err(context, 1, ret, "krb5_generate_random_keyblock"); + + ret = krb5_crypto_init(context, &key, 0, &crypto); + if (ret) + krb5_err(context, 1, ret, "krb5_crypto_init"); + + + ret = krb5_crypto_length(context, crypto, KRB5_CRYPTO_TYPE_HEADER, &len); + if (ret) + krb5_err(context, 1, ret, "krb5_crypto_length"); + + signonly.data = "This should be signed"; + signonly.length = strlen(signonly.data); + in.data = "inputdata"; + in.length = strlen(in.data); + + in2.data = "INPUTDATA"; + in2.length = strlen(in2.data); + + + memset(iov, 0, sizeof(iov)); + + iov[0].flags = KRB5_CRYPTO_TYPE_HEADER; + iov[1].flags = KRB5_CRYPTO_TYPE_DATA; + iov[1].data = in; + iov[2].flags = KRB5_CRYPTO_TYPE_SIGN_ONLY; + iov[2].data = signonly; + iov[3].flags = KRB5_CRYPTO_TYPE_EMPTY; + iov[4].flags = KRB5_CRYPTO_TYPE_PADDING; + iov[5].flags = KRB5_CRYPTO_TYPE_TRAILER; + + ret = krb5_crypto_length_iov(context, crypto, iov, + sizeof(iov)/sizeof(iov[0])); + if (ret) + krb5_err(context, 1, ret, "krb5_crypto_length_iov"); + + for (len = 0, i = 0; i < sizeof(iov)/sizeof(iov[0]); i++) { + if (iov[i].flags == KRB5_CRYPTO_TYPE_SIGN_ONLY) + continue; + len += iov[i].data.length; + } + + base = emalloc(len); + + /* + * Allocate data for the fields + */ + + for (p = base, i = 0; i < sizeof(iov)/sizeof(iov[0]); i++) { + if (iov[i].flags == KRB5_CRYPTO_TYPE_SIGN_ONLY) + continue;; + iov[i].data.data = p; + p += iov[i].data.length; + } + assert(iov[1].data.length == in.length); + memcpy(iov[1].data.data, in.data, iov[1].data.length); + + /* + * Encrypt + */ + + ret = krb5_encrypt_iov_ivec(context, crypto, 7, iov, + sizeof(iov)/sizeof(iov[0]), NULL); + if (ret) + krb5_err(context, 1, ret, "krb5_encrypt_iov_ivec"); + + /* + * Decrypt + */ + + ret = krb5_decrypt_iov_ivec(context, crypto, 7, + iov, sizeof(iov)/sizeof(iov[0]), NULL); + if (ret) + krb5_err(context, 1, ret, "krb5_decrypt_iov_ivec"); + + /* + * Verify data + */ + + if (krb5_data_cmp(&iov[1].data, &in) != 0) + krb5_errx(context, 1, "decrypted data not same"); + + /* + * Free memory + */ + + free(base); + + /* Set up for second try */ + + iov[3].flags = KRB5_CRYPTO_TYPE_DATA; + iov[3].data = in; + + ret = krb5_crypto_length_iov(context, crypto, + iov, sizeof(iov)/sizeof(iov[0])); + if (ret) + krb5_err(context, 1, ret, "krb5_crypto_length_iov"); + + for (len = 0, i = 0; i < sizeof(iov)/sizeof(iov[0]); i++) { + if (iov[i].flags == KRB5_CRYPTO_TYPE_SIGN_ONLY) + continue; + len += iov[i].data.length; + } + + base = emalloc(len); + + /* + * Allocate data for the fields + */ + + for (p = base, i = 0; i < sizeof(iov)/sizeof(iov[0]); i++) { + if (iov[i].flags == KRB5_CRYPTO_TYPE_SIGN_ONLY) + continue;; + iov[i].data.data = p; + p += iov[i].data.length; + } + assert(iov[1].data.length == in.length); + memcpy(iov[1].data.data, in.data, iov[1].data.length); + + assert(iov[3].data.length == in2.length); + memcpy(iov[3].data.data, in2.data, iov[3].data.length); + + + + /* + * Encrypt + */ + + ret = krb5_encrypt_iov_ivec(context, crypto, 7, + iov, sizeof(iov)/sizeof(iov[0]), NULL); + if (ret) + krb5_err(context, 1, ret, "krb5_encrypt_iov_ivec"); + + /* + * Decrypt + */ + + ret = krb5_decrypt_iov_ivec(context, crypto, 7, + iov, sizeof(iov)/sizeof(iov[0]), NULL); + if (ret) + krb5_err(context, 1, ret, "krb5_decrypt_iov_ivec"); + + /* + * Verify data + */ + + if (krb5_data_cmp(&iov[1].data, &in) != 0) + krb5_errx(context, 1, "decrypted data 2.1 not same"); + + if (krb5_data_cmp(&iov[3].data, &in2) != 0) + krb5_errx(context, 1, "decrypted data 2.2 not same"); + + /* + * Free memory + */ + + free(base); + + krb5_crypto_destroy(context, crypto); + + return 0; +} + + static int random_to_key(krb5_context context) @@ -592,7 +834,6 @@ random_to_key(krb5_context context) return 0; } - int main(int argc, char **argv) { @@ -608,6 +849,7 @@ main(int argc, char **argv) val |= krb_enc_test(context); val |= random_to_key(context); + val |= iov_test(context); if (verbose && val == 0) printf("all ok\n"); diff --git a/lib/krb5/crypto.c b/lib/krb5/crypto.c index 9fd211734..a30780d1e 100644 --- a/lib/krb5/crypto.c +++ b/lib/krb5/crypto.c @@ -3182,7 +3182,7 @@ krb5_encrypt_iov_ivec(krb5_context context, krb5_error_code ret; struct key_data *dkey; const struct encryption_type *et = crypto->et; - krb5_crypto_iov *tiv, *piv, *hiv, *div; + krb5_crypto_iov *tiv, *piv, *hiv; if (num_data < 0) { krb5_clear_error_message(context); @@ -3197,11 +3197,11 @@ krb5_encrypt_iov_ivec(krb5_context context, headersz = et->confoundersize; trailersz = CHECKSUMSIZE(et->keyed_checksum); - div = find_iv(data, num_data, KRB5_CRYPTO_TYPE_DATA); - if (div == NULL) - return KRB5_CRYPTO_INTERNAL; - - len = div->data.length; + for (len = 0, i = 0; i < num_data; i++) { + if (data[i].flags != KRB5_CRYPTO_TYPE_DATA) + continue; + len += data[i].data.length; + } sz = headersz + len; block_sz = (sz + et->padsize - 1) &~ (et->padsize - 1); /* pad */ @@ -3217,7 +3217,6 @@ krb5_encrypt_iov_ivec(krb5_context context, krb5_generate_random_block(hiv->data.data, hiv->data.length); /* padding */ - piv = find_iv(data, num_data, KRB5_CRYPTO_TYPE_PADDING); /* its ok to have no TYPE_PADDING if there is no padding */ if (piv == NULL && pad_sz != 0) @@ -3226,26 +3225,26 @@ krb5_encrypt_iov_ivec(krb5_context context, if (piv->data.length < pad_sz) return KRB5_BAD_MSIZE; piv->data.length = pad_sz; + if (pad_sz) + memset(piv->data.data, pad_sz, pad_sz); + else + piv = NULL; } - /* trailer */ - tiv = find_iv(data, num_data, KRB5_CRYPTO_TYPE_TRAILER); if (tiv == NULL || tiv->data.length != trailersz) return KRB5_BAD_MSIZE; - /* * XXX replace with EVP_Sign? at least make create_checksum an iov * function. * XXX CTS EVP is broken, can't handle multi buffers :( */ - len = hiv->data.length; + len = block_sz; for (i = 0; i < num_data; i++) { - if (data[i].flags != KRB5_CRYPTO_TYPE_DATA && - data[i].flags != KRB5_CRYPTO_TYPE_SIGN_ONLY) + if (data[i].flags != KRB5_CRYPTO_TYPE_SIGN_ONLY) continue; len += data[i].data.length; } @@ -3261,6 +3260,10 @@ krb5_encrypt_iov_ivec(krb5_context context, memcpy(q, data[i].data.data, data[i].data.length); q += data[i].data.length; } + if (piv) { + memset(q, 0, piv->data.length); + q += piv->data.length; + } ret = create_checksum(context, et->keyed_checksum, @@ -3282,30 +3285,24 @@ krb5_encrypt_iov_ivec(krb5_context context, memcpy(tiv->data.data, cksum.checksum.data, cksum.checksum.length); free_Checksum (&cksum); - /* now encrypt data */ - - ret = _get_derived_key(context, crypto, ENCRYPTION_USAGE(usage), &dkey); - if(ret) - return ret; - ret = _key_schedule(context, dkey); - if(ret) - return ret; - /* XXX replace with EVP_Cipher */ - - len = hiv->data.length + div->data.length; - if (piv) - len += piv->data.length; - - p = q = malloc(len); + p = q = malloc(block_sz); if(p == NULL) return ENOMEM; memcpy(q, hiv->data.data, hiv->data.length); q += hiv->data.length; - memcpy(q, div->data.data, div->data.length); - q += div->data.length; - memset(q, 0, pad_sz); + + for (i = 0; i < num_data; i++) { + if (data[i].flags != KRB5_CRYPTO_TYPE_DATA) + continue; + memcpy(q, data[i].data.data, data[i].data.length); + q += data[i].data.length; + } + if (piv) { + memset(q, 0, piv->data.length); + q += piv->data.length; + } ret = _get_derived_key(context, crypto, ENCRYPTION_USAGE(usage), &dkey); if(ret) { @@ -3318,7 +3315,7 @@ krb5_encrypt_iov_ivec(krb5_context context, return ret; } - ret = (*et->encrypt)(context, dkey, p, len, 1, usage, ivec); + ret = (*et->encrypt)(context, dkey, p, block_sz, 1, usage, ivec); if (ret) { free(p); return ret; @@ -3330,11 +3327,17 @@ krb5_encrypt_iov_ivec(krb5_context context, memcpy(hiv->data.data, q, hiv->data.length); q += hiv->data.length; - memcpy(div->data.data, q, div->data.length); - q += div->data.length; - - if (piv) + for (i = 0; i < num_data; i++) { + if (data[i].flags != KRB5_CRYPTO_TYPE_DATA) + continue; + memcpy(data[i].data.data, q, data[i].data.length); + q += data[i].data.length; + } + if (piv) { memcpy(piv->data.data, q, pad_sz); + q += pad_sz; + } + free(p); return ret; @@ -3371,13 +3374,12 @@ krb5_decrypt_iov_ivec(krb5_context context, { unsigned int i; size_t headersz, trailersz, len; - size_t sz, block_sz, pad_sz; Checksum cksum; unsigned char *p, *q; krb5_error_code ret; struct key_data *dkey; struct encryption_type *et = crypto->et; - krb5_crypto_iov *tiv, *hiv, *div; + krb5_crypto_iov *tiv, *hiv; if (num_data < 0) { krb5_clear_error_message(context); @@ -3390,56 +3392,47 @@ krb5_decrypt_iov_ivec(krb5_context context, } headersz = et->confoundersize; - trailersz = CHECKSUMSIZE(et->keyed_checksum); - - for (len = 0, i = 0; i < num_data; i++) { - if (data[i].flags == KRB5_CRYPTO_TYPE_DATA) { - if (len != 0) - return KRB5_CRYPTO_INTERNAL; - len += data[i].data.length; - } - } - - sz = headersz + len; - block_sz = (sz + et->padsize - 1) &~ (et->padsize - 1); /* pad */ - - pad_sz = block_sz - sz; - trailersz += pad_sz; - - /* header */ hiv = find_iv(data, num_data, KRB5_CRYPTO_TYPE_HEADER); - if (hiv == NULL || hiv->data.length < headersz) + if (hiv == NULL || hiv->data.length != headersz) return KRB5_BAD_MSIZE; - hiv->data.length = headersz; /* trailer */ + trailersz = CHECKSUMSIZE(et->keyed_checksum); tiv = find_iv(data, num_data, KRB5_CRYPTO_TYPE_TRAILER); - if (tiv == NULL || tiv->data.length < trailersz) + if (tiv->data.length != trailersz) return KRB5_BAD_MSIZE; - tiv->data.length = trailersz; - - div = find_iv(data, num_data, KRB5_CRYPTO_TYPE_DATA); - if (div == NULL) - return KRB5_CRYPTO_INTERNAL; - /* XXX replace with EVP_Cipher */ + /* Find length of data we will decrypt */ - for (len = 0, i = 0; i < num_data; i++) { - if (data[i].flags != KRB5_CRYPTO_TYPE_HEADER && - data[i].flags != KRB5_CRYPTO_TYPE_DATA) + len = headersz; + for (i = 0; i < num_data; i++) { + if (data[i].flags != KRB5_CRYPTO_TYPE_DATA) continue; len += data[i].data.length; } + if ((len % et->padsize) != 0) { + krb5_clear_error_message(context); + return KRB5_BAD_MSIZE; + } + + /* XXX replace with EVP_Cipher */ + p = q = malloc(len); if (p == NULL) return ENOMEM; memcpy(q, hiv->data.data, hiv->data.length); q += hiv->data.length; - memcpy(q, div->data.data, div->data.length); + + for (i = 0; i < num_data; i++) { + if (data[i].flags != KRB5_CRYPTO_TYPE_DATA) + continue; + memcpy(q, data[i].data.data, data[i].data.length); + q += data[i].data.length; + } ret = _get_derived_key(context, crypto, ENCRYPTION_USAGE(usage), &dkey); if(ret) { @@ -3460,20 +3453,26 @@ krb5_decrypt_iov_ivec(krb5_context context, /* copy data back to buffers */ memcpy(hiv->data.data, p, hiv->data.length); - memcpy(div->data.data, p + hiv->data.length, len - hiv->data.length); + q = p + hiv->data.length; + for (i = 0; i < num_data; i++) { + if (data[i].flags != KRB5_CRYPTO_TYPE_DATA) + continue; + memcpy(data[i].data.data, q, data[i].data.length); + q += data[i].data.length; + } + free(p); /* check signature */ - - len = hiv->data.length; for (i = 0; i < num_data; i++) { - if (data[i].flags != KRB5_CRYPTO_TYPE_DATA && - data[i].flags != KRB5_CRYPTO_TYPE_SIGN_ONLY) + if (data[i].flags != KRB5_CRYPTO_TYPE_SIGN_ONLY) continue; len += data[i].data.length; } p = q = malloc(len); + if (p == NULL) + return ENOMEM; memcpy(q, hiv->data.data, hiv->data.length); q += hiv->data.length; @@ -3582,33 +3581,145 @@ krb5_create_checksum_iov(krb5_context context, return 0; } +/** + * Verify a Kerberos message checksum. + * + * @param context Kerberos context + * @param crypto Kerberos crypto context + * @param usage Key usage for this buffer + * @param data array of buffers to process + * @param num_data length of array + * + * @return Return an error code or 0. + * @ingroup krb5_crypto + */ + +krb5_error_code KRB5_LIB_FUNCTION +krb5_verify_checksum_iov(krb5_context context, + krb5_crypto crypto, + unsigned usage, + krb5_crypto_iov *data, + unsigned int num_data, + krb5_cksumtype *type) +{ + struct encryption_type *et = crypto->et; + Checksum cksum; + krb5_crypto_iov *civ; + krb5_error_code ret; + int i; + size_t len; + char *p, *q; + + if (num_data < 0) { + krb5_clear_error_message(context); + return KRB5_CRYPTO_INTERNAL; + } + + if(!derived_crypto(context, crypto)) { + krb5_clear_error_message(context); + return KRB5_CRYPTO_INTERNAL; + } + + civ = find_iv(data, num_data, KRB5_CRYPTO_TYPE_CHECKSUM); + if (civ == NULL) + return KRB5_BAD_MSIZE; + + len = 0; + for (i = 0; i < num_data; i++) { + if (data[i].flags != KRB5_CRYPTO_TYPE_DATA && + data[i].flags != KRB5_CRYPTO_TYPE_SIGN_ONLY) + continue; + len += data[i].data.length; + } + + p = q = malloc(len); + + for (i = 0; i < num_data; i++) { + if (data[i].flags != KRB5_CRYPTO_TYPE_DATA && + data[i].flags != KRB5_CRYPTO_TYPE_SIGN_ONLY) + continue; + memcpy(q, data[i].data.data, data[i].data.length); + q += data[i].data.length; + } + + cksum.cksumtype = CHECKSUMTYPE(et->keyed_checksum); + cksum.checksum.length = civ->data.length; + cksum.checksum.data = civ->data.data; + + ret = krb5_verify_checksum(context, crypto, usage, p, len, &cksum); + free(p); + + if (ret == 0 && type) + *type = cksum.cksumtype; + + return ret; +} + -size_t KRB5_LIB_FUNCTION +krb5_error_code KRB5_LIB_FUNCTION krb5_crypto_length(krb5_context context, krb5_crypto crypto, - int type) + int type, + size_t *len) { - if (!derived_crypto(context, crypto)) - return (size_t)-1; + if (!derived_crypto(context, crypto)) { + krb5_set_error_message(context, EINVAL, "not a derived crypto"); + return EINVAL; + } + switch(type) { case KRB5_CRYPTO_TYPE_EMPTY: + *len = 0; return 0; case KRB5_CRYPTO_TYPE_HEADER: - return crypto->et->blocksize; + *len = crypto->et->blocksize; + return 0; + case KRB5_CRYPTO_TYPE_DATA: + case KRB5_CRYPTO_TYPE_SIGN_ONLY: + /* len must already been filled in */ + return 0; case KRB5_CRYPTO_TYPE_PADDING: if (crypto->et->padsize > 1) - return crypto->et->padsize; + *len = crypto->et->padsize; + else + *len = 0; return 0; case KRB5_CRYPTO_TYPE_TRAILER: - return CHECKSUMSIZE(crypto->et->keyed_checksum); + *len = CHECKSUMSIZE(crypto->et->keyed_checksum); + return 0; case KRB5_CRYPTO_TYPE_CHECKSUM: if (crypto->et->keyed_checksum) - return CHECKSUMSIZE(crypto->et->keyed_checksum); - return CHECKSUMSIZE(crypto->et->checksum); + *len = CHECKSUMSIZE(crypto->et->keyed_checksum); + else + *len = CHECKSUMSIZE(crypto->et->checksum); + return 0; + } + krb5_set_error_message(context, EINVAL, + "%d not a supported type", type); + return EINVAL; +} + + +krb5_error_code KRB5_LIB_FUNCTION +krb5_crypto_length_iov(krb5_context context, + krb5_crypto crypto, + krb5_crypto_iov *data, + unsigned int num_data) +{ + krb5_error_code ret; + int i; + + for (i = 0; i < num_data; i++) { + ret = krb5_crypto_length(context, crypto, + data[i].flags, + &data[i].data.length); + if (ret) + return ret; } - return (size_t)-1; + return 0; } + krb5_error_code KRB5_LIB_FUNCTION krb5_encrypt_ivec(krb5_context context, krb5_crypto crypto, diff --git a/lib/krb5/version-script.map b/lib/krb5/version-script.map index 6b34e754f..5cc48fc66 100644 --- a/lib/krb5/version-script.map +++ b/lib/krb5/version-script.map @@ -185,6 +185,7 @@ HEIMDAL_KRB5_2.0 { krb5_crypto_prf; krb5_crypto_prf_length; krb5_crypto_length; + krb5_crypto_length_iov; krb5_decrypt_iov_ivec; krb5_encrypt_iov_ivec; krb5_data_alloc; @@ -641,6 +642,7 @@ HEIMDAL_KRB5_2.0 { krb5_verify_ap_req; krb5_verify_authenticator_checksum; krb5_verify_checksum; + krb5_verify_checksum_iov; krb5_verify_init_creds; krb5_verify_init_creds_opt_init; krb5_verify_init_creds_opt_set_ap_req_nofail; diff --git a/tests/gss/check-context.in b/tests/gss/check-context.in index cb52b3001..b691b9572 100644 --- a/tests/gss/check-context.in +++ b/tests/gss/check-context.in @@ -175,30 +175,35 @@ ${context} --no-dns-canon --name-type=krb5-principal-name host/lucid || \ echo "======test context building" for mech in krb5 spnego ; do + iov="" + if [ "$mech" == "krb5" ] ; then + iov="--iov" + fi + echo "${mech} no-mutual" ${context} --mech-type=${mech} \ - --wrapunwrap \ + --wrapunwrap ${iov} \ --name-type=hostbased-service host@lucid.test.h5l.se || \ { exitcode=1 ; echo "test failed"; } echo "${mech} mutual" ${context} --mech-type=${mech} \ --mutual \ - --wrapunwrap \ + --wrapunwrap ${iov} \ --name-type=hostbased-service host@lucid.test.h5l.se || \ { exitcode=1 ; echo "test failed"; } echo "${mech} delegate" ${context} --mech-type=${mech} \ --delegate \ - --wrapunwrap \ + --wrapunwrap ${iov} \ --name-type=hostbased-service host@lucid.test.h5l.se || \ { exitcode=1 ; echo "test failed"; } echo "${mech} mutual delegate" ${context} --mech-type=${mech} \ --mutual --delegate \ - --wrapunwrap \ + --wrapunwrap ${iov} \ --name-type=hostbased-service host@lucid.test.h5l.se || \ { exitcode=1 ; echo "test failed"; } done @@ -206,13 +211,17 @@ done #add spnego ! echo "======dce-style" for mech in krb5 ; do + iov="" + if [ "$mech" == "krb5" ] ; then + iov="--iov" + fi echo "${mech}: dce-style" ${context} \ --mech-type=${mech} \ --mutual \ --dce-style \ - --wrapunwrap \ + --wrapunwrap ${iov} \ --name-type=hostbased-service host@lucid.test.h5l.se || \ { exitcode=1 ; echo "test failed"; } -- 2.11.4.GIT