1c19800e8SDoug Rabson /* 2c19800e8SDoug Rabson * Copyright (c) 2003, PADL Software Pty Ltd. 3c19800e8SDoug Rabson * All rights reserved. 4c19800e8SDoug Rabson * 5c19800e8SDoug Rabson * Redistribution and use in source and binary forms, with or without 6c19800e8SDoug Rabson * modification, are permitted provided that the following conditions 7c19800e8SDoug Rabson * are met: 8c19800e8SDoug Rabson * 9c19800e8SDoug Rabson * 1. Redistributions of source code must retain the above copyright 10c19800e8SDoug Rabson * notice, this list of conditions and the following disclaimer. 11c19800e8SDoug Rabson * 12c19800e8SDoug Rabson * 2. Redistributions in binary form must reproduce the above copyright 13c19800e8SDoug Rabson * notice, this list of conditions and the following disclaimer in the 14c19800e8SDoug Rabson * documentation and/or other materials provided with the distribution. 15c19800e8SDoug Rabson * 16c19800e8SDoug Rabson * 3. Neither the name of PADL Software nor the names of its contributors 17c19800e8SDoug Rabson * may be used to endorse or promote products derived from this software 18c19800e8SDoug Rabson * without specific prior written permission. 19c19800e8SDoug Rabson * 20c19800e8SDoug Rabson * THIS SOFTWARE IS PROVIDED BY PADL SOFTWARE AND CONTRIBUTORS ``AS IS'' AND 21c19800e8SDoug Rabson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22c19800e8SDoug Rabson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23c19800e8SDoug Rabson * ARE DISCLAIMED. IN NO EVENT SHALL PADL SOFTWARE OR CONTRIBUTORS BE LIABLE 24c19800e8SDoug Rabson * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25c19800e8SDoug Rabson * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26c19800e8SDoug Rabson * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27c19800e8SDoug Rabson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28c19800e8SDoug Rabson * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29c19800e8SDoug Rabson * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30c19800e8SDoug Rabson * SUCH DAMAGE. 31c19800e8SDoug Rabson */ 32c19800e8SDoug Rabson 33c19800e8SDoug Rabson #include "krb5/gsskrb5_locl.h" 34c19800e8SDoug Rabson 35c19800e8SDoug Rabson RCSID("$Id: cfx.c 19031 2006-11-13 18:02:57Z lha $"); 36c19800e8SDoug Rabson 37c19800e8SDoug Rabson /* 38c19800e8SDoug Rabson * Implementation of draft-ietf-krb-wg-gssapi-cfx-06.txt 39c19800e8SDoug Rabson */ 40c19800e8SDoug Rabson 41c19800e8SDoug Rabson #define CFXSentByAcceptor (1 << 0) 42c19800e8SDoug Rabson #define CFXSealed (1 << 1) 43c19800e8SDoug Rabson #define CFXAcceptorSubkey (1 << 2) 44c19800e8SDoug Rabson 45c19800e8SDoug Rabson krb5_error_code 46c19800e8SDoug Rabson _gsskrb5cfx_wrap_length_cfx(krb5_context context, 47c19800e8SDoug Rabson krb5_crypto crypto, 48c19800e8SDoug Rabson int conf_req_flag, 49c19800e8SDoug Rabson size_t input_length, 50c19800e8SDoug Rabson size_t *output_length, 51c19800e8SDoug Rabson size_t *cksumsize, 52c19800e8SDoug Rabson uint16_t *padlength) 53c19800e8SDoug Rabson { 54c19800e8SDoug Rabson krb5_error_code ret; 55c19800e8SDoug Rabson krb5_cksumtype type; 56c19800e8SDoug Rabson 57c19800e8SDoug Rabson /* 16-byte header is always first */ 58c19800e8SDoug Rabson *output_length = sizeof(gss_cfx_wrap_token_desc); 59c19800e8SDoug Rabson *padlength = 0; 60c19800e8SDoug Rabson 61c19800e8SDoug Rabson ret = krb5_crypto_get_checksum_type(context, crypto, &type); 62c19800e8SDoug Rabson if (ret) 63c19800e8SDoug Rabson return ret; 64c19800e8SDoug Rabson 65c19800e8SDoug Rabson ret = krb5_checksumsize(context, type, cksumsize); 66c19800e8SDoug Rabson if (ret) 67c19800e8SDoug Rabson return ret; 68c19800e8SDoug Rabson 69c19800e8SDoug Rabson if (conf_req_flag) { 70c19800e8SDoug Rabson size_t padsize; 71c19800e8SDoug Rabson 72c19800e8SDoug Rabson /* Header is concatenated with data before encryption */ 73c19800e8SDoug Rabson input_length += sizeof(gss_cfx_wrap_token_desc); 74c19800e8SDoug Rabson 75c19800e8SDoug Rabson ret = krb5_crypto_getpadsize(context, crypto, &padsize); 76c19800e8SDoug Rabson if (ret) { 77c19800e8SDoug Rabson return ret; 78c19800e8SDoug Rabson } 79c19800e8SDoug Rabson if (padsize > 1) { 80c19800e8SDoug Rabson /* XXX check this */ 81c19800e8SDoug Rabson *padlength = padsize - (input_length % padsize); 82c19800e8SDoug Rabson 83c19800e8SDoug Rabson /* We add the pad ourselves (noted here for completeness only) */ 84c19800e8SDoug Rabson input_length += *padlength; 85c19800e8SDoug Rabson } 86c19800e8SDoug Rabson 87c19800e8SDoug Rabson *output_length += krb5_get_wrapped_length(context, 88c19800e8SDoug Rabson crypto, input_length); 89c19800e8SDoug Rabson } else { 90c19800e8SDoug Rabson /* Checksum is concatenated with data */ 91c19800e8SDoug Rabson *output_length += input_length + *cksumsize; 92c19800e8SDoug Rabson } 93c19800e8SDoug Rabson 94c19800e8SDoug Rabson assert(*output_length > input_length); 95c19800e8SDoug Rabson 96c19800e8SDoug Rabson return 0; 97c19800e8SDoug Rabson } 98c19800e8SDoug Rabson 99c19800e8SDoug Rabson krb5_error_code 100c19800e8SDoug Rabson _gsskrb5cfx_max_wrap_length_cfx(krb5_context context, 101c19800e8SDoug Rabson krb5_crypto crypto, 102c19800e8SDoug Rabson int conf_req_flag, 103c19800e8SDoug Rabson size_t input_length, 104c19800e8SDoug Rabson OM_uint32 *output_length) 105c19800e8SDoug Rabson { 106c19800e8SDoug Rabson krb5_error_code ret; 107c19800e8SDoug Rabson 108c19800e8SDoug Rabson *output_length = 0; 109c19800e8SDoug Rabson 110c19800e8SDoug Rabson /* 16-byte header is always first */ 111c19800e8SDoug Rabson if (input_length < 16) 112c19800e8SDoug Rabson return 0; 113c19800e8SDoug Rabson input_length -= 16; 114c19800e8SDoug Rabson 115c19800e8SDoug Rabson if (conf_req_flag) { 116c19800e8SDoug Rabson size_t wrapped_size, sz; 117c19800e8SDoug Rabson 118c19800e8SDoug Rabson wrapped_size = input_length + 1; 119c19800e8SDoug Rabson do { 120c19800e8SDoug Rabson wrapped_size--; 121c19800e8SDoug Rabson sz = krb5_get_wrapped_length(context, 122c19800e8SDoug Rabson crypto, wrapped_size); 123c19800e8SDoug Rabson } while (wrapped_size && sz > input_length); 124c19800e8SDoug Rabson if (wrapped_size == 0) { 125c19800e8SDoug Rabson *output_length = 0; 126c19800e8SDoug Rabson return 0; 127c19800e8SDoug Rabson } 128c19800e8SDoug Rabson 129c19800e8SDoug Rabson /* inner header */ 130c19800e8SDoug Rabson if (wrapped_size < 16) { 131c19800e8SDoug Rabson *output_length = 0; 132c19800e8SDoug Rabson return 0; 133c19800e8SDoug Rabson } 134c19800e8SDoug Rabson wrapped_size -= 16; 135c19800e8SDoug Rabson 136c19800e8SDoug Rabson *output_length = wrapped_size; 137c19800e8SDoug Rabson } else { 138c19800e8SDoug Rabson krb5_cksumtype type; 139c19800e8SDoug Rabson size_t cksumsize; 140c19800e8SDoug Rabson 141c19800e8SDoug Rabson ret = krb5_crypto_get_checksum_type(context, crypto, &type); 142c19800e8SDoug Rabson if (ret) 143c19800e8SDoug Rabson return ret; 144c19800e8SDoug Rabson 145c19800e8SDoug Rabson ret = krb5_checksumsize(context, type, &cksumsize); 146c19800e8SDoug Rabson if (ret) 147c19800e8SDoug Rabson return ret; 148c19800e8SDoug Rabson 149c19800e8SDoug Rabson if (input_length < cksumsize) 150c19800e8SDoug Rabson return 0; 151c19800e8SDoug Rabson 152c19800e8SDoug Rabson /* Checksum is concatenated with data */ 153c19800e8SDoug Rabson *output_length = input_length - cksumsize; 154c19800e8SDoug Rabson } 155c19800e8SDoug Rabson 156c19800e8SDoug Rabson return 0; 157c19800e8SDoug Rabson } 158c19800e8SDoug Rabson 159c19800e8SDoug Rabson 160c19800e8SDoug Rabson OM_uint32 _gssapi_wrap_size_cfx(OM_uint32 *minor_status, 161c19800e8SDoug Rabson const gsskrb5_ctx context_handle, 162c19800e8SDoug Rabson krb5_context context, 163c19800e8SDoug Rabson int conf_req_flag, 164c19800e8SDoug Rabson gss_qop_t qop_req, 165c19800e8SDoug Rabson OM_uint32 req_output_size, 166c19800e8SDoug Rabson OM_uint32 *max_input_size, 167c19800e8SDoug Rabson krb5_keyblock *key) 168c19800e8SDoug Rabson { 169c19800e8SDoug Rabson krb5_error_code ret; 170c19800e8SDoug Rabson krb5_crypto crypto; 171c19800e8SDoug Rabson 172c19800e8SDoug Rabson ret = krb5_crypto_init(context, key, 0, &crypto); 173c19800e8SDoug Rabson if (ret != 0) { 174c19800e8SDoug Rabson *minor_status = ret; 175c19800e8SDoug Rabson return GSS_S_FAILURE; 176c19800e8SDoug Rabson } 177c19800e8SDoug Rabson 178c19800e8SDoug Rabson ret = _gsskrb5cfx_max_wrap_length_cfx(context, crypto, conf_req_flag, 179c19800e8SDoug Rabson req_output_size, max_input_size); 180c19800e8SDoug Rabson if (ret != 0) { 181c19800e8SDoug Rabson *minor_status = ret; 182c19800e8SDoug Rabson krb5_crypto_destroy(context, crypto); 183c19800e8SDoug Rabson return GSS_S_FAILURE; 184c19800e8SDoug Rabson } 185c19800e8SDoug Rabson 186c19800e8SDoug Rabson krb5_crypto_destroy(context, crypto); 187c19800e8SDoug Rabson 188c19800e8SDoug Rabson return GSS_S_COMPLETE; 189c19800e8SDoug Rabson } 190c19800e8SDoug Rabson 191c19800e8SDoug Rabson /* 192c19800e8SDoug Rabson * Rotate "rrc" bytes to the front or back 193c19800e8SDoug Rabson */ 194c19800e8SDoug Rabson 195c19800e8SDoug Rabson static krb5_error_code 196c19800e8SDoug Rabson rrc_rotate(void *data, size_t len, uint16_t rrc, krb5_boolean unrotate) 197c19800e8SDoug Rabson { 198c19800e8SDoug Rabson u_char *tmp, buf[256]; 199c19800e8SDoug Rabson size_t left; 200c19800e8SDoug Rabson 201c19800e8SDoug Rabson if (len == 0) 202c19800e8SDoug Rabson return 0; 203c19800e8SDoug Rabson 204c19800e8SDoug Rabson rrc %= len; 205c19800e8SDoug Rabson 206c19800e8SDoug Rabson if (rrc == 0) 207c19800e8SDoug Rabson return 0; 208c19800e8SDoug Rabson 209c19800e8SDoug Rabson left = len - rrc; 210c19800e8SDoug Rabson 211c19800e8SDoug Rabson if (rrc <= sizeof(buf)) { 212c19800e8SDoug Rabson tmp = buf; 213c19800e8SDoug Rabson } else { 214c19800e8SDoug Rabson tmp = malloc(rrc); 215c19800e8SDoug Rabson if (tmp == NULL) 216c19800e8SDoug Rabson return ENOMEM; 217c19800e8SDoug Rabson } 218c19800e8SDoug Rabson 219c19800e8SDoug Rabson if (unrotate) { 220c19800e8SDoug Rabson memcpy(tmp, data, rrc); 221c19800e8SDoug Rabson memmove(data, (u_char *)data + rrc, left); 222c19800e8SDoug Rabson memcpy((u_char *)data + left, tmp, rrc); 223c19800e8SDoug Rabson } else { 224c19800e8SDoug Rabson memcpy(tmp, (u_char *)data + left, rrc); 225c19800e8SDoug Rabson memmove((u_char *)data + rrc, data, left); 226c19800e8SDoug Rabson memcpy(data, tmp, rrc); 227c19800e8SDoug Rabson } 228c19800e8SDoug Rabson 229c19800e8SDoug Rabson if (rrc > sizeof(buf)) 230c19800e8SDoug Rabson free(tmp); 231c19800e8SDoug Rabson 232c19800e8SDoug Rabson return 0; 233c19800e8SDoug Rabson } 234c19800e8SDoug Rabson 235c19800e8SDoug Rabson OM_uint32 _gssapi_wrap_cfx(OM_uint32 *minor_status, 236c19800e8SDoug Rabson const gsskrb5_ctx context_handle, 237c19800e8SDoug Rabson krb5_context context, 238c19800e8SDoug Rabson int conf_req_flag, 239c19800e8SDoug Rabson gss_qop_t qop_req, 240c19800e8SDoug Rabson const gss_buffer_t input_message_buffer, 241c19800e8SDoug Rabson int *conf_state, 242c19800e8SDoug Rabson gss_buffer_t output_message_buffer, 243c19800e8SDoug Rabson krb5_keyblock *key) 244c19800e8SDoug Rabson { 245c19800e8SDoug Rabson krb5_crypto crypto; 246c19800e8SDoug Rabson gss_cfx_wrap_token token; 247c19800e8SDoug Rabson krb5_error_code ret; 248c19800e8SDoug Rabson unsigned usage; 249c19800e8SDoug Rabson krb5_data cipher; 250c19800e8SDoug Rabson size_t wrapped_len, cksumsize; 251c19800e8SDoug Rabson uint16_t padlength, rrc = 0; 252c19800e8SDoug Rabson int32_t seq_number; 253c19800e8SDoug Rabson u_char *p; 254c19800e8SDoug Rabson 255c19800e8SDoug Rabson ret = krb5_crypto_init(context, key, 0, &crypto); 256c19800e8SDoug Rabson if (ret != 0) { 257c19800e8SDoug Rabson *minor_status = ret; 258c19800e8SDoug Rabson return GSS_S_FAILURE; 259c19800e8SDoug Rabson } 260c19800e8SDoug Rabson 261c19800e8SDoug Rabson ret = _gsskrb5cfx_wrap_length_cfx(context, 262c19800e8SDoug Rabson crypto, conf_req_flag, 263c19800e8SDoug Rabson input_message_buffer->length, 264c19800e8SDoug Rabson &wrapped_len, &cksumsize, &padlength); 265c19800e8SDoug Rabson if (ret != 0) { 266c19800e8SDoug Rabson *minor_status = ret; 267c19800e8SDoug Rabson krb5_crypto_destroy(context, crypto); 268c19800e8SDoug Rabson return GSS_S_FAILURE; 269c19800e8SDoug Rabson } 270c19800e8SDoug Rabson 271c19800e8SDoug Rabson /* Always rotate encrypted token (if any) and checksum to header */ 272c19800e8SDoug Rabson rrc = (conf_req_flag ? sizeof(*token) : 0) + (uint16_t)cksumsize; 273c19800e8SDoug Rabson 274c19800e8SDoug Rabson output_message_buffer->length = wrapped_len; 275c19800e8SDoug Rabson output_message_buffer->value = malloc(output_message_buffer->length); 276c19800e8SDoug Rabson if (output_message_buffer->value == NULL) { 277c19800e8SDoug Rabson *minor_status = ENOMEM; 278c19800e8SDoug Rabson krb5_crypto_destroy(context, crypto); 279c19800e8SDoug Rabson return GSS_S_FAILURE; 280c19800e8SDoug Rabson } 281c19800e8SDoug Rabson 282c19800e8SDoug Rabson p = output_message_buffer->value; 283c19800e8SDoug Rabson token = (gss_cfx_wrap_token)p; 284c19800e8SDoug Rabson token->TOK_ID[0] = 0x05; 285c19800e8SDoug Rabson token->TOK_ID[1] = 0x04; 286c19800e8SDoug Rabson token->Flags = 0; 287c19800e8SDoug Rabson token->Filler = 0xFF; 288c19800e8SDoug Rabson if ((context_handle->more_flags & LOCAL) == 0) 289c19800e8SDoug Rabson token->Flags |= CFXSentByAcceptor; 290c19800e8SDoug Rabson if (context_handle->more_flags & ACCEPTOR_SUBKEY) 291c19800e8SDoug Rabson token->Flags |= CFXAcceptorSubkey; 292c19800e8SDoug Rabson if (conf_req_flag) { 293c19800e8SDoug Rabson /* 294c19800e8SDoug Rabson * In Wrap tokens with confidentiality, the EC field is 295c19800e8SDoug Rabson * used to encode the size (in bytes) of the random filler. 296c19800e8SDoug Rabson */ 297c19800e8SDoug Rabson token->Flags |= CFXSealed; 298c19800e8SDoug Rabson token->EC[0] = (padlength >> 8) & 0xFF; 299c19800e8SDoug Rabson token->EC[1] = (padlength >> 0) & 0xFF; 300c19800e8SDoug Rabson } else { 301c19800e8SDoug Rabson /* 302c19800e8SDoug Rabson * In Wrap tokens without confidentiality, the EC field is 303c19800e8SDoug Rabson * used to encode the size (in bytes) of the trailing 304c19800e8SDoug Rabson * checksum. 305c19800e8SDoug Rabson * 306c19800e8SDoug Rabson * This is not used in the checksum calcuation itself, 307c19800e8SDoug Rabson * because the checksum length could potentially vary 308c19800e8SDoug Rabson * depending on the data length. 309c19800e8SDoug Rabson */ 310c19800e8SDoug Rabson token->EC[0] = 0; 311c19800e8SDoug Rabson token->EC[1] = 0; 312c19800e8SDoug Rabson } 313c19800e8SDoug Rabson 314c19800e8SDoug Rabson /* 315c19800e8SDoug Rabson * In Wrap tokens that provide for confidentiality, the RRC 316c19800e8SDoug Rabson * field in the header contains the hex value 00 00 before 317c19800e8SDoug Rabson * encryption. 318c19800e8SDoug Rabson * 319c19800e8SDoug Rabson * In Wrap tokens that do not provide for confidentiality, 320c19800e8SDoug Rabson * both the EC and RRC fields in the appended checksum 321c19800e8SDoug Rabson * contain the hex value 00 00 for the purpose of calculating 322c19800e8SDoug Rabson * the checksum. 323c19800e8SDoug Rabson */ 324c19800e8SDoug Rabson token->RRC[0] = 0; 325c19800e8SDoug Rabson token->RRC[1] = 0; 326c19800e8SDoug Rabson 327c19800e8SDoug Rabson HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex); 328c19800e8SDoug Rabson krb5_auth_con_getlocalseqnumber(context, 329c19800e8SDoug Rabson context_handle->auth_context, 330c19800e8SDoug Rabson &seq_number); 331c19800e8SDoug Rabson _gsskrb5_encode_be_om_uint32(0, &token->SND_SEQ[0]); 332c19800e8SDoug Rabson _gsskrb5_encode_be_om_uint32(seq_number, &token->SND_SEQ[4]); 333c19800e8SDoug Rabson krb5_auth_con_setlocalseqnumber(context, 334c19800e8SDoug Rabson context_handle->auth_context, 335c19800e8SDoug Rabson ++seq_number); 336c19800e8SDoug Rabson HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex); 337c19800e8SDoug Rabson 338c19800e8SDoug Rabson /* 339c19800e8SDoug Rabson * If confidentiality is requested, the token header is 340c19800e8SDoug Rabson * appended to the plaintext before encryption; the resulting 341c19800e8SDoug Rabson * token is {"header" | encrypt(plaintext | pad | "header")}. 342c19800e8SDoug Rabson * 343c19800e8SDoug Rabson * If no confidentiality is requested, the checksum is 344c19800e8SDoug Rabson * calculated over the plaintext concatenated with the 345c19800e8SDoug Rabson * token header. 346c19800e8SDoug Rabson */ 347c19800e8SDoug Rabson if (context_handle->more_flags & LOCAL) { 348c19800e8SDoug Rabson usage = KRB5_KU_USAGE_INITIATOR_SEAL; 349c19800e8SDoug Rabson } else { 350c19800e8SDoug Rabson usage = KRB5_KU_USAGE_ACCEPTOR_SEAL; 351c19800e8SDoug Rabson } 352c19800e8SDoug Rabson 353c19800e8SDoug Rabson if (conf_req_flag) { 354c19800e8SDoug Rabson /* 355c19800e8SDoug Rabson * Any necessary padding is added here to ensure that the 356c19800e8SDoug Rabson * encrypted token header is always at the end of the 357c19800e8SDoug Rabson * ciphertext. 358c19800e8SDoug Rabson * 359c19800e8SDoug Rabson * The specification does not require that the padding 360c19800e8SDoug Rabson * bytes are initialized. 361c19800e8SDoug Rabson */ 362c19800e8SDoug Rabson p += sizeof(*token); 363c19800e8SDoug Rabson memcpy(p, input_message_buffer->value, input_message_buffer->length); 364c19800e8SDoug Rabson memset(p + input_message_buffer->length, 0xFF, padlength); 365c19800e8SDoug Rabson memcpy(p + input_message_buffer->length + padlength, 366c19800e8SDoug Rabson token, sizeof(*token)); 367c19800e8SDoug Rabson 368c19800e8SDoug Rabson ret = krb5_encrypt(context, crypto, 369c19800e8SDoug Rabson usage, p, 370c19800e8SDoug Rabson input_message_buffer->length + padlength + 371c19800e8SDoug Rabson sizeof(*token), 372c19800e8SDoug Rabson &cipher); 373c19800e8SDoug Rabson if (ret != 0) { 374c19800e8SDoug Rabson *minor_status = ret; 375c19800e8SDoug Rabson krb5_crypto_destroy(context, crypto); 376c19800e8SDoug Rabson _gsskrb5_release_buffer(minor_status, output_message_buffer); 377c19800e8SDoug Rabson return GSS_S_FAILURE; 378c19800e8SDoug Rabson } 379c19800e8SDoug Rabson assert(sizeof(*token) + cipher.length == wrapped_len); 380c19800e8SDoug Rabson token->RRC[0] = (rrc >> 8) & 0xFF; 381c19800e8SDoug Rabson token->RRC[1] = (rrc >> 0) & 0xFF; 382c19800e8SDoug Rabson 383c19800e8SDoug Rabson ret = rrc_rotate(cipher.data, cipher.length, rrc, FALSE); 384c19800e8SDoug Rabson if (ret != 0) { 385c19800e8SDoug Rabson *minor_status = ret; 386c19800e8SDoug Rabson krb5_crypto_destroy(context, crypto); 387c19800e8SDoug Rabson _gsskrb5_release_buffer(minor_status, output_message_buffer); 388c19800e8SDoug Rabson return GSS_S_FAILURE; 389c19800e8SDoug Rabson } 390c19800e8SDoug Rabson memcpy(p, cipher.data, cipher.length); 391c19800e8SDoug Rabson krb5_data_free(&cipher); 392c19800e8SDoug Rabson } else { 393c19800e8SDoug Rabson char *buf; 394c19800e8SDoug Rabson Checksum cksum; 395c19800e8SDoug Rabson 396c19800e8SDoug Rabson buf = malloc(input_message_buffer->length + sizeof(*token)); 397c19800e8SDoug Rabson if (buf == NULL) { 398c19800e8SDoug Rabson *minor_status = ENOMEM; 399c19800e8SDoug Rabson krb5_crypto_destroy(context, crypto); 400c19800e8SDoug Rabson _gsskrb5_release_buffer(minor_status, output_message_buffer); 401c19800e8SDoug Rabson return GSS_S_FAILURE; 402c19800e8SDoug Rabson } 403c19800e8SDoug Rabson memcpy(buf, input_message_buffer->value, input_message_buffer->length); 404c19800e8SDoug Rabson memcpy(buf + input_message_buffer->length, token, sizeof(*token)); 405c19800e8SDoug Rabson 406c19800e8SDoug Rabson ret = krb5_create_checksum(context, crypto, 407c19800e8SDoug Rabson usage, 0, buf, 408c19800e8SDoug Rabson input_message_buffer->length + 409c19800e8SDoug Rabson sizeof(*token), 410c19800e8SDoug Rabson &cksum); 411c19800e8SDoug Rabson if (ret != 0) { 412c19800e8SDoug Rabson *minor_status = ret; 413c19800e8SDoug Rabson krb5_crypto_destroy(context, crypto); 414c19800e8SDoug Rabson _gsskrb5_release_buffer(minor_status, output_message_buffer); 415c19800e8SDoug Rabson free(buf); 416c19800e8SDoug Rabson return GSS_S_FAILURE; 417c19800e8SDoug Rabson } 418c19800e8SDoug Rabson 419c19800e8SDoug Rabson free(buf); 420c19800e8SDoug Rabson 421c19800e8SDoug Rabson assert(cksum.checksum.length == cksumsize); 422c19800e8SDoug Rabson token->EC[0] = (cksum.checksum.length >> 8) & 0xFF; 423c19800e8SDoug Rabson token->EC[1] = (cksum.checksum.length >> 0) & 0xFF; 424c19800e8SDoug Rabson token->RRC[0] = (rrc >> 8) & 0xFF; 425c19800e8SDoug Rabson token->RRC[1] = (rrc >> 0) & 0xFF; 426c19800e8SDoug Rabson 427c19800e8SDoug Rabson p += sizeof(*token); 428c19800e8SDoug Rabson memcpy(p, input_message_buffer->value, input_message_buffer->length); 429c19800e8SDoug Rabson memcpy(p + input_message_buffer->length, 430c19800e8SDoug Rabson cksum.checksum.data, cksum.checksum.length); 431c19800e8SDoug Rabson 432c19800e8SDoug Rabson ret = rrc_rotate(p, 433c19800e8SDoug Rabson input_message_buffer->length + cksum.checksum.length, rrc, FALSE); 434c19800e8SDoug Rabson if (ret != 0) { 435c19800e8SDoug Rabson *minor_status = ret; 436c19800e8SDoug Rabson krb5_crypto_destroy(context, crypto); 437c19800e8SDoug Rabson _gsskrb5_release_buffer(minor_status, output_message_buffer); 438c19800e8SDoug Rabson free_Checksum(&cksum); 439c19800e8SDoug Rabson return GSS_S_FAILURE; 440c19800e8SDoug Rabson } 441c19800e8SDoug Rabson free_Checksum(&cksum); 442c19800e8SDoug Rabson } 443c19800e8SDoug Rabson 444c19800e8SDoug Rabson krb5_crypto_destroy(context, crypto); 445c19800e8SDoug Rabson 446c19800e8SDoug Rabson if (conf_state != NULL) { 447c19800e8SDoug Rabson *conf_state = conf_req_flag; 448c19800e8SDoug Rabson } 449c19800e8SDoug Rabson 450c19800e8SDoug Rabson *minor_status = 0; 451c19800e8SDoug Rabson return GSS_S_COMPLETE; 452c19800e8SDoug Rabson } 453c19800e8SDoug Rabson 454c19800e8SDoug Rabson OM_uint32 _gssapi_unwrap_cfx(OM_uint32 *minor_status, 455c19800e8SDoug Rabson const gsskrb5_ctx context_handle, 456c19800e8SDoug Rabson krb5_context context, 457c19800e8SDoug Rabson const gss_buffer_t input_message_buffer, 458c19800e8SDoug Rabson gss_buffer_t output_message_buffer, 459c19800e8SDoug Rabson int *conf_state, 460c19800e8SDoug Rabson gss_qop_t *qop_state, 461c19800e8SDoug Rabson krb5_keyblock *key) 462c19800e8SDoug Rabson { 463c19800e8SDoug Rabson krb5_crypto crypto; 464c19800e8SDoug Rabson gss_cfx_wrap_token token; 465c19800e8SDoug Rabson u_char token_flags; 466c19800e8SDoug Rabson krb5_error_code ret; 467c19800e8SDoug Rabson unsigned usage; 468c19800e8SDoug Rabson krb5_data data; 469c19800e8SDoug Rabson uint16_t ec, rrc; 470c19800e8SDoug Rabson OM_uint32 seq_number_lo, seq_number_hi; 471c19800e8SDoug Rabson size_t len; 472c19800e8SDoug Rabson u_char *p; 473c19800e8SDoug Rabson 474c19800e8SDoug Rabson *minor_status = 0; 475c19800e8SDoug Rabson 476c19800e8SDoug Rabson if (input_message_buffer->length < sizeof(*token)) { 477c19800e8SDoug Rabson return GSS_S_DEFECTIVE_TOKEN; 478c19800e8SDoug Rabson } 479c19800e8SDoug Rabson 480c19800e8SDoug Rabson p = input_message_buffer->value; 481c19800e8SDoug Rabson 482c19800e8SDoug Rabson token = (gss_cfx_wrap_token)p; 483c19800e8SDoug Rabson 484c19800e8SDoug Rabson if (token->TOK_ID[0] != 0x05 || token->TOK_ID[1] != 0x04) { 485c19800e8SDoug Rabson return GSS_S_DEFECTIVE_TOKEN; 486c19800e8SDoug Rabson } 487c19800e8SDoug Rabson 488c19800e8SDoug Rabson /* Ignore unknown flags */ 489c19800e8SDoug Rabson token_flags = token->Flags & 490c19800e8SDoug Rabson (CFXSentByAcceptor | CFXSealed | CFXAcceptorSubkey); 491c19800e8SDoug Rabson 492c19800e8SDoug Rabson if (token_flags & CFXSentByAcceptor) { 493c19800e8SDoug Rabson if ((context_handle->more_flags & LOCAL) == 0) 494c19800e8SDoug Rabson return GSS_S_DEFECTIVE_TOKEN; 495c19800e8SDoug Rabson } 496c19800e8SDoug Rabson 497c19800e8SDoug Rabson if (context_handle->more_flags & ACCEPTOR_SUBKEY) { 498c19800e8SDoug Rabson if ((token_flags & CFXAcceptorSubkey) == 0) 499c19800e8SDoug Rabson return GSS_S_DEFECTIVE_TOKEN; 500c19800e8SDoug Rabson } else { 501c19800e8SDoug Rabson if (token_flags & CFXAcceptorSubkey) 502c19800e8SDoug Rabson return GSS_S_DEFECTIVE_TOKEN; 503c19800e8SDoug Rabson } 504c19800e8SDoug Rabson 505c19800e8SDoug Rabson if (token->Filler != 0xFF) { 506c19800e8SDoug Rabson return GSS_S_DEFECTIVE_TOKEN; 507c19800e8SDoug Rabson } 508c19800e8SDoug Rabson 509c19800e8SDoug Rabson if (conf_state != NULL) { 510c19800e8SDoug Rabson *conf_state = (token_flags & CFXSealed) ? 1 : 0; 511c19800e8SDoug Rabson } 512c19800e8SDoug Rabson 513c19800e8SDoug Rabson ec = (token->EC[0] << 8) | token->EC[1]; 514c19800e8SDoug Rabson rrc = (token->RRC[0] << 8) | token->RRC[1]; 515c19800e8SDoug Rabson 516c19800e8SDoug Rabson /* 517c19800e8SDoug Rabson * Check sequence number 518c19800e8SDoug Rabson */ 519c19800e8SDoug Rabson _gsskrb5_decode_be_om_uint32(&token->SND_SEQ[0], &seq_number_hi); 520c19800e8SDoug Rabson _gsskrb5_decode_be_om_uint32(&token->SND_SEQ[4], &seq_number_lo); 521c19800e8SDoug Rabson if (seq_number_hi) { 522c19800e8SDoug Rabson /* no support for 64-bit sequence numbers */ 523c19800e8SDoug Rabson *minor_status = ERANGE; 524c19800e8SDoug Rabson return GSS_S_UNSEQ_TOKEN; 525c19800e8SDoug Rabson } 526c19800e8SDoug Rabson 527c19800e8SDoug Rabson HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex); 528c19800e8SDoug Rabson ret = _gssapi_msg_order_check(context_handle->order, seq_number_lo); 529c19800e8SDoug Rabson if (ret != 0) { 530c19800e8SDoug Rabson *minor_status = 0; 531c19800e8SDoug Rabson HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex); 532c19800e8SDoug Rabson _gsskrb5_release_buffer(minor_status, output_message_buffer); 533c19800e8SDoug Rabson return ret; 534c19800e8SDoug Rabson } 535c19800e8SDoug Rabson HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex); 536c19800e8SDoug Rabson 537c19800e8SDoug Rabson /* 538c19800e8SDoug Rabson * Decrypt and/or verify checksum 539c19800e8SDoug Rabson */ 540c19800e8SDoug Rabson ret = krb5_crypto_init(context, key, 0, &crypto); 541c19800e8SDoug Rabson if (ret != 0) { 542c19800e8SDoug Rabson *minor_status = ret; 543c19800e8SDoug Rabson return GSS_S_FAILURE; 544c19800e8SDoug Rabson } 545c19800e8SDoug Rabson 546c19800e8SDoug Rabson if (context_handle->more_flags & LOCAL) { 547c19800e8SDoug Rabson usage = KRB5_KU_USAGE_ACCEPTOR_SEAL; 548c19800e8SDoug Rabson } else { 549c19800e8SDoug Rabson usage = KRB5_KU_USAGE_INITIATOR_SEAL; 550c19800e8SDoug Rabson } 551c19800e8SDoug Rabson 552c19800e8SDoug Rabson p += sizeof(*token); 553c19800e8SDoug Rabson len = input_message_buffer->length; 554c19800e8SDoug Rabson len -= (p - (u_char *)input_message_buffer->value); 555c19800e8SDoug Rabson 556c19800e8SDoug Rabson /* Rotate by RRC; bogus to do this in-place XXX */ 557c19800e8SDoug Rabson *minor_status = rrc_rotate(p, len, rrc, TRUE); 558c19800e8SDoug Rabson if (*minor_status != 0) { 559c19800e8SDoug Rabson krb5_crypto_destroy(context, crypto); 560c19800e8SDoug Rabson return GSS_S_FAILURE; 561c19800e8SDoug Rabson } 562c19800e8SDoug Rabson 563c19800e8SDoug Rabson if (token_flags & CFXSealed) { 564c19800e8SDoug Rabson ret = krb5_decrypt(context, crypto, usage, 565c19800e8SDoug Rabson p, len, &data); 566c19800e8SDoug Rabson if (ret != 0) { 567c19800e8SDoug Rabson *minor_status = ret; 568c19800e8SDoug Rabson krb5_crypto_destroy(context, crypto); 569c19800e8SDoug Rabson return GSS_S_BAD_MIC; 570c19800e8SDoug Rabson } 571c19800e8SDoug Rabson 572c19800e8SDoug Rabson /* Check that there is room for the pad and token header */ 573c19800e8SDoug Rabson if (data.length < ec + sizeof(*token)) { 574c19800e8SDoug Rabson krb5_crypto_destroy(context, crypto); 575c19800e8SDoug Rabson krb5_data_free(&data); 576c19800e8SDoug Rabson return GSS_S_DEFECTIVE_TOKEN; 577c19800e8SDoug Rabson } 578c19800e8SDoug Rabson p = data.data; 579c19800e8SDoug Rabson p += data.length - sizeof(*token); 580c19800e8SDoug Rabson 581c19800e8SDoug Rabson /* RRC is unprotected; don't modify input buffer */ 582c19800e8SDoug Rabson ((gss_cfx_wrap_token)p)->RRC[0] = token->RRC[0]; 583c19800e8SDoug Rabson ((gss_cfx_wrap_token)p)->RRC[1] = token->RRC[1]; 584c19800e8SDoug Rabson 585c19800e8SDoug Rabson /* Check the integrity of the header */ 586c19800e8SDoug Rabson if (memcmp(p, token, sizeof(*token)) != 0) { 587c19800e8SDoug Rabson krb5_crypto_destroy(context, crypto); 588c19800e8SDoug Rabson krb5_data_free(&data); 589c19800e8SDoug Rabson return GSS_S_BAD_MIC; 590c19800e8SDoug Rabson } 591c19800e8SDoug Rabson 592c19800e8SDoug Rabson output_message_buffer->value = data.data; 593c19800e8SDoug Rabson output_message_buffer->length = data.length - ec - sizeof(*token); 594c19800e8SDoug Rabson } else { 595c19800e8SDoug Rabson Checksum cksum; 596c19800e8SDoug Rabson 597c19800e8SDoug Rabson /* Determine checksum type */ 598c19800e8SDoug Rabson ret = krb5_crypto_get_checksum_type(context, 599c19800e8SDoug Rabson crypto, &cksum.cksumtype); 600c19800e8SDoug Rabson if (ret != 0) { 601c19800e8SDoug Rabson *minor_status = ret; 602c19800e8SDoug Rabson krb5_crypto_destroy(context, crypto); 603c19800e8SDoug Rabson return GSS_S_FAILURE; 604c19800e8SDoug Rabson } 605c19800e8SDoug Rabson 606c19800e8SDoug Rabson cksum.checksum.length = ec; 607c19800e8SDoug Rabson 608c19800e8SDoug Rabson /* Check we have at least as much data as the checksum */ 609c19800e8SDoug Rabson if (len < cksum.checksum.length) { 610c19800e8SDoug Rabson *minor_status = ERANGE; 611c19800e8SDoug Rabson krb5_crypto_destroy(context, crypto); 612c19800e8SDoug Rabson return GSS_S_BAD_MIC; 613c19800e8SDoug Rabson } 614c19800e8SDoug Rabson 615c19800e8SDoug Rabson /* Length now is of the plaintext only, no checksum */ 616c19800e8SDoug Rabson len -= cksum.checksum.length; 617c19800e8SDoug Rabson cksum.checksum.data = p + len; 618c19800e8SDoug Rabson 619c19800e8SDoug Rabson output_message_buffer->length = len; /* for later */ 620c19800e8SDoug Rabson output_message_buffer->value = malloc(len + sizeof(*token)); 621c19800e8SDoug Rabson if (output_message_buffer->value == NULL) { 622c19800e8SDoug Rabson *minor_status = ENOMEM; 623c19800e8SDoug Rabson krb5_crypto_destroy(context, crypto); 624c19800e8SDoug Rabson return GSS_S_FAILURE; 625c19800e8SDoug Rabson } 626c19800e8SDoug Rabson 627c19800e8SDoug Rabson /* Checksum is over (plaintext-data | "header") */ 628c19800e8SDoug Rabson memcpy(output_message_buffer->value, p, len); 629c19800e8SDoug Rabson memcpy((u_char *)output_message_buffer->value + len, 630c19800e8SDoug Rabson token, sizeof(*token)); 631c19800e8SDoug Rabson 632c19800e8SDoug Rabson /* EC is not included in checksum calculation */ 633c19800e8SDoug Rabson token = (gss_cfx_wrap_token)((u_char *)output_message_buffer->value + 634c19800e8SDoug Rabson len); 635c19800e8SDoug Rabson token->EC[0] = 0; 636c19800e8SDoug Rabson token->EC[1] = 0; 637c19800e8SDoug Rabson token->RRC[0] = 0; 638c19800e8SDoug Rabson token->RRC[1] = 0; 639c19800e8SDoug Rabson 640c19800e8SDoug Rabson ret = krb5_verify_checksum(context, crypto, 641c19800e8SDoug Rabson usage, 642c19800e8SDoug Rabson output_message_buffer->value, 643c19800e8SDoug Rabson len + sizeof(*token), 644c19800e8SDoug Rabson &cksum); 645c19800e8SDoug Rabson if (ret != 0) { 646c19800e8SDoug Rabson *minor_status = ret; 647c19800e8SDoug Rabson krb5_crypto_destroy(context, crypto); 648c19800e8SDoug Rabson _gsskrb5_release_buffer(minor_status, output_message_buffer); 649c19800e8SDoug Rabson return GSS_S_BAD_MIC; 650c19800e8SDoug Rabson } 651c19800e8SDoug Rabson } 652c19800e8SDoug Rabson 653c19800e8SDoug Rabson krb5_crypto_destroy(context, crypto); 654c19800e8SDoug Rabson 655c19800e8SDoug Rabson if (qop_state != NULL) { 656c19800e8SDoug Rabson *qop_state = GSS_C_QOP_DEFAULT; 657c19800e8SDoug Rabson } 658c19800e8SDoug Rabson 659c19800e8SDoug Rabson *minor_status = 0; 660c19800e8SDoug Rabson return GSS_S_COMPLETE; 661c19800e8SDoug Rabson } 662c19800e8SDoug Rabson 663c19800e8SDoug Rabson OM_uint32 _gssapi_mic_cfx(OM_uint32 *minor_status, 664c19800e8SDoug Rabson const gsskrb5_ctx context_handle, 665c19800e8SDoug Rabson krb5_context context, 666c19800e8SDoug Rabson gss_qop_t qop_req, 667c19800e8SDoug Rabson const gss_buffer_t message_buffer, 668c19800e8SDoug Rabson gss_buffer_t message_token, 669c19800e8SDoug Rabson krb5_keyblock *key) 670c19800e8SDoug Rabson { 671c19800e8SDoug Rabson krb5_crypto crypto; 672c19800e8SDoug Rabson gss_cfx_mic_token token; 673c19800e8SDoug Rabson krb5_error_code ret; 674c19800e8SDoug Rabson unsigned usage; 675c19800e8SDoug Rabson Checksum cksum; 676c19800e8SDoug Rabson u_char *buf; 677c19800e8SDoug Rabson size_t len; 678c19800e8SDoug Rabson int32_t seq_number; 679c19800e8SDoug Rabson 680c19800e8SDoug Rabson ret = krb5_crypto_init(context, key, 0, &crypto); 681c19800e8SDoug Rabson if (ret != 0) { 682c19800e8SDoug Rabson *minor_status = ret; 683c19800e8SDoug Rabson return GSS_S_FAILURE; 684c19800e8SDoug Rabson } 685c19800e8SDoug Rabson 686c19800e8SDoug Rabson len = message_buffer->length + sizeof(*token); 687c19800e8SDoug Rabson buf = malloc(len); 688c19800e8SDoug Rabson if (buf == NULL) { 689c19800e8SDoug Rabson *minor_status = ENOMEM; 690c19800e8SDoug Rabson krb5_crypto_destroy(context, crypto); 691c19800e8SDoug Rabson return GSS_S_FAILURE; 692c19800e8SDoug Rabson } 693c19800e8SDoug Rabson 694c19800e8SDoug Rabson memcpy(buf, message_buffer->value, message_buffer->length); 695c19800e8SDoug Rabson 696c19800e8SDoug Rabson token = (gss_cfx_mic_token)(buf + message_buffer->length); 697c19800e8SDoug Rabson token->TOK_ID[0] = 0x04; 698c19800e8SDoug Rabson token->TOK_ID[1] = 0x04; 699c19800e8SDoug Rabson token->Flags = 0; 700c19800e8SDoug Rabson if ((context_handle->more_flags & LOCAL) == 0) 701c19800e8SDoug Rabson token->Flags |= CFXSentByAcceptor; 702c19800e8SDoug Rabson if (context_handle->more_flags & ACCEPTOR_SUBKEY) 703c19800e8SDoug Rabson token->Flags |= CFXAcceptorSubkey; 704c19800e8SDoug Rabson memset(token->Filler, 0xFF, 5); 705c19800e8SDoug Rabson 706c19800e8SDoug Rabson HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex); 707c19800e8SDoug Rabson krb5_auth_con_getlocalseqnumber(context, 708c19800e8SDoug Rabson context_handle->auth_context, 709c19800e8SDoug Rabson &seq_number); 710c19800e8SDoug Rabson _gsskrb5_encode_be_om_uint32(0, &token->SND_SEQ[0]); 711c19800e8SDoug Rabson _gsskrb5_encode_be_om_uint32(seq_number, &token->SND_SEQ[4]); 712c19800e8SDoug Rabson krb5_auth_con_setlocalseqnumber(context, 713c19800e8SDoug Rabson context_handle->auth_context, 714c19800e8SDoug Rabson ++seq_number); 715c19800e8SDoug Rabson HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex); 716c19800e8SDoug Rabson 717c19800e8SDoug Rabson if (context_handle->more_flags & LOCAL) { 718c19800e8SDoug Rabson usage = KRB5_KU_USAGE_INITIATOR_SIGN; 719c19800e8SDoug Rabson } else { 720c19800e8SDoug Rabson usage = KRB5_KU_USAGE_ACCEPTOR_SIGN; 721c19800e8SDoug Rabson } 722c19800e8SDoug Rabson 723c19800e8SDoug Rabson ret = krb5_create_checksum(context, crypto, 724c19800e8SDoug Rabson usage, 0, buf, len, &cksum); 725c19800e8SDoug Rabson if (ret != 0) { 726c19800e8SDoug Rabson *minor_status = ret; 727c19800e8SDoug Rabson krb5_crypto_destroy(context, crypto); 728c19800e8SDoug Rabson free(buf); 729c19800e8SDoug Rabson return GSS_S_FAILURE; 730c19800e8SDoug Rabson } 731c19800e8SDoug Rabson krb5_crypto_destroy(context, crypto); 732c19800e8SDoug Rabson 733c19800e8SDoug Rabson /* Determine MIC length */ 734c19800e8SDoug Rabson message_token->length = sizeof(*token) + cksum.checksum.length; 735c19800e8SDoug Rabson message_token->value = malloc(message_token->length); 736c19800e8SDoug Rabson if (message_token->value == NULL) { 737c19800e8SDoug Rabson *minor_status = ENOMEM; 738c19800e8SDoug Rabson free_Checksum(&cksum); 739c19800e8SDoug Rabson free(buf); 740c19800e8SDoug Rabson return GSS_S_FAILURE; 741c19800e8SDoug Rabson } 742c19800e8SDoug Rabson 743c19800e8SDoug Rabson /* Token is { "header" | get_mic("header" | plaintext-data) } */ 744c19800e8SDoug Rabson memcpy(message_token->value, token, sizeof(*token)); 745c19800e8SDoug Rabson memcpy((u_char *)message_token->value + sizeof(*token), 746c19800e8SDoug Rabson cksum.checksum.data, cksum.checksum.length); 747c19800e8SDoug Rabson 748c19800e8SDoug Rabson free_Checksum(&cksum); 749c19800e8SDoug Rabson free(buf); 750c19800e8SDoug Rabson 751c19800e8SDoug Rabson *minor_status = 0; 752c19800e8SDoug Rabson return GSS_S_COMPLETE; 753c19800e8SDoug Rabson } 754c19800e8SDoug Rabson 755c19800e8SDoug Rabson OM_uint32 _gssapi_verify_mic_cfx(OM_uint32 *minor_status, 756c19800e8SDoug Rabson const gsskrb5_ctx context_handle, 757c19800e8SDoug Rabson krb5_context context, 758c19800e8SDoug Rabson const gss_buffer_t message_buffer, 759c19800e8SDoug Rabson const gss_buffer_t token_buffer, 760c19800e8SDoug Rabson gss_qop_t *qop_state, 761c19800e8SDoug Rabson krb5_keyblock *key) 762c19800e8SDoug Rabson { 763c19800e8SDoug Rabson krb5_crypto crypto; 764c19800e8SDoug Rabson gss_cfx_mic_token token; 765c19800e8SDoug Rabson u_char token_flags; 766c19800e8SDoug Rabson krb5_error_code ret; 767c19800e8SDoug Rabson unsigned usage; 768c19800e8SDoug Rabson OM_uint32 seq_number_lo, seq_number_hi; 769c19800e8SDoug Rabson u_char *buf, *p; 770c19800e8SDoug Rabson Checksum cksum; 771c19800e8SDoug Rabson 772c19800e8SDoug Rabson *minor_status = 0; 773c19800e8SDoug Rabson 774c19800e8SDoug Rabson if (token_buffer->length < sizeof(*token)) { 775c19800e8SDoug Rabson return GSS_S_DEFECTIVE_TOKEN; 776c19800e8SDoug Rabson } 777c19800e8SDoug Rabson 778c19800e8SDoug Rabson p = token_buffer->value; 779c19800e8SDoug Rabson 780c19800e8SDoug Rabson token = (gss_cfx_mic_token)p; 781c19800e8SDoug Rabson 782c19800e8SDoug Rabson if (token->TOK_ID[0] != 0x04 || token->TOK_ID[1] != 0x04) { 783c19800e8SDoug Rabson return GSS_S_DEFECTIVE_TOKEN; 784c19800e8SDoug Rabson } 785c19800e8SDoug Rabson 786c19800e8SDoug Rabson /* Ignore unknown flags */ 787c19800e8SDoug Rabson token_flags = token->Flags & (CFXSentByAcceptor | CFXAcceptorSubkey); 788c19800e8SDoug Rabson 789c19800e8SDoug Rabson if (token_flags & CFXSentByAcceptor) { 790c19800e8SDoug Rabson if ((context_handle->more_flags & LOCAL) == 0) 791c19800e8SDoug Rabson return GSS_S_DEFECTIVE_TOKEN; 792c19800e8SDoug Rabson } 793c19800e8SDoug Rabson if (context_handle->more_flags & ACCEPTOR_SUBKEY) { 794c19800e8SDoug Rabson if ((token_flags & CFXAcceptorSubkey) == 0) 795c19800e8SDoug Rabson return GSS_S_DEFECTIVE_TOKEN; 796c19800e8SDoug Rabson } else { 797c19800e8SDoug Rabson if (token_flags & CFXAcceptorSubkey) 798c19800e8SDoug Rabson return GSS_S_DEFECTIVE_TOKEN; 799c19800e8SDoug Rabson } 800c19800e8SDoug Rabson 801c19800e8SDoug Rabson if (memcmp(token->Filler, "\xff\xff\xff\xff\xff", 5) != 0) { 802c19800e8SDoug Rabson return GSS_S_DEFECTIVE_TOKEN; 803c19800e8SDoug Rabson } 804c19800e8SDoug Rabson 805c19800e8SDoug Rabson /* 806c19800e8SDoug Rabson * Check sequence number 807c19800e8SDoug Rabson */ 808c19800e8SDoug Rabson _gsskrb5_decode_be_om_uint32(&token->SND_SEQ[0], &seq_number_hi); 809c19800e8SDoug Rabson _gsskrb5_decode_be_om_uint32(&token->SND_SEQ[4], &seq_number_lo); 810c19800e8SDoug Rabson if (seq_number_hi) { 811c19800e8SDoug Rabson *minor_status = ERANGE; 812c19800e8SDoug Rabson return GSS_S_UNSEQ_TOKEN; 813c19800e8SDoug Rabson } 814c19800e8SDoug Rabson 815c19800e8SDoug Rabson HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex); 816c19800e8SDoug Rabson ret = _gssapi_msg_order_check(context_handle->order, seq_number_lo); 817c19800e8SDoug Rabson if (ret != 0) { 818c19800e8SDoug Rabson *minor_status = 0; 819c19800e8SDoug Rabson HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex); 820c19800e8SDoug Rabson return ret; 821c19800e8SDoug Rabson } 822c19800e8SDoug Rabson HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex); 823c19800e8SDoug Rabson 824c19800e8SDoug Rabson /* 825c19800e8SDoug Rabson * Verify checksum 826c19800e8SDoug Rabson */ 827c19800e8SDoug Rabson ret = krb5_crypto_init(context, key, 0, &crypto); 828c19800e8SDoug Rabson if (ret != 0) { 829c19800e8SDoug Rabson *minor_status = ret; 830c19800e8SDoug Rabson return GSS_S_FAILURE; 831c19800e8SDoug Rabson } 832c19800e8SDoug Rabson 833c19800e8SDoug Rabson ret = krb5_crypto_get_checksum_type(context, crypto, 834c19800e8SDoug Rabson &cksum.cksumtype); 835c19800e8SDoug Rabson if (ret != 0) { 836c19800e8SDoug Rabson *minor_status = ret; 837c19800e8SDoug Rabson krb5_crypto_destroy(context, crypto); 838c19800e8SDoug Rabson return GSS_S_FAILURE; 839c19800e8SDoug Rabson } 840c19800e8SDoug Rabson 841c19800e8SDoug Rabson cksum.checksum.data = p + sizeof(*token); 842c19800e8SDoug Rabson cksum.checksum.length = token_buffer->length - sizeof(*token); 843c19800e8SDoug Rabson 844c19800e8SDoug Rabson if (context_handle->more_flags & LOCAL) { 845c19800e8SDoug Rabson usage = KRB5_KU_USAGE_ACCEPTOR_SIGN; 846c19800e8SDoug Rabson } else { 847c19800e8SDoug Rabson usage = KRB5_KU_USAGE_INITIATOR_SIGN; 848c19800e8SDoug Rabson } 849c19800e8SDoug Rabson 850c19800e8SDoug Rabson buf = malloc(message_buffer->length + sizeof(*token)); 851c19800e8SDoug Rabson if (buf == NULL) { 852c19800e8SDoug Rabson *minor_status = ENOMEM; 853c19800e8SDoug Rabson krb5_crypto_destroy(context, crypto); 854c19800e8SDoug Rabson return GSS_S_FAILURE; 855c19800e8SDoug Rabson } 856c19800e8SDoug Rabson memcpy(buf, message_buffer->value, message_buffer->length); 857c19800e8SDoug Rabson memcpy(buf + message_buffer->length, token, sizeof(*token)); 858c19800e8SDoug Rabson 859c19800e8SDoug Rabson ret = krb5_verify_checksum(context, crypto, 860c19800e8SDoug Rabson usage, 861c19800e8SDoug Rabson buf, 862c19800e8SDoug Rabson sizeof(*token) + message_buffer->length, 863c19800e8SDoug Rabson &cksum); 864c19800e8SDoug Rabson krb5_crypto_destroy(context, crypto); 865c19800e8SDoug Rabson if (ret != 0) { 866c19800e8SDoug Rabson *minor_status = ret; 867c19800e8SDoug Rabson free(buf); 868c19800e8SDoug Rabson return GSS_S_BAD_MIC; 869c19800e8SDoug Rabson } 870c19800e8SDoug Rabson 871c19800e8SDoug Rabson free(buf); 872c19800e8SDoug Rabson 873c19800e8SDoug Rabson if (qop_state != NULL) { 874c19800e8SDoug Rabson *qop_state = GSS_C_QOP_DEFAULT; 875c19800e8SDoug Rabson } 876c19800e8SDoug Rabson 877c19800e8SDoug Rabson return GSS_S_COMPLETE; 878c19800e8SDoug Rabson } 879