Implementation of draft-ietf-krb-wg-gssapi-cfx-00.txt from Luke Howard <lukeh@PADL.COM>
git-svn-id: svn://svn.h5l.se/heimdal/trunk/heimdal@12647 ec53bebd-3082-4978-b11e-865c3cabbd6b
This commit is contained in:
791
lib/gssapi/cfx.c
Normal file
791
lib/gssapi/cfx.c
Normal file
@@ -0,0 +1,791 @@
|
||||
/*
|
||||
* 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$");
|
||||
|
||||
/*
|
||||
* Implementation of draft-ietf-krb-wg-gssapi-cfx-00.txt
|
||||
*/
|
||||
|
||||
static krb5_error_code
|
||||
wrap_length_cfx(krb5_crypto crypto,
|
||||
int conf_req_flag,
|
||||
size_t input_length,
|
||||
size_t *output_length,
|
||||
u_int16_t *padlength)
|
||||
{
|
||||
krb5_error_code ret;
|
||||
|
||||
/* 16-byte header is always first */
|
||||
*output_length = sizeof(gss_cfx_wrap_token_desc);
|
||||
*padlength = 0;
|
||||
|
||||
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);
|
||||
}
|
||||
*output_length += krb5_get_wrapped_length(gssapi_krb5_context,
|
||||
crypto, input_length);
|
||||
} else {
|
||||
krb5_cksumtype type;
|
||||
size_t cksumsize;
|
||||
|
||||
/*
|
||||
* Find out how much space the wrapped cleartext will occupy.
|
||||
*/
|
||||
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;
|
||||
}
|
||||
|
||||
/* Checksum is concatenated with data */
|
||||
*output_length += input_length + cksumsize;
|
||||
}
|
||||
|
||||
assert(*output_length > input_length);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
OM_uint32 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, len, total_len;
|
||||
#ifdef GSS_C_DCE_STYLE
|
||||
int dce_style = (context_handle->flags & GSS_C_DCE_STYLE);
|
||||
#else
|
||||
int dce_style = 0;
|
||||
#endif /* GSS_C_DCE_STYLE */
|
||||
|
||||
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,
|
||||
dce_style ? 0 : req_output_size,
|
||||
&output_length, &padlength);
|
||||
if (ret != 0) {
|
||||
gssapi_krb5_set_error_string();
|
||||
*minor_status = ret;
|
||||
krb5_crypto_destroy(gssapi_krb5_context, crypto);
|
||||
return GSS_S_FAILURE;
|
||||
}
|
||||
|
||||
_gssapi_encap_length(output_length, &len, &total_len, GSS_KRB5_MECHANISM);
|
||||
|
||||
if (!dce_style)
|
||||
total_len -= req_output_size;
|
||||
if (total_len < req_output_size) {
|
||||
*max_input_size = (req_output_size - total_len);
|
||||
if (!dce_style)
|
||||
*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;
|
||||
}
|
||||
|
||||
static krb5_error_code rrc_rotate(void *data, size_t len, u_int16_t rrc)
|
||||
{
|
||||
u_char *tmp;
|
||||
|
||||
if (rrc == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (len < rrc) {
|
||||
return ERANGE;
|
||||
}
|
||||
|
||||
tmp = malloc(rrc);
|
||||
if (tmp == NULL) {
|
||||
return ENOMEM;
|
||||
}
|
||||
|
||||
memcpy(tmp, (u_char *)data + len - rrc, rrc);
|
||||
memmove((u_char *)data + rrc, data, len - rrc);
|
||||
memcpy(data, tmp, rrc);
|
||||
|
||||
free(tmp);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
OM_uint32 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, len, total_len;
|
||||
u_int16_t padlength, rrc;
|
||||
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, &padlength);
|
||||
if (ret != 0) {
|
||||
gssapi_krb5_set_error_string();
|
||||
*minor_status = ret;
|
||||
krb5_crypto_destroy(gssapi_krb5_context, crypto);
|
||||
return GSS_S_FAILURE;
|
||||
}
|
||||
|
||||
#ifdef GSS_C_DCE_STYLE
|
||||
if (context_handle->flags & GSS_C_DCE_STYLE) {
|
||||
rrc = wrapped_len - (input_message_buffer->length + padlength);
|
||||
_gssapi_encap_length(rrc, &len, &total_len, GSS_KRB5_MECHANISM);
|
||||
} else {
|
||||
#endif
|
||||
rrc = 0;
|
||||
_gssapi_encap_length(wrapped_len, &len, &total_len, GSS_KRB5_MECHANISM);
|
||||
#ifdef GSS_C_DCE_STYLE
|
||||
}
|
||||
#endif
|
||||
|
||||
output_message_buffer->length = total_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 = _gssapi_make_mech_header(output_message_buffer->value,
|
||||
len, GSS_KRB5_MECHANISM);
|
||||
token = (gss_cfx_wrap_token)p;
|
||||
token->TOK_ID[0] = 0x05;
|
||||
token->TOK_ID[1] = 0x04;
|
||||
token->Direction = (context_handle->more_flags & LOCAL) ? 0 : 0xFF;
|
||||
token->Seal = conf_req_flag ? 0xFF : 0;
|
||||
token->EC[0] = (padlength >> 0) & 0xFF;
|
||||
token->EC[1] = (padlength >> 8) & 0xFF;
|
||||
token->RRC[0] = (rrc >> 0) & 0xFF;
|
||||
token->RRC[1] = (rrc >> 8) & 0xFF;
|
||||
|
||||
HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex);
|
||||
krb5_auth_con_getlocalseqnumber(gssapi_krb5_context,
|
||||
context_handle->auth_context,
|
||||
&seq_number);
|
||||
gssapi_encode_om_uint32(seq_number, &token->SND_SEQ[0]);
|
||||
gssapi_encode_om_uint32(0, &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" | "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) {
|
||||
/*
|
||||
* Note: it is likely that in version 01 of this draft
|
||||
* the header and EC padding will be placed before the
|
||||
* plaintext data, rather than the header at the end as
|
||||
* is the case presently.
|
||||
*/
|
||||
/* Place the header after the plaintext */
|
||||
p += sizeof(*token);
|
||||
memcpy(p, input_message_buffer->value, input_message_buffer->length);
|
||||
memcpy(p + input_message_buffer->length, token, sizeof(*token));
|
||||
|
||||
ret = krb5_encrypt(gssapi_krb5_context, crypto,
|
||||
usage, p,
|
||||
input_message_buffer->length + 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);
|
||||
|
||||
ret = rrc_rotate(cipher.data, cipher.length, rrc);
|
||||
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);
|
||||
|
||||
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);
|
||||
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 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;
|
||||
krb5_error_code ret;
|
||||
unsigned usage;
|
||||
krb5_data data;
|
||||
size_t len;
|
||||
u_int16_t rrc, padlength;
|
||||
OM_uint32 seq_number_lo, seq_number_hi;
|
||||
u_char *p;
|
||||
|
||||
*minor_status = 0;
|
||||
|
||||
p = input_message_buffer->value;
|
||||
ret = _gssapi_verify_mech_header(&p,
|
||||
input_message_buffer->length,
|
||||
GSS_KRB5_MECHANISM);
|
||||
if (ret != 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* check input message buffer includes room for header */
|
||||
len = (p - (u_char *)input_message_buffer->value);
|
||||
if (input_message_buffer->length - len < sizeof(*token)) {
|
||||
return GSS_S_DEFECTIVE_TOKEN;
|
||||
}
|
||||
|
||||
token = (gss_cfx_wrap_token)p;
|
||||
|
||||
if (token->TOK_ID[0] != 0x05 || token->TOK_ID[1] != 0x04) {
|
||||
return GSS_S_DEFECTIVE_TOKEN;
|
||||
}
|
||||
|
||||
if (token->Direction != ((context_handle->more_flags & LOCAL) ? 0xFF : 0)){
|
||||
return GSS_S_DEFECTIVE_TOKEN;
|
||||
}
|
||||
|
||||
if (token->Seal != 0 && token->Seal != 0xFF) {
|
||||
return GSS_S_DEFECTIVE_TOKEN;
|
||||
}
|
||||
|
||||
if (conf_state != NULL) {
|
||||
*conf_state = (token->Seal == 0xFF);
|
||||
}
|
||||
|
||||
padlength = (token->EC[1] << 8) | token->EC[0];
|
||||
|
||||
rrc = (token->RRC[1] << 8) | token->RRC[0];
|
||||
|
||||
/*
|
||||
* Check sequence number
|
||||
*/
|
||||
gssapi_decode_om_uint32(&token->SND_SEQ[0], &seq_number_lo);
|
||||
gssapi_decode_om_uint32(&token->SND_SEQ[4], &seq_number_hi);
|
||||
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(input_message_buffer->value,
|
||||
input_message_buffer->length, rrc);
|
||||
if (*minor_status != 0) {
|
||||
krb5_crypto_destroy(gssapi_krb5_context, crypto);
|
||||
return GSS_S_FAILURE;
|
||||
}
|
||||
|
||||
if (token->Seal) {
|
||||
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 token header */
|
||||
if (data.length < 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);
|
||||
|
||||
/* 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 - sizeof(*token);
|
||||
} else {
|
||||
Checksum cksum;
|
||||
|
||||
/* EC shouldn't be set if confidentiality is not requested */
|
||||
/*
|
||||
* NB: it is possible that version 1 of this draft will
|
||||
* include the checksum length in EC.
|
||||
*/
|
||||
if (padlength != 0) {
|
||||
krb5_crypto_destroy(gssapi_krb5_context, crypto);
|
||||
return GSS_S_BAD_MIC;
|
||||
}
|
||||
|
||||
/* Determine checksum type and length */
|
||||
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;
|
||||
}
|
||||
|
||||
ret = krb5_checksumsize(gssapi_krb5_context, cksum.cksumtype,
|
||||
&cksum.checksum.length);
|
||||
if (ret != 0) {
|
||||
gssapi_krb5_set_error_string();
|
||||
*minor_status = ret;
|
||||
krb5_crypto_destroy(gssapi_krb5_context, crypto);
|
||||
return GSS_S_FAILURE;
|
||||
}
|
||||
|
||||
/* 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));
|
||||
|
||||
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 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, *p;
|
||||
size_t len, total_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 = sizeof(*token) + message_buffer->length;
|
||||
buf = malloc(len);
|
||||
if (buf == NULL) {
|
||||
*minor_status = ENOMEM;
|
||||
krb5_crypto_destroy(gssapi_krb5_context, crypto);
|
||||
return GSS_S_FAILURE;
|
||||
}
|
||||
|
||||
token = (gss_cfx_mic_token)buf;
|
||||
token->TOK_ID[0] = 0x04;
|
||||
token->TOK_ID[1] = 0x04;
|
||||
token->Direction = (context_handle->more_flags & LOCAL) ? 0 : 0xFF;
|
||||
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_om_uint32(seq_number, &token->SND_SEQ[0]);
|
||||
gssapi_encode_om_uint32(0, &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);
|
||||
|
||||
memcpy(buf + sizeof(*token), message_buffer->value, message_buffer->length);
|
||||
|
||||
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 */
|
||||
len = sizeof(*token) + cksum.checksum.length;
|
||||
_gssapi_encap_length(len, &len, &total_len, GSS_KRB5_MECHANISM);
|
||||
|
||||
message_token->length = total_len;
|
||||
message_token->value = malloc(message_token->length);
|
||||
if (message_token->value == NULL) {
|
||||
*minor_status = ENOMEM;
|
||||
free(buf);
|
||||
return GSS_S_FAILURE;
|
||||
}
|
||||
|
||||
p = _gssapi_make_mech_header(message_token->value, len, GSS_KRB5_MECHANISM);
|
||||
|
||||
/* Token is { "header" | get_mic("header" | plaintext-data) } */
|
||||
memcpy(p, token, sizeof(*token));
|
||||
p += sizeof(*token);
|
||||
|
||||
memcpy(p, cksum.checksum.data, cksum.checksum.length);
|
||||
|
||||
free_Checksum(&cksum);
|
||||
free(buf);
|
||||
|
||||
*minor_status = 0;
|
||||
return GSS_S_COMPLETE;
|
||||
}
|
||||
|
||||
OM_uint32 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;
|
||||
krb5_error_code ret;
|
||||
unsigned usage;
|
||||
size_t len;
|
||||
OM_uint32 seq_number_lo, seq_number_hi;
|
||||
u_char *buf, *p;
|
||||
Checksum cksum;
|
||||
|
||||
*minor_status = 0;
|
||||
|
||||
p = token_buffer->value;
|
||||
ret = _gssapi_verify_mech_header(&p,
|
||||
token_buffer->length,
|
||||
GSS_KRB5_MECHANISM);
|
||||
if (ret != 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* check input message buffer includes room for header */
|
||||
len = (p - (u_char *)token_buffer->value);
|
||||
if (token_buffer->length - len < sizeof(*token)) {
|
||||
return GSS_S_DEFECTIVE_TOKEN;
|
||||
}
|
||||
|
||||
token = (gss_cfx_mic_token)p;
|
||||
|
||||
if (token->TOK_ID[0] != 0x04 || token->TOK_ID[1] != 0x04) {
|
||||
return GSS_S_DEFECTIVE_TOKEN;
|
||||
}
|
||||
|
||||
if (token->Direction != ((context_handle->more_flags & LOCAL) ? 0xFF : 0)){
|
||||
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_om_uint32(&token->SND_SEQ[0], &seq_number_lo);
|
||||
gssapi_decode_om_uint32(&token->SND_SEQ[4], &seq_number_hi);
|
||||
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 - len - sizeof(*token);
|
||||
|
||||
if (context_handle->more_flags & LOCAL) {
|
||||
usage = KRB5_KU_USAGE_ACCEPTOR_SIGN;
|
||||
} else {
|
||||
usage = KRB5_KU_USAGE_INITIATOR_SIGN;
|
||||
}
|
||||
|
||||
buf = malloc(sizeof(*token) + message_buffer->length);
|
||||
if (buf == NULL) {
|
||||
*minor_status = ENOMEM;
|
||||
krb5_crypto_destroy(gssapi_krb5_context, crypto);
|
||||
return GSS_S_FAILURE;
|
||||
}
|
||||
memcpy(buf, token, sizeof(*token));
|
||||
memcpy(buf + sizeof(*token), message_buffer->value, message_buffer->length);
|
||||
|
||||
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;
|
||||
}
|
||||
|
104
lib/gssapi/cfx.h
Normal file
104
lib/gssapi/cfx.h
Normal file
@@ -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$ */
|
||||
|
||||
#ifndef CFX_H_
|
||||
#define CFX_H_ 1
|
||||
|
||||
/*
|
||||
* Implementation of draft-ietf-krb-wg-gssapi-cfx-00.txt
|
||||
*/
|
||||
|
||||
typedef struct gss_cfx_mic_token_desc_struct {
|
||||
u_char TOK_ID[2]; /* 04 04 */
|
||||
u_char Direction;
|
||||
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]; /* 05 04 */
|
||||
u_char Direction;
|
||||
u_char Seal;
|
||||
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]; /* 04 05 */
|
||||
u_char Direction;
|
||||
u_char Filler[5];
|
||||
u_char SND_SEQ[8];
|
||||
} gss_cfx_delete_token_desc, *gss_cfx_delete_token;
|
||||
|
||||
OM_uint32 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 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 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 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 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 /* CFX_H_ */
|
791
lib/gssapi/krb5/cfx.c
Normal file
791
lib/gssapi/krb5/cfx.c
Normal file
@@ -0,0 +1,791 @@
|
||||
/*
|
||||
* 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$");
|
||||
|
||||
/*
|
||||
* Implementation of draft-ietf-krb-wg-gssapi-cfx-00.txt
|
||||
*/
|
||||
|
||||
static krb5_error_code
|
||||
wrap_length_cfx(krb5_crypto crypto,
|
||||
int conf_req_flag,
|
||||
size_t input_length,
|
||||
size_t *output_length,
|
||||
u_int16_t *padlength)
|
||||
{
|
||||
krb5_error_code ret;
|
||||
|
||||
/* 16-byte header is always first */
|
||||
*output_length = sizeof(gss_cfx_wrap_token_desc);
|
||||
*padlength = 0;
|
||||
|
||||
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);
|
||||
}
|
||||
*output_length += krb5_get_wrapped_length(gssapi_krb5_context,
|
||||
crypto, input_length);
|
||||
} else {
|
||||
krb5_cksumtype type;
|
||||
size_t cksumsize;
|
||||
|
||||
/*
|
||||
* Find out how much space the wrapped cleartext will occupy.
|
||||
*/
|
||||
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;
|
||||
}
|
||||
|
||||
/* Checksum is concatenated with data */
|
||||
*output_length += input_length + cksumsize;
|
||||
}
|
||||
|
||||
assert(*output_length > input_length);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
OM_uint32 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, len, total_len;
|
||||
#ifdef GSS_C_DCE_STYLE
|
||||
int dce_style = (context_handle->flags & GSS_C_DCE_STYLE);
|
||||
#else
|
||||
int dce_style = 0;
|
||||
#endif /* GSS_C_DCE_STYLE */
|
||||
|
||||
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,
|
||||
dce_style ? 0 : req_output_size,
|
||||
&output_length, &padlength);
|
||||
if (ret != 0) {
|
||||
gssapi_krb5_set_error_string();
|
||||
*minor_status = ret;
|
||||
krb5_crypto_destroy(gssapi_krb5_context, crypto);
|
||||
return GSS_S_FAILURE;
|
||||
}
|
||||
|
||||
_gssapi_encap_length(output_length, &len, &total_len, GSS_KRB5_MECHANISM);
|
||||
|
||||
if (!dce_style)
|
||||
total_len -= req_output_size;
|
||||
if (total_len < req_output_size) {
|
||||
*max_input_size = (req_output_size - total_len);
|
||||
if (!dce_style)
|
||||
*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;
|
||||
}
|
||||
|
||||
static krb5_error_code rrc_rotate(void *data, size_t len, u_int16_t rrc)
|
||||
{
|
||||
u_char *tmp;
|
||||
|
||||
if (rrc == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (len < rrc) {
|
||||
return ERANGE;
|
||||
}
|
||||
|
||||
tmp = malloc(rrc);
|
||||
if (tmp == NULL) {
|
||||
return ENOMEM;
|
||||
}
|
||||
|
||||
memcpy(tmp, (u_char *)data + len - rrc, rrc);
|
||||
memmove((u_char *)data + rrc, data, len - rrc);
|
||||
memcpy(data, tmp, rrc);
|
||||
|
||||
free(tmp);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
OM_uint32 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, len, total_len;
|
||||
u_int16_t padlength, rrc;
|
||||
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, &padlength);
|
||||
if (ret != 0) {
|
||||
gssapi_krb5_set_error_string();
|
||||
*minor_status = ret;
|
||||
krb5_crypto_destroy(gssapi_krb5_context, crypto);
|
||||
return GSS_S_FAILURE;
|
||||
}
|
||||
|
||||
#ifdef GSS_C_DCE_STYLE
|
||||
if (context_handle->flags & GSS_C_DCE_STYLE) {
|
||||
rrc = wrapped_len - (input_message_buffer->length + padlength);
|
||||
_gssapi_encap_length(rrc, &len, &total_len, GSS_KRB5_MECHANISM);
|
||||
} else {
|
||||
#endif
|
||||
rrc = 0;
|
||||
_gssapi_encap_length(wrapped_len, &len, &total_len, GSS_KRB5_MECHANISM);
|
||||
#ifdef GSS_C_DCE_STYLE
|
||||
}
|
||||
#endif
|
||||
|
||||
output_message_buffer->length = total_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 = _gssapi_make_mech_header(output_message_buffer->value,
|
||||
len, GSS_KRB5_MECHANISM);
|
||||
token = (gss_cfx_wrap_token)p;
|
||||
token->TOK_ID[0] = 0x05;
|
||||
token->TOK_ID[1] = 0x04;
|
||||
token->Direction = (context_handle->more_flags & LOCAL) ? 0 : 0xFF;
|
||||
token->Seal = conf_req_flag ? 0xFF : 0;
|
||||
token->EC[0] = (padlength >> 0) & 0xFF;
|
||||
token->EC[1] = (padlength >> 8) & 0xFF;
|
||||
token->RRC[0] = (rrc >> 0) & 0xFF;
|
||||
token->RRC[1] = (rrc >> 8) & 0xFF;
|
||||
|
||||
HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex);
|
||||
krb5_auth_con_getlocalseqnumber(gssapi_krb5_context,
|
||||
context_handle->auth_context,
|
||||
&seq_number);
|
||||
gssapi_encode_om_uint32(seq_number, &token->SND_SEQ[0]);
|
||||
gssapi_encode_om_uint32(0, &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" | "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) {
|
||||
/*
|
||||
* Note: it is likely that in version 01 of this draft
|
||||
* the header and EC padding will be placed before the
|
||||
* plaintext data, rather than the header at the end as
|
||||
* is the case presently.
|
||||
*/
|
||||
/* Place the header after the plaintext */
|
||||
p += sizeof(*token);
|
||||
memcpy(p, input_message_buffer->value, input_message_buffer->length);
|
||||
memcpy(p + input_message_buffer->length, token, sizeof(*token));
|
||||
|
||||
ret = krb5_encrypt(gssapi_krb5_context, crypto,
|
||||
usage, p,
|
||||
input_message_buffer->length + 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);
|
||||
|
||||
ret = rrc_rotate(cipher.data, cipher.length, rrc);
|
||||
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);
|
||||
|
||||
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);
|
||||
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 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;
|
||||
krb5_error_code ret;
|
||||
unsigned usage;
|
||||
krb5_data data;
|
||||
size_t len;
|
||||
u_int16_t rrc, padlength;
|
||||
OM_uint32 seq_number_lo, seq_number_hi;
|
||||
u_char *p;
|
||||
|
||||
*minor_status = 0;
|
||||
|
||||
p = input_message_buffer->value;
|
||||
ret = _gssapi_verify_mech_header(&p,
|
||||
input_message_buffer->length,
|
||||
GSS_KRB5_MECHANISM);
|
||||
if (ret != 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* check input message buffer includes room for header */
|
||||
len = (p - (u_char *)input_message_buffer->value);
|
||||
if (input_message_buffer->length - len < sizeof(*token)) {
|
||||
return GSS_S_DEFECTIVE_TOKEN;
|
||||
}
|
||||
|
||||
token = (gss_cfx_wrap_token)p;
|
||||
|
||||
if (token->TOK_ID[0] != 0x05 || token->TOK_ID[1] != 0x04) {
|
||||
return GSS_S_DEFECTIVE_TOKEN;
|
||||
}
|
||||
|
||||
if (token->Direction != ((context_handle->more_flags & LOCAL) ? 0xFF : 0)){
|
||||
return GSS_S_DEFECTIVE_TOKEN;
|
||||
}
|
||||
|
||||
if (token->Seal != 0 && token->Seal != 0xFF) {
|
||||
return GSS_S_DEFECTIVE_TOKEN;
|
||||
}
|
||||
|
||||
if (conf_state != NULL) {
|
||||
*conf_state = (token->Seal == 0xFF);
|
||||
}
|
||||
|
||||
padlength = (token->EC[1] << 8) | token->EC[0];
|
||||
|
||||
rrc = (token->RRC[1] << 8) | token->RRC[0];
|
||||
|
||||
/*
|
||||
* Check sequence number
|
||||
*/
|
||||
gssapi_decode_om_uint32(&token->SND_SEQ[0], &seq_number_lo);
|
||||
gssapi_decode_om_uint32(&token->SND_SEQ[4], &seq_number_hi);
|
||||
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(input_message_buffer->value,
|
||||
input_message_buffer->length, rrc);
|
||||
if (*minor_status != 0) {
|
||||
krb5_crypto_destroy(gssapi_krb5_context, crypto);
|
||||
return GSS_S_FAILURE;
|
||||
}
|
||||
|
||||
if (token->Seal) {
|
||||
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 token header */
|
||||
if (data.length < 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);
|
||||
|
||||
/* 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 - sizeof(*token);
|
||||
} else {
|
||||
Checksum cksum;
|
||||
|
||||
/* EC shouldn't be set if confidentiality is not requested */
|
||||
/*
|
||||
* NB: it is possible that version 1 of this draft will
|
||||
* include the checksum length in EC.
|
||||
*/
|
||||
if (padlength != 0) {
|
||||
krb5_crypto_destroy(gssapi_krb5_context, crypto);
|
||||
return GSS_S_BAD_MIC;
|
||||
}
|
||||
|
||||
/* Determine checksum type and length */
|
||||
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;
|
||||
}
|
||||
|
||||
ret = krb5_checksumsize(gssapi_krb5_context, cksum.cksumtype,
|
||||
&cksum.checksum.length);
|
||||
if (ret != 0) {
|
||||
gssapi_krb5_set_error_string();
|
||||
*minor_status = ret;
|
||||
krb5_crypto_destroy(gssapi_krb5_context, crypto);
|
||||
return GSS_S_FAILURE;
|
||||
}
|
||||
|
||||
/* 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));
|
||||
|
||||
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 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, *p;
|
||||
size_t len, total_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 = sizeof(*token) + message_buffer->length;
|
||||
buf = malloc(len);
|
||||
if (buf == NULL) {
|
||||
*minor_status = ENOMEM;
|
||||
krb5_crypto_destroy(gssapi_krb5_context, crypto);
|
||||
return GSS_S_FAILURE;
|
||||
}
|
||||
|
||||
token = (gss_cfx_mic_token)buf;
|
||||
token->TOK_ID[0] = 0x04;
|
||||
token->TOK_ID[1] = 0x04;
|
||||
token->Direction = (context_handle->more_flags & LOCAL) ? 0 : 0xFF;
|
||||
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_om_uint32(seq_number, &token->SND_SEQ[0]);
|
||||
gssapi_encode_om_uint32(0, &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);
|
||||
|
||||
memcpy(buf + sizeof(*token), message_buffer->value, message_buffer->length);
|
||||
|
||||
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 */
|
||||
len = sizeof(*token) + cksum.checksum.length;
|
||||
_gssapi_encap_length(len, &len, &total_len, GSS_KRB5_MECHANISM);
|
||||
|
||||
message_token->length = total_len;
|
||||
message_token->value = malloc(message_token->length);
|
||||
if (message_token->value == NULL) {
|
||||
*minor_status = ENOMEM;
|
||||
free(buf);
|
||||
return GSS_S_FAILURE;
|
||||
}
|
||||
|
||||
p = _gssapi_make_mech_header(message_token->value, len, GSS_KRB5_MECHANISM);
|
||||
|
||||
/* Token is { "header" | get_mic("header" | plaintext-data) } */
|
||||
memcpy(p, token, sizeof(*token));
|
||||
p += sizeof(*token);
|
||||
|
||||
memcpy(p, cksum.checksum.data, cksum.checksum.length);
|
||||
|
||||
free_Checksum(&cksum);
|
||||
free(buf);
|
||||
|
||||
*minor_status = 0;
|
||||
return GSS_S_COMPLETE;
|
||||
}
|
||||
|
||||
OM_uint32 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;
|
||||
krb5_error_code ret;
|
||||
unsigned usage;
|
||||
size_t len;
|
||||
OM_uint32 seq_number_lo, seq_number_hi;
|
||||
u_char *buf, *p;
|
||||
Checksum cksum;
|
||||
|
||||
*minor_status = 0;
|
||||
|
||||
p = token_buffer->value;
|
||||
ret = _gssapi_verify_mech_header(&p,
|
||||
token_buffer->length,
|
||||
GSS_KRB5_MECHANISM);
|
||||
if (ret != 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* check input message buffer includes room for header */
|
||||
len = (p - (u_char *)token_buffer->value);
|
||||
if (token_buffer->length - len < sizeof(*token)) {
|
||||
return GSS_S_DEFECTIVE_TOKEN;
|
||||
}
|
||||
|
||||
token = (gss_cfx_mic_token)p;
|
||||
|
||||
if (token->TOK_ID[0] != 0x04 || token->TOK_ID[1] != 0x04) {
|
||||
return GSS_S_DEFECTIVE_TOKEN;
|
||||
}
|
||||
|
||||
if (token->Direction != ((context_handle->more_flags & LOCAL) ? 0xFF : 0)){
|
||||
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_om_uint32(&token->SND_SEQ[0], &seq_number_lo);
|
||||
gssapi_decode_om_uint32(&token->SND_SEQ[4], &seq_number_hi);
|
||||
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 - len - sizeof(*token);
|
||||
|
||||
if (context_handle->more_flags & LOCAL) {
|
||||
usage = KRB5_KU_USAGE_ACCEPTOR_SIGN;
|
||||
} else {
|
||||
usage = KRB5_KU_USAGE_INITIATOR_SIGN;
|
||||
}
|
||||
|
||||
buf = malloc(sizeof(*token) + message_buffer->length);
|
||||
if (buf == NULL) {
|
||||
*minor_status = ENOMEM;
|
||||
krb5_crypto_destroy(gssapi_krb5_context, crypto);
|
||||
return GSS_S_FAILURE;
|
||||
}
|
||||
memcpy(buf, token, sizeof(*token));
|
||||
memcpy(buf + sizeof(*token), message_buffer->value, message_buffer->length);
|
||||
|
||||
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;
|
||||
}
|
||||
|
104
lib/gssapi/krb5/cfx.h
Normal file
104
lib/gssapi/krb5/cfx.h
Normal file
@@ -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$ */
|
||||
|
||||
#ifndef CFX_H_
|
||||
#define CFX_H_ 1
|
||||
|
||||
/*
|
||||
* Implementation of draft-ietf-krb-wg-gssapi-cfx-00.txt
|
||||
*/
|
||||
|
||||
typedef struct gss_cfx_mic_token_desc_struct {
|
||||
u_char TOK_ID[2]; /* 04 04 */
|
||||
u_char Direction;
|
||||
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]; /* 05 04 */
|
||||
u_char Direction;
|
||||
u_char Seal;
|
||||
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]; /* 04 05 */
|
||||
u_char Direction;
|
||||
u_char Filler[5];
|
||||
u_char SND_SEQ[8];
|
||||
} gss_cfx_delete_token_desc, *gss_cfx_delete_token;
|
||||
|
||||
OM_uint32 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 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 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 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 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 /* CFX_H_ */
|
Reference in New Issue
Block a user