From 7f6d448621d6b697ac016f1b7cd4bf3eabdac15d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Love=20H=C3=B6rnquist=20=C3=85strand?= Date: Thu, 11 Dec 2008 04:49:37 +0000 Subject: [PATCH] implement the new gss_*_iov interfaces git-svn-id: svn://svn.h5l.se/heimdal/trunk/heimdal@24055 ec53bebd-3082-4978-b11e-865c3cabbd6b --- lib/gssapi/Makefile.am | 2 + lib/gssapi/gssapi/gssapi.h | 61 +++++++ lib/gssapi/gssapi_mech.h | 33 +++- lib/gssapi/krb5/aeap.c | 259 ++++++++++++++++++++++++++++++ lib/gssapi/krb5/external.c | 5 +- lib/gssapi/mech/gss_aeap.c | 103 ++++++++++++ lib/gssapi/mech/gss_mech_switch.c | 3 + lib/krb5/crypto.c | 14 +- 8 files changed, 472 insertions(+), 8 deletions(-) create mode 100644 lib/gssapi/krb5/aeap.c create mode 100644 lib/gssapi/mech/gss_aeap.c diff --git a/lib/gssapi/Makefile.am b/lib/gssapi/Makefile.am index 9fa140a90..3cb1f2cba 100644 --- a/lib/gssapi/Makefile.am +++ b/lib/gssapi/Makefile.am @@ -22,6 +22,7 @@ krb5src = \ krb5/acquire_cred.c \ krb5/add_cred.c \ krb5/address_to_krb5addr.c \ + krb5/aeap.c \ krb5/arcfour.c \ krb5/canonicalize_name.c \ krb5/ccache_name.c \ @@ -77,6 +78,7 @@ mechsrc = \ mech/gss_acquire_cred.c \ mech/gss_add_cred.c \ mech/gss_add_oid_set_member.c \ + mech/gss_aeap.c \ mech/gss_buffer_set.c \ mech/gss_canonicalize_name.c \ mech/gss_compare_name.c \ diff --git a/lib/gssapi/gssapi/gssapi.h b/lib/gssapi/gssapi/gssapi.h index f8b599a66..671ce457f 100644 --- a/lib/gssapi/gssapi/gssapi.h +++ b/lib/gssapi/gssapi/gssapi.h @@ -102,6 +102,12 @@ typedef struct gss_buffer_set_desc_struct { gss_buffer_desc *elements; } gss_buffer_set_desc, *gss_buffer_set_t; +typedef struct gss_iov_buffer_desc_struct { + OM_uint32 type; + OM_uint32 flags; + gss_buffer_desc buffer; +} gss_iov_buffer_desc, *gss_iov_buffer_t; + /* * For now, define a QOP-type as an OM_uint32 */ @@ -178,6 +184,7 @@ typedef OM_uint32 gss_qop_t; #define GSS_C_NO_CREDENTIAL ((gss_cred_id_t) 0) #define GSS_C_NO_CHANNEL_BINDINGS ((gss_channel_bindings_t) 0) #define GSS_C_EMPTY_BUFFER {0, NULL} +#define GSS_C_NO_IOV_BUFFER ((gss_iov_buffer_t)0) /* * Some alternate names for a couple of the above @@ -206,6 +213,26 @@ typedef OM_uint32 gss_qop_t; */ #define GSS_C_INDEFINITE 0xfffffffful +/* + * Type of gss_wrap_iov()/gss_unwrap_iov(). + */ + +#define GSS_IOV_BUFFER_TYPE_EMPTY 0 +#define GSS_IOV_BUFFER_TYPE_DATA 1 +#define GSS_IOV_BUFFER_TYPE_HEADER 2 +#define GSS_IOV_BUFFER_TYPE_TRAILER 7 +#define GSS_IOV_BUFFER_TYPE_PADDING 9 +#define GSS_IOV_BUFFER_TYPE_STREAM 10 + +/* + * Flags of gss_wrap_iov()/gss_unwrap_iov(). + */ + +#define GSS_IOV_BUFFER_FLAG_ALLOCATE 1 +#define GSS_IOV_BUFFER_FLAG_ALLOCATED 2 +#define GSS_IOV_BUFFER_FLAG_SIGN_ONLY 4 + + #ifdef __cplusplus extern "C" { #endif @@ -743,6 +770,40 @@ 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 */, + size_t /* iov_count */, + gss_iov_buffer_desc * /*iov */); + +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 */, + size_t /* iov_count */, + gss_iov_buffer_desc * /* iov */); + +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 */, + size_t /* iov_count */, + gss_iov_buffer_desc * /* iov */); + +OM_uint32 GSSAPI_LIB_FUNCTION +gss_release_iov_buffer(OM_uint32 * /* minor_status */, + size_t /* iov_count */, + gss_iov_buffer_desc * /* iov */); + /* * The following routines are obsolete variants of gss_get_mic, * gss_verify_mic, gss_wrap and gss_unwrap. They should be diff --git a/lib/gssapi/gssapi_mech.h b/lib/gssapi/gssapi_mech.h index b360de13f..8680aa21a 100644 --- a/lib/gssapi/gssapi_mech.h +++ b/lib/gssapi/gssapi_mech.h @@ -307,7 +307,34 @@ typedef OM_uint32 _gss_pseudo_random( gss_buffer_t prf_out ); -#define GMI_VERSION 1 +typedef OM_uint32 +_gss_wrap_iov_t(OM_uint32 *minor_status, + gss_ctx_id_t context_handle, + int conf_req_flag, + gss_qop_t qop_req, + int * conf_state, + size_t iov_count, + gss_iov_buffer_desc *iov); + +typedef OM_uint32 +_gss_unwrap_iov_t(OM_uint32 *minor_status, + gss_ctx_id_t context_handle, + int *conf_state, + gss_qop_t *qop_state, + size_t iov_count, + gss_iov_buffer_desc *iov); + +typedef OM_uint32 +_gss_wrap_iov_length_t(OM_uint32 * minor_status, + gss_ctx_id_t context_handle, + int conf_req_flag, + gss_qop_t qop_req, + size_t iov_count, + gss_iov_buffer_desc *iov); + + + +#define GMI_VERSION 2 typedef struct gssapi_mech_interface_desc { unsigned gm_version; @@ -347,6 +374,10 @@ typedef struct gssapi_mech_interface_desc { _gss_set_sec_context_option *gm_set_sec_context_option; _gss_set_cred_option *gm_set_cred_option; _gss_pseudo_random *gm_pseudo_random; + _gss_wrap_iov_t *gm_wrap_iov; + _gss_unwrap_iov_t *gm_unwrap_iov; + _gss_wrap_iov_length_t *gm_wrap_iov_length; + } gssapi_mech_interface_desc, *gssapi_mech_interface; gssapi_mech_interface diff --git a/lib/gssapi/krb5/aeap.c b/lib/gssapi/krb5/aeap.c new file mode 100644 index 000000000..e2d8a7353 --- /dev/null +++ b/lib/gssapi/krb5/aeap.c @@ -0,0 +1,259 @@ +/* + * Copyright (c) 2008 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "krb5/gsskrb5_locl.h" + +#include + +static OM_uint32 +iov_allocate(OM_uint32 *minor_status, gss_iov_buffer_desc *iov, size_t iov_count) +{ + unsigned int i; + + for (i = 0; i < iov_count; i++) { + if (iov[i].flags & GSS_IOV_BUFFER_FLAG_ALLOCATE) { + void *ptr = malloc(iov[i].buffer.length); + if (ptr == NULL) + abort(); + memcpy(ptr, iov[i].buffer.value, iov[i].buffer.length); + iov[i].buffer.value = ptr; + iov[i].flags |= GSS_IOV_BUFFER_FLAG_ALLOCATED; + } + } + return GSS_S_COMPLETE; +} + +static OM_uint32 +iov_map(OM_uint32 *minor_status, size_t iov_count, + const gss_iov_buffer_desc *iov, + krb5_crypto_iov *data) +{ + unsigned int i; + + for (i = 0; i < iov_count; i++) { + switch(iov[i].type) { + case GSS_IOV_BUFFER_TYPE_EMPTY: + data[i].flags = KRB5_CRYPTO_TYPE_EMPTY; + break; + case GSS_IOV_BUFFER_TYPE_DATA: + if (iov[i].flags & GSS_IOV_BUFFER_FLAG_SIGN_ONLY) + data[i].flags = KRB5_CRYPTO_TYPE_SIGN_ONLY; + else + data[i].flags = KRB5_CRYPTO_TYPE_DATA; + break; + case GSS_IOV_BUFFER_TYPE_HEADER: + data[i].flags = KRB5_CRYPTO_TYPE_HEADER; + break; + case GSS_IOV_BUFFER_TYPE_TRAILER: + data[i].flags = KRB5_CRYPTO_TYPE_TRAILER; + break; + case GSS_IOV_BUFFER_TYPE_PADDING: + data[i].flags = KRB5_CRYPTO_TYPE_PADDING; + break; + case GSS_IOV_BUFFER_TYPE_STREAM: + abort(); + break; + default: + *minor_status = EINVAL; + return GSS_S_FAILURE; + } + data[i].data.data = iov[i].buffer.value; + data[i].data.length = iov[i].buffer.length; + } + return GSS_S_COMPLETE; +} + +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, + size_t iov_count, + gss_iov_buffer_desc *iov) +{ + gsskrb5_ctx ctx = (gsskrb5_ctx) context_handle; + krb5_crypto crypto = NULL; + krb5_context context; + OM_uint32 major_status, junk; + krb5_crypto_iov *data; + unsigned usage; + + GSSAPI_KRB5_INIT (&context); + + major_status = iov_allocate(minor_status, iov, iov_count); + if (major_status != GSS_S_COMPLETE) + return major_status; + + data = calloc(iov_count, sizeof(data[0])); + if (data == NULL) { + gss_release_iov_buffer(&junk, iov_count, iov); + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + + major_status = iov_map(minor_status, iov_count, iov, data); + if (major_status != GSS_S_COMPLETE) { + gss_release_iov_buffer(&junk, iov_count, iov); + free(data); + return major_status; + } + + if (ctx->more_flags & LOCAL) { + usage = KRB5_KU_USAGE_ACCEPTOR_SIGN; + } else { + usage = KRB5_KU_USAGE_INITIATOR_SIGN; + } + + *minor_status = krb5_encrypt_iov_ivec(context, crypto, usage, + data, iov_count, NULL); + free(data); + if (major_status != GSS_S_COMPLETE) { + gss_release_iov_buffer(&junk, iov_count, iov); + return major_status; + } + + *minor_status = 0; + return GSS_S_COMPLETE; +} + +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, + size_t iov_count, + gss_iov_buffer_desc *iov) +{ + gsskrb5_ctx ctx = (gsskrb5_ctx) context_handle; + krb5_crypto crypto = NULL; + krb5_context context; + OM_uint32 major_status, junk; + krb5_crypto_iov *data; + unsigned usage; + + GSSAPI_KRB5_INIT (&context); + + major_status = iov_allocate(minor_status, iov, iov_count); + if (major_status != GSS_S_COMPLETE) + return major_status; + + data = calloc(iov_count, sizeof(data[0])); + if (data == NULL) { + gss_release_iov_buffer(&junk, iov_count, iov); + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + + major_status = iov_map(minor_status, iov_count, iov, data); + if (major_status != GSS_S_COMPLETE) { + gss_release_iov_buffer(&junk, iov_count, iov); + free(data); + return major_status; + } + + if (ctx->more_flags & LOCAL) { + usage = KRB5_KU_USAGE_INITIATOR_SIGN; + } else { + usage = KRB5_KU_USAGE_ACCEPTOR_SIGN; + } + + *minor_status = krb5_decrypt_iov_ivec(context, crypto, usage, + data, iov_count, NULL); + free(data); + if (major_status != GSS_S_COMPLETE) { + gss_release_iov_buffer(&junk, iov_count, iov); + return major_status; + } + + *minor_status = 0; + 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, + size_t iov_count, + gss_iov_buffer_desc *iov) +{ + krb5_context context; + krb5_crypto crypto = NULL; + unsigned int i; + size_t size; + size_t *padding = NULL; + + GSSAPI_KRB5_INIT (&context); + *minor_status = 0; + + for (size = 0, i = 0; i < iov_count; i++) { + switch(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: + size += krb5_crypto_length(context, crypto, KRB5_CRYPTO_TYPE_HEADER); + break; + case GSS_IOV_BUFFER_TYPE_TRAILER: + size += krb5_crypto_length(context, crypto, KRB5_CRYPTO_TYPE_TRAILER); + 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_STREAM: + size += iov[i].buffer.length; + break; + default: + *minor_status = EINVAL; + return GSS_S_FAILURE; + } + } + if (padding) { + size_t pad = krb5_crypto_length(context, crypto, KRB5_CRYPTO_TYPE_PADDING); + if (pad > 1) { + *padding = pad - (size % pad); + if (*padding == pad) + *padding = 0; + } else + *padding = 0; + } + + return GSS_S_COMPLETE; +} diff --git a/lib/gssapi/krb5/external.c b/lib/gssapi/krb5/external.c index 4efa61fd7..6a5fa9b61 100644 --- a/lib/gssapi/krb5/external.c +++ b/lib/gssapi/krb5/external.c @@ -469,7 +469,10 @@ static gssapi_mech_interface_desc krb5_mech = { _gsskrb5_inquire_cred_by_oid, _gsskrb5_set_sec_context_option, _gsskrb5_set_cred_option, - _gsskrb5_pseudo_random + _gsskrb5_pseudo_random, + _gk_wrap_iov, + _gk_unwrap_iov, + _gk_wrap_iov_length }; gssapi_mech_interface diff --git a/lib/gssapi/mech/gss_aeap.c b/lib/gssapi/mech/gss_aeap.c new file mode 100644 index 000000000..0887ebbee --- /dev/null +++ b/lib/gssapi/mech/gss_aeap.c @@ -0,0 +1,103 @@ +/* + * AEAD support + */ + +#include "mech_locl.h" +RCSID("$Id$"); + +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, + size_t iov_count, + gss_iov_buffer_desc *iov) +{ + struct _gss_context *ctx = (struct _gss_context *) context_handle; + gssapi_mech_interface m = ctx->gc_mech; + + if (conf_state) + *conf_state = 0; + if (ctx == NULL) { + *minor_status = 0; + return GSS_S_NO_CONTEXT; + } + if (m->gm_wrap_iov == NULL) { + *minor_status = 0; + return GSS_S_UNAVAILABLE; + } + + return (m->gm_wrap_iov)(minor_status, ctx->gc_ctx, + conf_req_flag, qop_req, conf_state, iov_count, iov); +} + +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, + size_t iov_count, + gss_iov_buffer_desc *iov) +{ + struct _gss_context *ctx = (struct _gss_context *) context_handle; + gssapi_mech_interface m = ctx->gc_mech; + + if (conf_state) + *conf_state = 0; + if (qop_state) + *qop_state = 0; + if (ctx == NULL) { + *minor_status = 0; + return GSS_S_NO_CONTEXT; + } + if (m->gm_unwrap_iov == NULL) { + *minor_status = 0; + return GSS_S_UNAVAILABLE; + } + + return (m->gm_unwrap_iov)(minor_status, ctx->gc_ctx, + conf_state, qop_state, iov_count, iov); +} + +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, + size_t iov_count, + gss_iov_buffer_desc *iov) +{ + struct _gss_context *ctx = (struct _gss_context *) context_handle; + gssapi_mech_interface m = ctx->gc_mech; + + if (ctx == NULL) { + *minor_status = 0; + return GSS_S_NO_CONTEXT; + } + if (m->gm_wrap_iov == NULL) { + *minor_status = 0; + return GSS_S_UNAVAILABLE; + } + + return (m->gm_wrap_iov_length)(minor_status, ctx->gc_ctx, + conf_req_flag, qop_req, iov_count, iov); +} + +OM_uint32 GSSAPI_LIB_FUNCTION +gss_release_iov_buffer(OM_uint32 *minor_status, + size_t iov_count, + gss_iov_buffer_desc *iov) +{ + OM_uint32 junk; + size_t i; + + for (i = 0; i < iov_count; i++) { + if ((iov[i].flags & GSS_IOV_BUFFER_FLAG_ALLOCATED) == 0) + continue; + gss_release_buffer(&junk, &iov[i].buffer); + } + *minor_status = 0; + return GSS_S_COMPLETE; +} + diff --git a/lib/gssapi/mech/gss_mech_switch.c b/lib/gssapi/mech/gss_mech_switch.c index 0ba521286..17bf1c325 100644 --- a/lib/gssapi/mech/gss_mech_switch.c +++ b/lib/gssapi/mech/gss_mech_switch.c @@ -317,6 +317,9 @@ _gss_load_mech(void) OPTSYM(set_sec_context_option); OPTSYM(set_cred_option); OPTSYM(pseudo_random); + OPTSYM(wrap_iov); + OPTSYM(unwrap_iov); + OPTSYM(wrap_iov_length); SLIST_INSERT_HEAD(&_gss_mechs, m, gm_link); continue; diff --git a/lib/krb5/crypto.c b/lib/krb5/crypto.c index bc6512cf1..46306f0bb 100644 --- a/lib/krb5/crypto.c +++ b/lib/krb5/crypto.c @@ -3122,7 +3122,7 @@ decrypt_internal_special(krb5_context context, } static krb5_crypto_iov * -find_iv(krb5_crypto_iov *data, int num_data, int type) +find_iv(krb5_crypto_iov *data, unsigned int num_data, int type) { int i; for (i = 0; i < num_data; i++) @@ -3160,11 +3160,12 @@ krb5_encrypt_iov_ivec(krb5_context context, krb5_crypto crypto, unsigned usage, krb5_crypto_iov *data, - size_t num_data, + unsigned int num_data, void *ivec) { size_t headersz, trailersz, len; - size_t i, sz, block_sz, pad_sz; + unsigned int i; + size_t sz, block_sz, pad_sz; Checksum cksum; unsigned char *p, *q; krb5_error_code ret; @@ -3360,11 +3361,12 @@ krb5_decrypt_iov_ivec(krb5_context context, krb5_crypto crypto, unsigned usage, krb5_crypto_iov *data, - size_t num_data, + unsigned int num_data, void *ivec) { + unsigned int i; size_t headersz, trailersz, len; - size_t i, sz, block_sz, pad_sz; + size_t sz, block_sz, pad_sz; Checksum cksum; unsigned char *p, *q; krb5_error_code ret; @@ -3517,7 +3519,7 @@ krb5_create_checksum_iov(krb5_context context, krb5_crypto crypto, unsigned usage, krb5_crypto_iov *data, - size_t num_data, + unsigned int num_data, krb5_cksumtype *type) { Checksum cksum;