cfx.c

来自「samba最新软件」· C语言 代码 · 共 879 行 · 第 1/2 页

C
879
字号
/* * 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 "krb5/gsskrb5_locl.h"RCSID("$Id: cfx.c 19031 2006-11-13 18:02:57Z lha $");/* * Implementation of draft-ietf-krb-wg-gssapi-cfx-06.txt */#define CFXSentByAcceptor	(1 << 0)#define CFXSealed		(1 << 1)#define CFXAcceptorSubkey	(1 << 2)krb5_error_code_gsskrb5cfx_wrap_length_cfx(krb5_context context,			    krb5_crypto crypto,			    int conf_req_flag,			    size_t input_length,			    size_t *output_length,			    size_t *cksumsize,			    uint16_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(context, crypto, &type);    if (ret)	return ret;    ret = krb5_checksumsize(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(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(context,						  crypto, input_length);    } else {	/* Checksum is concatenated with data */	*output_length += input_length + *cksumsize;    }    assert(*output_length > input_length);    return 0;}krb5_error_code_gsskrb5cfx_max_wrap_length_cfx(krb5_context context,				krb5_crypto crypto,				int conf_req_flag,				size_t input_length,				OM_uint32 *output_length){    krb5_error_code ret;    *output_length = 0;    /* 16-byte header is always first */    if (input_length < 16)	return 0;    input_length -= 16;    if (conf_req_flag) {	size_t wrapped_size, sz;	wrapped_size = input_length + 1;	do {	    wrapped_size--;	    sz = krb5_get_wrapped_length(context, 					 crypto, wrapped_size);	} while (wrapped_size && sz > input_length);	if (wrapped_size == 0) {	    *output_length = 0;	    return 0;	}	/* inner header */	if (wrapped_size < 16) {	    *output_length = 0;	    return 0;	}	wrapped_size -= 16;	*output_length = wrapped_size;    } else {	krb5_cksumtype type;	size_t cksumsize;	ret = krb5_crypto_get_checksum_type(context, crypto, &type);	if (ret)	    return ret;	ret = krb5_checksumsize(context, type, &cksumsize);	if (ret)	    return ret;	if (input_length < cksumsize)	    return 0;	/* Checksum is concatenated with data */	*output_length = input_length - cksumsize;    }    return 0;}OM_uint32 _gssapi_wrap_size_cfx(OM_uint32 *minor_status,				const gsskrb5_ctx context_handle,				krb5_context context,				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;    ret = krb5_crypto_init(context, key, 0, &crypto);    if (ret != 0) {	*minor_status = ret;	return GSS_S_FAILURE;    }    ret = _gsskrb5cfx_max_wrap_length_cfx(context, crypto, conf_req_flag, 					  req_output_size, max_input_size);    if (ret != 0) {	*minor_status = ret;	krb5_crypto_destroy(context, crypto);	return GSS_S_FAILURE;    }    krb5_crypto_destroy(context, crypto);    return GSS_S_COMPLETE;}/* * Rotate "rrc" bytes to the front or back */static krb5_error_coderrc_rotate(void *data, size_t len, uint16_t rrc, krb5_boolean unrotate){    u_char *tmp, buf[256];    size_t left;    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 gsskrb5_ctx context_handle,			   krb5_context context,			   int conf_req_flag,			   gss_qop_t qop_req,			   const gss_buffer_t input_message_buffer,			   int *conf_state,			   gss_buffer_t output_message_buffer,			   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;    uint16_t padlength, rrc = 0;    int32_t seq_number;    u_char *p;    ret = krb5_crypto_init(context, key, 0, &crypto);    if (ret != 0) {	*minor_status = ret;	return GSS_S_FAILURE;    }    ret = _gsskrb5cfx_wrap_length_cfx(context,				      crypto, conf_req_flag, 				      input_message_buffer->length,				      &wrapped_len, &cksumsize, &padlength);    if (ret != 0) {	*minor_status = ret;	krb5_crypto_destroy(context, crypto);	return GSS_S_FAILURE;    }    /* Always rotate encrypted token (if any) and checksum to header */    rrc = (conf_req_flag ? sizeof(*token) : 0) + (uint16_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(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(context,				    context_handle->auth_context,				    &seq_number);    _gsskrb5_encode_be_om_uint32(0,          &token->SND_SEQ[0]);    _gsskrb5_encode_be_om_uint32(seq_number, &token->SND_SEQ[4]);    krb5_auth_con_setlocalseqnumber(context,				    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(context, crypto,			   usage, p,			   input_message_buffer->length + padlength +				sizeof(*token),			   &cipher);	if (ret != 0) {	    *minor_status = ret;	    krb5_crypto_destroy(context, crypto);	    _gsskrb5_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) {	    *minor_status = ret;	    krb5_crypto_destroy(context, crypto);	    _gsskrb5_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(context, crypto);	    _gsskrb5_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(context, crypto,				   usage, 0, buf, 				   input_message_buffer->length +					sizeof(*token), 				   &cksum);	if (ret != 0) {	    *minor_status = ret;	    krb5_crypto_destroy(context, crypto);	    _gsskrb5_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) {	    *minor_status = ret;	    krb5_crypto_destroy(context, crypto);	    _gsskrb5_release_buffer(minor_status, output_message_buffer);	    free_Checksum(&cksum);	    return GSS_S_FAILURE;	}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?