diff options
author | Heimdal Import User <samba-bugs@samba.org> | 2005-07-11 01:16:55 +0000 |
---|---|---|
committer | Gerald (Jerry) Carter <jerry@samba.org> | 2007-10-10 13:19:33 -0500 |
commit | 954c01728e0c7485b72c9a5d5737e5f6bd0cf0b9 (patch) | |
tree | fc11a048c8a582e2ca66415ff04dacf74f9abf22 /source4/heimdal/lib/gssapi | |
parent | 7ead5ab06cea9f33e954a4579163262f97ea06ff (diff) | |
download | samba-954c01728e0c7485b72c9a5d5737e5f6bd0cf0b9.tar.gz samba-954c01728e0c7485b72c9a5d5737e5f6bd0cf0b9.tar.bz2 samba-954c01728e0c7485b72c9a5d5737e5f6bd0cf0b9.zip |
r8302: import mini HEIMDAL into the tree
(This used to be commit 118be28a7aef233799956615a99d1a2a74dac175)
Diffstat (limited to 'source4/heimdal/lib/gssapi')
38 files changed, 10055 insertions, 0 deletions
diff --git a/source4/heimdal/lib/gssapi/8003.c b/source4/heimdal/lib/gssapi/8003.c new file mode 100644 index 0000000000..b60d2608e2 --- /dev/null +++ b/source4/heimdal/lib/gssapi/8003.c @@ -0,0 +1,246 @@ +/* + * Copyright (c) 1997 - 2003 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 "gssapi_locl.h" + +RCSID("$Id: 8003.c,v 1.17 2005/04/01 08:55:36 lha Exp $"); + +krb5_error_code +gssapi_encode_om_uint32(OM_uint32 n, u_char *p) +{ + p[0] = (n >> 0) & 0xFF; + p[1] = (n >> 8) & 0xFF; + p[2] = (n >> 16) & 0xFF; + p[3] = (n >> 24) & 0xFF; + return 0; +} + +krb5_error_code +gssapi_encode_be_om_uint32(OM_uint32 n, u_char *p) +{ + p[0] = (n >> 24) & 0xFF; + p[1] = (n >> 16) & 0xFF; + p[2] = (n >> 8) & 0xFF; + p[3] = (n >> 0) & 0xFF; + return 0; +} + +krb5_error_code +gssapi_decode_om_uint32(u_char *p, OM_uint32 *n) +{ + *n = (p[0] << 0) | (p[1] << 8) | (p[2] << 16) | (p[3] << 24); + return 0; +} + +krb5_error_code +gssapi_decode_be_om_uint32(u_char *p, OM_uint32 *n) +{ + *n = (p[0] <<24) | (p[1] << 16) | (p[2] << 8) | (p[3] << 0); + return 0; +} + +static krb5_error_code +hash_input_chan_bindings (const gss_channel_bindings_t b, + u_char *p) +{ + u_char num[4]; + MD5_CTX md5; + + MD5_Init(&md5); + gssapi_encode_om_uint32 (b->initiator_addrtype, num); + MD5_Update (&md5, num, sizeof(num)); + gssapi_encode_om_uint32 (b->initiator_address.length, num); + MD5_Update (&md5, num, sizeof(num)); + if (b->initiator_address.length) + MD5_Update (&md5, + b->initiator_address.value, + b->initiator_address.length); + gssapi_encode_om_uint32 (b->acceptor_addrtype, num); + MD5_Update (&md5, num, sizeof(num)); + gssapi_encode_om_uint32 (b->acceptor_address.length, num); + MD5_Update (&md5, num, sizeof(num)); + if (b->acceptor_address.length) + MD5_Update (&md5, + b->acceptor_address.value, + b->acceptor_address.length); + gssapi_encode_om_uint32 (b->application_data.length, num); + MD5_Update (&md5, num, sizeof(num)); + if (b->application_data.length) + MD5_Update (&md5, + b->application_data.value, + b->application_data.length); + MD5_Final (p, &md5); + return 0; +} + +/* + * create a checksum over the chanel bindings in + * `input_chan_bindings', `flags' and `fwd_data' and return it in + * `result' + */ + +OM_uint32 +gssapi_krb5_create_8003_checksum ( + OM_uint32 *minor_status, + const gss_channel_bindings_t input_chan_bindings, + OM_uint32 flags, + const krb5_data *fwd_data, + Checksum *result) +{ + u_char *p; + + /* + * see rfc1964 (section 1.1.1 (Initial Token), and the checksum value + * field's format) */ + result->cksumtype = CKSUMTYPE_GSSAPI; + if (fwd_data->length > 0 && (flags & GSS_C_DELEG_FLAG)) + result->checksum.length = 24 + 4 + fwd_data->length; + else + result->checksum.length = 24; + result->checksum.data = malloc (result->checksum.length); + if (result->checksum.data == NULL) { + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + + p = result->checksum.data; + gssapi_encode_om_uint32 (16, p); + p += 4; + if (input_chan_bindings == GSS_C_NO_CHANNEL_BINDINGS) { + memset (p, 0, 16); + } else { + hash_input_chan_bindings (input_chan_bindings, p); + } + p += 16; + gssapi_encode_om_uint32 (flags, p); + p += 4; + + if (fwd_data->length > 0 && (flags & GSS_C_DELEG_FLAG)) { + + *p++ = (1 >> 0) & 0xFF; /* DlgOpt */ /* == 1 */ + *p++ = (1 >> 8) & 0xFF; /* DlgOpt */ /* == 0 */ + *p++ = (fwd_data->length >> 0) & 0xFF; /* Dlgth */ + *p++ = (fwd_data->length >> 8) & 0xFF; /* Dlgth */ + memcpy(p, (unsigned char *) fwd_data->data, fwd_data->length); + + p += fwd_data->length; + } + + return GSS_S_COMPLETE; +} + +/* + * verify the checksum in `cksum' over `input_chan_bindings' + * returning `flags' and `fwd_data' + */ + +OM_uint32 +gssapi_krb5_verify_8003_checksum( + OM_uint32 *minor_status, + const gss_channel_bindings_t input_chan_bindings, + const Checksum *cksum, + OM_uint32 *flags, + krb5_data *fwd_data) +{ + unsigned char hash[16]; + unsigned char *p; + OM_uint32 length; + int DlgOpt; + static unsigned char zeros[16]; + + if (cksum == NULL) { + *minor_status = 0; + return GSS_S_BAD_BINDINGS; + } + + /* XXX should handle checksums > 24 bytes */ + if(cksum->cksumtype != CKSUMTYPE_GSSAPI || cksum->checksum.length < 24) { + *minor_status = 0; + return GSS_S_BAD_BINDINGS; + } + + p = cksum->checksum.data; + gssapi_decode_om_uint32(p, &length); + if(length != sizeof(hash)) { + *minor_status = 0; + return GSS_S_BAD_BINDINGS; + } + + p += 4; + + if (input_chan_bindings != GSS_C_NO_CHANNEL_BINDINGS + && memcmp(p, zeros, sizeof(zeros)) != 0) { + if(hash_input_chan_bindings(input_chan_bindings, hash) != 0) { + *minor_status = 0; + return GSS_S_BAD_BINDINGS; + } + if(memcmp(hash, p, sizeof(hash)) != 0) { + *minor_status = 0; + return GSS_S_BAD_BINDINGS; + } + } + + p += sizeof(hash); + + gssapi_decode_om_uint32(p, flags); + p += 4; + + if (cksum->checksum.length > 24 && (*flags & GSS_C_DELEG_FLAG)) { + if(cksum->checksum.length < 28) { + *minor_status = 0; + return GSS_S_BAD_BINDINGS; + } + + DlgOpt = (p[0] << 0) | (p[1] << 8); + p += 2; + if (DlgOpt != 1) { + *minor_status = 0; + return GSS_S_BAD_BINDINGS; + } + + fwd_data->length = (p[0] << 0) | (p[1] << 8); + p += 2; + if(cksum->checksum.length < 28 + fwd_data->length) { + *minor_status = 0; + return GSS_S_BAD_BINDINGS; + } + fwd_data->data = malloc(fwd_data->length); + if (fwd_data->data == NULL) { + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + memcpy(fwd_data->data, p, fwd_data->length); + } + + return GSS_S_COMPLETE; +} diff --git a/source4/heimdal/lib/gssapi/accept_sec_context.c b/source4/heimdal/lib/gssapi/accept_sec_context.c new file mode 100644 index 0000000000..6672f3fc67 --- /dev/null +++ b/source4/heimdal/lib/gssapi/accept_sec_context.c @@ -0,0 +1,1118 @@ +/* + * Copyright (c) 1997 - 2003 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 "gssapi_locl.h" + +RCSID("$Id: accept_sec_context.c,v 1.53 2005/05/29 15:12:41 lha Exp $"); + +HEIMDAL_MUTEX gssapi_keytab_mutex = HEIMDAL_MUTEX_INITIALIZER; +krb5_keytab gssapi_krb5_keytab; + +OM_uint32 +gsskrb5_register_acceptor_identity (const char *identity) +{ + krb5_error_code ret; + + ret = gssapi_krb5_init(); + if(ret) + return GSS_S_FAILURE; + + HEIMDAL_MUTEX_lock(&gssapi_keytab_mutex); + + if(gssapi_krb5_keytab != NULL) { + krb5_kt_close(gssapi_krb5_context, gssapi_krb5_keytab); + gssapi_krb5_keytab = NULL; + } + if (identity == NULL) { + ret = krb5_kt_default(gssapi_krb5_context, &gssapi_krb5_keytab); + } else { + char *p; + + asprintf(&p, "FILE:%s", identity); + if(p == NULL) { + HEIMDAL_MUTEX_unlock(&gssapi_keytab_mutex); + return GSS_S_FAILURE; + } + ret = krb5_kt_resolve(gssapi_krb5_context, p, &gssapi_krb5_keytab); + free(p); + } + HEIMDAL_MUTEX_unlock(&gssapi_keytab_mutex); + if(ret) + return GSS_S_FAILURE; + return GSS_S_COMPLETE; +} + +void +gsskrb5_is_cfx(gss_ctx_id_t context_handle, int *is_cfx) +{ + krb5_keyblock *key; + int acceptor = (context_handle->more_flags & LOCAL) == 0; + + if (acceptor) { + if (context_handle->auth_context->local_subkey) + key = context_handle->auth_context->local_subkey; + else + key = context_handle->auth_context->remote_subkey; + } else { + if (context_handle->auth_context->remote_subkey) + key = context_handle->auth_context->remote_subkey; + else + key = context_handle->auth_context->local_subkey; + } + if (key == NULL) + key = context_handle->auth_context->keyblock; + + if (key == NULL) + return; + + switch (key->keytype) { + case ETYPE_DES_CBC_CRC: + case ETYPE_DES_CBC_MD4: + case ETYPE_DES_CBC_MD5: + case ETYPE_DES3_CBC_MD5: + case ETYPE_DES3_CBC_SHA1: + case ETYPE_ARCFOUR_HMAC_MD5: + case ETYPE_ARCFOUR_HMAC_MD5_56: + break; + default : + *is_cfx = 1; + if ((acceptor && context_handle->auth_context->local_subkey) || + (!acceptor && context_handle->auth_context->remote_subkey)) + context_handle->more_flags |= ACCEPTOR_SUBKEY; + break; + } +} + + +static OM_uint32 +gsskrb5_accept_delegated_token + (OM_uint32 * minor_status, + gss_ctx_id_t * context_handle, + gss_cred_id_t * delegated_cred_handle) +{ + krb5_data *fwd_data = &(*context_handle)->fwd_data; + OM_uint32 *flags = &(*context_handle)->flags; + krb5_principal principal = (*context_handle)->source; + krb5_ccache ccache = NULL; + krb5_error_code kret; + int32_t ac_flags, ret; + gss_cred_id_t handle = NULL; + + if (delegated_cred_handle == NULL) { + /* XXX Create a new delegated_cred_handle? */ + + ret = 0; + + kret = krb5_cc_default (gssapi_krb5_context, &ccache); + if (kret) { + *flags &= ~GSS_C_DELEG_FLAG; + goto end_fwd; + } + } else { + + *delegated_cred_handle = NULL; + + handle = calloc(1, sizeof(*handle)); + if (handle == NULL) { + ret = GSS_S_FAILURE; + *minor_status = ENOMEM; + krb5_set_error_string(gssapi_krb5_context, "out of memory"); + gssapi_krb5_set_error_string(); + *flags &= ~GSS_C_DELEG_FLAG; + goto end_fwd; + } + if ((ret = gss_duplicate_name(minor_status, principal, + &handle->principal)) != 0) { + *flags &= ~GSS_C_DELEG_FLAG; + ret = 0; + goto end_fwd; + } + kret = krb5_cc_gen_new (gssapi_krb5_context, + &krb5_mcc_ops, + &handle->ccache); + if (kret) { + *flags &= ~GSS_C_DELEG_FLAG; + ret = 0; + goto end_fwd; + } + ccache = handle->ccache; + + ret = gss_create_empty_oid_set(minor_status, &handle->mechanisms); + if (ret) { + *flags &= ~GSS_C_DELEG_FLAG; + goto end_fwd; + } + ret = gss_add_oid_set_member(minor_status, GSS_KRB5_MECHANISM, + &handle->mechanisms); + if (ret) { + *flags &= ~GSS_C_DELEG_FLAG; + goto end_fwd; + } + } + + kret = krb5_cc_initialize(gssapi_krb5_context, ccache, principal); + if (kret) { + *flags &= ~GSS_C_DELEG_FLAG; + ret = 0; + goto end_fwd; + } + + krb5_auth_con_removeflags(gssapi_krb5_context, + (*context_handle)->auth_context, + KRB5_AUTH_CONTEXT_DO_TIME, + &ac_flags); + kret = krb5_rd_cred2(gssapi_krb5_context, + (*context_handle)->auth_context, + ccache, + fwd_data); + if (kret) + gssapi_krb5_set_error_string(); + krb5_auth_con_setflags(gssapi_krb5_context, + (*context_handle)->auth_context, + ac_flags); + if (kret) { + *flags &= ~GSS_C_DELEG_FLAG; + ret = GSS_S_FAILURE; + *minor_status = kret; + goto end_fwd; + } + end_fwd: + /* if there was some kind of failure, clean up internal structures */ + if ((*flags & GSS_C_DELEG_FLAG) == 0) { + if (handle) { + if (handle->principal) + gss_release_name(minor_status, &handle->principal); + if (handle->mechanisms) + gss_release_oid_set(NULL, &handle->mechanisms); + if (handle->ccache) + krb5_cc_destroy(gssapi_krb5_context, handle->ccache); + free(handle); + handle = NULL; + } + } + if (delegated_cred_handle == NULL) { + if (ccache) + krb5_cc_close(gssapi_krb5_context, ccache); + } + if (handle) + *delegated_cred_handle = handle; + + return ret; +} + +static OM_uint32 +gsskrb5_acceptor_ready( + OM_uint32 * minor_status, + gss_ctx_id_t * context_handle, + gss_cred_id_t * delegated_cred_handle) +{ + OM_uint32 ret; + int32_t seq_number; + int is_cfx = 0; + u_int32_t flags = (*context_handle)->flags; + + krb5_auth_getremoteseqnumber (gssapi_krb5_context, + (*context_handle)->auth_context, + &seq_number); + + gsskrb5_is_cfx(*context_handle, &is_cfx); + + ret = _gssapi_msg_order_create(minor_status, + &(*context_handle)->order, + _gssapi_msg_order_f(flags), + seq_number, 0, is_cfx); + if (ret) return ret; + + if (!(flags & GSS_C_MUTUAL_FLAG) && _gssapi_msg_order_f(flags)) { + krb5_auth_con_setlocalseqnumber(gssapi_krb5_context, + (*context_handle)->auth_context, + seq_number); + } + + /* + * We should handle the delegation ticket, in case it's there + */ + if ((*context_handle)->fwd_data.length > 0 && (flags & GSS_C_DELEG_FLAG)) { + ret = gsskrb5_accept_delegated_token(minor_status, + context_handle, + delegated_cred_handle); + if (ret) return ret; + } + + (*context_handle)->state = ACCEPTOR_READY; + (*context_handle)->more_flags |= OPEN; + + return GSS_S_COMPLETE; +} + +static OM_uint32 +gsskrb5_acceptor_start( + OM_uint32 * minor_status, + gss_ctx_id_t * context_handle, + const gss_cred_id_t acceptor_cred_handle, + const gss_buffer_t input_token, + const gss_channel_bindings_t input_chan_bindings, + gss_name_t * src_name, + gss_OID * mech_type, + gss_buffer_t output_token, + OM_uint32 * ret_flags, + OM_uint32 * time_rec, + gss_cred_id_t * delegated_cred_handle) +{ + krb5_error_code kret; + OM_uint32 ret = GSS_S_COMPLETE; + krb5_data indata; + krb5_flags ap_options; + OM_uint32 flags; + krb5_ticket *ticket = NULL; + krb5_keytab keytab = NULL; + krb5_keyblock *keyblock = NULL; + int no_wrap = 0; + + /* + * TODO: check the channel_bindings + */ + + /* + * We need a sequence number + */ + krb5_auth_con_addflags(gssapi_krb5_context, + (*context_handle)->auth_context, + KRB5_AUTH_CONTEXT_DO_SEQUENCE, + NULL); + + /* + * We need remove the decapsulate only when GSS_C_DCE_STYLE isn't in use + */ + ret = gssapi_krb5_decapsulate(minor_status, + input_token,&indata, + "\x01\x00", + GSS_KRB5_MECHANISM); + if (ret) { + /* No OID wrapping apparently available. */ + no_wrap = 1; + indata.length = input_token->length; + indata.data = input_token->value; + } + + /* + * We need to get our keytab + */ + if (acceptor_cred_handle == GSS_C_NO_CREDENTIAL) { + if (gssapi_krb5_keytab != NULL) { + keytab = gssapi_krb5_keytab; + } + } else { + keytab = acceptor_cred_handle->keytab; + } + + /* + * We need to check the ticket and create the AP-REP packet + */ + kret = krb5_rd_req_return_keyblock(gssapi_krb5_context, + &(*context_handle)->auth_context, + &indata, + (acceptor_cred_handle == GSS_C_NO_CREDENTIAL) ? NULL : acceptor_cred_handle->principal, + keytab, + &ap_options, + &ticket, + &keyblock); + if (kret) { + *minor_status = kret; + gssapi_krb5_set_error_string (); + return GSS_S_FAILURE; + } + + /* + * We need to remember some data on the context_handle + */ + (*context_handle)->ticket = ticket; + (*context_handle)->service_keyblock = keyblock; + (*context_handle)->lifetime = ticket->ticket.endtime; + + /* + * We need to copy the principal names to the context and the calling layer + */ + kret = krb5_copy_principal(gssapi_krb5_context, + ticket->client, + &(*context_handle)->source); + if (kret) { + *minor_status = kret; + gssapi_krb5_set_error_string (); + return GSS_S_FAILURE; + } + + kret = krb5_copy_principal(gssapi_krb5_context, + ticket->server, + &(*context_handle)->target); + if (kret) { + *minor_status = kret; + gssapi_krb5_set_error_string (); + return GSS_S_FAILURE; + } + + /* + * We need to setup some compat stuff, this assumes that context_handle->target is already set + */ + ret = _gss_DES3_get_mic_compat(minor_status, *context_handle); + if (ret) return ret; + + /* + * We need to get the flags out of the 8003 checksum + */ + { + krb5_authenticator authenticator; + + kret = krb5_auth_con_getauthenticator(gssapi_krb5_context, + (*context_handle)->auth_context, + &authenticator); + if (kret) { + *minor_status = kret; + gssapi_krb5_set_error_string (); + return GSS_S_FAILURE; + } + + ret = gssapi_krb5_verify_8003_checksum(minor_status, + input_chan_bindings, + authenticator->cksum, + &flags, + &(*context_handle)->fwd_data); + krb5_free_authenticator(gssapi_krb5_context, &authenticator); + if (ret) return ret; + } + + /* And remember them for later */ + (*context_handle)->flags = flags; + + if(flags & GSS_C_MUTUAL_FLAG) { + int is_cfx = 0; + krb5_data outbuf; + + gsskrb5_is_cfx(*context_handle, &is_cfx); + + if (is_cfx || (ap_options & AP_OPTS_USE_SUBKEY)) { + kret = krb5_auth_con_addflags(gssapi_krb5_context, + (*context_handle)->auth_context, + KRB5_AUTH_CONTEXT_USE_SUBKEY, + NULL); + (*context_handle)->more_flags |= ACCEPTOR_SUBKEY; + } + + kret = krb5_mk_rep(gssapi_krb5_context, + (*context_handle)->auth_context, + &outbuf); + if (kret) { + *minor_status = kret; + gssapi_krb5_set_error_string (); + return GSS_S_FAILURE; + } + + if (!(flags & GSS_C_DCE_STYLE)) { + ret = gssapi_krb5_encapsulate(minor_status, + &outbuf, + output_token, + "\x02\x00", + GSS_KRB5_MECHANISM); + krb5_data_free (&outbuf); + if (ret) return ret; + } else { + output_token->length = outbuf.length; + output_token->value = outbuf.data; + } + } + + /* + * We need to set the return value for the calling layer + */ + if (ret_flags) *ret_flags = flags; + + if (time_rec) { + ret = gssapi_lifetime_left(minor_status, + (*context_handle)->lifetime, + time_rec); + if (ret) return ret; + } + + if (src_name) { + kret = krb5_copy_principal(gssapi_krb5_context, + (*context_handle)->source, + src_name); + if (kret) { + *minor_status = kret; + gssapi_krb5_set_error_string (); + return GSS_S_FAILURE; + } + } + + /* + * When GSS_C_DCE_STYLE is in use, we need ask for a AP-REP from the client + */ + if (flags & GSS_C_DCE_STYLE) { + (*context_handle)->state = ACCEPTOR_WAIT_FOR_DCESTYLE; + return GSS_S_CONTINUE_NEEDED; + } + + return gsskrb5_acceptor_ready(minor_status, context_handle, delegated_cred_handle); +} + +static OM_uint32 +gsskrb5_acceptor_wait_for_dcestyle( + OM_uint32 * minor_status, + gss_ctx_id_t * context_handle, + const gss_cred_id_t acceptor_cred_handle, + const gss_buffer_t input_token, + const gss_channel_bindings_t input_chan_bindings, + gss_name_t * src_name, + gss_OID * mech_type, + gss_buffer_t output_token, + OM_uint32 * ret_flags, + OM_uint32 * time_rec, + gss_cred_id_t * delegated_cred_handle) +{ + OM_uint32 ret; + krb5_error_code kret; + krb5_data inbuf; + OM_uint32 r_seq_number; + OM_uint32 l_seq_number; + + /* We know it's GSS_C_DCE_STYLE so we don't need to decapsulate the AP_REP */ + inbuf.length = input_token->length; + inbuf.data = input_token->value; + + /* + * We need to remeber the old remote seq_number, then check if the client has replied with our local seq_number, + * and then reset the remote seq_number to the old value + */ + { + kret = krb5_auth_con_getlocalseqnumber(gssapi_krb5_context, + (*context_handle)->auth_context, + &l_seq_number); + if (kret) { + gssapi_krb5_set_error_string (); + *minor_status = kret; + return GSS_S_FAILURE; + } + + kret = krb5_auth_getremoteseqnumber(gssapi_krb5_context, + (*context_handle)->auth_context, + &r_seq_number); + if (kret) { + gssapi_krb5_set_error_string (); + *minor_status = kret; + return GSS_S_FAILURE; + } + + kret = krb5_auth_con_setremoteseqnumber(gssapi_krb5_context, + (*context_handle)->auth_context, + l_seq_number); + if (kret) { + gssapi_krb5_set_error_string (); + *minor_status = kret; + return GSS_S_FAILURE; + } + } + + /* We need to verify the AP_REP, but we need to flag that this + is DCE_STYLE, so don't check the timestamps this time + */ + { + krb5_ap_rep_enc_part *repl; + + kret = _krb5_rd_rep_type(gssapi_krb5_context, + (*context_handle)->auth_context, + &inbuf, + &repl, + TRUE); + if (kret) { + gssapi_krb5_set_error_string (); + *minor_status = kret; + return GSS_S_FAILURE; + } + krb5_free_ap_rep_enc_part(gssapi_krb5_context, repl); + } + + /* We need to check the liftime */ + { + OM_uint32 lifetime_rec; + + ret = gssapi_lifetime_left(minor_status, + (*context_handle)->lifetime, + &lifetime_rec); + if (ret) return ret; + + if (lifetime_rec == 0) { + return GSS_S_CONTEXT_EXPIRED; + } + + if (time_rec) *time_rec = lifetime_rec; + } + + /* We need to give the caller the flags which are in use */ + if (ret_flags) *ret_flags = (*context_handle)->flags; + + if (src_name) { + kret = krb5_copy_principal(gssapi_krb5_context, + (*context_handle)->source, + src_name); + if (kret) { + *minor_status = kret; + gssapi_krb5_set_error_string (); + return GSS_S_FAILURE; + } + } + + /* + * After the krb5_rd_rep() the remote and local seq_number should be the same, + * because the client just replies the seq_number from our AP-REP in its AP-REP, + * but then the client uses the seq_number from its AP-REQ for GSS_wrap() + */ + { + OM_uint32 tmp_r_seq_number; + OM_uint32 l_seq_number; + + kret = krb5_auth_getremoteseqnumber(gssapi_krb5_context, + (*context_handle)->auth_context, + &tmp_r_seq_number); + if (kret) { + gssapi_krb5_set_error_string (); + *minor_status = kret; + return GSS_S_FAILURE; + } + + kret = krb5_auth_con_getlocalseqnumber(gssapi_krb5_context, + (*context_handle)->auth_context, + &l_seq_number); + if (kret) { + gssapi_krb5_set_error_string (); + *minor_status = kret; + return GSS_S_FAILURE; + } + + /* + * Here we check if the client has responsed with our local seq_number, + */ + if (tmp_r_seq_number != l_seq_number) { + return GSS_S_UNSEQ_TOKEN; + } + } + + /* + * We need to reset the remote seq_number, because the client will use, + * the old one for the GSS_wrap() calls + */ + { + kret = krb5_auth_con_setremoteseqnumber(gssapi_krb5_context, + (*context_handle)->auth_context, + r_seq_number); + if (kret) { + gssapi_krb5_set_error_string (); + *minor_status = kret; + return GSS_S_FAILURE; + } + } + + return gsskrb5_acceptor_ready(minor_status, context_handle, delegated_cred_handle); +} + +static OM_uint32 +gsskrb5_accept_sec_context( + OM_uint32 * minor_status, + gss_ctx_id_t * context_handle, + const gss_cred_id_t acceptor_cred_handle, + const gss_buffer_t input_token, + const gss_channel_bindings_t input_chan_bindings, + gss_name_t * src_name, + gss_OID * actual_mech_type, + gss_buffer_t output_token, + OM_uint32 * ret_flags, + OM_uint32 * time_rec, + gss_cred_id_t * delegated_cred_handle) +{ + OM_uint32 ret; + + if (*context_handle == GSS_C_NO_CONTEXT) { + ret = _gsskrb5_create_ctx(minor_status, + context_handle, + input_chan_bindings, + ACCEPTOR_START); + if (ret) return ret; + } + + if (actual_mech_type) *actual_mech_type = GSS_KRB5_MECHANISM; + + HEIMDAL_MUTEX_lock(&(*context_handle)->ctx_id_mutex); + + switch ((*context_handle)->state) { + case ACCEPTOR_START: + ret = gsskrb5_acceptor_start(minor_status, + context_handle, + acceptor_cred_handle, + input_token, + input_chan_bindings, + src_name, + actual_mech_type, + output_token, + ret_flags, + time_rec, + delegated_cred_handle); + break; + case ACCEPTOR_WAIT_FOR_DCESTYLE: + ret = gsskrb5_acceptor_wait_for_dcestyle(minor_status, + context_handle, + acceptor_cred_handle, + input_token, + input_chan_bindings, + src_name, + actual_mech_type, + output_token, + ret_flags, + time_rec, + delegated_cred_handle); + break; + case ACCEPTOR_READY: + /* this function should not be called after it has returned GSS_S_COMPLETE */ + ret = GSS_S_BAD_STATUS; + break; + default: + /* TODO: is this correct here? --metze */ + ret = GSS_S_BAD_STATUS; + break; + } + + HEIMDAL_MUTEX_unlock(&(*context_handle)->ctx_id_mutex); + + return ret; +} + +static OM_uint32 +code_NegTokenArg(OM_uint32 *minor_status, + const NegTokenTarg *targ, + krb5_data *data, + u_char **ret_buf) +{ + OM_uint32 ret; + u_char *buf; + size_t buf_size, buf_len; + + buf_size = 1024; + buf = malloc(buf_size); + if (buf == NULL) { + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + + do { + ret = encode_NegTokenTarg(buf + buf_size - 1, + buf_size, + targ, &buf_len); + if (ret == 0) { + size_t tmp; + + ret = der_put_length_and_tag(buf + buf_size - buf_len - 1, + buf_size - buf_len, + buf_len, + ASN1_C_CONTEXT, + CONS, + 1, + &tmp); + if (ret == 0) + buf_len += tmp; + } + if (ret) { + if (ret == ASN1_OVERFLOW) { + u_char *tmp; + + buf_size *= 2; + tmp = realloc (buf, buf_size); + if (tmp == NULL) { + *minor_status = ENOMEM; + free(buf); + return GSS_S_FAILURE; + } + buf = tmp; + } else { + *minor_status = ret; + free(buf); + return GSS_S_FAILURE; + } + } + } while (ret == ASN1_OVERFLOW); + + data->data = buf + buf_size - buf_len; + data->length = buf_len; + *ret_buf = buf; + return GSS_S_COMPLETE; +} + +static OM_uint32 +send_reject (OM_uint32 *minor_status, + gss_buffer_t output_token) +{ + NegTokenTarg targ; + krb5_data data; + u_char *buf; + OM_uint32 ret; + + ALLOC(targ.negResult, 1); + if (targ.negResult == NULL) { + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + *(targ.negResult) = reject; + targ.supportedMech = NULL; + targ.responseToken = NULL; + targ.mechListMIC = NULL; + + ret = code_NegTokenArg (minor_status, &targ, &data, &buf); + free_NegTokenTarg(&targ); + if (ret) + return ret; + +#if 0 + ret = _gssapi_encapsulate(minor_status, + &data, + output_token, + GSS_SPNEGO_MECHANISM); +#else + output_token->value = malloc(data.length); + if (output_token->value == NULL) { + *minor_status = ENOMEM; + ret = GSS_S_FAILURE; + } else { + output_token->length = data.length; + memcpy(output_token->value, data.data, output_token->length); + } +#endif + free(buf); + if (ret) + return ret; + return GSS_S_BAD_MECH; +} + +static OM_uint32 +send_accept (OM_uint32 *minor_status, + OM_uint32 major_status, + gss_buffer_t output_token, + gss_buffer_t mech_token, + gss_ctx_id_t context_handle, + const MechTypeList *mechtypelist) +{ + NegTokenTarg targ; + krb5_data data; + u_char *buf; + OM_uint32 ret; + gss_buffer_desc mech_buf, mech_mic_buf; + krb5_boolean require_mic; + + memset(&targ, 0, sizeof(targ)); + ALLOC(targ.negResult, 1); + if (targ.negResult == NULL) { + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + *(targ.negResult) = accept_completed; + + ALLOC(targ.supportedMech, 1); + if (targ.supportedMech == NULL) { + free_NegTokenTarg(&targ); + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + + ret = der_get_oid(GSS_KRB5_MECHANISM->elements, + GSS_KRB5_MECHANISM->length, + targ.supportedMech, + NULL); + if (ret) { + free_NegTokenTarg(&targ); + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + + if (mech_token != NULL && mech_token->length != 0) { + ALLOC(targ.responseToken, 1); + if (targ.responseToken == NULL) { + free_NegTokenTarg(&targ); + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + targ.responseToken->length = mech_token->length; + targ.responseToken->data = mech_token->value; + mech_token->length = 0; + mech_token->value = NULL; + } else { + targ.responseToken = NULL; + } + + ret = _gss_spnego_require_mechlist_mic(minor_status, context_handle, + &require_mic); + if (ret) { + free_NegTokenTarg(&targ); + return ret; + } + + if (major_status == GSS_S_COMPLETE && require_mic) { + size_t buf_len; + + ALLOC(targ.mechListMIC, 1); + if (targ.mechListMIC == NULL) { + free_NegTokenTarg(&targ); + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + + ASN1_MALLOC_ENCODE(MechTypeList, mech_buf.value, mech_buf.length, + mechtypelist, &buf_len, ret); + if (ret) { + free_NegTokenTarg(&targ); + return ret; + } + if (mech_buf.length != buf_len) + abort(); + + ret = gss_get_mic(minor_status, context_handle, 0, &mech_buf, + &mech_mic_buf); + free (mech_buf.value); + if (ret) { + free_NegTokenTarg(&targ); + return ret; + } + + targ.mechListMIC->length = mech_mic_buf.length; + targ.mechListMIC->data = mech_mic_buf.value; + } else + targ.mechListMIC = NULL; + + ret = code_NegTokenArg (minor_status, &targ, &data, &buf); + free_NegTokenTarg(&targ); + if (ret) + return ret; + +#if 0 + ret = _gssapi_encapsulate(minor_status, + &data, + output_token, + GSS_SPNEGO_MECHANISM); +#else + output_token->value = malloc(data.length); + if (output_token->value == NULL) { + *minor_status = ENOMEM; + ret = GSS_S_FAILURE; + } else { + output_token->length = data.length; + memcpy(output_token->value, data.data, output_token->length); + } +#endif + free(buf); + if (ret) + return ret; + return GSS_S_COMPLETE; +} + +static OM_uint32 +spnego_accept_sec_context + (OM_uint32 * minor_status, + gss_ctx_id_t * context_handle, + const gss_cred_id_t acceptor_cred_handle, + const gss_buffer_t input_token_buffer, + const gss_channel_bindings_t input_chan_bindings, + gss_name_t * src_name, + gss_OID * mech_type, + gss_buffer_t output_token, + OM_uint32 * ret_flags, + OM_uint32 * time_rec, + gss_cred_id_t * delegated_cred_handle + ) +{ + OM_uint32 ret, ret2; + NegTokenInit ni; + size_t ni_len; + int i; + int found = 0; + krb5_data data; + size_t len, taglen; + + output_token->length = 0; + output_token->value = NULL; + + ret = _gssapi_decapsulate (minor_status, + input_token_buffer, + &data, + GSS_SPNEGO_MECHANISM); + if (ret) + return ret; + + ret = der_match_tag_and_length(data.data, data.length, + ASN1_C_CONTEXT, CONS, 0, &len, &taglen); + if (ret) + return ret; + + if(len > data.length - taglen) + return ASN1_OVERRUN; + + ret = decode_NegTokenInit((const char *)data.data + taglen, len, + &ni, &ni_len); + if (ret) + return GSS_S_DEFECTIVE_TOKEN; + + if (ni.mechTypes == NULL) { + free_NegTokenInit(&ni); + return send_reject (minor_status, output_token); + } + + for (i = 0; !found && i < ni.mechTypes->len; ++i) { + char mechbuf[17]; + size_t mech_len; + + ret = der_put_oid (mechbuf + sizeof(mechbuf) - 1, + sizeof(mechbuf), + &ni.mechTypes->val[i], + &mech_len); + if (ret) { + free_NegTokenInit(&ni); + return GSS_S_DEFECTIVE_TOKEN; + } + if (mech_len == GSS_KRB5_MECHANISM->length + && memcmp(GSS_KRB5_MECHANISM->elements, + mechbuf + sizeof(mechbuf) - mech_len, + mech_len) == 0) + found = 1; + } + if (found) { + gss_buffer_desc ibuf, obuf; + gss_buffer_t ot = NULL; + OM_uint32 minor; + + if (ni.mechToken != NULL) { + ibuf.length = ni.mechToken->length; + ibuf.value = ni.mechToken->data; + + ret = gsskrb5_accept_sec_context(&minor, + context_handle, + acceptor_cred_handle, + &ibuf, + input_chan_bindings, + src_name, + mech_type, + &obuf, + ret_flags, + time_rec, + delegated_cred_handle); + if (ret == GSS_S_COMPLETE || ret == GSS_S_CONTINUE_NEEDED) { + ot = &obuf; + } else { + free_NegTokenInit(&ni); + send_reject (minor_status, output_token); + return ret; + } + } + ret2 = send_accept (minor_status, ret, output_token, ot, + *context_handle, ni.mechTypes); + if (ret2 != GSS_S_COMPLETE) + ret = ret2; + if (ot != NULL) + gss_release_buffer(&minor, ot); + free_NegTokenInit(&ni); + return ret; + } else { + free_NegTokenInit(&ni); + return send_reject (minor_status, output_token); + } +} + +OM_uint32 +gss_accept_sec_context( + OM_uint32 * minor_status, + gss_ctx_id_t * context_handle, + const gss_cred_id_t acceptor_cred_handle, + const gss_buffer_t input_token, + const gss_channel_bindings_t input_chan_bindings, + gss_name_t * src_name, + gss_OID * actual_mech_type, + gss_buffer_t output_token, + OM_uint32 * ret_flags, + OM_uint32 * time_rec, + gss_cred_id_t * delegated_cred_handle) +{ + ssize_t mech_len; + const u_char *p; + + GSSAPI_KRB5_INIT (); + + *minor_status = 0; + + if (src_name) *src_name = GSS_C_NO_NAME; + if (actual_mech_type) *actual_mech_type = GSS_C_NO_OID; + + output_token->length = 0; + output_token->value = NULL; + + if (ret_flags) *ret_flags = 0; + if (time_rec) *time_rec = 0; + if (delegated_cred_handle) *delegated_cred_handle = NULL; + + mech_len = gssapi_krb5_get_mech(input_token->value, + input_token->length, + &p); + + /* This could be 'dce style' kerberos, where the OID is missing :-( */ + if ((mech_len < 0) || (mech_len == GSS_KRB5_MECHANISM->length + && memcmp(p, GSS_KRB5_MECHANISM->elements, mech_len) == 0)) { + return gsskrb5_accept_sec_context(minor_status, + context_handle, + acceptor_cred_handle, + input_token, + input_chan_bindings, + src_name, + actual_mech_type, + output_token, + ret_flags, + time_rec, + delegated_cred_handle); + } else if (mech_len == GSS_SPNEGO_MECHANISM->length + && memcmp(p, GSS_SPNEGO_MECHANISM->elements, mech_len) == 0) { + return spnego_accept_sec_context(minor_status, + context_handle, + acceptor_cred_handle, + input_token, + input_chan_bindings, + src_name, + actual_mech_type, + output_token, + ret_flags, + time_rec, + delegated_cred_handle); + } + + return GSS_S_BAD_MECH; +} diff --git a/source4/heimdal/lib/gssapi/acquire_cred.c b/source4/heimdal/lib/gssapi/acquire_cred.c new file mode 100644 index 0000000000..6ded413626 --- /dev/null +++ b/source4/heimdal/lib/gssapi/acquire_cred.c @@ -0,0 +1,376 @@ +/* + * Copyright (c) 1997 - 2004 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 "gssapi_locl.h" + +RCSID("$Id: acquire_cred.c,v 1.22 2005/01/05 02:32:26 lukeh Exp $"); + +static krb5_error_code +get_keytab(krb5_context context, krb5_keytab *keytab) +{ + char kt_name[256]; + krb5_error_code kret; + + HEIMDAL_MUTEX_lock(&gssapi_keytab_mutex); + + if (gssapi_krb5_keytab != NULL) { + kret = krb5_kt_get_name(context, + gssapi_krb5_keytab, + kt_name, sizeof(kt_name)); + if (kret == 0) + kret = krb5_kt_resolve(context, kt_name, keytab); + } else + kret = krb5_kt_default(context, keytab); + + HEIMDAL_MUTEX_unlock(&gssapi_keytab_mutex); + + return (kret); +} + +static OM_uint32 acquire_initiator_cred + (OM_uint32 * minor_status, + krb5_context context, + krb5_keytab keytab, + krb5_ccache ccache, + const gss_name_t desired_name, + OM_uint32 time_req, + const gss_OID_set desired_mechs, + gss_cred_usage_t cred_usage, + gss_cred_id_t handle, + gss_OID_set * actual_mechs, + OM_uint32 * time_rec + ) +{ + OM_uint32 ret; + krb5_creds cred; + krb5_principal def_princ; + krb5_get_init_creds_opt *opt; + krb5_error_code kret; + krb5_boolean made_ccache = FALSE; + krb5_boolean made_keytab = FALSE; + + def_princ = NULL; + ret = GSS_S_FAILURE; + memset(&cred, 0, sizeof(cred)); + + if (ccache == NULL) { + kret = krb5_cc_default(context, &ccache); + if (kret) + goto end; + made_ccache = TRUE; + } + kret = krb5_cc_get_principal(context, ccache, + &def_princ); + if (kret != 0) { + /* we'll try to use a keytab below */ + krb5_cc_destroy(context, ccache); + made_ccache = FALSE; + ccache = NULL; + kret = 0; + } else if (handle->principal == NULL) { + kret = krb5_copy_principal(context, def_princ, + &handle->principal); + if (kret) + goto end; + } else if (handle->principal != NULL && + krb5_principal_compare(context, handle->principal, + def_princ) == FALSE) { + /* Before failing, lets check the keytab */ + krb5_free_principal(context, def_princ); + def_princ = NULL; + } + if (def_princ == NULL) { + /* We have no existing credentials cache, + * so attempt to get a TGT using a keytab. + */ + if (handle->principal == NULL) { + kret = krb5_get_default_principal(context, + &handle->principal); + if (kret) + goto end; + } + if (keytab != NULL) { + kret = get_keytab(context, &keytab); + if (kret) + goto end; + made_keytab = TRUE; + } + kret = krb5_get_init_creds_opt_alloc(context, &opt); + if (kret) + goto end; + kret = krb5_get_init_creds_keytab(context, &cred, + handle->principal, keytab, 0, NULL, opt); + krb5_get_init_creds_opt_free(opt); + if (kret) + goto end; + if (ccache == NULL) { + kret = krb5_cc_gen_new(context, &krb5_mcc_ops, + &ccache); + if (kret) + goto end; + made_ccache = TRUE; + } + kret = krb5_cc_initialize(context, ccache, cred.client); + if (kret) + goto end; + kret = krb5_cc_store_cred(context, ccache, &cred); + if (kret) + goto end; + handle->lifetime = cred.times.endtime; + } else { + krb5_creds in_cred, *out_cred; + krb5_const_realm realm; + + memset(&in_cred, 0, sizeof(in_cred)); + in_cred.client = handle->principal; + + realm = krb5_principal_get_realm(context, + handle->principal); + if (realm == NULL) { + kret = KRB5_PRINC_NOMATCH; /* XXX */ + goto end; + } + + kret = krb5_make_principal(context, &in_cred.server, + realm, KRB5_TGS_NAME, realm, NULL); + if (kret) + goto end; + + kret = krb5_get_credentials(context, 0, + ccache, &in_cred, &out_cred); + krb5_free_principal(context, in_cred.server); + if (kret) + goto end; + + handle->lifetime = out_cred->times.endtime; + krb5_free_creds(context, out_cred); + } + + handle->ccache = ccache; + handle->made_ccache = made_ccache; + ret = GSS_S_COMPLETE; + +end: + if (cred.client != NULL) + krb5_free_cred_contents(context, &cred); + if (def_princ != NULL) + krb5_free_principal(context, def_princ); + if (made_keytab) + krb5_kt_close(context, keytab); + if (ret != GSS_S_COMPLETE) { + if (made_ccache) + krb5_cc_close(context, ccache); + if (kret != 0) { + *minor_status = kret; + gssapi_krb5_set_error_string (); + } + } + return (ret); +} + +static OM_uint32 acquire_acceptor_cred + (OM_uint32 * minor_status, + krb5_context context, + krb5_keytab keytab, + OM_uint32 time_req, + const gss_OID_set desired_mechs, + gss_cred_usage_t cred_usage, + gss_cred_id_t handle, + gss_OID_set * actual_mechs, + OM_uint32 * time_rec + ) +{ + OM_uint32 ret; + krb5_error_code kret; + + kret = 0; + ret = GSS_S_FAILURE; + if (keytab == NULL) { + kret = get_keytab(context, &handle->keytab); + if (kret) + goto end; + handle->made_keytab = TRUE; + } else { + handle->keytab = keytab; + handle->made_keytab = FALSE; + } + ret = GSS_S_COMPLETE; + +end: + if (ret != GSS_S_COMPLETE) { + if (handle->made_keytab) + krb5_kt_close(context, handle->keytab); + if (kret != 0) { + *minor_status = kret; + gssapi_krb5_set_error_string (); + } + } + return (ret); +} + +OM_uint32 gsskrb5_acquire_cred + (OM_uint32 * minor_status, + struct krb5_keytab_data *keytab, + struct krb5_ccache_data *ccache, + const gss_name_t desired_name, + OM_uint32 time_req, + const gss_OID_set desired_mechs, + gss_cred_usage_t cred_usage, + gss_cred_id_t * output_cred_handle, + gss_OID_set * actual_mechs, + OM_uint32 * time_rec + ) +{ + gss_cred_id_t handle; + OM_uint32 ret; + + if (cred_usage != GSS_C_ACCEPT && cred_usage != GSS_C_INITIATE && cred_usage != GSS_C_BOTH) { + *minor_status = GSS_KRB5_S_G_BAD_USAGE; + return GSS_S_FAILURE; + } + + GSSAPI_KRB5_INIT (); + + *output_cred_handle = NULL; + if (time_rec) + *time_rec = 0; + if (actual_mechs) + *actual_mechs = GSS_C_NO_OID_SET; + + if (desired_mechs) { + int present = 0; + + ret = gss_test_oid_set_member(minor_status, GSS_KRB5_MECHANISM, + desired_mechs, &present); + if (ret) + return ret; + if (!present) { + *minor_status = 0; + return GSS_S_BAD_MECH; + } + } + + handle = (gss_cred_id_t)malloc(sizeof(*handle)); + if (handle == GSS_C_NO_CREDENTIAL) { + *minor_status = ENOMEM; + return (GSS_S_FAILURE); + } + + memset(handle, 0, sizeof (*handle)); + HEIMDAL_MUTEX_init(&handle->cred_id_mutex); + + if (desired_name != GSS_C_NO_NAME) { + ret = gss_duplicate_name(minor_status, desired_name, + &handle->principal); + if (ret != GSS_S_COMPLETE) { + HEIMDAL_MUTEX_destroy(&handle->cred_id_mutex); + free(handle); + return (ret); + } + } + if (cred_usage == GSS_C_INITIATE || cred_usage == GSS_C_BOTH) { + ret = acquire_initiator_cred(minor_status, gssapi_krb5_context, + keytab, ccache, + desired_name, time_req, + desired_mechs, cred_usage, + handle, actual_mechs, time_rec); + if (ret != GSS_S_COMPLETE) { + HEIMDAL_MUTEX_destroy(&handle->cred_id_mutex); + krb5_free_principal(gssapi_krb5_context, handle->principal); + free(handle); + return (ret); + } + } + if (cred_usage == GSS_C_ACCEPT || cred_usage == GSS_C_BOTH) { + ret = acquire_acceptor_cred(minor_status, gssapi_krb5_context, + keytab, time_req, + desired_mechs, cred_usage, + handle, actual_mechs, time_rec); + if (ret != GSS_S_COMPLETE) { + HEIMDAL_MUTEX_destroy(&handle->cred_id_mutex); + krb5_free_principal(gssapi_krb5_context, handle->principal); + free(handle); + return (ret); + } + } + ret = gss_create_empty_oid_set(minor_status, &handle->mechanisms); + if (ret == GSS_S_COMPLETE) + ret = gss_add_oid_set_member(minor_status, GSS_KRB5_MECHANISM, + &handle->mechanisms); + if (ret == GSS_S_COMPLETE) + ret = gss_inquire_cred(minor_status, handle, NULL, time_rec, NULL, + actual_mechs); + if (ret != GSS_S_COMPLETE) { + if (handle->mechanisms != NULL) + gss_release_oid_set(NULL, &handle->mechanisms); + HEIMDAL_MUTEX_destroy(&handle->cred_id_mutex); + krb5_free_principal(gssapi_krb5_context, handle->principal); + free(handle); + return (ret); + } + *minor_status = 0; + if (time_rec) { + ret = gssapi_lifetime_left(minor_status, + handle->lifetime, + time_rec); + + if (ret) + return ret; + } + handle->usage = cred_usage; + + *output_cred_handle = handle; + return (GSS_S_COMPLETE); +} + +OM_uint32 gss_acquire_cred + (OM_uint32 * minor_status, + const gss_name_t desired_name, + OM_uint32 time_req, + const gss_OID_set desired_mechs, + gss_cred_usage_t cred_usage, + gss_cred_id_t * output_cred_handle, + gss_OID_set * actual_mechs, + OM_uint32 * time_rec + ) +{ + return gsskrb5_acquire_cred(minor_status, + NULL, NULL, + desired_name, + time_req, + desired_mechs, + cred_usage, + output_cred_handle, + actual_mechs, + time_rec); +} diff --git a/source4/heimdal/lib/gssapi/add_oid_set_member.c b/source4/heimdal/lib/gssapi/add_oid_set_member.c new file mode 100644 index 0000000000..ed654fc8c5 --- /dev/null +++ b/source4/heimdal/lib/gssapi/add_oid_set_member.c @@ -0,0 +1,69 @@ +/* + * Copyright (c) 1997 - 2001, 2003 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 "gssapi_locl.h" + +RCSID("$Id: add_oid_set_member.c,v 1.8 2003/03/16 17:50:49 lha Exp $"); + +OM_uint32 gss_add_oid_set_member ( + OM_uint32 * minor_status, + const gss_OID member_oid, + gss_OID_set * oid_set + ) +{ + gss_OID tmp; + size_t n; + OM_uint32 res; + int present; + + res = gss_test_oid_set_member(minor_status, member_oid, *oid_set, &present); + if (res != GSS_S_COMPLETE) + return res; + + if (present) { + *minor_status = 0; + return GSS_S_COMPLETE; + } + + n = (*oid_set)->count + 1; + tmp = realloc ((*oid_set)->elements, n * sizeof(gss_OID_desc)); + if (tmp == NULL) { + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + (*oid_set)->elements = tmp; + (*oid_set)->count = n; + (*oid_set)->elements[n-1] = *member_oid; + *minor_status = 0; + return GSS_S_COMPLETE; +} diff --git a/source4/heimdal/lib/gssapi/address_to_krb5addr.c b/source4/heimdal/lib/gssapi/address_to_krb5addr.c new file mode 100644 index 0000000000..13a6825f55 --- /dev/null +++ b/source4/heimdal/lib/gssapi/address_to_krb5addr.c @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2000 - 2001 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 "gssapi_locl.h" + +#include <roken.h> + +krb5_error_code +gss_address_to_krb5addr(OM_uint32 gss_addr_type, + gss_buffer_desc *gss_addr, + int16_t port, + krb5_address *address) +{ + int addr_type; + struct sockaddr sa; + krb5_socklen_t sa_size = sizeof(sa); + krb5_error_code problem; + + if (gss_addr == NULL) + return GSS_S_FAILURE; + + switch (gss_addr_type) { +#ifdef HAVE_IPV6 + case GSS_C_AF_INET6: addr_type = AF_INET6; + break; +#endif /* HAVE_IPV6 */ + + case GSS_C_AF_INET: addr_type = AF_INET; + break; + default: + return GSS_S_FAILURE; + } + + problem = krb5_h_addr2sockaddr (gssapi_krb5_context, + addr_type, + gss_addr->value, + &sa, + &sa_size, + port); + if (problem) + return GSS_S_FAILURE; + + problem = krb5_sockaddr2address (gssapi_krb5_context, &sa, address); + + return problem; +} diff --git a/source4/heimdal/lib/gssapi/arcfour.c b/source4/heimdal/lib/gssapi/arcfour.c new file mode 100644 index 0000000000..5edcee08ec --- /dev/null +++ b/source4/heimdal/lib/gssapi/arcfour.c @@ -0,0 +1,660 @@ +/* + * Copyright (c) 2003 - 2004 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 "gssapi_locl.h" + +RCSID("$Id: arcfour.c,v 1.17 2005/05/06 07:13:32 lha Exp $"); + +/* + * Implements draft-brezak-win2k-krb-rc4-hmac-04.txt + * + * The arcfour message have the following formats: + * + * MIC token + * TOK_ID[2] = 01 01 + * SGN_ALG[2] = 11 00 + * Filler[4] + * SND_SEQ[8] + * SGN_CKSUM[8] + * + * WRAP token + * TOK_ID[2] = 02 01 + * SGN_ALG[2]; + * SEAL_ALG[2] + * Filler[2] + * SND_SEQ[2] + * SGN_CKSUM[8] + * Confounder[8] + */ + + +static krb5_error_code +arcfour_mic_key(krb5_context context, krb5_keyblock *key, + void *cksum_data, size_t cksum_size, + void *key6_data, size_t key6_size) +{ + krb5_error_code ret; + + Checksum cksum_k5; + krb5_keyblock key5; + char k5_data[16]; + + Checksum cksum_k6; + + char T[4]; + + memset(T, 0, 4); + cksum_k5.checksum.data = k5_data; + cksum_k5.checksum.length = sizeof(k5_data); + + if (key->keytype == KEYTYPE_ARCFOUR_56) { + char L40[14] = "fortybits"; + + memcpy(L40 + 10, T, sizeof(T)); + ret = krb5_hmac(context, CKSUMTYPE_RSA_MD5, + L40, 14, 0, key, &cksum_k5); + memset(&k5_data[7], 0xAB, 9); + } else { + ret = krb5_hmac(context, CKSUMTYPE_RSA_MD5, + T, 4, 0, key, &cksum_k5); + } + if (ret) + return ret; + + key5.keytype = KEYTYPE_ARCFOUR; + key5.keyvalue = cksum_k5.checksum; + + cksum_k6.checksum.data = key6_data; + cksum_k6.checksum.length = key6_size; + + return krb5_hmac(context, CKSUMTYPE_RSA_MD5, + cksum_data, cksum_size, 0, &key5, &cksum_k6); +} + + +static krb5_error_code +arcfour_mic_cksum(krb5_keyblock *key, unsigned usage, + u_char *sgn_cksum, size_t sgn_cksum_sz, + const char *v1, size_t l1, + const void *v2, size_t l2, + const void *v3, size_t l3) +{ + Checksum CKSUM; + u_char *ptr; + size_t len; + krb5_crypto crypto; + krb5_error_code ret; + + assert(sgn_cksum_sz == 8); + + len = l1 + l2 + l3; + + ptr = malloc(len); + if (ptr == NULL) + return ENOMEM; + + memcpy(ptr, v1, l1); + memcpy(ptr + l1, v2, l2); + memcpy(ptr + l1 + l2, v3, l3); + + ret = krb5_crypto_init(gssapi_krb5_context, key, 0, &crypto); + if (ret) { + free(ptr); + return ret; + } + + ret = krb5_create_checksum(gssapi_krb5_context, + crypto, + usage, + 0, + ptr, len, + &CKSUM); + free(ptr); + if (ret == 0) { + memcpy(sgn_cksum, CKSUM.checksum.data, sgn_cksum_sz); + free_Checksum(&CKSUM); + } + krb5_crypto_destroy(gssapi_krb5_context, crypto); + + return ret; +} + + +OM_uint32 +_gssapi_get_mic_arcfour(OM_uint32 * minor_status, + const gss_ctx_id_t context_handle, + gss_qop_t qop_req, + const gss_buffer_t message_buffer, + gss_buffer_t message_token, + krb5_keyblock *key) +{ + krb5_error_code ret; + int32_t seq_number; + size_t len, total_len; + u_char k6_data[16], *p0, *p; + RC4_KEY rc4_key; + + gssapi_krb5_encap_length (22, &len, &total_len, GSS_KRB5_MECHANISM); + + message_token->length = total_len; + message_token->value = malloc (total_len); + if (message_token->value == NULL) { + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + + p0 = _gssapi_make_mech_header(message_token->value, + len, + GSS_KRB5_MECHANISM); + p = p0; + + *p++ = 0x01; /* TOK_ID */ + *p++ = 0x01; + *p++ = 0x11; /* SGN_ALG */ + *p++ = 0x00; + *p++ = 0xff; /* Filler */ + *p++ = 0xff; + *p++ = 0xff; + *p++ = 0xff; + + p = NULL; + + ret = arcfour_mic_cksum(key, KRB5_KU_USAGE_SIGN, + p0 + 16, 8, /* SGN_CKSUM */ + p0, 8, /* TOK_ID, SGN_ALG, Filer */ + message_buffer->value, message_buffer->length, + NULL, 0); + if (ret) { + gss_release_buffer(minor_status, message_token); + *minor_status = ret; + return GSS_S_FAILURE; + } + + ret = arcfour_mic_key(gssapi_krb5_context, key, + p0 + 16, 8, /* SGN_CKSUM */ + k6_data, sizeof(k6_data)); + if (ret) { + gss_release_buffer(minor_status, message_token); + *minor_status = ret; + return GSS_S_FAILURE; + } + + HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex); + krb5_auth_con_getlocalseqnumber (gssapi_krb5_context, + context_handle->auth_context, + &seq_number); + p = p0 + 8; /* SND_SEQ */ + gssapi_encode_be_om_uint32(seq_number, p); + + krb5_auth_con_setlocalseqnumber (gssapi_krb5_context, + context_handle->auth_context, + ++seq_number); + HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex); + + memset (p + 4, (context_handle->more_flags & LOCAL) ? 0 : 0xff, 4); + + RC4_set_key (&rc4_key, sizeof(k6_data), k6_data); + RC4 (&rc4_key, 8, p, p); + + memset(&rc4_key, 0, sizeof(rc4_key)); + memset(k6_data, 0, sizeof(k6_data)); + + *minor_status = 0; + return GSS_S_COMPLETE; +} + + +OM_uint32 +_gssapi_verify_mic_arcfour(OM_uint32 * minor_status, + const gss_ctx_id_t context_handle, + const gss_buffer_t message_buffer, + const gss_buffer_t token_buffer, + gss_qop_t * qop_state, + krb5_keyblock *key, + char *type) +{ + krb5_error_code ret; + int32_t seq_number; + OM_uint32 omret; + char cksum_data[8], k6_data[16], SND_SEQ[8]; + u_char *p; + int cmp; + + if (qop_state) + *qop_state = 0; + + p = token_buffer->value; + omret = gssapi_krb5_verify_header (&p, + token_buffer->length, + type, + GSS_KRB5_MECHANISM); + if (omret) + return omret; + + if (memcmp(p, "\x11\x00", 2) != 0) /* SGN_ALG = HMAC MD5 ARCFOUR */ + return GSS_S_BAD_SIG; + p += 2; + if (memcmp (p, "\xff\xff\xff\xff", 4) != 0) + return GSS_S_BAD_MIC; + p += 4; + + ret = arcfour_mic_cksum(key, KRB5_KU_USAGE_SIGN, + cksum_data, sizeof(cksum_data), + p - 8, 8, + message_buffer->value, message_buffer->length, + NULL, 0); + if (ret) { + *minor_status = ret; + return GSS_S_FAILURE; + } + + ret = arcfour_mic_key(gssapi_krb5_context, key, + cksum_data, sizeof(cksum_data), + k6_data, sizeof(k6_data)); + if (ret) { + *minor_status = ret; + return GSS_S_FAILURE; + } + + cmp = memcmp(cksum_data, p + 8, 8); + if (cmp) { + *minor_status = 0; + return GSS_S_BAD_MIC; + } + + { + RC4_KEY rc4_key; + + RC4_set_key (&rc4_key, sizeof(k6_data), k6_data); + RC4 (&rc4_key, 8, p, SND_SEQ); + + memset(&rc4_key, 0, sizeof(rc4_key)); + memset(k6_data, 0, sizeof(k6_data)); + } + + gssapi_decode_be_om_uint32(SND_SEQ, &seq_number); + + if (context_handle->more_flags & LOCAL) + cmp = memcmp(&SND_SEQ[4], "\xff\xff\xff\xff", 4); + else + cmp = memcmp(&SND_SEQ[4], "\x00\x00\x00\x00", 4); + + memset(SND_SEQ, 0, sizeof(SND_SEQ)); + if (cmp != 0) { + *minor_status = 0; + return GSS_S_BAD_MIC; + } + + HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex); + omret = _gssapi_msg_order_check(context_handle->order, seq_number); + HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex); + if (omret) + return omret; + + *minor_status = 0; + return GSS_S_COMPLETE; +} + +OM_uint32 +_gssapi_wrap_arcfour(OM_uint32 * minor_status, + const gss_ctx_id_t context_handle, + 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, + krb5_keyblock *key) +{ + u_char Klocaldata[16], k6_data[16], *p, *p0; + size_t len, total_len, datalen; + krb5_keyblock Klocal; + krb5_error_code ret; + int32_t seq_number; + + if (conf_state) + *conf_state = 0; + + datalen = input_message_buffer->length; + len = GSS_ARCFOUR_WRAP_TOKEN_SIZE; + /* if GSS_C_DCE_STYLE is in use: + * - we only need to encapsulate the WRAP token + * - we should not add padding + */ + if (!(context_handle->flags & GSS_C_DCE_STYLE)) { + datalen += 1 /* padding */; + len += datalen; + } + _gssapi_encap_length(len, &len, &total_len, GSS_KRB5_MECHANISM); + if (context_handle->flags & GSS_C_DCE_STYLE) { + total_len += datalen; + } + + output_message_buffer->length = total_len; + output_message_buffer->value = malloc (total_len); + if (output_message_buffer->value == NULL) { + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + + p0 = _gssapi_make_mech_header(output_message_buffer->value, + len, + GSS_KRB5_MECHANISM); + p = p0; + + *p++ = 0x02; /* TOK_ID */ + *p++ = 0x01; + *p++ = 0x11; /* SGN_ALG */ + *p++ = 0x00; + if (conf_req_flag) { + *p++ = 0x10; /* SEAL_ALG */ + *p++ = 0x00; + } else { + *p++ = 0xff; /* SEAL_ALG */ + *p++ = 0xff; + } + *p++ = 0xff; /* Filler */ + *p++ = 0xff; + + p = NULL; + + HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex); + krb5_auth_con_getlocalseqnumber (gssapi_krb5_context, + context_handle->auth_context, + &seq_number); + + gssapi_encode_be_om_uint32(seq_number, p0 + 8); + + krb5_auth_con_setlocalseqnumber (gssapi_krb5_context, + context_handle->auth_context, + ++seq_number); + HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex); + + memset (p0 + 8 + 4, + (context_handle->more_flags & LOCAL) ? 0 : 0xff, + 4); + + krb5_generate_random_block(p0 + 24, 8); /* fill in Confounder */ + + /* p points to data */ + p = p0 + GSS_ARCFOUR_WRAP_TOKEN_SIZE; + memcpy(p, input_message_buffer->value, input_message_buffer->length); + /* only add padding when GSS_C_DCE_STYLE is not in use */ + if (!(context_handle->flags & GSS_C_DCE_STYLE)) { + p[input_message_buffer->length] = 1; /* PADDING */ + } + + ret = arcfour_mic_cksum(key, KRB5_KU_USAGE_SEAL, + p0 + 16, 8, /* SGN_CKSUM */ + p0, 8, /* TOK_ID, SGN_ALG, SEAL_ALG, Filler */ + p0 + 24, 8, /* Confounder */ + p0 + GSS_ARCFOUR_WRAP_TOKEN_SIZE, + datalen); + if (ret) { + *minor_status = ret; + gss_release_buffer(minor_status, output_message_buffer); + return GSS_S_FAILURE; + } + + { + int i; + + Klocal.keytype = key->keytype; + Klocal.keyvalue.data = Klocaldata; + Klocal.keyvalue.length = sizeof(Klocaldata); + + for (i = 0; i < 16; i++) + Klocaldata[i] = ((u_char *)key->keyvalue.data)[i] ^ 0xF0; + } + ret = arcfour_mic_key(gssapi_krb5_context, &Klocal, + p0 + 8, 4, /* SND_SEQ */ + k6_data, sizeof(k6_data)); + memset(Klocaldata, 0, sizeof(Klocaldata)); + if (ret) { + gss_release_buffer(minor_status, output_message_buffer); + *minor_status = ret; + return GSS_S_FAILURE; + } + + + if(conf_req_flag) { + RC4_KEY rc4_key; + + RC4_set_key (&rc4_key, sizeof(k6_data), k6_data); + /* XXX ? */ + RC4 (&rc4_key, 8 + datalen, p0 + 24, p0 + 24); /* Confounder + data */ + memset(&rc4_key, 0, sizeof(rc4_key)); + } + memset(k6_data, 0, sizeof(k6_data)); + + ret = arcfour_mic_key(gssapi_krb5_context, key, + p0 + 16, 8, /* SGN_CKSUM */ + k6_data, sizeof(k6_data)); + if (ret) { + gss_release_buffer(minor_status, output_message_buffer); + *minor_status = ret; + return GSS_S_FAILURE; + } + + { + RC4_KEY rc4_key; + + RC4_set_key (&rc4_key, sizeof(k6_data), k6_data); + RC4 (&rc4_key, 8, p0 + 8, p0 + 8); /* SND_SEQ */ + memset(&rc4_key, 0, sizeof(rc4_key)); + memset(k6_data, 0, sizeof(k6_data)); + } + + if (conf_state) + *conf_state = conf_req_flag; + + *minor_status = 0; + return GSS_S_COMPLETE; +} + +OM_uint32 _gssapi_unwrap_arcfour(OM_uint32 *minor_status, + const gss_ctx_id_t context_handle, + const gss_buffer_t input_message_buffer, + gss_buffer_t output_message_buffer, + int *conf_state, + gss_qop_t *qop_state, + krb5_keyblock *key) +{ + u_char Klocaldata[16]; + krb5_keyblock Klocal; + krb5_error_code ret; + int32_t seq_number; + size_t len, datalen; + OM_uint32 omret; + char k6_data[16], SND_SEQ[8], Confounder[8]; + char cksum_data[8]; + u_char *p, *p0; + int cmp; + int conf_flag; + size_t padlen = 0; + + if (conf_state) + *conf_state = 0; + if (qop_state) + *qop_state = 0; + + p0 = input_message_buffer->value; + len = input_message_buffer->length; + /* if we have GSS_C_DCE_STYLE in use, we only need to decapsulate the WRAP token */ + if (context_handle->flags & GSS_C_DCE_STYLE) { + if (input_message_buffer->length < (GSS_ARCFOUR_WRAP_TOKEN_OFFSET+GSS_ARCFOUR_WRAP_TOKEN_SIZE)) { + return GSS_S_BAD_MECH; + } + len = GSS_ARCFOUR_WRAP_TOKEN_OFFSET+GSS_ARCFOUR_WRAP_TOKEN_SIZE; + } + omret = _gssapi_verify_mech_header(&p0, + len, + GSS_KRB5_MECHANISM); + if (omret) + return omret; + p = p0; + + datalen = input_message_buffer->length - + (p - ((u_char *)input_message_buffer->value)) - + GSS_ARCFOUR_WRAP_TOKEN_SIZE; + + if (memcmp(p, "\x02\x01", 2) != 0) + return GSS_S_BAD_SIG; + p += 2; + if (memcmp(p, "\x11\x00", 2) != 0) /* SGN_ALG = HMAC MD5 ARCFOUR */ + return GSS_S_BAD_SIG; + p += 2; + + if (memcmp (p, "\x10\x00", 2) == 0) + conf_flag = 1; + else if (memcmp (p, "\xff\xff", 2) == 0) + conf_flag = 0; + else + return GSS_S_BAD_SIG; + + p += 2; + if (memcmp (p, "\xff\xff", 2) != 0) + return GSS_S_BAD_MIC; + p = NULL; + + ret = arcfour_mic_key(gssapi_krb5_context, key, + p0 + 16, 8, /* SGN_CKSUM */ + k6_data, sizeof(k6_data)); + if (ret) { + *minor_status = ret; + return GSS_S_FAILURE; + } + + { + RC4_KEY rc4_key; + + RC4_set_key (&rc4_key, sizeof(k6_data), k6_data); + RC4 (&rc4_key, 8, p0 + 8, SND_SEQ); /* SND_SEQ */ + memset(&rc4_key, 0, sizeof(rc4_key)); + memset(k6_data, 0, sizeof(k6_data)); + } + + gssapi_decode_be_om_uint32(SND_SEQ, &seq_number); + + if (context_handle->more_flags & LOCAL) + cmp = memcmp(&SND_SEQ[4], "\xff\xff\xff\xff", 4); + else + cmp = memcmp(&SND_SEQ[4], "\x00\x00\x00\x00", 4); + + if (cmp != 0) { + *minor_status = 0; + return GSS_S_BAD_MIC; + } + + { + int i; + + Klocal.keytype = key->keytype; + Klocal.keyvalue.data = Klocaldata; + Klocal.keyvalue.length = sizeof(Klocaldata); + + for (i = 0; i < 16; i++) + Klocaldata[i] = ((u_char *)key->keyvalue.data)[i] ^ 0xF0; + } + ret = arcfour_mic_key(gssapi_krb5_context, &Klocal, + SND_SEQ, 4, + k6_data, sizeof(k6_data)); + memset(Klocaldata, 0, sizeof(Klocaldata)); + if (ret) { + *minor_status = ret; + return GSS_S_FAILURE; + } + + output_message_buffer->value = malloc(datalen); + if (output_message_buffer->value == NULL) { + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + output_message_buffer->length = datalen; + + if(conf_flag) { + RC4_KEY rc4_key; + + RC4_set_key (&rc4_key, sizeof(k6_data), k6_data); + RC4 (&rc4_key, 8, p0 + 24, Confounder); /* Confounder */ + RC4 (&rc4_key, datalen, p0 + GSS_ARCFOUR_WRAP_TOKEN_SIZE, + output_message_buffer->value); + memset(&rc4_key, 0, sizeof(rc4_key)); + } else { + memcpy(Confounder, p0 + 24, 8); /* Confounder */ + memcpy(output_message_buffer->value, + p0 + GSS_ARCFOUR_WRAP_TOKEN_SIZE, + datalen); + } + memset(k6_data, 0, sizeof(k6_data)); + + if (!(context_handle->flags & GSS_C_DCE_STYLE)) { + ret = _gssapi_verify_pad(output_message_buffer, datalen, &padlen); + if (ret) { + gss_release_buffer(minor_status, output_message_buffer); + *minor_status = 0; + return ret; + } + output_message_buffer->length -= padlen; + } + + ret = arcfour_mic_cksum(key, KRB5_KU_USAGE_SEAL, + cksum_data, sizeof(cksum_data), + p0, 8, + Confounder, sizeof(Confounder), + output_message_buffer->value, + output_message_buffer->length + padlen); + if (ret) { + gss_release_buffer(minor_status, output_message_buffer); + *minor_status = ret; + return GSS_S_FAILURE; + } + + cmp = memcmp(cksum_data, p0 + 16, 8); /* SGN_CKSUM */ + if (cmp) { + gss_release_buffer(minor_status, output_message_buffer); + *minor_status = 0; + return GSS_S_BAD_MIC; + } + + HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex); + omret = _gssapi_msg_order_check(context_handle->order, seq_number); + HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex); + if (omret) + return omret; + + if (conf_state) + *conf_state = conf_flag; + + *minor_status = 0; + return GSS_S_COMPLETE; +} diff --git a/source4/heimdal/lib/gssapi/arcfour.h b/source4/heimdal/lib/gssapi/arcfour.h new file mode 100644 index 0000000000..5acfcad29d --- /dev/null +++ b/source4/heimdal/lib/gssapi/arcfour.h @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2003 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. + */ + +/* $Id: arcfour.h,v 1.5 2004/03/07 22:30:57 lha Exp $ */ + +#ifndef GSSAPI_ARCFOUR_H_ +#define GSSAPI_ARCFOUR_H_ 1 + +#define GSS_ARCFOUR_WRAP_TOKEN_SIZE 32 +#define GSS_ARCFOUR_WRAP_TOKEN_OFFSET 13 + +OM_uint32 _gssapi_wrap_arcfour(OM_uint32 *minor_status, + const gss_ctx_id_t context_handle, + 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, + krb5_keyblock *key); + +OM_uint32 _gssapi_unwrap_arcfour(OM_uint32 *minor_status, + const gss_ctx_id_t context_handle, + const gss_buffer_t input_message_buffer, + gss_buffer_t output_message_buffer, + int *conf_state, + gss_qop_t *qop_state, + krb5_keyblock *key); + +OM_uint32 _gssapi_get_mic_arcfour(OM_uint32 *minor_status, + const gss_ctx_id_t context_handle, + gss_qop_t qop_req, + const gss_buffer_t message_buffer, + gss_buffer_t message_token, + krb5_keyblock *key); + +OM_uint32 _gssapi_verify_mic_arcfour(OM_uint32 *minor_status, + const gss_ctx_id_t context_handle, + const gss_buffer_t message_buffer, + const gss_buffer_t token_buffer, + gss_qop_t *qop_state, + krb5_keyblock *key, + char *type); + +#endif /* GSSAPI_ARCFOUR_H_ */ diff --git a/source4/heimdal/lib/gssapi/ccache_name.c b/source4/heimdal/lib/gssapi/ccache_name.c new file mode 100755 index 0000000000..3bebb83c1f --- /dev/null +++ b/source4/heimdal/lib/gssapi/ccache_name.c @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2004 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 "gssapi_locl.h" + +RCSID("$Id: ccache_name.c,v 1.2 2005/06/16 20:38:49 lha Exp $"); + +char *last_out_name; + +OM_uint32 +gss_krb5_ccache_name(OM_uint32 *minor_status, + const char *name, + const char **out_name) +{ + krb5_error_code kret; + + *minor_status = 0; + + GSSAPI_KRB5_INIT(); + + if (out_name) { + const char *n; + + if (last_out_name) { + free(last_out_name); + last_out_name = NULL; + } + + n = krb5_cc_default_name(gssapi_krb5_context); + if (n == NULL) { + *minor_status = ENOMEM; + gssapi_krb5_set_error_string (); + return GSS_S_FAILURE; + } + last_out_name = strdup(n); + if (last_out_name == NULL) { + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + *out_name = last_out_name; + } + + kret = krb5_cc_set_default_name(gssapi_krb5_context, name); + if (kret) { + *minor_status = kret; + gssapi_krb5_set_error_string (); + return GSS_S_FAILURE; + } + return GSS_S_COMPLETE; +} diff --git a/source4/heimdal/lib/gssapi/cfx.c b/source4/heimdal/lib/gssapi/cfx.c new file mode 100755 index 0000000000..75b6a8bcfa --- /dev/null +++ b/source4/heimdal/lib/gssapi/cfx.c @@ -0,0 +1,841 @@ +/* + * Copyright (c) 2003, PADL Software Pty Ltd. + * 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 PADL Software 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 PADL SOFTWARE 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 PADL SOFTWARE 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 "gssapi_locl.h" + +RCSID("$Id: cfx.c,v 1.17 2005/04/27 17:47:32 lha Exp $"); + +/* + * Implementation of draft-ietf-krb-wg-gssapi-cfx-06.txt + */ + +#define CFXSentByAcceptor (1 << 0) +#define CFXSealed (1 << 1) +#define CFXAcceptorSubkey (1 << 2) + +static krb5_error_code +wrap_length_cfx(krb5_crypto crypto, + int conf_req_flag, + size_t input_length, + size_t *output_length, + size_t *cksumsize, + u_int16_t *padlength) +{ + krb5_error_code ret; + krb5_cksumtype type; + + /* 16-byte header is always first */ + *output_length = sizeof(gss_cfx_wrap_token_desc); + *padlength = 0; + + ret = krb5_crypto_get_checksum_type(gssapi_krb5_context, crypto, &type); + if (ret) { + return ret; + } + + ret = krb5_checksumsize(gssapi_krb5_context, type, cksumsize); + if (ret) { + return ret; + } + + if (conf_req_flag) { + size_t padsize; + + /* Header is concatenated with data before encryption */ + input_length += sizeof(gss_cfx_wrap_token_desc); + + ret = krb5_crypto_getpadsize(gssapi_krb5_context, crypto, &padsize); + if (ret) { + return ret; + } + if (padsize > 1) { + /* XXX check this */ + *padlength = padsize - (input_length % padsize); + } + + /* We add the pad ourselves (noted here for completeness only) */ + input_length += *padlength; + + *output_length += krb5_get_wrapped_length(gssapi_krb5_context, + crypto, input_length); + } else { + /* Checksum is concatenated with data */ + *output_length += input_length + *cksumsize; + } + + assert(*output_length > input_length); + + return 0; +} + +OM_uint32 _gssapi_wrap_size_cfx(OM_uint32 *minor_status, + const gss_ctx_id_t context_handle, + int conf_req_flag, + gss_qop_t qop_req, + OM_uint32 req_output_size, + OM_uint32 *max_input_size, + krb5_keyblock *key) +{ + krb5_error_code ret; + krb5_crypto crypto; + u_int16_t padlength; + size_t output_length, cksumsize; + + ret = krb5_crypto_init(gssapi_krb5_context, key, 0, &crypto); + if (ret != 0) { + gssapi_krb5_set_error_string(); + *minor_status = ret; + return GSS_S_FAILURE; + } + + ret = wrap_length_cfx(crypto, conf_req_flag, + req_output_size, + &output_length, &cksumsize, &padlength); + if (ret != 0) { + gssapi_krb5_set_error_string(); + *minor_status = ret; + krb5_crypto_destroy(gssapi_krb5_context, crypto); + return GSS_S_FAILURE; + } + + if (output_length < req_output_size) { + *max_input_size = (req_output_size - output_length); + *max_input_size -= padlength; + } else { + /* Should this return an error? */ + *max_input_size = 0; + } + + krb5_crypto_destroy(gssapi_krb5_context, crypto); + + return GSS_S_COMPLETE; +} + +/* + * Rotate "rrc" bytes to the front or back + */ + +static krb5_error_code +rrc_rotate(void *data, size_t len, u_int16_t rrc, krb5_boolean unrotate) +{ + u_char *tmp; + size_t left; + char buf[256]; + + if (len == 0) + return 0; + + rrc %= len; + + if (rrc == 0) + return 0; + + left = len - rrc; + + if (rrc <= sizeof(buf)) { + tmp = buf; + } else { + tmp = malloc(rrc); + if (tmp == NULL) + return ENOMEM; + } + + if (unrotate) { + memcpy(tmp, data, rrc); + memmove(data, (u_char *)data + rrc, left); + memcpy((u_char *)data + left, tmp, rrc); + } else { + memcpy(tmp, (u_char *)data + left, rrc); + memmove((u_char *)data + rrc, data, left); + memcpy(data, tmp, rrc); + } + + if (rrc > sizeof(buf)) + free(tmp); + + return 0; +} + +OM_uint32 _gssapi_wrap_cfx(OM_uint32 *minor_status, + const gss_ctx_id_t context_handle, + 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, + krb5_keyblock *key) +{ + krb5_crypto crypto; + gss_cfx_wrap_token token; + krb5_error_code ret; + unsigned usage; + krb5_data cipher; + size_t wrapped_len, cksumsize; + u_int16_t padlength, rrc = 0; + OM_uint32 seq_number; + u_char *p; + + ret = krb5_crypto_init(gssapi_krb5_context, key, 0, &crypto); + if (ret != 0) { + gssapi_krb5_set_error_string(); + *minor_status = ret; + return GSS_S_FAILURE; + } + + ret = wrap_length_cfx(crypto, conf_req_flag, + input_message_buffer->length, + &wrapped_len, &cksumsize, &padlength); + if (ret != 0) { + gssapi_krb5_set_error_string(); + *minor_status = ret; + krb5_crypto_destroy(gssapi_krb5_context, crypto); + return GSS_S_FAILURE; + } + + /* Always rotate encrypted token (if any) and checksum to header */ + rrc = (conf_req_flag ? sizeof(*token) : 0) + (u_int16_t)cksumsize; + + output_message_buffer->length = wrapped_len; + output_message_buffer->value = malloc(output_message_buffer->length); + if (output_message_buffer->value == NULL) { + *minor_status = ENOMEM; + krb5_crypto_destroy(gssapi_krb5_context, crypto); + return GSS_S_FAILURE; + } + + p = output_message_buffer->value; + token = (gss_cfx_wrap_token)p; + token->TOK_ID[0] = 0x05; + token->TOK_ID[1] = 0x04; + token->Flags = 0; + token->Filler = 0xFF; + if ((context_handle->more_flags & LOCAL) == 0) + token->Flags |= CFXSentByAcceptor; + if (context_handle->more_flags & ACCEPTOR_SUBKEY) + token->Flags |= CFXAcceptorSubkey; + 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(&context_handle->ctx_id_mutex); + krb5_auth_con_getlocalseqnumber(gssapi_krb5_context, + context_handle->auth_context, + &seq_number); + gssapi_encode_be_om_uint32(0, &token->SND_SEQ[0]); + gssapi_encode_be_om_uint32(seq_number, &token->SND_SEQ[4]); + krb5_auth_con_setlocalseqnumber(gssapi_krb5_context, + context_handle->auth_context, + ++seq_number); + HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex); + + /* + * If confidentiality is requested, the token header is + * appended to the plaintext before encryption; the resulting + * token is {"header" | encrypt(plaintext | pad | "header")}. + * + * If no confidentiality is requested, the checksum is + * calculated over the plaintext concatenated with the + * token header. + */ + if (context_handle->more_flags & LOCAL) { + usage = KRB5_KU_USAGE_INITIATOR_SEAL; + } else { + usage = KRB5_KU_USAGE_ACCEPTOR_SEAL; + } + + if (conf_req_flag) { + /* + * Any necessary padding is added here to ensure that the + * encrypted token header is always at the end of the + * ciphertext. + * + * The specification does not require that the padding + * bytes are initialized. + */ + p += sizeof(*token); + memcpy(p, input_message_buffer->value, input_message_buffer->length); + memset(p + input_message_buffer->length, 0xFF, padlength); + memcpy(p + input_message_buffer->length + padlength, + token, sizeof(*token)); + + ret = krb5_encrypt(gssapi_krb5_context, crypto, + usage, p, + input_message_buffer->length + padlength + + sizeof(*token), + &cipher); + if (ret != 0) { + gssapi_krb5_set_error_string(); + *minor_status = ret; + krb5_crypto_destroy(gssapi_krb5_context, crypto); + gss_release_buffer(minor_status, output_message_buffer); + return GSS_S_FAILURE; + } + assert(sizeof(*token) + cipher.length == wrapped_len); + token->RRC[0] = (rrc >> 8) & 0xFF; + token->RRC[1] = (rrc >> 0) & 0xFF; + + ret = rrc_rotate(cipher.data, cipher.length, rrc, FALSE); + if (ret != 0) { + gssapi_krb5_set_error_string(); + *minor_status = ret; + krb5_crypto_destroy(gssapi_krb5_context, crypto); + gss_release_buffer(minor_status, output_message_buffer); + return GSS_S_FAILURE; + } + memcpy(p, cipher.data, cipher.length); + krb5_data_free(&cipher); + } else { + char *buf; + Checksum cksum; + + buf = malloc(input_message_buffer->length + sizeof(*token)); + if (buf == NULL) { + *minor_status = ENOMEM; + krb5_crypto_destroy(gssapi_krb5_context, crypto); + gss_release_buffer(minor_status, output_message_buffer); + return GSS_S_FAILURE; + } + memcpy(buf, input_message_buffer->value, input_message_buffer->length); + memcpy(buf + input_message_buffer->length, token, sizeof(*token)); + + ret = krb5_create_checksum(gssapi_krb5_context, crypto, + usage, 0, buf, + input_message_buffer->length + + sizeof(*token), + &cksum); + if (ret != 0) { + gssapi_krb5_set_error_string(); + *minor_status = ret; + krb5_crypto_destroy(gssapi_krb5_context, crypto); + gss_release_buffer(minor_status, output_message_buffer); + free(buf); + return GSS_S_FAILURE; + } + + free(buf); + + assert(cksum.checksum.length == cksumsize); + token->EC[0] = (cksum.checksum.length >> 8) & 0xFF; + token->EC[1] = (cksum.checksum.length >> 0) & 0xFF; + token->RRC[0] = (rrc >> 8) & 0xFF; + token->RRC[1] = (rrc >> 0) & 0xFF; + + p += sizeof(*token); + memcpy(p, input_message_buffer->value, input_message_buffer->length); + memcpy(p + input_message_buffer->length, + cksum.checksum.data, cksum.checksum.length); + + ret = rrc_rotate(p, + input_message_buffer->length + cksum.checksum.length, rrc, FALSE); + if (ret != 0) { + gssapi_krb5_set_error_string(); + *minor_status = ret; + krb5_crypto_destroy(gssapi_krb5_context, crypto); + gss_release_buffer(minor_status, output_message_buffer); + free_Checksum(&cksum); + return GSS_S_FAILURE; + } + free_Checksum(&cksum); + } + + krb5_crypto_destroy(gssapi_krb5_context, crypto); + + if (conf_state != NULL) { + *conf_state = conf_req_flag; + } + + *minor_status = 0; + return GSS_S_COMPLETE; +} + +OM_uint32 _gssapi_unwrap_cfx(OM_uint32 *minor_status, + const gss_ctx_id_t context_handle, + const gss_buffer_t input_message_buffer, + gss_buffer_t output_message_buffer, + int *conf_state, + gss_qop_t *qop_state, + krb5_keyblock *key) +{ + krb5_crypto crypto; + gss_cfx_wrap_token token; + u_char token_flags; + krb5_error_code ret; + unsigned usage; + krb5_data data; + u_int16_t ec, rrc; + OM_uint32 seq_number_lo, seq_number_hi; + size_t len; + u_char *p; + + *minor_status = 0; + + if (input_message_buffer->length < sizeof(*token)) { + return GSS_S_DEFECTIVE_TOKEN; + } + + p = input_message_buffer->value; + + token = (gss_cfx_wrap_token)p; + + 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 ((context_handle->more_flags & LOCAL) == 0) + return GSS_S_DEFECTIVE_TOKEN; + } + + if (context_handle->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 + */ + gssapi_decode_be_om_uint32(&token->SND_SEQ[0], &seq_number_hi); + gssapi_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(&context_handle->ctx_id_mutex); + ret = _gssapi_msg_order_check(context_handle->order, seq_number_lo); + if (ret != 0) { + *minor_status = 0; + HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex); + gss_release_buffer(minor_status, output_message_buffer); + return ret; + } + HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex); + + /* + * Decrypt and/or verify checksum + */ + ret = krb5_crypto_init(gssapi_krb5_context, key, 0, &crypto); + if (ret != 0) { + gssapi_krb5_set_error_string(); + *minor_status = ret; + return GSS_S_FAILURE; + } + + if (context_handle->more_flags & LOCAL) { + usage = KRB5_KU_USAGE_ACCEPTOR_SEAL; + } else { + usage = KRB5_KU_USAGE_INITIATOR_SEAL; + } + + p += sizeof(*token); + len = input_message_buffer->length; + len -= (p - (u_char *)input_message_buffer->value); + + /* Rotate by RRC; bogus to do this in-place XXX */ + *minor_status = rrc_rotate(p, len, rrc, TRUE); + if (*minor_status != 0) { + krb5_crypto_destroy(gssapi_krb5_context, crypto); + return GSS_S_FAILURE; + } + + if (token_flags & CFXSealed) { + ret = krb5_decrypt(gssapi_krb5_context, crypto, usage, + p, len, &data); + if (ret != 0) { + gssapi_krb5_set_error_string(); + *minor_status = ret; + krb5_crypto_destroy(gssapi_krb5_context, crypto); + return GSS_S_BAD_MIC; + } + + /* Check that there is room for the pad and token header */ + if (data.length < ec + sizeof(*token)) { + krb5_crypto_destroy(gssapi_krb5_context, crypto); + krb5_data_free(&data); + return GSS_S_DEFECTIVE_TOKEN; + } + p = data.data; + p += data.length - sizeof(*token); + + /* RRC is unprotected; don't modify input buffer */ + ((gss_cfx_wrap_token)p)->RRC[0] = token->RRC[0]; + ((gss_cfx_wrap_token)p)->RRC[1] = token->RRC[1]; + + /* Check the integrity of the header */ + if (memcmp(p, token, sizeof(*token)) != 0) { + krb5_crypto_destroy(gssapi_krb5_context, crypto); + krb5_data_free(&data); + return GSS_S_BAD_MIC; + } + + output_message_buffer->value = data.data; + output_message_buffer->length = data.length - ec - sizeof(*token); + } else { + Checksum cksum; + + /* Determine checksum type */ + ret = krb5_crypto_get_checksum_type(gssapi_krb5_context, + crypto, &cksum.cksumtype); + if (ret != 0) { + gssapi_krb5_set_error_string(); + *minor_status = ret; + krb5_crypto_destroy(gssapi_krb5_context, crypto); + return GSS_S_FAILURE; + } + + cksum.checksum.length = ec; + + /* Check we have at least as much data as the checksum */ + if (len < cksum.checksum.length) { + *minor_status = ERANGE; + krb5_crypto_destroy(gssapi_krb5_context, crypto); + return GSS_S_BAD_MIC; + } + + /* Length now is of the plaintext only, no checksum */ + len -= cksum.checksum.length; + cksum.checksum.data = p + len; + + output_message_buffer->length = len; /* for later */ + output_message_buffer->value = malloc(len + sizeof(*token)); + if (output_message_buffer->value == NULL) { + *minor_status = ENOMEM; + krb5_crypto_destroy(gssapi_krb5_context, crypto); + return GSS_S_FAILURE; + } + + /* Checksum is over (plaintext-data | "header") */ + memcpy(output_message_buffer->value, p, len); + memcpy((u_char *)output_message_buffer->value + len, + token, sizeof(*token)); + + /* EC is not included in checksum calculation */ + token = (gss_cfx_wrap_token)((u_char *)output_message_buffer->value + + len); + token->EC[0] = 0; + token->EC[1] = 0; + token->RRC[0] = 0; + token->RRC[1] = 0; + + ret = krb5_verify_checksum(gssapi_krb5_context, crypto, + usage, + output_message_buffer->value, + len + sizeof(*token), + &cksum); + if (ret != 0) { + gssapi_krb5_set_error_string(); + *minor_status = ret; + krb5_crypto_destroy(gssapi_krb5_context, crypto); + gss_release_buffer(minor_status, output_message_buffer); + return GSS_S_BAD_MIC; + } + } + + krb5_crypto_destroy(gssapi_krb5_context, crypto); + + if (qop_state != NULL) { + *qop_state = GSS_C_QOP_DEFAULT; + } + + *minor_status = 0; + return GSS_S_COMPLETE; +} + +OM_uint32 _gssapi_mic_cfx(OM_uint32 *minor_status, + const gss_ctx_id_t context_handle, + gss_qop_t qop_req, + const gss_buffer_t message_buffer, + gss_buffer_t message_token, + krb5_keyblock *key) +{ + krb5_crypto crypto; + gss_cfx_mic_token token; + krb5_error_code ret; + unsigned usage; + Checksum cksum; + u_char *buf; + size_t len; + OM_uint32 seq_number; + + ret = krb5_crypto_init(gssapi_krb5_context, key, 0, &crypto); + if (ret != 0) { + gssapi_krb5_set_error_string(); + *minor_status = ret; + return GSS_S_FAILURE; + } + + len = message_buffer->length + sizeof(*token); + buf = malloc(len); + if (buf == NULL) { + *minor_status = ENOMEM; + krb5_crypto_destroy(gssapi_krb5_context, crypto); + return GSS_S_FAILURE; + } + + memcpy(buf, message_buffer->value, message_buffer->length); + + token = (gss_cfx_mic_token)(buf + message_buffer->length); + token->TOK_ID[0] = 0x04; + token->TOK_ID[1] = 0x04; + token->Flags = 0; + if ((context_handle->more_flags & LOCAL) == 0) + token->Flags |= CFXSentByAcceptor; + if (context_handle->more_flags & ACCEPTOR_SUBKEY) + token->Flags |= CFXAcceptorSubkey; + memset(token->Filler, 0xFF, 5); + + HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex); + krb5_auth_con_getlocalseqnumber(gssapi_krb5_context, + context_handle->auth_context, + &seq_number); + gssapi_encode_be_om_uint32(0, &token->SND_SEQ[0]); + gssapi_encode_be_om_uint32(seq_number, &token->SND_SEQ[4]); + krb5_auth_con_setlocalseqnumber(gssapi_krb5_context, + context_handle->auth_context, + ++seq_number); + HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex); + + if (context_handle->more_flags & LOCAL) { + usage = KRB5_KU_USAGE_INITIATOR_SIGN; + } else { + usage = KRB5_KU_USAGE_ACCEPTOR_SIGN; + } + + ret = krb5_create_checksum(gssapi_krb5_context, crypto, + usage, 0, buf, len, &cksum); + if (ret != 0) { + gssapi_krb5_set_error_string(); + *minor_status = ret; + krb5_crypto_destroy(gssapi_krb5_context, crypto); + free(buf); + return GSS_S_FAILURE; + } + krb5_crypto_destroy(gssapi_krb5_context, crypto); + + /* Determine MIC length */ + message_token->length = sizeof(*token) + cksum.checksum.length; + message_token->value = malloc(message_token->length); + if (message_token->value == NULL) { + *minor_status = ENOMEM; + free_Checksum(&cksum); + free(buf); + return GSS_S_FAILURE; + } + + /* Token is { "header" | get_mic("header" | plaintext-data) } */ + memcpy(message_token->value, token, sizeof(*token)); + memcpy((u_char *)message_token->value + sizeof(*token), + cksum.checksum.data, cksum.checksum.length); + + free_Checksum(&cksum); + free(buf); + + *minor_status = 0; + return GSS_S_COMPLETE; +} + +OM_uint32 _gssapi_verify_mic_cfx(OM_uint32 *minor_status, + const gss_ctx_id_t context_handle, + const gss_buffer_t message_buffer, + const gss_buffer_t token_buffer, + gss_qop_t *qop_state, + krb5_keyblock *key) +{ + krb5_crypto crypto; + gss_cfx_mic_token token; + u_char token_flags; + krb5_error_code ret; + unsigned usage; + OM_uint32 seq_number_lo, seq_number_hi; + u_char *buf, *p; + Checksum cksum; + + *minor_status = 0; + + if (token_buffer->length < sizeof(*token)) { + return GSS_S_DEFECTIVE_TOKEN; + } + + p = token_buffer->value; + + token = (gss_cfx_mic_token)p; + + if (token->TOK_ID[0] != 0x04 || token->TOK_ID[1] != 0x04) { + return GSS_S_DEFECTIVE_TOKEN; + } + + /* Ignore unknown flags */ + token_flags = token->Flags & (CFXSentByAcceptor | CFXAcceptorSubkey); + + if (token_flags & CFXSentByAcceptor) { + if ((context_handle->more_flags & LOCAL) == 0) + return GSS_S_DEFECTIVE_TOKEN; + } + if (context_handle->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 (memcmp(token->Filler, "\xff\xff\xff\xff\xff", 5) != 0) { + return GSS_S_DEFECTIVE_TOKEN; + } + + /* + * Check sequence number + */ + gssapi_decode_be_om_uint32(&token->SND_SEQ[0], &seq_number_hi); + gssapi_decode_be_om_uint32(&token->SND_SEQ[4], &seq_number_lo); + if (seq_number_hi) { + *minor_status = ERANGE; + return GSS_S_UNSEQ_TOKEN; + } + + HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex); + ret = _gssapi_msg_order_check(context_handle->order, seq_number_lo); + if (ret != 0) { + *minor_status = 0; + HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex); + return ret; + } + HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex); + + /* + * Verify checksum + */ + ret = krb5_crypto_init(gssapi_krb5_context, key, 0, &crypto); + if (ret != 0) { + gssapi_krb5_set_error_string(); + *minor_status = ret; + return GSS_S_FAILURE; + } + + ret = krb5_crypto_get_checksum_type(gssapi_krb5_context, crypto, + &cksum.cksumtype); + if (ret != 0) { + gssapi_krb5_set_error_string(); + *minor_status = ret; + krb5_crypto_destroy(gssapi_krb5_context, crypto); + return GSS_S_FAILURE; + } + + cksum.checksum.data = p + sizeof(*token); + cksum.checksum.length = token_buffer->length - sizeof(*token); + + if (context_handle->more_flags & LOCAL) { + usage = KRB5_KU_USAGE_ACCEPTOR_SIGN; + } else { + usage = KRB5_KU_USAGE_INITIATOR_SIGN; + } + + buf = malloc(message_buffer->length + sizeof(*token)); + if (buf == NULL) { + *minor_status = ENOMEM; + krb5_crypto_destroy(gssapi_krb5_context, crypto); + return GSS_S_FAILURE; + } + memcpy(buf, message_buffer->value, message_buffer->length); + memcpy(buf + message_buffer->length, token, sizeof(*token)); + + ret = krb5_verify_checksum(gssapi_krb5_context, crypto, + usage, + buf, + sizeof(*token) + message_buffer->length, + &cksum); + if (ret != 0) { + gssapi_krb5_set_error_string(); + *minor_status = ret; + krb5_crypto_destroy(gssapi_krb5_context, crypto); + free(buf); + return GSS_S_BAD_MIC; + } + + free(buf); + + if (qop_state != NULL) { + *qop_state = GSS_C_QOP_DEFAULT; + } + + return GSS_S_COMPLETE; +} diff --git a/source4/heimdal/lib/gssapi/cfx.h b/source4/heimdal/lib/gssapi/cfx.h new file mode 100755 index 0000000000..a587cb9d97 --- /dev/null +++ b/source4/heimdal/lib/gssapi/cfx.h @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2003, PADL Software Pty Ltd. + * 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 PADL Software 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 PADL SOFTWARE 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 PADL SOFTWARE 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. + */ + +/* $Id: cfx.h,v 1.5 2003/09/22 21:48:35 lha Exp $ */ + +#ifndef GSSAPI_CFX_H_ +#define GSSAPI_CFX_H_ 1 + +/* + * Implementation of draft-ietf-krb-wg-gssapi-cfx-01.txt + */ + +typedef struct gss_cfx_mic_token_desc_struct { + u_char TOK_ID[2]; /* 04 04 */ + u_char Flags; + u_char Filler[5]; + u_char SND_SEQ[8]; +} gss_cfx_mic_token_desc, *gss_cfx_mic_token; + +typedef struct gss_cfx_wrap_token_desc_struct { + u_char TOK_ID[2]; /* 04 05 */ + u_char Flags; + u_char Filler; + u_char EC[2]; + u_char RRC[2]; + u_char SND_SEQ[8]; +} gss_cfx_wrap_token_desc, *gss_cfx_wrap_token; + +typedef struct gss_cfx_delete_token_desc_struct { + u_char TOK_ID[2]; /* 05 04 */ + u_char Flags; + u_char Filler[5]; + u_char SND_SEQ[8]; +} gss_cfx_delete_token_desc, *gss_cfx_delete_token; + +OM_uint32 _gssapi_wrap_size_cfx(OM_uint32 *minor_status, + const gss_ctx_id_t context_handle, + int conf_req_flag, + gss_qop_t qop_req, + OM_uint32 req_output_size, + OM_uint32 *max_input_size, + krb5_keyblock *key); + +OM_uint32 _gssapi_wrap_cfx(OM_uint32 *minor_status, + const gss_ctx_id_t context_handle, + 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, + krb5_keyblock *key); + +OM_uint32 _gssapi_unwrap_cfx(OM_uint32 *minor_status, + const gss_ctx_id_t context_handle, + const gss_buffer_t input_message_buffer, + gss_buffer_t output_message_buffer, + int *conf_state, + gss_qop_t *qop_state, + krb5_keyblock *key); + +OM_uint32 _gssapi_mic_cfx(OM_uint32 *minor_status, + const gss_ctx_id_t context_handle, + gss_qop_t qop_req, + const gss_buffer_t message_buffer, + gss_buffer_t message_token, + krb5_keyblock *key); + +OM_uint32 _gssapi_verify_mic_cfx(OM_uint32 *minor_status, + const gss_ctx_id_t context_handle, + const gss_buffer_t message_buffer, + const gss_buffer_t token_buffer, + gss_qop_t *qop_state, + krb5_keyblock *key); + +#endif /* GSSAPI_CFX_H_ */ diff --git a/source4/heimdal/lib/gssapi/compat.c b/source4/heimdal/lib/gssapi/compat.c new file mode 100644 index 0000000000..5605c48023 --- /dev/null +++ b/source4/heimdal/lib/gssapi/compat.c @@ -0,0 +1,154 @@ +/* + * Copyright (c) 2003 - 2005 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 "gssapi_locl.h" + +RCSID("$Id: compat.c,v 1.10 2005/05/30 20:51:51 lha Exp $"); + + +krb5_error_code +_gss_check_compat(OM_uint32 *minor_status, gss_name_t name, + const char *option, krb5_boolean *compat, + krb5_boolean match_val) +{ + krb5_error_code ret = 0; + char **p, **q; + krb5_principal match; + + + p = krb5_config_get_strings(gssapi_krb5_context, NULL, "gssapi", + option, NULL); + if(p == NULL) + return 0; + + match = NULL; + for(q = p; *q; q++) { + ret = krb5_parse_name(gssapi_krb5_context, *q, &match); + if (ret) + break; + + if (krb5_principal_match(gssapi_krb5_context, name, match)) { + *compat = match_val; + break; + } + + krb5_free_principal(gssapi_krb5_context, match); + match = NULL; + } + if (match) + krb5_free_principal(gssapi_krb5_context, match); + krb5_config_free_strings(p); + + if (ret) { + if (minor_status) + *minor_status = ret; + return GSS_S_FAILURE; + } + + return 0; +} + +/* + * ctx->ctx_id_mutex is assumed to be locked + */ + +OM_uint32 +_gss_DES3_get_mic_compat(OM_uint32 *minor_status, gss_ctx_id_t ctx) +{ + krb5_boolean use_compat = FALSE; + OM_uint32 ret; + + if ((ctx->more_flags & COMPAT_OLD_DES3_SELECTED) == 0) { + ret = _gss_check_compat(minor_status, ctx->target, + "broken_des3_mic", &use_compat, TRUE); + if (ret) + return ret; + ret = _gss_check_compat(minor_status, ctx->target, + "correct_des3_mic", &use_compat, FALSE); + if (ret) + return ret; + + if (use_compat) + ctx->more_flags |= COMPAT_OLD_DES3; + ctx->more_flags |= COMPAT_OLD_DES3_SELECTED; + } + return 0; +} + +OM_uint32 +gss_krb5_compat_des3_mic(OM_uint32 *minor_status, gss_ctx_id_t ctx, int on) +{ + *minor_status = 0; + + HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex); + if (on) { + ctx->more_flags |= COMPAT_OLD_DES3; + } else { + ctx->more_flags &= ~COMPAT_OLD_DES3; + } + ctx->more_flags |= COMPAT_OLD_DES3_SELECTED; + HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex); + + return 0; +} + +/* + * For compatability with the Windows SPNEGO implementation, the + * default is to ignore the mechListMIC unless the initiator specified + * CFX or configured in krb5.conf with the option + * [gssapi]require_mechlist_mic=target-principal-pattern. + * The option is valid for both initiator and acceptor. + */ +OM_uint32 +_gss_spnego_require_mechlist_mic(OM_uint32 *minor_status, + gss_ctx_id_t ctx, + krb5_boolean *require_mic) +{ + OM_uint32 ret; + int is_cfx = 0; + + gsskrb5_is_cfx(ctx, &is_cfx); + if (is_cfx) { + /* CFX session key was used */ + *require_mic = TRUE; + } else { + *require_mic = FALSE; + ret = _gss_check_compat(minor_status, ctx->target, + "require_mechlist_mic", + require_mic, TRUE); + if (ret) + return ret; + } + *minor_status = 0; + return GSS_S_COMPLETE; +} diff --git a/source4/heimdal/lib/gssapi/context_time.c b/source4/heimdal/lib/gssapi/context_time.c new file mode 100644 index 0000000000..e13480c85e --- /dev/null +++ b/source4/heimdal/lib/gssapi/context_time.c @@ -0,0 +1,87 @@ +/* + * Copyright (c) 1997 - 2003 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 "gssapi_locl.h" + +RCSID("$Id: context_time.c,v 1.10 2003/06/03 15:08:00 lha Exp $"); + +OM_uint32 +gssapi_lifetime_left(OM_uint32 *minor_status, + OM_uint32 lifetime, + OM_uint32 *lifetime_rec) +{ + krb5_timestamp timeret; + krb5_error_code kret; + + kret = krb5_timeofday(gssapi_krb5_context, &timeret); + if (kret) { + *minor_status = kret; + gssapi_krb5_set_error_string (); + return GSS_S_FAILURE; + } + + if (lifetime < timeret) + *lifetime_rec = 0; + else + *lifetime_rec = lifetime - timeret; + + return GSS_S_COMPLETE; +} + + +OM_uint32 gss_context_time + (OM_uint32 * minor_status, + const gss_ctx_id_t context_handle, + OM_uint32 * time_rec + ) +{ + OM_uint32 lifetime; + OM_uint32 major_status; + + GSSAPI_KRB5_INIT (); + + HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex); + lifetime = context_handle->lifetime; + HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex); + + major_status = gssapi_lifetime_left(minor_status, lifetime, time_rec); + if (major_status != GSS_S_COMPLETE) + return major_status; + + *minor_status = 0; + + if (*time_rec == 0) + return GSS_S_CONTEXT_EXPIRED; + + return GSS_S_COMPLETE; +} diff --git a/source4/heimdal/lib/gssapi/copy_ccache.c b/source4/heimdal/lib/gssapi/copy_ccache.c new file mode 100644 index 0000000000..4f2b3f4895 --- /dev/null +++ b/source4/heimdal/lib/gssapi/copy_ccache.c @@ -0,0 +1,134 @@ +/* + * Copyright (c) 2000 - 2001, 2003 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 "gssapi_locl.h" + +RCSID("$Id: copy_ccache.c,v 1.7 2003/09/01 15:11:09 lha Exp $"); + +OM_uint32 +gss_krb5_copy_ccache(OM_uint32 *minor_status, + gss_cred_id_t cred, + krb5_ccache out) +{ + krb5_error_code kret; + + HEIMDAL_MUTEX_lock(&cred->cred_id_mutex); + + if (cred->ccache == NULL) { + HEIMDAL_MUTEX_unlock(&cred->cred_id_mutex); + *minor_status = EINVAL; + return GSS_S_FAILURE; + } + + kret = krb5_cc_copy_cache(gssapi_krb5_context, cred->ccache, out); + HEIMDAL_MUTEX_unlock(&cred->cred_id_mutex); + if (kret) { + *minor_status = kret; + gssapi_krb5_set_error_string (); + return GSS_S_FAILURE; + } + *minor_status = 0; + return GSS_S_COMPLETE; +} + +OM_uint32 +gsskrb5_extract_authz_data_from_sec_context(OM_uint32 *minor_status, + gss_ctx_id_t context_handle, + int ad_type, + gss_buffer_t ad_data) +{ + krb5_error_code ret; + krb5_data data; + + ad_data->value = NULL; + ad_data->length = 0; + + HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex); + if (context_handle->ticket == NULL) { + HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex); + *minor_status = EINVAL; + return GSS_S_FAILURE; + } + + ret = krb5_ticket_get_authorization_data_type(gssapi_krb5_context, + context_handle->ticket, + ad_type, + &data); + HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex); + if (ret) { + *minor_status = ret; + return GSS_S_FAILURE; + } + + ad_data->value = malloc(data.length); + if (ad_data->value == NULL) { + krb5_data_free(&data); + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + + ad_data->length = data.length; + memcpy(ad_data->value, data.data, ad_data->length); + krb5_data_free(&data); + + *minor_status = 0; + return GSS_S_COMPLETE; +} + +OM_uint32 gss_krb5_copy_service_keyblock + (OM_uint32 *minor_status, + gss_ctx_id_t context_handle, + struct EncryptionKey **out) +{ + krb5_error_code ret; + + HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex); + if (context_handle->service_keyblock == NULL) { + HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex); + *minor_status = EINVAL; + return GSS_S_FAILURE; + } + + ret = krb5_copy_keyblock(gssapi_krb5_context, + context_handle->service_keyblock, + out); + + HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex); + if (ret) { + *minor_status = ret; + return GSS_S_FAILURE; + } + + *minor_status = 0; + return GSS_S_COMPLETE; +} diff --git a/source4/heimdal/lib/gssapi/create_emtpy_oid_set.c b/source4/heimdal/lib/gssapi/create_emtpy_oid_set.c new file mode 100644 index 0000000000..1a25e0d781 --- /dev/null +++ b/source4/heimdal/lib/gssapi/create_emtpy_oid_set.c @@ -0,0 +1,52 @@ +/* + * Copyright (c) 1997 - 2001, 2003 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 "gssapi_locl.h" + +RCSID("$Id: create_emtpy_oid_set.c,v 1.5 2003/03/16 17:47:07 lha Exp $"); + +OM_uint32 gss_create_empty_oid_set ( + OM_uint32 * minor_status, + gss_OID_set * oid_set + ) +{ + *oid_set = malloc(sizeof(**oid_set)); + if (*oid_set == NULL) { + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + (*oid_set)->count = 0; + (*oid_set)->elements = NULL; + *minor_status = 0; + return GSS_S_COMPLETE; +} diff --git a/source4/heimdal/lib/gssapi/decapsulate.c b/source4/heimdal/lib/gssapi/decapsulate.c new file mode 100644 index 0000000000..90e037f09b --- /dev/null +++ b/source4/heimdal/lib/gssapi/decapsulate.c @@ -0,0 +1,209 @@ +/* + * Copyright (c) 1997 - 2001 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 "gssapi_locl.h" + +RCSID("$Id: decapsulate.c,v 1.12 2005/06/16 20:40:49 lha Exp $"); + +/* + * return the length of the mechanism in token or -1 + * (which implies that the token was bad - GSS_S_DEFECTIVE_TOKEN + */ + +ssize_t +gssapi_krb5_get_mech (const u_char *ptr, + size_t total_len, + const u_char **mech_ret) +{ + size_t len, len_len, mech_len, foo; + const u_char *p = ptr; + int e; + + if (total_len < 1) + return -1; + if (*p++ != 0x60) + return -1; + e = der_get_length (p, total_len - 1, &len, &len_len); + if (e || 1 + len_len + len != total_len) + return -1; + p += len_len; + if (*p++ != 0x06) + return -1; + e = der_get_length (p, total_len - 1 - len_len - 1, + &mech_len, &foo); + if (e) + return -1; + p += foo; + *mech_ret = p; + return mech_len; +} + +OM_uint32 +_gssapi_verify_mech_header(u_char **str, + size_t total_len, + gss_OID mech) +{ + const u_char *p; + ssize_t mech_len; + + mech_len = gssapi_krb5_get_mech (*str, total_len, &p); + if (mech_len < 0) + return GSS_S_DEFECTIVE_TOKEN; + + if (mech_len != mech->length) + return GSS_S_BAD_MECH; + if (memcmp(p, + mech->elements, + mech->length) != 0) + return GSS_S_BAD_MECH; + p += mech_len; + *str = rk_UNCONST(p); + return GSS_S_COMPLETE; +} + +OM_uint32 +gssapi_krb5_verify_header(u_char **str, + size_t total_len, + const u_char *type, + gss_OID oid) +{ + OM_uint32 ret; + size_t len; + u_char *p = *str; + + ret = _gssapi_verify_mech_header(str, total_len, oid); + if (ret) + return ret; + + len = total_len - (*str - p); + + if (len < 2) + return GSS_S_DEFECTIVE_TOKEN; + + if (memcmp (*str, type, 2) != 0) + return GSS_S_DEFECTIVE_TOKEN; + *str += 2; + + return 0; +} + +/* + * Remove the GSS-API wrapping from `in_token' giving `out_data. + * Does not copy data, so just free `in_token'. + */ + +OM_uint32 +_gssapi_decapsulate( + OM_uint32 *minor_status, + gss_buffer_t input_token_buffer, + krb5_data *out_data, + const gss_OID mech +) +{ + u_char *p; + OM_uint32 ret; + + p = input_token_buffer->value; + ret = _gssapi_verify_mech_header(&p, + input_token_buffer->length, + mech); + if (ret) { + *minor_status = 0; + return ret; + } + + out_data->length = input_token_buffer->length - + (p - (u_char *)input_token_buffer->value); + out_data->data = p; + return GSS_S_COMPLETE; +} + +/* + * Remove the GSS-API wrapping from `in_token' giving `out_data. + * Does not copy data, so just free `in_token'. + */ + +OM_uint32 +gssapi_krb5_decapsulate(OM_uint32 *minor_status, + gss_buffer_t input_token_buffer, + krb5_data *out_data, + const char *type, + gss_OID oid) +{ + u_char *p; + OM_uint32 ret; + + p = input_token_buffer->value; + ret = gssapi_krb5_verify_header(&p, + input_token_buffer->length, + type, + oid); + if (ret) { + *minor_status = 0; + return ret; + } + + out_data->length = input_token_buffer->length - + (p - (u_char *)input_token_buffer->value); + out_data->data = p; + return GSS_S_COMPLETE; +} + +/* + * Verify padding of a gss wrapped message and return its length. + */ + +OM_uint32 +_gssapi_verify_pad(gss_buffer_t wrapped_token, + size_t datalen, + size_t *padlen) +{ + u_char *pad; + size_t padlength; + int i; + + pad = (u_char *)wrapped_token->value + wrapped_token->length - 1; + padlength = *pad; + + if (padlength > datalen) + return GSS_S_BAD_MECH; + + for (i = padlength; i > 0 && *pad == padlength; i--, pad--) + ; + if (i != 0) + return GSS_S_BAD_MIC; + + *padlen = padlength; + + return 0; +} diff --git a/source4/heimdal/lib/gssapi/delete_sec_context.c b/source4/heimdal/lib/gssapi/delete_sec_context.c new file mode 100644 index 0000000000..83658fa76c --- /dev/null +++ b/source4/heimdal/lib/gssapi/delete_sec_context.c @@ -0,0 +1,77 @@ +/* + * Copyright (c) 1997 - 2003 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 "gssapi_locl.h" + +RCSID("$Id: delete_sec_context.c,v 1.15 2005/04/27 17:48:17 lha Exp $"); + +OM_uint32 gss_delete_sec_context + (OM_uint32 * minor_status, + gss_ctx_id_t * context_handle, + gss_buffer_t output_token + ) +{ + GSSAPI_KRB5_INIT (); + + if (output_token) { + output_token->length = 0; + output_token->value = NULL; + } + + HEIMDAL_MUTEX_lock(&(*context_handle)->ctx_id_mutex); + + krb5_auth_con_free (gssapi_krb5_context, + (*context_handle)->auth_context); + if((*context_handle)->source) + krb5_free_principal (gssapi_krb5_context, + (*context_handle)->source); + if((*context_handle)->target) + krb5_free_principal (gssapi_krb5_context, + (*context_handle)->target); + if ((*context_handle)->ticket) + krb5_free_ticket (gssapi_krb5_context, + (*context_handle)->ticket); + if ((*context_handle)->service_keyblock) + krb5_free_keyblock (gssapi_krb5_context, + (*context_handle)->service_keyblock); + if((*context_handle)->order) + _gssapi_msg_order_destroy(&(*context_handle)->order); + + HEIMDAL_MUTEX_unlock(&(*context_handle)->ctx_id_mutex); + HEIMDAL_MUTEX_destroy(&(*context_handle)->ctx_id_mutex); + memset(*context_handle, 0, sizeof(**context_handle)); + free (*context_handle); + *context_handle = GSS_C_NO_CONTEXT; + *minor_status = 0; + return GSS_S_COMPLETE; +} diff --git a/source4/heimdal/lib/gssapi/display_name.c b/source4/heimdal/lib/gssapi/display_name.c new file mode 100644 index 0000000000..27a232fd3c --- /dev/null +++ b/source4/heimdal/lib/gssapi/display_name.c @@ -0,0 +1,73 @@ +/* + * Copyright (c) 1997 - 2003 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 "gssapi_locl.h" + +RCSID("$Id: display_name.c,v 1.9 2003/03/16 17:46:11 lha Exp $"); + +OM_uint32 gss_display_name + (OM_uint32 * minor_status, + const gss_name_t input_name, + gss_buffer_t output_name_buffer, + gss_OID * output_name_type + ) +{ + krb5_error_code kret; + char *buf; + size_t len; + + GSSAPI_KRB5_INIT (); + kret = krb5_unparse_name (gssapi_krb5_context, + input_name, + &buf); + if (kret) { + *minor_status = kret; + gssapi_krb5_set_error_string (); + return GSS_S_FAILURE; + } + len = strlen (buf); + output_name_buffer->length = len; + output_name_buffer->value = malloc(len + 1); + if (output_name_buffer->value == NULL) { + free (buf); + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + memcpy (output_name_buffer->value, buf, len); + ((char *)output_name_buffer->value)[len] = '\0'; + free (buf); + if (output_name_type) + *output_name_type = GSS_KRB5_NT_PRINCIPAL_NAME; + *minor_status = 0; + return GSS_S_COMPLETE; +} diff --git a/source4/heimdal/lib/gssapi/display_status.c b/source4/heimdal/lib/gssapi/display_status.c new file mode 100644 index 0000000000..2c84628266 --- /dev/null +++ b/source4/heimdal/lib/gssapi/display_status.c @@ -0,0 +1,208 @@ +/* + * Copyright (c) 1998 - 2005 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 "gssapi_locl.h" + +RCSID("$Id: display_status.c,v 1.12 2005/03/16 13:15:03 lha Exp $"); + +static char * +calling_error(OM_uint32 v) +{ + static char *msgs[] = { + NULL, /* 0 */ + "A required input parameter could not be read.", /* */ + "A required output parameter could not be written.", /* */ + "A parameter was malformed" + }; + + v >>= GSS_C_CALLING_ERROR_OFFSET; + + if (v == 0) + return ""; + else if (v >= sizeof(msgs)/sizeof(*msgs)) + return "unknown calling error"; + else + return msgs[v]; +} + +static char * +routine_error(OM_uint32 v) +{ + static char *msgs[] = { + NULL, /* 0 */ + "An unsupported mechanism was requested", + "An invalid name was supplied", + "A supplied name was of an unsupported type", + "Incorrect channel bindings were supplied", + "An invalid status code was supplied", + "A token had an invalid MIC", + "No credentials were supplied, " + "or the credentials were unavailable or inaccessible.", + "No context has been established", + "A token was invalid", + "A credential was invalid", + "The referenced credentials have expired", + "The context has expired", + "Miscellaneous failure (see text)", + "The quality-of-protection requested could not be provide", + "The operation is forbidden by local security policy", + "The operation or option is not available", + "The requested credential element already exists", + "The provided name was not a mechanism name.", + }; + + v >>= GSS_C_ROUTINE_ERROR_OFFSET; + + if (v == 0) + return ""; + else if (v >= sizeof(msgs)/sizeof(*msgs)) + return "unknown routine error"; + else + return msgs[v]; +} + +static char * +supplementary_error(OM_uint32 v) +{ + static char *msgs[] = { + "normal completion", + "continuation call to routine required", + "duplicate per-message token detected", + "timed-out per-message token detected", + "reordered (early) per-message token detected", + "skipped predecessor token(s) detected" + }; + + v >>= GSS_C_SUPPLEMENTARY_OFFSET; + + if (v >= sizeof(msgs)/sizeof(*msgs)) + return "unknown routine error"; + else + return msgs[v]; +} + +void +gssapi_krb5_set_error_string (void) +{ + struct gssapi_thr_context *ctx = gssapi_get_thread_context(1); + char *e; + + if (ctx == NULL) + return; + HEIMDAL_MUTEX_lock(&ctx->mutex); + if (ctx->error_string) + free(ctx->error_string); + e = krb5_get_error_string(gssapi_krb5_context); + if (e == NULL) + ctx->error_string = NULL; + else { + /* ignore failures, will use status code instead */ + ctx->error_string = strdup(e); + krb5_free_error_string(gssapi_krb5_context, e); + } + HEIMDAL_MUTEX_unlock(&ctx->mutex); +} + +char * +gssapi_krb5_get_error_string (void) +{ + struct gssapi_thr_context *ctx = gssapi_get_thread_context(0); + char *ret; + + if (ctx == NULL) + return NULL; + HEIMDAL_MUTEX_lock(&ctx->mutex); + ret = ctx->error_string; + ctx->error_string = NULL; + HEIMDAL_MUTEX_unlock(&ctx->mutex); + return ret; +} + +OM_uint32 gss_display_status + (OM_uint32 *minor_status, + OM_uint32 status_value, + int status_type, + const gss_OID mech_type, + OM_uint32 *message_context, + gss_buffer_t status_string) +{ + char *buf; + + GSSAPI_KRB5_INIT (); + + status_string->length = 0; + status_string->value = NULL; + + if (gss_oid_equal(mech_type, GSS_C_NO_OID) == 0 && + gss_oid_equal(mech_type, GSS_KRB5_MECHANISM) == 0) { + *minor_status = 0; + return GSS_C_GSS_CODE; + } + + if (status_type == GSS_C_GSS_CODE) { + if (GSS_SUPPLEMENTARY_INFO(status_value)) + asprintf(&buf, "%s", + supplementary_error(GSS_SUPPLEMENTARY_INFO(status_value))); + else + asprintf (&buf, "%s %s", + calling_error(GSS_CALLING_ERROR(status_value)), + routine_error(GSS_ROUTINE_ERROR(status_value))); + } else if (status_type == GSS_C_MECH_CODE) { + buf = gssapi_krb5_get_error_string (); + if (buf == NULL) { + const char *tmp = krb5_get_err_text (gssapi_krb5_context, + status_value); + if (tmp == NULL) + asprintf(&buf, "unknown mech error-code %u", + (unsigned)status_value); + else + buf = strdup(tmp); + } + } else { + *minor_status = EINVAL; + return GSS_S_BAD_STATUS; + } + + if (buf == NULL) { + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + + *message_context = 0; + *minor_status = 0; + + status_string->length = strlen(buf); + status_string->value = buf; + + return GSS_S_COMPLETE; +} diff --git a/source4/heimdal/lib/gssapi/duplicate_name.c b/source4/heimdal/lib/gssapi/duplicate_name.c new file mode 100644 index 0000000000..2b54e90ec8 --- /dev/null +++ b/source4/heimdal/lib/gssapi/duplicate_name.c @@ -0,0 +1,59 @@ +/* + * Copyright (c) 1997 - 2003 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 "gssapi_locl.h" + +RCSID("$Id: duplicate_name.c,v 1.7 2003/03/16 17:44:26 lha Exp $"); + +OM_uint32 gss_duplicate_name ( + OM_uint32 * minor_status, + const gss_name_t src_name, + gss_name_t * dest_name + ) +{ + krb5_error_code kret; + + GSSAPI_KRB5_INIT (); + + kret = krb5_copy_principal (gssapi_krb5_context, + src_name, + dest_name); + if (kret) { + *minor_status = kret; + gssapi_krb5_set_error_string (); + return GSS_S_FAILURE; + } else { + *minor_status = 0; + return GSS_S_COMPLETE; + } +} diff --git a/source4/heimdal/lib/gssapi/encapsulate.c b/source4/heimdal/lib/gssapi/encapsulate.c new file mode 100644 index 0000000000..4d488a6c42 --- /dev/null +++ b/source4/heimdal/lib/gssapi/encapsulate.c @@ -0,0 +1,153 @@ +/* + * Copyright (c) 1997 - 2003 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 "gssapi_locl.h" + +RCSID("$Id: encapsulate.c,v 1.8 2003/09/04 18:08:55 lha Exp $"); + +void +_gssapi_encap_length (size_t data_len, + size_t *len, + size_t *total_len, + const gss_OID mech) +{ + size_t len_len; + + *len = 1 + 1 + mech->length + data_len; + + len_len = length_len(*len); + + *total_len = 1 + len_len + *len; +} + +void +gssapi_krb5_encap_length (size_t data_len, + size_t *len, + size_t *total_len, + const gss_OID mech) +{ + _gssapi_encap_length(data_len + 2, len, total_len, mech); +} + +u_char * +gssapi_krb5_make_header (u_char *p, + size_t len, + const u_char *type, + const gss_OID mech) +{ + p = _gssapi_make_mech_header(p, len, mech); + memcpy (p, type, 2); + p += 2; + return p; +} + +u_char * +_gssapi_make_mech_header(u_char *p, + size_t len, + const gss_OID mech) +{ + int e; + size_t len_len, foo; + + *p++ = 0x60; + len_len = length_len(len); + e = der_put_length (p + len_len - 1, len_len, len, &foo); + if(e || foo != len_len) + abort (); + p += len_len; + *p++ = 0x06; + *p++ = mech->length; + memcpy (p, mech->elements, mech->length); + p += mech->length; + return p; +} + +/* + * Give it a krb5_data and it will encapsulate with extra GSS-API wrappings. + */ + +OM_uint32 +_gssapi_encapsulate( + OM_uint32 *minor_status, + const krb5_data *in_data, + gss_buffer_t output_token, + const gss_OID mech +) +{ + size_t len, outer_len; + u_char *p; + + _gssapi_encap_length (in_data->length, &len, &outer_len, mech); + + output_token->length = outer_len; + output_token->value = malloc (outer_len); + if (output_token->value == NULL) { + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + + p = _gssapi_make_mech_header (output_token->value, len, mech); + memcpy (p, in_data->data, in_data->length); + return GSS_S_COMPLETE; +} + +/* + * Give it a krb5_data and it will encapsulate with extra GSS-API krb5 + * wrappings. + */ + +OM_uint32 +gssapi_krb5_encapsulate( + OM_uint32 *minor_status, + const krb5_data *in_data, + gss_buffer_t output_token, + const u_char *type, + const gss_OID mech +) +{ + size_t len, outer_len; + u_char *p; + + gssapi_krb5_encap_length (in_data->length, &len, &outer_len, mech); + + output_token->length = outer_len; + output_token->value = malloc (outer_len); + if (output_token->value == NULL) { + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + + p = gssapi_krb5_make_header (output_token->value, len, type, mech); + memcpy (p, in_data->data, in_data->length); + return GSS_S_COMPLETE; +} diff --git a/source4/heimdal/lib/gssapi/external.c b/source4/heimdal/lib/gssapi/external.c new file mode 100644 index 0000000000..f3e97181e6 --- /dev/null +++ b/source4/heimdal/lib/gssapi/external.c @@ -0,0 +1,270 @@ +/* + * Copyright (c) 1997 - 2000 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 "gssapi_locl.h" + +RCSID("$Id: external.c,v 1.6 2003/09/08 15:34:19 lha Exp $"); + +/* + * The implementation must reserve static storage for a + * gss_OID_desc object containing the value + * {10, (void *)"\x2a\x86\x48\x86\xf7\x12" + * "\x01\x02\x01\x01"}, + * corresponding to an object-identifier value of + * {iso(1) member-body(2) United States(840) mit(113554) + * infosys(1) gssapi(2) generic(1) user_name(1)}. The constant + * GSS_C_NT_USER_NAME should be initialized to point + * to that gss_OID_desc. + */ + +static gss_OID_desc gss_c_nt_user_name_oid_desc = +{10, (void *)"\x2a\x86\x48\x86\xf7\x12" + "\x01\x02\x01\x01"}; + +gss_OID GSS_C_NT_USER_NAME = &gss_c_nt_user_name_oid_desc; + +/* + * The implementation must reserve static storage for a + * gss_OID_desc object containing the value + * {10, (void *)"\x2a\x86\x48\x86\xf7\x12" + * "\x01\x02\x01\x02"}, + * corresponding to an object-identifier value of + * {iso(1) member-body(2) United States(840) mit(113554) + * infosys(1) gssapi(2) generic(1) machine_uid_name(2)}. + * The constant GSS_C_NT_MACHINE_UID_NAME should be + * initialized to point to that gss_OID_desc. + */ + +static gss_OID_desc gss_c_nt_machine_uid_name_oid_desc = +{10, (void *)"\x2a\x86\x48\x86\xf7\x12" + "\x01\x02\x01\x02"}; + +gss_OID GSS_C_NT_MACHINE_UID_NAME = &gss_c_nt_machine_uid_name_oid_desc; + +/* + * The implementation must reserve static storage for a + * gss_OID_desc object containing the value + * {10, (void *)"\x2a\x86\x48\x86\xf7\x12" + * "\x01\x02\x01\x03"}, + * corresponding to an object-identifier value of + * {iso(1) member-body(2) United States(840) mit(113554) + * infosys(1) gssapi(2) generic(1) string_uid_name(3)}. + * The constant GSS_C_NT_STRING_UID_NAME should be + * initialized to point to that gss_OID_desc. + */ + +static gss_OID_desc gss_c_nt_string_uid_name_oid_desc = +{10, (void *)"\x2a\x86\x48\x86\xf7\x12" + "\x01\x02\x01\x03"}; + +gss_OID GSS_C_NT_STRING_UID_NAME = &gss_c_nt_string_uid_name_oid_desc; + +/* + * The implementation must reserve static storage for a + * gss_OID_desc object containing the value + * {6, (void *)"\x2b\x06\x01\x05\x06\x02"}, + * corresponding to an object-identifier value of + * {iso(1) org(3) dod(6) internet(1) security(5) + * nametypes(6) gss-host-based-services(2)). The constant + * GSS_C_NT_HOSTBASED_SERVICE_X should be initialized to point + * to that gss_OID_desc. This is a deprecated OID value, and + * implementations wishing to support hostbased-service names + * should instead use the GSS_C_NT_HOSTBASED_SERVICE OID, + * defined below, to identify such names; + * GSS_C_NT_HOSTBASED_SERVICE_X should be accepted a synonym + * for GSS_C_NT_HOSTBASED_SERVICE when presented as an input + * parameter, but should not be emitted by GSS-API + * implementations + */ + +static gss_OID_desc gss_c_nt_hostbased_service_x_oid_desc = +{6, (void *)"\x2b\x06\x01\x05\x06\x02"}; + +gss_OID GSS_C_NT_HOSTBASED_SERVICE_X = &gss_c_nt_hostbased_service_x_oid_desc; + +/* + * The implementation must reserve static storage for a + * gss_OID_desc object containing the value + * {10, (void *)"\x2a\x86\x48\x86\xf7\x12" + * "\x01\x02\x01\x04"}, corresponding to an + * object-identifier value of {iso(1) member-body(2) + * Unites States(840) mit(113554) infosys(1) gssapi(2) + * generic(1) service_name(4)}. The constant + * GSS_C_NT_HOSTBASED_SERVICE should be initialized + * to point to that gss_OID_desc. + */ +static gss_OID_desc gss_c_nt_hostbased_service_oid_desc = +{10, (void *)"\x2a\x86\x48\x86\xf7\x12" "\x01\x02\x01\x04"}; + +gss_OID GSS_C_NT_HOSTBASED_SERVICE = &gss_c_nt_hostbased_service_oid_desc; + +/* + * The implementation must reserve static storage for a + * gss_OID_desc object containing the value + * {6, (void *)"\x2b\x06\01\x05\x06\x03"}, + * corresponding to an object identifier value of + * {1(iso), 3(org), 6(dod), 1(internet), 5(security), + * 6(nametypes), 3(gss-anonymous-name)}. The constant + * and GSS_C_NT_ANONYMOUS should be initialized to point + * to that gss_OID_desc. + */ + +static gss_OID_desc gss_c_nt_anonymous_oid_desc = +{6, (void *)"\x2b\x06\01\x05\x06\x03"}; + +gss_OID GSS_C_NT_ANONYMOUS = &gss_c_nt_anonymous_oid_desc; + +/* + * The implementation must reserve static storage for a + * gss_OID_desc object containing the value + * {6, (void *)"\x2b\x06\x01\x05\x06\x04"}, + * corresponding to an object-identifier value of + * {1(iso), 3(org), 6(dod), 1(internet), 5(security), + * 6(nametypes), 4(gss-api-exported-name)}. The constant + * GSS_C_NT_EXPORT_NAME should be initialized to point + * to that gss_OID_desc. + */ + +static gss_OID_desc gss_c_nt_export_name_oid_desc = +{6, (void *)"\x2b\x06\x01\x05\x06\x04"}; + +gss_OID GSS_C_NT_EXPORT_NAME = &gss_c_nt_export_name_oid_desc; + +/* + * This name form shall be represented by the Object Identifier {iso(1) + * member-body(2) United States(840) mit(113554) infosys(1) gssapi(2) + * krb5(2) krb5_name(1)}. The recommended symbolic name for this type + * is "GSS_KRB5_NT_PRINCIPAL_NAME". + */ + +static gss_OID_desc gss_krb5_nt_principal_name_oid_desc = +{10, (void *)"\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x01"}; + +gss_OID GSS_KRB5_NT_PRINCIPAL_NAME = &gss_krb5_nt_principal_name_oid_desc; + +/* + * This name form shall be represented by the Object Identifier {iso(1) + * member-body(2) United States(840) mit(113554) infosys(1) gssapi(2) + * generic(1) user_name(1)}. The recommended symbolic name for this + * type is "GSS_KRB5_NT_USER_NAME". + */ + +gss_OID GSS_KRB5_NT_USER_NAME = &gss_c_nt_user_name_oid_desc; + +/* + * This name form shall be represented by the Object Identifier {iso(1) + * member-body(2) United States(840) mit(113554) infosys(1) gssapi(2) + * generic(1) machine_uid_name(2)}. The recommended symbolic name for + * this type is "GSS_KRB5_NT_MACHINE_UID_NAME". + */ + +gss_OID GSS_KRB5_NT_MACHINE_UID_NAME = &gss_c_nt_machine_uid_name_oid_desc; + +/* + * This name form shall be represented by the Object Identifier {iso(1) + * member-body(2) United States(840) mit(113554) infosys(1) gssapi(2) + * generic(1) string_uid_name(3)}. The recommended symbolic name for + * this type is "GSS_KRB5_NT_STRING_UID_NAME". + */ + +gss_OID GSS_KRB5_NT_STRING_UID_NAME = &gss_c_nt_string_uid_name_oid_desc; + +/* + * To support ongoing experimentation, testing, and evolution of the + * specification, the Kerberos V5 GSS-API mechanism as defined in this + * and any successor memos will be identified with the following Object + * Identifier, as defined in RFC-1510, until the specification is + * advanced to the level of Proposed Standard RFC: + * + * {iso(1), org(3), dod(5), internet(1), security(5), kerberosv5(2)} + * + * Upon advancement to the level of Proposed Standard RFC, the Kerberos + * V5 GSS-API mechanism will be identified by an Object Identifier + * having the value: + * + * {iso(1) member-body(2) United States(840) mit(113554) infosys(1) + * gssapi(2) krb5(2)} + */ + +#if 0 /* This is the old OID */ + +static gss_OID_desc gss_krb5_mechanism_oid_desc = +{5, (void *)"\x2b\x05\x01\x05\x02"}; + +#endif + +static gss_OID_desc gss_krb5_mechanism_oid_desc = +{9, (void *)"\x2a\x86\x48\x86\xf7\x12\x01\x02\x02"}; + +gss_OID GSS_KRB5_MECHANISM = &gss_krb5_mechanism_oid_desc; + +/* + * RFC2478, SPNEGO: + * The security mechanism of the initial + * negotiation token is identified by the Object Identifier + * iso.org.dod.internet.security.mechanism.snego (1.3.6.1.5.5.2). + */ + +static gss_OID_desc gss_spnego_mechanism_oid_desc = +{6, (void *)"\x2b\x06\x01\x05\x05\x02"}; + +gss_OID GSS_SPNEGO_MECHANISM = &gss_spnego_mechanism_oid_desc; + +/* + * draft-ietf-cat-iakerb-09, IAKERB: + * The mechanism ID for IAKERB proxy GSS-API Kerberos, in accordance + * with the mechanism proposed by SPNEGO [7] for negotiating protocol + * variations, is: {iso(1) org(3) dod(6) internet(1) security(5) + * mechanisms(5) iakerb(10) iakerbProxyProtocol(1)}. The proposed + * mechanism ID for IAKERB minimum messages GSS-API Kerberos, in + * accordance with the mechanism proposed by SPNEGO for negotiating + * protocol variations, is: {iso(1) org(3) dod(6) internet(1) + * security(5) mechanisms(5) iakerb(10) + * iakerbMinimumMessagesProtocol(2)}. + */ + +static gss_OID_desc gss_iakerb_proxy_mechanism_oid_desc = +{7, (void *)"\x2b\x06\x01\x05\x05\x0a\x01"}; + +gss_OID GSS_IAKERB_PROXY_MECHANISM = &gss_iakerb_proxy_mechanism_oid_desc; + +static gss_OID_desc gss_iakerb_min_msg_mechanism_oid_desc = +{7, (void *)"\x2b\x06\x01\x05\x05\x0a\x02"}; + +gss_OID GSS_IAKERB_MIN_MSG_MECHANISM = &gss_iakerb_min_msg_mechanism_oid_desc; + +/* + * Context for krb5 calls. + */ + +krb5_context gssapi_krb5_context; diff --git a/source4/heimdal/lib/gssapi/get_mic.c b/source4/heimdal/lib/gssapi/get_mic.c new file mode 100644 index 0000000000..1c950e95d9 --- /dev/null +++ b/source4/heimdal/lib/gssapi/get_mic.c @@ -0,0 +1,302 @@ +/* + * Copyright (c) 1997 - 2003 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 "gssapi_locl.h" + +RCSID("$Id: get_mic.c,v 1.29 2005/01/05 02:52:12 lukeh Exp $"); + +static OM_uint32 +mic_des + (OM_uint32 * minor_status, + const gss_ctx_id_t context_handle, + gss_qop_t qop_req, + const gss_buffer_t message_buffer, + gss_buffer_t message_token, + krb5_keyblock *key + ) +{ + u_char *p; + MD5_CTX md5; + u_char hash[16]; + DES_key_schedule schedule; + DES_cblock deskey; + DES_cblock zero; + int32_t seq_number; + size_t len, total_len; + + gssapi_krb5_encap_length (22, &len, &total_len, GSS_KRB5_MECHANISM); + + message_token->length = total_len; + message_token->value = malloc (total_len); + if (message_token->value == NULL) { + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + + p = gssapi_krb5_make_header(message_token->value, + len, + "\x01\x01", /* TOK_ID */ + GSS_KRB5_MECHANISM); + + memcpy (p, "\x00\x00", 2); /* SGN_ALG = DES MAC MD5 */ + p += 2; + + memcpy (p, "\xff\xff\xff\xff", 4); /* Filler */ + p += 4; + + /* Fill in later (SND-SEQ) */ + memset (p, 0, 16); + p += 16; + + /* checksum */ + MD5_Init (&md5); + MD5_Update (&md5, p - 24, 8); + MD5_Update (&md5, message_buffer->value, message_buffer->length); + MD5_Final (hash, &md5); + + memset (&zero, 0, sizeof(zero)); + memcpy (&deskey, key->keyvalue.data, sizeof(deskey)); + DES_set_key (&deskey, &schedule); + DES_cbc_cksum ((void *)hash, (void *)hash, sizeof(hash), + &schedule, &zero); + memcpy (p - 8, hash, 8); /* SGN_CKSUM */ + + HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex); + /* sequence number */ + krb5_auth_con_getlocalseqnumber (gssapi_krb5_context, + context_handle->auth_context, + &seq_number); + + p -= 16; /* SND_SEQ */ + p[0] = (seq_number >> 0) & 0xFF; + p[1] = (seq_number >> 8) & 0xFF; + p[2] = (seq_number >> 16) & 0xFF; + p[3] = (seq_number >> 24) & 0xFF; + memset (p + 4, + (context_handle->more_flags & LOCAL) ? 0 : 0xFF, + 4); + + DES_set_key (&deskey, &schedule); + DES_cbc_encrypt ((void *)p, (void *)p, 8, + &schedule, (DES_cblock *)(p + 8), DES_ENCRYPT); + + krb5_auth_con_setlocalseqnumber (gssapi_krb5_context, + context_handle->auth_context, + ++seq_number); + HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex); + + memset (deskey, 0, sizeof(deskey)); + memset (&schedule, 0, sizeof(schedule)); + + *minor_status = 0; + return GSS_S_COMPLETE; +} + +static OM_uint32 +mic_des3 + (OM_uint32 * minor_status, + const gss_ctx_id_t context_handle, + gss_qop_t qop_req, + const gss_buffer_t message_buffer, + gss_buffer_t message_token, + krb5_keyblock *key + ) +{ + u_char *p; + Checksum cksum; + u_char seq[8]; + + int32_t seq_number; + size_t len, total_len; + + krb5_crypto crypto; + krb5_error_code kret; + krb5_data encdata; + char *tmp; + char ivec[8]; + + gssapi_krb5_encap_length (36, &len, &total_len, GSS_KRB5_MECHANISM); + + message_token->length = total_len; + message_token->value = malloc (total_len); + if (message_token->value == NULL) { + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + + p = gssapi_krb5_make_header(message_token->value, + len, + "\x01\x01", /* TOK-ID */ + GSS_KRB5_MECHANISM); + + memcpy (p, "\x04\x00", 2); /* SGN_ALG = HMAC SHA1 DES3-KD */ + p += 2; + + memcpy (p, "\xff\xff\xff\xff", 4); /* filler */ + p += 4; + + /* this should be done in parts */ + + tmp = malloc (message_buffer->length + 8); + if (tmp == NULL) { + free (message_token->value); + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + memcpy (tmp, p - 8, 8); + memcpy (tmp + 8, message_buffer->value, message_buffer->length); + + kret = krb5_crypto_init(gssapi_krb5_context, key, 0, &crypto); + if (kret) { + free (message_token->value); + free (tmp); + gssapi_krb5_set_error_string (); + *minor_status = kret; + return GSS_S_FAILURE; + } + + kret = krb5_create_checksum (gssapi_krb5_context, + crypto, + KRB5_KU_USAGE_SIGN, + 0, + tmp, + message_buffer->length + 8, + &cksum); + free (tmp); + krb5_crypto_destroy (gssapi_krb5_context, crypto); + if (kret) { + free (message_token->value); + gssapi_krb5_set_error_string (); + *minor_status = kret; + return GSS_S_FAILURE; + } + + memcpy (p + 8, cksum.checksum.data, cksum.checksum.length); + + HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex); + /* sequence number */ + krb5_auth_con_getlocalseqnumber (gssapi_krb5_context, + context_handle->auth_context, + &seq_number); + + seq[0] = (seq_number >> 0) & 0xFF; + seq[1] = (seq_number >> 8) & 0xFF; + seq[2] = (seq_number >> 16) & 0xFF; + seq[3] = (seq_number >> 24) & 0xFF; + memset (seq + 4, + (context_handle->more_flags & LOCAL) ? 0 : 0xFF, + 4); + + kret = krb5_crypto_init(gssapi_krb5_context, key, + ETYPE_DES3_CBC_NONE, &crypto); + if (kret) { + free (message_token->value); + gssapi_krb5_set_error_string (); + *minor_status = kret; + return GSS_S_FAILURE; + } + + if (context_handle->more_flags & COMPAT_OLD_DES3) + memset(ivec, 0, 8); + else + memcpy(ivec, p + 8, 8); + + kret = krb5_encrypt_ivec (gssapi_krb5_context, + crypto, + KRB5_KU_USAGE_SEQ, + seq, 8, &encdata, ivec); + krb5_crypto_destroy (gssapi_krb5_context, crypto); + if (kret) { + free (message_token->value); + gssapi_krb5_set_error_string (); + *minor_status = kret; + return GSS_S_FAILURE; + } + + assert (encdata.length == 8); + + memcpy (p, encdata.data, encdata.length); + krb5_data_free (&encdata); + + krb5_auth_con_setlocalseqnumber (gssapi_krb5_context, + context_handle->auth_context, + ++seq_number); + HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex); + + free_Checksum (&cksum); + *minor_status = 0; + return GSS_S_COMPLETE; +} + +OM_uint32 gss_get_mic + (OM_uint32 * minor_status, + const gss_ctx_id_t context_handle, + gss_qop_t qop_req, + const gss_buffer_t message_buffer, + gss_buffer_t message_token + ) +{ + krb5_keyblock *key; + OM_uint32 ret; + krb5_keytype keytype; + + ret = gss_krb5_get_subkey(context_handle, &key); + if (ret) { + gssapi_krb5_set_error_string (); + *minor_status = ret; + return GSS_S_FAILURE; + } + krb5_enctype_to_keytype (gssapi_krb5_context, key->keytype, &keytype); + + switch (keytype) { + case KEYTYPE_DES : + ret = mic_des (minor_status, context_handle, qop_req, + message_buffer, message_token, key); + break; + case KEYTYPE_DES3 : + ret = mic_des3 (minor_status, context_handle, qop_req, + message_buffer, message_token, key); + break; + case KEYTYPE_ARCFOUR: + case KEYTYPE_ARCFOUR_56: + ret = _gssapi_get_mic_arcfour (minor_status, context_handle, qop_req, + message_buffer, message_token, key); + break; + default : + ret = _gssapi_mic_cfx (minor_status, context_handle, qop_req, + message_buffer, message_token, key); + break; + } + krb5_free_keyblock (gssapi_krb5_context, key); + return ret; +} diff --git a/source4/heimdal/lib/gssapi/gssapi.h b/source4/heimdal/lib/gssapi/gssapi.h new file mode 100644 index 0000000000..5712581d3f --- /dev/null +++ b/source4/heimdal/lib/gssapi/gssapi.h @@ -0,0 +1,826 @@ +/* + * Copyright (c) 1997 - 2003 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. + */ + +/* $Id: gssapi.h,v 1.37 2005/02/21 08:48:15 lukeh Exp $ */ + +#ifndef GSSAPI_H_ +#define GSSAPI_H_ + +/* + * First, include stddef.h to get size_t defined. + */ +#include <stddef.h> + +#include <krb5-types.h> + +/* + * Now define the three implementation-dependent types. + */ + +typedef u_int32_t OM_uint32; + +typedef u_int32_t gss_uint32; + +/* + * This is to avoid having to include <krb5.h> + */ + +struct krb5_auth_context_data; + +struct Principal; + +/* typedef void *gss_name_t; */ + +typedef struct Principal *gss_name_t; + +struct gss_ctx_id_t_desc_struct; +typedef struct gss_ctx_id_t_desc_struct *gss_ctx_id_t; + +typedef struct gss_OID_desc_struct { + OM_uint32 length; + void *elements; +} gss_OID_desc, *gss_OID; + +typedef struct gss_OID_set_desc_struct { + size_t count; + gss_OID elements; +} gss_OID_set_desc, *gss_OID_set; + +struct krb5_keytab_data; + +struct krb5_ccache_data; + +typedef int gss_cred_usage_t; + +struct gss_cred_id_t_desc_struct; +typedef struct gss_cred_id_t_desc_struct *gss_cred_id_t; + +typedef struct gss_buffer_desc_struct { + size_t length; + void *value; +} gss_buffer_desc, *gss_buffer_t; + +typedef struct gss_channel_bindings_struct { + OM_uint32 initiator_addrtype; + gss_buffer_desc initiator_address; + OM_uint32 acceptor_addrtype; + gss_buffer_desc acceptor_address; + gss_buffer_desc application_data; +} *gss_channel_bindings_t; + +/* + * For now, define a QOP-type as an OM_uint32 + */ +typedef OM_uint32 gss_qop_t; + +/* + * Flag bits for context-level services. + */ +#define GSS_C_DELEG_FLAG 1 /* 0x00000001 */ +#define GSS_C_MUTUAL_FLAG 2 /* 0x00000002 */ +#define GSS_C_REPLAY_FLAG 4 /* 0x00000004 */ +#define GSS_C_SEQUENCE_FLAG 8 /* 0x00000008 */ +#define GSS_C_CONF_FLAG 16 /* 0x00000010 */ +#define GSS_C_INTEG_FLAG 32 /* 0x00000020 */ +#define GSS_C_ANON_FLAG 64 /* 0x00000040 */ +#define GSS_C_PROT_READY_FLAG 128 /* 0x00000080 */ +#define GSS_C_TRANS_FLAG 256 /* 0x00000100 */ + +/* these are from draft-brezak-win2k-krb-rc4-hmac-04.txt */ +#define GSS_C_DCE_STYLE 4096 /* 0x00001000 */ +#define GSS_C_IDENTIFY_FLAG 8192 /* 0x00002000 */ +#define GSS_C_EXTENDED_ERROR_FLAG 16384 /* 0x00004000 */ + +/* + * Credential usage options + */ +#define GSS_C_BOTH 0 +#define GSS_C_INITIATE 1 +#define GSS_C_ACCEPT 2 + +/* + * Status code types for gss_display_status + */ +#define GSS_C_GSS_CODE 1 +#define GSS_C_MECH_CODE 2 + +/* + * The constant definitions for channel-bindings address families + */ +#define GSS_C_AF_UNSPEC 0 +#define GSS_C_AF_LOCAL 1 +#define GSS_C_AF_INET 2 +#define GSS_C_AF_IMPLINK 3 +#define GSS_C_AF_PUP 4 +#define GSS_C_AF_CHAOS 5 +#define GSS_C_AF_NS 6 +#define GSS_C_AF_NBS 7 +#define GSS_C_AF_ECMA 8 +#define GSS_C_AF_DATAKIT 9 +#define GSS_C_AF_CCITT 10 +#define GSS_C_AF_SNA 11 +#define GSS_C_AF_DECnet 12 +#define GSS_C_AF_DLI 13 +#define GSS_C_AF_LAT 14 +#define GSS_C_AF_HYLINK 15 +#define GSS_C_AF_APPLETALK 16 +#define GSS_C_AF_BSC 17 +#define GSS_C_AF_DSS 18 +#define GSS_C_AF_OSI 19 +#define GSS_C_AF_X25 21 +#define GSS_C_AF_INET6 24 + +#define GSS_C_AF_NULLADDR 255 + +/* + * Various Null values + */ +#define GSS_C_NO_NAME ((gss_name_t) 0) +#define GSS_C_NO_BUFFER ((gss_buffer_t) 0) +#define GSS_C_NO_OID ((gss_OID) 0) +#define GSS_C_NO_OID_SET ((gss_OID_set) 0) +#define GSS_C_NO_CONTEXT ((gss_ctx_id_t) 0) +#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} + +/* + * Some alternate names for a couple of the above + * values. These are defined for V1 compatibility. + */ +#define GSS_C_NULL_OID GSS_C_NO_OID +#define GSS_C_NULL_OID_SET GSS_C_NO_OID_SET + +/* + * Define the default Quality of Protection for per-message + * services. Note that an implementation that offers multiple + * levels of QOP may define GSS_C_QOP_DEFAULT to be either zero + * (as done here) to mean "default protection", or to a specific + * explicit QOP value. However, a value of 0 should always be + * interpreted by a GSSAPI implementation as a request for the + * default protection level. + */ +#define GSS_C_QOP_DEFAULT 0 + +#define GSS_KRB5_CONF_C_QOP_DES 0x0100 +#define GSS_KRB5_CONF_C_QOP_DES3_KD 0x0200 + +/* + * Expiration time of 2^32-1 seconds means infinite lifetime for a + * credential or security context + */ +#define GSS_C_INDEFINITE 0xfffffffful + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * The implementation must reserve static storage for a + * gss_OID_desc object containing the value + * {10, (void *)"\x2a\x86\x48\x86\xf7\x12" + * "\x01\x02\x01\x01"}, + * corresponding to an object-identifier value of + * {iso(1) member-body(2) United States(840) mit(113554) + * infosys(1) gssapi(2) generic(1) user_name(1)}. The constant + * GSS_C_NT_USER_NAME should be initialized to point + * to that gss_OID_desc. + */ +extern gss_OID GSS_C_NT_USER_NAME; + +/* + * The implementation must reserve static storage for a + * gss_OID_desc object containing the value + * {10, (void *)"\x2a\x86\x48\x86\xf7\x12" + * "\x01\x02\x01\x02"}, + * corresponding to an object-identifier value of + * {iso(1) member-body(2) United States(840) mit(113554) + * infosys(1) gssapi(2) generic(1) machine_uid_name(2)}. + * The constant GSS_C_NT_MACHINE_UID_NAME should be + * initialized to point to that gss_OID_desc. + */ +extern gss_OID GSS_C_NT_MACHINE_UID_NAME; + +/* + * The implementation must reserve static storage for a + * gss_OID_desc object containing the value + * {10, (void *)"\x2a\x86\x48\x86\xf7\x12" + * "\x01\x02\x01\x03"}, + * corresponding to an object-identifier value of + * {iso(1) member-body(2) United States(840) mit(113554) + * infosys(1) gssapi(2) generic(1) string_uid_name(3)}. + * The constant GSS_C_NT_STRING_UID_NAME should be + * initialized to point to that gss_OID_desc. + */ +extern gss_OID GSS_C_NT_STRING_UID_NAME; + +/* + * The implementation must reserve static storage for a + * gss_OID_desc object containing the value + * {6, (void *)"\x2b\x06\x01\x05\x06\x02"}, + * corresponding to an object-identifier value of + * {iso(1) org(3) dod(6) internet(1) security(5) + * nametypes(6) gss-host-based-services(2)). The constant + * GSS_C_NT_HOSTBASED_SERVICE_X should be initialized to point + * to that gss_OID_desc. This is a deprecated OID value, and + * implementations wishing to support hostbased-service names + * should instead use the GSS_C_NT_HOSTBASED_SERVICE OID, + * defined below, to identify such names; + * GSS_C_NT_HOSTBASED_SERVICE_X should be accepted a synonym + * for GSS_C_NT_HOSTBASED_SERVICE when presented as an input + * parameter, but should not be emitted by GSS-API + * implementations + */ +extern gss_OID GSS_C_NT_HOSTBASED_SERVICE_X; + +/* + * The implementation must reserve static storage for a + * gss_OID_desc object containing the value + * {10, (void *)"\x2a\x86\x48\x86\xf7\x12" + * "\x01\x02\x01\x04"}, corresponding to an + * object-identifier value of {iso(1) member-body(2) + * Unites States(840) mit(113554) infosys(1) gssapi(2) + * generic(1) service_name(4)}. The constant + * GSS_C_NT_HOSTBASED_SERVICE should be initialized + * to point to that gss_OID_desc. + */ +extern gss_OID GSS_C_NT_HOSTBASED_SERVICE; + +/* + * The implementation must reserve static storage for a + * gss_OID_desc object containing the value + * {6, (void *)"\x2b\x06\01\x05\x06\x03"}, + * corresponding to an object identifier value of + * {1(iso), 3(org), 6(dod), 1(internet), 5(security), + * 6(nametypes), 3(gss-anonymous-name)}. The constant + * and GSS_C_NT_ANONYMOUS should be initialized to point + * to that gss_OID_desc. + */ +extern gss_OID GSS_C_NT_ANONYMOUS; + +/* + * The implementation must reserve static storage for a + * gss_OID_desc object containing the value + * {6, (void *)"\x2b\x06\x01\x05\x06\x04"}, + * corresponding to an object-identifier value of + * {1(iso), 3(org), 6(dod), 1(internet), 5(security), + * 6(nametypes), 4(gss-api-exported-name)}. The constant + * GSS_C_NT_EXPORT_NAME should be initialized to point + * to that gss_OID_desc. + */ +extern gss_OID GSS_C_NT_EXPORT_NAME; + +/* + * RFC2478, SPNEGO: + * The security mechanism of the initial + * negotiation token is identified by the Object Identifier + * iso.org.dod.internet.security.mechanism.snego (1.3.6.1.5.5.2). + */ +extern gss_OID GSS_SPNEGO_MECHANISM; + +/* + * This if for kerberos5 names. + */ + +extern gss_OID GSS_KRB5_NT_PRINCIPAL_NAME; +extern gss_OID GSS_KRB5_NT_USER_NAME; +extern gss_OID GSS_KRB5_NT_MACHINE_UID_NAME; +extern gss_OID GSS_KRB5_NT_STRING_UID_NAME; + +extern gss_OID GSS_KRB5_MECHANISM; + +/* for compatibility with MIT api */ + +#define gss_mech_krb5 GSS_KRB5_MECHANISM +#define gss_krb5_nt_general_name GSS_KRB5_NT_PRINCIPAL_NAME + +/* Major status codes */ + +#define GSS_S_COMPLETE 0 + +/* + * Some "helper" definitions to make the status code macros obvious. + */ +#define GSS_C_CALLING_ERROR_OFFSET 24 +#define GSS_C_ROUTINE_ERROR_OFFSET 16 +#define GSS_C_SUPPLEMENTARY_OFFSET 0 +#define GSS_C_CALLING_ERROR_MASK 0377ul +#define GSS_C_ROUTINE_ERROR_MASK 0377ul +#define GSS_C_SUPPLEMENTARY_MASK 0177777ul + +/* + * The macros that test status codes for error conditions. + * Note that the GSS_ERROR() macro has changed slightly from + * the V1 GSSAPI so that it now evaluates its argument + * only once. + */ +#define GSS_CALLING_ERROR(x) \ + (x & (GSS_C_CALLING_ERROR_MASK << GSS_C_CALLING_ERROR_OFFSET)) +#define GSS_ROUTINE_ERROR(x) \ + (x & (GSS_C_ROUTINE_ERROR_MASK << GSS_C_ROUTINE_ERROR_OFFSET)) +#define GSS_SUPPLEMENTARY_INFO(x) \ + (x & (GSS_C_SUPPLEMENTARY_MASK << GSS_C_SUPPLEMENTARY_OFFSET)) +#define GSS_ERROR(x) \ + (x & ((GSS_C_CALLING_ERROR_MASK << GSS_C_CALLING_ERROR_OFFSET) | \ + (GSS_C_ROUTINE_ERROR_MASK << GSS_C_ROUTINE_ERROR_OFFSET))) + +/* + * Now the actual status code definitions + */ + +/* + * Calling errors: + */ +#define GSS_S_CALL_INACCESSIBLE_READ \ + (1ul << GSS_C_CALLING_ERROR_OFFSET) +#define GSS_S_CALL_INACCESSIBLE_WRITE \ + (2ul << GSS_C_CALLING_ERROR_OFFSET) +#define GSS_S_CALL_BAD_STRUCTURE \ + (3ul << GSS_C_CALLING_ERROR_OFFSET) + +/* + * Routine errors: + */ +#define GSS_S_BAD_MECH (1ul << GSS_C_ROUTINE_ERROR_OFFSET) +#define GSS_S_BAD_NAME (2ul << GSS_C_ROUTINE_ERROR_OFFSET) +#define GSS_S_BAD_NAMETYPE (3ul << GSS_C_ROUTINE_ERROR_OFFSET) + +#define GSS_S_BAD_BINDINGS (4ul << GSS_C_ROUTINE_ERROR_OFFSET) +#define GSS_S_BAD_STATUS (5ul << GSS_C_ROUTINE_ERROR_OFFSET) +#define GSS_S_BAD_SIG (6ul << GSS_C_ROUTINE_ERROR_OFFSET) +#define GSS_S_BAD_MIC GSS_S_BAD_SIG +#define GSS_S_NO_CRED (7ul << GSS_C_ROUTINE_ERROR_OFFSET) +#define GSS_S_NO_CONTEXT (8ul << GSS_C_ROUTINE_ERROR_OFFSET) +#define GSS_S_DEFECTIVE_TOKEN (9ul << GSS_C_ROUTINE_ERROR_OFFSET) +#define GSS_S_DEFECTIVE_CREDENTIAL (10ul << GSS_C_ROUTINE_ERROR_OFFSET) +#define GSS_S_CREDENTIALS_EXPIRED (11ul << GSS_C_ROUTINE_ERROR_OFFSET) +#define GSS_S_CONTEXT_EXPIRED (12ul << GSS_C_ROUTINE_ERROR_OFFSET) +#define GSS_S_FAILURE (13ul << GSS_C_ROUTINE_ERROR_OFFSET) +#define GSS_S_BAD_QOP (14ul << GSS_C_ROUTINE_ERROR_OFFSET) +#define GSS_S_UNAUTHORIZED (15ul << GSS_C_ROUTINE_ERROR_OFFSET) +#define GSS_S_UNAVAILABLE (16ul << GSS_C_ROUTINE_ERROR_OFFSET) +#define GSS_S_DUPLICATE_ELEMENT (17ul << GSS_C_ROUTINE_ERROR_OFFSET) +#define GSS_S_NAME_NOT_MN (18ul << GSS_C_ROUTINE_ERROR_OFFSET) + +/* + * Supplementary info bits: + */ +#define GSS_S_CONTINUE_NEEDED (1ul << (GSS_C_SUPPLEMENTARY_OFFSET + 0)) +#define GSS_S_DUPLICATE_TOKEN (1ul << (GSS_C_SUPPLEMENTARY_OFFSET + 1)) +#define GSS_S_OLD_TOKEN (1ul << (GSS_C_SUPPLEMENTARY_OFFSET + 2)) +#define GSS_S_UNSEQ_TOKEN (1ul << (GSS_C_SUPPLEMENTARY_OFFSET + 3)) +#define GSS_S_GAP_TOKEN (1ul << (GSS_C_SUPPLEMENTARY_OFFSET + 4)) + +/* + * From RFC1964: + * + * 4.1.1. Non-Kerberos-specific codes + */ + +#define GSS_KRB5_S_G_BAD_SERVICE_NAME 1 + /* "No @ in SERVICE-NAME name string" */ +#define GSS_KRB5_S_G_BAD_STRING_UID 2 + /* "STRING-UID-NAME contains nondigits" */ +#define GSS_KRB5_S_G_NOUSER 3 + /* "UID does not resolve to username" */ +#define GSS_KRB5_S_G_VALIDATE_FAILED 4 + /* "Validation error" */ +#define GSS_KRB5_S_G_BUFFER_ALLOC 5 + /* "Couldn't allocate gss_buffer_t data" */ +#define GSS_KRB5_S_G_BAD_MSG_CTX 6 + /* "Message context invalid" */ +#define GSS_KRB5_S_G_WRONG_SIZE 7 + /* "Buffer is the wrong size" */ +#define GSS_KRB5_S_G_BAD_USAGE 8 + /* "Credential usage type is unknown" */ +#define GSS_KRB5_S_G_UNKNOWN_QOP 9 + /* "Unknown quality of protection specified" */ + + /* + * 4.1.2. Kerberos-specific-codes + */ + +#define GSS_KRB5_S_KG_CCACHE_NOMATCH 10 + /* "Principal in credential cache does not match desired name" */ +#define GSS_KRB5_S_KG_KEYTAB_NOMATCH 11 + /* "No principal in keytab matches desired name" */ +#define GSS_KRB5_S_KG_TGT_MISSING 12 + /* "Credential cache has no TGT" */ +#define GSS_KRB5_S_KG_NO_SUBKEY 13 + /* "Authenticator has no subkey" */ +#define GSS_KRB5_S_KG_CONTEXT_ESTABLISHED 14 + /* "Context is already fully established" */ +#define GSS_KRB5_S_KG_BAD_SIGN_TYPE 15 + /* "Unknown signature type in token" */ +#define GSS_KRB5_S_KG_BAD_LENGTH 16 + /* "Invalid field length in token" */ +#define GSS_KRB5_S_KG_CTX_INCOMPLETE 17 + /* "Attempt to use incomplete security context" */ + +/* + * Finally, function prototypes for the GSS-API routines. + */ + + +OM_uint32 gss_acquire_cred + (OM_uint32 * /*minor_status*/, + const gss_name_t /*desired_name*/, + OM_uint32 /*time_req*/, + const gss_OID_set /*desired_mechs*/, + gss_cred_usage_t /*cred_usage*/, + gss_cred_id_t * /*output_cred_handle*/, + gss_OID_set * /*actual_mechs*/, + OM_uint32 * /*time_rec*/ + ); + +OM_uint32 gss_release_cred + (OM_uint32 * /*minor_status*/, + gss_cred_id_t * /*cred_handle*/ + ); + +OM_uint32 gss_init_sec_context + (OM_uint32 * /*minor_status*/, + const gss_cred_id_t /*initiator_cred_handle*/, + gss_ctx_id_t * /*context_handle*/, + const gss_name_t /*target_name*/, + const gss_OID /*mech_type*/, + OM_uint32 /*req_flags*/, + OM_uint32 /*time_req*/, + const gss_channel_bindings_t /*input_chan_bindings*/, + const gss_buffer_t /*input_token*/, + gss_OID * /*actual_mech_type*/, + gss_buffer_t /*output_token*/, + OM_uint32 * /*ret_flags*/, + OM_uint32 * /*time_rec*/ + ); + +OM_uint32 gss_accept_sec_context + (OM_uint32 * /*minor_status*/, + gss_ctx_id_t * /*context_handle*/, + const gss_cred_id_t /*acceptor_cred_handle*/, + const gss_buffer_t /*input_token_buffer*/, + const gss_channel_bindings_t /*input_chan_bindings*/, + gss_name_t * /*src_name*/, + gss_OID * /*mech_type*/, + gss_buffer_t /*output_token*/, + OM_uint32 * /*ret_flags*/, + OM_uint32 * /*time_rec*/, + gss_cred_id_t * /*delegated_cred_handle*/ + ); + +OM_uint32 gss_process_context_token + (OM_uint32 * /*minor_status*/, + const gss_ctx_id_t /*context_handle*/, + const gss_buffer_t /*token_buffer*/ + ); + +OM_uint32 gss_delete_sec_context + (OM_uint32 * /*minor_status*/, + gss_ctx_id_t * /*context_handle*/, + gss_buffer_t /*output_token*/ + ); + +OM_uint32 gss_context_time + (OM_uint32 * /*minor_status*/, + const gss_ctx_id_t /*context_handle*/, + OM_uint32 * /*time_rec*/ + ); + +OM_uint32 gss_get_mic + (OM_uint32 * /*minor_status*/, + const gss_ctx_id_t /*context_handle*/, + gss_qop_t /*qop_req*/, + const gss_buffer_t /*message_buffer*/, + gss_buffer_t /*message_token*/ + ); + +OM_uint32 gss_verify_mic + (OM_uint32 * /*minor_status*/, + const gss_ctx_id_t /*context_handle*/, + const gss_buffer_t /*message_buffer*/, + const gss_buffer_t /*token_buffer*/, + gss_qop_t * /*qop_state*/ + ); + +OM_uint32 gss_wrap + (OM_uint32 * /*minor_status*/, + const gss_ctx_id_t /*context_handle*/, + 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*/ + ); + +OM_uint32 gss_unwrap + (OM_uint32 * /*minor_status*/, + const gss_ctx_id_t /*context_handle*/, + const gss_buffer_t /*input_message_buffer*/, + gss_buffer_t /*output_message_buffer*/, + int * /*conf_state*/, + gss_qop_t * /*qop_state*/ + ); + +OM_uint32 gss_display_status + (OM_uint32 * /*minor_status*/, + OM_uint32 /*status_value*/, + int /*status_type*/, + const gss_OID /*mech_type*/, + OM_uint32 * /*message_context*/, + gss_buffer_t /*status_string*/ + ); + +OM_uint32 gss_indicate_mechs + (OM_uint32 * /*minor_status*/, + gss_OID_set * /*mech_set*/ + ); + +OM_uint32 gss_compare_name + (OM_uint32 * /*minor_status*/, + const gss_name_t /*name1*/, + const gss_name_t /*name2*/, + int * /*name_equal*/ + ); + +OM_uint32 gss_display_name + (OM_uint32 * /*minor_status*/, + const gss_name_t /*input_name*/, + gss_buffer_t /*output_name_buffer*/, + gss_OID * /*output_name_type*/ + ); + +OM_uint32 gss_import_name + (OM_uint32 * /*minor_status*/, + const gss_buffer_t /*input_name_buffer*/, + const gss_OID /*input_name_type*/, + gss_name_t * /*output_name*/ + ); + +OM_uint32 gss_export_name + (OM_uint32 * /*minor_status*/, + const gss_name_t /*input_name*/, + gss_buffer_t /*exported_name*/ + ); + +OM_uint32 gss_release_name + (OM_uint32 * /*minor_status*/, + gss_name_t * /*input_name*/ + ); + +OM_uint32 gss_release_buffer + (OM_uint32 * /*minor_status*/, + gss_buffer_t /*buffer*/ + ); + +OM_uint32 gss_release_oid_set + (OM_uint32 * /*minor_status*/, + gss_OID_set * /*set*/ + ); + +OM_uint32 gss_inquire_cred + (OM_uint32 * /*minor_status*/, + const gss_cred_id_t /*cred_handle*/, + gss_name_t * /*name*/, + OM_uint32 * /*lifetime*/, + gss_cred_usage_t * /*cred_usage*/, + gss_OID_set * /*mechanisms*/ + ); + +OM_uint32 gss_inquire_context ( + OM_uint32 * /*minor_status*/, + const gss_ctx_id_t /*context_handle*/, + gss_name_t * /*src_name*/, + gss_name_t * /*targ_name*/, + OM_uint32 * /*lifetime_rec*/, + gss_OID * /*mech_type*/, + OM_uint32 * /*ctx_flags*/, + int * /*locally_initiated*/, + int * /*open_context*/ + ); + +OM_uint32 gss_wrap_size_limit ( + OM_uint32 * /*minor_status*/, + const gss_ctx_id_t /*context_handle*/, + int /*conf_req_flag*/, + gss_qop_t /*qop_req*/, + OM_uint32 /*req_output_size*/, + OM_uint32 * /*max_input_size*/ + ); + +OM_uint32 gss_add_cred ( + OM_uint32 * /*minor_status*/, + const gss_cred_id_t /*input_cred_handle*/, + const gss_name_t /*desired_name*/, + const gss_OID /*desired_mech*/, + gss_cred_usage_t /*cred_usage*/, + OM_uint32 /*initiator_time_req*/, + OM_uint32 /*acceptor_time_req*/, + gss_cred_id_t * /*output_cred_handle*/, + gss_OID_set * /*actual_mechs*/, + OM_uint32 * /*initiator_time_rec*/, + OM_uint32 * /*acceptor_time_rec*/ + ); + +OM_uint32 gss_inquire_cred_by_mech ( + OM_uint32 * /*minor_status*/, + const gss_cred_id_t /*cred_handle*/, + const gss_OID /*mech_type*/, + gss_name_t * /*name*/, + OM_uint32 * /*initiator_lifetime*/, + OM_uint32 * /*acceptor_lifetime*/, + gss_cred_usage_t * /*cred_usage*/ + ); + +OM_uint32 gss_export_sec_context ( + OM_uint32 * /*minor_status*/, + gss_ctx_id_t * /*context_handle*/, + gss_buffer_t /*interprocess_token*/ + ); + +OM_uint32 gss_import_sec_context ( + OM_uint32 * /*minor_status*/, + const gss_buffer_t /*interprocess_token*/, + gss_ctx_id_t * /*context_handle*/ + ); + +OM_uint32 gss_create_empty_oid_set ( + OM_uint32 * /*minor_status*/, + gss_OID_set * /*oid_set*/ + ); + +OM_uint32 gss_add_oid_set_member ( + OM_uint32 * /*minor_status*/, + const gss_OID /*member_oid*/, + gss_OID_set * /*oid_set*/ + ); + +OM_uint32 gss_test_oid_set_member ( + OM_uint32 * /*minor_status*/, + const gss_OID /*member*/, + const gss_OID_set /*set*/, + int * /*present*/ + ); + +OM_uint32 gss_inquire_names_for_mech ( + OM_uint32 * /*minor_status*/, + const gss_OID /*mechanism*/, + gss_OID_set * /*name_types*/ + ); + +OM_uint32 gss_inquire_mechs_for_name ( + OM_uint32 * /*minor_status*/, + const gss_name_t /*input_name*/, + gss_OID_set * /*mech_types*/ + ); + +OM_uint32 gss_canonicalize_name ( + OM_uint32 * /*minor_status*/, + const gss_name_t /*input_name*/, + const gss_OID /*mech_type*/, + gss_name_t * /*output_name*/ + ); + +OM_uint32 gss_duplicate_name ( + OM_uint32 * /*minor_status*/, + const gss_name_t /*src_name*/, + gss_name_t * /*dest_name*/ + ); + +/* + * The following routines are obsolete variants of gss_get_mic, + * gss_verify_mic, gss_wrap and gss_unwrap. They should be + * provided by GSSAPI V2 implementations for backwards + * compatibility with V1 applications. Distinct entrypoints + * (as opposed to #defines) should be provided, both to allow + * GSSAPI V1 applications to link against GSSAPI V2 implementations, + * and to retain the slight parameter type differences between the + * obsolete versions of these routines and their current forms. + */ + +OM_uint32 gss_sign + (OM_uint32 * /*minor_status*/, + gss_ctx_id_t /*context_handle*/, + int /*qop_req*/, + gss_buffer_t /*message_buffer*/, + gss_buffer_t /*message_token*/ + ); + +OM_uint32 gss_verify + (OM_uint32 * /*minor_status*/, + gss_ctx_id_t /*context_handle*/, + gss_buffer_t /*message_buffer*/, + gss_buffer_t /*token_buffer*/, + int * /*qop_state*/ + ); + +OM_uint32 gss_seal + (OM_uint32 * /*minor_status*/, + gss_ctx_id_t /*context_handle*/, + int /*conf_req_flag*/, + int /*qop_req*/, + gss_buffer_t /*input_message_buffer*/, + int * /*conf_state*/, + gss_buffer_t /*output_message_buffer*/ + ); + +OM_uint32 gss_unseal + (OM_uint32 * /*minor_status*/, + gss_ctx_id_t /*context_handle*/, + gss_buffer_t /*input_message_buffer*/, + gss_buffer_t /*output_message_buffer*/, + int * /*conf_state*/, + int * /*qop_state*/ + ); + +/* + * kerberos mechanism specific functions + */ + +OM_uint32 gsskrb5_acquire_cred + (OM_uint32 * minor_status, + struct krb5_keytab_data *keytab, + struct krb5_ccache_data *ccache, + const gss_name_t desired_name, + OM_uint32 time_req, + const gss_OID_set desired_mechs, + gss_cred_usage_t cred_usage, + gss_cred_id_t * output_cred_handle, + gss_OID_set * actual_mechs, + OM_uint32 * time_rec + ); + +OM_uint32 +gss_krb5_ccache_name(OM_uint32 * /*minor_status*/, + const char * /*name */, + const char ** /*out_name */); + +OM_uint32 gsskrb5_register_acceptor_identity + (const char */*identity*/); + +OM_uint32 gss_krb5_copy_ccache + (OM_uint32 */*minor*/, + gss_cred_id_t /*cred*/, + struct krb5_ccache_data */*out*/); + +OM_uint32 gss_krb5_copy_service_keyblock + (OM_uint32 *minor_status, + gss_ctx_id_t context_handle, + struct EncryptionKey **out); + +OM_uint32 gss_krb5_get_tkt_flags + (OM_uint32 */*minor*/, + gss_ctx_id_t /*context_handle*/, + OM_uint32 */*tkt_flags*/); + +OM_uint32 +gsskrb5_extract_authz_data_from_sec_context + (OM_uint32 * /*minor_status*/, + gss_ctx_id_t /*context_handle*/, + int /*ad_type*/, + gss_buffer_t /*ad_data*/); +OM_uint32 +gsskrb5_get_initiator_subkey + (OM_uint32 * /*minor_status*/, + const gss_ctx_id_t context_handle, + gss_buffer_t /* subkey */); + +#define GSS_C_KRB5_COMPAT_DES3_MIC 1 + +OM_uint32 +gss_krb5_compat_des3_mic(OM_uint32 *, gss_ctx_id_t, int); + +#ifdef __cplusplus +} +#endif + +#endif /* GSSAPI_H_ */ diff --git a/source4/heimdal/lib/gssapi/gssapi_locl.h b/source4/heimdal/lib/gssapi/gssapi_locl.h new file mode 100644 index 0000000000..47a37e4657 --- /dev/null +++ b/source4/heimdal/lib/gssapi/gssapi_locl.h @@ -0,0 +1,295 @@ +/* + * Copyright (c) 1997 - 2004 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. + */ + +/* $Id: gssapi_locl.h,v 1.40 2005/06/16 20:34:03 lha Exp $ */ + +#ifndef GSSAPI_LOCL_H +#define GSSAPI_LOCL_H + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <krb5_locl.h> +#include <gssapi.h> +#include <assert.h> + +#include "cfx.h" +#include "arcfour.h" + +#include "spnego_asn1.h" + +/* + * + */ + +struct gss_msg_order; + +typedef struct gss_ctx_id_t_desc_struct { + struct krb5_auth_context_data *auth_context; + gss_name_t source, target; + enum gss_ctx_id_t_state { + INITIATOR_START = 1, INITIATOR_WAIT_FOR_MUTAL = 2, INITIATOR_READY= 3, + ACCEPTOR_START = 11, ACCEPTOR_WAIT_FOR_DCESTYLE = 12, ACCEPTOR_READY = 13 + } state; + OM_uint32 flags; + enum {LOCAL = 1, + OPEN = 2, + COMPAT_OLD_DES3 = 4, + COMPAT_OLD_DES3_SELECTED = 8, + ACCEPTOR_SUBKEY = 16 + } more_flags; + struct krb5_ticket *ticket; + krb5_keyblock *service_keyblock; + krb5_data fwd_data; + OM_uint32 lifetime; + HEIMDAL_MUTEX ctx_id_mutex; + struct gss_msg_order *order; +} gss_ctx_id_t_desc; + +typedef struct gss_cred_id_t_desc_struct { + gss_name_t principal; + krb5_boolean made_keytab; + struct krb5_keytab_data *keytab; + OM_uint32 lifetime; + gss_cred_usage_t usage; + gss_OID_set mechanisms; + krb5_boolean made_ccache; + struct krb5_ccache_data *ccache; + HEIMDAL_MUTEX cred_id_mutex; +} gss_cred_id_t_desc; + +/* + * + */ + +extern krb5_context gssapi_krb5_context; + +extern krb5_keytab gssapi_krb5_keytab; +extern HEIMDAL_MUTEX gssapi_keytab_mutex; + +struct gssapi_thr_context { + HEIMDAL_MUTEX mutex; + char *error_string; +}; + +/* + * Prototypes + */ + +krb5_error_code gssapi_krb5_init (void); + +#define GSSAPI_KRB5_INIT() do { \ + krb5_error_code kret_gss_init; \ + if((kret_gss_init = gssapi_krb5_init ()) != 0) { \ + *minor_status = kret_gss_init; \ + return GSS_S_FAILURE; \ + } \ +} while (0) + +struct gssapi_thr_context * +gssapi_get_thread_context(int); + +OM_uint32 +_gsskrb5_create_ctx( + OM_uint32 * minor_status, + gss_ctx_id_t * context_handle, + const gss_channel_bindings_t input_chan_bindings, + enum gss_ctx_id_t_state state); + +void +gsskrb5_is_cfx(gss_ctx_id_t, int *); + +OM_uint32 +gssapi_krb5_create_8003_checksum ( + OM_uint32 *minor_status, + const gss_channel_bindings_t input_chan_bindings, + OM_uint32 flags, + const krb5_data *fwd_data, + Checksum *result); + +OM_uint32 +gssapi_krb5_verify_8003_checksum ( + OM_uint32 *minor_status, + const gss_channel_bindings_t input_chan_bindings, + const Checksum *cksum, + OM_uint32 *flags, + krb5_data *fwd_data); + +void +_gssapi_encap_length (size_t data_len, + size_t *len, + size_t *total_len, + const gss_OID mech); + +void +gssapi_krb5_encap_length (size_t data_len, + size_t *len, + size_t *total_len, + const gss_OID mech); + + + +OM_uint32 +_gssapi_encapsulate(OM_uint32 *minor_status, + const krb5_data *in_data, + gss_buffer_t output_token, + const gss_OID mech); + + +OM_uint32 +gssapi_krb5_encapsulate(OM_uint32 *minor_status, + const krb5_data *in_data, + gss_buffer_t output_token, + const u_char *type, + const gss_OID mech); + +OM_uint32 +gssapi_krb5_decapsulate(OM_uint32 *minor_status, + gss_buffer_t input_token_buffer, + krb5_data *out_data, + const char *type, + gss_OID oid); + +u_char * +gssapi_krb5_make_header (u_char *p, + size_t len, + const u_char *type, + const gss_OID mech); + +u_char * +_gssapi_make_mech_header(u_char *p, + size_t len, + const gss_OID mech); + +OM_uint32 +_gssapi_verify_mech_header(u_char **str, + size_t total_len, + gss_OID oid); + +OM_uint32 +gssapi_krb5_verify_header(u_char **str, + size_t total_len, + const u_char *type, + gss_OID oid); + +OM_uint32 +_gssapi_decapsulate(OM_uint32 *minor_status, + gss_buffer_t input_token_buffer, + krb5_data *out_data, + const gss_OID mech); + + +ssize_t +gssapi_krb5_get_mech (const u_char *, size_t, const u_char **); + +OM_uint32 +_gssapi_verify_pad(gss_buffer_t, size_t, size_t *); + +OM_uint32 +gss_verify_mic_internal(OM_uint32 * minor_status, + const gss_ctx_id_t context_handle, + const gss_buffer_t message_buffer, + const gss_buffer_t token_buffer, + gss_qop_t * qop_state, + char * type); + +OM_uint32 +gss_krb5_get_subkey(const gss_ctx_id_t context_handle, + krb5_keyblock **key); + +krb5_error_code +gss_address_to_krb5addr(OM_uint32 gss_addr_type, + gss_buffer_desc *gss_addr, + int16_t port, + krb5_address *address); + +/* sec_context flags */ + +#define SC_LOCAL_ADDRESS 0x01 +#define SC_REMOTE_ADDRESS 0x02 +#define SC_KEYBLOCK 0x04 +#define SC_LOCAL_SUBKEY 0x08 +#define SC_REMOTE_SUBKEY 0x10 + +int +gss_oid_equal(const gss_OID a, const gss_OID b); + +void +gssapi_krb5_set_error_string (void); + +char * +gssapi_krb5_get_error_string (void); + +OM_uint32 +_gss_DES3_get_mic_compat(OM_uint32 *, gss_ctx_id_t); + +OM_uint32 +_gss_spnego_require_mechlist_mic(OM_uint32 *, gss_ctx_id_t, krb5_boolean *); + +krb5_error_code +_gss_check_compat(OM_uint32 *, gss_name_t, const char *, + krb5_boolean *, krb5_boolean); + +OM_uint32 +gssapi_lifetime_left(OM_uint32 *, OM_uint32, OM_uint32 *); + +/* sequence */ + +OM_uint32 +_gssapi_msg_order_create(OM_uint32 *, struct gss_msg_order **, + OM_uint32, OM_uint32, OM_uint32, int); +OM_uint32 +_gssapi_msg_order_destroy(struct gss_msg_order **); + +OM_uint32 +_gssapi_msg_order_check(struct gss_msg_order *, OM_uint32); + +OM_uint32 +_gssapi_msg_order_f(OM_uint32); + +/* 8003 */ + +krb5_error_code +gssapi_encode_om_uint32(OM_uint32, u_char *); + +krb5_error_code +gssapi_encode_be_om_uint32(OM_uint32, u_char *); + +krb5_error_code +gssapi_decode_om_uint32(u_char *, OM_uint32 *); + +krb5_error_code +gssapi_decode_be_om_uint32(u_char *, OM_uint32 *); + +#endif diff --git a/source4/heimdal/lib/gssapi/import_name.c b/source4/heimdal/lib/gssapi/import_name.c new file mode 100644 index 0000000000..423e757146 --- /dev/null +++ b/source4/heimdal/lib/gssapi/import_name.c @@ -0,0 +1,229 @@ +/* + * Copyright (c) 1997 - 2003 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 "gssapi_locl.h" + +RCSID("$Id: import_name.c,v 1.13 2003/03/16 17:33:31 lha Exp $"); + +static OM_uint32 +parse_krb5_name (OM_uint32 *minor_status, + const char *name, + gss_name_t *output_name) +{ + krb5_error_code kerr; + + kerr = krb5_parse_name (gssapi_krb5_context, name, output_name); + + if (kerr == 0) + return GSS_S_COMPLETE; + else if (kerr == KRB5_PARSE_ILLCHAR || kerr == KRB5_PARSE_MALFORMED) { + gssapi_krb5_set_error_string (); + *minor_status = kerr; + return GSS_S_BAD_NAME; + } else { + gssapi_krb5_set_error_string (); + *minor_status = kerr; + return GSS_S_FAILURE; + } +} + +static OM_uint32 +import_krb5_name (OM_uint32 *minor_status, + const gss_buffer_t input_name_buffer, + gss_name_t *output_name) +{ + OM_uint32 ret; + char *tmp; + + tmp = malloc (input_name_buffer->length + 1); + if (tmp == NULL) { + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + memcpy (tmp, + input_name_buffer->value, + input_name_buffer->length); + tmp[input_name_buffer->length] = '\0'; + + ret = parse_krb5_name(minor_status, tmp, output_name); + free(tmp); + + return ret; +} + +static OM_uint32 +import_hostbased_name (OM_uint32 *minor_status, + const gss_buffer_t input_name_buffer, + gss_name_t *output_name) +{ + krb5_error_code kerr; + char *tmp; + char *p; + char *host; + char local_hostname[MAXHOSTNAMELEN]; + + *output_name = NULL; + + tmp = malloc (input_name_buffer->length + 1); + if (tmp == NULL) { + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + memcpy (tmp, + input_name_buffer->value, + input_name_buffer->length); + tmp[input_name_buffer->length] = '\0'; + + p = strchr (tmp, '@'); + if (p != NULL) { + *p = '\0'; + host = p + 1; + } else { + if (gethostname(local_hostname, sizeof(local_hostname)) < 0) { + *minor_status = errno; + free (tmp); + return GSS_S_FAILURE; + } + host = local_hostname; + } + + kerr = krb5_sname_to_principal (gssapi_krb5_context, + host, + tmp, + KRB5_NT_SRV_HST, + output_name); + free (tmp); + *minor_status = kerr; + if (kerr == 0) + return GSS_S_COMPLETE; + else if (kerr == KRB5_PARSE_ILLCHAR || kerr == KRB5_PARSE_MALFORMED) { + gssapi_krb5_set_error_string (); + *minor_status = kerr; + return GSS_S_BAD_NAME; + } else { + gssapi_krb5_set_error_string (); + *minor_status = kerr; + return GSS_S_FAILURE; + } +} + +static OM_uint32 +import_export_name (OM_uint32 *minor_status, + const gss_buffer_t input_name_buffer, + gss_name_t *output_name) +{ + unsigned char *p; + uint32_t length; + OM_uint32 ret; + char *name; + + if (input_name_buffer->length < 10 + GSS_KRB5_MECHANISM->length) + return GSS_S_BAD_NAME; + + /* TOK, MECH_OID_LEN, DER(MECH_OID), NAME_LEN, NAME */ + + p = input_name_buffer->value; + + if (memcmp(&p[0], "\x04\x01\x00", 3) != 0 || + p[3] != GSS_KRB5_MECHANISM->length + 2 || + p[4] != 0x06 || + p[5] != GSS_KRB5_MECHANISM->length || + memcmp(&p[6], GSS_KRB5_MECHANISM->elements, + GSS_KRB5_MECHANISM->length) != 0) + return GSS_S_BAD_NAME; + + p += 6 + GSS_KRB5_MECHANISM->length; + + length = p[0] << 24 | p[1] << 16 | p[2] << 8 | p[3]; + p += 4; + + if (length > input_name_buffer->length - 10 - GSS_KRB5_MECHANISM->length) + return GSS_S_BAD_NAME; + + name = malloc(length + 1); + if (name == NULL) { + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + memcpy(name, p, length); + name[length] = '\0'; + + ret = parse_krb5_name(minor_status, name, output_name); + free(name); + + return ret; +} + +int +gss_oid_equal(const gss_OID a, const gss_OID b) +{ + if (a == b) + return 1; + else if (a == GSS_C_NO_OID || b == GSS_C_NO_OID || a->length != b->length) + return 0; + else + return memcmp(a->elements, b->elements, a->length) == 0; +} + +OM_uint32 gss_import_name + (OM_uint32 * minor_status, + const gss_buffer_t input_name_buffer, + const gss_OID input_name_type, + gss_name_t * output_name + ) +{ + GSSAPI_KRB5_INIT (); + + *minor_status = 0; + *output_name = GSS_C_NO_NAME; + + if (gss_oid_equal(input_name_type, GSS_C_NT_HOSTBASED_SERVICE)) + return import_hostbased_name (minor_status, + input_name_buffer, + output_name); + else if (gss_oid_equal(input_name_type, GSS_C_NO_OID) + || gss_oid_equal(input_name_type, GSS_C_NT_USER_NAME) + || gss_oid_equal(input_name_type, GSS_KRB5_NT_PRINCIPAL_NAME)) + /* default printable syntax */ + return import_krb5_name (minor_status, + input_name_buffer, + output_name); + else if (gss_oid_equal(input_name_type, GSS_C_NT_EXPORT_NAME)) { + return import_export_name(minor_status, + input_name_buffer, + output_name); + } else { + *minor_status = 0; + return GSS_S_BAD_NAMETYPE; + } +} diff --git a/source4/heimdal/lib/gssapi/init.c b/source4/heimdal/lib/gssapi/init.c new file mode 100644 index 0000000000..37f46624ae --- /dev/null +++ b/source4/heimdal/lib/gssapi/init.c @@ -0,0 +1,111 @@ +/* + * Copyright (c) 1997 - 2001, 2003 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 "gssapi_locl.h" + +RCSID("$Id: init.c,v 1.7 2003/07/22 19:50:11 lha Exp $"); + +static HEIMDAL_MUTEX gssapi_krb5_context_mutex = HEIMDAL_MUTEX_INITIALIZER; +static int created_key; +static HEIMDAL_thread_key gssapi_context_key; + +static void +gssapi_destroy_thread_context(void *ptr) +{ + struct gssapi_thr_context *ctx = ptr; + + if (ctx == NULL) + return; + if (ctx->error_string) + free(ctx->error_string); + HEIMDAL_MUTEX_destroy(&ctx->mutex); + free(ctx); +} + + +struct gssapi_thr_context * +gssapi_get_thread_context(int createp) +{ + struct gssapi_thr_context *ctx; + int ret; + + HEIMDAL_MUTEX_lock(&gssapi_krb5_context_mutex); + + if (!created_key) + abort(); + ctx = HEIMDAL_getspecific(gssapi_context_key); + if (ctx == NULL) { + if (!createp) + goto fail; + ctx = malloc(sizeof(*ctx)); + if (ctx == NULL) + goto fail; + ctx->error_string = NULL; + HEIMDAL_MUTEX_init(&ctx->mutex); + HEIMDAL_setspecific(gssapi_context_key, ctx, ret); + if (ret) + goto fail; + } + HEIMDAL_MUTEX_unlock(&gssapi_krb5_context_mutex); + return ctx; + fail: + HEIMDAL_MUTEX_unlock(&gssapi_krb5_context_mutex); + if (ctx) + free(ctx); + return NULL; +} + +krb5_error_code +gssapi_krb5_init (void) +{ + krb5_error_code ret = 0; + + HEIMDAL_MUTEX_lock(&gssapi_krb5_context_mutex); + + if(gssapi_krb5_context == NULL) + ret = krb5_init_context (&gssapi_krb5_context); + if (ret == 0 && !created_key) { + HEIMDAL_key_create(&gssapi_context_key, + gssapi_destroy_thread_context, + ret); + if (ret) { + krb5_free_context(gssapi_krb5_context); + gssapi_krb5_context = NULL; + } else + created_key = 1; + } + + HEIMDAL_MUTEX_unlock(&gssapi_krb5_context_mutex); + + return ret; +} diff --git a/source4/heimdal/lib/gssapi/init_sec_context.c b/source4/heimdal/lib/gssapi/init_sec_context.c new file mode 100644 index 0000000000..c7e4aa50d6 --- /dev/null +++ b/source4/heimdal/lib/gssapi/init_sec_context.c @@ -0,0 +1,1261 @@ +/* + * Copyright (c) 1997 - 2003 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 "gssapi_locl.h" + +RCSID("$Id: init_sec_context.c,v 1.57 2005/05/30 20:58:29 lha Exp $"); + +/* + * copy the addresses from `input_chan_bindings' (if any) to + * the auth context `ac' + */ + +static OM_uint32 +gsskrb5_set_addresses( + krb5_auth_context ac, + const gss_channel_bindings_t input_chan_bindings) +{ + /* Port numbers are expected to be in application_data.value, + * initator's port first */ + + krb5_address initiator_addr, acceptor_addr; + krb5_error_code kret; + + if (input_chan_bindings == GSS_C_NO_CHANNEL_BINDINGS + || input_chan_bindings->application_data.length != + 2 * sizeof(ac->local_port)) + return 0; + + memset(&initiator_addr, 0, sizeof(initiator_addr)); + memset(&acceptor_addr, 0, sizeof(acceptor_addr)); + + ac->local_port = + *(int16_t *) input_chan_bindings->application_data.value; + + ac->remote_port = + *((int16_t *) input_chan_bindings->application_data.value + 1); + + kret = gss_address_to_krb5addr(input_chan_bindings->acceptor_addrtype, + &input_chan_bindings->acceptor_address, + ac->remote_port, + &acceptor_addr); + if (kret) + return kret; + + kret = gss_address_to_krb5addr(input_chan_bindings->initiator_addrtype, + &input_chan_bindings->initiator_address, + ac->local_port, + &initiator_addr); + if (kret) { + krb5_free_address (gssapi_krb5_context, &acceptor_addr); + return kret; + } + + kret = krb5_auth_con_setaddrs(gssapi_krb5_context, + ac, + &initiator_addr, /* local address */ + &acceptor_addr); /* remote address */ + + krb5_free_address (gssapi_krb5_context, &initiator_addr); + krb5_free_address (gssapi_krb5_context, &acceptor_addr); + +#if 0 + free(input_chan_bindings->application_data.value); + input_chan_bindings->application_data.value = NULL; + input_chan_bindings->application_data.length = 0; +#endif + + return kret; +} + +OM_uint32 +_gsskrb5_create_ctx( + OM_uint32 * minor_status, + gss_ctx_id_t * context_handle, + const gss_channel_bindings_t input_chan_bindings, + enum gss_ctx_id_t_state state) +{ + krb5_error_code kret; + + *context_handle = malloc(sizeof(**context_handle)); + if (*context_handle == NULL) { + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + (*context_handle)->auth_context = NULL; + (*context_handle)->source = NULL; + (*context_handle)->target = NULL; + (*context_handle)->state = state; + (*context_handle)->flags = 0; + (*context_handle)->more_flags = 0; + (*context_handle)->service_keyblock = NULL; + (*context_handle)->ticket = NULL; + krb5_data_zero(&(*context_handle)->fwd_data); + (*context_handle)->lifetime = GSS_C_INDEFINITE; + (*context_handle)->order = NULL; + HEIMDAL_MUTEX_init(&(*context_handle)->ctx_id_mutex); + + kret = krb5_auth_con_init (gssapi_krb5_context, + &(*context_handle)->auth_context); + if (kret) { + *minor_status = kret; + gssapi_krb5_set_error_string (); + + HEIMDAL_MUTEX_destroy(&(*context_handle)->ctx_id_mutex); + + return GSS_S_FAILURE; + } + + kret = gsskrb5_set_addresses((*context_handle)->auth_context, + input_chan_bindings); + if (kret) { + *minor_status = kret; + + HEIMDAL_MUTEX_destroy(&(*context_handle)->ctx_id_mutex); + + krb5_auth_con_free(gssapi_krb5_context, (*context_handle)->auth_context); + + return GSS_S_BAD_BINDINGS; + } + + return GSS_S_COMPLETE; +} + +static OM_uint32 +gsskrb5_get_creds( + OM_uint32 * minor_status, + const gss_cred_id_t initiator_cred_handle, + gss_ctx_id_t * context_handle, + const gss_name_t target_name, + OM_uint32 time_req, + OM_uint32 * time_rec, + krb5_creds ** cred) +{ + OM_uint32 ret; + krb5_error_code kret; + krb5_creds this_cred; + krb5_ccache ccache = NULL; + OM_uint32 lifetime_rec; + + *cred = NULL; + + if (initiator_cred_handle == GSS_C_NO_CREDENTIAL) { + kret = krb5_cc_default (gssapi_krb5_context, &ccache); + if (kret) { + gssapi_krb5_set_error_string (); + *minor_status = kret; + return GSS_S_FAILURE; + } + } else { + ccache = initiator_cred_handle->ccache; + } + + kret = krb5_cc_get_principal(gssapi_krb5_context, + ccache, + &(*context_handle)->source); + if (kret) { + gssapi_krb5_set_error_string (); + *minor_status = kret; + return GSS_S_FAILURE; + } + + kret = krb5_copy_principal(gssapi_krb5_context, + target_name, + &(*context_handle)->target); + if (kret) { + gssapi_krb5_set_error_string (); + *minor_status = kret; + return GSS_S_FAILURE; + } + + memset(&this_cred, 0, sizeof(this_cred)); + this_cred.client = (*context_handle)->source; + this_cred.server = (*context_handle)->target; + + if (time_req && time_req != GSS_C_INDEFINITE) { + krb5_timestamp ts; + + krb5_timeofday (gssapi_krb5_context, &ts); + this_cred.times.endtime = ts + time_req; + } else { + this_cred.times.endtime = 0; + } + + this_cred.session.keytype = KEYTYPE_NULL; + + kret = krb5_get_credentials(gssapi_krb5_context, + 0, + ccache, + &this_cred, + cred); + if (kret) { + gssapi_krb5_set_error_string (); + *minor_status = kret; + return GSS_S_FAILURE; + } + + (*context_handle)->lifetime = (*cred)->times.endtime; + + ret = gssapi_lifetime_left(minor_status, + (*context_handle)->lifetime, + &lifetime_rec); + if (ret) return ret; + + if (lifetime_rec == 0) { + *minor_status = 0; + return GSS_S_CONTEXT_EXPIRED; + } + + if (time_rec) *time_rec = lifetime_rec; + + if (initiator_cred_handle == GSS_C_NO_CREDENTIAL) { + krb5_cc_close(gssapi_krb5_context, ccache); + } + + return GSS_S_COMPLETE; +} + +static OM_uint32 +gsskrb5_initiator_ready( + OM_uint32 * minor_status, + gss_ctx_id_t * context_handle) +{ + OM_uint32 ret; + int32_t seq_number; + int is_cfx = 0; + u_int32_t flags = (*context_handle)->flags; + + krb5_auth_getremoteseqnumber (gssapi_krb5_context, + (*context_handle)->auth_context, + &seq_number); + + gsskrb5_is_cfx(*context_handle, &is_cfx); + + ret = _gssapi_msg_order_create(minor_status, + &(*context_handle)->order, + _gssapi_msg_order_f(flags), + seq_number, 0, is_cfx); + if (ret) return ret; + + (*context_handle)->state = INITIATOR_READY; + (*context_handle)->more_flags |= OPEN; + + return GSS_S_COMPLETE; +} + +/* + * handle delegated creds in init-sec-context + */ + +static void +gsskrb5_do_delegation( + krb5_auth_context ac, + krb5_ccache ccache, + krb5_creds *cred, + const gss_name_t target_name, + krb5_data *fwd_data, + int *flags) +{ + krb5_creds creds; + krb5_kdc_flags fwd_flags; + krb5_error_code kret; + + memset (&creds, 0, sizeof(creds)); + krb5_data_zero (fwd_data); + + kret = krb5_cc_get_principal(gssapi_krb5_context, ccache, &creds.client); + if (kret) + goto out; + + kret = krb5_build_principal(gssapi_krb5_context, + &creds.server, + strlen(creds.client->realm), + creds.client->realm, + KRB5_TGS_NAME, + creds.client->realm, + NULL); + if (kret) + goto out; + + creds.times.endtime = 0; + + fwd_flags.i = 0; + fwd_flags.b.forwarded = 1; + fwd_flags.b.forwardable = 1; + + if ( /*target_name->name.name_type != KRB5_NT_SRV_HST ||*/ + target_name->name.name_string.len < 2) + goto out; + + kret = krb5_get_forwarded_creds(gssapi_krb5_context, + ac, + ccache, + fwd_flags.i, + target_name->name.name_string.val[1], + &creds, + fwd_data); + + out: + if (kret) + *flags &= ~GSS_C_DELEG_FLAG; + else + *flags |= GSS_C_DELEG_FLAG; + + if (creds.client) + krb5_free_principal(gssapi_krb5_context, creds.client); + if (creds.server) + krb5_free_principal(gssapi_krb5_context, creds.server); +} + +/* + * first stage of init-sec-context + */ + +static OM_uint32 +gsskrb5_initiator_start( + OM_uint32 * minor_status, + const gss_cred_id_t initiator_cred_handle, + gss_ctx_id_t * context_handle, + const gss_name_t target_name, + const gss_OID mech_type, + OM_uint32 req_flags, + OM_uint32 time_req, + const gss_channel_bindings_t input_chan_bindings, + const gss_buffer_t input_token, + gss_buffer_t output_token, + OM_uint32 * ret_flags, + OM_uint32 * time_rec) +{ + OM_uint32 ret = GSS_S_FAILURE; + krb5_error_code kret; + krb5_flags ap_options; + krb5_creds *cred = NULL; + krb5_data outbuf; + krb5_ccache ccache = NULL; + u_int32_t flags; + krb5_data authenticator; + Checksum cksum; + krb5_enctype enctype; + krb5_data fwd_data; + + krb5_data_zero(&outbuf); + krb5_data_zero(&fwd_data); + + (*context_handle)->more_flags |= LOCAL; + + /* We need to get the credentials for the requested target */ + ret = gsskrb5_get_creds(minor_status, + initiator_cred_handle, + context_handle, + target_name, + time_req, + time_rec, + &cred); + if (ret) return ret; + + /* + * We need to setup some compat stuff, this assumes that context_handle->target is already set + */ + ret = _gss_DES3_get_mic_compat(minor_status, *context_handle); + if (ret) return ret; + + /* + * We need a sequence number + */ + + krb5_auth_con_addflags(gssapi_krb5_context, + (*context_handle)->auth_context, + KRB5_AUTH_CONTEXT_DO_SEQUENCE, + NULL); + + /* We need the key and a random local subkey */ + { + kret = krb5_auth_con_setkey(gssapi_krb5_context, + (*context_handle)->auth_context, + &cred->session); + if (kret) { + gssapi_krb5_set_error_string (); + *minor_status = kret; + return GSS_S_FAILURE; + } + + kret = krb5_auth_con_generatelocalsubkey(gssapi_krb5_context, + (*context_handle)->auth_context, + &cred->session); + if (kret) { + gssapi_krb5_set_error_string (); + *minor_status = kret; + return GSS_S_FAILURE; + } + } + + /* We need to prepare the flags used for this context */ + { + flags = 0; + ap_options = 0; + + if (req_flags & GSS_C_DELEG_FLAG) { + gsskrb5_do_delegation((*context_handle)->auth_context, + ccache, cred, target_name, &fwd_data, &flags); + } + + if (req_flags & GSS_C_MUTUAL_FLAG) { + flags |= GSS_C_MUTUAL_FLAG; + ap_options |= AP_OPTS_MUTUAL_REQUIRED; + } + + if (req_flags & GSS_C_REPLAY_FLAG) { + flags |= GSS_C_REPLAY_FLAG; + } + + if (req_flags & GSS_C_SEQUENCE_FLAG) { + flags |= GSS_C_SEQUENCE_FLAG; + } + + if (req_flags & GSS_C_ANON_FLAG) { + ;/* XXX */ + } + + if (req_flags & GSS_C_DCE_STYLE) { + flags |= GSS_C_DCE_STYLE; + /* GSS_C_DCE_STYLE implies GSS_C_MUTUAL_FLAG */ + flags |= GSS_C_MUTUAL_FLAG; + ap_options |= AP_OPTS_MUTUAL_REQUIRED; + } + + if (req_flags & GSS_C_IDENTIFY_FLAG) { + flags |= GSS_C_IDENTIFY_FLAG; + } + + if (req_flags & GSS_C_EXTENDED_ERROR_FLAG) { + flags |= GSS_C_EXTENDED_ERROR_FLAG; + } + + /* TODO: why are this always there? --metze */ + flags |= GSS_C_CONF_FLAG; + flags |= GSS_C_INTEG_FLAG; + flags |= GSS_C_TRANS_FLAG; + + if (ret_flags) *ret_flags = flags; + (*context_handle)->flags = flags; + } + + /* We need to generate the 8003 checksum */ + { + ret = gssapi_krb5_create_8003_checksum(minor_status, + input_chan_bindings, + flags, + &fwd_data, + &cksum); + krb5_data_free (&fwd_data); + if (ret) return ret; + } + + enctype = (*context_handle)->auth_context->keyblock->keytype; + + /* We need to create an Authenticator */ + { + kret = krb5_build_authenticator (gssapi_krb5_context, + (*context_handle)->auth_context, + enctype, + cred, + &cksum, + NULL, + &authenticator, + KRB5_KU_AP_REQ_AUTH); + free_Checksum(&cksum); + if (kret) { + gssapi_krb5_set_error_string (); + *minor_status = kret; + return GSS_S_FAILURE; + } + } + + /* We need to create the AP_REQ */ + { + kret = krb5_build_ap_req(gssapi_krb5_context, + enctype, + cred, + ap_options, + authenticator, + &outbuf); + if (kret) { + gssapi_krb5_set_error_string (); + *minor_status = kret; + return GSS_S_FAILURE; + } + } + + /* We need to encapsulate the AP_REQ if GSS_C_DCE_STYLE isn't in use */ + { + if (!(flags & GSS_C_DCE_STYLE)) { + ret = gssapi_krb5_encapsulate(minor_status, &outbuf, output_token, + "\x01\x00", GSS_KRB5_MECHANISM); + krb5_data_free (&outbuf); + if (ret) return ret; + } else { + output_token->length = outbuf.length; + output_token->value = outbuf.data; + } + } + + /* We no longer need the creds */ + krb5_free_creds(gssapi_krb5_context, cred); + + /* We are done if GSS_C_MUTUAL_FLAG is in use */ + if (flags & GSS_C_MUTUAL_FLAG) { + (*context_handle)->state = INITIATOR_WAIT_FOR_MUTAL; + return GSS_S_CONTINUE_NEEDED; + } + + return gsskrb5_initiator_ready(minor_status, context_handle); +} + +static OM_uint32 +gsskrb5_initiator_wait_for_mutual( + OM_uint32 * minor_status, + const gss_cred_id_t initiator_cred_handle, + gss_ctx_id_t * context_handle, + const gss_name_t target_name, + const gss_OID mech_type, + OM_uint32 req_flags, + OM_uint32 time_req, + const gss_channel_bindings_t input_chan_bindings, + const gss_buffer_t input_token, + gss_buffer_t output_token, + OM_uint32 * ret_flags, + OM_uint32 * time_rec) +{ + OM_uint32 ret; + krb5_error_code kret; + krb5_data inbuf; + u_int32_t flags = (*context_handle)->flags; + OM_uint32 l_seq_number; + OM_uint32 r_seq_number; + + /* We need to decapsulate the AP_REP if GSS_C_DCE_STYLE isn't in use */ + { + if (!(flags & GSS_C_DCE_STYLE)) { + ret = gssapi_krb5_decapsulate(minor_status, input_token, &inbuf, + "\x02\x00", GSS_KRB5_MECHANISM); + if (ret) return ret; + } else { + inbuf.length = input_token->length; + inbuf.data = input_token->value; + } + } + + /* We need to verify the AP_REP */ + { + krb5_ap_rep_enc_part *repl; + + kret = krb5_rd_rep(gssapi_krb5_context, + (*context_handle)->auth_context, + &inbuf, + &repl); + if (kret) { + gssapi_krb5_set_error_string (); + *minor_status = kret; + return GSS_S_FAILURE; + } + krb5_free_ap_rep_enc_part(gssapi_krb5_context, repl); + } + + /* We need to check the liftime */ + { + OM_uint32 lifetime_rec; + + ret = gssapi_lifetime_left(minor_status, + (*context_handle)->lifetime, + &lifetime_rec); + if (ret) return ret; + + if (lifetime_rec == 0) { + return GSS_S_CONTEXT_EXPIRED; + } + + if (time_rec) *time_rec = lifetime_rec; + } + + /* We need to give the caller the flags which are in use */ + if (ret_flags) *ret_flags = (*context_handle)->flags; + + /* We are done here if GSS_C_DCE_STYLE isn't in use */ + if (!(flags & GSS_C_DCE_STYLE)) { + return gsskrb5_initiator_ready(minor_status, context_handle); + } + + /* + * We need to set the local seq_number to the remote one just for the krb5_mk_rep(), + * and then we need to use the old local seq_number again for the GSS_Wrap() messages + */ + { + kret = krb5_auth_getremoteseqnumber(gssapi_krb5_context, + (*context_handle)->auth_context, + &r_seq_number); + if (kret) { + gssapi_krb5_set_error_string (); + *minor_status = kret; + return GSS_S_FAILURE; + } + + kret = krb5_auth_con_getlocalseqnumber(gssapi_krb5_context, + (*context_handle)->auth_context, + &l_seq_number); + if (kret) { + gssapi_krb5_set_error_string (); + *minor_status = kret; + return GSS_S_FAILURE; + } + + kret = krb5_auth_con_setlocalseqnumber(gssapi_krb5_context, + (*context_handle)->auth_context, + r_seq_number); + if (kret) { + gssapi_krb5_set_error_string (); + *minor_status = kret; + return GSS_S_FAILURE; + } + } + + /* We need to create an AP_REP */ + { + krb5_data outbuf; + + kret = krb5_mk_rep(gssapi_krb5_context, + (*context_handle)->auth_context, + &outbuf); + if (kret) { + gssapi_krb5_set_error_string (); + *minor_status = kret; + return GSS_S_FAILURE; + } + + output_token->length = outbuf.length; + output_token->value = outbuf.data; + } + + /* We need to reset the local seq_number */ + { + kret = krb5_auth_con_setlocalseqnumber(gssapi_krb5_context, + (*context_handle)->auth_context, + l_seq_number); + if (kret) { + gssapi_krb5_set_error_string (); + *minor_status = kret; + return GSS_S_FAILURE; + } + } + + return gsskrb5_initiator_ready(minor_status, context_handle); +} + +static OM_uint32 +gsskrb5_init_sec_context( + OM_uint32 * minor_status, + const gss_cred_id_t initiator_cred_handle, + gss_ctx_id_t * context_handle, + const gss_name_t target_name, + const gss_OID mech_type, + OM_uint32 req_flags, + OM_uint32 time_req, + const gss_channel_bindings_t input_chan_bindings, + const gss_buffer_t input_token, + gss_OID * actual_mech_type, + gss_buffer_t output_token, + OM_uint32 * ret_flags, + OM_uint32 * time_rec) +{ + OM_uint32 ret; + + if (*context_handle == GSS_C_NO_CONTEXT) { + ret = _gsskrb5_create_ctx(minor_status, + context_handle, + input_chan_bindings, + INITIATOR_START); + if (ret) return ret; + } + + if (actual_mech_type) *actual_mech_type = GSS_KRB5_MECHANISM; + + HEIMDAL_MUTEX_lock(&(*context_handle)->ctx_id_mutex); + + switch ((*context_handle)->state) { + case INITIATOR_START: + ret = gsskrb5_initiator_start(minor_status, + initiator_cred_handle, + context_handle, + target_name, + mech_type, + req_flags, + time_req, + input_chan_bindings, + input_token, + output_token, + ret_flags, + time_rec); + break; + case INITIATOR_WAIT_FOR_MUTAL: + ret = gsskrb5_initiator_wait_for_mutual(minor_status, + initiator_cred_handle, + context_handle, + target_name, + mech_type, + req_flags, + time_req, + input_chan_bindings, + input_token, + output_token, + ret_flags, + time_rec); + break; + case INITIATOR_READY: + /* should this be GSS_S_BAD_STATUS ? --metze */ + + /* We need to check the liftime */ + { + OM_uint32 lifetime_rec; + + ret = gssapi_lifetime_left(minor_status, + (*context_handle)->lifetime, + &lifetime_rec); + if (ret) break; + + if (lifetime_rec == 0) { + *minor_status = 0; + ret = GSS_S_CONTEXT_EXPIRED; + break; + } + + if (time_rec) *time_rec = lifetime_rec; + } + + /* We need to give the caller the flags which are in use */ + if (ret_flags) *ret_flags = (*context_handle)->flags; + + ret = GSS_S_COMPLETE; + break; + default: + /* TODO: is this correct here? --metze */ + ret = GSS_S_BAD_STATUS; + break; + } + + HEIMDAL_MUTEX_unlock(&(*context_handle)->ctx_id_mutex); + + return ret; +} + +static OM_uint32 +spnego_reply + (OM_uint32 * minor_status, + const gss_cred_id_t initiator_cred_handle, + gss_ctx_id_t * context_handle, + const gss_name_t target_name, + const gss_OID mech_type, + OM_uint32 req_flags, + OM_uint32 time_req, + const gss_channel_bindings_t input_chan_bindings, + const gss_buffer_t input_token, + gss_OID * actual_mech_type, + gss_buffer_t output_token, + OM_uint32 * ret_flags, + OM_uint32 * time_rec + ) +{ + OM_uint32 ret; + krb5_data indata; + NegTokenTarg targ; + u_char oidbuf[17]; + size_t oidlen; + gss_buffer_desc sub_token; + ssize_t mech_len; + const u_char *p; + size_t len, taglen; + krb5_boolean require_mic; + + output_token->length = 0; + output_token->value = NULL; + + /* + * SPNEGO doesn't include gss wrapping on SubsequentContextToken + * like the Kerberos 5 mech does. But lets check for it anyway. + */ + + mech_len = gssapi_krb5_get_mech (input_token->value, + input_token->length, + &p); + + if (mech_len < 0) { + indata.data = input_token->value; + indata.length = input_token->length; + } else if (mech_len == GSS_KRB5_MECHANISM->length + && memcmp(GSS_KRB5_MECHANISM->elements, p, mech_len) == 0) + return gsskrb5_init_sec_context (minor_status, + initiator_cred_handle, + context_handle, + target_name, + GSS_KRB5_MECHANISM, + req_flags, + time_req, + input_chan_bindings, + input_token, + actual_mech_type, + output_token, + ret_flags, + time_rec); + else if (mech_len == GSS_SPNEGO_MECHANISM->length + && memcmp(GSS_SPNEGO_MECHANISM->elements, p, mech_len) == 0){ + ret = _gssapi_decapsulate (minor_status, + input_token, + &indata, + GSS_SPNEGO_MECHANISM); + if (ret) + return ret; + } else + return GSS_S_BAD_MECH; + + ret = der_match_tag_and_length((const char *)indata.data, + indata.length, + ASN1_C_CONTEXT, CONS, 1, &len, &taglen); + if (ret) + return ret; + + if(len > indata.length - taglen) + return ASN1_OVERRUN; + + ret = decode_NegTokenTarg((const char *)indata.data + taglen, + len, &targ, NULL); + if (ret) { + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + + if (targ.negResult == NULL + || *(targ.negResult) == reject + || targ.supportedMech == NULL) { + free_NegTokenTarg(&targ); + return GSS_S_BAD_MECH; + } + + ret = der_put_oid(oidbuf + sizeof(oidbuf) - 1, + sizeof(oidbuf), + targ.supportedMech, + &oidlen); + if (ret || oidlen != GSS_KRB5_MECHANISM->length + || memcmp(oidbuf + sizeof(oidbuf) - oidlen, + GSS_KRB5_MECHANISM->elements, + oidlen) != 0) { + free_NegTokenTarg(&targ); + return GSS_S_BAD_MECH; + } + + if (targ.responseToken != NULL) { + sub_token.length = targ.responseToken->length; + sub_token.value = targ.responseToken->data; + } else { + sub_token.length = 0; + sub_token.value = NULL; + } + + ret = gsskrb5_init_sec_context(minor_status, + initiator_cred_handle, + context_handle, + target_name, + GSS_KRB5_MECHANISM, + req_flags, + time_req, + input_chan_bindings, + &sub_token, + actual_mech_type, + output_token, + ret_flags, + time_rec); + if (ret) { + free_NegTokenTarg(&targ); + return ret; + } + + /* + * Verify the mechListMIC if CFX was used; or if local policy + * dictated so. + */ + ret = _gss_spnego_require_mechlist_mic(minor_status, *context_handle, + &require_mic); + if (ret) { + free_NegTokenTarg(&targ); + return ret; + } + + if (require_mic) { + MechTypeList mechlist; + MechType m0; + size_t buf_len; + gss_buffer_desc mic_buf, mech_buf; + + if (targ.mechListMIC == NULL) { + free_NegTokenTarg(&targ); + *minor_status = 0; + return GSS_S_BAD_MIC; + } + + mechlist.len = 1; + mechlist.val = &m0; + + ret = der_get_oid(GSS_KRB5_MECHANISM->elements, + GSS_KRB5_MECHANISM->length, + &m0, + NULL); + if (ret) { + free_NegTokenTarg(&targ); + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + + ASN1_MALLOC_ENCODE(MechTypeList, mech_buf.value, mech_buf.length, + &mechlist, &buf_len, ret); + if (ret) { + free_NegTokenTarg(&targ); + free_oid(&m0); + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + if (mech_buf.length != buf_len) + abort(); + + mic_buf.length = targ.mechListMIC->length; + mic_buf.value = targ.mechListMIC->data; + + ret = gss_verify_mic(minor_status, *context_handle, + &mech_buf, &mic_buf, NULL); + free(mech_buf.value); + free_oid(&m0); + } + free_NegTokenTarg(&targ); + return ret; +} + +static OM_uint32 +spnego_initial + (OM_uint32 * minor_status, + const gss_cred_id_t initiator_cred_handle, + gss_ctx_id_t * context_handle, + const gss_name_t target_name, + const gss_OID mech_type, + OM_uint32 req_flags, + OM_uint32 time_req, + const gss_channel_bindings_t input_chan_bindings, + const gss_buffer_t input_token, + gss_OID * actual_mech_type, + gss_buffer_t output_token, + OM_uint32 * ret_flags, + OM_uint32 * time_rec + ) +{ + NegTokenInit ni; + int ret; + OM_uint32 sub, minor; + gss_buffer_desc mech_token; + u_char *buf; + size_t buf_size, buf_len; + krb5_data data; +#if 1 + size_t ni_len; +#endif + + memset (&ni, 0, sizeof(ni)); + + ALLOC(ni.mechTypes, 1); + if (ni.mechTypes == NULL) { + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + ALLOC_SEQ(ni.mechTypes, 1); + if (ni.mechTypes->val == NULL) { + free_NegTokenInit(&ni); + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + ret = der_get_oid(GSS_KRB5_MECHANISM->elements, + GSS_KRB5_MECHANISM->length, + &ni.mechTypes->val[0], + NULL); + if (ret) { + free_NegTokenInit(&ni); + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + +#if 0 + ALLOC(ni.reqFlags, 1); + if (ni.reqFlags == NULL) { + free_NegTokenInit(&ni); + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + ni.reqFlags->delegFlag = req_flags & GSS_C_DELEG_FLAG; + ni.reqFlags->mutualFlag = req_flags & GSS_C_MUTUAL_FLAG; + ni.reqFlags->replayFlag = req_flags & GSS_C_REPLAY_FLAG; + ni.reqFlags->sequenceFlag = req_flags & GSS_C_SEQUENCE_FLAG; + ni.reqFlags->anonFlag = req_flags & GSS_C_ANON_FLAG; + ni.reqFlags->confFlag = req_flags & GSS_C_CONF_FLAG; + ni.reqFlags->integFlag = req_flags & GSS_C_INTEG_FLAG; +#else + ni.reqFlags = NULL; +#endif + + sub = gsskrb5_init_sec_context(&minor, + initiator_cred_handle, + context_handle, + target_name, + GSS_KRB5_MECHANISM, + req_flags, + time_req, + input_chan_bindings, + GSS_C_NO_BUFFER, + actual_mech_type, + &mech_token, + ret_flags, + time_rec); + if (GSS_ERROR(sub)) { + free_NegTokenInit(&ni); + return sub; + } + if (mech_token.length != 0) { + ALLOC(ni.mechToken, 1); + if (ni.mechToken == NULL) { + free_NegTokenInit(&ni); + gss_release_buffer(&minor, &mech_token); + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + ni.mechToken->length = mech_token.length; + ni.mechToken->data = malloc(mech_token.length); + if (ni.mechToken->data == NULL && mech_token.length != 0) { + free_NegTokenInit(&ni); + gss_release_buffer(&minor, &mech_token); + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + memcpy(ni.mechToken->data, mech_token.value, mech_token.length); + gss_release_buffer(&minor, &mech_token); + } else + ni.mechToken = NULL; + + /* XXX ignore mech list mic for now */ + ni.mechListMIC = NULL; + + +#if 0 + { + int ret; + NegotiationToken nt; + + nt.element = choice_NegotiationToken_negTokenInit; + nt.u.negTokenInit = ni; + + ASN1_MALLOC_ENCODE(NegotiationToken, buf, buf_size, + &nt, &buf_len, ret); + if (buf_size != buf_len) + abort(); + } +#else + ni_len = length_NegTokenInit(&ni); + buf_size = 1 + length_len(ni_len) + ni_len; + + buf = malloc(buf_size); + if (buf == NULL) { + free_NegTokenInit(&ni); + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + + ret = encode_NegTokenInit(buf + buf_size - 1, + ni_len, + &ni, &buf_len); + if (ret == 0 && ni_len != buf_len) + abort(); + + if (ret == 0) { + size_t tmp; + + ret = der_put_length_and_tag(buf + buf_size - buf_len - 1, + buf_size - buf_len, + buf_len, + ASN1_C_CONTEXT, + CONS, + 0, + &tmp); + if (ret == 0 && tmp + buf_len != buf_size) + abort(); + } + if (ret) { + *minor_status = ret; + free(buf); + free_NegTokenInit(&ni); + return GSS_S_FAILURE; + } + +#endif + data.data = buf; + data.length = buf_size; + + free_NegTokenInit(&ni); + if (ret) + return ret; + + sub = _gssapi_encapsulate(minor_status, + &data, + output_token, + GSS_SPNEGO_MECHANISM); + free (buf); + + if (sub) + return sub; + + return GSS_S_CONTINUE_NEEDED; +} + +static OM_uint32 +spnego_init_sec_context + (OM_uint32 * minor_status, + const gss_cred_id_t initiator_cred_handle, + gss_ctx_id_t * context_handle, + const gss_name_t target_name, + const gss_OID mech_type, + OM_uint32 req_flags, + OM_uint32 time_req, + const gss_channel_bindings_t input_chan_bindings, + const gss_buffer_t input_token, + gss_OID * actual_mech_type, + gss_buffer_t output_token, + OM_uint32 * ret_flags, + OM_uint32 * time_rec + ) +{ + if (input_token == GSS_C_NO_BUFFER || input_token->length == 0) + return spnego_initial (minor_status, + initiator_cred_handle, + context_handle, + target_name, + mech_type, + req_flags, + time_req, + input_chan_bindings, + input_token, + actual_mech_type, + output_token, + ret_flags, + time_rec); + else + return spnego_reply (minor_status, + initiator_cred_handle, + context_handle, + target_name, + mech_type, + req_flags, + time_req, + input_chan_bindings, + input_token, + actual_mech_type, + output_token, + ret_flags, + time_rec); +} + +/* + * gss_init_sec_context + */ + +OM_uint32 gss_init_sec_context( + OM_uint32 * minor_status, + const gss_cred_id_t initiator_cred_handle, + gss_ctx_id_t * context_handle, + const gss_name_t target_name, + const gss_OID mech_type, + OM_uint32 req_flags, + OM_uint32 time_req, + const gss_channel_bindings_t input_chan_bindings, + const gss_buffer_t input_token, + gss_OID * actual_mech_type, + gss_buffer_t output_token, + OM_uint32 * ret_flags, + OM_uint32 * time_rec) +{ + GSSAPI_KRB5_INIT (); + + *minor_status = 0; + + if (actual_mech_type) *actual_mech_type = GSS_C_NO_OID; + + output_token->length = 0; + output_token->value = NULL; + + if (ret_flags) *ret_flags = 0; + if (time_rec) *time_rec = 0; + + if (target_name == GSS_C_NO_NAME) return GSS_S_BAD_NAME; + + if (mech_type == GSS_C_NO_OID || + gss_oid_equal(mech_type, GSS_KRB5_MECHANISM)) { + return gsskrb5_init_sec_context(minor_status, + initiator_cred_handle, + context_handle, + target_name, + mech_type, + req_flags, + time_req, + input_chan_bindings, + input_token, + actual_mech_type, + output_token, + ret_flags, + time_rec); + } else if (gss_oid_equal(mech_type, GSS_SPNEGO_MECHANISM)) { + return spnego_init_sec_context (minor_status, + initiator_cred_handle, + context_handle, + target_name, + mech_type, + req_flags, + time_req, + input_chan_bindings, + input_token, + actual_mech_type, + output_token, + ret_flags, + time_rec); + } + + return GSS_S_BAD_MECH; +} diff --git a/source4/heimdal/lib/gssapi/inquire_cred.c b/source4/heimdal/lib/gssapi/inquire_cred.c new file mode 100644 index 0000000000..9ed1ff4cc4 --- /dev/null +++ b/source4/heimdal/lib/gssapi/inquire_cred.c @@ -0,0 +1,123 @@ +/* + * Copyright (c) 1997, 2003 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 "gssapi_locl.h" + +RCSID("$Id: inquire_cred.c,v 1.7 2004/11/30 19:27:11 lha Exp $"); + +OM_uint32 gss_inquire_cred + (OM_uint32 * minor_status, + const gss_cred_id_t cred_handle, + gss_name_t * name, + OM_uint32 * lifetime, + gss_cred_usage_t * cred_usage, + gss_OID_set * mechanisms + ) +{ + gss_cred_id_t cred; + OM_uint32 ret; + + *minor_status = 0; + + if (name) + *name = NULL; + if (mechanisms) + *mechanisms = GSS_C_NO_OID_SET; + + if (cred_handle == GSS_C_NO_CREDENTIAL) { + ret = gss_acquire_cred(minor_status, + GSS_C_NO_NAME, + GSS_C_INDEFINITE, + GSS_C_NO_OID_SET, + GSS_C_BOTH, + &cred, + NULL, + NULL); + if (ret) + return ret; + } else + cred = (gss_cred_id_t)cred_handle; + + HEIMDAL_MUTEX_lock(&cred->cred_id_mutex); + + if (name != NULL) { + if (cred->principal != NULL) { + ret = gss_duplicate_name(minor_status, cred->principal, + name); + if (ret) + goto out; + } else if (cred->usage == GSS_C_ACCEPT) { + *minor_status = krb5_sname_to_principal(gssapi_krb5_context, NULL, + NULL, KRB5_NT_SRV_HST, name); + if (*minor_status) { + ret = GSS_S_FAILURE; + goto out; + } + } else { + *minor_status = krb5_get_default_principal(gssapi_krb5_context, + name); + if (*minor_status) { + ret = GSS_S_FAILURE; + goto out; + } + } + } + if (lifetime != NULL) { + ret = gssapi_lifetime_left(minor_status, + cred->lifetime, + lifetime); + if (ret) + goto out; + } + if (cred_usage != NULL) + *cred_usage = cred->usage; + + if (mechanisms != NULL) { + ret = gss_create_empty_oid_set(minor_status, mechanisms); + if (ret) + goto out; + ret = gss_add_oid_set_member(minor_status, + &cred->mechanisms->elements[0], + mechanisms); + if (ret) + goto out; + } + ret = GSS_S_COMPLETE; + out: + HEIMDAL_MUTEX_unlock(&cred->cred_id_mutex); + + if (cred_handle == GSS_C_NO_CREDENTIAL) + ret = gss_release_cred(minor_status, &cred); + + return ret; +} diff --git a/source4/heimdal/lib/gssapi/release_buffer.c b/source4/heimdal/lib/gssapi/release_buffer.c new file mode 100644 index 0000000000..258b76f627 --- /dev/null +++ b/source4/heimdal/lib/gssapi/release_buffer.c @@ -0,0 +1,48 @@ +/* + * Copyright (c) 1997 - 2000, 2003 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 "gssapi_locl.h" + +RCSID("$Id: release_buffer.c,v 1.5 2003/03/16 17:58:20 lha Exp $"); + +OM_uint32 gss_release_buffer + (OM_uint32 * minor_status, + gss_buffer_t buffer + ) +{ + *minor_status = 0; + free (buffer->value); + buffer->value = NULL; + buffer->length = 0; + return GSS_S_COMPLETE; +} diff --git a/source4/heimdal/lib/gssapi/release_cred.c b/source4/heimdal/lib/gssapi/release_cred.c new file mode 100644 index 0000000000..8ae65dd528 --- /dev/null +++ b/source4/heimdal/lib/gssapi/release_cred.c @@ -0,0 +1,73 @@ +/* + * Copyright (c) 1997-2003 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 "gssapi_locl.h" + +RCSID("$Id: release_cred.c,v 1.10 2003/10/07 00:51:46 lha Exp $"); + +OM_uint32 gss_release_cred + (OM_uint32 * minor_status, + gss_cred_id_t * cred_handle + ) +{ + *minor_status = 0; + + if (*cred_handle == GSS_C_NO_CREDENTIAL) { + return GSS_S_COMPLETE; + } + + GSSAPI_KRB5_INIT (); + + HEIMDAL_MUTEX_lock(&(*cred_handle)->cred_id_mutex); + + if ((*cred_handle)->principal != NULL) + krb5_free_principal(gssapi_krb5_context, (*cred_handle)->principal); + if ((*cred_handle)->made_keytab) + krb5_kt_close(gssapi_krb5_context, (*cred_handle)->keytab); + if ((*cred_handle)->made_ccache) { + const krb5_cc_ops *ops; + ops = krb5_cc_get_ops(gssapi_krb5_context, (*cred_handle)->ccache); + if (ops == &krb5_mcc_ops) + krb5_cc_destroy(gssapi_krb5_context, (*cred_handle)->ccache); + else + krb5_cc_close(gssapi_krb5_context, (*cred_handle)->ccache); + } + gss_release_oid_set(NULL, &(*cred_handle)->mechanisms); + HEIMDAL_MUTEX_unlock(&(*cred_handle)->cred_id_mutex); + HEIMDAL_MUTEX_destroy(&(*cred_handle)->cred_id_mutex); + memset(*cred_handle, 0, sizeof(**cred_handle)); + free(*cred_handle); + *cred_handle = GSS_C_NO_CREDENTIAL; + return GSS_S_COMPLETE; +} + diff --git a/source4/heimdal/lib/gssapi/release_name.c b/source4/heimdal/lib/gssapi/release_name.c new file mode 100644 index 0000000000..6894ffae49 --- /dev/null +++ b/source4/heimdal/lib/gssapi/release_name.c @@ -0,0 +1,50 @@ +/* + * Copyright (c) 1997 - 2003 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 "gssapi_locl.h" + +RCSID("$Id: release_name.c,v 1.7 2003/03/16 17:52:48 lha Exp $"); + +OM_uint32 gss_release_name + (OM_uint32 * minor_status, + gss_name_t * input_name + ) +{ + GSSAPI_KRB5_INIT (); + if (minor_status) + *minor_status = 0; + krb5_free_principal(gssapi_krb5_context, + *input_name); + *input_name = GSS_C_NO_NAME; + return GSS_S_COMPLETE; +} diff --git a/source4/heimdal/lib/gssapi/release_oid_set.c b/source4/heimdal/lib/gssapi/release_oid_set.c new file mode 100644 index 0000000000..04eb01565f --- /dev/null +++ b/source4/heimdal/lib/gssapi/release_oid_set.c @@ -0,0 +1,49 @@ +/* + * Copyright (c) 1997 - 2000, 2003 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 "gssapi_locl.h" + +RCSID("$Id: release_oid_set.c,v 1.5 2003/03/16 17:53:25 lha Exp $"); + +OM_uint32 gss_release_oid_set + (OM_uint32 * minor_status, + gss_OID_set * set + ) +{ + if (minor_status) + *minor_status = 0; + free ((*set)->elements); + free (*set); + *set = GSS_C_NO_OID_SET; + return GSS_S_COMPLETE; +} diff --git a/source4/heimdal/lib/gssapi/sequence.c b/source4/heimdal/lib/gssapi/sequence.c new file mode 100755 index 0000000000..973fc6ad05 --- /dev/null +++ b/source4/heimdal/lib/gssapi/sequence.c @@ -0,0 +1,189 @@ +/* + * Copyright (c) 2003 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 "gssapi_locl.h" + +RCSID("$Id: sequence.c,v 1.5 2005/04/27 17:49:43 lha Exp $"); + +#define DEFAULT_JITTER_WINDOW 20 + +struct gss_msg_order { + OM_uint32 flags; + OM_uint32 start; + OM_uint32 length; + OM_uint32 jitter_window; + OM_uint32 first_seq; + OM_uint32 elem[1]; +}; + +/* + * + */ + +OM_uint32 +_gssapi_msg_order_create(OM_uint32 *minor_status, + struct gss_msg_order **o, + OM_uint32 flags, + OM_uint32 seq_num, + OM_uint32 jitter_window, + int use_64) +{ + size_t len; + + if (jitter_window == 0) + jitter_window = DEFAULT_JITTER_WINDOW; + + len = jitter_window * sizeof((*o)->elem[0]); + len += sizeof(**o); + len -= sizeof((*o)->elem[0]); + + *o = malloc(len); + if (*o == NULL) { + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + memset(*o, 0, len); + (*o)->flags = flags; + (*o)->length = 0; + (*o)->first_seq = seq_num; + (*o)->jitter_window = jitter_window; + (*o)->elem[0] = seq_num - 1; + + *minor_status = 0; + return GSS_S_COMPLETE; +} + +OM_uint32 +_gssapi_msg_order_destroy(struct gss_msg_order **m) +{ + free(*m); + *m = NULL; + return GSS_S_COMPLETE; +} + +static void +elem_set(struct gss_msg_order *o, unsigned int slot, OM_uint32 val) +{ + o->elem[slot % o->jitter_window] = val; +} + +static void +elem_insert(struct gss_msg_order *o, + unsigned int after_slot, + OM_uint32 seq_num) +{ + assert(o->jitter_window > after_slot); + + if (o->length > after_slot) + memmove(&o->elem[after_slot + 1], &o->elem[after_slot], + (o->length - after_slot - 1) * sizeof(o->elem[0])); + + elem_set(o, after_slot, seq_num); + + if (o->length < o->jitter_window) + o->length++; +} + +/* rule 1: expected sequence number */ +/* rule 2: > expected sequence number */ +/* rule 3: seqnum < seqnum(first) */ +/* rule 4+5: seqnum in [seqnum(first),seqnum(last)] */ + +OM_uint32 +_gssapi_msg_order_check(struct gss_msg_order *o, OM_uint32 seq_num) +{ + OM_uint32 r; + int i; + + if (o == NULL) + return GSS_S_COMPLETE; + + if ((o->flags & (GSS_C_REPLAY_FLAG|GSS_C_SEQUENCE_FLAG)) == 0) + return GSS_S_COMPLETE; + + /* check if the packet is the next in order */ + if (o->elem[0] == seq_num - 1) { + elem_insert(o, 0, seq_num); + return GSS_S_COMPLETE; + } + + r = (o->flags & (GSS_C_REPLAY_FLAG|GSS_C_SEQUENCE_FLAG))==GSS_C_REPLAY_FLAG; + + /* sequence number larger then largest sequence number + * or smaller then the first sequence number */ + if (seq_num > o->elem[0] + || seq_num < o->first_seq + || o->length == 0) + { + elem_insert(o, 0, seq_num); + if (r) { + return GSS_S_COMPLETE; + } else { + return GSS_S_GAP_TOKEN; + } + } + + assert(o->length > 0); + + /* sequence number smaller the first sequence number */ + if (seq_num < o->elem[o->length - 1]) { + if (r) + return(GSS_S_OLD_TOKEN); + else + return(GSS_S_UNSEQ_TOKEN); + } + + if (seq_num == o->elem[o->length - 1]) { + return GSS_S_DUPLICATE_TOKEN; + } + + for (i = 0; i < o->length - 1; i++) { + if (o->elem[i] == seq_num) + return GSS_S_DUPLICATE_TOKEN; + if (o->elem[i + 1] < seq_num && o->elem[i] < seq_num) { + elem_insert(o, i, seq_num); + if (r) + return GSS_S_COMPLETE; + else + return GSS_S_UNSEQ_TOKEN; + } + } + + return GSS_S_FAILURE; +} + +OM_uint32 +_gssapi_msg_order_f(OM_uint32 flags) +{ + return flags & (GSS_C_SEQUENCE_FLAG|GSS_C_REPLAY_FLAG); +} diff --git a/source4/heimdal/lib/gssapi/spnego.asn1 b/source4/heimdal/lib/gssapi/spnego.asn1 new file mode 100755 index 0000000000..5dc767cf76 --- /dev/null +++ b/source4/heimdal/lib/gssapi/spnego.asn1 @@ -0,0 +1,42 @@ +-- $Id: spnego.asn1,v 1.4 2004/03/07 13:38:08 lha Exp $ + +SPNEGO DEFINITIONS ::= +BEGIN + +MechType::= OBJECT IDENTIFIER + +MechTypeList ::= SEQUENCE OF MechType + +ContextFlags ::= BIT STRING { + delegFlag (0), + mutualFlag (1), + replayFlag (2), + sequenceFlag (3), + anonFlag (4), + confFlag (5), + integFlag (6) +} + +NegTokenInit ::= SEQUENCE { + mechTypes [0] MechTypeList OPTIONAL, + reqFlags [1] ContextFlags OPTIONAL, + mechToken [2] OCTET STRING OPTIONAL, + mechListMIC [3] OCTET STRING OPTIONAL + } + +NegTokenTarg ::= SEQUENCE { + negResult [0] ENUMERATED { + accept_completed (0), + accept_incomplete (1), + reject (2) } OPTIONAL, + supportedMech [1] MechType OPTIONAL, + responseToken [2] OCTET STRING OPTIONAL, + mechListMIC [3] OCTET STRING OPTIONAL +} + +NegotiationToken ::= CHOICE { + negTokenInit[0] NegTokenInit, + negTokenTarg[1] NegTokenTarg +} + +END diff --git a/source4/heimdal/lib/gssapi/test_oid_set_member.c b/source4/heimdal/lib/gssapi/test_oid_set_member.c new file mode 100644 index 0000000000..e747c5acc1 --- /dev/null +++ b/source4/heimdal/lib/gssapi/test_oid_set_member.c @@ -0,0 +1,55 @@ +/* + * Copyright (c) 1997, 2003 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 "gssapi_locl.h" + +RCSID("$Id: test_oid_set_member.c,v 1.5 2003/03/16 17:54:06 lha Exp $"); + +OM_uint32 gss_test_oid_set_member ( + OM_uint32 * minor_status, + const gss_OID member, + const gss_OID_set set, + int * present + ) +{ + size_t i; + + *minor_status = 0; + *present = 0; + for (i = 0; i < set->count; ++i) + if (gss_oid_equal(member, &set->elements[i]) != 0) { + *present = 1; + break; + } + return GSS_S_COMPLETE; +} diff --git a/source4/heimdal/lib/gssapi/unwrap.c b/source4/heimdal/lib/gssapi/unwrap.c new file mode 100644 index 0000000000..c358c1aa24 --- /dev/null +++ b/source4/heimdal/lib/gssapi/unwrap.c @@ -0,0 +1,413 @@ +/* + * Copyright (c) 1997 - 2004 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 "gssapi_locl.h" + +RCSID("$Id: unwrap.c,v 1.34 2005/04/27 17:50:40 lha Exp $"); + +static OM_uint32 +unwrap_des + (OM_uint32 * minor_status, + const gss_ctx_id_t context_handle, + const gss_buffer_t input_message_buffer, + gss_buffer_t output_message_buffer, + int * conf_state, + gss_qop_t * qop_state, + krb5_keyblock *key + ) +{ + u_char *p, *seq; + size_t len; + MD5_CTX md5; + u_char hash[16]; + DES_key_schedule schedule; + DES_cblock deskey; + DES_cblock zero; + int i; + int32_t seq_number; + size_t padlength; + OM_uint32 ret; + int cstate; + int cmp; + + p = input_message_buffer->value; + ret = gssapi_krb5_verify_header (&p, + input_message_buffer->length, + "\x02\x01", + GSS_KRB5_MECHANISM); + if (ret) + return ret; + + if (memcmp (p, "\x00\x00", 2) != 0) + return GSS_S_BAD_SIG; + p += 2; + if (memcmp (p, "\x00\x00", 2) == 0) { + cstate = 1; + } else if (memcmp (p, "\xFF\xFF", 2) == 0) { + cstate = 0; + } else + return GSS_S_BAD_MIC; + p += 2; + if(conf_state != NULL) + *conf_state = cstate; + if (memcmp (p, "\xff\xff", 2) != 0) + return GSS_S_DEFECTIVE_TOKEN; + p += 2; + p += 16; + + len = p - (u_char *)input_message_buffer->value; + + if(cstate) { + /* decrypt data */ + memcpy (&deskey, key->keyvalue.data, sizeof(deskey)); + + for (i = 0; i < sizeof(deskey); ++i) + deskey[i] ^= 0xf0; + DES_set_key (&deskey, &schedule); + memset (&zero, 0, sizeof(zero)); + DES_cbc_encrypt ((void *)p, + (void *)p, + input_message_buffer->length - len, + &schedule, + &zero, + DES_DECRYPT); + + memset (deskey, 0, sizeof(deskey)); + memset (&schedule, 0, sizeof(schedule)); + } + /* check pad */ + ret = _gssapi_verify_pad(input_message_buffer, + input_message_buffer->length - len, + &padlength); + if (ret) + return ret; + + MD5_Init (&md5); + MD5_Update (&md5, p - 24, 8); + MD5_Update (&md5, p, input_message_buffer->length - len); + MD5_Final (hash, &md5); + + memset (&zero, 0, sizeof(zero)); + memcpy (&deskey, key->keyvalue.data, sizeof(deskey)); + DES_set_key (&deskey, &schedule); + DES_cbc_cksum ((void *)hash, (void *)hash, sizeof(hash), + &schedule, &zero); + if (memcmp (p - 8, hash, 8) != 0) + return GSS_S_BAD_MIC; + + /* verify sequence number */ + + HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex); + + p -= 16; + DES_set_key (&deskey, &schedule); + DES_cbc_encrypt ((void *)p, (void *)p, 8, + &schedule, (DES_cblock *)hash, DES_DECRYPT); + + memset (deskey, 0, sizeof(deskey)); + memset (&schedule, 0, sizeof(schedule)); + + seq = p; + gssapi_decode_om_uint32(seq, &seq_number); + + if (context_handle->more_flags & LOCAL) + cmp = memcmp(&seq[4], "\xff\xff\xff\xff", 4); + else + cmp = memcmp(&seq[4], "\x00\x00\x00\x00", 4); + + if (cmp != 0) { + HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex); + return GSS_S_BAD_MIC; + } + + ret = _gssapi_msg_order_check(context_handle->order, seq_number); + if (ret) { + HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex); + return ret; + } + + HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex); + + /* copy out data */ + + output_message_buffer->length = input_message_buffer->length + - len - padlength - 8; + output_message_buffer->value = malloc(output_message_buffer->length); + if(output_message_buffer->length != 0 && output_message_buffer->value == NULL) + return GSS_S_FAILURE; + memcpy (output_message_buffer->value, + p + 24, + output_message_buffer->length); + return GSS_S_COMPLETE; +} + +static OM_uint32 +unwrap_des3 + (OM_uint32 * minor_status, + const gss_ctx_id_t context_handle, + const gss_buffer_t input_message_buffer, + gss_buffer_t output_message_buffer, + int * conf_state, + gss_qop_t * qop_state, + krb5_keyblock *key + ) +{ + u_char *p; + size_t len; + u_char *seq; + krb5_data seq_data; + u_char cksum[20]; + int32_t seq_number; + size_t padlength; + OM_uint32 ret; + int cstate; + krb5_crypto crypto; + Checksum csum; + int cmp; + + p = input_message_buffer->value; + ret = gssapi_krb5_verify_header (&p, + input_message_buffer->length, + "\x02\x01", + GSS_KRB5_MECHANISM); + if (ret) + return ret; + + if (memcmp (p, "\x04\x00", 2) != 0) /* HMAC SHA1 DES3_KD */ + return GSS_S_BAD_SIG; + p += 2; + if (memcmp (p, "\x02\x00", 2) == 0) { + cstate = 1; + } else if (memcmp (p, "\xff\xff", 2) == 0) { + cstate = 0; + } else + return GSS_S_BAD_MIC; + p += 2; + if(conf_state != NULL) + *conf_state = cstate; + if (memcmp (p, "\xff\xff", 2) != 0) + return GSS_S_DEFECTIVE_TOKEN; + p += 2; + p += 28; + + len = p - (u_char *)input_message_buffer->value; + + if(cstate) { + /* decrypt data */ + krb5_data tmp; + + ret = krb5_crypto_init(gssapi_krb5_context, key, + ETYPE_DES3_CBC_NONE, &crypto); + if (ret) { + gssapi_krb5_set_error_string (); + *minor_status = ret; + return GSS_S_FAILURE; + } + ret = krb5_decrypt(gssapi_krb5_context, crypto, KRB5_KU_USAGE_SEAL, + p, input_message_buffer->length - len, &tmp); + krb5_crypto_destroy(gssapi_krb5_context, crypto); + if (ret) { + gssapi_krb5_set_error_string (); + *minor_status = ret; + return GSS_S_FAILURE; + } + assert (tmp.length == input_message_buffer->length - len); + + memcpy (p, tmp.data, tmp.length); + krb5_data_free(&tmp); + } + /* check pad */ + ret = _gssapi_verify_pad(input_message_buffer, + input_message_buffer->length - len, + &padlength); + if (ret) + return ret; + + /* verify sequence number */ + + HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex); + + p -= 28; + + ret = krb5_crypto_init(gssapi_krb5_context, key, + ETYPE_DES3_CBC_NONE, &crypto); + if (ret) { + gssapi_krb5_set_error_string (); + *minor_status = ret; + HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex); + return GSS_S_FAILURE; + } + { + DES_cblock ivec; + + memcpy(&ivec, p + 8, 8); + ret = krb5_decrypt_ivec (gssapi_krb5_context, + crypto, + KRB5_KU_USAGE_SEQ, + p, 8, &seq_data, + &ivec); + } + krb5_crypto_destroy (gssapi_krb5_context, crypto); + if (ret) { + gssapi_krb5_set_error_string (); + *minor_status = ret; + HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex); + return GSS_S_FAILURE; + } + if (seq_data.length != 8) { + krb5_data_free (&seq_data); + *minor_status = 0; + HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex); + return GSS_S_BAD_MIC; + } + + seq = seq_data.data; + gssapi_decode_om_uint32(seq, &seq_number); + + if (context_handle->more_flags & LOCAL) + cmp = memcmp(&seq[4], "\xff\xff\xff\xff", 4); + else + cmp = memcmp(&seq[4], "\x00\x00\x00\x00", 4); + + krb5_data_free (&seq_data); + if (cmp != 0) { + *minor_status = 0; + HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex); + return GSS_S_BAD_MIC; + } + + ret = _gssapi_msg_order_check(context_handle->order, seq_number); + if (ret) { + *minor_status = 0; + HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex); + return ret; + } + + HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex); + + /* verify checksum */ + + memcpy (cksum, p + 8, 20); + + memcpy (p + 20, p - 8, 8); + + csum.cksumtype = CKSUMTYPE_HMAC_SHA1_DES3; + csum.checksum.length = 20; + csum.checksum.data = cksum; + + ret = krb5_crypto_init(gssapi_krb5_context, key, 0, &crypto); + if (ret) { + gssapi_krb5_set_error_string (); + *minor_status = ret; + return GSS_S_FAILURE; + } + + ret = krb5_verify_checksum (gssapi_krb5_context, crypto, + KRB5_KU_USAGE_SIGN, + p + 20, + input_message_buffer->length - len + 8, + &csum); + krb5_crypto_destroy (gssapi_krb5_context, crypto); + if (ret) { + gssapi_krb5_set_error_string (); + *minor_status = ret; + return GSS_S_FAILURE; + } + + /* copy out data */ + + output_message_buffer->length = input_message_buffer->length + - len - padlength - 8; + output_message_buffer->value = malloc(output_message_buffer->length); + if(output_message_buffer->length != 0 && output_message_buffer->value == NULL) + return GSS_S_FAILURE; + memcpy (output_message_buffer->value, + p + 36, + output_message_buffer->length); + return GSS_S_COMPLETE; +} + +OM_uint32 gss_unwrap + (OM_uint32 * minor_status, + const gss_ctx_id_t context_handle, + const gss_buffer_t input_message_buffer, + gss_buffer_t output_message_buffer, + int * conf_state, + gss_qop_t * qop_state + ) +{ + krb5_keyblock *key; + OM_uint32 ret; + krb5_keytype keytype; + + output_message_buffer->value = NULL; + output_message_buffer->length = 0; + + if (qop_state != NULL) + *qop_state = GSS_C_QOP_DEFAULT; + ret = gss_krb5_get_subkey(context_handle, &key); + if (ret) { + gssapi_krb5_set_error_string (); + *minor_status = ret; + return GSS_S_FAILURE; + } + krb5_enctype_to_keytype (gssapi_krb5_context, key->keytype, &keytype); + + *minor_status = 0; + + switch (keytype) { + case KEYTYPE_DES : + ret = unwrap_des (minor_status, context_handle, + input_message_buffer, output_message_buffer, + conf_state, qop_state, key); + break; + case KEYTYPE_DES3 : + ret = unwrap_des3 (minor_status, context_handle, + input_message_buffer, output_message_buffer, + conf_state, qop_state, key); + break; + case KEYTYPE_ARCFOUR: + case KEYTYPE_ARCFOUR_56: + ret = _gssapi_unwrap_arcfour (minor_status, context_handle, + input_message_buffer, output_message_buffer, + conf_state, qop_state, key); + break; + default : + ret = _gssapi_unwrap_cfx (minor_status, context_handle, + input_message_buffer, output_message_buffer, + conf_state, qop_state, key); + break; + } + krb5_free_keyblock (gssapi_krb5_context, key); + return ret; +} diff --git a/source4/heimdal/lib/gssapi/verify_mic.c b/source4/heimdal/lib/gssapi/verify_mic.c new file mode 100644 index 0000000000..7b7d437e99 --- /dev/null +++ b/source4/heimdal/lib/gssapi/verify_mic.c @@ -0,0 +1,336 @@ +/* + * Copyright (c) 1997 - 2003 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 "gssapi_locl.h" + +RCSID("$Id: verify_mic.c,v 1.32 2005/04/27 17:51:04 lha Exp $"); + +static OM_uint32 +verify_mic_des + (OM_uint32 * minor_status, + const gss_ctx_id_t context_handle, + const gss_buffer_t message_buffer, + const gss_buffer_t token_buffer, + gss_qop_t * qop_state, + krb5_keyblock *key, + char *type + ) +{ + u_char *p; + MD5_CTX md5; + u_char hash[16], *seq; + DES_key_schedule schedule; + DES_cblock zero; + DES_cblock deskey; + int32_t seq_number; + OM_uint32 ret; + int cmp; + + p = token_buffer->value; + ret = gssapi_krb5_verify_header (&p, + token_buffer->length, + type, + GSS_KRB5_MECHANISM); + if (ret) + return ret; + + if (memcmp(p, "\x00\x00", 2) != 0) + return GSS_S_BAD_SIG; + p += 2; + if (memcmp (p, "\xff\xff\xff\xff", 4) != 0) + return GSS_S_BAD_MIC; + p += 4; + p += 16; + + /* verify checksum */ + MD5_Init (&md5); + MD5_Update (&md5, p - 24, 8); + MD5_Update (&md5, message_buffer->value, + message_buffer->length); + MD5_Final (hash, &md5); + + memset (&zero, 0, sizeof(zero)); + memcpy (&deskey, key->keyvalue.data, sizeof(deskey)); + + DES_set_key (&deskey, &schedule); + DES_cbc_cksum ((void *)hash, (void *)hash, sizeof(hash), + &schedule, &zero); + if (memcmp (p - 8, hash, 8) != 0) { + memset (deskey, 0, sizeof(deskey)); + memset (&schedule, 0, sizeof(schedule)); + return GSS_S_BAD_MIC; + } + + /* verify sequence number */ + + HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex); + + p -= 16; + DES_set_key (&deskey, &schedule); + DES_cbc_encrypt ((void *)p, (void *)p, 8, + &schedule, (DES_cblock *)hash, DES_DECRYPT); + + memset (deskey, 0, sizeof(deskey)); + memset (&schedule, 0, sizeof(schedule)); + + seq = p; + gssapi_decode_om_uint32(seq, &seq_number); + + if (context_handle->more_flags & LOCAL) + cmp = memcmp(&seq[4], "\xff\xff\xff\xff", 4); + else + cmp = memcmp(&seq[4], "\x00\x00\x00\x00", 4); + + if (cmp != 0) { + HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex); + return GSS_S_BAD_MIC; + } + + ret = _gssapi_msg_order_check(context_handle->order, seq_number); + if (ret) { + HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex); + return ret; + } + + HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex); + + return GSS_S_COMPLETE; +} + +static OM_uint32 +verify_mic_des3 + (OM_uint32 * minor_status, + const gss_ctx_id_t context_handle, + const gss_buffer_t message_buffer, + const gss_buffer_t token_buffer, + gss_qop_t * qop_state, + krb5_keyblock *key, + char *type + ) +{ + u_char *p; + u_char *seq; + int32_t seq_number; + OM_uint32 ret; + krb5_crypto crypto; + krb5_data seq_data; + int cmp, docompat; + Checksum csum; + char *tmp; + char ivec[8]; + + p = token_buffer->value; + ret = gssapi_krb5_verify_header (&p, + token_buffer->length, + type, + GSS_KRB5_MECHANISM); + if (ret) + return ret; + + if (memcmp(p, "\x04\x00", 2) != 0) /* SGN_ALG = HMAC SHA1 DES3-KD */ + return GSS_S_BAD_SIG; + p += 2; + if (memcmp (p, "\xff\xff\xff\xff", 4) != 0) + return GSS_S_BAD_MIC; + p += 4; + + ret = krb5_crypto_init(gssapi_krb5_context, key, + ETYPE_DES3_CBC_NONE, &crypto); + if (ret){ + gssapi_krb5_set_error_string (); + *minor_status = ret; + return GSS_S_FAILURE; + } + + /* verify sequence number */ + docompat = 0; +retry: + if (docompat) + memset(ivec, 0, 8); + else + memcpy(ivec, p + 8, 8); + + ret = krb5_decrypt_ivec (gssapi_krb5_context, + crypto, + KRB5_KU_USAGE_SEQ, + p, 8, &seq_data, ivec); + if (ret) { + if (docompat++) { + gssapi_krb5_set_error_string (); + krb5_crypto_destroy (gssapi_krb5_context, crypto); + *minor_status = ret; + return GSS_S_FAILURE; + } else + goto retry; + } + + if (seq_data.length != 8) { + krb5_data_free (&seq_data); + if (docompat++) { + krb5_crypto_destroy (gssapi_krb5_context, crypto); + return GSS_S_BAD_MIC; + } else + goto retry; + } + + HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex); + + seq = seq_data.data; + gssapi_decode_om_uint32(seq, &seq_number); + + if (context_handle->more_flags & LOCAL) + cmp = memcmp(&seq[4], "\xff\xff\xff\xff", 4); + else + cmp = memcmp(&seq[4], "\x00\x00\x00\x00", 4); + + krb5_data_free (&seq_data); + if (cmp != 0) { + krb5_crypto_destroy (gssapi_krb5_context, crypto); + *minor_status = 0; + HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex); + return GSS_S_BAD_MIC; + } + + ret = _gssapi_msg_order_check(context_handle->order, seq_number); + if (ret) { + krb5_crypto_destroy (gssapi_krb5_context, crypto); + *minor_status = 0; + HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex); + return ret; + } + + /* verify checksum */ + + tmp = malloc (message_buffer->length + 8); + if (tmp == NULL) { + krb5_crypto_destroy (gssapi_krb5_context, crypto); + HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex); + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + + memcpy (tmp, p - 8, 8); + memcpy (tmp + 8, message_buffer->value, message_buffer->length); + + csum.cksumtype = CKSUMTYPE_HMAC_SHA1_DES3; + csum.checksum.length = 20; + csum.checksum.data = p + 8; + + ret = krb5_verify_checksum (gssapi_krb5_context, crypto, + KRB5_KU_USAGE_SIGN, + tmp, message_buffer->length + 8, + &csum); + free (tmp); + if (ret) { + gssapi_krb5_set_error_string (); + krb5_crypto_destroy (gssapi_krb5_context, crypto); + *minor_status = ret; + HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex); + return GSS_S_BAD_MIC; + } + HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex); + + krb5_crypto_destroy (gssapi_krb5_context, crypto); + return GSS_S_COMPLETE; +} + +OM_uint32 +gss_verify_mic_internal + (OM_uint32 * minor_status, + const gss_ctx_id_t context_handle, + const gss_buffer_t message_buffer, + const gss_buffer_t token_buffer, + gss_qop_t * qop_state, + char * type + ) +{ + krb5_keyblock *key; + OM_uint32 ret; + krb5_keytype keytype; + + ret = gss_krb5_get_subkey(context_handle, &key); + if (ret) { + gssapi_krb5_set_error_string (); + *minor_status = ret; + return GSS_S_FAILURE; + } + *minor_status = 0; + krb5_enctype_to_keytype (gssapi_krb5_context, key->keytype, &keytype); + switch (keytype) { + case KEYTYPE_DES : + ret = verify_mic_des (minor_status, context_handle, + message_buffer, token_buffer, qop_state, key, + type); + break; + case KEYTYPE_DES3 : + ret = verify_mic_des3 (minor_status, context_handle, + message_buffer, token_buffer, qop_state, key, + type); + break; + case KEYTYPE_ARCFOUR : + case KEYTYPE_ARCFOUR_56 : + ret = _gssapi_verify_mic_arcfour (minor_status, context_handle, + message_buffer, token_buffer, + qop_state, key, type); + break; + default : + ret = _gssapi_verify_mic_cfx (minor_status, context_handle, + message_buffer, token_buffer, qop_state, + key); + break; + } + krb5_free_keyblock (gssapi_krb5_context, key); + + return ret; +} + +OM_uint32 +gss_verify_mic + (OM_uint32 * minor_status, + const gss_ctx_id_t context_handle, + const gss_buffer_t message_buffer, + const gss_buffer_t token_buffer, + gss_qop_t * qop_state + ) +{ + OM_uint32 ret; + + if (qop_state != NULL) + *qop_state = GSS_C_QOP_DEFAULT; + + ret = gss_verify_mic_internal(minor_status, context_handle, + message_buffer, token_buffer, + qop_state, "\x01\x01"); + + return ret; +} diff --git a/source4/heimdal/lib/gssapi/wrap.c b/source4/heimdal/lib/gssapi/wrap.c new file mode 100644 index 0000000000..bdb09e633b --- /dev/null +++ b/source4/heimdal/lib/gssapi/wrap.c @@ -0,0 +1,533 @@ +/* + * Copyright (c) 1997 - 2003 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 "gssapi_locl.h" + +RCSID("$Id: wrap.c,v 1.31 2005/01/05 02:52:12 lukeh Exp $"); + +OM_uint32 +gsskrb5_get_initiator_subkey(OM_uint32 *minor_status, + gss_ctx_id_t context_handle, + gss_buffer_t key) +{ + krb5_error_code ret; + krb5_keyblock *skey = NULL; + + HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex); + if (context_handle->more_flags & LOCAL) { + ret = krb5_auth_con_getlocalsubkey(gssapi_krb5_context, + context_handle->auth_context, + &skey); + if (ret) { + *minor_status = ret; + return GSS_KRB5_S_KG_NO_SUBKEY; /* XXX */ + } + + } else { + ret = krb5_auth_con_getremotesubkey(gssapi_krb5_context, + context_handle->auth_context, + &skey); + if (ret) { + *minor_status = ret; + return GSS_KRB5_S_KG_NO_SUBKEY; /* XXX */ + } + + } + HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex); + key->length = skey->keyvalue.length; + key->value = malloc (key->length); + if (!key->value) { + krb5_free_keyblock(gssapi_krb5_context, skey); + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + memcpy(key->value, skey->keyvalue.data, key->length); + krb5_free_keyblock(gssapi_krb5_context, skey); + return 0; +} + +OM_uint32 +gss_krb5_get_subkey(const gss_ctx_id_t context_handle, + krb5_keyblock **key) +{ + krb5_keyblock *skey = NULL; + + HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex); + if (context_handle->more_flags & LOCAL) { + krb5_auth_con_getremotesubkey(gssapi_krb5_context, + context_handle->auth_context, + &skey); + } else { + krb5_auth_con_getlocalsubkey(gssapi_krb5_context, + context_handle->auth_context, + &skey); + } + /* + * Only use the initiator subkey or ticket session key if + * an acceptor subkey was not required. + */ + if (skey == NULL && + (context_handle->more_flags & ACCEPTOR_SUBKEY) == 0) { + if (context_handle->more_flags & LOCAL) { + krb5_auth_con_getlocalsubkey(gssapi_krb5_context, + context_handle->auth_context, + &skey); + } else { + krb5_auth_con_getremotesubkey(gssapi_krb5_context, + context_handle->auth_context, + &skey); + } + if(skey == NULL) + krb5_auth_con_getkey(gssapi_krb5_context, + context_handle->auth_context, + &skey); + } + HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex); + if(skey == NULL) + return GSS_KRB5_S_KG_NO_SUBKEY; /* XXX */ + *key = skey; + return 0; +} + +static OM_uint32 +sub_wrap_size ( + OM_uint32 req_output_size, + OM_uint32 * max_input_size, + int blocksize, + int extrasize + ) +{ + size_t len, total_len; + + len = 8 + req_output_size + blocksize + extrasize; + + gssapi_krb5_encap_length(len, &len, &total_len, GSS_KRB5_MECHANISM); + + total_len -= req_output_size; /* token length */ + if (total_len < req_output_size) { + *max_input_size = (req_output_size - total_len); + (*max_input_size) &= (~(OM_uint32)(blocksize - 1)); + } else { + *max_input_size = 0; + } + return GSS_S_COMPLETE; +} + +OM_uint32 +gss_wrap_size_limit ( + OM_uint32 * minor_status, + const gss_ctx_id_t context_handle, + int conf_req_flag, + gss_qop_t qop_req, + OM_uint32 req_output_size, + OM_uint32 * max_input_size + ) +{ + krb5_keyblock *key; + OM_uint32 ret; + krb5_keytype keytype; + + ret = gss_krb5_get_subkey(context_handle, &key); + if (ret) { + gssapi_krb5_set_error_string (); + *minor_status = ret; + return GSS_S_FAILURE; + } + krb5_enctype_to_keytype (gssapi_krb5_context, key->keytype, &keytype); + + switch (keytype) { + case KEYTYPE_DES : + case KEYTYPE_ARCFOUR: + case KEYTYPE_ARCFOUR_56: + ret = sub_wrap_size(req_output_size, max_input_size, 8, 22); + break; + case KEYTYPE_DES3 : + ret = sub_wrap_size(req_output_size, max_input_size, 8, 34); + break; + default : + ret = _gssapi_wrap_size_cfx(minor_status, context_handle, + conf_req_flag, qop_req, + req_output_size, max_input_size, key); + break; + } + krb5_free_keyblock (gssapi_krb5_context, key); + *minor_status = 0; + return ret; +} + +static OM_uint32 +wrap_des + (OM_uint32 * minor_status, + const gss_ctx_id_t context_handle, + 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, + krb5_keyblock *key + ) +{ + u_char *p; + MD5_CTX md5; + u_char hash[16]; + DES_key_schedule schedule; + DES_cblock deskey; + DES_cblock zero; + int i; + int32_t seq_number; + size_t len, total_len, padlength, datalen; + + padlength = 8 - (input_message_buffer->length % 8); + datalen = input_message_buffer->length + padlength + 8; + len = datalen + 22; + gssapi_krb5_encap_length (len, &len, &total_len, GSS_KRB5_MECHANISM); + + output_message_buffer->length = total_len; + output_message_buffer->value = malloc (total_len); + if (output_message_buffer->value == NULL) { + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + + p = gssapi_krb5_make_header(output_message_buffer->value, + len, + "\x02\x01", /* TOK_ID */ + GSS_KRB5_MECHANISM); + + /* SGN_ALG */ + memcpy (p, "\x00\x00", 2); + p += 2; + /* SEAL_ALG */ + if(conf_req_flag) + memcpy (p, "\x00\x00", 2); + else + memcpy (p, "\xff\xff", 2); + p += 2; + /* Filler */ + memcpy (p, "\xff\xff", 2); + p += 2; + + /* fill in later */ + memset (p, 0, 16); + p += 16; + + /* confounder + data + pad */ + krb5_generate_random_block(p, 8); + memcpy (p + 8, input_message_buffer->value, + input_message_buffer->length); + memset (p + 8 + input_message_buffer->length, padlength, padlength); + + /* checksum */ + MD5_Init (&md5); + MD5_Update (&md5, p - 24, 8); + MD5_Update (&md5, p, datalen); + MD5_Final (hash, &md5); + + memset (&zero, 0, sizeof(zero)); + memcpy (&deskey, key->keyvalue.data, sizeof(deskey)); + DES_set_key (&deskey, &schedule); + DES_cbc_cksum ((void *)hash, (void *)hash, sizeof(hash), + &schedule, &zero); + memcpy (p - 8, hash, 8); + + /* sequence number */ + HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex); + krb5_auth_con_getlocalseqnumber (gssapi_krb5_context, + context_handle->auth_context, + &seq_number); + + p -= 16; + p[0] = (seq_number >> 0) & 0xFF; + p[1] = (seq_number >> 8) & 0xFF; + p[2] = (seq_number >> 16) & 0xFF; + p[3] = (seq_number >> 24) & 0xFF; + memset (p + 4, + (context_handle->more_flags & LOCAL) ? 0 : 0xFF, + 4); + + DES_set_key (&deskey, &schedule); + DES_cbc_encrypt ((void *)p, (void *)p, 8, + &schedule, (DES_cblock *)(p + 8), DES_ENCRYPT); + + krb5_auth_con_setlocalseqnumber (gssapi_krb5_context, + context_handle->auth_context, + ++seq_number); + HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex); + + /* encrypt the data */ + p += 16; + + if(conf_req_flag) { + memcpy (&deskey, key->keyvalue.data, sizeof(deskey)); + + for (i = 0; i < sizeof(deskey); ++i) + deskey[i] ^= 0xf0; + DES_set_key (&deskey, &schedule); + memset (&zero, 0, sizeof(zero)); + DES_cbc_encrypt ((void *)p, + (void *)p, + datalen, + &schedule, + &zero, + DES_ENCRYPT); + } + memset (deskey, 0, sizeof(deskey)); + memset (&schedule, 0, sizeof(schedule)); + + if(conf_state != NULL) + *conf_state = conf_req_flag; + *minor_status = 0; + return GSS_S_COMPLETE; +} + +static OM_uint32 +wrap_des3 + (OM_uint32 * minor_status, + const gss_ctx_id_t context_handle, + 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, + krb5_keyblock *key + ) +{ + u_char *p; + u_char seq[8]; + int32_t seq_number; + size_t len, total_len, padlength, datalen; + u_int32_t ret; + krb5_crypto crypto; + Checksum cksum; + krb5_data encdata; + + padlength = 8 - (input_message_buffer->length % 8); + datalen = input_message_buffer->length + padlength + 8; + len = datalen + 34; + gssapi_krb5_encap_length (len, &len, &total_len, GSS_KRB5_MECHANISM); + + output_message_buffer->length = total_len; + output_message_buffer->value = malloc (total_len); + if (output_message_buffer->value == NULL) { + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + + p = gssapi_krb5_make_header(output_message_buffer->value, + len, + "\x02\x01", /* TOK_ID */ + GSS_KRB5_MECHANISM); + + /* SGN_ALG */ + memcpy (p, "\x04\x00", 2); /* HMAC SHA1 DES3-KD */ + p += 2; + /* SEAL_ALG */ + if(conf_req_flag) + memcpy (p, "\x02\x00", 2); /* DES3-KD */ + else + memcpy (p, "\xff\xff", 2); + p += 2; + /* Filler */ + memcpy (p, "\xff\xff", 2); + p += 2; + + /* calculate checksum (the above + confounder + data + pad) */ + + memcpy (p + 20, p - 8, 8); + krb5_generate_random_block(p + 28, 8); + memcpy (p + 28 + 8, input_message_buffer->value, + input_message_buffer->length); + memset (p + 28 + 8 + input_message_buffer->length, padlength, padlength); + + ret = krb5_crypto_init(gssapi_krb5_context, key, 0, &crypto); + if (ret) { + gssapi_krb5_set_error_string (); + free (output_message_buffer->value); + *minor_status = ret; + return GSS_S_FAILURE; + } + + ret = krb5_create_checksum (gssapi_krb5_context, + crypto, + KRB5_KU_USAGE_SIGN, + 0, + p + 20, + datalen + 8, + &cksum); + krb5_crypto_destroy (gssapi_krb5_context, crypto); + if (ret) { + gssapi_krb5_set_error_string (); + free (output_message_buffer->value); + *minor_status = ret; + return GSS_S_FAILURE; + } + + /* zero out SND_SEQ + SGN_CKSUM in case */ + memset (p, 0, 28); + + memcpy (p + 8, cksum.checksum.data, cksum.checksum.length); + free_Checksum (&cksum); + + HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex); + /* sequence number */ + krb5_auth_con_getlocalseqnumber (gssapi_krb5_context, + context_handle->auth_context, + &seq_number); + + seq[0] = (seq_number >> 0) & 0xFF; + seq[1] = (seq_number >> 8) & 0xFF; + seq[2] = (seq_number >> 16) & 0xFF; + seq[3] = (seq_number >> 24) & 0xFF; + memset (seq + 4, + (context_handle->more_flags & LOCAL) ? 0 : 0xFF, + 4); + + + ret = krb5_crypto_init(gssapi_krb5_context, key, ETYPE_DES3_CBC_NONE, + &crypto); + if (ret) { + free (output_message_buffer->value); + *minor_status = ret; + return GSS_S_FAILURE; + } + + { + DES_cblock ivec; + + memcpy (&ivec, p + 8, 8); + ret = krb5_encrypt_ivec (gssapi_krb5_context, + crypto, + KRB5_KU_USAGE_SEQ, + seq, 8, &encdata, + &ivec); + } + krb5_crypto_destroy (gssapi_krb5_context, crypto); + if (ret) { + gssapi_krb5_set_error_string (); + free (output_message_buffer->value); + *minor_status = ret; + return GSS_S_FAILURE; + } + + assert (encdata.length == 8); + + memcpy (p, encdata.data, encdata.length); + krb5_data_free (&encdata); + + krb5_auth_con_setlocalseqnumber (gssapi_krb5_context, + context_handle->auth_context, + ++seq_number); + HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex); + + /* encrypt the data */ + p += 28; + + if(conf_req_flag) { + krb5_data tmp; + + ret = krb5_crypto_init(gssapi_krb5_context, key, + ETYPE_DES3_CBC_NONE, &crypto); + if (ret) { + gssapi_krb5_set_error_string (); + free (output_message_buffer->value); + *minor_status = ret; + return GSS_S_FAILURE; + } + ret = krb5_encrypt(gssapi_krb5_context, crypto, KRB5_KU_USAGE_SEAL, + p, datalen, &tmp); + krb5_crypto_destroy(gssapi_krb5_context, crypto); + if (ret) { + gssapi_krb5_set_error_string (); + free (output_message_buffer->value); + *minor_status = ret; + return GSS_S_FAILURE; + } + assert (tmp.length == datalen); + + memcpy (p, tmp.data, datalen); + krb5_data_free(&tmp); + } + if(conf_state != NULL) + *conf_state = conf_req_flag; + *minor_status = 0; + return GSS_S_COMPLETE; +} + +OM_uint32 gss_wrap + (OM_uint32 * minor_status, + const gss_ctx_id_t context_handle, + 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 + ) +{ + krb5_keyblock *key; + OM_uint32 ret; + krb5_keytype keytype; + + ret = gss_krb5_get_subkey(context_handle, &key); + if (ret) { + gssapi_krb5_set_error_string (); + *minor_status = ret; + return GSS_S_FAILURE; + } + krb5_enctype_to_keytype (gssapi_krb5_context, key->keytype, &keytype); + + switch (keytype) { + case KEYTYPE_DES : + ret = wrap_des (minor_status, context_handle, conf_req_flag, + qop_req, input_message_buffer, conf_state, + output_message_buffer, key); + break; + case KEYTYPE_DES3 : + ret = wrap_des3 (minor_status, context_handle, conf_req_flag, + qop_req, input_message_buffer, conf_state, + output_message_buffer, key); + break; + case KEYTYPE_ARCFOUR: + case KEYTYPE_ARCFOUR_56: + ret = _gssapi_wrap_arcfour (minor_status, context_handle, conf_req_flag, + qop_req, input_message_buffer, conf_state, + output_message_buffer, key); + break; + default : + ret = _gssapi_wrap_cfx (minor_status, context_handle, conf_req_flag, + qop_req, input_message_buffer, conf_state, + output_message_buffer, key); + break; + } + krb5_free_keyblock (gssapi_krb5_context, key); + return ret; +} |