gsskrb5: add support [un]wrap_ex with cfx
authorStefan Metzmacher <metze@samba.org>
Fri, 8 Aug 2008 14:37:25 +0000 (16:37 +0200)
committerStefan Metzmacher <metze@samba.org>
Mon, 18 Aug 2008 06:49:05 +0000 (08:49 +0200)
metze

source/heimdal/lib/gssapi/krb5/cfx.c
source/heimdal/lib/gssapi/krb5/gsskrb5-private.h
source/heimdal/lib/gssapi/krb5/unwrap.c
source/heimdal/lib/gssapi/krb5/wrap.c

index bc0d736e81ac8230bb7e97da71722a2fc0c80c2e..3ed7cab6f904b0d3b45ad545bdba05b356043988 100755 (executable)
@@ -464,6 +464,310 @@ OM_uint32 _gssapi_wrap_cfx(OM_uint32 *minor_status,
     return GSS_S_COMPLETE;
 }
 
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_create_integrity_checksum(krb5_context context,
+                    krb5_crypto crypto,
+                    krb5_key_usage usage,
+                    int type,
+                    void *data,
+                    size_t len,
+                    Checksum *result);
+
+OM_uint32 _gssapi_wrap_ex_cfx(OM_uint32 *minor_status,
+                             const gsskrb5_ctx context_handle,
+                             krb5_context context,
+                             int conf_req_flag,
+                             gss_qop_t qop_req,
+                             int *conf_state,
+                             krb5_keyblock *key,
+                             const gss_buffer_t associated_data_buffer,
+                             gss_buffer_t message_buffer,
+                             gss_buffer_t output_token_buffer)
+{
+    krb5_crypto crypto;
+    gss_cfx_wrap_token token;
+    krb5_error_code ret;
+    unsigned usage;
+    krb5_data cipher;
+    size_t wrapped_len, cksumsize;
+    uint16_t padlength, rrc = 0;
+    int32_t seq_number;
+    u_char *p;
+
+    ret = krb5_crypto_init(context, key, 0, &crypto);
+    if (ret != 0) {
+       *minor_status = ret;
+       return GSS_S_FAILURE;
+    }
+
+    ret = _gsskrb5cfx_wrap_length_cfx(context_handle, context,
+                                     crypto, conf_req_flag, 
+                                     message_buffer->length,
+                                     &wrapped_len, &cksumsize, &padlength);
+    if (ret != 0) {
+       *minor_status = ret;
+       krb5_crypto_destroy(context, crypto);
+       return GSS_S_FAILURE;
+    }
+
+    /* Always rotate encrypted token (if any) and checksum to header */
+    rrc = (conf_req_flag ? sizeof(*token) : 0) + (uint16_t)cksumsize;
+
+    output_token_buffer->length = wrapped_len - message_buffer->length;
+    output_token_buffer->value = malloc(output_token_buffer->length);
+    if (output_token_buffer->value == NULL) {
+       *minor_status = ENOMEM;
+       krb5_crypto_destroy(context, crypto);
+       return GSS_S_FAILURE;
+    }
+
+    p = output_token_buffer->value;
+    token = (gss_cfx_wrap_token)p;
+    token->TOK_ID[0] = 0x05;
+    token->TOK_ID[1] = 0x04;
+    token->Flags     = 0;
+    token->Filler    = 0xFF;
+    if ((context_handle->more_flags & LOCAL) == 0)
+       token->Flags |= CFXSentByAcceptor;
+    if (context_handle->more_flags & ACCEPTOR_SUBKEY)
+       token->Flags |= CFXAcceptorSubkey;
+    if (conf_req_flag) {
+       /*
+        * In Wrap tokens with confidentiality, the EC field is
+        * used to encode the size (in bytes) of the random filler.
+        */
+       token->Flags |= CFXSealed;
+       token->EC[0] = (padlength >> 8) & 0xFF;
+       token->EC[1] = (padlength >> 0) & 0xFF;
+    } else {
+       /*
+        * In Wrap tokens without confidentiality, the EC field is
+        * used to encode the size (in bytes) of the trailing
+        * checksum.
+        *
+        * This is not used in the checksum calcuation itself,
+        * because the checksum length could potentially vary
+        * depending on the data length.
+        */
+       token->EC[0] = 0;
+       token->EC[1] = 0;
+    }
+
+    /*
+     * In Wrap tokens that provide for confidentiality, the RRC
+     * field in the header contains the hex value 00 00 before
+     * encryption.
+     *
+     * In Wrap tokens that do not provide for confidentiality,
+     * both the EC and RRC fields in the appended checksum
+     * contain the hex value 00 00 for the purpose of calculating
+     * the checksum.
+     */
+    token->RRC[0] = 0;
+    token->RRC[1] = 0;
+
+    HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex);
+    krb5_auth_con_getlocalseqnumber(context,
+                                   context_handle->auth_context,
+                                   &seq_number);
+    _gsskrb5_encode_be_om_uint32(0,          &token->SND_SEQ[0]);
+    _gsskrb5_encode_be_om_uint32(seq_number, &token->SND_SEQ[4]);
+    krb5_auth_con_setlocalseqnumber(context,
+                                   context_handle->auth_context,
+                                   ++seq_number);
+    HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
+
+    /*
+     * If confidentiality is requested, the token header is
+     * appended to the plaintext before encryption; the resulting
+     * token is {"header" | encrypt(plaintext | pad | "header")}.
+     *
+     * If no confidentiality is requested, the checksum is
+     * calculated over the plaintext concatenated with the
+     * token header.
+     */
+    if (context_handle->more_flags & LOCAL) {
+       usage = KRB5_KU_USAGE_INITIATOR_SEAL;
+    } else {
+       usage = KRB5_KU_USAGE_ACCEPTOR_SEAL;
+    }
+
+    if (conf_req_flag) {
+       Checksum cksum;
+       size_t cf_len = 0;
+       uint8_t *cf;
+       size_t sign_len = 0;
+       size_t sign_idx = 0;
+       uint8_t *sign;
+       size_t seal_len = 0;
+       size_t seal_idx = 0;
+       uint8_t *seal;
+
+       krb5_crypto_getconfoundersize(context, crypto, &cf_len);
+
+       cf = (uint8_t *)malloc(cf_len);
+       if (cf == NULL) {
+           *minor_status = ENOMEM;
+           krb5_crypto_destroy(context, crypto);
+           _gsskrb5_release_buffer(minor_status, output_token_buffer);
+           return GSS_S_FAILURE;
+       }
+
+       krb5_generate_random_block(cf, cf_len);
+
+       /*
+        * Any necessary padding is added here to ensure that the
+        * encrypted token header is always at the end of the
+        * ciphertext.
+        *
+        * The specification does not require that the padding
+        * bytes are initialized.
+        */
+       sign_len += cf_len;
+       sign_len += associated_data_buffer->length;
+       sign_len += padlength;
+       sign_len += sizeof(*token);
+
+       sign = (uint8_t *)malloc(sign_len);
+       if (sign == NULL) {
+           *minor_status = ENOMEM;
+           free(cf);
+           krb5_crypto_destroy(context, crypto);
+           _gsskrb5_release_buffer(minor_status, output_token_buffer);
+           return GSS_S_FAILURE;
+       }
+
+       memcpy(sign + sign_idx, cf, cf_len);
+       sign_idx += cf_len;
+       memcpy(sign + sign_idx, associated_data_buffer->value, associated_data_buffer->length);
+       sign_idx += associated_data_buffer->length;
+       memset(sign + sign_idx, 0xFF, padlength);
+       sign_idx += padlength;
+       memcpy(sign + sign_idx, token, sizeof(*token));
+       sign_idx += sizeof(*token);
+
+       ret = krb5_create_integrity_checksum(context, crypto, usage, 0,
+                                            sign, sign_len, &cksum);
+       free(sign);
+       if (ret != 0) {
+           *minor_status = ret;
+           free(cf);
+           krb5_crypto_destroy(context, crypto);
+           _gsskrb5_release_buffer(minor_status, output_token_buffer);
+           return GSS_S_FAILURE;
+       }
+
+       seal_len += cf_len;
+       seal_len += message_buffer->length;
+       seal_len += padlength;
+       seal_len += sizeof(*token);
+
+       seal = (uint8_t *)malloc(seal_len);
+       if (seal == NULL) {
+           *minor_status = ENOMEM;
+           free(cf);
+           free_Checksum(&cksum);
+           krb5_crypto_destroy(context, crypto);
+           _gsskrb5_release_buffer(minor_status, output_token_buffer);
+           return GSS_S_FAILURE;
+       }
+
+       memcpy(seal + seal_idx, cf, cf_len);
+       seal_idx += cf_len;
+       memcpy(seal + seal_idx, message_buffer->value, message_buffer->length);
+       seal_idx += message_buffer->length;
+       memset(seal + seal_idx, 0xFF, padlength);
+       seal_idx += padlength;
+       memcpy(seal + seal_idx, token, sizeof(*token));
+       seal_idx += sizeof(*token);
+
+       ret = krb5_encrypt_inplace_ivec(context, crypto, usage,
+                                       seal, seal_len, NULL);
+       free(cf);
+       if (ret != 0) {
+           *minor_status = ret;
+           free(seal);
+           free_Checksum(&cksum);
+           krb5_crypto_destroy(context, crypto);
+           _gsskrb5_release_buffer(minor_status, output_token_buffer);
+           return GSS_S_FAILURE;
+       }
+
+       memcpy(message_buffer->value, seal + cf_len, message_buffer->length);
+
+       token->RRC[0] = (rrc >> 8) & 0xFF;
+       token->RRC[1] = (rrc >> 0) & 0xFF;
+
+       p += sizeof(*token);
+
+       /* rotated by padlength+sizeof(token)+checksum.length */
+       seal_idx = cf_len + message_buffer->length;
+       memcpy(p, seal + seal_idx, padlength);
+       p += padlength;
+
+       seal_idx += padlength;
+       memcpy(p, seal + seal_idx, sizeof(*token));
+       p += sizeof(*token);
+
+       assert(cksum.checksum.length == cksumsize);
+       memcpy(p, cksum.checksum.data, cksum.checksum.length);
+       p += cksum.checksum.length;
+
+       memcpy(p, seal, cf_len);
+
+       free_Checksum(&cksum);
+       free(seal);
+
+    } else {
+       char *buf;
+       Checksum cksum;
+
+       buf = malloc(associated_data_buffer->length + sizeof(*token));
+       if (buf == NULL) {
+           *minor_status = ENOMEM;
+           krb5_crypto_destroy(context, crypto);
+           _gsskrb5_release_buffer(minor_status, output_token_buffer);
+           return GSS_S_FAILURE;
+       }
+       memcpy(buf, associated_data_buffer->value, associated_data_buffer->length);
+       memcpy(buf + associated_data_buffer->length, token, sizeof(*token));
+
+       ret = krb5_create_checksum(context, crypto,
+                                  usage, 0, buf, 
+                                  associated_data_buffer->length +
+                                       sizeof(*token), 
+                                  &cksum);
+       if (ret != 0) {
+           *minor_status = ret;
+           krb5_crypto_destroy(context, crypto);
+           _gsskrb5_release_buffer(minor_status, output_token_buffer);
+           free(buf);
+           return GSS_S_FAILURE;
+       }
+
+       free(buf);
+
+       assert(cksum.checksum.length == cksumsize);
+       token->EC[0] =  (cksum.checksum.length >> 8) & 0xFF;
+       token->EC[1] =  (cksum.checksum.length >> 0) & 0xFF;
+       token->RRC[0] = (rrc >> 8) & 0xFF;  
+       token->RRC[1] = (rrc >> 0) & 0xFF;
+
+       p += sizeof(*token);
+       memcpy(p, cksum.checksum.data, cksum.checksum.length);
+       free_Checksum(&cksum);
+    }
+
+    krb5_crypto_destroy(context, crypto);
+
+    if (conf_state != NULL) {
+       *conf_state = conf_req_flag;
+    }
+
+    *minor_status = 0;
+    return GSS_S_COMPLETE;
+}
+
 OM_uint32 _gssapi_unwrap_cfx(OM_uint32 *minor_status,
                             const gsskrb5_ctx context_handle,
                             krb5_context context,
@@ -687,6 +991,327 @@ OM_uint32 _gssapi_unwrap_cfx(OM_uint32 *minor_status,
     return GSS_S_COMPLETE;
 }
 
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_verify_integrity_checksum(krb5_context context,
+                    krb5_crypto crypto,
+                    krb5_key_usage usage, 
+                    void *data,
+                    size_t len,
+                    Checksum *cksum);
+
+OM_uint32 _gssapi_unwrap_ex_cfx(OM_uint32 *minor_status,
+                               const gsskrb5_ctx context_handle,
+                               krb5_context context,
+                               int *conf_state,
+                               gss_qop_t *qop_state,
+                               krb5_keyblock *key,
+                               const gss_buffer_t token_header_buffer,
+                               const gss_buffer_t associated_data_buffer,
+                               gss_buffer_t message_buffer)
+{
+    krb5_crypto crypto;
+    gss_cfx_wrap_token token;
+    u_char token_flags;
+    krb5_error_code ret;
+    unsigned usage;
+    krb5_data data;
+    uint16_t ec, rrc;
+    OM_uint32 seq_number_lo, seq_number_hi;
+    size_t len;
+    u_char *p;
+
+    *minor_status = 0;
+
+    if (token_header_buffer->length < sizeof(*token)) {
+       return GSS_S_DEFECTIVE_TOKEN;
+    }
+
+    p = token_header_buffer->value;
+
+    token = (gss_cfx_wrap_token)p;
+
+    if (token->TOK_ID[0] != 0x05 || token->TOK_ID[1] != 0x04) {
+       return GSS_S_DEFECTIVE_TOKEN;
+    }
+
+    /* Ignore unknown flags */
+    token_flags = token->Flags &
+       (CFXSentByAcceptor | CFXSealed | CFXAcceptorSubkey);
+
+    if (token_flags & CFXSentByAcceptor) {
+       if ((context_handle->more_flags & LOCAL) == 0)
+           return GSS_S_DEFECTIVE_TOKEN;
+    }
+
+    if (context_handle->more_flags & ACCEPTOR_SUBKEY) {
+       if ((token_flags & CFXAcceptorSubkey) == 0)
+           return GSS_S_DEFECTIVE_TOKEN;
+    } else {
+       if (token_flags & CFXAcceptorSubkey)
+           return GSS_S_DEFECTIVE_TOKEN;
+    }
+
+    if (token->Filler != 0xFF) {
+       return GSS_S_DEFECTIVE_TOKEN;
+    }
+
+    if (conf_state != NULL) {
+       *conf_state = (token_flags & CFXSealed) ? 1 : 0;
+    }
+
+    ec  = (token->EC[0]  << 8) | token->EC[1];
+    rrc = (token->RRC[0] << 8) | token->RRC[1];
+
+    /*
+     * Check sequence number
+     */
+    _gsskrb5_decode_be_om_uint32(&token->SND_SEQ[0], &seq_number_hi);
+    _gsskrb5_decode_be_om_uint32(&token->SND_SEQ[4], &seq_number_lo);
+    if (seq_number_hi) {
+       /* no support for 64-bit sequence numbers */
+       *minor_status = ERANGE;
+       return GSS_S_UNSEQ_TOKEN;
+    }
+
+    HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex);
+    ret = _gssapi_msg_order_check(context_handle->order, seq_number_lo);
+    if (ret != 0) {
+       *minor_status = 0;
+       HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
+       return ret;
+    }
+    HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex);
+
+    /*
+     * Decrypt and/or verify checksum
+     */
+    ret = krb5_crypto_init(context, key, 0, &crypto);
+    if (ret != 0) {
+       *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);
+
+    if (token_flags & CFXSealed) {
+       Checksum cksum;
+       size_t overhead;
+       size_t cf_len = 0;
+       uint8_t *cf;
+       size_t rot_len = 0;
+       size_t rot_idx = 0;
+       uint8_t *rot;
+       size_t seal_len = 0;
+       uint8_t *seal;
+       size_t sign_len = 0;
+       size_t sign_idx = 0;
+       uint8_t *sign;
+       uint8_t *pad;
+       gss_cfx_wrap_token token2;
+
+       overhead = token_header_buffer->length - sizeof(*token);
+
+       /* Determine checksum type */
+       ret = krb5_crypto_get_checksum_type(context,
+                                           crypto, &cksum.cksumtype);
+       if (ret != 0) {
+           *minor_status = ret;
+           krb5_crypto_destroy(context, crypto);
+           return GSS_S_FAILURE;
+       }
+
+       /* Determine checksum size */
+       ret = krb5_checksumsize(context,
+                               cksum.cksumtype, &cksum.checksum.length);
+       if (ret != 0) {
+           *minor_status = ret;
+           krb5_crypto_destroy(context, crypto);
+           return GSS_S_FAILURE;
+       }
+
+       /* Determine confounder size */
+       ret = krb5_crypto_getconfoundersize(context, crypto, &cf_len);
+       if (ret != 0) {
+           *minor_status = ret;
+           krb5_crypto_destroy(context, crypto);
+           return GSS_S_FAILURE;
+       }
+
+       if (overhead != (ec + sizeof(*token) + cksum.checksum.length + cf_len)) {
+           *minor_status = ERANGE;
+           krb5_crypto_destroy(context, crypto);
+           return GSS_S_BAD_MIC;
+       }
+
+       rot_len += overhead;
+       rot_len += message_buffer->length;
+
+       rot = (uint8_t *)malloc(rot_len);
+       if (rot == NULL) {
+           *minor_status = ENOMEM;
+           krb5_crypto_destroy(context, crypto);
+           return GSS_S_FAILURE;
+       }
+
+       memcpy(rot + rot_idx, p, token_header_buffer->length - sizeof(*token));
+       rot_idx += (token_header_buffer->length - sizeof(*token));
+
+       memcpy(rot + rot_idx, message_buffer->value, message_buffer->length);
+       rot_idx += message_buffer->length;
+
+       *minor_status = rrc_rotate(rot, rot_len, rrc+ec, TRUE);
+       if (*minor_status != 0) {
+           free(rot);
+           krb5_crypto_destroy(context, crypto);
+           return GSS_S_FAILURE;
+       }
+
+       seal = rot;
+       seal_len = rot_len - cksum.checksum.length;
+
+       cksum.checksum.data = seal + seal_len;
+
+       ret = krb5_decrypt_inplace_ivec(context, crypto, usage,
+                                       seal, seal_len, NULL);
+       if (ret != 0) {
+           *minor_status = ret;
+           free(rot);
+           krb5_crypto_destroy(context, crypto);
+           return GSS_S_FAILURE;
+       }
+
+       cf = seal;
+       memcpy(message_buffer->value, seal + cf_len, message_buffer->length);
+       pad = seal + cf_len + message_buffer->length;
+       token2 = (gss_cfx_wrap_token)((uint8_t *)seal + cf_len + message_buffer->length + ec);
+
+       sign_len += cf_len;
+       sign_len += associated_data_buffer->length;
+       sign_len += ec;
+       sign_len += sizeof(*token2);
+
+       sign = (uint8_t *)malloc(sign_len);
+       if (sign == NULL) {
+           *minor_status = ENOMEM;
+           krb5_crypto_destroy(context, crypto);
+           return GSS_S_FAILURE;
+       }
+
+       memcpy(sign + sign_idx, cf, cf_len);
+       sign_idx += cf_len;
+       memcpy(sign + sign_idx, associated_data_buffer->value, associated_data_buffer->length);
+       sign_idx += associated_data_buffer->length;
+       memcpy(sign + sign_idx, pad, ec);
+       sign_idx += ec;
+       memcpy(sign + sign_idx, token2, sizeof(*token2));
+       sign_idx += sizeof(*token2);
+
+       ret = krb5_verify_integrity_checksum(context, crypto, usage,
+                                            sign, sign_len, &cksum);
+       free(sign);
+       if (ret != 0) {
+           *minor_status = ret;
+           free(rot);
+           krb5_crypto_destroy(context, crypto);
+           return GSS_S_FAILURE;
+       }
+
+       /* RRC is unprotected; don't modify input buffer */
+       token2->RRC[0] = token->RRC[0];
+       token2->RRC[1] = token->RRC[1];
+
+       /* Check the integrity of the header */
+       if (memcmp(token2, token, sizeof(*token)) != 0) {
+           free(rot);
+           krb5_crypto_destroy(context, crypto);
+           return GSS_S_BAD_MIC;
+       }
+
+       free(rot);
+    } else {
+       Checksum cksum;
+#if 0
+       gssoutput_message;
+
+       /* Rotate by RRC; bogus to do this in-place XXX */
+       *minor_status = rrc_rotate(p, len, rrc, TRUE);
+       if (*minor_status != 0) {
+           krb5_crypto_destroy(context, crypto);
+           return GSS_S_FAILURE;
+       }
+
+       /* Determine checksum type */
+       ret = krb5_crypto_get_checksum_type(context,
+                                           crypto, &cksum.cksumtype);
+       if (ret != 0) {
+           *minor_status = ret;
+           krb5_crypto_destroy(context, crypto);
+           return GSS_S_FAILURE;
+       }
+
+       cksum.checksum.length = ec;
+
+       /* Check we have at least as much data as the checksum */
+       if (len < cksum.checksum.length) {
+           *minor_status = ERANGE;
+           krb5_crypto_destroy(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(context, crypto);
+           return GSS_S_FAILURE;
+       }
+
+       /* Checksum is over (plaintext-data | "header") */
+       memcpy(output_message_buffer->value, p, len);
+       memcpy((u_char *)output_message_buffer->value + len, 
+              token, sizeof(*token));
+
+       /* EC is not included in checksum calculation */
+       token = (gss_cfx_wrap_token)((u_char *)output_message_buffer->value +
+                                    len);
+       token->EC[0]  = 0;
+       token->EC[1]  = 0;
+       token->RRC[0] = 0;
+       token->RRC[1] = 0;
+
+       ret = krb5_verify_checksum(context, crypto,
+                                  usage,
+                                  output_message_buffer->value,
+                                  len + sizeof(*token),
+                                  &cksum);
+       if (ret != 0) {
+           *minor_status = ret;
+           krb5_crypto_destroy(context, crypto);
+           return GSS_S_BAD_MIC;
+       }
+#endif
+    }
+
+    krb5_crypto_destroy(context, crypto);
+
+    if (qop_state != NULL) {
+       *qop_state = GSS_C_QOP_DEFAULT;
+    }
+
+    *minor_status = 0;
+    return GSS_S_COMPLETE;
+}
+
 OM_uint32 _gssapi_mic_cfx(OM_uint32 *minor_status,
                          const gsskrb5_ctx context_handle,
                          krb5_context context,
index 08a65b10df077eb04ff212c25bcfebcb3d0e05aa..eb992b19c3a66c047c9d361c575d70f0b0167932 100644 (file)
@@ -132,6 +132,18 @@ _gssapi_unwrap_cfx (
        gss_qop_t */*qop_state*/,
        krb5_keyblock */*key*/);
 
+OM_uint32
+_gssapi_unwrap_ex_cfx (
+       OM_uint32 * /*minor_status*/,
+       const gsskrb5_ctx /*context_handle*/,
+       krb5_context /*context*/,
+       int * /*conf_state*/,
+       gss_qop_t * /*qop_state*/,
+       krb5_keyblock * /*key*/,
+       const gss_buffer_t /*token_header_buffer*/,
+       const gss_buffer_t /*associated_data_buffer*/,
+       gss_buffer_t /*message_buffer*/);
+
 OM_uint32
 _gssapi_verify_mech_header (
        u_char **/*str*/,
@@ -201,6 +213,19 @@ _gssapi_wrap_cfx (
        gss_buffer_t /*output_message_buffer*/,
        krb5_keyblock */*key*/);
 
+OM_uint32
+_gssapi_wrap_ex_cfx (
+       OM_uint32 * /*minor_status*/,
+       const gsskrb5_ctx /*context_handle*/,
+       krb5_context /*context*/,
+       int /*conf_req_flag*/,
+       gss_qop_t /*qop_req*/,
+       int * /*conf_state*/,
+       krb5_keyblock * /*key*/,
+       const gss_buffer_t /*associated_data_buffer*/,
+       gss_buffer_t /*message_buffer*/,
+       gss_buffer_t /*output_token_buffer*/);
+
 OM_uint32
 _gssapi_wrap_size_arcfour (
        OM_uint32 */*minor_status*/,
index 0a55e93edd1bbec827b551c0ca24a6ea6b0033a7..db7b3972f141fbc3dca1ca6ff63e5594b4fb7bf6 100644 (file)
@@ -473,9 +473,10 @@ OM_uint32 _gsskrb5_unwrap_ex
   switch (keytype) {
   case KEYTYPE_DES:
   case KEYTYPE_DES3:
-  default:
       no_ex = 1;
       break;
+  default:
+      break;
   }
 
   if (no_ex) {
@@ -534,8 +535,11 @@ OM_uint32 _gsskrb5_unwrap_ex
                                      message_buffer);
       break;
   default:
-      *minor_status = EINVAL;
-      ret = GSS_S_FAILURE;
+      ret = _gssapi_unwrap_ex_cfx(minor_status, ctx, context,
+                                 conf_state, qop_state, key,
+                                 token_header_buffer,
+                                 associated_data_buffer,
+                                 message_buffer);
       break;
   }
 
index df58cde6ada97533c87febc8a68e2d994d30a84c..539a071c0fe55af741d64047f3aa6d8003533825 100644 (file)
@@ -601,10 +601,11 @@ OM_uint32 _gsskrb5_wrap_ex
   switch (keytype) {
   case KEYTYPE_DES:
   case KEYTYPE_DES3:
-  default:
       krb5_free_keyblock (context, key);
       no_ex = 1;
       break;
+  default:
+      break;
   }
 
   if (no_ex) {
@@ -651,8 +652,12 @@ OM_uint32 _gsskrb5_wrap_ex
                                    output_token_buffer);
       break;
   default:
-      *minor_status = EINVAL;
-      ret = GSS_S_FAILURE;
+      ret = _gssapi_wrap_ex_cfx(minor_status,
+                               ctx, context, conf_req_flag,
+                               qop_req, conf_state, key,
+                               associated_data_buffer,
+                               message_buffer,
+                               output_token_buffer);
       break;
   }